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