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