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