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/>.
23 #include <sys/types.h>
27 #define discard_const(ptr) ((void *)((intptr_t)(ptr)))
29 typedef struct _data_t {
34 typedef struct _tree_t {
37 struct _tree_t *parent;
39 struct _tree_t *right;
49 static void free_node(tree_t *t)
51 free(discard_const(t->key.dptr));
52 free(discard_const(t->fh.dptr));
56 static tree_t *find_fhandle(tree_t *tree, const char *key)
64 i = strcmp(key, tree->key.dptr);
69 return find_fhandle(tree->left, key);
72 return find_fhandle(tree->right, key);
75 static data_t *recursive_lookup_fhandle(struct nfsio *nfsio, const char *name)
82 while (name[0] == '.') name++;
88 tmpname = strdup(name);
89 strp = rindex(tmpname, '/');
96 recursive_lookup_fhandle(nfsio, tmpname);
99 t = find_fhandle(nfsio->fhandles, name);
104 ret = nfsio_lookup(nfsio, name, NULL);
109 t = find_fhandle(nfsio->fhandles, name);
117 static data_t *lookup_fhandle(struct nfsio *nfsio, const char *name)
121 while (name[0] == '.') name++;
127 t = find_fhandle(nfsio->fhandles, name);
129 return recursive_lookup_fhandle(nfsio, name);
135 static void delete_fhandle(struct nfsio *nfsio, const char *name)
139 while (name[0] == '.') name++;
141 t = find_fhandle(nfsio->fhandles, name);
146 /* we have a left child */
150 for(tmp_tree=t->left;tmp_tree->right;tmp_tree=tmp_tree->right)
152 tmp_tree->right = t->right;
154 t->right->parent = tmp_tree;
157 if (t->parent == NULL) {
158 nfsio->fhandles = tmp_tree;
159 tmp_tree->parent = NULL;
164 if (t->parent->left == t) {
165 t->parent->left = t->left;
167 t->left->parent = t->parent;
173 t->parent->right = t->left;
175 t->left->parent = t->parent;
181 /* we only have a right child */
185 for(tmp_tree=t->right;tmp_tree->left;tmp_tree=tmp_tree->left)
187 tmp_tree->left = t->left;
189 t->left->parent = tmp_tree;
192 if (t->parent == NULL) {
193 nfsio->fhandles = tmp_tree;
194 tmp_tree->parent = NULL;
199 if (t->parent->left == t) {
200 t->parent->left = t->right;
202 t->right->parent = t->parent;
208 t->parent->right = t->right;
210 t->right->parent = t->parent;
216 /* we are a leaf node */
217 if (t->parent == NULL) {
218 nfsio->fhandles = NULL;
220 if (t->parent->left == t) {
221 t->parent->left = NULL;
223 t->parent->right = NULL;
230 static void insert_fhandle(struct nfsio *nfsio, const char *name, const char *fhandle, int length)
236 while (name[0] == '.') name++;
238 t = malloc(sizeof(tree_t));
240 fprintf(stderr, "MALLOC failed to allocate tree_t in insert_fhandle\n");
244 t->key.dptr = strdup(name);
245 if (t->key.dptr == NULL) {
246 fprintf(stderr, "STRDUP failed to allocate key in insert_fhandle\n");
249 t->key.dsize = strlen(name);
252 t->fh.dptr = malloc(length);
253 if (t->key.dptr == NULL) {
254 fprintf(stderr, "MALLOC failed to allocate fhandle in insert_fhandle\n");
257 memcpy(discard_const(t->fh.dptr), fhandle, length);
258 t->fh.dsize = length;
264 if (nfsio->fhandles == NULL) {
269 tmp_t = nfsio->fhandles;
271 i = strcmp(t->key.dptr, tmp_t->key.dptr);
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));
281 if (tmp_t->left == NULL) {
289 if (tmp_t->right == NULL) {
294 tmp_t = tmp_t->right;
304 static const struct nfs_errors nfs_errors[] = {
307 {"NFS3ERR_NOENT", 2},
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},
338 const char *nfs_error(int error)
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;
347 return "Unknown NFS error";
353 void nfsio_disconnect(struct nfsio *nfsio)
355 if (nfsio->clnt != NULL) {
356 clnt_destroy(nfsio->clnt);
359 if (nfsio->s != -1) {
362 // qqq free the tree*/
370 struct nfsio *nfsio_connect(const char *server, const char *export, const char *protocol)
372 dirpath mountdir=discard_const(export);
376 struct sockaddr_in sin;
379 nfsio = malloc(sizeof(struct nfsio));
381 fprintf(stderr, "Failed to malloc nfsio\n");
384 bzero(nfsio, sizeof(struct nfsio));
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"
395 memset(&sin, 0, sizeof(sin));
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);
404 if (!strcmp(protocol, "tcp")) {
405 nfsio->s = RPC_ANYSOCK;
406 nfsio->clnt = clnttcp_create(&sin, MOUNT_PROGRAM, MOUNT_V3, &nfsio->s, 32768, 32768);
412 nfsio->s = RPC_ANYSOCK;
413 nfsio->clnt = clntudp_create(&sin, MOUNT_PROGRAM, MOUNT_V3, wait, &nfsio->s);
416 if (nfsio->clnt == NULL) {
417 printf("ERROR: failed to connect to MOUNT daemon on %s\n", server);
418 nfsio_disconnect(nfsio);
421 nfsio->clnt->cl_auth = authunix_create_default();
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);
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);
435 fh = &mountres->mountres3_u.mountinfo.fhandle;
436 insert_fhandle(nfsio, "/", fh->fhandle3_val, fh->fhandle3_len);
439 /* we dont need the mount client any more */
440 clnt_destroy(nfsio->clnt);
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"
452 memset(&sin, 0, sizeof(sin));
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);
461 if (!strcmp(protocol, "tcp")) {
462 nfsio->s = RPC_ANYSOCK;
463 nfsio->clnt = clnttcp_create(&sin, NFS_PROGRAM, NFS_V3, &nfsio->s, 327680, 327680);
469 nfsio->s = RPC_ANYSOCK;
470 nfsio->clnt = clntudp_create(&sin, NFS_PROGRAM, NFS_V3, wait, &nfsio->s);
473 if (nfsio->clnt == NULL) {
474 fprintf(stderr, "Failed to initialize nfs client structure\n");
475 nfsio_disconnect(nfsio);
478 nfsio->clnt->cl_auth = authunix_create_default();
484 nfsstat3 nfsio_getattr(struct nfsio *nfsio, const char *name, fattr3 *attributes)
486 struct GETATTR3args GETATTR3args;
487 struct GETATTR3res *GETATTR3res;
490 fh = lookup_fhandle(nfsio, name);
492 fprintf(stderr, "failed to fetch handle in nfsio_getattr\n");
493 return NFS3ERR_SERVERFAULT;
496 GETATTR3args.object.data.data_len = fh->dsize;
497 GETATTR3args.object.data.data_val = discard_const(fh->dptr);
499 GETATTR3res = nfsproc3_getattr_3(&GETATTR3args, nfsio->clnt);
501 if (GETATTR3res == NULL) {
502 fprintf(stderr, "nfsproc3_getattr_3 failed in getattr\n");
503 return NFS3ERR_SERVERFAULT;
506 if (GETATTR3res->status != NFS3_OK) {
507 fprintf(stderr, "nfsproc3_getattr_3 failed in getattr. status:%d\n", GETATTR3res->status);
508 return GETATTR3res->status;
512 memcpy(attributes, &GETATTR3res->GETATTR3res_u.resok.obj_attributes, sizeof(fattr3));
518 nfsstat3 nfsio_lookup(struct nfsio *nfsio, const char *name, fattr3 *attributes)
521 struct LOOKUP3args LOOKUP3args;
522 struct LOOKUP3res *LOOKUP3res;
523 char *tmp_name = NULL;
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;
535 ptr = rindex(tmp_name, '/');
537 fprintf(stderr, "name did not contain '/' in nfsio_lookup\n");
538 ret = NFS3ERR_SERVERFAULT;
545 fh = lookup_fhandle(nfsio, tmp_name);
547 fprintf(stderr, "failed to fetch parent handle for '%s' in nfsio_lookup\n", tmp_name);
548 ret = NFS3ERR_SERVERFAULT;
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;
556 LOOKUP3res = nfsproc3_lookup_3(&LOOKUP3args, nfsio->clnt);
558 if (LOOKUP3res == NULL) {
559 fprintf(stderr, "nfsproc3_lookup_3 failed in lookup\n");
560 ret = NFS3ERR_SERVERFAULT;
564 if (LOOKUP3res->status != NFS3_OK) {
565 ret = LOOKUP3res->status;
570 insert_fhandle(nfsio, name,
571 LOOKUP3res->LOOKUP3res_u.resok.object.data.data_val,
572 LOOKUP3res->LOOKUP3res_u.resok.object.data.data_len);
574 free(LOOKUP3res->LOOKUP3res_u.resok.object.data.data_val);
577 memcpy(attributes, &LOOKUP3res->LOOKUP3res_u.resok.obj_attributes.post_op_attr_u.attributes, sizeof(fattr3));
588 nfsstat3 nfsio_access(struct nfsio *nfsio, const char *name, uint32 desired, uint32 *access)
591 struct ACCESS3args ACCESS3args;
592 struct ACCESS3res *ACCESS3res;
595 fh = lookup_fhandle(nfsio, name);
597 fprintf(stderr, "failed to fetch handle in nfsio_access\n");
598 return NFS3ERR_SERVERFAULT;
601 ACCESS3args.object.data.data_val = discard_const(fh->dptr);
602 ACCESS3args.object.data.data_len = fh->dsize;
603 ACCESS3args.access = desired;
605 ACCESS3res = nfsproc3_access_3(&ACCESS3args, nfsio->clnt);
607 if (ACCESS3res == NULL) {
608 fprintf(stderr, "nfsproc3_access_3 failed in access\n");
609 return NFS3ERR_SERVERFAULT;
612 if (ACCESS3res->status != NFS3_OK) {
613 fprintf(stderr, "nfsproc3_access_3 failed. status:%d\n",
615 return ACCESS3res->status;
619 *access = ACCESS3res->ACCESS3res_u.resok.access;
627 nfsstat3 nfsio_create(struct nfsio *nfsio, const char *name)
630 struct CREATE3args CREATE3args;
631 struct CREATE3res *CREATE3res;
632 char *tmp_name = NULL;
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;
644 ptr = rindex(tmp_name, '/');
646 fprintf(stderr, "name did not contain '/' in nfsio_create\n");
647 ret = NFS3ERR_SERVERFAULT;
654 fh = lookup_fhandle(nfsio, tmp_name);
656 fprintf(stderr, "failed to fetch parent handle in nfsio_create\n");
657 ret = NFS3ERR_SERVERFAULT;
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;
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;
676 CREATE3res = nfsproc3_create_3(&CREATE3args, nfsio->clnt);
678 if (CREATE3res == NULL) {
679 fprintf(stderr, "nfsproc3_create_3 failed in nfsio_create\n");
680 ret = NFS3ERR_SERVERFAULT;
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;
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);
703 nfsstat3 nfsio_remove(struct nfsio *nfsio, const char *name)
706 struct REMOVE3args REMOVE3args;
707 struct REMOVE3res *REMOVE3res;
709 char *tmp_name = NULL;
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;
720 ptr = rindex(tmp_name, '/');
722 fprintf(stderr, "name did not contain '/' in nfsio_remove\n");
723 ret = NFS3ERR_SERVERFAULT;
730 fh = lookup_fhandle(nfsio, tmp_name);
732 fprintf(stderr, "failed to fetch parent handle in nfsio_remove\n");
733 ret = NFS3ERR_SERVERFAULT;
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;
742 REMOVE3res = nfsproc3_remove_3(&REMOVE3args, nfsio->clnt);
744 if (REMOVE3res == NULL) {
745 fprintf(stderr, "nfsproc3_remove_3 failed in nfsio_remove\n");
746 ret = NFS3ERR_SERVERFAULT;
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;
757 delete_fhandle(nfsio, name);
768 nfsstat3 nfsio_write(struct nfsio *nfsio, const char *name, char *buf, uint32 offset, int len, int stable)
770 struct WRITE3args WRITE3args;
771 struct WRITE3res *WRITE3res;
775 fh = lookup_fhandle(nfsio, name);
777 fprintf(stderr, "failed to fetch handle in nfsio_write\n");
778 ret = NFS3ERR_SERVERFAULT;
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;
791 WRITE3res = nfsproc3_write_3(&WRITE3args, nfsio->clnt);
793 if (WRITE3res == NULL) {
794 fprintf(stderr, "nfsproc3_write_3 failed in nfsio_write\n");
795 ret = NFS3ERR_SERVERFAULT;
799 if (WRITE3res->status != NFS3_OK) {
800 fprintf(stderr, "nfsproc3_write_3 failed in getattr. status:%d\n", WRITE3res->status);
801 ret = WRITE3res->status;
808 nfsstat3 nfsio_read(struct nfsio *nfsio, const char *name, char *buf, uint32 offset, int len, int *count, int *eof)
810 struct READ3args READ3args;
811 struct READ3res *READ3res;
815 fh = lookup_fhandle(nfsio, name);
817 fprintf(stderr, "failed to fetch handle in nfsio_read\n");
818 ret = NFS3ERR_SERVERFAULT;
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;
827 READ3res = nfsproc3_read_3(&READ3args, nfsio->clnt);
829 if (READ3res == NULL) {
830 fprintf(stderr, "nfsproc3_read_3 failed in nfsio_read\n");
831 ret = NFS3ERR_SERVERFAULT;
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;
842 *count = READ3res->READ3res_u.resok.count;
845 *eof = READ3res->READ3res_u.resok.eof;
848 memcpy(buf, &READ3res->READ3res_u.resok.data.data_val,
849 READ3res->READ3res_u.resok.count);
851 free(READ3res->READ3res_u.resok.data.data_val);
852 READ3res->READ3res_u.resok.data.data_val = NULL;
859 nfsstat3 nfsio_commit(struct nfsio *nfsio, const char *name)
861 struct COMMIT3args COMMIT3args;
862 struct COMMIT3res *COMMIT3res;
866 fh = lookup_fhandle(nfsio, name);
868 fprintf(stderr, "failed to fetch handle in nfsio_commit\n");
869 ret = NFS3ERR_SERVERFAULT;
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;
879 COMMIT3res = nfsproc3_commit_3(&COMMIT3args, nfsio->clnt);
881 if (COMMIT3res == NULL) {
882 fprintf(stderr, "nfsproc3_commit_3 failed in nfsio_commit\n");
883 ret = NFS3ERR_SERVERFAULT;
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;
897 nfsstat3 nfsio_fsinfo(struct nfsio *nfsio)
899 struct FSINFO3args FSINFO3args;
900 struct FSINFO3res *FSINFO3res;
903 fh = lookup_fhandle(nfsio, "/");
905 fprintf(stderr, "failed to fetch handle in nfsio_fsinfo\n");
906 return NFS3ERR_SERVERFAULT;
909 FSINFO3args.fsroot.data.data_len = fh->dsize;
910 FSINFO3args.fsroot.data.data_val = discard_const(fh->dptr);
912 FSINFO3res = nfsproc3_fsinfo_3(&FSINFO3args, nfsio->clnt);
914 if (FSINFO3res == NULL) {
915 fprintf(stderr, "nfsproc3_fsinfo_3 failed in nfsio_fsinfo\n");
916 return NFS3ERR_SERVERFAULT;
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;
928 nfsstat3 nfsio_fsstat(struct nfsio *nfsio)
930 struct FSSTAT3args FSSTAT3args;
931 struct FSSTAT3res *FSSTAT3res;
934 fh = lookup_fhandle(nfsio, "/");
936 fprintf(stderr, "failed to fetch handle in nfsio_fsstat\n");
937 return NFS3ERR_SERVERFAULT;
940 FSSTAT3args.fsroot.data.data_len = fh->dsize;
941 FSSTAT3args.fsroot.data.data_val = discard_const(fh->dptr);
943 FSSTAT3res = nfsproc3_fsstat_3(&FSSTAT3args, nfsio->clnt);
945 if (FSSTAT3res == NULL) {
946 fprintf(stderr, "nfsproc3_fsstat_3 failed in nfsio_fsstat\n");
947 return NFS3ERR_SERVERFAULT;
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;
958 nfsstat3 nfsio_pathconf(struct nfsio *nfsio, char *name)
960 struct PATHCONF3args PATHCONF3args;
961 struct PATHCONF3res *PATHCONF3res;
964 fh = lookup_fhandle(nfsio, name);
966 fprintf(stderr, "failed to fetch handle in nfsio_pathconf\n");
967 return NFS3ERR_SERVERFAULT;
970 PATHCONF3args.object.data.data_len = fh->dsize;
971 PATHCONF3args.object.data.data_val = discard_const(fh->dptr);
973 PATHCONF3res = nfsproc3_pathconf_3(&PATHCONF3args, nfsio->clnt);
975 if (PATHCONF3res == NULL) {
976 fprintf(stderr, "nfsproc3_pathconf_3 failed in nfsio_pathconf\n");
977 return NFS3ERR_SERVERFAULT;
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;
989 nfsstat3 nfsio_symlink(struct nfsio *nfsio, const char *old, const char *new)
992 struct SYMLINK3args SYMLINK3args;
993 struct SYMLINK3res *SYMLINK3res;
995 char *tmp_name = NULL;
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;
1006 ptr = rindex(tmp_name, '/');
1008 fprintf(stderr, "name did not contain '/' in nfsio_symlink\n");
1009 ret = NFS3ERR_SERVERFAULT;
1016 fh = lookup_fhandle(nfsio, tmp_name);
1018 fprintf(stderr, "failed to fetch parent handle in nfsio_symlink\n");
1019 ret = NFS3ERR_SERVERFAULT;
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;
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);
1040 SYMLINK3res = nfsproc3_symlink_3(&SYMLINK3args, nfsio->clnt);
1042 if (SYMLINK3res == NULL) {
1043 fprintf(stderr, "nfsproc3_symlink_3 failed in nfsio_symlink\n");
1044 ret = NFS3ERR_SERVERFAULT;
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;
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);
1068 nfsstat3 nfsio_link(struct nfsio *nfsio, const char *old, const char *new)
1071 struct LINK3args LINK3args;
1072 struct LINK3res *LINK3res;
1074 char *tmp_name = NULL;
1075 data_t *fh, *new_fh;
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;
1085 ptr = rindex(tmp_name, '/');
1087 fprintf(stderr, "name did not contain '/' in nfsio_link\n");
1088 ret = NFS3ERR_SERVERFAULT;
1095 fh = lookup_fhandle(nfsio, tmp_name);
1097 fprintf(stderr, "failed to fetch parent handle in nfsio_link\n");
1098 ret = NFS3ERR_SERVERFAULT;
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;
1111 LINK3args.file.data.data_len = new_fh->dsize;
1112 LINK3args.file.data.data_val = discard_const(new_fh->dptr);
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;
1119 LINK3res = nfsproc3_link_3(&LINK3args, nfsio->clnt);
1121 if (LINK3res == NULL) {
1122 fprintf(stderr, "nfsproc3_link_3 failed in nfsio_link\n");
1123 ret = NFS3ERR_SERVERFAULT;
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;
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);
1148 nfsstat3 nfsio_readlink(struct nfsio *nfsio, char *name, char **link_name)
1150 struct READLINK3args READLINK3args;
1151 struct READLINK3res *READLINK3res;
1154 fh = lookup_fhandle(nfsio, name);
1156 fprintf(stderr, "failed to fetch handle in nfsio_readlink\n");
1157 return NFS3ERR_SERVERFAULT;
1161 READLINK3args.symlink.data.data_len = fh->dsize;
1162 READLINK3args.symlink.data.data_val = discard_const(fh->dptr);
1164 READLINK3res = nfsproc3_readlink_3(&READLINK3args, nfsio->clnt);
1166 if (READLINK3res == NULL) {
1167 fprintf(stderr, "nfsproc3_readlink_3 failed in nfsio_readlink\n");
1168 return NFS3ERR_SERVERFAULT;
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;
1177 *link_name = strdup(READLINK3res->READLINK3res_u.resok.data);
1184 nfsstat3 nfsio_rmdir(struct nfsio *nfsio, const char *name)
1187 struct RMDIR3args RMDIR3args;
1188 struct RMDIR3res *RMDIR3res;
1190 char *tmp_name = NULL;
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;
1200 ptr = rindex(tmp_name, '/');
1202 fprintf(stderr, "name did not contain '/' in nfsio_rmdir\n");
1203 ret = NFS3ERR_SERVERFAULT;
1210 fh = lookup_fhandle(nfsio, tmp_name);
1212 fprintf(stderr, "failed to fetch parent handle in nfsio_rmdir\n");
1213 ret = NFS3ERR_SERVERFAULT;
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;
1222 RMDIR3res = nfsproc3_rmdir_3(&RMDIR3args, nfsio->clnt);
1224 if (RMDIR3res == NULL) {
1225 fprintf(stderr, "nfsproc3_rmdir_3 failed in nfsio_rmdir\n");
1226 ret = NFS3ERR_SERVERFAULT;
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;
1237 delete_fhandle(nfsio, name);
1249 nfsstat3 nfsio_mkdir(struct nfsio *nfsio, const char *name)
1252 struct MKDIR3args MKDIR3args;
1253 struct MKDIR3res *MKDIR3res;
1255 char *tmp_name = NULL;
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;
1265 ptr = rindex(tmp_name, '/');
1267 fprintf(stderr, "name did not contain '/' in nfsio_mkdir\n");
1268 ret = NFS3ERR_SERVERFAULT;
1275 fh = lookup_fhandle(nfsio, tmp_name);
1277 fprintf(stderr, "failed to fetch parent handle in nfsio_mkdir\n");
1278 ret = NFS3ERR_SERVERFAULT;
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;
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;
1296 MKDIR3res = nfsproc3_mkdir_3(&MKDIR3args, nfsio->clnt);
1298 if (MKDIR3res == NULL) {
1299 fprintf(stderr, "nfsproc3_mkdir_3 failed in nfsio_mkdir\n");
1300 ret = NFS3ERR_SERVERFAULT;
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;
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);
1322 nfsstat3 nfsio_readdirplus(struct nfsio *nfsio, const char *name, nfs3_dirent_cb cb, void *private_data)
1324 struct READDIRPLUS3args READDIRPLUS3args;
1325 struct READDIRPLUS3res *READDIRPLUS3res;
1328 entryplus3 *e, *last_e = NULL;
1333 if(dir[strlen(dir)-1] != '/'){
1336 dir[strlen(dir)-1] = 0;
1339 fh = lookup_fhandle(nfsio, name);
1341 fprintf(stderr, "failed to fetch handle for '%s' in nfsio_readdirplus\n", name);
1342 ret = NFS3ERR_SERVERFAULT;
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;
1354 READDIRPLUS3res = nfsproc3_readdirplus_3(&READDIRPLUS3args, nfsio->clnt);
1356 if (READDIRPLUS3res == NULL) {
1357 fprintf(stderr, "nfsproc3_readdirplus_3 failed in readdirplus\n");
1358 ret = NFS3ERR_SERVERFAULT;
1362 if (READDIRPLUS3res->status != NFS3_OK) {
1363 fprintf(stderr, "nfsproc3_readdirplus_3 failed in readdirplus. status:%d\n", READDIRPLUS3res->status);
1364 ret = READDIRPLUS3res->status;
1368 for(e = READDIRPLUS3res->READDIRPLUS3res_u.resok.reply.entries;e;e=e->nextentry){
1371 if(!strcmp(e->name, ".")){
1374 if(!strcmp(e->name, "..")){
1377 if(e->name_handle.handle_follows == 0){
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);
1390 cb(e, private_data);
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);
1401 READDIRPLUS3args.cookie = last_e->cookie;
1415 nfsstat3 nfsio_rename(struct nfsio *nfsio, const char *old, const char *new)
1418 struct RENAME3args RENAME3args;
1419 struct RENAME3res *RENAME3res;
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;
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;
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;
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;
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;
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;
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;
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;
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;
1483 RENAME3res = nfsproc3_rename_3(&RENAME3args, nfsio->clnt);
1485 if (RENAME3res == NULL) {
1486 fprintf(stderr, "nfsproc3_rename_3 failed in nfsio_rename\n");
1487 ret = NFS3ERR_SERVERFAULT;
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;
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;
1506 insert_fhandle(nfsio, new, old_fh->dptr, old_fh->dsize);
1507 delete_fhandle(nfsio, old);