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 {
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, ssize_t *size)
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, ssize_t size)
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;
271 if (nfsio->fhandles == NULL) {
276 tmp_t = nfsio->fhandles;
278 i = strcmp(t->key.dptr, tmp_t->key.dptr);
280 free(discard_const(tmp_t->fh.dptr));
281 tmp_t->fh.dsize = t->fh.dsize;
282 tmp_t->fh.dptr = t->fh.dptr;
283 free(discard_const(t->key.dptr));
288 if (tmp_t->left == NULL) {
296 if (tmp_t->right == NULL) {
301 tmp_t = tmp_t->right;
311 static const struct nfs_errors nfs_errors[] = {
314 {"NFS3ERR_NOENT", 2},
317 {"NFS3ERR_ACCES", 13},
318 {"NFS3ERR_EXIST", 17},
319 {"NFS3ERR_XDEV", 18},
320 {"NFS3ERR_NODEV", 19},
321 {"NFS3ERR_NOTDIR", 20},
322 {"NFS3ERR_ISDIR", 21},
323 {"NFS3ERR_INVAL", 22},
324 {"NFS3ERR_FBIG", 27},
325 {"NFS3ERR_NOSPC", 28},
326 {"NFS3ERR_ROFS", 30},
327 {"NFS3ERR_MLINK", 31},
328 {"NFS3ERR_NAMETOOLONG", 63},
329 {"NFS3ERR_NOTEMPTY", 66},
330 {"NFS3ERR_DQUOT", 69},
331 {"NFS3ERR_STALE", 70},
332 {"NFS3ERR_REMOTE", 71},
333 {"NFS3ERR_BADHANDLE", 10001},
334 {"NFS3ERR_NOT_SYNC", 10002},
335 {"NFS3ERR_BAD_COOKIE", 10003},
336 {"NFS3ERR_NOTSUPP", 10004},
337 {"NFS3ERR_TOOSMALL", 10005},
338 {"NFS3ERR_SERVERFAULT", 10006},
339 {"NFS3ERR_BADTYPE", 10007},
340 {"NFS3ERR_JUKEBOX", 10008},
345 const char *nfs_error(int error)
349 for(i=0;i<sizeof(nfs_errors)/sizeof(struct nfs_errors);i++) {
350 if (error == nfs_errors[i].idx) {
351 return nfs_errors[i].err;
354 return "Unknown NFS error";
360 void nfsio_disconnect(struct nfsio *nfsio)
362 if (nfsio->clnt != NULL) {
363 clnt_destroy(nfsio->clnt);
366 if (nfsio->s != -1) {
369 // qqq free the tree*/
377 struct nfsio *nfsio_connect(const char *server, const char *export, const char *protocol)
379 dirpath mountdir=discard_const(export);
383 struct sockaddr_in sin;
386 nfsio = malloc(sizeof(struct nfsio));
388 fprintf(stderr, "Failed to malloc nfsio\n");
391 bzero(nfsio, sizeof(struct nfsio));
397 * set up the MOUNT client. If we are running as root, we get
398 * a port <1024 by default. If we are not root, we can not
399 * bind to these ports, so the server must be in "insecure"
402 memset(&sin, 0, sizeof(sin));
404 sin.sin_family = PF_INET;
405 if (inet_aton(server, &sin.sin_addr) == 0) {
406 fprintf(stderr, "Invalid address '%s'\n", server);
407 nfsio_disconnect(nfsio);
411 if (!strcmp(protocol, "tcp")) {
412 nfsio->s = RPC_ANYSOCK;
413 nfsio->clnt = clnttcp_create(&sin, MOUNT_PROGRAM, MOUNT_V3, &nfsio->s, 32768, 32768);
419 nfsio->s = RPC_ANYSOCK;
420 nfsio->clnt = clntudp_create(&sin, MOUNT_PROGRAM, MOUNT_V3, wait, &nfsio->s);
423 if (nfsio->clnt == NULL) {
424 printf("ERROR: failed to connect to MOUNT daemon on %s\n", server);
425 nfsio_disconnect(nfsio);
428 nfsio->clnt->cl_auth = authunix_create_default();
430 mountres=mountproc3_mnt_3(&mountdir, nfsio->clnt);
431 if (mountres == NULL) {
432 printf("ERROR: failed to call the MNT procedure\n");
433 nfsio_disconnect(nfsio);
436 if (mountres->fhs_status != MNT3_OK) {
437 printf("ERROR: Server returned error %d when trying to MNT\n",mountres->fhs_status);
438 nfsio_disconnect(nfsio);
442 fh = &mountres->mountres3_u.mountinfo.fhandle;
443 insert_fhandle(nfsio, "/",
449 /* we dont need the mount client any more */
450 clnt_destroy(nfsio->clnt);
457 * set up the NFS client. If we are running as root, we get
458 * a port <1024 by default. If we are not root, we can not
459 * bind to these ports, so the server must be in "insecure"
462 memset(&sin, 0, sizeof(sin));
464 sin.sin_family = PF_INET;
465 if (inet_aton(server, &sin.sin_addr) == 0) {
466 fprintf(stderr, "Invalid address '%s'\n", server);
467 nfsio_disconnect(nfsio);
471 if (!strcmp(protocol, "tcp")) {
472 nfsio->s = RPC_ANYSOCK;
473 nfsio->clnt = clnttcp_create(&sin, NFS_PROGRAM, NFS_V3, &nfsio->s, 327680, 327680);
479 nfsio->s = RPC_ANYSOCK;
480 nfsio->clnt = clntudp_create(&sin, NFS_PROGRAM, NFS_V3, wait, &nfsio->s);
483 if (nfsio->clnt == NULL) {
484 fprintf(stderr, "Failed to initialize nfs client structure\n");
485 nfsio_disconnect(nfsio);
488 nfsio->clnt->cl_auth = authunix_create_default();
494 nfsstat3 nfsio_getattr(struct nfsio *nfsio, const char *name, fattr3 *attributes)
496 struct GETATTR3args GETATTR3args;
497 struct GETATTR3res *GETATTR3res;
500 fh = lookup_fhandle(nfsio, name, NULL);
502 fprintf(stderr, "failed to fetch handle in nfsio_getattr\n");
503 return NFS3ERR_SERVERFAULT;
506 GETATTR3args.object.data.data_len = fh->dsize;
507 GETATTR3args.object.data.data_val = discard_const(fh->dptr);
509 GETATTR3res = nfsproc3_getattr_3(&GETATTR3args, nfsio->clnt);
511 if (GETATTR3res == NULL) {
512 fprintf(stderr, "nfsproc3_getattr_3 failed in getattr\n");
513 return NFS3ERR_SERVERFAULT;
516 if (GETATTR3res->status != NFS3_OK) {
517 fprintf(stderr, "nfsproc3_getattr_3 failed in getattr. status:%d\n", GETATTR3res->status);
518 return GETATTR3res->status;
522 memcpy(attributes, &GETATTR3res->GETATTR3res_u.resok.obj_attributes, sizeof(fattr3));
528 nfsstat3 nfsio_lookup(struct nfsio *nfsio, const char *name, fattr3 *attributes)
531 struct LOOKUP3args LOOKUP3args;
532 struct LOOKUP3res *LOOKUP3res;
533 char *tmp_name = NULL;
538 tmp_name = strdup(name);
539 if (tmp_name == NULL) {
540 fprintf(stderr, "failed to strdup name in nfsio_lookup\n");
541 ret = NFS3ERR_SERVERFAULT;
545 ptr = rindex(tmp_name, '/');
547 fprintf(stderr, "name did not contain '/' in nfsio_lookup\n");
548 ret = NFS3ERR_SERVERFAULT;
555 fh = lookup_fhandle(nfsio, tmp_name, NULL);
557 fprintf(stderr, "failed to fetch parent handle for '%s' in nfsio_lookup\n", tmp_name);
558 ret = NFS3ERR_SERVERFAULT;
562 LOOKUP3args.what.dir.data.data_len = fh->dsize;
563 LOOKUP3args.what.dir.data.data_val = discard_const(fh->dptr);
564 LOOKUP3args.what.name = ptr;
566 LOOKUP3res = nfsproc3_lookup_3(&LOOKUP3args, nfsio->clnt);
568 if (LOOKUP3res == NULL) {
569 fprintf(stderr, "nfsproc3_lookup_3 failed in lookup\n");
570 ret = NFS3ERR_SERVERFAULT;
574 if (LOOKUP3res->status != NFS3_OK) {
575 ret = LOOKUP3res->status;
579 insert_fhandle(nfsio, name,
580 LOOKUP3res->LOOKUP3res_u.resok.object.data.data_val,
581 LOOKUP3res->LOOKUP3res_u.resok.object.data.data_len,
582 LOOKUP3res->LOOKUP3res_u.resok.obj_attributes.post_op_attr_u.attributes.size);
584 free(LOOKUP3res->LOOKUP3res_u.resok.object.data.data_val);
587 memcpy(attributes, &LOOKUP3res->LOOKUP3res_u.resok.obj_attributes.post_op_attr_u.attributes, sizeof(fattr3));
598 nfsstat3 nfsio_access(struct nfsio *nfsio, const char *name, uint32 desired, uint32 *access)
601 struct ACCESS3args ACCESS3args;
602 struct ACCESS3res *ACCESS3res;
605 fh = lookup_fhandle(nfsio, name, NULL);
607 fprintf(stderr, "failed to fetch handle in nfsio_access\n");
608 return NFS3ERR_SERVERFAULT;
611 ACCESS3args.object.data.data_val = discard_const(fh->dptr);
612 ACCESS3args.object.data.data_len = fh->dsize;
613 ACCESS3args.access = desired;
615 ACCESS3res = nfsproc3_access_3(&ACCESS3args, nfsio->clnt);
617 if (ACCESS3res == NULL) {
618 fprintf(stderr, "nfsproc3_access_3 failed in access\n");
619 return NFS3ERR_SERVERFAULT;
622 if (ACCESS3res->status != NFS3_OK) {
623 fprintf(stderr, "nfsproc3_access_3 failed. status:%d\n",
625 return ACCESS3res->status;
629 *access = ACCESS3res->ACCESS3res_u.resok.access;
637 nfsstat3 nfsio_create(struct nfsio *nfsio, const char *name)
640 struct CREATE3args CREATE3args;
641 struct CREATE3res *CREATE3res;
642 char *tmp_name = NULL;
647 tmp_name = strdup(name);
648 if (tmp_name == NULL) {
649 fprintf(stderr, "failed to strdup name in nfsio_create\n");
650 ret = NFS3ERR_SERVERFAULT;
654 ptr = rindex(tmp_name, '/');
656 fprintf(stderr, "name did not contain '/' in nfsio_create\n");
657 ret = NFS3ERR_SERVERFAULT;
664 fh = lookup_fhandle(nfsio, tmp_name, NULL);
666 fprintf(stderr, "failed to fetch parent handle in nfsio_create\n");
667 ret = NFS3ERR_SERVERFAULT;
671 CREATE3args.where.dir.data.data_len = fh->dsize;
672 CREATE3args.where.dir.data.data_val = discard_const(fh->dptr);
673 CREATE3args.where.name = ptr;
675 CREATE3args.how.mode = UNCHECKED;
676 CREATE3args.how.createhow3_u.obj_attributes.mode.set_it = TRUE;
677 CREATE3args.how.createhow3_u.obj_attributes.mode.set_mode3_u.mode = 0777;
678 CREATE3args.how.createhow3_u.obj_attributes.uid.set_it = TRUE;
679 CREATE3args.how.createhow3_u.obj_attributes.uid.set_uid3_u.uid = 0;
680 CREATE3args.how.createhow3_u.obj_attributes.gid.set_it = TRUE;
681 CREATE3args.how.createhow3_u.obj_attributes.gid.set_gid3_u.gid = 0;
682 CREATE3args.how.createhow3_u.obj_attributes.size.set_it = FALSE;
683 CREATE3args.how.createhow3_u.obj_attributes.atime.set_it = FALSE;
684 CREATE3args.how.createhow3_u.obj_attributes.mtime.set_it = FALSE;
686 CREATE3res = nfsproc3_create_3(&CREATE3args, nfsio->clnt);
688 if (CREATE3res == NULL) {
689 fprintf(stderr, "nfsproc3_create_3 failed in nfsio_create\n");
690 ret = NFS3ERR_SERVERFAULT;
694 if (CREATE3res->status != NFS3_OK) {
695 fprintf(stderr, "nfsproc3_create_3 failed in nfsio_create. status:%d\n", CREATE3res->status);
696 ret = CREATE3res->status;
701 insert_fhandle(nfsio, name,
702 CREATE3res->CREATE3res_u.resok.obj.post_op_fh3_u.handle.data.data_val,
703 CREATE3res->CREATE3res_u.resok.obj.post_op_fh3_u.handle.data.data_len,
715 nfsstat3 nfsio_remove(struct nfsio *nfsio, const char *name)
718 struct REMOVE3args REMOVE3args;
719 struct REMOVE3res *REMOVE3res;
721 char *tmp_name = NULL;
725 tmp_name = strdup(name);
726 if (tmp_name == NULL) {
727 fprintf(stderr, "failed to strdup name in nfsio_remove\n");
728 ret = NFS3ERR_SERVERFAULT;
732 ptr = rindex(tmp_name, '/');
734 fprintf(stderr, "name did not contain '/' in nfsio_remove\n");
735 ret = NFS3ERR_SERVERFAULT;
742 fh = lookup_fhandle(nfsio, tmp_name, NULL);
744 fprintf(stderr, "failed to fetch parent handle in nfsio_remove\n");
745 ret = NFS3ERR_SERVERFAULT;
750 REMOVE3args.object.dir.data.data_len = fh->dsize;
751 REMOVE3args.object.dir.data.data_val = discard_const(fh->dptr);
752 REMOVE3args.object.name = ptr;
754 REMOVE3res = nfsproc3_remove_3(&REMOVE3args, nfsio->clnt);
756 if (REMOVE3res == NULL) {
757 fprintf(stderr, "nfsproc3_remove_3 failed in nfsio_remove\n");
758 ret = NFS3ERR_SERVERFAULT;
762 if (REMOVE3res->status != NFS3_OK) {
763 fprintf(stderr, "nfsproc3_remove_3 failed in nfsio_remove. status:%d\n", REMOVE3res->status);
764 ret = REMOVE3res->status;
769 delete_fhandle(nfsio, name);
780 nfsstat3 nfsio_write(struct nfsio *nfsio, const char *name, char *buf, uint32 offset, int len, int stable)
782 struct WRITE3args WRITE3args;
783 struct WRITE3res *WRITE3res;
787 fh = lookup_fhandle(nfsio, name, NULL);
789 fprintf(stderr, "failed to fetch handle in nfsio_write\n");
790 ret = NFS3ERR_SERVERFAULT;
794 WRITE3args.file.data.data_len = fh->dsize;
795 WRITE3args.file.data.data_val = discard_const(fh->dptr);
796 WRITE3args.offset = offset;
797 WRITE3args.count = len;
798 WRITE3args.stable = stable;
799 WRITE3args.data.data_len = len;
800 WRITE3args.data.data_val = buf;
803 WRITE3res = nfsproc3_write_3(&WRITE3args, nfsio->clnt);
805 if (WRITE3res == NULL) {
806 fprintf(stderr, "nfsproc3_write_3 failed in nfsio_write\n");
807 ret = NFS3ERR_SERVERFAULT;
811 if (WRITE3res->status != NFS3_OK) {
812 fprintf(stderr, "nfsproc3_write_3 failed in getattr. status:%d\n", WRITE3res->status);
813 ret = WRITE3res->status;
820 nfsstat3 nfsio_read(struct nfsio *nfsio, const char *name, char *buf, uint32 offset, int len, int *count, int *eof)
822 struct READ3args READ3args;
823 struct READ3res *READ3res;
828 fh = lookup_fhandle(nfsio, name, &size);
830 fprintf(stderr, "failed to fetch handle in nfsio_read\n");
831 ret = NFS3ERR_SERVERFAULT;
835 if (offset >= size) {
836 offset = offset % size;
838 if (offset+len >= size) {
842 READ3args.file.data.data_len = fh->dsize;
843 READ3args.file.data.data_val = discard_const(fh->dptr);
844 READ3args.offset = offset;
845 READ3args.count = len;
847 READ3res = nfsproc3_read_3(&READ3args, nfsio->clnt);
849 if (READ3res == NULL) {
850 fprintf(stderr, "nfsproc3_read_3 failed in nfsio_read\n");
851 ret = NFS3ERR_SERVERFAULT;
855 if (READ3res->status != NFS3_OK) {
856 fprintf(stderr, "nfsproc3_read_3 failed in nfsio_read. status:%d\n", READ3res->status);
857 ret = READ3res->status;
862 *count = READ3res->READ3res_u.resok.count;
865 *eof = READ3res->READ3res_u.resok.eof;
868 memcpy(buf, &READ3res->READ3res_u.resok.data.data_val,
869 READ3res->READ3res_u.resok.count);
871 free(READ3res->READ3res_u.resok.data.data_val);
872 READ3res->READ3res_u.resok.data.data_val = NULL;
879 nfsstat3 nfsio_commit(struct nfsio *nfsio, const char *name)
881 struct COMMIT3args COMMIT3args;
882 struct COMMIT3res *COMMIT3res;
886 fh = lookup_fhandle(nfsio, name, NULL);
888 fprintf(stderr, "failed to fetch handle in nfsio_commit\n");
889 ret = NFS3ERR_SERVERFAULT;
893 COMMIT3args.file.data.data_len = fh->dsize;
894 COMMIT3args.file.data.data_val = discard_const(fh->dptr);
895 COMMIT3args.offset = 0;
896 COMMIT3args.count = 0;
899 COMMIT3res = nfsproc3_commit_3(&COMMIT3args, nfsio->clnt);
901 if (COMMIT3res == NULL) {
902 fprintf(stderr, "nfsproc3_commit_3 failed in nfsio_commit\n");
903 ret = NFS3ERR_SERVERFAULT;
907 if (COMMIT3res->status != NFS3_OK) {
908 fprintf(stderr, "nfsproc3_commit_3 failed in nfsio_commit. status:%d\n", COMMIT3res->status);
909 ret = COMMIT3res->status;
917 nfsstat3 nfsio_fsinfo(struct nfsio *nfsio)
919 struct FSINFO3args FSINFO3args;
920 struct FSINFO3res *FSINFO3res;
923 fh = lookup_fhandle(nfsio, "/", NULL);
925 fprintf(stderr, "failed to fetch handle in nfsio_fsinfo\n");
926 return NFS3ERR_SERVERFAULT;
929 FSINFO3args.fsroot.data.data_len = fh->dsize;
930 FSINFO3args.fsroot.data.data_val = discard_const(fh->dptr);
932 FSINFO3res = nfsproc3_fsinfo_3(&FSINFO3args, nfsio->clnt);
934 if (FSINFO3res == NULL) {
935 fprintf(stderr, "nfsproc3_fsinfo_3 failed in nfsio_fsinfo\n");
936 return NFS3ERR_SERVERFAULT;
939 if (FSINFO3res->status != NFS3_OK) {
940 fprintf(stderr, "nfsproc3_fsinfo_3 failed in nfsio_fsinfo. status:%d\n", FSINFO3res->status);
941 return FSINFO3res->status;
948 nfsstat3 nfsio_fsstat(struct nfsio *nfsio)
950 struct FSSTAT3args FSSTAT3args;
951 struct FSSTAT3res *FSSTAT3res;
954 fh = lookup_fhandle(nfsio, "/", NULL);
956 fprintf(stderr, "failed to fetch handle in nfsio_fsstat\n");
957 return NFS3ERR_SERVERFAULT;
960 FSSTAT3args.fsroot.data.data_len = fh->dsize;
961 FSSTAT3args.fsroot.data.data_val = discard_const(fh->dptr);
963 FSSTAT3res = nfsproc3_fsstat_3(&FSSTAT3args, nfsio->clnt);
965 if (FSSTAT3res == NULL) {
966 fprintf(stderr, "nfsproc3_fsstat_3 failed in nfsio_fsstat\n");
967 return NFS3ERR_SERVERFAULT;
970 if (FSSTAT3res->status != NFS3_OK) {
971 fprintf(stderr, "nfsproc3_fsstat_3 failed in nfsio_fsstat. status:%d\n", FSSTAT3res->status);
972 return FSSTAT3res->status;
978 nfsstat3 nfsio_pathconf(struct nfsio *nfsio, char *name)
980 struct PATHCONF3args PATHCONF3args;
981 struct PATHCONF3res *PATHCONF3res;
984 fh = lookup_fhandle(nfsio, name, NULL);
986 fprintf(stderr, "failed to fetch handle in nfsio_pathconf\n");
987 return NFS3ERR_SERVERFAULT;
990 PATHCONF3args.object.data.data_len = fh->dsize;
991 PATHCONF3args.object.data.data_val = discard_const(fh->dptr);
993 PATHCONF3res = nfsproc3_pathconf_3(&PATHCONF3args, nfsio->clnt);
995 if (PATHCONF3res == NULL) {
996 fprintf(stderr, "nfsproc3_pathconf_3 failed in nfsio_pathconf\n");
997 return NFS3ERR_SERVERFAULT;
1000 if (PATHCONF3res->status != NFS3_OK) {
1001 fprintf(stderr, "nfsproc3_pathconf_3 failed in nfsio_pathconf. status:%d\n", PATHCONF3res->status);
1002 return PATHCONF3res->status;
1009 nfsstat3 nfsio_symlink(struct nfsio *nfsio, const char *old, const char *new)
1012 struct SYMLINK3args SYMLINK3args;
1013 struct SYMLINK3res *SYMLINK3res;
1015 char *tmp_name = NULL;
1019 tmp_name = strdup(old);
1020 if (tmp_name == NULL) {
1021 fprintf(stderr, "failed to strdup name in nfsio_symlink\n");
1022 ret = NFS3ERR_SERVERFAULT;
1026 ptr = rindex(tmp_name, '/');
1028 fprintf(stderr, "name did not contain '/' in nfsio_symlink\n");
1029 ret = NFS3ERR_SERVERFAULT;
1036 fh = lookup_fhandle(nfsio, tmp_name, NULL);
1038 fprintf(stderr, "failed to fetch parent handle in nfsio_symlink\n");
1039 ret = NFS3ERR_SERVERFAULT;
1044 SYMLINK3args.where.dir.data.data_len = fh->dsize;
1045 SYMLINK3args.where.dir.data.data_val = discard_const(fh->dptr);
1046 SYMLINK3args.where.name = ptr;
1048 SYMLINK3args.symlink.symlink_attributes.mode.set_it = TRUE;
1049 SYMLINK3args.symlink.symlink_attributes.mode.set_mode3_u.mode = 0777;
1050 SYMLINK3args.symlink.symlink_attributes.uid.set_it = TRUE;
1051 SYMLINK3args.symlink.symlink_attributes.uid.set_uid3_u.uid= 0;
1052 SYMLINK3args.symlink.symlink_attributes.gid.set_it = TRUE;
1053 SYMLINK3args.symlink.symlink_attributes.gid.set_gid3_u.gid = 0;
1054 SYMLINK3args.symlink.symlink_attributes.size.set_it = FALSE;
1055 SYMLINK3args.symlink.symlink_attributes.atime.set_it = FALSE;
1056 SYMLINK3args.symlink.symlink_attributes.mtime.set_it = FALSE;
1057 SYMLINK3args.symlink.symlink_data = discard_const(new);
1060 SYMLINK3res = nfsproc3_symlink_3(&SYMLINK3args, nfsio->clnt);
1062 if (SYMLINK3res == NULL) {
1063 fprintf(stderr, "nfsproc3_symlink_3 failed in nfsio_symlink\n");
1064 ret = NFS3ERR_SERVERFAULT;
1068 if (SYMLINK3res->status != NFS3_OK) {
1069 fprintf(stderr, "nfsproc3_symlink_3 failed in nfsio_symlink. status:%d\n", SYMLINK3res->status);
1070 ret = SYMLINK3res->status;
1075 insert_fhandle(nfsio, old,
1076 SYMLINK3res->SYMLINK3res_u.resok.obj.post_op_fh3_u.handle.data.data_val,
1077 SYMLINK3res->SYMLINK3res_u.resok.obj.post_op_fh3_u.handle.data.data_len,
1090 nfsstat3 nfsio_link(struct nfsio *nfsio, const char *old, const char *new)
1093 struct LINK3args LINK3args;
1094 struct LINK3res *LINK3res;
1096 char *tmp_name = NULL;
1097 data_t *fh, *new_fh;
1100 tmp_name = strdup(old);
1101 if (tmp_name == NULL) {
1102 fprintf(stderr, "failed to strdup name in nfsio_link\n");
1103 ret = NFS3ERR_SERVERFAULT;
1107 ptr = rindex(tmp_name, '/');
1109 fprintf(stderr, "name did not contain '/' in nfsio_link\n");
1110 ret = NFS3ERR_SERVERFAULT;
1117 fh = lookup_fhandle(nfsio, tmp_name, NULL);
1119 fprintf(stderr, "failed to fetch parent handle in nfsio_link\n");
1120 ret = NFS3ERR_SERVERFAULT;
1125 new_fh = lookup_fhandle(nfsio, new, NULL);
1126 if (new_fh == NULL) {
1127 fprintf(stderr, "failed to fetch handle in nfsio_link\n");
1128 ret = NFS3ERR_SERVERFAULT;
1133 LINK3args.file.data.data_len = new_fh->dsize;
1134 LINK3args.file.data.data_val = discard_const(new_fh->dptr);
1137 LINK3args.link.dir.data.data_len = fh->dsize;
1138 LINK3args.link.dir.data.data_val = discard_const(fh->dptr);
1139 LINK3args.link.name = ptr;
1141 LINK3res = nfsproc3_link_3(&LINK3args, nfsio->clnt);
1143 if (LINK3res == NULL) {
1144 fprintf(stderr, "nfsproc3_link_3 failed in nfsio_link\n");
1145 ret = NFS3ERR_SERVERFAULT;
1149 if (LINK3res->status != NFS3_OK) {
1150 fprintf(stderr, "nfsproc3_link_3 failed in nfsio_link. status:%d\n", LINK3res->status);
1151 ret = LINK3res->status;
1156 // insert_fhandle(nfsio, old,
1157 // LINK3res->LINK3res_u.resok.obj.post_op_fh3_u.handle.data.data_val,
1158 // LINK3res->LINK3res_u.resok.obj.post_op_fh3_u.handle.data.data_len);
1170 nfsstat3 nfsio_readlink(struct nfsio *nfsio, char *name, char **link_name)
1172 struct READLINK3args READLINK3args;
1173 struct READLINK3res *READLINK3res;
1176 fh = lookup_fhandle(nfsio, name, NULL);
1178 fprintf(stderr, "failed to fetch handle in nfsio_readlink\n");
1179 return NFS3ERR_SERVERFAULT;
1183 READLINK3args.symlink.data.data_len = fh->dsize;
1184 READLINK3args.symlink.data.data_val = discard_const(fh->dptr);
1186 READLINK3res = nfsproc3_readlink_3(&READLINK3args, nfsio->clnt);
1188 if (READLINK3res == NULL) {
1189 fprintf(stderr, "nfsproc3_readlink_3 failed in nfsio_readlink\n");
1190 return NFS3ERR_SERVERFAULT;
1193 if (READLINK3res->status != NFS3_OK) {
1194 fprintf(stderr, "nfsproc3_readlink_3 failed in nfsio_readlink. status:%d\n", READLINK3res->status);
1195 return READLINK3res->status;
1199 *link_name = strdup(READLINK3res->READLINK3res_u.resok.data);
1206 nfsstat3 nfsio_rmdir(struct nfsio *nfsio, const char *name)
1209 struct RMDIR3args RMDIR3args;
1210 struct RMDIR3res *RMDIR3res;
1212 char *tmp_name = NULL;
1216 tmp_name = strdup(name);
1217 if (tmp_name == NULL) {
1218 fprintf(stderr, "failed to strdup name in nfsio_rmdir\n");
1219 return NFS3ERR_SERVERFAULT;
1222 ptr = rindex(tmp_name, '/');
1224 fprintf(stderr, "name did not contain '/' in nfsio_rmdir\n");
1225 ret = NFS3ERR_SERVERFAULT;
1232 fh = lookup_fhandle(nfsio, tmp_name, NULL);
1234 fprintf(stderr, "failed to fetch parent handle in nfsio_rmdir\n");
1235 ret = NFS3ERR_SERVERFAULT;
1240 RMDIR3args.object.dir.data.data_len = fh->dsize;
1241 RMDIR3args.object.dir.data.data_val = discard_const(fh->dptr);
1242 RMDIR3args.object.name = ptr;
1244 RMDIR3res = nfsproc3_rmdir_3(&RMDIR3args, nfsio->clnt);
1246 if (RMDIR3res == NULL) {
1247 fprintf(stderr, "nfsproc3_rmdir_3 failed in nfsio_rmdir\n");
1248 ret = NFS3ERR_SERVERFAULT;
1252 if (RMDIR3res->status != NFS3_OK) {
1253 fprintf(stderr, "nfsproc3_rmdir_3(%s) failed in nfsio_rmdir. status:%s(%d)\n", name, nfs_error(RMDIR3res->status), RMDIR3res->status);
1254 ret = RMDIR3res->status;
1259 delete_fhandle(nfsio, name);
1271 nfsstat3 nfsio_mkdir(struct nfsio *nfsio, const char *name)
1274 struct MKDIR3args MKDIR3args;
1275 struct MKDIR3res *MKDIR3res;
1277 char *tmp_name = NULL;
1281 tmp_name = strdup(name);
1282 if (tmp_name == NULL) {
1283 fprintf(stderr, "failed to strdup name in nfsio_mkdir\n");
1284 return NFS3ERR_SERVERFAULT;
1287 ptr = rindex(tmp_name, '/');
1289 fprintf(stderr, "name did not contain '/' in nfsio_mkdir\n");
1290 ret = NFS3ERR_SERVERFAULT;
1297 fh = lookup_fhandle(nfsio, tmp_name, NULL);
1299 fprintf(stderr, "failed to fetch parent handle in nfsio_mkdir\n");
1300 ret = NFS3ERR_SERVERFAULT;
1304 MKDIR3args.where.dir.data.data_len = fh->dsize;
1305 MKDIR3args.where.dir.data.data_val = discard_const(fh->dptr);
1306 MKDIR3args.where.name = ptr;
1308 MKDIR3args.attributes.mode.set_it = TRUE;
1309 MKDIR3args.attributes.mode.set_mode3_u.mode = 0777;
1310 MKDIR3args.attributes.uid.set_it = TRUE;
1311 MKDIR3args.attributes.uid.set_uid3_u.uid = 0;
1312 MKDIR3args.attributes.gid.set_it = TRUE;
1313 MKDIR3args.attributes.gid.set_gid3_u.gid = 0;
1314 MKDIR3args.attributes.size.set_it = FALSE;
1315 MKDIR3args.attributes.atime.set_it = FALSE;
1316 MKDIR3args.attributes.mtime.set_it = FALSE;
1318 MKDIR3res = nfsproc3_mkdir_3(&MKDIR3args, nfsio->clnt);
1320 if (MKDIR3res == NULL) {
1321 fprintf(stderr, "nfsproc3_mkdir_3 failed in nfsio_mkdir\n");
1322 ret = NFS3ERR_SERVERFAULT;
1326 if (MKDIR3res->status != NFS3_OK) {
1327 fprintf(stderr, "nfsproc3_mkdir_3(%s) failed in nfsio_mkdir. status:%s(%d)\n", name, nfs_error(MKDIR3res->status), MKDIR3res->status);
1328 ret = MKDIR3res->status;
1332 insert_fhandle(nfsio, name,
1333 MKDIR3res->MKDIR3res_u.resok.obj.post_op_fh3_u.handle.data.data_val,
1334 MKDIR3res->MKDIR3res_u.resok.obj.post_op_fh3_u.handle.data.data_len,
1346 nfsstat3 nfsio_readdirplus(struct nfsio *nfsio, const char *name, nfs3_dirent_cb cb, void *private_data)
1348 struct READDIRPLUS3args READDIRPLUS3args;
1349 struct READDIRPLUS3res *READDIRPLUS3res;
1352 entryplus3 *e, *last_e = NULL;
1357 if(dir[strlen(dir)-1] != '/'){
1360 dir[strlen(dir)-1] = 0;
1363 fh = lookup_fhandle(nfsio, name, NULL);
1365 fprintf(stderr, "failed to fetch handle for '%s' in nfsio_readdirplus\n", name);
1366 ret = NFS3ERR_SERVERFAULT;
1370 READDIRPLUS3args.dir.data.data_len = fh->dsize;
1371 READDIRPLUS3args.dir.data.data_val = discard_const(fh->dptr);
1372 READDIRPLUS3args.cookie = 0;
1373 bzero(&READDIRPLUS3args.cookieverf, NFS3_COOKIEVERFSIZE);
1374 READDIRPLUS3args.dircount = 6000;
1375 READDIRPLUS3args.maxcount = 8192;
1378 READDIRPLUS3res = nfsproc3_readdirplus_3(&READDIRPLUS3args, nfsio->clnt);
1380 if (READDIRPLUS3res == NULL) {
1381 fprintf(stderr, "nfsproc3_readdirplus_3 failed in readdirplus\n");
1382 ret = NFS3ERR_SERVERFAULT;
1386 if (READDIRPLUS3res->status != NFS3_OK) {
1387 fprintf(stderr, "nfsproc3_readdirplus_3 failed in readdirplus. status:%d\n", READDIRPLUS3res->status);
1388 ret = READDIRPLUS3res->status;
1392 for(e = READDIRPLUS3res->READDIRPLUS3res_u.resok.reply.entries;e;e=e->nextentry){
1395 if(!strcmp(e->name, ".")){
1398 if(!strcmp(e->name, "..")){
1401 if(e->name_handle.handle_follows == 0){
1407 asprintf(&new_name, "%s/%s", dir, e->name);
1408 insert_fhandle(nfsio, new_name,
1409 e->name_handle.post_op_fh3_u.handle.data.data_val,
1410 e->name_handle.post_op_fh3_u.handle.data.data_len,
1416 cb(e, private_data);
1420 if (READDIRPLUS3res->READDIRPLUS3res_u.resok.reply.eof == 0) {
1421 if (READDIRPLUS3args.cookie == 0) {
1422 memcpy(&READDIRPLUS3args.cookieverf,
1423 &READDIRPLUS3res->READDIRPLUS3res_u.resok.cookieverf,
1424 NFS3_COOKIEVERFSIZE);
1427 READDIRPLUS3args.cookie = last_e->cookie;
1441 nfsstat3 nfsio_rename(struct nfsio *nfsio, const char *old, const char *new)
1444 struct RENAME3args RENAME3args;
1445 struct RENAME3res *RENAME3res;
1447 char *tmp_old_name = NULL;
1448 char *tmp_new_name = NULL;
1449 data_t *old_fh, *new_fh;
1450 char *old_ptr, *new_ptr;
1452 tmp_old_name = strdup(old);
1453 if (tmp_old_name == NULL) {
1454 fprintf(stderr, "failed to strdup name in nfsio_rename\n");
1455 ret = NFS3ERR_SERVERFAULT;
1459 old_ptr = rindex(tmp_old_name, '/');
1460 if (old_ptr == NULL) {
1461 fprintf(stderr, "name did not contain '/' in nfsio_rename\n");
1462 ret = NFS3ERR_SERVERFAULT;
1469 old_fh = lookup_fhandle(nfsio, tmp_old_name, NULL);
1470 if (old_fh == NULL) {
1471 fprintf(stderr, "failed to fetch parent handle in nfsio_rename\n");
1472 ret = NFS3ERR_SERVERFAULT;
1476 tmp_new_name = strdup(new);
1477 if (tmp_new_name == NULL) {
1478 fprintf(stderr, "failed to strdup name in nfsio_rename\n");
1479 ret = NFS3ERR_SERVERFAULT;
1483 new_ptr = rindex(tmp_new_name, '/');
1484 if (new_ptr == NULL) {
1485 fprintf(stderr, "name did not contain '/' in nfsio_rename\n");
1486 ret = NFS3ERR_SERVERFAULT;
1493 new_fh = lookup_fhandle(nfsio, tmp_new_name, NULL);
1494 if (new_fh == NULL) {
1495 fprintf(stderr, "failed to fetch parent handle in nfsio_rename\n");
1496 ret = NFS3ERR_SERVERFAULT;
1500 RENAME3args.from.dir.data.data_len = old_fh->dsize;
1501 RENAME3args.from.dir.data.data_val = discard_const(old_fh->dptr);
1502 RENAME3args.from.name = old_ptr;
1504 RENAME3args.to.dir.data.data_len = new_fh->dsize;
1505 RENAME3args.to.dir.data.data_val = discard_const(new_fh->dptr);
1506 RENAME3args.to.name = new_ptr;
1509 RENAME3res = nfsproc3_rename_3(&RENAME3args, nfsio->clnt);
1511 if (RENAME3res == NULL) {
1512 fprintf(stderr, "nfsproc3_rename_3 failed in nfsio_rename\n");
1513 ret = NFS3ERR_SERVERFAULT;
1517 if (RENAME3res->status != NFS3_OK) {
1518 fprintf(stderr, "nfsproc3_rename_3 failed in nfsio_rename. status:%d\n", RENAME3res->status);
1519 ret = RENAME3res->status;
1524 old_fh = lookup_fhandle(nfsio, old, NULL);
1525 if (old_fh == NULL) {
1526 fprintf(stderr, "failed to fetch parent handle in nfsio_rename\n");
1527 ret = NFS3ERR_SERVERFAULT;
1532 insert_fhandle(nfsio, new, old_fh->dptr, old_fh->dsize, 0 /*qqq*/);
1533 delete_fhandle(nfsio, old);