4 Copyright (C) 2008 by Ronnie Sahlberg (ronniesahlberg@gmail.com)
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.
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.
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/>.
19 #define _FILE_OFFSET_BITS 64
23 #include <sys/types.h>
27 #define discard_const(ptr) ((void *)((intptr_t)(ptr)))
29 typedef struct _data_t {
34 typedef struct _tree_t {
38 struct _tree_t *parent;
40 struct _tree_t *right;
50 static void free_node(tree_t *t)
52 free(discard_const(t->key.dptr));
53 free(discard_const(t->fh.dptr));
57 static tree_t *find_fhandle(tree_t *tree, const char *key)
65 i = strcmp(key, tree->key.dptr);
70 return find_fhandle(tree->left, key);
73 return find_fhandle(tree->right, key);
76 static data_t *recursive_lookup_fhandle(struct nfsio *nfsio, const char *name)
83 while (name[0] == '.') name++;
89 tmpname = strdup(name);
90 strp = rindex(tmpname, '/');
97 recursive_lookup_fhandle(nfsio, tmpname);
100 t = find_fhandle(nfsio->fhandles, name);
105 ret = nfsio_lookup(nfsio, name, NULL);
110 t = find_fhandle(nfsio->fhandles, name);
118 static data_t *lookup_fhandle(struct nfsio *nfsio, const char *name, off_t *off)
122 while (name[0] == '.') name++;
128 t = find_fhandle(nfsio->fhandles, name);
130 return recursive_lookup_fhandle(nfsio, name);
140 static void delete_fhandle(struct nfsio *nfsio, const char *name)
144 while (name[0] == '.') name++;
146 t = find_fhandle(nfsio->fhandles, name);
151 /* we have a left child */
155 for(tmp_tree=t->left;tmp_tree->right;tmp_tree=tmp_tree->right)
157 tmp_tree->right = t->right;
159 t->right->parent = tmp_tree;
162 if (t->parent == NULL) {
163 nfsio->fhandles = tmp_tree;
164 tmp_tree->parent = NULL;
169 if (t->parent->left == t) {
170 t->parent->left = t->left;
172 t->left->parent = t->parent;
178 t->parent->right = t->left;
180 t->left->parent = t->parent;
186 /* we only have a right child */
190 for(tmp_tree=t->right;tmp_tree->left;tmp_tree=tmp_tree->left)
192 tmp_tree->left = t->left;
194 t->left->parent = tmp_tree;
197 if (t->parent == NULL) {
198 nfsio->fhandles = tmp_tree;
199 tmp_tree->parent = NULL;
204 if (t->parent->left == t) {
205 t->parent->left = t->right;
207 t->right->parent = t->parent;
213 t->parent->right = t->right;
215 t->right->parent = t->parent;
221 /* we are a leaf node */
222 if (t->parent == NULL) {
223 nfsio->fhandles = NULL;
225 if (t->parent->left == t) {
226 t->parent->left = NULL;
228 t->parent->right = NULL;
235 static void insert_fhandle(struct nfsio *nfsio, const char *name, const char *fhandle, int length, off_t off)
241 while (name[0] == '.') name++;
243 t = malloc(sizeof(tree_t));
245 fprintf(stderr, "MALLOC failed to allocate tree_t in insert_fhandle\n");
249 t->key.dptr = strdup(name);
250 if (t->key.dptr == NULL) {
251 fprintf(stderr, "STRDUP failed to allocate key in insert_fhandle\n");
254 t->key.dsize = strlen(name);
257 t->fh.dptr = malloc(length);
258 if (t->key.dptr == NULL) {
259 fprintf(stderr, "MALLOC failed to allocate fhandle in insert_fhandle\n");
262 memcpy(discard_const(t->fh.dptr), fhandle, length);
263 t->fh.dsize = length;
270 if (nfsio->fhandles == NULL) {
275 tmp_t = nfsio->fhandles;
277 i = strcmp(t->key.dptr, tmp_t->key.dptr);
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));
287 if (tmp_t->left == NULL) {
295 if (tmp_t->right == NULL) {
300 tmp_t = tmp_t->right;
310 static const struct nfs_errors nfs_errors[] = {
313 {"NFS3ERR_NOENT", 2},
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},
344 const char *nfs_error(int error)
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;
353 return "Unknown NFS error";
359 void nfsio_disconnect(struct nfsio *nfsio)
361 if (nfsio->clnt != NULL) {
362 clnt_destroy(nfsio->clnt);
365 if (nfsio->s != -1) {
368 // qqq free the tree*/
376 struct nfsio *nfsio_connect(const char *server, const char *export, const char *protocol)
378 dirpath mountdir=discard_const(export);
382 struct sockaddr_in sin;
385 nfsio = malloc(sizeof(struct nfsio));
387 fprintf(stderr, "Failed to malloc nfsio\n");
390 bzero(nfsio, sizeof(struct nfsio));
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"
401 memset(&sin, 0, sizeof(sin));
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);
410 if (!strcmp(protocol, "tcp")) {
411 nfsio->s = RPC_ANYSOCK;
412 nfsio->clnt = clnttcp_create(&sin, MOUNT_PROGRAM, MOUNT_V3, &nfsio->s, 32768, 32768);
418 nfsio->s = RPC_ANYSOCK;
419 nfsio->clnt = clntudp_create(&sin, MOUNT_PROGRAM, MOUNT_V3, wait, &nfsio->s);
422 if (nfsio->clnt == NULL) {
423 printf("ERROR: failed to connect to MOUNT daemon on %s\n", server);
424 nfsio_disconnect(nfsio);
427 nfsio->clnt->cl_auth = authunix_create_default();
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);
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);
441 fh = &mountres->mountres3_u.mountinfo.fhandle;
442 insert_fhandle(nfsio, "/",
448 /* we dont need the mount client any more */
449 clnt_destroy(nfsio->clnt);
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"
461 memset(&sin, 0, sizeof(sin));
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);
470 if (!strcmp(protocol, "tcp")) {
471 nfsio->s = RPC_ANYSOCK;
472 nfsio->clnt = clnttcp_create(&sin, NFS_PROGRAM, NFS_V3, &nfsio->s, 327680, 327680);
478 nfsio->s = RPC_ANYSOCK;
479 nfsio->clnt = clntudp_create(&sin, NFS_PROGRAM, NFS_V3, wait, &nfsio->s);
482 if (nfsio->clnt == NULL) {
483 fprintf(stderr, "Failed to initialize nfs client structure\n");
484 nfsio_disconnect(nfsio);
487 nfsio->clnt->cl_auth = authunix_create_default();
493 nfsstat3 nfsio_getattr(struct nfsio *nfsio, const char *name, fattr3 *attributes)
495 struct GETATTR3args GETATTR3args;
496 struct GETATTR3res *GETATTR3res;
499 fh = lookup_fhandle(nfsio, name, NULL);
501 fprintf(stderr, "failed to fetch handle in nfsio_getattr\n");
502 return NFS3ERR_SERVERFAULT;
505 GETATTR3args.object.data.data_len = fh->dsize;
506 GETATTR3args.object.data.data_val = discard_const(fh->dptr);
508 GETATTR3res = nfsproc3_getattr_3(&GETATTR3args, nfsio->clnt);
510 if (GETATTR3res == NULL) {
511 fprintf(stderr, "nfsproc3_getattr_3 failed in getattr\n");
512 return NFS3ERR_SERVERFAULT;
515 if (GETATTR3res->status != NFS3_OK) {
516 fprintf(stderr, "nfsproc3_getattr_3 failed in getattr. status:%d\n", GETATTR3res->status);
517 return GETATTR3res->status;
521 memcpy(attributes, &GETATTR3res->GETATTR3res_u.resok.obj_attributes, sizeof(fattr3));
527 nfsstat3 nfsio_lookup(struct nfsio *nfsio, const char *name, fattr3 *attributes)
530 struct LOOKUP3args LOOKUP3args;
531 struct LOOKUP3res *LOOKUP3res;
532 char *tmp_name = NULL;
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;
544 ptr = rindex(tmp_name, '/');
546 fprintf(stderr, "name did not contain '/' in nfsio_lookup\n");
547 ret = NFS3ERR_SERVERFAULT;
554 fh = lookup_fhandle(nfsio, tmp_name, NULL);
556 fprintf(stderr, "failed to fetch parent handle for '%s' in nfsio_lookup\n", tmp_name);
557 ret = NFS3ERR_SERVERFAULT;
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;
565 LOOKUP3res = nfsproc3_lookup_3(&LOOKUP3args, nfsio->clnt);
567 if (LOOKUP3res == NULL) {
568 fprintf(stderr, "nfsproc3_lookup_3 failed in lookup\n");
569 ret = NFS3ERR_SERVERFAULT;
573 if (LOOKUP3res->status != NFS3_OK) {
574 ret = LOOKUP3res->status;
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);
583 free(LOOKUP3res->LOOKUP3res_u.resok.object.data.data_val);
586 memcpy(attributes, &LOOKUP3res->LOOKUP3res_u.resok.obj_attributes.post_op_attr_u.attributes, sizeof(fattr3));
597 nfsstat3 nfsio_access(struct nfsio *nfsio, const char *name, uint32 desired, uint32 *access)
600 struct ACCESS3args ACCESS3args;
601 struct ACCESS3res *ACCESS3res;
604 fh = lookup_fhandle(nfsio, name, NULL);
606 fprintf(stderr, "failed to fetch handle in nfsio_access\n");
607 return NFS3ERR_SERVERFAULT;
610 ACCESS3args.object.data.data_val = discard_const(fh->dptr);
611 ACCESS3args.object.data.data_len = fh->dsize;
612 ACCESS3args.access = desired;
614 ACCESS3res = nfsproc3_access_3(&ACCESS3args, nfsio->clnt);
616 if (ACCESS3res == NULL) {
617 fprintf(stderr, "nfsproc3_access_3 failed in access\n");
618 return NFS3ERR_SERVERFAULT;
621 if (ACCESS3res->status != NFS3_OK) {
622 fprintf(stderr, "nfsproc3_access_3 failed. status:%d\n",
624 return ACCESS3res->status;
628 *access = ACCESS3res->ACCESS3res_u.resok.access;
636 nfsstat3 nfsio_create(struct nfsio *nfsio, const char *name)
639 struct CREATE3args CREATE3args;
640 struct CREATE3res *CREATE3res;
641 char *tmp_name = NULL;
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;
653 ptr = rindex(tmp_name, '/');
655 fprintf(stderr, "name did not contain '/' in nfsio_create\n");
656 ret = NFS3ERR_SERVERFAULT;
663 fh = lookup_fhandle(nfsio, tmp_name, NULL);
665 fprintf(stderr, "failed to fetch parent handle in nfsio_create\n");
666 ret = NFS3ERR_SERVERFAULT;
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;
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;
685 CREATE3res = nfsproc3_create_3(&CREATE3args, nfsio->clnt);
687 if (CREATE3res == NULL) {
688 fprintf(stderr, "nfsproc3_create_3 failed in nfsio_create\n");
689 ret = NFS3ERR_SERVERFAULT;
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;
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,
714 nfsstat3 nfsio_remove(struct nfsio *nfsio, const char *name)
717 struct REMOVE3args REMOVE3args;
718 struct REMOVE3res *REMOVE3res;
720 char *tmp_name = NULL;
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;
731 ptr = rindex(tmp_name, '/');
733 fprintf(stderr, "name did not contain '/' in nfsio_remove\n");
734 ret = NFS3ERR_SERVERFAULT;
741 fh = lookup_fhandle(nfsio, tmp_name, NULL);
743 fprintf(stderr, "failed to fetch parent handle in nfsio_remove\n");
744 ret = NFS3ERR_SERVERFAULT;
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;
753 REMOVE3res = nfsproc3_remove_3(&REMOVE3args, nfsio->clnt);
755 if (REMOVE3res == NULL) {
756 fprintf(stderr, "nfsproc3_remove_3 failed in nfsio_remove\n");
757 ret = NFS3ERR_SERVERFAULT;
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;
768 delete_fhandle(nfsio, name);
779 nfsstat3 nfsio_write(struct nfsio *nfsio, const char *name, char *buf, uint64_t offset, int len, int stable)
781 struct WRITE3args WRITE3args;
782 struct WRITE3res *WRITE3res;
786 fh = lookup_fhandle(nfsio, name, NULL);
788 fprintf(stderr, "failed to fetch handle in nfsio_write\n");
789 ret = NFS3ERR_SERVERFAULT;
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;
802 WRITE3res = nfsproc3_write_3(&WRITE3args, nfsio->clnt);
804 if (WRITE3res == NULL) {
805 fprintf(stderr, "nfsproc3_write_3 failed in nfsio_write\n");
806 ret = NFS3ERR_SERVERFAULT;
810 if (WRITE3res->status != NFS3_OK) {
811 fprintf(stderr, "nfsproc3_write_3 failed in getattr. status:%d\n", WRITE3res->status);
812 ret = WRITE3res->status;
819 nfsstat3 nfsio_read(struct nfsio *nfsio, const char *name, char *buf, uint64_t offset, int len, int *count, int *eof)
821 struct READ3args READ3args;
822 struct READ3res *READ3res;
827 fh = lookup_fhandle(nfsio, name, &size);
829 fprintf(stderr, "failed to fetch handle in nfsio_read\n");
830 ret = NFS3ERR_SERVERFAULT;
834 if (offset >= size && size > 0) {
835 offset = offset % size;
837 if (offset+len >= size) {
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;
846 READ3res = nfsproc3_read_3(&READ3args, nfsio->clnt);
848 if (READ3res == NULL) {
849 fprintf(stderr, "nfsproc3_read_3 failed in nfsio_read\n");
850 ret = NFS3ERR_SERVERFAULT;
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;
861 *count = READ3res->READ3res_u.resok.count;
864 *eof = READ3res->READ3res_u.resok.eof;
867 memcpy(buf, &READ3res->READ3res_u.resok.data.data_val,
868 READ3res->READ3res_u.resok.count);
870 free(READ3res->READ3res_u.resok.data.data_val);
871 READ3res->READ3res_u.resok.data.data_val = NULL;
878 nfsstat3 nfsio_commit(struct nfsio *nfsio, const char *name)
880 struct COMMIT3args COMMIT3args;
881 struct COMMIT3res *COMMIT3res;
885 fh = lookup_fhandle(nfsio, name, NULL);
887 fprintf(stderr, "failed to fetch handle in nfsio_commit\n");
888 ret = NFS3ERR_SERVERFAULT;
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;
898 COMMIT3res = nfsproc3_commit_3(&COMMIT3args, nfsio->clnt);
900 if (COMMIT3res == NULL) {
901 fprintf(stderr, "nfsproc3_commit_3 failed in nfsio_commit\n");
902 ret = NFS3ERR_SERVERFAULT;
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;
916 nfsstat3 nfsio_fsinfo(struct nfsio *nfsio)
918 struct FSINFO3args FSINFO3args;
919 struct FSINFO3res *FSINFO3res;
922 fh = lookup_fhandle(nfsio, "/", NULL);
924 fprintf(stderr, "failed to fetch handle in nfsio_fsinfo\n");
925 return NFS3ERR_SERVERFAULT;
928 FSINFO3args.fsroot.data.data_len = fh->dsize;
929 FSINFO3args.fsroot.data.data_val = discard_const(fh->dptr);
931 FSINFO3res = nfsproc3_fsinfo_3(&FSINFO3args, nfsio->clnt);
933 if (FSINFO3res == NULL) {
934 fprintf(stderr, "nfsproc3_fsinfo_3 failed in nfsio_fsinfo\n");
935 return NFS3ERR_SERVERFAULT;
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;
947 nfsstat3 nfsio_fsstat(struct nfsio *nfsio)
949 struct FSSTAT3args FSSTAT3args;
950 struct FSSTAT3res *FSSTAT3res;
953 fh = lookup_fhandle(nfsio, "/", NULL);
955 fprintf(stderr, "failed to fetch handle in nfsio_fsstat\n");
956 return NFS3ERR_SERVERFAULT;
959 FSSTAT3args.fsroot.data.data_len = fh->dsize;
960 FSSTAT3args.fsroot.data.data_val = discard_const(fh->dptr);
962 FSSTAT3res = nfsproc3_fsstat_3(&FSSTAT3args, nfsio->clnt);
964 if (FSSTAT3res == NULL) {
965 fprintf(stderr, "nfsproc3_fsstat_3 failed in nfsio_fsstat\n");
966 return NFS3ERR_SERVERFAULT;
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;
977 nfsstat3 nfsio_pathconf(struct nfsio *nfsio, char *name)
979 struct PATHCONF3args PATHCONF3args;
980 struct PATHCONF3res *PATHCONF3res;
983 fh = lookup_fhandle(nfsio, name, NULL);
985 fprintf(stderr, "failed to fetch handle in nfsio_pathconf\n");
986 return NFS3ERR_SERVERFAULT;
989 PATHCONF3args.object.data.data_len = fh->dsize;
990 PATHCONF3args.object.data.data_val = discard_const(fh->dptr);
992 PATHCONF3res = nfsproc3_pathconf_3(&PATHCONF3args, nfsio->clnt);
994 if (PATHCONF3res == NULL) {
995 fprintf(stderr, "nfsproc3_pathconf_3 failed in nfsio_pathconf\n");
996 return NFS3ERR_SERVERFAULT;
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;
1008 nfsstat3 nfsio_symlink(struct nfsio *nfsio, const char *old, const char *new)
1011 struct SYMLINK3args SYMLINK3args;
1012 struct SYMLINK3res *SYMLINK3res;
1014 char *tmp_name = NULL;
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;
1025 ptr = rindex(tmp_name, '/');
1027 fprintf(stderr, "name did not contain '/' in nfsio_symlink\n");
1028 ret = NFS3ERR_SERVERFAULT;
1035 fh = lookup_fhandle(nfsio, tmp_name, NULL);
1037 fprintf(stderr, "failed to fetch parent handle in nfsio_symlink\n");
1038 ret = NFS3ERR_SERVERFAULT;
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;
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);
1059 SYMLINK3res = nfsproc3_symlink_3(&SYMLINK3args, nfsio->clnt);
1061 if (SYMLINK3res == NULL) {
1062 fprintf(stderr, "nfsproc3_symlink_3 failed in nfsio_symlink\n");
1063 ret = NFS3ERR_SERVERFAULT;
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;
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,
1089 nfsstat3 nfsio_link(struct nfsio *nfsio, const char *old, const char *new)
1092 struct LINK3args LINK3args;
1093 struct LINK3res *LINK3res;
1095 char *tmp_name = NULL;
1096 data_t *fh, *new_fh;
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;
1106 ptr = rindex(tmp_name, '/');
1108 fprintf(stderr, "name did not contain '/' in nfsio_link\n");
1109 ret = NFS3ERR_SERVERFAULT;
1116 fh = lookup_fhandle(nfsio, tmp_name, NULL);
1118 fprintf(stderr, "failed to fetch parent handle in nfsio_link\n");
1119 ret = NFS3ERR_SERVERFAULT;
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;
1132 LINK3args.file.data.data_len = new_fh->dsize;
1133 LINK3args.file.data.data_val = discard_const(new_fh->dptr);
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;
1140 LINK3res = nfsproc3_link_3(&LINK3args, nfsio->clnt);
1142 if (LINK3res == NULL) {
1143 fprintf(stderr, "nfsproc3_link_3 failed in nfsio_link\n");
1144 ret = NFS3ERR_SERVERFAULT;
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;
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);
1169 nfsstat3 nfsio_readlink(struct nfsio *nfsio, char *name, char **link_name)
1171 struct READLINK3args READLINK3args;
1172 struct READLINK3res *READLINK3res;
1175 fh = lookup_fhandle(nfsio, name, NULL);
1177 fprintf(stderr, "failed to fetch handle in nfsio_readlink\n");
1178 return NFS3ERR_SERVERFAULT;
1182 READLINK3args.symlink.data.data_len = fh->dsize;
1183 READLINK3args.symlink.data.data_val = discard_const(fh->dptr);
1185 READLINK3res = nfsproc3_readlink_3(&READLINK3args, nfsio->clnt);
1187 if (READLINK3res == NULL) {
1188 fprintf(stderr, "nfsproc3_readlink_3 failed in nfsio_readlink\n");
1189 return NFS3ERR_SERVERFAULT;
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;
1198 *link_name = strdup(READLINK3res->READLINK3res_u.resok.data);
1205 nfsstat3 nfsio_rmdir(struct nfsio *nfsio, const char *name)
1208 struct RMDIR3args RMDIR3args;
1209 struct RMDIR3res *RMDIR3res;
1211 char *tmp_name = NULL;
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;
1221 ptr = rindex(tmp_name, '/');
1223 fprintf(stderr, "name did not contain '/' in nfsio_rmdir\n");
1224 ret = NFS3ERR_SERVERFAULT;
1231 fh = lookup_fhandle(nfsio, tmp_name, NULL);
1233 fprintf(stderr, "failed to fetch parent handle in nfsio_rmdir\n");
1234 ret = NFS3ERR_SERVERFAULT;
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;
1243 RMDIR3res = nfsproc3_rmdir_3(&RMDIR3args, nfsio->clnt);
1245 if (RMDIR3res == NULL) {
1246 fprintf(stderr, "nfsproc3_rmdir_3 failed in nfsio_rmdir\n");
1247 ret = NFS3ERR_SERVERFAULT;
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;
1258 delete_fhandle(nfsio, name);
1270 nfsstat3 nfsio_mkdir(struct nfsio *nfsio, const char *name)
1273 struct MKDIR3args MKDIR3args;
1274 struct MKDIR3res *MKDIR3res;
1276 char *tmp_name = NULL;
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;
1286 ptr = rindex(tmp_name, '/');
1288 fprintf(stderr, "name did not contain '/' in nfsio_mkdir\n");
1289 ret = NFS3ERR_SERVERFAULT;
1296 fh = lookup_fhandle(nfsio, tmp_name, NULL);
1298 fprintf(stderr, "failed to fetch parent handle in nfsio_mkdir\n");
1299 ret = NFS3ERR_SERVERFAULT;
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;
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;
1317 MKDIR3res = nfsproc3_mkdir_3(&MKDIR3args, nfsio->clnt);
1319 if (MKDIR3res == NULL) {
1320 fprintf(stderr, "nfsproc3_mkdir_3 failed in nfsio_mkdir\n");
1321 ret = NFS3ERR_SERVERFAULT;
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;
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,
1345 nfsstat3 nfsio_readdirplus(struct nfsio *nfsio, const char *name, nfs3_dirent_cb cb, void *private_data)
1347 struct READDIRPLUS3args READDIRPLUS3args;
1348 struct READDIRPLUS3res *READDIRPLUS3res;
1351 entryplus3 *e, *last_e = NULL;
1356 if(dir[strlen(dir)-1] != '/'){
1359 dir[strlen(dir)-1] = 0;
1362 fh = lookup_fhandle(nfsio, name, NULL);
1364 fprintf(stderr, "failed to fetch handle for '%s' in nfsio_readdirplus\n", name);
1365 ret = NFS3ERR_SERVERFAULT;
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;
1377 READDIRPLUS3res = nfsproc3_readdirplus_3(&READDIRPLUS3args, nfsio->clnt);
1379 if (READDIRPLUS3res == NULL) {
1380 fprintf(stderr, "nfsproc3_readdirplus_3 failed in readdirplus\n");
1381 ret = NFS3ERR_SERVERFAULT;
1385 if (READDIRPLUS3res->status != NFS3_OK) {
1386 fprintf(stderr, "nfsproc3_readdirplus_3 failed in readdirplus. status:%d\n", READDIRPLUS3res->status);
1387 ret = READDIRPLUS3res->status;
1391 for(e = READDIRPLUS3res->READDIRPLUS3res_u.resok.reply.entries;e;e=e->nextentry){
1394 if(!strcmp(e->name, ".")){
1397 if(!strcmp(e->name, "..")){
1400 if(e->name_handle.handle_follows == 0){
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,
1415 cb(e, private_data);
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);
1426 READDIRPLUS3args.cookie = last_e->cookie;
1440 nfsstat3 nfsio_rename(struct nfsio *nfsio, const char *old, const char *new)
1443 struct RENAME3args RENAME3args;
1444 struct RENAME3res *RENAME3res;
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;
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;
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;
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;
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;
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;
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;
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;
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;
1508 RENAME3res = nfsproc3_rename_3(&RENAME3args, nfsio->clnt);
1510 if (RENAME3res == NULL) {
1511 fprintf(stderr, "nfsproc3_rename_3 failed in nfsio_rename\n");
1512 ret = NFS3ERR_SERVERFAULT;
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;
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;
1531 insert_fhandle(nfsio, new, old_fh->dptr, old_fh->dsize, 0 /*qqq*/);
1532 delete_fhandle(nfsio, old);