Create the TCP and UDP clients explicitely using clnttcp/udp_create
[tridge/dbench.git] / libnfs.c
1 /* 
2    nfs library for dbench
3
4    Copyright (C) 2008 by Ronnie Sahlberg (ronniesahlberg@gmail.com)
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "mount.h"
21 #include "nfs.h"
22 #include "libnfs.h"
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26
27 #define discard_const(ptr) ((void *)((intptr_t)(ptr)))
28
29 typedef struct _data_t {
30         const char *dptr;
31         int dsize;
32 } data_t;
33
34 typedef struct _tree_t {
35         data_t key;
36         data_t fh;
37         struct _tree_t *parent;
38         struct _tree_t *left;
39         struct _tree_t *right;
40 } tree_t;
41
42
43 struct nfsio {
44         int s;
45         CLIENT *clnt;
46         tree_t *fhandles;
47 };
48
49 static void free_node(tree_t *t)
50 {
51         free(discard_const(t->key.dptr));
52         free(discard_const(t->fh.dptr));
53         free(t);
54 }
55
56 static tree_t *find_fhandle(tree_t *tree, const char *key)
57 {
58         int i;
59
60         if (tree == NULL) {
61                 return NULL;
62         }
63
64         i = strcmp(key, tree->key.dptr);
65         if (i == 0) {
66                 return tree;
67         }
68         if (i < 0) {
69                 return find_fhandle(tree->left, key);
70         }
71
72         return find_fhandle(tree->right, key);
73 }
74
75 static data_t *lookup_fhandle(struct nfsio *nfsio, const char *name)
76 {
77         tree_t *t;
78
79         while (name[0] == '.') name++;
80
81         if (name[0] == 0) {
82                 name = "/";
83         }
84
85         t = find_fhandle(nfsio->fhandles, name);
86         if (t == NULL) {
87                 return NULL;
88         }
89
90         return &t->fh;
91 }
92
93 static void delete_fhandle(struct nfsio *nfsio, const char *name)
94 {
95         tree_t *t;
96
97         while (name[0] == '.') name++;
98
99         t = find_fhandle(nfsio->fhandles, name);
100         if (t == NULL) {
101                 return;
102         }
103
104         /* we have a left child */
105         if (t->left) {
106                 tree_t *tmp_tree;
107
108                 for(tmp_tree=t->left;tmp_tree->right;tmp_tree=tmp_tree->right)
109                         ;
110                 tmp_tree->right = t->right;
111
112                 if (t->parent == NULL) {
113                         nfsio->fhandles = tmp_tree;
114                         free_node(t);
115                         return;
116                 }
117
118                 if (t->parent->left == t) {
119                         t->parent->left = t->left;
120                         free_node(t);
121                         return;
122                 }
123
124                 t->parent->right = t->left;
125                 free_node(t);
126                 return;
127         }
128
129         /* we only have a right child */
130         if (t->right) {
131                 tree_t *tmp_tree;
132
133                 for(tmp_tree=t->right;tmp_tree->left;tmp_tree=tmp_tree->left)
134                         ;
135                 tmp_tree->left = t->left;
136
137                 if (t->parent == NULL) {
138                         nfsio->fhandles = tmp_tree;
139                         free_node(t);
140                         return;
141                 }
142
143                 if (t->parent->left == t) {
144                         t->parent->left = t->right;
145                         free_node(t);
146                         return;
147                 }
148
149                 t->parent->right = t->right;
150                 free_node(t);
151                 return;
152         }
153
154         /* we are a leaf node */
155         if (t->parent == NULL) {
156                 nfsio->fhandles = NULL;
157         } else {
158                 if (t->parent->left == t) {
159                         t->parent->left = NULL;
160                 } else {
161                         t->parent->right = NULL;
162                 }
163         }
164         free_node(t);
165         return;
166 }
167
168 static void insert_fhandle(struct nfsio *nfsio, const char *name, const char *fhandle, int length)
169 {
170         tree_t *tmp_t;
171         tree_t *t;
172         int i;
173
174         while (name[0] == '.') name++;
175
176         t = malloc(sizeof(tree_t));
177         if (t == NULL) {
178                 fprintf(stderr, "MALLOC failed to allocate tree_t in insert_fhandle\n");
179                 exit(10);
180         }
181
182         t->key.dptr = strdup(name);
183         if (t->key.dptr == NULL) {
184                 fprintf(stderr, "STRDUP failed to allocate key in insert_fhandle\n");
185                 exit(10);
186         }
187         t->key.dsize = strlen(name);
188
189
190         t->fh.dptr = malloc(length);
191         if (t->key.dptr == NULL) {
192                 fprintf(stderr, "MALLOC failed to allocate fhandle in insert_fhandle\n");
193                 exit(10);
194         }
195         memcpy(discard_const(t->fh.dptr), fhandle, length);
196         t->fh.dsize = length;   
197         
198         t->left   = NULL;
199         t->right  = NULL;
200         t->parent = NULL;
201
202         if (nfsio->fhandles == NULL) {
203                 nfsio->fhandles = t;
204                 return;
205         }
206
207         tmp_t = nfsio->fhandles;
208 again:
209         i = strcmp(t->key.dptr, tmp_t->key.dptr);
210         if (i == 0) {
211                 free(discard_const(tmp_t->fh.dptr));
212                 tmp_t->fh.dsize = t->fh.dsize;
213                 tmp_t->fh.dptr  = t->fh.dptr;
214                 free(discard_const(t->key.dptr));
215                 free(t);
216                 return;
217         }
218         if (i < 0) {
219                 if (tmp_t->left == NULL) {
220                         tmp_t->left = t;
221                         t->parent = tmp_t;
222                         return;
223                 }
224                 tmp_t = tmp_t->left;
225                 goto again;
226         }
227         if (tmp_t->right == NULL) {
228                 tmp_t->right = t;
229                 t->parent = tmp_t;
230                 return;
231         }
232         tmp_t = tmp_t->right;
233         goto again;
234 }
235
236
237 struct nfs_errors {
238         const char *err;
239         int idx;
240 };
241
242 static const struct nfs_errors nfs_errors[] = {
243         {"NFS3_OK", 0},
244         {"NFS3ERR_PERM", 1},
245         {"NFS3ERR_NOENT", 2},
246         {"NFS3ERR_IO", 5},
247         {"NFS3ERR_NXIO", 6},
248         {"NFS3ERR_ACCES", 13},
249         {"NFS3ERR_EXIST", 17},
250         {"NFS3ERR_XDEV", 18},
251         {"NFS3ERR_NODEV", 19},
252         {"NFS3ERR_NOTDIR", 20},
253         {"NFS3ERR_ISDIR", 21},
254         {"NFS3ERR_INVAL", 22},
255         {"NFS3ERR_FBIG", 27},
256         {"NFS3ERR_NOSPC", 28},
257         {"NFS3ERR_ROFS", 30},
258         {"NFS3ERR_MLINK", 31},
259         {"NFS3ERR_NAMETOOLONG", 63},
260         {"NFS3ERR_NOTEMPTY", 66},
261         {"NFS3ERR_DQUOT", 69},
262         {"NFS3ERR_STALE", 70},
263         {"NFS3ERR_REMOTE", 71},
264         {"NFS3ERR_BADHANDLE", 10001},
265         {"NFS3ERR_NOT_SYNC", 10002},
266         {"NFS3ERR_BAD_COOKIE", 10003},
267         {"NFS3ERR_NOTSUPP", 10004},
268         {"NFS3ERR_TOOSMALL", 10005},
269         {"NFS3ERR_SERVERFAULT", 10006},
270         {"NFS3ERR_BADTYPE", 10007},
271         {"NFS3ERR_JUKEBOX", 10008},
272 };
273
274
275
276 const char *nfs_error(int error)
277 {
278         unsigned int i;
279
280         for(i=0;i<sizeof(nfs_errors)/sizeof(struct nfs_errors);i++) {
281                 if (error == nfs_errors[i].idx) {
282                         return nfs_errors[i].err;
283                 }
284         }
285         return "Unknown NFS error";
286 }
287
288
289
290
291 void nfsio_disconnect(struct nfsio *nfsio)
292 {
293         if (nfsio->clnt != NULL) {
294                 clnt_destroy(nfsio->clnt);
295                 nfsio->clnt = NULL;
296         }
297         if (nfsio->s != -1) {
298                 close(nfsio->s);
299         }
300         // qqq free the tree*/
301
302         free(nfsio);
303 }
304
305
306
307
308 struct nfsio *nfsio_connect(const char *server, const char *export, const char *protocol)
309 {
310         dirpath mountdir=discard_const(export);
311         struct nfsio *nfsio;
312         mountres3 *mountres;
313         fhandle3 *fh;
314         struct sockaddr_in sin;
315         int ret;
316
317         nfsio = malloc(sizeof(struct nfsio));
318         if (nfsio == NULL) {
319                 fprintf(stderr, "Failed to malloc nfsio\n");
320                 return NULL;
321         }
322         bzero(nfsio, sizeof(struct nfsio));
323
324         nfsio->s = -1;
325
326
327         /*
328          * set up the MOUNT client. If we are running as root, we get
329          * a port <1024 by default. If we are not root, we can not
330          * bind to these ports, so the server must be in "insecure"
331          * mode.
332          */
333         memset(&sin, 0, sizeof(sin));
334         sin.sin_port = 0;
335         sin.sin_family = PF_INET;
336         if (inet_aton(server, &sin.sin_addr) == 0) {
337                 fprintf(stderr, "Invalid address '%s'\n", server);
338                 nfsio_disconnect(nfsio);
339                 return NULL;
340         }
341
342         if (!strcmp(protocol, "tcp")) {
343                 nfsio->s = RPC_ANYSOCK;
344                 nfsio->clnt = clnttcp_create(&sin, MOUNT_PROGRAM, MOUNT_V3, &nfsio->s, 32768, 32768);
345         } else {
346                 struct timeval wait;
347
348                 wait.tv_sec  = 5;
349                 wait.tv_usec = 0;
350                 nfsio->s = RPC_ANYSOCK;
351                 nfsio->clnt = clntudp_create(&sin, MOUNT_PROGRAM, MOUNT_V3, wait, &nfsio->s);
352         }
353
354         if (nfsio->clnt == NULL) {
355                 printf("ERROR: failed to connect to MOUNT daemon on %s\n", server);
356                 nfsio_disconnect(nfsio);
357                 return NULL;
358         }
359         nfsio->clnt->cl_auth = authunix_create_default();
360
361         mountres=mountproc3_mnt_3(&mountdir, nfsio->clnt);
362         if (mountres == NULL) {
363                 printf("ERROR: failed to call the MNT procedure\n");
364                 nfsio_disconnect(nfsio);
365                 return NULL;
366         }
367         if (mountres->fhs_status != MNT3_OK) {
368                 printf("ERROR: Server returned error %d when trying to MNT\n",mountres->fhs_status);
369                 nfsio_disconnect(nfsio);
370                 return NULL;
371         }
372
373         fh = &mountres->mountres3_u.mountinfo.fhandle;
374         insert_fhandle(nfsio, "/", fh->fhandle3_val, fh->fhandle3_len);
375
376
377         /* we dont need the mount client any more */
378         clnt_destroy(nfsio->clnt);
379         nfsio->clnt = NULL;
380         close(nfsio->s);
381         nfsio->s = -1;
382
383
384         /*
385          * set up the NFS client. If we are running as root, we get
386          * a port <1024 by default. If we are not root, we can not
387          * bind to these ports, so the server must be in "insecure"
388          * mode.
389          */
390         memset(&sin, 0, sizeof(sin));
391         sin.sin_port = 0;
392         sin.sin_family = PF_INET;
393         if (inet_aton(server, &sin.sin_addr) == 0) {
394                 fprintf(stderr, "Invalid address '%s'\n", server);
395                 nfsio_disconnect(nfsio);
396                 return NULL;
397         }
398
399         if (!strcmp(protocol, "tcp")) {
400                 nfsio->s = RPC_ANYSOCK;
401                 nfsio->clnt = clnttcp_create(&sin, NFS_PROGRAM, NFS_V3, &nfsio->s, 327680, 327680);
402         } else {
403                 struct timeval wait;
404
405                 wait.tv_sec  = 5;
406                 wait.tv_usec = 0;
407                 nfsio->s = RPC_ANYSOCK;
408                 nfsio->clnt = clntudp_create(&sin, NFS_PROGRAM, NFS_V3, wait, &nfsio->s);
409         }
410
411         if (nfsio->clnt == NULL) {
412                 fprintf(stderr, "Failed to initialize nfs client structure\n");
413                 nfsio_disconnect(nfsio);
414                 return NULL;
415         }
416         nfsio->clnt->cl_auth = authunix_create_default();
417
418         return nfsio;
419 }
420
421
422 nfsstat3 nfsio_getattr(struct nfsio *nfsio, const char *name, fattr3 *attributes)
423 {
424         struct GETATTR3args GETATTR3args;
425         struct GETATTR3res *GETATTR3res;
426         data_t *fh;
427
428         fh = lookup_fhandle(nfsio, name);
429         if (fh == NULL) {
430                 fprintf(stderr, "failed to fetch handle in nfsio_getattr\n");
431                 return NFS3ERR_SERVERFAULT;
432         }
433
434         GETATTR3args.object.data.data_len = fh->dsize;
435         GETATTR3args.object.data.data_val = discard_const(fh->dptr);
436
437         GETATTR3res = nfsproc3_getattr_3(&GETATTR3args, nfsio->clnt);
438
439         if (GETATTR3res == NULL) {
440                 fprintf(stderr, "nfsproc3_getattr_3 failed in getattr\n");
441                 return NFS3ERR_SERVERFAULT;
442         }
443
444         if (GETATTR3res->status != NFS3_OK) {
445                 fprintf(stderr, "nfsproc3_getattr_3 failed in getattr. status:%d\n", GETATTR3res->status);
446                 return GETATTR3res->status;
447         }
448
449         if (attributes) {
450                 memcpy(attributes, &GETATTR3res->GETATTR3res_u.resok.obj_attributes, sizeof(fattr3));
451         }
452
453         return NFS3_OK;
454 }
455
456 nfsstat3 nfsio_lookup(struct nfsio *nfsio, const char *name, fattr3 *attributes)
457 {
458
459         struct LOOKUP3args LOOKUP3args;
460         struct LOOKUP3res *LOOKUP3res;
461         char *tmp_name = NULL;
462         int ret = NFS3_OK;
463         data_t *fh;
464         char *ptr;
465
466         tmp_name = strdup(name);
467         if (tmp_name == NULL) {
468                 fprintf(stderr, "failed to strdup name in nfsio_lookup\n");
469                 ret = NFS3ERR_SERVERFAULT;
470                 goto finished;
471         }
472
473         ptr = rindex(tmp_name, '/');
474         if (ptr == NULL) {      
475                 fprintf(stderr, "name did not contain '/' in nfsio_lookup\n");
476                 ret = NFS3ERR_SERVERFAULT;
477                 goto finished;
478         }
479
480         *ptr = 0;
481         ptr++;
482
483         fh = lookup_fhandle(nfsio, tmp_name);
484         if (fh == NULL) {
485                 fprintf(stderr, "failed to fetch parent handle for '%s' in nfsio_lookup\n", tmp_name);
486                 ret = NFS3ERR_SERVERFAULT;
487                 goto finished;
488         }
489
490         LOOKUP3args.what.dir.data.data_len = fh->dsize;
491         LOOKUP3args.what.dir.data.data_val = discard_const(fh->dptr);
492         LOOKUP3args.what.name = ptr;
493
494         LOOKUP3res = nfsproc3_lookup_3(&LOOKUP3args, nfsio->clnt);
495
496         if (LOOKUP3res == NULL) {
497                 fprintf(stderr, "nfsproc3_lookup_3 failed in lookup\n");
498                 ret = NFS3ERR_SERVERFAULT;
499                 goto finished;
500         }
501
502         if (LOOKUP3res->status != NFS3_OK) {
503                 ret = LOOKUP3res->status;
504                 goto finished;
505         }
506
507
508         insert_fhandle(nfsio, name, 
509                         LOOKUP3res->LOOKUP3res_u.resok.object.data.data_val,
510                         LOOKUP3res->LOOKUP3res_u.resok.object.data.data_len);
511
512         if (attributes) {
513                 memcpy(attributes, &LOOKUP3res->LOOKUP3res_u.resok.obj_attributes.post_op_attr_u.attributes, sizeof(fattr3));
514         }
515
516 finished:
517         if (tmp_name) {
518                 free(tmp_name);
519         }
520         return ret;
521 }
522
523
524 nfsstat3 nfsio_access(struct nfsio *nfsio, const char *name, uint32 desired, uint32 *access)
525 {
526
527         struct ACCESS3args ACCESS3args;
528         struct ACCESS3res *ACCESS3res;
529         data_t *fh;
530
531         fh = lookup_fhandle(nfsio, name);
532         if (fh == NULL) {
533                 fprintf(stderr, "failed to fetch handle in nfsio_access\n");
534                 return NFS3ERR_SERVERFAULT;
535         }
536
537         ACCESS3args.object.data.data_val = discard_const(fh->dptr);
538         ACCESS3args.object.data.data_len = fh->dsize;
539         ACCESS3args.access = desired;
540
541         ACCESS3res = nfsproc3_access_3(&ACCESS3args, nfsio->clnt);
542
543         if (ACCESS3res == NULL) {
544                 fprintf(stderr, "nfsproc3_access_3 failed in access\n");
545                 return NFS3ERR_SERVERFAULT;
546         }
547
548         if (ACCESS3res->status != NFS3_OK) {
549                 fprintf(stderr, "nfsproc3_access_3 failed. status:%d\n", 
550 ACCESS3res->status);
551                 return ACCESS3res->status;
552         }
553
554         if (access) {
555                 *access = ACCESS3res->ACCESS3res_u.resok.access;
556         }
557
558         return NFS3_OK;
559 }
560
561
562
563 nfsstat3 nfsio_create(struct nfsio *nfsio, const char *name)
564 {
565
566         struct CREATE3args CREATE3args;
567         struct CREATE3res *CREATE3res;
568         char *tmp_name = NULL;
569         data_t *fh;
570         char *ptr;
571         int ret = NFS3_OK;
572
573         tmp_name = strdup(name);
574         if (tmp_name == NULL) {
575                 fprintf(stderr, "failed to strdup name in nfsio_create\n");
576                 ret = NFS3ERR_SERVERFAULT;
577                 goto finished;
578         }
579
580         ptr = rindex(tmp_name, '/');
581         if (ptr == NULL) {      
582                 fprintf(stderr, "name did not contain '/' in nfsio_create\n");
583                 ret = NFS3ERR_SERVERFAULT;
584                 goto finished;
585         }
586
587         *ptr = 0;
588         ptr++;
589
590         fh = lookup_fhandle(nfsio, tmp_name);
591         if (fh == NULL) {
592                 fprintf(stderr, "failed to fetch parent handle in nfsio_create\n");
593                 ret = NFS3ERR_SERVERFAULT;
594                 goto finished;
595         }
596
597         CREATE3args.where.dir.data.data_len  = fh->dsize;
598         CREATE3args.where.dir.data.data_val  = discard_const(fh->dptr);
599         CREATE3args.where.name               = ptr;
600
601         CREATE3args.how.mode = UNCHECKED;
602         CREATE3args.how.createhow3_u.obj_attributes.mode.set_it  = TRUE;
603         CREATE3args.how.createhow3_u.obj_attributes.mode.set_mode3_u.mode    = 0777;
604         CREATE3args.how.createhow3_u.obj_attributes.uid.set_it   = TRUE;
605         CREATE3args.how.createhow3_u.obj_attributes.uid.set_uid3_u.uid      = 0;
606         CREATE3args.how.createhow3_u.obj_attributes.gid.set_it   = TRUE;
607         CREATE3args.how.createhow3_u.obj_attributes.gid.set_gid3_u.gid      = 0;
608         CREATE3args.how.createhow3_u.obj_attributes.size.set_it  = FALSE;
609         CREATE3args.how.createhow3_u.obj_attributes.atime.set_it = FALSE;
610         CREATE3args.how.createhow3_u.obj_attributes.mtime.set_it = FALSE;
611
612         CREATE3res = nfsproc3_create_3(&CREATE3args, nfsio->clnt);
613
614         if (CREATE3res == NULL) {
615                 fprintf(stderr, "nfsproc3_create_3 failed in nfsio_create\n");
616                 ret = NFS3ERR_SERVERFAULT;
617                 goto finished;
618         }
619
620         if (CREATE3res->status != NFS3_OK) {
621                 fprintf(stderr, "nfsproc3_create_3 failed in nfsio_create. status:%d\n", CREATE3res->status);
622                 ret = CREATE3res->status;
623                 goto finished;
624         }
625
626
627         insert_fhandle(nfsio, name, 
628                 CREATE3res->CREATE3res_u.resok.obj.post_op_fh3_u.handle.data.data_val,
629                 CREATE3res->CREATE3res_u.resok.obj.post_op_fh3_u.handle.data.data_len);
630
631
632 finished:
633         if (tmp_name) {
634                 free(tmp_name);
635         }
636         return ret;
637 }
638
639 nfsstat3 nfsio_remove(struct nfsio *nfsio, const char *name)
640 {
641
642         struct REMOVE3args REMOVE3args;
643         struct REMOVE3res *REMOVE3res;
644         int ret = NFS3_OK;
645         char *tmp_name = NULL;
646         data_t *fh;
647         char *ptr;
648
649         tmp_name = strdup(name);
650         if (tmp_name == NULL) {
651                 fprintf(stderr, "failed to strdup name in nfsio_remove\n");
652                 ret = NFS3ERR_SERVERFAULT;
653                 goto finished;
654         }
655
656         ptr = rindex(tmp_name, '/');
657         if (ptr == NULL) {      
658                 fprintf(stderr, "name did not contain '/' in nfsio_remove\n");
659                 ret = NFS3ERR_SERVERFAULT;
660                 goto finished;
661         }
662
663         *ptr = 0;
664         ptr++;
665
666         fh = lookup_fhandle(nfsio, tmp_name);
667         if (fh == NULL) {
668                 fprintf(stderr, "failed to fetch parent handle in nfsio_remove\n");
669                 ret = NFS3ERR_SERVERFAULT;
670                 goto finished;
671         }
672
673
674         REMOVE3args.object.dir.data.data_len  = fh->dsize;
675         REMOVE3args.object.dir.data.data_val  = discard_const(fh->dptr);
676         REMOVE3args.object.name               = ptr;
677
678         REMOVE3res = nfsproc3_remove_3(&REMOVE3args, nfsio->clnt);
679
680         if (REMOVE3res == NULL) {
681                 fprintf(stderr, "nfsproc3_remove_3 failed in nfsio_remove\n");
682                 ret = NFS3ERR_SERVERFAULT;
683                 goto finished;
684         }
685
686         if (REMOVE3res->status != NFS3_OK) {
687                 fprintf(stderr, "nfsproc3_remove_3 failed in nfsio_remove. status:%d\n", REMOVE3res->status);
688                 ret = REMOVE3res->status;
689                 goto finished;
690         }
691
692
693         delete_fhandle(nfsio, name);
694
695
696 finished:
697         if (tmp_name) {
698                 free(tmp_name);
699         }
700         return ret;
701 }
702
703
704 nfsstat3 nfsio_write(struct nfsio *nfsio, const char *name, char *buf, uint32 offset, int len, int stable)
705 {
706         struct WRITE3args WRITE3args;
707         struct WRITE3res *WRITE3res;
708         int ret = NFS3_OK;
709         data_t *fh;
710
711         fh = lookup_fhandle(nfsio, name);
712         if (fh == NULL) {
713                 fprintf(stderr, "failed to fetch handle in nfsio_write\n");
714                 ret = NFS3ERR_SERVERFAULT;
715                 goto finished;
716         }
717
718         WRITE3args.file.data.data_len = fh->dsize;
719         WRITE3args.file.data.data_val = discard_const(fh->dptr);
720         WRITE3args.offset             = offset;
721         WRITE3args.count              = len;
722         WRITE3args.stable             = stable;
723         WRITE3args.data.data_len      = len;
724         WRITE3args.data.data_val      = buf;
725
726
727         WRITE3res = nfsproc3_write_3(&WRITE3args, nfsio->clnt);
728
729         if (WRITE3res == NULL) {
730                 fprintf(stderr, "nfsproc3_write_3 failed in nfsio_write\n");
731                 ret = NFS3ERR_SERVERFAULT;
732                 goto finished;
733         }
734
735         if (WRITE3res->status != NFS3_OK) {
736                 fprintf(stderr, "nfsproc3_write_3 failed in getattr. status:%d\n", WRITE3res->status);
737                 ret = WRITE3res->status;
738         }
739
740 finished:
741         return ret;
742 }
743
744 nfsstat3 nfsio_read(struct nfsio *nfsio, const char *name, char *buf, uint32 offset, int len, int *count, int *eof)
745 {
746         struct READ3args READ3args;
747         struct READ3res *READ3res;
748         int ret = NFS3_OK;
749         data_t *fh;
750
751         fh = lookup_fhandle(nfsio, name);
752         if (fh == NULL) {
753                 fprintf(stderr, "failed to fetch handle in nfsio_read\n");
754                 ret = NFS3ERR_SERVERFAULT;
755                 goto finished;
756         }
757
758         READ3args.file.data.data_len = fh->dsize;
759         READ3args.file.data.data_val = discard_const(fh->dptr);
760         READ3args.offset             = offset;
761         READ3args.count              = len;
762
763         READ3res = nfsproc3_read_3(&READ3args, nfsio->clnt);
764
765         if (READ3res == NULL) {
766                 fprintf(stderr, "nfsproc3_read_3 failed in nfsio_read\n");
767                 ret = NFS3ERR_SERVERFAULT;
768                 goto finished;
769         }
770
771         if (READ3res->status != NFS3_OK) {
772                 fprintf(stderr, "nfsproc3_read_3 failed in nfsio_read. status:%d\n", READ3res->status);
773                 ret = READ3res->status;
774                 goto finished;
775         }
776
777         if (count) {
778                 *count = READ3res->READ3res_u.resok.count;
779         }
780         if (eof) {
781                 *eof = READ3res->READ3res_u.resok.eof;
782         }
783         memcpy(buf, &READ3res->READ3res_u.resok.data.data_val,
784                                 READ3res->READ3res_u.resok.count);
785
786
787 finished:
788         return ret;
789 }
790
791
792 nfsstat3 nfsio_commit(struct nfsio *nfsio, const char *name)
793 {
794         struct COMMIT3args COMMIT3args;
795         struct COMMIT3res *COMMIT3res;  
796         int ret = NFS3_OK;
797         data_t *fh;
798
799         fh = lookup_fhandle(nfsio, name);
800         if (fh == NULL) {
801                 fprintf(stderr, "failed to fetch handle in nfsio_commit\n");
802                 ret = NFS3ERR_SERVERFAULT;
803                 goto finished;
804         }
805
806         COMMIT3args.file.data.data_len = fh->dsize;
807         COMMIT3args.file.data.data_val = discard_const(fh->dptr);
808         COMMIT3args.offset             = 0;
809         COMMIT3args.count              = 0;
810
811
812         COMMIT3res = nfsproc3_commit_3(&COMMIT3args, nfsio->clnt);
813
814         if (COMMIT3res == NULL) {
815                 fprintf(stderr, "nfsproc3_commit_3 failed in nfsio_commit\n");
816                 ret = NFS3ERR_SERVERFAULT;
817                 goto finished;
818         }
819
820         if (COMMIT3res->status != NFS3_OK) {
821                 fprintf(stderr, "nfsproc3_commit_3 failed in nfsio_commit. status:%d\n", COMMIT3res->status);
822                 ret = COMMIT3res->status;
823                 goto finished;
824         }
825
826 finished:
827         return ret;
828 }
829
830 nfsstat3 nfsio_fsinfo(struct nfsio *nfsio)
831 {
832         struct FSINFO3args FSINFO3args;
833         struct FSINFO3res *FSINFO3res;
834         data_t *fh;
835
836         fh = lookup_fhandle(nfsio, "/");
837         if (fh == NULL) {
838                 fprintf(stderr, "failed to fetch handle in nfsio_fsinfo\n");
839                 return NFS3ERR_SERVERFAULT;
840         }
841
842         FSINFO3args.fsroot.data.data_len = fh->dsize;
843         FSINFO3args.fsroot.data.data_val = discard_const(fh->dptr);
844
845         FSINFO3res = nfsproc3_fsinfo_3(&FSINFO3args, nfsio->clnt);
846
847         if (FSINFO3res == NULL) {
848                 fprintf(stderr, "nfsproc3_fsinfo_3 failed in nfsio_fsinfo\n");
849                 return NFS3ERR_SERVERFAULT;
850         }
851
852         if (FSINFO3res->status != NFS3_OK) {
853                 fprintf(stderr, "nfsproc3_fsinfo_3 failed in nfsio_fsinfo. status:%d\n", FSINFO3res->status);
854                 return FSINFO3res->status;
855         }
856
857         return NFS3_OK;
858 }
859
860
861 nfsstat3 nfsio_fsstat(struct nfsio *nfsio)
862 {
863         struct FSSTAT3args FSSTAT3args;
864         struct FSSTAT3res *FSSTAT3res;
865         data_t *fh;
866
867         fh = lookup_fhandle(nfsio, "/");
868         if (fh == NULL) {
869                 fprintf(stderr, "failed to fetch handle in nfsio_fsstat\n");
870                 return NFS3ERR_SERVERFAULT;
871         }
872
873         FSSTAT3args.fsroot.data.data_len = fh->dsize;
874         FSSTAT3args.fsroot.data.data_val = discard_const(fh->dptr);
875
876         FSSTAT3res = nfsproc3_fsstat_3(&FSSTAT3args, nfsio->clnt);
877
878         if (FSSTAT3res == NULL) {
879                 fprintf(stderr, "nfsproc3_fsstat_3 failed in nfsio_fsstat\n");
880                 return NFS3ERR_SERVERFAULT;
881         }
882
883         if (FSSTAT3res->status != NFS3_OK) {
884                 fprintf(stderr, "nfsproc3_fsstat_3 failed in nfsio_fsstat. status:%d\n", FSSTAT3res->status);
885                 return FSSTAT3res->status;
886         }
887
888         return NFS3_OK;
889 }
890
891 nfsstat3 nfsio_pathconf(struct nfsio *nfsio, char *name)
892 {
893         struct PATHCONF3args PATHCONF3args;
894         struct PATHCONF3res *PATHCONF3res;
895         data_t *fh;
896
897         fh = lookup_fhandle(nfsio, name);
898         if (fh == NULL) {
899                 fprintf(stderr, "failed to fetch handle in nfsio_pathconf\n");
900                 return NFS3ERR_SERVERFAULT;
901         }
902
903         PATHCONF3args.object.data.data_len = fh->dsize;
904         PATHCONF3args.object.data.data_val = discard_const(fh->dptr);
905
906         PATHCONF3res = nfsproc3_pathconf_3(&PATHCONF3args, nfsio->clnt);
907
908         if (PATHCONF3res == NULL) {
909                 fprintf(stderr, "nfsproc3_pathconf_3 failed in nfsio_pathconf\n");
910                 return NFS3ERR_SERVERFAULT;
911         }
912
913         if (PATHCONF3res->status != NFS3_OK) {
914                 fprintf(stderr, "nfsproc3_pathconf_3 failed in nfsio_pathconf. status:%d\n", PATHCONF3res->status);
915                 return PATHCONF3res->status;
916         }
917
918         return NFS3_OK;
919 }
920
921
922 nfsstat3 nfsio_symlink(struct nfsio *nfsio, const char *old, const char *new)
923 {
924
925         struct SYMLINK3args SYMLINK3args;
926         struct SYMLINK3res *SYMLINK3res;
927         int ret = NFS3_OK;
928         char *tmp_name = NULL;
929         data_t *fh;
930         char *ptr;
931
932         tmp_name = strdup(old);
933         if (tmp_name == NULL) {
934                 fprintf(stderr, "failed to strdup name in nfsio_symlink\n");
935                 ret = NFS3ERR_SERVERFAULT;
936                 goto finished;
937         }
938
939         ptr = rindex(tmp_name, '/');
940         if (ptr == NULL) {      
941                 fprintf(stderr, "name did not contain '/' in nfsio_symlink\n");
942                 ret = NFS3ERR_SERVERFAULT;
943                 goto finished;
944         }
945
946         *ptr = 0;
947         ptr++;
948
949         fh = lookup_fhandle(nfsio, tmp_name);
950         if (fh == NULL) {
951                 fprintf(stderr, "failed to fetch parent handle in nfsio_symlink\n");
952                 ret = NFS3ERR_SERVERFAULT;
953                 goto finished;
954         }
955
956
957         SYMLINK3args.where.dir.data.data_len  = fh->dsize;
958         SYMLINK3args.where.dir.data.data_val  = discard_const(fh->dptr);
959         SYMLINK3args.where.name               = ptr;
960
961         SYMLINK3args.symlink.symlink_attributes.mode.set_it = TRUE;
962         SYMLINK3args.symlink.symlink_attributes.mode.set_mode3_u.mode = 0777;
963         SYMLINK3args.symlink.symlink_attributes.uid.set_it = TRUE;
964         SYMLINK3args.symlink.symlink_attributes.uid.set_uid3_u.uid= 0;
965         SYMLINK3args.symlink.symlink_attributes.gid.set_it = TRUE;
966         SYMLINK3args.symlink.symlink_attributes.gid.set_gid3_u.gid = 0;
967         SYMLINK3args.symlink.symlink_attributes.size.set_it = FALSE;
968         SYMLINK3args.symlink.symlink_attributes.atime.set_it = FALSE;
969         SYMLINK3args.symlink.symlink_attributes.mtime.set_it = FALSE;
970         SYMLINK3args.symlink.symlink_data     = discard_const(new);
971
972
973         SYMLINK3res = nfsproc3_symlink_3(&SYMLINK3args, nfsio->clnt);
974
975         if (SYMLINK3res == NULL) {
976                 fprintf(stderr, "nfsproc3_symlink_3 failed in nfsio_symlink\n");
977                 ret = NFS3ERR_SERVERFAULT;
978                 goto finished;
979         }
980
981         if (SYMLINK3res->status != NFS3_OK) {
982                 fprintf(stderr, "nfsproc3_symlink_3 failed in nfsio_symlink. status:%d\n", SYMLINK3res->status);
983                 ret = SYMLINK3res->status;
984                 goto finished;
985         }
986
987
988         insert_fhandle(nfsio, old, 
989                 SYMLINK3res->SYMLINK3res_u.resok.obj.post_op_fh3_u.handle.data.data_val,
990                 SYMLINK3res->SYMLINK3res_u.resok.obj.post_op_fh3_u.handle.data.data_len);
991
992
993 finished:
994         if (tmp_name) {
995                 free(tmp_name);
996         }
997         return ret;
998 }
999
1000
1001 nfsstat3 nfsio_link(struct nfsio *nfsio, const char *old, const char *new)
1002 {
1003
1004         struct LINK3args LINK3args;
1005         struct LINK3res *LINK3res;
1006         int ret = NFS3_OK;
1007         char *tmp_name = NULL;
1008         data_t *fh, *new_fh;
1009         char *ptr;
1010
1011         tmp_name = strdup(old);
1012         if (tmp_name == NULL) {
1013                 fprintf(stderr, "failed to strdup name in nfsio_link\n");
1014                 ret = NFS3ERR_SERVERFAULT;
1015                 goto finished;
1016         }
1017
1018         ptr = rindex(tmp_name, '/');
1019         if (ptr == NULL) {      
1020                 fprintf(stderr, "name did not contain '/' in nfsio_link\n");
1021                 ret = NFS3ERR_SERVERFAULT;
1022                 goto finished;
1023         }
1024
1025         *ptr = 0;
1026         ptr++;
1027
1028         fh = lookup_fhandle(nfsio, tmp_name);
1029         if (fh == NULL) {
1030                 fprintf(stderr, "failed to fetch parent handle in nfsio_link\n");
1031                 ret = NFS3ERR_SERVERFAULT;
1032                 goto finished;
1033         }
1034
1035
1036         new_fh = lookup_fhandle(nfsio, new);
1037         if (new_fh == NULL) {
1038                 fprintf(stderr, "failed to fetch handle in nfsio_link\n");
1039                 ret = NFS3ERR_SERVERFAULT;
1040                 goto finished;
1041         }
1042
1043
1044         LINK3args.file.data.data_len  = new_fh->dsize;
1045         LINK3args.file.data.data_val  = discard_const(new_fh->dptr);
1046
1047
1048         LINK3args.link.dir.data.data_len  = fh->dsize;
1049         LINK3args.link.dir.data.data_val  = discard_const(fh->dptr);
1050         LINK3args.link.name               = ptr;
1051
1052         LINK3res = nfsproc3_link_3(&LINK3args, nfsio->clnt);
1053
1054         if (LINK3res == NULL) {
1055                 fprintf(stderr, "nfsproc3_link_3 failed in nfsio_link\n");
1056                 ret = NFS3ERR_SERVERFAULT;
1057                 goto finished;
1058         }
1059
1060         if (LINK3res->status != NFS3_OK) {
1061                 fprintf(stderr, "nfsproc3_link_3 failed in nfsio_link. status:%d\n", LINK3res->status);
1062                 ret = LINK3res->status;
1063                 goto finished;
1064         }
1065
1066
1067 //      insert_fhandle(nfsio, old, 
1068 //              LINK3res->LINK3res_u.resok.obj.post_op_fh3_u.handle.data.data_val,
1069 //              LINK3res->LINK3res_u.resok.obj.post_op_fh3_u.handle.data.data_len);
1070
1071
1072 finished:
1073         if (tmp_name) {
1074                 free(tmp_name);
1075         }
1076         return ret;
1077 }
1078
1079
1080
1081 nfsstat3 nfsio_readlink(struct nfsio *nfsio, char *name, char **link_name)
1082 {
1083         struct READLINK3args READLINK3args;
1084         struct READLINK3res *READLINK3res;
1085         data_t *fh;
1086
1087         fh = lookup_fhandle(nfsio, name);
1088         if (fh == NULL) {
1089                 fprintf(stderr, "failed to fetch handle in nfsio_readlink\n");
1090                 return NFS3ERR_SERVERFAULT;
1091         }
1092
1093
1094         READLINK3args.symlink.data.data_len  = fh->dsize;
1095         READLINK3args.symlink.data.data_val  = discard_const(fh->dptr);
1096
1097         READLINK3res = nfsproc3_readlink_3(&READLINK3args, nfsio->clnt);
1098
1099         if (READLINK3res == NULL) {
1100                 fprintf(stderr, "nfsproc3_readlink_3 failed in nfsio_readlink\n");
1101                 return NFS3ERR_SERVERFAULT;
1102         }
1103
1104         if (READLINK3res->status != NFS3_OK) {
1105                 fprintf(stderr, "nfsproc3_readlink_3 failed in nfsio_readlink. status:%d\n", READLINK3res->status);
1106                 return READLINK3res->status;
1107         }
1108
1109         if (link_name) {
1110                 *link_name = strdup(READLINK3res->READLINK3res_u.resok.data);
1111         }
1112
1113         return NFS3_OK;
1114 }
1115
1116
1117 nfsstat3 nfsio_rmdir(struct nfsio *nfsio, const char *name)
1118 {
1119
1120         struct RMDIR3args RMDIR3args;
1121         struct RMDIR3res *RMDIR3res;
1122         int ret = NFS3_OK;
1123         char *tmp_name = NULL;
1124         data_t *fh;
1125         char *ptr;
1126
1127         tmp_name = strdup(name);
1128         if (tmp_name == NULL) {
1129                 fprintf(stderr, "failed to strdup name in nfsio_rmdir\n");
1130                 return NFS3ERR_SERVERFAULT;
1131         }
1132
1133         ptr = rindex(tmp_name, '/');
1134         if (ptr == NULL) {      
1135                 fprintf(stderr, "name did not contain '/' in nfsio_rmdir\n");
1136                 ret = NFS3ERR_SERVERFAULT;
1137                 goto finished;
1138         }
1139
1140         *ptr = 0;
1141         ptr++;
1142
1143         fh = lookup_fhandle(nfsio, tmp_name);
1144         if (fh == NULL) {
1145                 fprintf(stderr, "failed to fetch parent handle in nfsio_rmdir\n");
1146                 ret = NFS3ERR_SERVERFAULT;
1147                 goto finished;
1148         }
1149
1150
1151         RMDIR3args.object.dir.data.data_len  = fh->dsize;
1152         RMDIR3args.object.dir.data.data_val  = discard_const(fh->dptr);
1153         RMDIR3args.object.name               = ptr;
1154
1155         RMDIR3res = nfsproc3_rmdir_3(&RMDIR3args, nfsio->clnt);
1156
1157         if (RMDIR3res == NULL) {
1158                 fprintf(stderr, "nfsproc3_rmdir_3 failed in nfsio_rmdir\n");
1159                 ret = NFS3ERR_SERVERFAULT;
1160                 goto finished;
1161         }
1162
1163         if (RMDIR3res->status != NFS3_OK) {
1164                 fprintf(stderr, "nfsproc3_rmdir_3(%s) failed in nfsio_rmdir. status:%s(%d)\n", name, nfs_error(RMDIR3res->status), RMDIR3res->status);
1165                 ret = RMDIR3res->status;
1166                 goto finished;
1167         }
1168
1169
1170         delete_fhandle(nfsio, name);
1171
1172
1173 finished:
1174         if (tmp_name) {
1175                 free(tmp_name);
1176         }
1177         return ret;
1178 }
1179
1180
1181
1182 nfsstat3 nfsio_mkdir(struct nfsio *nfsio, const char *name)
1183 {
1184
1185         struct MKDIR3args MKDIR3args;
1186         struct MKDIR3res *MKDIR3res;
1187         int ret = NFS3_OK;
1188         char *tmp_name = NULL;
1189         data_t *fh;
1190         char *ptr;
1191
1192         tmp_name = strdup(name);
1193         if (tmp_name == NULL) {
1194                 fprintf(stderr, "failed to strdup name in nfsio_mkdir\n");
1195                 return NFS3ERR_SERVERFAULT;
1196         }
1197
1198         ptr = rindex(tmp_name, '/');
1199         if (ptr == NULL) {      
1200                 fprintf(stderr, "name did not contain '/' in nfsio_mkdir\n");
1201                 ret = NFS3ERR_SERVERFAULT;
1202                 goto finished;
1203         }
1204
1205         *ptr = 0;
1206         ptr++;
1207
1208         fh = lookup_fhandle(nfsio, tmp_name);
1209         if (fh == NULL) {
1210                 fprintf(stderr, "failed to fetch parent handle in nfsio_mkdir\n");
1211                 ret = NFS3ERR_SERVERFAULT;
1212                 goto finished;
1213         }
1214
1215         MKDIR3args.where.dir.data.data_len  = fh->dsize;
1216         MKDIR3args.where.dir.data.data_val  = discard_const(fh->dptr);
1217         MKDIR3args.where.name               = ptr;
1218
1219         MKDIR3args.attributes.mode.set_it  = TRUE;
1220         MKDIR3args.attributes.mode.set_mode3_u.mode    = 0777;
1221         MKDIR3args.attributes.uid.set_it   = TRUE;
1222         MKDIR3args.attributes.uid.set_uid3_u.uid      = 0;
1223         MKDIR3args.attributes.gid.set_it   = TRUE;
1224         MKDIR3args.attributes.gid.set_gid3_u.gid      = 0;
1225         MKDIR3args.attributes.size.set_it  = FALSE;
1226         MKDIR3args.attributes.atime.set_it = FALSE;
1227         MKDIR3args.attributes.mtime.set_it = FALSE;
1228
1229         MKDIR3res = nfsproc3_mkdir_3(&MKDIR3args, nfsio->clnt);
1230
1231         if (MKDIR3res == NULL) {
1232                 fprintf(stderr, "nfsproc3_mkdir_3 failed in nfsio_mkdir\n");
1233                 ret = NFS3ERR_SERVERFAULT;
1234                 goto finished;
1235         }
1236
1237         if (MKDIR3res->status != NFS3_OK) {
1238                 fprintf(stderr, "nfsproc3_mkdir_3(%s) failed in nfsio_mkdir. status:%s(%d)\n", name, nfs_error(MKDIR3res->status), MKDIR3res->status);
1239                 ret = MKDIR3res->status;
1240                 goto finished;
1241         }
1242
1243         insert_fhandle(nfsio, name, 
1244                 MKDIR3res->MKDIR3res_u.resok.obj.post_op_fh3_u.handle.data.data_val,
1245                 MKDIR3res->MKDIR3res_u.resok.obj.post_op_fh3_u.handle.data.data_len);
1246
1247 finished:
1248         if (tmp_name) {
1249                 free(tmp_name);
1250         }
1251         return ret;
1252 }
1253
1254
1255 nfsstat3 nfsio_readdirplus(struct nfsio *nfsio, const char *name, nfs3_dirent_cb cb, void *private_data)
1256 {
1257         struct READDIRPLUS3args READDIRPLUS3args;
1258         struct READDIRPLUS3res *READDIRPLUS3res;
1259         int ret = NFS3_OK;
1260         data_t *fh;
1261         entryplus3 *e, *last_e = NULL;
1262         char *dir = NULL;
1263
1264         dir = strdup(name);
1265         while(strlen(dir)){
1266                 if(dir[strlen(dir)-1] != '/'){
1267                         break;
1268                 }
1269                 dir[strlen(dir)-1] = 0;
1270         }
1271  
1272         fh = lookup_fhandle(nfsio, name);
1273         if (fh == NULL) {
1274                 fprintf(stderr, "failed to fetch handle for '%s' in nfsio_readdirplus\n", name);
1275                 ret = NFS3ERR_SERVERFAULT;
1276                 goto finished;
1277         }
1278
1279         READDIRPLUS3args.dir.data.data_len = fh->dsize;
1280         READDIRPLUS3args.dir.data.data_val = discard_const(fh->dptr);
1281         READDIRPLUS3args.cookie            = 0;
1282         bzero(&READDIRPLUS3args.cookieverf, NFS3_COOKIEVERFSIZE);
1283         READDIRPLUS3args.dircount          = 6000;
1284         READDIRPLUS3args.maxcount          = 8192;
1285
1286 again:
1287         READDIRPLUS3res = nfsproc3_readdirplus_3(&READDIRPLUS3args, nfsio->clnt);
1288
1289         if (READDIRPLUS3res == NULL) {
1290                 fprintf(stderr, "nfsproc3_readdirplus_3 failed in readdirplus\n");
1291                 ret = NFS3ERR_SERVERFAULT;
1292                 goto finished;
1293         }
1294
1295         if (READDIRPLUS3res->status != NFS3_OK) {
1296                 fprintf(stderr, "nfsproc3_readdirplus_3 failed in readdirplus. status:%d\n", READDIRPLUS3res->status);
1297                 ret = READDIRPLUS3res->status;
1298                 goto finished;
1299         }
1300
1301         for(e = READDIRPLUS3res->READDIRPLUS3res_u.resok.reply.entries;e;e=e->nextentry){
1302                 char *new_name;
1303
1304                 if(!strcmp(e->name, ".")){
1305                         continue;
1306                 }
1307                 if(!strcmp(e->name, "..")){
1308                         continue;
1309                 }
1310                 if(e->name_handle.handle_follows == 0){
1311                         continue;
1312                 }
1313
1314                 last_e = e;
1315
1316                 asprintf(&new_name, "%s/%s", dir, e->name);
1317                 insert_fhandle(nfsio, new_name, 
1318                         e->name_handle.post_op_fh3_u.handle.data.data_val,
1319                         e->name_handle.post_op_fh3_u.handle.data.data_len);
1320                 free(new_name);
1321
1322                 if (cb) {
1323                         cb(e, private_data);
1324                 }
1325         }       
1326
1327         if (READDIRPLUS3res->READDIRPLUS3res_u.resok.reply.eof == 0) {
1328                 if (READDIRPLUS3args.cookie == 0) {
1329                         memcpy(&READDIRPLUS3args.cookieverf, 
1330                         &READDIRPLUS3res->READDIRPLUS3res_u.resok.cookieverf,
1331                         NFS3_COOKIEVERFSIZE);           
1332                 }
1333
1334                 READDIRPLUS3args.cookie = last_e->cookie;
1335
1336                 goto again;
1337         }
1338
1339
1340 finished:
1341         if (dir) {
1342                 free(dir);
1343         }
1344         return ret;
1345 }
1346
1347
1348 nfsstat3 nfsio_rename(struct nfsio *nfsio, const char *old, const char *new)
1349 {
1350
1351         struct RENAME3args RENAME3args;
1352         struct RENAME3res *RENAME3res;
1353         int ret = NFS3_OK;
1354         char *tmp_old_name = NULL;
1355         char *tmp_new_name = NULL;
1356         data_t *old_fh, *new_fh;
1357         char *old_ptr, *new_ptr;
1358
1359         tmp_old_name = strdup(old);
1360         if (tmp_old_name == NULL) {
1361                 fprintf(stderr, "failed to strdup name in nfsio_rename\n");
1362                 ret = NFS3ERR_SERVERFAULT;
1363                 goto finished;
1364         }
1365
1366         old_ptr = rindex(tmp_old_name, '/');
1367         if (old_ptr == NULL) {  
1368                 fprintf(stderr, "name did not contain '/' in nfsio_rename\n");
1369                 ret = NFS3ERR_SERVERFAULT;
1370                 goto finished;
1371         }
1372
1373         *old_ptr = 0;
1374         old_ptr++;
1375
1376         old_fh = lookup_fhandle(nfsio, tmp_old_name);
1377         if (old_fh == NULL) {
1378                 fprintf(stderr, "failed to fetch parent handle in nfsio_rename\n");
1379                 ret = NFS3ERR_SERVERFAULT;
1380                 goto finished;
1381         }
1382
1383         tmp_new_name = strdup(new);
1384         if (tmp_new_name == NULL) {
1385                 fprintf(stderr, "failed to strdup name in nfsio_rename\n");
1386                 ret = NFS3ERR_SERVERFAULT;
1387                 goto finished;
1388         }
1389
1390         new_ptr = rindex(tmp_new_name, '/');
1391         if (new_ptr == NULL) {  
1392                 fprintf(stderr, "name did not contain '/' in nfsio_rename\n");
1393                 ret = NFS3ERR_SERVERFAULT;
1394                 goto finished;
1395         }
1396
1397         *new_ptr = 0;
1398         new_ptr++;
1399
1400         new_fh = lookup_fhandle(nfsio, tmp_new_name);
1401         if (new_fh == NULL) {
1402                 fprintf(stderr, "failed to fetch parent handle in nfsio_rename\n");
1403                 ret = NFS3ERR_SERVERFAULT;
1404                 goto finished;
1405         }
1406
1407         RENAME3args.from.dir.data.data_len  = old_fh->dsize;
1408         RENAME3args.from.dir.data.data_val  = discard_const(old_fh->dptr);
1409         RENAME3args.from.name               = old_ptr;
1410
1411         RENAME3args.to.dir.data.data_len  = new_fh->dsize;
1412         RENAME3args.to.dir.data.data_val  = discard_const(new_fh->dptr);
1413         RENAME3args.to.name               = new_ptr;
1414
1415
1416         RENAME3res = nfsproc3_rename_3(&RENAME3args, nfsio->clnt);
1417
1418         if (RENAME3res == NULL) {
1419                 fprintf(stderr, "nfsproc3_rename_3 failed in nfsio_rename\n");
1420                 ret = NFS3ERR_SERVERFAULT;
1421                 goto finished;
1422         }
1423
1424         if (RENAME3res->status != NFS3_OK) {
1425                 fprintf(stderr, "nfsproc3_rename_3 failed in nfsio_rename. status:%d\n", RENAME3res->status);
1426                 ret = RENAME3res->status;
1427                 goto finished;
1428         }
1429
1430
1431         old_fh = lookup_fhandle(nfsio, old);
1432         if (old_fh == NULL) {
1433                 fprintf(stderr, "failed to fetch parent handle in nfsio_rename\n");
1434                 ret = NFS3ERR_SERVERFAULT;
1435                 goto finished;
1436         }
1437
1438
1439         insert_fhandle(nfsio, new, old_fh->dptr, old_fh->dsize);
1440         delete_fhandle(nfsio, old);
1441
1442
1443 finished:
1444         if (tmp_old_name) {
1445                 free(tmp_old_name);
1446         }
1447         if (tmp_new_name) {
1448                 free(tmp_new_name);
1449         }
1450         return ret;
1451 }
1452