3115a686198b31d68a920bbb473d117f33a0cae7
[deb_libnfs.git] / lib / libnfs.c
1 /*
2 Copyright (C) 2010 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 2.1 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17 /*
18 * High level api to nfs filesystems
19 */
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #ifdef AROS
25 #include "aros_compat.h"
26 #endif
27
28 #ifdef WIN32
29 #include "win32_compat.h"
30 #endif
31
32 #ifdef HAVE_UTIME_H
33 #include <utime.h>
34 #endif
35
36 #ifdef ANDROID
37 #define statvfs statfs
38 #endif
39
40 #define _GNU_SOURCE
41
42 #ifdef HAVE_UNISTD_H
43 #include <unistd.h>
44 #endif
45
46 #ifdef HAVE_SYS_VFS_H
47 #include <sys/vfs.h>
48 #endif
49
50 #ifdef HAVE_SYS_STATVFS_H
51 #include <sys/statvfs.h>
52 #endif
53
54 #ifdef HAVE_NETINET_IN_H
55 #include <netinet/in.h>
56 #endif
57
58 #ifdef HAVE_STRINGS_H
59 #include <strings.h>
60 #endif
61
62 #ifdef MAJOR_IN_MKDEV
63 #include <sys/mkdev.h>
64 #endif
65
66 #ifdef MAJOR_IN_SYSMACROS
67 #include <sys/sysmacros.h>
68 #endif
69
70 #include <stdio.h>
71 #include <stdarg.h>
72 #include <stdlib.h>
73 #include <string.h>
74 #include <assert.h>
75 #include <errno.h>
76 #include <sys/types.h>
77 #include <sys/stat.h>
78 #include <fcntl.h>
79 #include "libnfs-zdr.h"
80 #include "slist.h"
81 #include "libnfs.h"
82 #include "libnfs-raw.h"
83 #include "libnfs-raw-mount.h"
84 #include "libnfs-raw-nfs.h"
85 #include "libnfs-raw-portmap.h"
86 #include "libnfs-private.h"
87
88 #define MAX_DIR_CACHE 128
89
90 struct nfsdir {
91 struct nfs_fh3 fh;
92 fattr3 attr;
93 struct nfsdir *next;
94
95 struct nfsdirent *entries;
96 struct nfsdirent *current;
97 };
98
99 struct nfs_readahead {
100 uint64_t fh_offset;
101 uint64_t last_offset;
102 uint64_t buf_offset;
103 uint64_t buf_count;
104 time_t buf_ts;
105 void *buf;
106 uint32_t cur_ra;
107 };
108
109 struct nfsfh {
110 struct nfs_fh3 fh;
111 int is_sync;
112 int is_append;
113 uint64_t offset;
114 struct nfs_readahead ra;
115 };
116
117 struct nfs_context {
118 struct rpc_context *rpc;
119 char *server;
120 char *export;
121 struct nfs_fh3 rootfh;
122 uint64_t readmax;
123 uint64_t writemax;
124 char *cwd;
125 struct nfsdir *dircache;
126 };
127
128 void nfs_free_nfsdir(struct nfsdir *nfsdir)
129 {
130 while (nfsdir->entries) {
131 struct nfsdirent *dirent = nfsdir->entries->next;
132 if (nfsdir->entries->name != NULL) {
133 free(nfsdir->entries->name);
134 }
135 free(nfsdir->entries);
136 nfsdir->entries = dirent;
137 }
138 free(nfsdir->fh.data.data_val);
139 free(nfsdir);
140 }
141
142 static void nfs_dircache_add(struct nfs_context *nfs, struct nfsdir *nfsdir)
143 {
144 int i;
145 LIBNFS_LIST_ADD(&nfs->dircache, nfsdir);
146
147 for (nfsdir = nfs->dircache, i = 0; nfsdir; nfsdir = nfsdir->next, i++) {
148 if (i > MAX_DIR_CACHE) {
149 LIBNFS_LIST_REMOVE(&nfs->dircache, nfsdir);
150 nfs_free_nfsdir(nfsdir);
151 break;
152 }
153 }
154 }
155
156 static struct nfsdir *nfs_dircache_find(struct nfs_context *nfs, struct nfs_fh3 *fh)
157 {
158 struct nfsdir *nfsdir;
159
160 for (nfsdir = nfs->dircache; nfsdir; nfsdir = nfsdir->next) {
161 if (nfsdir->fh.data.data_len == fh->data.data_len &&
162 !memcmp(nfsdir->fh.data.data_val, fh->data.data_val, fh->data.data_len)) {
163 LIBNFS_LIST_REMOVE(&nfs->dircache, nfsdir);
164 return nfsdir;
165 }
166 }
167
168 return NULL;
169 }
170
171 struct nfs_cb_data;
172 typedef int (*continue_func)(struct nfs_context *nfs, fattr3 *attr,
173 struct nfs_cb_data *data);
174
175 struct nfs_cb_data {
176 struct nfs_context *nfs;
177 struct nfsfh *nfsfh;
178 char *saved_path, *path;
179
180 nfs_cb cb;
181 void *private_data;
182
183 continue_func continue_cb;
184 void *continue_data;
185 void (*free_continue_data)(void *);
186 int continue_int;
187
188 struct nfs_fh3 fh;
189
190 /* for multi-read/write calls. */
191 int error;
192 int cancel;
193 int oom;
194 int num_calls;
195 uint64_t offset, count, max_offset, org_offset, org_count;
196 char *buffer;
197 char *usrbuf;
198 };
199
200 struct nfs_mcb_data {
201 struct nfs_cb_data *data;
202 uint64_t offset;
203 uint64_t count;
204 int update_pos;
205 };
206
207 static int nfs_lookup_path_async_internal(struct nfs_context *nfs, fattr3 *attr, struct nfs_cb_data *data, struct nfs_fh3 *fh);
208
209 void nfs_set_auth(struct nfs_context *nfs, struct AUTH *auth)
210 {
211 rpc_set_auth(nfs->rpc, auth);
212 }
213
214 int nfs_get_fd(struct nfs_context *nfs)
215 {
216 return rpc_get_fd(nfs->rpc);
217 }
218
219 int nfs_queue_length(struct nfs_context *nfs)
220 {
221 return rpc_queue_length(nfs->rpc);
222 }
223
224 int nfs_which_events(struct nfs_context *nfs)
225 {
226 return rpc_which_events(nfs->rpc);
227 }
228
229 int nfs_service(struct nfs_context *nfs, int revents)
230 {
231 return rpc_service(nfs->rpc, revents);
232 }
233
234 char *nfs_get_error(struct nfs_context *nfs)
235 {
236 return rpc_get_error(nfs->rpc);
237 };
238
239 static int nfs_set_context_args(struct nfs_context *nfs, char *arg, char *val)
240 {
241 if (!strcmp(arg, "tcp-syncnt")) {
242 rpc_set_tcp_syncnt(nfs_get_rpc_context(nfs), atoi(val));
243 } else if (!strcmp(arg, "uid")) {
244 rpc_set_uid(nfs_get_rpc_context(nfs), atoi(val));
245 } else if (!strcmp(arg, "gid")) {
246 rpc_set_gid(nfs_get_rpc_context(nfs), atoi(val));
247 } else if (!strcmp(arg, "readahaed")) {
248 rpc_set_readahead(nfs_get_rpc_context(nfs), atoi(val));
249 }
250 return 0;
251 }
252
253 static struct nfs_url *nfs_parse_url(struct nfs_context *nfs, const char *url, int dir, int incomplete)
254 {
255 struct nfs_url *urls;
256 char *strp, *flagsp, *strp2;
257
258 if (strncmp(url, "nfs://", 6)) {
259 rpc_set_error(nfs->rpc, "Invalid URL specified");
260 return NULL;
261 }
262
263 urls = malloc(sizeof(struct nfs_url));
264 if (urls == NULL) {
265 rpc_set_error(nfs->rpc, "Out of memory");
266 return NULL;
267 }
268
269 memset(urls, 0x00, sizeof(struct nfs_url));
270 urls->server = strdup(url + 6);
271 if (urls->server == NULL) {
272 nfs_destroy_url(urls);
273 rpc_set_error(nfs->rpc, "Out of memory");
274 return NULL;
275 }
276
277 if (urls->server[0] == '/' || urls->server[0] == '\0' ||
278 urls->server[0] == '?') {
279 if (incomplete) {
280 flagsp = strchr(urls->server, '?');
281 goto flags;
282 }
283 nfs_destroy_url(urls);
284 rpc_set_error(nfs->rpc, "Invalid server string");
285 return NULL;
286 }
287
288 strp = strchr(urls->server, '/');
289 if (strp == NULL) {
290 if (incomplete) {
291 flagsp = strchr(urls->server, '?');
292 goto flags;
293 }
294 nfs_destroy_url(urls);
295 rpc_set_error(nfs->rpc, "Incomplete or invalid URL specified.");
296 return NULL;
297 }
298
299 urls->path = strdup(strp);
300 if (urls->path == NULL) {
301 nfs_destroy_url(urls);
302 rpc_set_error(nfs->rpc, "Out of memory");
303 return NULL;
304 }
305 *strp = 0;
306
307 if (dir) {
308 flagsp = strchr(urls->path, '?');
309 goto flags;
310 }
311
312 strp = strrchr(urls->path, '/');
313 if (strp == NULL) {
314 if (incomplete) {
315 flagsp = strchr(urls->path, '?');
316 goto flags;
317 }
318 nfs_destroy_url(urls);
319 rpc_set_error(nfs->rpc, "Incomplete or invalid URL specified.");
320 return NULL;
321 }
322 urls->file = strdup(strp);
323 if (urls->path == NULL) {
324 nfs_destroy_url(urls);
325 rpc_set_error(nfs->rpc, "Out of memory");
326 return NULL;
327 }
328 *strp = 0;
329 flagsp = strchr(urls->file, '?');
330
331 flags:
332 if (flagsp) {
333 *flagsp = 0;
334 }
335
336 if (urls->file && !strlen(urls->file)) {
337 free(urls->file);
338 urls->file = NULL;
339 if (!incomplete) {
340 nfs_destroy_url(urls);
341 rpc_set_error(nfs->rpc, "Incomplete or invalid URL specified.");
342 return NULL;
343 }
344 }
345
346 while (flagsp != NULL && *(flagsp+1) != 0) {
347 strp = flagsp + 1;
348 flagsp = strchr(strp, '&');
349 if (flagsp) {
350 *flagsp = 0;
351 }
352 strp2 = strchr(strp, '=');
353 if (strp2) {
354 *strp2 = 0;
355 strp2++;
356 nfs_set_context_args(nfs, strp, strp2);
357 }
358 }
359
360 if (urls->server && strlen(urls->server) <= 1) {
361 free(urls->server);
362 urls->server = NULL;
363 }
364
365 return urls;
366 }
367
368 struct nfs_url *nfs_parse_url_full(struct nfs_context *nfs, const char *url)
369 {
370 return nfs_parse_url(nfs, url, 0, 0);
371 }
372
373 struct nfs_url *nfs_parse_url_dir(struct nfs_context *nfs, const char *url)
374 {
375 return nfs_parse_url(nfs, url, 1, 0);
376 }
377
378 struct nfs_url *nfs_parse_url_incomplete(struct nfs_context *nfs, const char *url)
379 {
380 return nfs_parse_url(nfs, url, 0, 1);
381 }
382
383
384 void nfs_destroy_url(struct nfs_url *url)
385 {
386 if (url) {
387 free(url->server);
388 free(url->path);
389 free(url->file);
390 }
391 free(url);
392 }
393
394 struct nfs_context *nfs_init_context(void)
395 {
396 struct nfs_context *nfs;
397
398 nfs = malloc(sizeof(struct nfs_context));
399 if (nfs == NULL) {
400 return NULL;
401 }
402 memset(nfs, 0, sizeof(struct nfs_context));
403
404 nfs->rpc = rpc_init_context();
405 if (nfs->rpc == NULL) {
406 free(nfs);
407 return NULL;
408 }
409
410 nfs->cwd = strdup("/");
411
412 return nfs;
413 }
414
415 void nfs_destroy_context(struct nfs_context *nfs)
416 {
417 rpc_destroy_context(nfs->rpc);
418 nfs->rpc = NULL;
419
420 if (nfs->server) {
421 free(nfs->server);
422 nfs->server = NULL;
423 }
424
425 if (nfs->export) {
426 free(nfs->export);
427 nfs->export = NULL;
428 }
429
430 if (nfs->cwd) {
431 free(nfs->cwd);
432 nfs->cwd = NULL;
433 }
434
435 if (nfs->rootfh.data.data_val != NULL) {
436 free(nfs->rootfh.data.data_val);
437 nfs->rootfh.data.data_val = NULL;
438 }
439
440 while (nfs->dircache) {
441 struct nfsdir *nfsdir = nfs->dircache;
442 LIBNFS_LIST_REMOVE(&nfs->dircache, nfsdir);
443 nfs_free_nfsdir(nfsdir);
444 }
445
446 free(nfs);
447 }
448
449 struct rpc_cb_data {
450 char *server;
451 uint32_t program;
452 uint32_t version;
453
454 rpc_cb cb;
455 void *private_data;
456 };
457
458 void free_rpc_cb_data(struct rpc_cb_data *data)
459 {
460 free(data->server);
461 data->server = NULL;
462 free(data);
463 }
464
465 static void rpc_connect_program_5_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
466 {
467 struct rpc_cb_data *data = private_data;
468
469 assert(rpc->magic == RPC_CONTEXT_MAGIC);
470
471 /* Dont want any more callbacks even if the socket is closed */
472 rpc->connect_cb = NULL;
473
474 if (status == RPC_STATUS_ERROR) {
475 data->cb(rpc, status, command_data, data->private_data);
476 free_rpc_cb_data(data);
477 return;
478 }
479 if (status == RPC_STATUS_CANCEL) {
480 data->cb(rpc, status, "Command was cancelled", data->private_data);
481 free_rpc_cb_data(data);
482 return;
483 }
484
485 data->cb(rpc, status, NULL, data->private_data);
486 free_rpc_cb_data(data);
487 }
488
489 static void rpc_connect_program_4_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
490 {
491 struct rpc_cb_data *data = private_data;
492
493 assert(rpc->magic == RPC_CONTEXT_MAGIC);
494
495 /* Dont want any more callbacks even if the socket is closed */
496 rpc->connect_cb = NULL;
497
498 if (status == RPC_STATUS_ERROR) {
499 data->cb(rpc, status, command_data, data->private_data);
500 free_rpc_cb_data(data);
501 return;
502 }
503 if (status == RPC_STATUS_CANCEL) {
504 data->cb(rpc, status, "Command was cancelled", data->private_data);
505 free_rpc_cb_data(data);
506 return;
507 }
508
509 switch (data->program) {
510 case MOUNT_PROGRAM:
511 if (rpc_mount3_null_async(rpc, rpc_connect_program_5_cb,
512 data) != 0) {
513 data->cb(rpc, status, command_data, data->private_data);
514 free_rpc_cb_data(data);
515 return;
516 }
517 return;
518 case NFS_PROGRAM:
519 if (rpc_nfs3_null_async(rpc, rpc_connect_program_5_cb,
520 data) != 0) {
521 data->cb(rpc, status, command_data, data->private_data);
522 free_rpc_cb_data(data);
523 return;
524 }
525 return;
526 }
527
528 data->cb(rpc, status, NULL, data->private_data);
529 free_rpc_cb_data(data);
530 }
531
532 static void rpc_connect_program_3_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
533 {
534 struct rpc_cb_data *data = private_data;
535 struct pmap3_string_result *gar;
536 uint32_t rpc_port = 0;
537 unsigned char *ptr;
538
539 assert(rpc->magic == RPC_CONTEXT_MAGIC);
540
541 if (status == RPC_STATUS_ERROR) {
542 data->cb(rpc, status, command_data, data->private_data);
543 free_rpc_cb_data(data);
544 return;
545 }
546 if (status == RPC_STATUS_CANCEL) {
547 data->cb(rpc, status, "Command was cancelled", data->private_data);
548 free_rpc_cb_data(data);
549 return;
550 }
551
552 switch (rpc->s.ss_family) {
553 case AF_INET:
554 rpc_port = *(uint32_t *)command_data;
555 break;
556 case AF_INET6:
557 /* ouch. portmapper and ipv6 are not great */
558 gar = command_data;
559 if (gar->addr == NULL) {
560 break;
561 }
562 ptr = strrchr(gar->addr, '.');
563 if (ptr == NULL) {
564 break;
565 }
566 rpc_port = atoi(ptr + 1);
567 *ptr = 0;
568 ptr = strrchr(gar->addr, '.');
569 if (ptr == NULL) {
570 break;
571 }
572 rpc_port += 256 * atoi(ptr + 1);
573 break;
574 }
575 if (rpc_port == 0) {
576 rpc_set_error(rpc, "RPC error. Program is not available on %s", data->server);
577 data->cb(rpc, RPC_STATUS_ERROR, rpc_get_error(rpc), data->private_data);
578 free_rpc_cb_data(data);
579 return;
580 }
581
582 rpc_disconnect(rpc, "normal disconnect");
583 if (rpc_connect_async(rpc, data->server, rpc_port, rpc_connect_program_4_cb, data) != 0) {
584 data->cb(rpc, status, command_data, data->private_data);
585 free_rpc_cb_data(data);
586 return;
587 }
588 }
589
590 static void rpc_connect_program_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
591 {
592 struct rpc_cb_data *data = private_data;
593 struct pmap3_mapping map;
594
595 assert(rpc->magic == RPC_CONTEXT_MAGIC);
596
597 if (status == RPC_STATUS_ERROR) {
598 data->cb(rpc, status, command_data, data->private_data);
599 free_rpc_cb_data(data);
600 return;
601 }
602 if (status == RPC_STATUS_CANCEL) {
603 data->cb(rpc, status, "Command was cancelled", data->private_data);
604 free_rpc_cb_data(data);
605 return;
606 }
607
608 switch (rpc->s.ss_family) {
609 case AF_INET:
610 if (rpc_pmap2_getport_async(rpc, data->program, data->version, IPPROTO_TCP, rpc_connect_program_3_cb, private_data) != 0) {
611 data->cb(rpc, status, command_data, data->private_data);
612 free_rpc_cb_data(data);
613 return;
614 }
615 break;
616 case AF_INET6:
617 map.prog=data->program;
618 map.vers=data->version;
619 map.netid="";
620 map.addr="";
621 map.owner="";
622 if (rpc_pmap3_getaddr_async(rpc, &map, rpc_connect_program_3_cb, private_data) != 0) {
623 data->cb(rpc, status, command_data, data->private_data);
624 free_rpc_cb_data(data);
625 return;
626 }
627 break;
628 }
629 }
630
631 static void rpc_connect_program_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
632 {
633 struct rpc_cb_data *data = private_data;
634
635 assert(rpc->magic == RPC_CONTEXT_MAGIC);
636
637 /* Dont want any more callbacks even if the socket is closed */
638 rpc->connect_cb = NULL;
639
640 if (status == RPC_STATUS_ERROR) {
641 data->cb(rpc, status, command_data, data->private_data);
642 free_rpc_cb_data(data);
643 return;
644 }
645 if (status == RPC_STATUS_CANCEL) {
646 data->cb(rpc, status, "Command was cancelled", data->private_data);
647 free_rpc_cb_data(data);
648 return;
649 }
650
651 switch (rpc->s.ss_family) {
652 case AF_INET:
653 if (rpc_pmap2_null_async(rpc, rpc_connect_program_2_cb, data) != 0) {
654 data->cb(rpc, status, command_data, data->private_data);
655 free_rpc_cb_data(data);
656 return;
657 }
658 break;
659 case AF_INET6:
660 if (rpc_pmap3_null_async(rpc, rpc_connect_program_2_cb, data) != 0) {
661 data->cb(rpc, status, command_data, data->private_data);
662 free_rpc_cb_data(data);
663 return;
664 }
665 break;
666 }
667 }
668
669 int rpc_connect_program_async(struct rpc_context *rpc, const char *server, int program, int version, rpc_cb cb, void *private_data)
670 {
671 struct rpc_cb_data *data;
672
673 data = malloc(sizeof(struct rpc_cb_data));
674 if (data == NULL) {
675 return -1;
676 }
677 memset(data, 0, sizeof(struct rpc_cb_data));
678 data->server = strdup(server);
679 data->program = program;
680 data->version = version;
681
682 data->cb = cb;
683 data->private_data = private_data;
684
685 if (rpc_connect_async(rpc, server, 111, rpc_connect_program_1_cb, data) != 0) {
686 rpc_set_error(rpc, "Failed to start connection");
687 free_rpc_cb_data(data);
688 return -1;
689 }
690 return 0;
691 }
692
693 static void free_nfs_cb_data(struct nfs_cb_data *data)
694 {
695 if (data->continue_data != NULL) {
696 assert(data->free_continue_data);
697 data->free_continue_data(data->continue_data);
698 }
699
700 free(data->saved_path);
701 free(data->fh.data.data_val);
702 free(data->buffer);
703
704 free(data);
705 }
706
707 static void free_nfsfh(struct nfsfh *nfsfh)
708 {
709 if (nfsfh->fh.data.data_val != NULL) {
710 free(nfsfh->fh.data.data_val);
711 nfsfh->fh.data.data_val = NULL;
712 }
713 free(nfsfh->ra.buf);
714 free(nfsfh);
715 }
716
717
718 static void nfs_mount_10_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
719 {
720 struct nfs_cb_data *data = private_data;
721 struct nfs_context *nfs = data->nfs;
722
723 assert(rpc->magic == RPC_CONTEXT_MAGIC);
724
725 if (status == RPC_STATUS_ERROR) {
726 data->cb(-EFAULT, nfs, command_data, data->private_data);
727 free_nfs_cb_data(data);
728 return;
729 }
730 if (status == RPC_STATUS_CANCEL) {
731 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
732 free_nfs_cb_data(data);
733 return;
734 }
735
736 data->cb(0, nfs, NULL, data->private_data);
737 free_nfs_cb_data(data);
738 }
739
740 static void nfs_mount_9_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
741 {
742 struct nfs_cb_data *data = private_data;
743 struct nfs_context *nfs = data->nfs;
744 FSINFO3res *res = command_data;
745 struct GETATTR3args args;
746
747 assert(rpc->magic == RPC_CONTEXT_MAGIC);
748
749 if (status == RPC_STATUS_ERROR) {
750 data->cb(-EFAULT, nfs, command_data, data->private_data);
751 free_nfs_cb_data(data);
752 return;
753 }
754 if (status == RPC_STATUS_CANCEL) {
755 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
756 free_nfs_cb_data(data);
757 return;
758 }
759
760 nfs->readmax = res->FSINFO3res_u.resok.rtmax;
761 nfs->writemax = res->FSINFO3res_u.resok.wtmax;
762
763 memset(&args, 0, sizeof(GETATTR3args));
764 args.object = nfs->rootfh;
765
766 if (rpc_nfs3_getattr_async(rpc, nfs_mount_10_cb, &args, data) != 0) {
767 data->cb(-ENOMEM, nfs, command_data, data->private_data);
768 free_nfs_cb_data(data);
769 return;
770 }
771 }
772
773 static void nfs_mount_8_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
774 {
775 struct nfs_cb_data *data = private_data;
776 struct nfs_context *nfs = data->nfs;
777 struct FSINFO3args args;
778
779 assert(rpc->magic == RPC_CONTEXT_MAGIC);
780
781 if (status == RPC_STATUS_ERROR) {
782 data->cb(-EFAULT, nfs, command_data, data->private_data);
783 free_nfs_cb_data(data);
784 return;
785 }
786 if (status == RPC_STATUS_CANCEL) {
787 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
788 free_nfs_cb_data(data);
789 return;
790 }
791
792 /* NFS TCP connections we want to autoreconnect after sessions are torn down (due to inactivity or error) */
793 rpc_set_autoreconnect(rpc);
794
795 args.fsroot = nfs->rootfh;
796 if (rpc_nfs3_fsinfo_async(rpc, nfs_mount_9_cb, &args, data) != 0) {
797 data->cb(-ENOMEM, nfs, command_data, data->private_data);
798 free_nfs_cb_data(data);
799 return;
800 }
801 }
802
803 static void nfs_mount_6_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
804 {
805 struct nfs_cb_data *data = private_data;
806 struct nfs_context *nfs = data->nfs;
807 mountres3 *res;
808
809 assert(rpc->magic == RPC_CONTEXT_MAGIC);
810
811 if (status == RPC_STATUS_ERROR) {
812 data->cb(-EFAULT, nfs, command_data, data->private_data);
813 free_nfs_cb_data(data);
814 return;
815 }
816 if (status == RPC_STATUS_CANCEL) {
817 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
818 free_nfs_cb_data(data);
819 return;
820 }
821
822 res = command_data;
823 if (res->fhs_status != MNT3_OK) {
824 rpc_set_error(rpc, "RPC error: Mount failed with error %s(%d) %s(%d)", mountstat3_to_str(res->fhs_status), res->fhs_status, strerror(-mountstat3_to_errno(res->fhs_status)), -mountstat3_to_errno(res->fhs_status));
825 data->cb(mountstat3_to_errno(res->fhs_status), nfs, rpc_get_error(rpc), data->private_data);
826 free_nfs_cb_data(data);
827 return;
828 }
829
830 nfs->rootfh.data.data_len = res->mountres3_u.mountinfo.fhandle.fhandle3_len;
831 nfs->rootfh.data.data_val = malloc(nfs->rootfh.data.data_len);
832 if (nfs->rootfh.data.data_val == NULL) {
833 rpc_set_error(rpc, "Out of memory. Could not allocate memory to store root filehandle");
834 data->cb(-ENOMEM, nfs, rpc_get_error(rpc), data->private_data);
835 free_nfs_cb_data(data);
836 return;
837 }
838 memcpy(nfs->rootfh.data.data_val, res->mountres3_u.mountinfo.fhandle.fhandle3_val, nfs->rootfh.data.data_len);
839
840 rpc_disconnect(rpc, "normal disconnect");
841
842 if (rpc_connect_program_async(nfs->rpc, nfs->server, NFS_PROGRAM, NFS_V3, nfs_mount_8_cb, data) != 0) {
843 data->cb(-ENOMEM, nfs, command_data, data->private_data);
844 free_nfs_cb_data(data);
845 return;
846 }
847 }
848
849
850 static void nfs_mount_5_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
851 {
852 struct nfs_cb_data *data = private_data;
853 struct nfs_context *nfs = data->nfs;
854
855 assert(rpc->magic == RPC_CONTEXT_MAGIC);
856
857 if (status == RPC_STATUS_ERROR) {
858 data->cb(-EFAULT, nfs, command_data, data->private_data);
859 free_nfs_cb_data(data);
860 return;
861 }
862 if (status == RPC_STATUS_CANCEL) {
863 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
864 free_nfs_cb_data(data);
865 return;
866 }
867
868 if (rpc_mount3_mnt_async(rpc, nfs_mount_6_cb, nfs->export, data) != 0) {
869 data->cb(-ENOMEM, nfs, command_data, data->private_data);
870 free_nfs_cb_data(data);
871 return;
872 }
873 }
874
875 /*
876 * Async call for mounting an nfs share and geting the root filehandle
877 */
878 int nfs_mount_async(struct nfs_context *nfs, const char *server, const char *export, nfs_cb cb, void *private_data)
879 {
880 struct nfs_cb_data *data;
881 char *new_server, *new_export;
882
883 data = malloc(sizeof(struct nfs_cb_data));
884 if (data == NULL) {
885 rpc_set_error(nfs->rpc, "out of memory. failed to allocate memory for nfs mount data");
886 return -1;
887 }
888 memset(data, 0, sizeof(struct nfs_cb_data));
889 new_server = strdup(server);
890 new_export = strdup(export);
891 if (nfs->server != NULL) {
892 free(nfs->server);
893 }
894 nfs->server = new_server;
895 if (nfs->export != NULL) {
896 free(nfs->export);
897 }
898 nfs->export = new_export;
899 data->nfs = nfs;
900 data->cb = cb;
901 data->private_data = private_data;
902
903 if (rpc_connect_program_async(nfs->rpc, server, MOUNT_PROGRAM, MOUNT_V3, nfs_mount_5_cb, data) != 0) {
904 rpc_set_error(nfs->rpc, "Failed to start connection");
905 free_nfs_cb_data(data);
906 return -1;
907 }
908
909 return 0;
910 }
911
912
913
914 /*
915 * Functions to first look up a path, component by component, and then finally call a specific function once
916 * the filehandle for the final component is found.
917 */
918 static void nfs_lookup_path_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
919 {
920 struct nfs_cb_data *data = private_data;
921 struct nfs_context *nfs = data->nfs;
922 LOOKUP3res *res;
923 fattr3 *attr;
924
925 assert(rpc->magic == RPC_CONTEXT_MAGIC);
926
927 if (status == RPC_STATUS_ERROR) {
928 data->cb(-EFAULT, nfs, command_data, data->private_data);
929 free_nfs_cb_data(data);
930 return;
931 }
932 if (status == RPC_STATUS_CANCEL) {
933 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
934 free_nfs_cb_data(data);
935 return;
936 }
937
938 res = command_data;
939 if (res->status != NFS3_OK) {
940 rpc_set_error(nfs->rpc, "NFS: Lookup of %s failed with %s(%d)", data->saved_path, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
941 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
942 free_nfs_cb_data(data);
943 return;
944 }
945
946 attr = res->LOOKUP3res_u.resok.obj_attributes.attributes_follow ?
947 &res->LOOKUP3res_u.resok.obj_attributes.post_op_attr_u.attributes :
948 NULL;
949
950 /* This function will always invoke the callback and cleanup
951 * for failures. So no need to check the return value.
952 */
953 nfs_lookup_path_async_internal(nfs, attr, data, &res->LOOKUP3res_u.resok.object);
954 }
955
956 static int nfs_lookup_path_async_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data, struct nfs_fh3 *fh)
957 {
958 char *path, *slash;
959 LOOKUP3args args;
960
961 while (*data->path == '/') {
962 data->path++;
963 }
964
965 path = data->path;
966 slash = strchr(path, '/');
967 if (slash != NULL) {
968 /* Clear slash so that path is a zero terminated string for
969 * the current path component. Set it back to '/' again later
970 * when we are finished referencing this component so that
971 * data->saved_path will still point to the full
972 * normalized path.
973 */
974 *slash = 0;
975 data->path = slash+1;
976 } else {
977 while (*data->path != 0) {
978 data->path++;
979 }
980 }
981
982 if (*path == 0) {
983 data->fh.data.data_len = fh->data.data_len;
984 data->fh.data.data_val = malloc(data->fh.data.data_len);
985 if (data->fh.data.data_val == NULL) {
986 rpc_set_error(nfs->rpc, "Out of memory: Failed to allocate fh for %s", data->path);
987 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
988 free_nfs_cb_data(data);
989 return -1;
990 }
991 memcpy(data->fh.data.data_val, fh->data.data_val, data->fh.data.data_len);
992 if (slash != NULL) {
993 *slash = '/';
994 }
995 data->continue_cb(nfs, attr, data);
996 return 0;
997 }
998
999 memset(&args, 0, sizeof(LOOKUP3args));
1000 args.what.dir = *fh;
1001 args.what.name = path;
1002
1003 if (rpc_nfs3_lookup_async(nfs->rpc, nfs_lookup_path_1_cb, &args, data) != 0) {
1004 rpc_set_error(nfs->rpc, "RPC error: Failed to send lookup call for %s", data->path);
1005 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1006 free_nfs_cb_data(data);
1007 return -1;
1008 }
1009 if (slash != NULL) {
1010 *slash = '/';
1011 }
1012 return 0;
1013 }
1014
1015 static int nfs_normalize_path(struct nfs_context *nfs, char *path)
1016 {
1017 char *str;
1018 int len;
1019
1020 /* // -> / */
1021 while ((str = strstr(path, "//"))) {
1022 while(*str) {
1023 *str = *(str + 1);
1024 str++;
1025 }
1026 }
1027
1028 /* /./ -> / */
1029 while ((str = strstr(path, "/./"))) {
1030 while(*(str + 1)) {
1031 *str = *(str + 2);
1032 str++;
1033 }
1034 }
1035
1036 /* ^/../ -> error */
1037 if (!strncmp(path, "/../", 4)) {
1038 rpc_set_error(nfs->rpc,
1039 "Absolute path starts with '/../' "
1040 "during normalization");
1041 return -1;
1042 }
1043
1044 /* ^[^/] -> error */
1045 if (path[0] != '/') {
1046 rpc_set_error(nfs->rpc,
1047 "Absolute path does not start with '/'");
1048 return -1;
1049 }
1050
1051 /* /string/../ -> / */
1052 while ((str = strstr(path, "/../"))) {
1053 char *tmp;
1054
1055 if (!strncmp(path, "/../", 4)) {
1056 rpc_set_error(nfs->rpc,
1057 "Absolute path starts with '/../' "
1058 "during normalization");
1059 return -1;
1060 }
1061
1062 tmp = str - 1;
1063 while (*tmp != '/') {
1064 tmp--;
1065 }
1066 str += 3;
1067 while((*(tmp++) = *(str++)) != '\0')
1068 ;
1069 }
1070
1071 /* /$ -> \0 */
1072 len = strlen(path);
1073 if (len > 1) {
1074 if (path[len - 1] == '/') {
1075 path[len - 1] = '\0';
1076 len--;
1077 }
1078 }
1079 if (path[0] == '\0') {
1080 rpc_set_error(nfs->rpc,
1081 "Absolute path became '' "
1082 "during normalization");
1083 return -1;
1084 }
1085
1086 /* /.$ -> \0 */
1087 if (len >= 2) {
1088 if (!strcmp(&path[len - 2], "/.")) {
1089 path[len - 2] = '\0';
1090 len -= 2;
1091 }
1092 }
1093
1094 /* ^/..$ -> error */
1095 if (!strcmp(path, "/..")) {
1096 rpc_set_error(nfs->rpc,
1097 "Absolute path is '/..' "
1098 "during normalization");
1099 return -1;
1100 }
1101
1102 /* /string/..$ -> / */
1103 if (len >= 3) {
1104 if (!strcmp(&path[len - 3], "/..")) {
1105 char *tmp = &path[len - 3];
1106 while (*--tmp != '/')
1107 ;
1108 *tmp = '\0';
1109 }
1110 }
1111
1112 return 0;
1113 }
1114
1115 static void nfs_lookup_path_getattr_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
1116 {
1117 struct nfs_cb_data *data = private_data;
1118 struct nfs_context *nfs = data->nfs;
1119 GETATTR3res *res;
1120 fattr3 *attr;
1121
1122 assert(rpc->magic == RPC_CONTEXT_MAGIC);
1123
1124 if (status == RPC_STATUS_ERROR) {
1125 data->cb(-EFAULT, nfs, command_data, data->private_data);
1126 free_nfs_cb_data(data);
1127 return;
1128 }
1129 if (status == RPC_STATUS_CANCEL) {
1130 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1131 free_nfs_cb_data(data);
1132 return;
1133 }
1134
1135 res = command_data;
1136 if (res->status != NFS3_OK) {
1137 rpc_set_error(nfs->rpc, "NFS: GETATTR of %s failed with %s(%d)", data->saved_path, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
1138 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
1139 free_nfs_cb_data(data);
1140 return;
1141 }
1142
1143 attr = &res->GETATTR3res_u.resok.obj_attributes;
1144 /* This function will always invoke the callback and cleanup
1145 * for failures. So no need to check the return value.
1146 */
1147 nfs_lookup_path_async_internal(nfs, attr, data, &nfs->rootfh);
1148 }
1149
1150 static int nfs_lookuppath_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data, continue_func continue_cb, void *continue_data, void (*free_continue_data)(void *), int continue_int)
1151 {
1152 struct nfs_cb_data *data;
1153 struct GETATTR3args args;
1154
1155 if (path[0] == '\0') {
1156 path = ".";
1157 }
1158
1159 data = malloc(sizeof(struct nfs_cb_data));
1160 if (data == NULL) {
1161 rpc_set_error(nfs->rpc, "out of memory: failed to allocate "
1162 "nfs_cb_data structure");
1163 if (free_continue_data)
1164 free_continue_data(continue_data);
1165 return -1;
1166 }
1167 memset(data, 0, sizeof(struct nfs_cb_data));
1168 data->nfs = nfs;
1169 data->cb = cb;
1170 data->continue_cb = continue_cb;
1171 data->continue_data = continue_data;
1172 data->free_continue_data = free_continue_data;
1173 data->continue_int = continue_int;
1174 data->private_data = private_data;
1175 if (path[0] == '/') {
1176 data->saved_path = strdup(path);
1177 } else {
1178 data->saved_path = malloc(strlen(path) + strlen(nfs->cwd) + 2);
1179 if (data->saved_path == NULL) {
1180 rpc_set_error(nfs->rpc, "out of memory: failed to "
1181 "malloc path string");
1182 free_nfs_cb_data(data);
1183 return -1;
1184 }
1185 sprintf(data->saved_path, "%s/%s", nfs->cwd, path);
1186 }
1187
1188 if (data->saved_path == NULL) {
1189 rpc_set_error(nfs->rpc, "out of memory: failed to copy path string");
1190 free_nfs_cb_data(data);
1191 return -1;
1192 }
1193 if (nfs_normalize_path(nfs, data->saved_path) != 0) {
1194 free_nfs_cb_data(data);
1195 return -1;
1196 }
1197
1198 data->path = data->saved_path;
1199 if (data->path[0]) {
1200 /* This function will always invoke the callback and cleanup
1201 * for failures. So no need to check the return value.
1202 */
1203 nfs_lookup_path_async_internal(nfs, NULL, data, &nfs->rootfh);
1204 return 0;
1205 }
1206
1207 /* We have a request for "", so just perform a GETATTR3 so we can
1208 * return the attributes to the caller.
1209 */
1210 memset(&args, 0, sizeof(GETATTR3args));
1211 args.object = nfs->rootfh;
1212 if (rpc_nfs3_getattr_async(nfs->rpc, nfs_lookup_path_getattr_cb, &args, data) != 0) {
1213 free_nfs_cb_data(data);
1214 return -1;
1215 }
1216 return 0;
1217 }
1218
1219
1220 /*
1221 * Async stat()
1222 */
1223 static dev_t specdata3_to_rdev(struct specdata3 *rdev)
1224 {
1225 #ifdef makedev
1226 return makedev(rdev->specdata1, rdev->specdata2);
1227 #else
1228 return 0;
1229 #endif
1230 }
1231
1232 static void nfs_stat_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
1233 {
1234 GETATTR3res *res;
1235 struct nfs_cb_data *data = private_data;
1236 struct nfs_context *nfs = data->nfs;
1237 #ifdef WIN32
1238 struct __stat64 st;
1239 #else
1240 struct stat st;
1241 #endif
1242
1243 assert(rpc->magic == RPC_CONTEXT_MAGIC);
1244
1245 if (status == RPC_STATUS_ERROR) {
1246 data->cb(-EFAULT, nfs, command_data, data->private_data);
1247 free_nfs_cb_data(data);
1248 return;
1249 }
1250 if (status == RPC_STATUS_CANCEL) {
1251 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1252 free_nfs_cb_data(data);
1253 return;
1254 }
1255
1256 res = command_data;
1257 if (res->status != NFS3_OK) {
1258 rpc_set_error(nfs->rpc, "NFS: GETATTR of %s failed with %s(%d)", data->saved_path, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
1259 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
1260 free_nfs_cb_data(data);
1261 return;
1262 }
1263
1264 st.st_dev = res->GETATTR3res_u.resok.obj_attributes.fsid;
1265 st.st_ino = res->GETATTR3res_u.resok.obj_attributes.fileid;
1266 st.st_mode = res->GETATTR3res_u.resok.obj_attributes.mode;
1267 switch (res->GETATTR3res_u.resok.obj_attributes.type) {
1268 case NF3REG:
1269 st.st_mode |= S_IFREG;
1270 break;
1271 case NF3DIR:
1272 st.st_mode |= S_IFDIR;
1273 break;
1274 case NF3BLK:
1275 st.st_mode |= S_IFBLK;
1276 break;
1277 case NF3CHR:
1278 st.st_mode |= S_IFCHR;
1279 break;
1280 case NF3LNK:
1281 st.st_mode |= S_IFLNK;
1282 break;
1283 case NF3SOCK:
1284 st.st_mode |= S_IFSOCK;
1285 break;
1286 case NF3FIFO:
1287 st.st_mode |= S_IFIFO;
1288 break;
1289 }
1290 st.st_nlink = res->GETATTR3res_u.resok.obj_attributes.nlink;
1291 st.st_uid = res->GETATTR3res_u.resok.obj_attributes.uid;
1292 st.st_gid = res->GETATTR3res_u.resok.obj_attributes.gid;
1293 st.st_rdev = specdata3_to_rdev(&res->GETATTR3res_u.resok.obj_attributes.rdev);
1294 st.st_size = res->GETATTR3res_u.resok.obj_attributes.size;
1295 #ifndef WIN32
1296 st.st_blksize = NFS_BLKSIZE;
1297 st.st_blocks = (res->GETATTR3res_u.resok.obj_attributes.used + 512 - 1) / 512;
1298 #endif//WIN32
1299 st.st_atime = res->GETATTR3res_u.resok.obj_attributes.atime.seconds;
1300 st.st_mtime = res->GETATTR3res_u.resok.obj_attributes.mtime.seconds;
1301 st.st_ctime = res->GETATTR3res_u.resok.obj_attributes.ctime.seconds;
1302 #ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
1303 st.st_atim.tv_nsec = res->GETATTR3res_u.resok.obj_attributes.atime.nseconds;
1304 st.st_mtim.tv_nsec = res->GETATTR3res_u.resok.obj_attributes.mtime.nseconds;
1305 st.st_ctim.tv_nsec = res->GETATTR3res_u.resok.obj_attributes.ctime.nseconds;
1306 #endif
1307
1308 data->cb(0, nfs, &st, data->private_data);
1309 free_nfs_cb_data(data);
1310 }
1311
1312 static int nfs_stat_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
1313 {
1314 struct GETATTR3args args;
1315
1316 memset(&args, 0, sizeof(GETATTR3args));
1317 args.object = data->fh;
1318
1319 if (rpc_nfs3_getattr_async(nfs->rpc, nfs_stat_1_cb, &args, data) != 0) {
1320 rpc_set_error(nfs->rpc, "RPC error: Failed to send STAT GETATTR call for %s", data->path);
1321 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1322 free_nfs_cb_data(data);
1323 return -1;
1324 }
1325 return 0;
1326 }
1327
1328 int nfs_stat_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
1329 {
1330 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_stat_continue_internal, NULL, NULL, 0) != 0) {
1331 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
1332 return -1;
1333 }
1334
1335 return 0;
1336 }
1337
1338
1339 /*
1340 * Async nfs_stat64()
1341 */
1342 static void nfs_stat64_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
1343 {
1344 GETATTR3res *res;
1345 struct nfs_cb_data *data = private_data;
1346 struct nfs_context *nfs = data->nfs;
1347 struct nfs_stat_64 st;
1348
1349 assert(rpc->magic == RPC_CONTEXT_MAGIC);
1350
1351 if (status == RPC_STATUS_ERROR) {
1352 data->cb(-EFAULT, nfs, command_data, data->private_data);
1353 free_nfs_cb_data(data);
1354 return;
1355 }
1356 if (status == RPC_STATUS_CANCEL) {
1357 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1358 free_nfs_cb_data(data);
1359 return;
1360 }
1361
1362 res = command_data;
1363 if (res->status != NFS3_OK) {
1364 rpc_set_error(nfs->rpc, "NFS: GETATTR of %s failed with %s(%d)", data->saved_path, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
1365 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
1366 free_nfs_cb_data(data);
1367 return;
1368 }
1369
1370 st.nfs_dev = res->GETATTR3res_u.resok.obj_attributes.fsid;
1371 st.nfs_ino = res->GETATTR3res_u.resok.obj_attributes.fileid;
1372 st.nfs_mode = res->GETATTR3res_u.resok.obj_attributes.mode;
1373 switch (res->GETATTR3res_u.resok.obj_attributes.type) {
1374 case NF3REG:
1375 st.nfs_mode |= S_IFREG;
1376 break;
1377 case NF3DIR:
1378 st.nfs_mode |= S_IFDIR;
1379 break;
1380 case NF3BLK:
1381 st.nfs_mode |= S_IFBLK;
1382 break;
1383 case NF3CHR:
1384 st.nfs_mode |= S_IFCHR;
1385 break;
1386 case NF3LNK:
1387 st.nfs_mode |= S_IFLNK;
1388 break;
1389 case NF3SOCK:
1390 st.nfs_mode |= S_IFSOCK;
1391 break;
1392 case NF3FIFO:
1393 st.nfs_mode |= S_IFIFO;
1394 break;
1395 }
1396 st.nfs_nlink = res->GETATTR3res_u.resok.obj_attributes.nlink;
1397 st.nfs_uid = res->GETATTR3res_u.resok.obj_attributes.uid;
1398 st.nfs_gid = res->GETATTR3res_u.resok.obj_attributes.gid;
1399 st.nfs_rdev = specdata3_to_rdev(&res->GETATTR3res_u.resok.obj_attributes.rdev);
1400 st.nfs_size = res->GETATTR3res_u.resok.obj_attributes.size;
1401 st.nfs_blksize = NFS_BLKSIZE;
1402 st.nfs_blocks = (res->GETATTR3res_u.resok.obj_attributes.used + 512 - 1) / 512;
1403 st.nfs_atime = res->GETATTR3res_u.resok.obj_attributes.atime.seconds;
1404 st.nfs_mtime = res->GETATTR3res_u.resok.obj_attributes.mtime.seconds;
1405 st.nfs_ctime = res->GETATTR3res_u.resok.obj_attributes.ctime.seconds;
1406 st.nfs_atime_nsec = res->GETATTR3res_u.resok.obj_attributes.atime.nseconds;
1407 st.nfs_mtime_nsec = res->GETATTR3res_u.resok.obj_attributes.mtime.nseconds;
1408 st.nfs_ctime_nsec = res->GETATTR3res_u.resok.obj_attributes.ctime.nseconds;
1409 st.nfs_used = res->GETATTR3res_u.resok.obj_attributes.used;
1410
1411 data->cb(0, nfs, &st, data->private_data);
1412 free_nfs_cb_data(data);
1413 }
1414
1415 static int nfs_stat64_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
1416 {
1417 struct GETATTR3args args;
1418
1419 memset(&args, 0, sizeof(GETATTR3args));
1420 args.object = data->fh;
1421
1422 if (rpc_nfs3_getattr_async(nfs->rpc, nfs_stat64_1_cb, &args, data) != 0) {
1423 rpc_set_error(nfs->rpc, "RPC error: Failed to send STAT GETATTR call for %s", data->path);
1424 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1425 free_nfs_cb_data(data);
1426 return -1;
1427 }
1428 return 0;
1429 }
1430
1431 int nfs_stat64_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
1432 {
1433 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_stat64_continue_internal, NULL, NULL, 0) != 0) {
1434 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
1435 return -1;
1436 }
1437
1438 return 0;
1439 }
1440
1441 /*
1442 * Async open()
1443 */
1444 static void nfs_open_trunc_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
1445 {
1446 struct nfs_cb_data *data = private_data;
1447 struct nfs_context *nfs = data->nfs;
1448 struct nfsfh *nfsfh;
1449 SETATTR3res *res;
1450
1451 assert(rpc->magic == RPC_CONTEXT_MAGIC);
1452
1453 if (status == RPC_STATUS_ERROR) {
1454 data->cb(-EFAULT, nfs, command_data, data->private_data);
1455 free_nfs_cb_data(data);
1456 return;
1457 }
1458 if (status == RPC_STATUS_CANCEL) {
1459 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1460 free_nfs_cb_data(data);
1461 return;
1462 }
1463
1464 res = command_data;
1465 if (res->status != NFS3_OK) {
1466 rpc_set_error(nfs->rpc, "NFS: Setattr failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
1467 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
1468 free_nfs_cb_data(data);
1469 return;
1470 }
1471
1472 nfsfh = malloc(sizeof(struct nfsfh));
1473 if (nfsfh == NULL) {
1474 rpc_set_error(nfs->rpc, "NFS: Failed to allocate nfsfh structure");
1475 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1476 free_nfs_cb_data(data);
1477 return;
1478 }
1479 memset(nfsfh, 0, sizeof(struct nfsfh));
1480
1481 if (data->continue_int & O_SYNC) {
1482 nfsfh->is_sync = 1;
1483 }
1484 if (data->continue_int & O_APPEND) {
1485 nfsfh->is_append = 1;
1486 }
1487
1488 /* steal the filehandle */
1489 nfsfh->fh = data->fh;
1490 data->fh.data.data_val = NULL;
1491
1492 data->cb(0, nfs, nfsfh, data->private_data);
1493 free_nfs_cb_data(data);
1494 }
1495
1496 static void nfs_open_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
1497 {
1498 ACCESS3res *res;
1499 struct nfs_cb_data *data = private_data;
1500 struct nfs_context *nfs = data->nfs;
1501 struct nfsfh *nfsfh;
1502 unsigned int nfsmode = 0;
1503
1504 assert(rpc->magic == RPC_CONTEXT_MAGIC);
1505
1506 if (status == RPC_STATUS_ERROR) {
1507 data->cb(-EFAULT, nfs, command_data, data->private_data);
1508 free_nfs_cb_data(data);
1509 return;
1510 }
1511 if (status == RPC_STATUS_CANCEL) {
1512 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1513 free_nfs_cb_data(data);
1514 return;
1515 }
1516
1517 res = command_data;
1518 if (res->status != NFS3_OK) {
1519 rpc_set_error(nfs->rpc, "NFS: ACCESS of %s failed with %s(%d)", data->saved_path, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
1520 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
1521 free_nfs_cb_data(data);
1522 return;
1523 }
1524
1525 if (data->continue_int & O_WRONLY) {
1526 nfsmode |= ACCESS3_MODIFY;
1527 }
1528 if (data->continue_int & O_RDWR) {
1529 nfsmode |= ACCESS3_READ|ACCESS3_MODIFY;
1530 }
1531 if (!(data->continue_int & (O_WRONLY|O_RDWR))) {
1532 nfsmode |= ACCESS3_READ;
1533 }
1534
1535
1536 if (res->ACCESS3res_u.resok.access != nfsmode) {
1537 rpc_set_error(nfs->rpc, "NFS: ACCESS denied. Required access %c%c%c. Allowed access %c%c%c",
1538 nfsmode&ACCESS3_READ?'r':'-',
1539 nfsmode&ACCESS3_MODIFY?'w':'-',
1540 nfsmode&ACCESS3_EXECUTE?'x':'-',
1541 res->ACCESS3res_u.resok.access&ACCESS3_READ?'r':'-',
1542 res->ACCESS3res_u.resok.access&ACCESS3_MODIFY?'w':'-',
1543 res->ACCESS3res_u.resok.access&ACCESS3_EXECUTE?'x':'-');
1544 data->cb(-EACCES, nfs, rpc_get_error(nfs->rpc), data->private_data);
1545 free_nfs_cb_data(data);
1546 return;
1547 }
1548
1549 /* Try to truncate it if we were requested to */
1550 if ((data->continue_int & O_TRUNC) &&
1551 (data->continue_int & (O_RDWR|O_WRONLY))) {
1552 SETATTR3args args;
1553
1554 memset(&args, 0, sizeof(SETATTR3args));
1555 args.object = data->fh;
1556 args.new_attributes.size.set_it = 1;
1557 args.new_attributes.size.set_size3_u.size = 0;
1558
1559 if (rpc_nfs3_setattr_async(nfs->rpc, nfs_open_trunc_cb, &args,
1560 data) != 0) {
1561 rpc_set_error(nfs->rpc, "RPC error: Failed to send "
1562 "SETATTR call for %s", data->path);
1563 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc),
1564 data->private_data);
1565 free_nfs_cb_data(data);
1566 return;
1567 }
1568 return;
1569 }
1570
1571 nfsfh = malloc(sizeof(struct nfsfh));
1572 if (nfsfh == NULL) {
1573 rpc_set_error(nfs->rpc, "NFS: Failed to allocate nfsfh structure");
1574 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1575 free_nfs_cb_data(data);
1576 return;
1577 }
1578 memset(nfsfh, 0, sizeof(struct nfsfh));
1579
1580 if (data->continue_int & O_SYNC) {
1581 nfsfh->is_sync = 1;
1582 }
1583 if (data->continue_int & O_APPEND) {
1584 nfsfh->is_append = 1;
1585 }
1586
1587 /* steal the filehandle */
1588 nfsfh->fh = data->fh;
1589 data->fh.data.data_val = NULL;
1590
1591 data->cb(0, nfs, nfsfh, data->private_data);
1592 free_nfs_cb_data(data);
1593 }
1594
1595 static int nfs_open_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
1596 {
1597 int nfsmode = 0;
1598 ACCESS3args args;
1599
1600 if (data->continue_int & O_WRONLY) {
1601 nfsmode |= ACCESS3_MODIFY;
1602 }
1603 if (data->continue_int & O_RDWR) {
1604 nfsmode |= ACCESS3_READ|ACCESS3_MODIFY;
1605 }
1606 if (!(data->continue_int & (O_WRONLY|O_RDWR))) {
1607 nfsmode |= ACCESS3_READ;
1608 }
1609
1610 memset(&args, 0, sizeof(ACCESS3args));
1611 args.object = data->fh;
1612 args.access = nfsmode;
1613
1614 if (rpc_nfs3_access_async(nfs->rpc, nfs_open_cb, &args, data) != 0) {
1615 rpc_set_error(nfs->rpc, "RPC error: Failed to send OPEN ACCESS "
1616 "call for %s", data->path);
1617 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc),
1618 data->private_data);
1619 free_nfs_cb_data(data);
1620 return -1;
1621 }
1622 return 0;
1623 }
1624
1625 int nfs_open_async(struct nfs_context *nfs, const char *path, int flags, nfs_cb cb, void *private_data)
1626 {
1627 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_open_continue_internal, NULL, NULL, flags) != 0) {
1628 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
1629 return -1;
1630 }
1631
1632 return 0;
1633 }
1634
1635
1636 /*
1637 * Async chdir()
1638 */
1639 static int nfs_chdir_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
1640 {
1641 /* steal saved_path */
1642 free(nfs->cwd);
1643 nfs->cwd = data->saved_path;
1644 data->saved_path = NULL;
1645
1646 data->cb(0, nfs, NULL, data->private_data);
1647 free_nfs_cb_data(data);
1648
1649 return 0;
1650 }
1651
1652 int nfs_chdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
1653 {
1654 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_chdir_continue_internal, NULL, NULL, 0) != 0) {
1655 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
1656 return -1;
1657 }
1658
1659 return 0;
1660 }
1661
1662
1663 /*
1664 * Async pread()
1665 */
1666 static void nfs_fill_READ3args(READ3args *args, struct nfsfh *fh, uint64_t offset, uint64_t count)
1667 {
1668 memset(args, 0, sizeof(READ3args));
1669 args->file = fh->fh;
1670 args->offset = offset;
1671 args->count = count;
1672 }
1673
1674 static void nfs_pread_mcb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
1675 {
1676 struct nfs_mcb_data *mdata = private_data;
1677 struct nfs_cb_data *data = mdata->data;
1678 struct nfs_context *nfs = data->nfs;
1679 READ3res *res;
1680
1681 assert(rpc->magic == RPC_CONTEXT_MAGIC);
1682
1683 data->num_calls--;
1684
1685 if (status == RPC_STATUS_ERROR) {
1686 /* flag the failure but do not invoke callback until we have received all responses */
1687 data->error = 1;
1688 }
1689 if (status == RPC_STATUS_CANCEL) {
1690 /* flag the cancellation but do not invoke callback until we have received all responses */
1691 data->cancel = 1;
1692 }
1693
1694 if (status == RPC_STATUS_SUCCESS) {
1695 res = command_data;
1696 if (res->status != NFS3_OK) {
1697 rpc_set_error(nfs->rpc, "NFS: Read failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
1698 data->error = 1;
1699 } else {
1700 uint64_t count = res->READ3res_u.resok.count;
1701
1702 if (mdata->update_pos)
1703 data->nfsfh->offset += count;
1704
1705 /* if we have more than one call or we have received a short read we need a reassembly buffer */
1706 if (data->num_calls || (count < mdata->count && !res->READ3res_u.resok.eof)) {
1707 if (data->buffer == NULL) {
1708 data->buffer = malloc(data->count);
1709 if (data->buffer == NULL) {
1710 rpc_set_error(nfs->rpc, "Out-Of-Memory: Failed to allocate reassembly buffer for %d bytes", (int)data->count);
1711 data->oom = 1;
1712 }
1713 }
1714 }
1715 if (count > 0) {
1716 if (count <= mdata->count) {
1717 /* copy data into reassembly buffer if we have one */
1718 if (data->buffer != NULL) {
1719 memcpy(&data->buffer[mdata->offset - data->offset], res->READ3res_u.resok.data.data_val, count);
1720 }
1721 if (data->max_offset < mdata->offset + count) {
1722 data->max_offset = mdata->offset + count;
1723 }
1724 } else {
1725 rpc_set_error(nfs->rpc, "NFS: Read overflow. Server has sent more data than requested!");
1726 data->error = 1;
1727 }
1728 }
1729 /* check if we have received a short read */
1730 if (count < mdata->count && !res->READ3res_u.resok.eof) {
1731 if (count == 0) {
1732 rpc_set_error(nfs->rpc, "NFS: Read failed. No bytes read and not at EOF!");
1733 data->error = 1;
1734 } else {
1735 /* reissue reminder of this read request */
1736 READ3args args;
1737 mdata->offset += count;
1738 mdata->count -= count;
1739 nfs_fill_READ3args(&args, data->nfsfh, mdata->offset, mdata->count);
1740 if (rpc_nfs3_read_async(nfs->rpc, nfs_pread_mcb, &args, mdata) == 0) {
1741 data->num_calls++;
1742 return;
1743 } else {
1744 rpc_set_error(nfs->rpc, "RPC error: Failed to send READ call for %s", data->path);
1745 data->oom = 1;
1746 }
1747 }
1748 }
1749 }
1750 }
1751
1752 free(mdata);
1753
1754 if (data->num_calls > 0) {
1755 /* still waiting for more replies */
1756 return;
1757 }
1758 if (data->oom != 0) {
1759 data->cb(-ENOMEM, nfs, command_data, data->private_data);
1760 free_nfs_cb_data(data);
1761 return;
1762 }
1763 if (data->error != 0) {
1764 data->cb(-EFAULT, nfs, command_data, data->private_data);
1765 free_nfs_cb_data(data);
1766 return;
1767 }
1768 if (data->cancel != 0) {
1769 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1770 free_nfs_cb_data(data);
1771 return;
1772 }
1773
1774 if (data->buffer) {
1775 if (data->max_offset > data->org_offset + data->org_count) {
1776 data->max_offset = data->org_offset + data->org_count;
1777 }
1778 data->cb(data->max_offset - data->org_offset, nfs, data->buffer + (data->org_offset - data->offset), data->private_data);
1779 } else {
1780 data->cb(res->READ3res_u.resok.count, nfs, res->READ3res_u.resok.data.data_val, data->private_data);
1781 }
1782
1783 data->nfsfh->ra.fh_offset = data->max_offset;
1784 if (data->nfsfh->ra.cur_ra) {
1785 free(data->nfsfh->ra.buf);
1786 data->nfsfh->ra.buf = data->buffer;
1787 data->nfsfh->ra.buf_offset = data->offset;
1788 data->nfsfh->ra.buf_count = data->count;
1789 data->nfsfh->ra.buf_ts = time(NULL);
1790 data->buffer = NULL;
1791 }
1792 free_nfs_cb_data(data);
1793 }
1794
1795 static void nfs_ra_invalidate(struct nfsfh *nfsfh) {
1796 free(nfsfh->ra.buf);
1797 nfsfh->ra.buf = NULL;
1798 nfsfh->ra.buf_offset = 0;
1799 nfsfh->ra.buf_count = 0;
1800 nfsfh->ra.buf_ts = time(NULL);
1801 nfsfh->ra.cur_ra = NFS_BLKSIZE;
1802 }
1803
1804 static int nfs_pread_async_internal(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, nfs_cb cb, void *private_data, int update_pos)
1805 {
1806 struct nfs_cb_data *data;
1807
1808 data = malloc(sizeof(struct nfs_cb_data));
1809 if (data == NULL) {
1810 rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
1811 return -1;
1812 }
1813 memset(data, 0, sizeof(struct nfs_cb_data));
1814 data->nfs = nfs;
1815 data->cb = cb;
1816 data->private_data = private_data;
1817 data->nfsfh = nfsfh;
1818 data->org_offset = offset;
1819 data->org_count = count;
1820
1821 assert(data->num_calls == 0);
1822
1823 if (nfs->rpc->readahead && time(NULL) - nfsfh->ra.buf_ts > NFS_RA_TIMEOUT) {
1824 /* readahead cache timeout */
1825 nfs_ra_invalidate(nfsfh);
1826 }
1827
1828 if (nfs->rpc->readahead) {
1829 if (offset >= nfsfh->ra.last_offset &&
1830 offset - NFS_BLKSIZE <= nfsfh->ra.fh_offset + nfsfh->ra.cur_ra) {
1831 if (nfs->rpc->readahead > nfsfh->ra.cur_ra) {
1832 nfsfh->ra.cur_ra <<= 1;
1833 }
1834 } else {
1835 nfsfh->ra.cur_ra = NFS_BLKSIZE;
1836 }
1837
1838 nfsfh->ra.last_offset = offset;
1839
1840 if (nfsfh->ra.buf_offset <= offset &&
1841 nfsfh->ra.buf_offset + nfsfh->ra.buf_count >= offset + count) {
1842 /* serve request completely from cache */
1843 data->buffer = malloc(count);
1844 if (data->buffer == NULL) {
1845 free_nfs_cb_data(data);
1846 return -ENOMEM;
1847 }
1848 memcpy(data->buffer, nfsfh->ra.buf + (offset - nfsfh->ra.buf_offset), count);
1849 data->cb(count, nfs, data->buffer, data->private_data);
1850 nfsfh->ra.fh_offset = offset + count;
1851 free_nfs_cb_data(data);
1852 return 0;
1853 }
1854
1855 /* align start offset to blocksize */
1856 count += offset & (NFS_BLKSIZE - 1);
1857 offset &= ~(NFS_BLKSIZE - 1);
1858
1859 /* align end offset to blocksize and add readahead */
1860 count += nfsfh->ra.cur_ra - 1;
1861 count &= ~(NFS_BLKSIZE - 1);
1862
1863 data->buffer = malloc(count);
1864 if (data->buffer == NULL) {
1865 free_nfs_cb_data(data);
1866 return -ENOMEM;
1867 }
1868 data->offset = offset;
1869 data->count = count;
1870
1871 if (nfsfh->ra.buf_count && nfsfh->ra.buf_offset <= offset &&
1872 nfsfh->ra.buf_offset + nfsfh->ra.buf_count >= offset) {
1873 /* serve request partially from cache */
1874 size_t overlap = (nfsfh->ra.buf_offset + nfsfh->ra.buf_count) - offset;
1875 if (overlap > count) count = overlap;
1876 memcpy(data->buffer, nfsfh->ra.buf + (offset - nfsfh->ra.buf_offset), overlap);
1877 offset += overlap;
1878 count -= overlap;
1879 }
1880 } else {
1881 data->offset = offset;
1882 data->count = count;
1883 }
1884
1885 data->max_offset = offset;
1886
1887 /* chop requests into chunks of at most READMAX bytes if necessary.
1888 * we send all reads in parallel so that performance is still good.
1889 */
1890 do {
1891 uint64_t readcount = count;
1892 struct nfs_mcb_data *mdata;
1893 READ3args args;
1894
1895 if (readcount > nfs_get_readmax(nfs)) {
1896 readcount = nfs_get_readmax(nfs);
1897 }
1898
1899 mdata = malloc(sizeof(struct nfs_mcb_data));
1900 if (mdata == NULL) {
1901 rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_mcb_data structure");
1902 if (data->num_calls == 0) {
1903 free_nfs_cb_data(data);
1904 return -1;
1905 }
1906 data->oom = 1;
1907 break;
1908 }
1909 memset(mdata, 0, sizeof(struct nfs_mcb_data));
1910 mdata->data = data;
1911 mdata->offset = offset;
1912 mdata->count = readcount;
1913 mdata->update_pos = update_pos;
1914
1915 nfs_fill_READ3args(&args, nfsfh, offset, readcount);
1916
1917 if (rpc_nfs3_read_async(nfs->rpc, nfs_pread_mcb, &args, mdata) != 0) {
1918 rpc_set_error(nfs->rpc, "RPC error: Failed to send READ call for %s", data->path);
1919 free(mdata);
1920 if (data->num_calls == 0) {
1921 free_nfs_cb_data(data);
1922 return -1;
1923 }
1924 data->oom = 1;
1925 break;
1926 }
1927
1928 count -= readcount;
1929 offset += readcount;
1930 data->num_calls++;
1931 } while (count > 0);
1932
1933 return 0;
1934 }
1935
1936 int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, nfs_cb cb, void *private_data)
1937 {
1938 return nfs_pread_async_internal(nfs, nfsfh, offset, count, cb, private_data, 0);
1939 }
1940
1941 /*
1942 * Async read()
1943 */
1944 int nfs_read_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, nfs_cb cb, void *private_data)
1945 {
1946 return nfs_pread_async_internal(nfs, nfsfh, nfsfh->offset, count, cb, private_data, 1);
1947 }
1948
1949
1950
1951 /*
1952 * Async pwrite()
1953 */
1954 static void nfs_fill_WRITE3args (WRITE3args *args, struct nfsfh *fh, uint64_t offset, uint64_t count,
1955 void *buf)
1956 {
1957 memset(args, 0, sizeof(WRITE3args));
1958 args->file = fh->fh;
1959 args->offset = offset;
1960 args->count = count;
1961 args->stable = fh->is_sync ? FILE_SYNC : UNSTABLE;
1962 args->data.data_len = count;
1963 args->data.data_val = buf;
1964 }
1965
1966 static void nfs_pwrite_mcb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
1967 {
1968 struct nfs_mcb_data *mdata = private_data;
1969 struct nfs_cb_data *data = mdata->data;
1970 struct nfs_context *nfs = data->nfs;
1971 WRITE3res *res;
1972
1973 assert(rpc->magic == RPC_CONTEXT_MAGIC);
1974
1975 data->num_calls--;
1976
1977 if (status == RPC_STATUS_ERROR) {
1978 /* flag the failure but do not invoke callback until we have received all responses */
1979 data->error = 1;
1980 }
1981 if (status == RPC_STATUS_CANCEL) {
1982 /* flag the cancellation but do not invoke callback until we have received all responses */
1983 data->cancel = 1;
1984 }
1985
1986 if (status == RPC_STATUS_SUCCESS) {
1987 res = command_data;
1988 if (res->status != NFS3_OK) {
1989 rpc_set_error(nfs->rpc, "NFS: Write failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
1990 data->error = 1;
1991 } else {
1992 uint64_t count = res->WRITE3res_u.resok.count;
1993
1994 if (mdata->update_pos)
1995 data->nfsfh->offset += count;
1996
1997 if (count < mdata->count) {
1998 if (count == 0) {
1999 rpc_set_error(nfs->rpc, "NFS: Write failed. No bytes written!");
2000 data->error = 1;
2001 } else {
2002 /* reissue reminder of this write request */
2003 WRITE3args args;
2004 mdata->offset += count;
2005 mdata->count -= count;
2006
2007 nfs_fill_WRITE3args(&args, data->nfsfh, mdata->offset, mdata->count,
2008 &data->usrbuf[mdata->offset - data->offset]);
2009 if (rpc_nfs3_write_async(nfs->rpc, nfs_pwrite_mcb, &args, mdata) == 0) {
2010 data->num_calls++;
2011 return;
2012 } else {
2013 rpc_set_error(nfs->rpc, "RPC error: Failed to send WRITE call for %s", data->path);
2014 data->oom = 1;
2015 }
2016 }
2017 }
2018 if (count > 0) {
2019 if (data->max_offset < mdata->offset + count) {
2020 data->max_offset = mdata->offset + count;
2021 }
2022 }
2023 }
2024 }
2025
2026 free(mdata);
2027
2028 if (data->num_calls > 0) {
2029 /* still waiting for more replies */
2030 return;
2031 }
2032 if (data->oom != 0) {
2033 data->cb(-ENOMEM, nfs, command_data, data->private_data);
2034 free_nfs_cb_data(data);
2035 return;
2036 }
2037 if (data->error != 0) {
2038 data->cb(-EFAULT, nfs, command_data, data->private_data);
2039 free_nfs_cb_data(data);
2040 return;
2041 }
2042 if (data->cancel != 0) {
2043 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2044 free_nfs_cb_data(data);
2045 return;
2046 }
2047
2048 data->cb(data->max_offset - data->offset, nfs, NULL, data->private_data);
2049
2050 free_nfs_cb_data(data);
2051 }
2052
2053
2054 static int nfs_pwrite_async_internal(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buf, nfs_cb cb, void *private_data, int update_pos)
2055 {
2056 struct nfs_cb_data *data;
2057
2058 data = malloc(sizeof(struct nfs_cb_data));
2059 if (data == NULL) {
2060 rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
2061 return -1;
2062 }
2063 memset(data, 0, sizeof(struct nfs_cb_data));
2064 data->nfs = nfs;
2065 data->cb = cb;
2066 data->private_data = private_data;
2067 data->nfsfh = nfsfh;
2068 data->usrbuf = buf;
2069
2070 /* hello, clang-analyzer */
2071 assert(data->num_calls == 0);
2072
2073 /* chop requests into chunks of at most WRITEMAX bytes if necessary.
2074 * we send all writes in parallel so that performance is still good.
2075 */
2076 data->max_offset = offset;
2077 data->offset = offset;
2078
2079 do {
2080 uint64_t writecount = count;
2081 struct nfs_mcb_data *mdata;
2082 WRITE3args args;
2083
2084 if (writecount > nfs_get_writemax(nfs)) {
2085 writecount = nfs_get_writemax(nfs);
2086 }
2087
2088 mdata = malloc(sizeof(struct nfs_mcb_data));
2089 if (mdata == NULL) {
2090 rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_mcb_data structure");
2091 if (data->num_calls == 0) {
2092 free_nfs_cb_data(data);
2093 return -1;
2094 }
2095 data->oom = 1;
2096 break;
2097 }
2098 memset(mdata, 0, sizeof(struct nfs_mcb_data));
2099 mdata->data = data;
2100 mdata->offset = offset;
2101 mdata->count = writecount;
2102 mdata->update_pos = update_pos;
2103
2104 nfs_fill_WRITE3args(&args, nfsfh, offset, writecount, &buf[offset - data->offset]);
2105
2106 if (rpc_nfs3_write_async(nfs->rpc, nfs_pwrite_mcb, &args, mdata) != 0) {
2107 rpc_set_error(nfs->rpc, "RPC error: Failed to send WRITE call for %s", data->path);
2108 free(mdata);
2109 if (data->num_calls == 0) {
2110 free_nfs_cb_data(data);
2111 return -1;
2112 }
2113 data->oom = 1;
2114 break;
2115 }
2116
2117 count -= writecount;
2118 offset += writecount;
2119 data->num_calls++;
2120 } while (count > 0);
2121
2122 return 0;
2123 }
2124
2125 int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buf, nfs_cb cb, void *private_data)
2126 {
2127 return nfs_pwrite_async_internal(nfs, nfsfh, offset, count, buf, cb, private_data, 0);
2128 }
2129
2130 /*
2131 * Async write()
2132 */
2133 static void nfs_write_append_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
2134 {
2135 struct nfs_cb_data *data = private_data;
2136 struct nfs_context *nfs = data->nfs;
2137 GETATTR3res *res;
2138
2139 assert(rpc->magic == RPC_CONTEXT_MAGIC);
2140
2141 if (status == RPC_STATUS_ERROR) {
2142 data->cb(-EFAULT, nfs, command_data, data->private_data);
2143 free_nfs_cb_data(data);
2144 return;
2145 }
2146 if (status == RPC_STATUS_CANCEL) {
2147 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2148 free_nfs_cb_data(data);
2149 return;
2150 }
2151
2152 res = command_data;
2153 if (res->status != NFS3_OK) {
2154 rpc_set_error(nfs->rpc, "NFS: GETATTR failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
2155 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
2156 free_nfs_cb_data(data);
2157 return;
2158 }
2159
2160 if (nfs_pwrite_async_internal(nfs, data->nfsfh, res->GETATTR3res_u.resok.obj_attributes.size, data->count, data->usrbuf, data->cb, data->private_data, 1) != 0) {
2161 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2162 free_nfs_cb_data(data);
2163 return;
2164 }
2165 free_nfs_cb_data(data);
2166 }
2167
2168 int nfs_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buf, nfs_cb cb, void *private_data)
2169 {
2170 nfs_ra_invalidate(nfsfh);
2171 if (nfsfh->is_append) {
2172 struct GETATTR3args args;
2173 struct nfs_cb_data *data;
2174
2175 data = malloc(sizeof(struct nfs_cb_data));
2176 if (data == NULL) {
2177 rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
2178 return -1;
2179 }
2180 memset(data, 0, sizeof(struct nfs_cb_data));
2181 data->nfs = nfs;
2182 data->cb = cb;
2183 data->private_data = private_data;
2184 data->nfsfh = nfsfh;
2185 data->usrbuf = buf;
2186 data->count = count;
2187
2188 memset(&args, 0, sizeof(GETATTR3args));
2189 args.object = nfsfh->fh;
2190
2191 if (rpc_nfs3_getattr_async(nfs->rpc, nfs_write_append_cb, &args, data) != 0) {
2192 rpc_set_error(nfs->rpc, "out of memory: failed to send GETATTR");
2193 free_nfs_cb_data(data);
2194 return -1;
2195 }
2196 return 0;
2197 }
2198 return nfs_pwrite_async_internal(nfs, nfsfh, nfsfh->offset, count, buf, cb, private_data, 1);
2199 }
2200
2201
2202
2203
2204 /*
2205 * close
2206 */
2207
2208 int nfs_close_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data)
2209 {
2210 free_nfsfh(nfsfh);
2211 cb(0, nfs, NULL, private_data);
2212 return 0;
2213 };
2214
2215
2216
2217
2218
2219 /*
2220 * Async fstat()
2221 */
2222 int nfs_fstat_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data)
2223 {
2224 struct nfs_cb_data *data;
2225 struct GETATTR3args args;
2226
2227 data = malloc(sizeof(struct nfs_cb_data));
2228 if (data == NULL) {
2229 rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
2230 return -1;
2231 }
2232 memset(data, 0, sizeof(struct nfs_cb_data));
2233 data->nfs = nfs;
2234 data->cb = cb;
2235 data->private_data = private_data;
2236
2237 memset(&args, 0, sizeof(GETATTR3args));
2238 args.object = nfsfh->fh;
2239
2240 if (rpc_nfs3_getattr_async(nfs->rpc, nfs_stat_1_cb, &args, data) != 0) {
2241 rpc_set_error(nfs->rpc, "RPC error: Failed to send STAT GETATTR call for %s", data->path);
2242 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2243 free_nfs_cb_data(data);
2244 return -1;
2245 }
2246 return 0;
2247 }
2248
2249 /*
2250 * Async fstat64()
2251 */
2252 int nfs_fstat64_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data)
2253 {
2254 struct nfs_cb_data *data;
2255 struct GETATTR3args args;
2256
2257 data = malloc(sizeof(struct nfs_cb_data));
2258 if (data == NULL) {
2259 rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
2260 return -1;
2261 }
2262 memset(data, 0, sizeof(struct nfs_cb_data));
2263 data->nfs = nfs;
2264 data->cb = cb;
2265 data->private_data = private_data;
2266
2267 memset(&args, 0, sizeof(GETATTR3args));
2268 args.object = nfsfh->fh;
2269
2270 if (rpc_nfs3_getattr_async(nfs->rpc, nfs_stat64_1_cb, &args, data) != 0) {
2271 rpc_set_error(nfs->rpc, "RPC error: Failed to send STAT GETATTR call for %s", data->path);
2272 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2273 free_nfs_cb_data(data);
2274 return -1;
2275 }
2276 return 0;
2277 }
2278
2279
2280
2281 /*
2282 * Async fsync()
2283 */
2284 static void nfs_fsync_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
2285 {
2286 struct nfs_cb_data *data = private_data;
2287 struct nfs_context *nfs = data->nfs;
2288 COMMIT3res *res;
2289
2290 assert(rpc->magic == RPC_CONTEXT_MAGIC);
2291
2292 if (status == RPC_STATUS_ERROR) {
2293 data->cb(-EFAULT, nfs, command_data, data->private_data);
2294 free_nfs_cb_data(data);
2295 return;
2296 }
2297 if (status == RPC_STATUS_CANCEL) {
2298 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2299 free_nfs_cb_data(data);
2300 return;
2301 }
2302
2303 res = command_data;
2304 if (res->status != NFS3_OK) {
2305 rpc_set_error(nfs->rpc, "NFS: Commit failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
2306 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
2307 free_nfs_cb_data(data);
2308 return;
2309 }
2310
2311 data->cb(0, nfs, NULL, data->private_data);
2312 free_nfs_cb_data(data);
2313 }
2314
2315 int nfs_fsync_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data)
2316 {
2317 struct nfs_cb_data *data;
2318 struct COMMIT3args args;
2319
2320 data = malloc(sizeof(struct nfs_cb_data));
2321 if (data == NULL) {
2322 rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
2323 return -1;
2324 }
2325 memset(data, 0, sizeof(struct nfs_cb_data));
2326 data->nfs = nfs;
2327 data->cb = cb;
2328 data->private_data = private_data;
2329
2330 args.file = nfsfh->fh;
2331 args.offset = 0;
2332 args.count = 0;
2333 if (rpc_nfs3_commit_async(nfs->rpc, nfs_fsync_cb, &args, data) != 0) {
2334 rpc_set_error(nfs->rpc, "RPC error: Failed to send COMMIT call for %s", data->path);
2335 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2336 free_nfs_cb_data(data);
2337 return -1;
2338 }
2339 return 0;
2340 }
2341
2342
2343
2344
2345 /*
2346 * Async ftruncate()
2347 */
2348 static void nfs_ftruncate_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
2349 {
2350 struct nfs_cb_data *data = private_data;
2351 struct nfs_context *nfs = data->nfs;
2352 SETATTR3res *res;
2353
2354 assert(rpc->magic == RPC_CONTEXT_MAGIC);
2355
2356 if (status == RPC_STATUS_ERROR) {
2357 data->cb(-EFAULT, nfs, command_data, data->private_data);
2358 free_nfs_cb_data(data);
2359 return;
2360 }
2361 if (status == RPC_STATUS_CANCEL) {
2362 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2363 free_nfs_cb_data(data);
2364 return;
2365 }
2366
2367 res = command_data;
2368 if (res->status != NFS3_OK) {
2369 rpc_set_error(nfs->rpc, "NFS: Setattr failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
2370 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
2371 free_nfs_cb_data(data);
2372 return;
2373 }
2374
2375 data->cb(0, nfs, NULL, data->private_data);
2376 free_nfs_cb_data(data);
2377 }
2378
2379 int nfs_ftruncate_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t length, nfs_cb cb, void *private_data)
2380 {
2381 struct nfs_cb_data *data;
2382 SETATTR3args args;
2383
2384 data = malloc(sizeof(struct nfs_cb_data));
2385 if (data == NULL) {
2386 rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
2387 return -1;
2388 }
2389 memset(data, 0, sizeof(struct nfs_cb_data));
2390 data->nfs = nfs;
2391 data->cb = cb;
2392 data->private_data = private_data;
2393
2394 memset(&args, 0, sizeof(SETATTR3args));
2395 args.object = nfsfh->fh;
2396 args.new_attributes.size.set_it = 1;
2397 args.new_attributes.size.set_size3_u.size = length;
2398
2399 if (rpc_nfs3_setattr_async(nfs->rpc, nfs_ftruncate_cb, &args, data) != 0) {
2400 rpc_set_error(nfs->rpc, "RPC error: Failed to send SETATTR call for %s", data->path);
2401 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2402 free_nfs_cb_data(data);
2403 return -1;
2404 }
2405 return 0;
2406 }
2407
2408
2409 /*
2410 * Async truncate()
2411 */
2412 static int nfs_truncate_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
2413 {
2414 uint64_t offset = data->continue_int;
2415 struct nfsfh nfsfh;
2416
2417 nfsfh.fh = data->fh;
2418
2419 if (nfs_ftruncate_async(nfs, &nfsfh, offset, data->cb, data->private_data) != 0) {
2420 rpc_set_error(nfs->rpc, "RPC error: Failed to send SETATTR call for %s", data->path);
2421 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2422 free_nfs_cb_data(data);
2423 return -1;
2424 }
2425 free_nfs_cb_data(data);
2426 return 0;
2427 }
2428
2429 int nfs_truncate_async(struct nfs_context *nfs, const char *path, uint64_t length, nfs_cb cb, void *private_data)
2430 {
2431 uint64_t offset;
2432
2433 offset = length;
2434
2435 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_truncate_continue_internal, NULL, NULL, offset) != 0) {
2436 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
2437 return -1;
2438 }
2439
2440 return 0;
2441 }
2442
2443
2444
2445
2446 /*
2447 * Async mkdir()
2448 */
2449 static void nfs_mkdir_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
2450 {
2451 MKDIR3res *res;
2452 struct nfs_cb_data *data = private_data;
2453 struct nfs_context *nfs = data->nfs;
2454 char *str = data->continue_data;
2455
2456 assert(rpc->magic == RPC_CONTEXT_MAGIC);
2457
2458 str = &str[strlen(str) + 1];
2459
2460 if (status == RPC_STATUS_ERROR) {
2461 data->cb(-EFAULT, nfs, command_data, data->private_data);
2462 free_nfs_cb_data(data);
2463 return;
2464 }
2465 if (status == RPC_STATUS_CANCEL) {
2466 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2467 free_nfs_cb_data(data);
2468 return;
2469 }
2470
2471 res = command_data;
2472 if (res->status != NFS3_OK) {
2473 rpc_set_error(nfs->rpc, "NFS: MKDIR of %s/%s failed with %s(%d)", data->saved_path, str, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
2474 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
2475 free_nfs_cb_data(data);
2476 return;
2477 }
2478
2479 data->cb(0, nfs, NULL, data->private_data);
2480 free_nfs_cb_data(data);
2481 }
2482
2483 static int nfs_mkdir_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
2484 {
2485 char *str = data->continue_data;
2486 MKDIR3args args;
2487
2488 str = &str[strlen(str) + 1];
2489
2490 memset(&args, 0, sizeof(MKDIR3args));
2491 args.where.dir = data->fh;
2492 args.where.name = str;
2493 args.attributes.mode.set_it = 1;
2494 args.attributes.mode.set_mode3_u.mode = 0755;
2495
2496 if (rpc_nfs3_mkdir_async(nfs->rpc, nfs_mkdir_cb, &args, data) != 0) {
2497 rpc_set_error(nfs->rpc, "RPC error: Failed to send MKDIR call for %s", data->path);
2498 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2499 free_nfs_cb_data(data);
2500 return -1;
2501 }
2502 return 0;
2503 }
2504
2505 int nfs_mkdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
2506 {
2507 char *new_path;
2508 char *ptr;
2509
2510 new_path = strdup(path);
2511 if (new_path == NULL) {
2512 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for path");
2513 return -1;
2514 }
2515
2516 ptr = strrchr(new_path, '/');
2517 if (ptr == NULL) {
2518 free(new_path);
2519 rpc_set_error(nfs->rpc, "Invalid path %s", path);
2520 return -1;
2521 }
2522 *ptr = 0;
2523
2524 /* new_path now points to the parent directory, and beyond the nul terminateor is the new directory to create */
2525 if (nfs_lookuppath_async(nfs, new_path, cb, private_data, nfs_mkdir_continue_internal, new_path, free, 0) != 0) {
2526 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path component");
2527 return -1;
2528 }
2529
2530 return 0;
2531 }
2532
2533
2534
2535
2536
2537 /*
2538 * Async rmdir()
2539 */
2540 static void nfs_rmdir_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
2541 {
2542 RMDIR3res *res;
2543 struct nfs_cb_data *data = private_data;
2544 struct nfs_context *nfs = data->nfs;
2545 char *str = data->continue_data;
2546
2547 assert(rpc->magic == RPC_CONTEXT_MAGIC);
2548
2549 str = &str[strlen(str) + 1];
2550
2551 if (status == RPC_STATUS_ERROR) {
2552 data->cb(-EFAULT, nfs, command_data, data->private_data);
2553 free_nfs_cb_data(data);
2554 return;
2555 }
2556 if (status == RPC_STATUS_CANCEL) {
2557 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2558 free_nfs_cb_data(data);
2559 return;
2560 }
2561
2562 res = command_data;
2563 if (res->status != NFS3_OK) {
2564 rpc_set_error(nfs->rpc, "NFS: RMDIR of %s/%s failed with %s(%d)", data->saved_path, str, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
2565 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
2566 free_nfs_cb_data(data);
2567 return;
2568 }
2569
2570 data->cb(0, nfs, NULL, data->private_data);
2571 free_nfs_cb_data(data);
2572 }
2573
2574 static int nfs_rmdir_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
2575 {
2576 char *str = data->continue_data;
2577 RMDIR3args args;
2578
2579 str = &str[strlen(str) + 1];
2580
2581 args.object.dir = data->fh;
2582 args.object.name = str;
2583 if (rpc_nfs3_rmdir_async(nfs->rpc, nfs_rmdir_cb, &args, data) != 0) {
2584 rpc_set_error(nfs->rpc, "RPC error: Failed to send RMDIR call for %s", data->path);
2585 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2586 free_nfs_cb_data(data);
2587 return -1;
2588 }
2589 return 0;
2590 }
2591
2592 int nfs_rmdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
2593 {
2594 char *new_path;
2595 char *ptr;
2596
2597 new_path = strdup(path);
2598 if (new_path == NULL) {
2599 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for path");
2600 return -1;
2601 }
2602
2603 ptr = strrchr(new_path, '/');
2604 if (ptr == NULL) {
2605 free(new_path);
2606 rpc_set_error(nfs->rpc, "Invalid path %s", path);
2607 return -1;
2608 }
2609 *ptr = 0;
2610
2611 /* new_path now points to the parent directory, and beyond the nul terminateor is the new directory to create */
2612 if (nfs_lookuppath_async(nfs, new_path, cb, private_data, nfs_rmdir_continue_internal, new_path, free, 0) != 0) {
2613 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
2614 return -1;
2615 }
2616
2617 return 0;
2618 }
2619
2620
2621
2622
2623 /*
2624 * Async creat()
2625 */
2626 struct create_cb_data {
2627 char *path;
2628 int flags;
2629 int mode;
2630 };
2631
2632 static void free_create_cb_data(void *ptr)
2633 {
2634 struct create_cb_data *data = ptr;
2635
2636 free(data->path);
2637 free(data);
2638 }
2639
2640 static void nfs_create_trunc_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
2641 {
2642 struct nfs_cb_data *data = private_data;
2643 struct nfs_context *nfs = data->nfs;
2644 struct nfsfh *nfsfh;
2645 SETATTR3res *res;
2646
2647 assert(rpc->magic == RPC_CONTEXT_MAGIC);
2648
2649 if (status == RPC_STATUS_ERROR) {
2650 data->cb(-EFAULT, nfs, command_data, data->private_data);
2651 free_nfs_cb_data(data);
2652 free_nfsfh(nfsfh);
2653 return;
2654 }
2655 if (status == RPC_STATUS_CANCEL) {
2656 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2657 free_nfs_cb_data(data);
2658 free_nfsfh(nfsfh);
2659 return;
2660 }
2661
2662 res = command_data;
2663 if (res->status != NFS3_OK) {
2664 rpc_set_error(nfs->rpc, "NFS: Setattr failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
2665 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
2666 free_nfs_cb_data(data);
2667 free_nfsfh(nfsfh);
2668 return;
2669 }
2670
2671 data->cb(0, nfs, data->nfsfh, data->private_data);
2672 free_nfs_cb_data(data);
2673 }
2674
2675 static void nfs_create_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
2676 {
2677 LOOKUP3res *res;
2678 struct nfs_cb_data *data = private_data;
2679 struct nfs_context *nfs = data->nfs;
2680 struct nfsfh *nfsfh;
2681 struct create_cb_data *cb_data = data->continue_data;
2682 char *str = cb_data->path;
2683
2684 assert(rpc->magic == RPC_CONTEXT_MAGIC);
2685
2686 if (status == RPC_STATUS_ERROR) {
2687 data->cb(-EFAULT, nfs, command_data, data->private_data);
2688 free_nfs_cb_data(data);
2689 return;
2690 }
2691 if (status == RPC_STATUS_CANCEL) {
2692 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2693 free_nfs_cb_data(data);
2694 return;
2695 }
2696
2697 str = &str[strlen(str) + 1];
2698 res = command_data;
2699 if (res->status != NFS3_OK) {
2700 rpc_set_error(nfs->rpc, "NFS: CREATE of %s/%s failed with %s(%d)", data->saved_path, str, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
2701 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
2702
2703 return;
2704 }
2705
2706 nfsfh = malloc(sizeof(struct nfsfh));
2707 if (nfsfh == NULL) {
2708 rpc_set_error(nfs->rpc, "NFS: Failed to allocate nfsfh structure");
2709 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2710 free_nfs_cb_data(data);
2711 return;
2712 }
2713 memset(nfsfh, 0, sizeof(struct nfsfh));
2714
2715 if (cb_data->flags & O_SYNC) {
2716 nfsfh->is_sync = 1;
2717 }
2718 if (cb_data->flags & O_APPEND) {
2719 nfsfh->is_append = 1;
2720 }
2721
2722 /* copy the filehandle */
2723 nfsfh->fh.data.data_len = res->LOOKUP3res_u.resok.object.data.data_len;
2724 nfsfh->fh.data.data_val = malloc(nfsfh->fh.data.data_len);
2725 if (nfsfh->fh.data.data_val == NULL) {
2726 rpc_set_error(nfs->rpc, "Out of memory: Failed to allocate fh structure");
2727 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2728 free_nfs_cb_data(data);
2729 free(nfsfh);
2730 return;
2731 }
2732 memcpy(nfsfh->fh.data.data_val, res->LOOKUP3res_u.resok.object.data.data_val, nfsfh->fh.data.data_len);
2733
2734 /* Try to truncate it if we were requested to */
2735 if (cb_data->flags & O_TRUNC) {
2736 SETATTR3args args;
2737
2738 data->nfsfh = nfsfh;
2739
2740 memset(&args, 0, sizeof(SETATTR3args));
2741 args.object = nfsfh->fh;
2742 args.new_attributes.size.set_it = 1;
2743 args.new_attributes.size.set_size3_u.size = 0;
2744
2745 if (rpc_nfs3_setattr_async(nfs->rpc, nfs_create_trunc_cb,
2746 &args, data) != 0) {
2747 rpc_set_error(nfs->rpc, "RPC error: Failed to send "
2748 "SETATTR call for %s", data->path);
2749 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc),
2750 data->private_data);
2751 free_nfs_cb_data(data);
2752 free_nfsfh(nfsfh);
2753 return;
2754 }
2755 return;
2756 }
2757
2758 data->cb(0, nfs, nfsfh, data->private_data);
2759 free_nfs_cb_data(data);
2760 }
2761
2762
2763
2764 static void nfs_create_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
2765 {
2766 CREATE3res *res;
2767 struct nfs_cb_data *data = private_data;
2768 struct nfs_context *nfs = data->nfs;
2769 struct create_cb_data *cb_data = data->continue_data;
2770 char *str = cb_data->path;
2771 LOOKUP3args args;
2772
2773 assert(rpc->magic == RPC_CONTEXT_MAGIC);
2774
2775 if (status == RPC_STATUS_ERROR) {
2776 data->cb(-EFAULT, nfs, command_data, data->private_data);
2777 free_nfs_cb_data(data);
2778 return;
2779 }
2780 if (status == RPC_STATUS_CANCEL) {
2781 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2782 free_nfs_cb_data(data);
2783 return;
2784 }
2785
2786 str = &str[strlen(str) + 1];
2787 res = command_data;
2788 if (res->status != NFS3_OK) {
2789 rpc_set_error(nfs->rpc, "NFS: CREATE of %s/%s failed with %s(%d)", data->saved_path, str, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
2790 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
2791 free_nfs_cb_data(data);
2792 return;
2793 }
2794
2795 memset(&args, 0, sizeof(LOOKUP3args));
2796 args.what.dir = data->fh;
2797 args.what.name = str;
2798
2799 if (rpc_nfs3_lookup_async(nfs->rpc, nfs_create_2_cb, &args, data) != 0) {
2800 rpc_set_error(nfs->rpc, "RPC error: Failed to send lookup call for %s/%s", data->saved_path, str);
2801 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2802 free_nfs_cb_data(data);
2803 return;
2804 }
2805 return;
2806 }
2807
2808 static int nfs_create_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
2809 {
2810 struct create_cb_data *cb_data = data->continue_data;
2811 char *str = cb_data->path;
2812 CREATE3args args;
2813
2814 str = &str[strlen(str) + 1];
2815
2816 memset(&args, 0, sizeof(CREATE3args));
2817 args.where.dir = data->fh;
2818 args.where.name = str;
2819 args.how.mode = (cb_data->flags & O_EXCL) ? GUARDED : UNCHECKED;
2820 args.how.createhow3_u.obj_attributes.mode.set_it = 1;
2821 args.how.createhow3_u.obj_attributes.mode.set_mode3_u.mode = cb_data->mode;
2822
2823 if (rpc_nfs3_create_async(nfs->rpc, nfs_create_1_cb, &args, data) != 0) {
2824 rpc_set_error(nfs->rpc, "RPC error: Failed to send CREATE call for %s/%s", data->path, str);
2825 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2826 free_nfs_cb_data(data);
2827 return -1;
2828 }
2829 return 0;
2830 }
2831
2832 int nfs_create_async(struct nfs_context *nfs, const char *path, int flags, int mode, nfs_cb cb, void *private_data)
2833 {
2834 struct create_cb_data *cb_data;
2835 char *ptr;
2836
2837 cb_data = malloc(sizeof(struct create_cb_data));
2838 if (cb_data == NULL) {
2839 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for cb data");
2840 return -1;
2841 }
2842
2843 cb_data->path = strdup(path);
2844 if (cb_data->path == NULL) {
2845 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for path");
2846 free(cb_data);
2847 return -1;
2848 }
2849
2850 ptr = strrchr(cb_data->path, '/');
2851 if (ptr == NULL) {
2852 rpc_set_error(nfs->rpc, "Invalid path %s", path);
2853 free_create_cb_data(cb_data);
2854 return -1;
2855 }
2856 *ptr = 0;
2857
2858 cb_data->flags = flags;
2859 cb_data->mode = mode;
2860
2861 /* new_path now points to the parent directory, and beyond the nul terminator is the new directory to create */
2862 if (nfs_lookuppath_async(nfs, cb_data->path, cb, private_data, nfs_create_continue_internal, cb_data, free_create_cb_data, 0) != 0) {
2863 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
2864 return -1;
2865 }
2866
2867 return 0;
2868 }
2869
2870 int nfs_creat_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data)
2871 {
2872 return nfs_create_async(nfs, path, 0, mode, cb, private_data);
2873 }
2874
2875
2876
2877
2878 /*
2879 * Async unlink()
2880 */
2881 static void nfs_unlink_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
2882 {
2883 REMOVE3res *res;
2884 struct nfs_cb_data *data = private_data;
2885 struct nfs_context *nfs = data->nfs;
2886 char *str = data->continue_data;
2887
2888 assert(rpc->magic == RPC_CONTEXT_MAGIC);
2889
2890 str = &str[strlen(str) + 1];
2891
2892 if (status == RPC_STATUS_ERROR) {
2893 data->cb(-EFAULT, nfs, command_data, data->private_data);
2894 free_nfs_cb_data(data);
2895 return;
2896 }
2897 if (status == RPC_STATUS_CANCEL) {
2898 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2899 free_nfs_cb_data(data);
2900 return;
2901 }
2902
2903 res = command_data;
2904 if (res->status != NFS3_OK) {
2905 rpc_set_error(nfs->rpc, "NFS: REMOVE of %s/%s failed with %s(%d)", data->saved_path, str, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
2906 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
2907 free_nfs_cb_data(data);
2908 return;
2909 }
2910
2911 data->cb(0, nfs, NULL, data->private_data);
2912 free_nfs_cb_data(data);
2913 }
2914
2915 static int nfs_unlink_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
2916 {
2917 char *str = data->continue_data;
2918 struct REMOVE3args args;
2919
2920 str = &str[strlen(str) + 1];
2921
2922 args.object.dir = data->fh;
2923 args.object.name = str;
2924 if (rpc_nfs3_remove_async(nfs->rpc, nfs_unlink_cb, &args, data) != 0) {
2925 rpc_set_error(nfs->rpc, "RPC error: Failed to send REMOVE call for %s", data->path);
2926 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2927 free_nfs_cb_data(data);
2928 return -1;
2929 }
2930 return 0;
2931 }
2932
2933 int nfs_unlink_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
2934 {
2935 char *new_path;
2936 char *ptr;
2937
2938 new_path = strdup(path);
2939 if (new_path == NULL) {
2940 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for path");
2941 return -1;
2942 }
2943
2944 ptr = strrchr(new_path, '/');
2945 if (ptr == NULL) {
2946 free(new_path);
2947 rpc_set_error(nfs->rpc, "Invalid path %s", path);
2948 return -1;
2949 }
2950 *ptr = 0;
2951
2952 /* new_path now points to the parent directory, and beyond the nul terminateor is the new directory to create */
2953 if (nfs_lookuppath_async(nfs, new_path, cb, private_data, nfs_unlink_continue_internal, new_path, free, 0) != 0) {
2954 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
2955 return -1;
2956 }
2957
2958 return 0;
2959 }
2960
2961
2962 /*
2963 * Async mknod()
2964 */
2965 struct mknod_cb_data {
2966 char *path;
2967 int mode;
2968 int major;
2969 int minor;
2970 };
2971
2972 static void free_mknod_cb_data(void *ptr)
2973 {
2974 struct mknod_cb_data *data = ptr;
2975
2976 free(data->path);
2977 free(data);
2978 }
2979
2980 static void nfs_mknod_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
2981 {
2982 MKNOD3res *res;
2983 struct nfs_cb_data *data = private_data;
2984 struct nfs_context *nfs = data->nfs;
2985 char *str = data->continue_data;
2986
2987 assert(rpc->magic == RPC_CONTEXT_MAGIC);
2988
2989 str = &str[strlen(str) + 1];
2990
2991 if (status == RPC_STATUS_ERROR) {
2992 data->cb(-EFAULT, nfs, command_data, data->private_data);
2993 free_nfs_cb_data(data);
2994 return;
2995 }
2996 if (status == RPC_STATUS_CANCEL) {
2997 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2998 free_nfs_cb_data(data);
2999 return;
3000 }
3001
3002 res = command_data;
3003 if (res->status != NFS3_OK) {
3004 rpc_set_error(nfs->rpc, "NFS: MKNOD of %s/%s failed with %s(%d)", data->saved_path, str, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
3005 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
3006 free_nfs_cb_data(data);
3007 return;
3008 }
3009
3010 data->cb(0, nfs, NULL, data->private_data);
3011 free_nfs_cb_data(data);
3012 }
3013
3014 static int nfs_mknod_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
3015 {
3016 struct mknod_cb_data *cb_data = data->continue_data;
3017 char *str = cb_data->path;
3018 MKNOD3args args;
3019
3020 str = &str[strlen(str) + 1];
3021
3022 args.where.dir = data->fh;
3023 args.where.name = str;
3024 switch (cb_data->mode & S_IFMT) {
3025 case S_IFCHR:
3026 args.what.type = NF3CHR;
3027 args.what.mknoddata3_u.chr_device.dev_attributes.mode.set_it = 1;
3028 args.what.mknoddata3_u.chr_device.dev_attributes.mode.set_mode3_u.mode = cb_data->mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
3029 args.what.mknoddata3_u.chr_device.spec.specdata1 = cb_data->major;
3030 args.what.mknoddata3_u.chr_device.spec.specdata2 = cb_data->minor;
3031 break;
3032 case S_IFBLK:
3033 args.what.type = NF3BLK;
3034 args.what.mknoddata3_u.blk_device.dev_attributes.mode.set_it = 1;
3035 args.what.mknoddata3_u.blk_device.dev_attributes.mode.set_mode3_u.mode = cb_data->mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
3036 args.what.mknoddata3_u.blk_device.spec.specdata1 = cb_data->major;
3037 args.what.mknoddata3_u.blk_device.spec.specdata2 = cb_data->minor;
3038 case S_IFSOCK:
3039 args.what.type = NF3SOCK;
3040 args.what.mknoddata3_u.sock_attributes.mode.set_it = 1;
3041 args.what.mknoddata3_u.sock_attributes.mode.set_mode3_u.mode = cb_data->mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
3042 break;
3043 case S_IFIFO:
3044 args.what.type = NF3FIFO;
3045 args.what.mknoddata3_u.pipe_attributes.mode.set_it = 1;
3046 args.what.mknoddata3_u.pipe_attributes.mode.set_mode3_u.mode = cb_data->mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
3047 break;
3048 default:
3049 rpc_set_error(nfs->rpc, "Invalid file type for NFS3/MKNOD call");
3050 data->cb(-EINVAL, nfs, rpc_get_error(nfs->rpc), data->private_data);
3051 free_nfs_cb_data(data);
3052 return -1;
3053 }
3054
3055 if (rpc_nfs3_mknod_async(nfs->rpc, nfs_mknod_cb, &args, data) != 0) {
3056 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
3057 free_nfs_cb_data(data);
3058 return -1;
3059 }
3060 return 0;
3061 }
3062
3063 int nfs_mknod_async(struct nfs_context *nfs, const char *path, int mode, int dev, nfs_cb cb, void *private_data)
3064 {
3065 char *ptr;
3066 struct mknod_cb_data *cb_data;
3067
3068 cb_data = malloc(sizeof(struct mknod_cb_data));
3069 if (cb_data == NULL) {
3070 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for cb data");
3071 return -1;
3072 }
3073
3074 cb_data->path = strdup(path);
3075 if (cb_data->path == NULL) {
3076 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for path");
3077 free(cb_data);
3078 return -1;
3079 }
3080
3081 ptr = strrchr(cb_data->path, '/');
3082 if (ptr == NULL) {
3083 rpc_set_error(nfs->rpc, "Invalid path %s", path);
3084 free_mknod_cb_data(cb_data);
3085 return -1;
3086 }
3087 *ptr = 0;
3088
3089 cb_data->mode = mode;
3090 cb_data->major = major(dev);
3091 cb_data->minor = minor(dev);
3092
3093 /* data->path now points to the parent directory, and beyond the nul terminateor is the new directory to create */
3094 if (nfs_lookuppath_async(nfs, cb_data->path, cb, private_data, nfs_mknod_continue_internal, cb_data, free_mknod_cb_data, 0) != 0) {
3095 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
3096 return -1;
3097 }
3098
3099 return 0;
3100 }
3101
3102 /*
3103 * Async opendir()
3104 */
3105
3106 /* ReadDirPlus Emulation Callback data */
3107 struct rdpe_cb_data {
3108 int getattrcount;
3109 int status;
3110 struct nfs_cb_data *data;
3111 };
3112
3113 /* ReadDirPlus Emulation LOOKUP Callback data */
3114 struct rdpe_lookup_cb_data {
3115 struct rdpe_cb_data *rdpe_cb_data;
3116 struct nfsdirent *nfsdirent;
3117 };
3118
3119 /* Workaround for servers lacking READDIRPLUS, use READDIR instead and a GETATTR-loop */
3120 static void nfs_opendir3_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
3121 {
3122 LOOKUP3res *res = command_data;
3123 struct rdpe_lookup_cb_data *rdpe_lookup_cb_data = private_data;
3124 struct rdpe_cb_data *rdpe_cb_data = rdpe_lookup_cb_data->rdpe_cb_data;
3125 struct nfs_cb_data *data = rdpe_cb_data->data;
3126 struct nfsdir *nfsdir = data->continue_data;
3127 struct nfs_context *nfs = data->nfs;
3128 struct nfsdirent *nfsdirent = rdpe_lookup_cb_data->nfsdirent;
3129
3130 assert(rpc->magic == RPC_CONTEXT_MAGIC);
3131
3132 free(rdpe_lookup_cb_data);
3133
3134 rdpe_cb_data->getattrcount--;
3135
3136 if (status == RPC_STATUS_ERROR) {
3137 rpc_set_error(nfs->rpc, "LOOKUP during READDIRPLUS emulation "
3138 "failed with RPC_STATUS_ERROR");
3139 rdpe_cb_data->status = RPC_STATUS_ERROR;
3140 }
3141 if (status == RPC_STATUS_CANCEL) {
3142 rpc_set_error(nfs->rpc, "LOOKUP during READDIRPLUS emulation "
3143 "failed with RPC_STATUS_CANCEL");
3144 rdpe_cb_data->status = RPC_STATUS_CANCEL;
3145 }
3146 if (status == RPC_STATUS_SUCCESS && res->status == NFS3_OK) {
3147 if (res->LOOKUP3res_u.resok.obj_attributes.attributes_follow) {
3148 fattr3 *attributes = &res->LOOKUP3res_u.resok.obj_attributes.post_op_attr_u.attributes;
3149
3150 nfsdirent->type = attributes->type;
3151 nfsdirent->mode = attributes->mode;
3152 nfsdirent->size = attributes->size;
3153
3154 nfsdirent->atime.tv_sec = attributes->atime.seconds;
3155 nfsdirent->atime.tv_usec = attributes->atime.nseconds/1000;
3156 nfsdirent->atime_nsec = attributes->atime.nseconds;
3157 nfsdirent->mtime.tv_sec = attributes->mtime.seconds;
3158 nfsdirent->mtime.tv_usec = attributes->mtime.nseconds/1000;
3159 nfsdirent->mtime_nsec = attributes->mtime.nseconds;
3160 nfsdirent->ctime.tv_sec = attributes->ctime.seconds;
3161 nfsdirent->ctime.tv_usec = attributes->ctime.nseconds/1000;
3162 nfsdirent->ctime_nsec = attributes->ctime.nseconds;
3163 nfsdirent->uid = attributes->uid;
3164 nfsdirent->gid = attributes->gid;
3165 nfsdirent->nlink = attributes->nlink;
3166 nfsdirent->dev = attributes->fsid;
3167 nfsdirent->rdev = specdata3_to_rdev(&attributes->rdev);
3168 nfsdirent->blksize = NFS_BLKSIZE;
3169 nfsdirent->blocks = (attributes->used + 512 - 1) / 512;
3170 nfsdirent->used = attributes->used;
3171 }
3172 }
3173
3174 if (rdpe_cb_data->getattrcount == 0) {
3175 if (rdpe_cb_data->status != RPC_STATUS_SUCCESS) {
3176 rpc_set_error(nfs->rpc, "READDIRPLUS emulation "
3177 "failed: %s", rpc_get_error(rpc));
3178 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc),
3179 data->private_data);
3180 nfs_free_nfsdir(nfsdir);
3181 } else {
3182 data->cb(0, nfs, nfsdir, data->private_data);
3183 }
3184 free(rdpe_cb_data);
3185
3186 data->continue_data = NULL;
3187 free_nfs_cb_data(data);
3188 }
3189 }
3190
3191 static void nfs_opendir2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
3192 {
3193 READDIR3res *res = command_data;
3194 struct nfs_cb_data *data = private_data;
3195 struct nfs_context *nfs = data->nfs;
3196 struct nfsdir *nfsdir = data->continue_data;
3197 struct nfsdirent *nfsdirent;
3198 struct entry3 *entry;
3199 uint64_t cookie = 0;
3200 struct rdpe_cb_data *rdpe_cb_data;
3201
3202 assert(rpc->magic == RPC_CONTEXT_MAGIC);
3203
3204 if (status == RPC_STATUS_ERROR) {
3205 data->cb(-EFAULT, nfs, command_data, data->private_data);
3206 nfs_free_nfsdir(nfsdir);
3207 data->continue_data = NULL;
3208 free_nfs_cb_data(data);
3209 return;
3210 }
3211
3212 if (status == RPC_STATUS_CANCEL) {
3213 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
3214 nfs_free_nfsdir(nfsdir);
3215 data->continue_data = NULL;
3216 free_nfs_cb_data(data);
3217 return;
3218 }
3219
3220 if (res->status != NFS3_OK) {
3221 rpc_set_error(nfs->rpc, "NFS: READDIR of %s failed with %s(%d)", data->saved_path, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
3222 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
3223 nfs_free_nfsdir(nfsdir);
3224 data->continue_data = NULL;
3225 free_nfs_cb_data(data);
3226 return;
3227 }
3228
3229 entry =res->READDIR3res_u.resok.reply.entries;
3230 while (entry != NULL) {
3231 nfsdirent = malloc(sizeof(struct nfsdirent));
3232 if (nfsdirent == NULL) {
3233 data->cb(-ENOMEM, nfs, "Failed to allocate dirent", data->private_data);
3234 nfs_free_nfsdir(nfsdir);
3235 data->continue_data = NULL;
3236 free_nfs_cb_data(data);
3237 return;
3238 }
3239 memset(nfsdirent, 0, sizeof(struct nfsdirent));
3240 nfsdirent->name = strdup(entry->name);
3241 if (nfsdirent->name == NULL) {
3242 data->cb(-ENOMEM, nfs, "Failed to allocate dirent->name", data->private_data);
3243 free(nfsdirent);
3244 nfs_free_nfsdir(nfsdir);
3245 data->continue_data = NULL;
3246 free_nfs_cb_data(data);
3247 return;
3248 }
3249 nfsdirent->inode = entry->fileid;
3250
3251 nfsdirent->next = nfsdir->entries;
3252 nfsdir->entries = nfsdirent;
3253
3254 cookie = entry->cookie;
3255 entry = entry->nextentry;
3256 }
3257
3258 if (res->READDIR3res_u.resok.reply.eof == 0) {
3259 READDIR3args args;
3260
3261 args.dir = data->fh;
3262 args.cookie = cookie;
3263 memcpy(&args.cookieverf, res->READDIR3res_u.resok.cookieverf, sizeof(cookieverf3));
3264 args.count = 8192;
3265
3266 if (rpc_nfs3_readdir_async(nfs->rpc, nfs_opendir2_cb, &args, data) != 0) {
3267 rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR call for %s", data->path);
3268 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
3269 nfs_free_nfsdir(nfsdir);
3270 data->continue_data = NULL;
3271 free_nfs_cb_data(data);
3272 return;
3273 }
3274 return;
3275 }
3276
3277 if (res->READDIR3res_u.resok.dir_attributes.attributes_follow)
3278 nfsdir->attr = res->READDIR3res_u.resok.dir_attributes.post_op_attr_u.attributes;
3279
3280 /* steal the dirhandle */
3281 nfsdir->current = nfsdir->entries;
3282
3283 if (nfsdir->entries) {
3284 rdpe_cb_data = malloc(sizeof(struct rdpe_cb_data));
3285 rdpe_cb_data->getattrcount = 0;
3286 rdpe_cb_data->status = RPC_STATUS_SUCCESS;
3287 rdpe_cb_data->data = data;
3288 for (nfsdirent = nfsdir->entries; nfsdirent; nfsdirent = nfsdirent->next) {
3289 struct rdpe_lookup_cb_data *rdpe_lookup_cb_data;
3290 LOOKUP3args args;
3291
3292 rdpe_lookup_cb_data = malloc(sizeof(struct rdpe_lookup_cb_data));
3293 rdpe_lookup_cb_data->rdpe_cb_data = rdpe_cb_data;
3294 rdpe_lookup_cb_data->nfsdirent = nfsdirent;
3295
3296 memset(&args, 0, sizeof(LOOKUP3args));
3297 args.what.dir = data->fh;
3298 args.what.name = nfsdirent->name;
3299
3300 if (rpc_nfs3_lookup_async(nfs->rpc, nfs_opendir3_cb, &args, rdpe_lookup_cb_data) != 0) {
3301 rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR LOOKUP call");
3302
3303 /* if we have already commands in flight, we cant just stop, we have to wait for the
3304 * commands in flight to complete
3305 */
3306 if (rdpe_cb_data->getattrcount > 0) {
3307 nfs_free_nfsdir(nfsdir);
3308 data->continue_data = NULL;
3309 free_nfs_cb_data(data);
3310 rdpe_cb_data->status = RPC_STATUS_ERROR;
3311 free(rdpe_lookup_cb_data);
3312 return;
3313 }
3314
3315 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
3316 nfs_free_nfsdir(nfsdir);
3317 data->continue_data = NULL;
3318 free_nfs_cb_data(data);
3319 free(rdpe_lookup_cb_data);
3320 free(rdpe_cb_data);
3321 return;
3322 }
3323 rdpe_cb_data->getattrcount++;
3324 }
3325 }
3326 }
3327
3328 static void nfs_opendir_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
3329 {
3330 READDIRPLUS3res *res = command_data;
3331 struct nfs_cb_data *data = private_data;
3332 struct nfs_context *nfs = data->nfs;
3333 struct nfsdir *nfsdir = data->continue_data;
3334 struct entryplus3 *entry;
3335 uint64_t cookie = 0;
3336
3337 assert(rpc->magic == RPC_CONTEXT_MAGIC);
3338
3339 if (status == RPC_STATUS_ERROR || (status == RPC_STATUS_SUCCESS && res->status == NFS3ERR_NOTSUPP) ){
3340 READDIR3args args;
3341
3342 args.dir = data->fh;
3343 args.cookie = cookie;
3344 memset(&args.cookieverf, 0, sizeof(cookieverf3));
3345 args.count = 8192;
3346
3347 if (rpc_nfs3_readdir_async(nfs->rpc, nfs_opendir2_cb, &args, data) != 0) {
3348 rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR call for %s", data->path);
3349 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
3350 nfs_free_nfsdir(nfsdir);
3351 data->continue_data = NULL;
3352 free_nfs_cb_data(data);
3353 return;
3354 }
3355 return;
3356 }
3357
3358 if (status == RPC_STATUS_CANCEL) {
3359 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
3360 nfs_free_nfsdir(nfsdir);
3361 data->continue_data = NULL;
3362 free_nfs_cb_data(data);
3363 return;
3364 }
3365
3366 if (res->status != NFS3_OK) {
3367 rpc_set_error(nfs->rpc, "NFS: READDIRPLUS of %s failed with %s(%d)", data->saved_path, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
3368 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
3369 nfs_free_nfsdir(nfsdir);
3370 data->continue_data = NULL;
3371 free_nfs_cb_data(data);
3372 return;
3373 }
3374
3375 entry =res->READDIRPLUS3res_u.resok.reply.entries;
3376 while (entry != NULL) {
3377 struct nfsdirent *nfsdirent;
3378
3379 nfsdirent = malloc(sizeof(struct nfsdirent));
3380 if (nfsdirent == NULL) {
3381 data->cb(-ENOMEM, nfs, "Failed to allocate dirent", data->private_data);
3382 nfs_free_nfsdir(nfsdir);
3383 data->continue_data = NULL;
3384 free_nfs_cb_data(data);
3385 return;
3386 }
3387 memset(nfsdirent, 0, sizeof(struct nfsdirent));
3388 nfsdirent->name = strdup(entry->name);
3389 if (nfsdirent->name == NULL) {
3390 data->cb(-ENOMEM, nfs, "Failed to allocate dirent->name", data->private_data);
3391 free(nfsdirent);
3392 nfs_free_nfsdir(nfsdir);
3393 data->continue_data = NULL;
3394 free_nfs_cb_data(data);
3395 return;
3396 }
3397 nfsdirent->inode = entry->fileid;
3398 if (entry->name_attributes.attributes_follow) {
3399 nfsdirent->type = entry->name_attributes.post_op_attr_u.attributes.type;
3400 nfsdirent->mode = entry->name_attributes.post_op_attr_u.attributes.mode;
3401 nfsdirent->size = entry->name_attributes.post_op_attr_u.attributes.size;
3402
3403 nfsdirent->atime.tv_sec = entry->name_attributes.post_op_attr_u.attributes.atime.seconds;
3404 nfsdirent->atime.tv_usec = entry->name_attributes.post_op_attr_u.attributes.atime.nseconds/1000;
3405 nfsdirent->atime_nsec = entry->name_attributes.post_op_attr_u.attributes.atime.nseconds;
3406 nfsdirent->mtime.tv_sec = entry->name_attributes.post_op_attr_u.attributes.mtime.seconds;
3407 nfsdirent->mtime.tv_usec = entry->name_attributes.post_op_attr_u.attributes.mtime.nseconds/1000;
3408 nfsdirent->mtime_nsec = entry->name_attributes.post_op_attr_u.attributes.mtime.nseconds;
3409 nfsdirent->ctime.tv_sec = entry->name_attributes.post_op_attr_u.attributes.ctime.seconds;
3410 nfsdirent->ctime.tv_usec = entry->name_attributes.post_op_attr_u.attributes.ctime.nseconds/1000;
3411 nfsdirent->ctime_nsec = entry->name_attributes.post_op_attr_u.attributes.ctime.nseconds;
3412 nfsdirent->uid = entry->name_attributes.post_op_attr_u.attributes.uid;
3413 nfsdirent->gid = entry->name_attributes.post_op_attr_u.attributes.gid;
3414 nfsdirent->nlink = entry->name_attributes.post_op_attr_u.attributes.nlink;
3415 nfsdirent->dev = entry->name_attributes.post_op_attr_u.attributes.fsid;
3416 nfsdirent->rdev = specdata3_to_rdev(&entry->name_attributes.post_op_attr_u.attributes.rdev);
3417 nfsdirent->blksize = NFS_BLKSIZE;
3418 nfsdirent->blocks = (entry->name_attributes.post_op_attr_u.attributes.used + 512 - 1) / 512;
3419 nfsdirent->used = entry->name_attributes.post_op_attr_u.attributes.used;
3420 }
3421
3422 nfsdirent->next = nfsdir->entries;
3423 nfsdir->entries = nfsdirent;
3424
3425 cookie = entry->cookie;
3426 entry = entry->nextentry;
3427 }
3428
3429 if (res->READDIRPLUS3res_u.resok.reply.eof == 0) {
3430 READDIRPLUS3args args;
3431
3432 args.dir = data->fh;
3433 args.cookie = cookie;
3434 memcpy(&args.cookieverf, res->READDIRPLUS3res_u.resok.cookieverf, sizeof(cookieverf3));
3435 args.dircount = 8192;
3436 args.maxcount = 8192;
3437
3438 if (rpc_nfs3_readdirplus_async(nfs->rpc, nfs_opendir_cb, &args, data) != 0) {
3439 rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIRPLUS call for %s", data->path);
3440 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
3441 nfs_free_nfsdir(nfsdir);
3442 data->continue_data = NULL;
3443 free_nfs_cb_data(data);
3444 return;
3445 }
3446 return;
3447 }
3448
3449 if (res->READDIRPLUS3res_u.resok.dir_attributes.attributes_follow)
3450 nfsdir->attr = res->READDIRPLUS3res_u.resok.dir_attributes.post_op_attr_u.attributes;
3451
3452 /* steal the dirhandle */
3453 data->continue_data = NULL;
3454 nfsdir->current = nfsdir->entries;
3455
3456 data->cb(0, nfs, nfsdir, data->private_data);
3457 free_nfs_cb_data(data);
3458 }
3459
3460 static int nfs_opendir_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
3461 {
3462 READDIRPLUS3args args;
3463 struct nfsdir *nfsdir = data->continue_data;;
3464 struct nfsdir *cached;
3465
3466 cached = nfs_dircache_find(nfs, &data->fh);
3467 if (cached) {
3468 if (attr && attr->mtime.seconds == cached->attr.mtime.seconds) {
3469 cached->current = cached->entries;
3470 data->cb(0, nfs, cached, data->private_data);
3471 free_nfs_cb_data(data);
3472 return 0;
3473 } else {
3474 /* cache must be stale */
3475 nfs_free_nfsdir(cached);
3476 }
3477 }
3478
3479 nfsdir->fh.data.data_len = data->fh.data.data_len;
3480 nfsdir->fh.data.data_val = malloc(nfsdir->fh.data.data_len);
3481 if (nfsdir->fh.data.data_val == NULL) {
3482 rpc_set_error(nfs->rpc, "OOM when allocating fh for nfsdir");
3483 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
3484 free_nfs_cb_data(data);
3485 return -1;
3486 }
3487 memcpy(nfsdir->fh.data.data_val, data->fh.data.data_val, data->fh.data.data_len);
3488
3489 args.dir = data->fh;
3490 args.cookie = 0;
3491 memset(&args.cookieverf, 0, sizeof(cookieverf3));
3492 args.dircount = 8192;
3493 args.maxcount = 8192;
3494 if (rpc_nfs3_readdirplus_async(nfs->rpc, nfs_opendir_cb, &args, data) != 0) {
3495 rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIRPLUS call for %s", data->path);
3496 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
3497 free_nfs_cb_data(data);
3498 return -1;
3499 }
3500 return 0;
3501 }
3502
3503 int nfs_opendir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
3504 {
3505 struct nfsdir *nfsdir;
3506
3507 nfsdir = malloc(sizeof(struct nfsdir));
3508 if (nfsdir == NULL) {
3509 rpc_set_error(nfs->rpc, "failed to allocate buffer for nfsdir");
3510 return -1;
3511 }
3512 memset(nfsdir, 0, sizeof(struct nfsdir));
3513
3514 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_opendir_continue_internal, nfsdir, free, 0) != 0) {
3515 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
3516 return -1;
3517 }
3518
3519 return 0;
3520 }
3521
3522
3523 struct nfsdirent *nfs_readdir(struct nfs_context *nfs _U_, struct nfsdir *nfsdir)
3524 {
3525 struct nfsdirent *nfsdirent = nfsdir->current;
3526
3527 if (nfsdir->current != NULL) {
3528 nfsdir->current = nfsdir->current->next;
3529 }
3530 return nfsdirent;
3531 }
3532
3533
3534 /*
3535 * closedir()
3536 */
3537 void nfs_closedir(struct nfs_context *nfs, struct nfsdir *nfsdir)
3538 {
3539 nfs_dircache_add(nfs, nfsdir);
3540 }
3541
3542
3543 /*
3544 * getcwd()
3545 */
3546 void nfs_getcwd(struct nfs_context *nfs, const char **cwd)
3547 {
3548 if (cwd) {
3549 *cwd = nfs->cwd;
3550 }
3551 }
3552
3553
3554 /*
3555 * Async lseek()
3556 */
3557 struct lseek_cb_data {
3558 struct nfs_context *nfs;
3559 struct nfsfh *nfsfh;
3560 int64_t offset;
3561 nfs_cb cb;
3562 void *private_data;
3563 };
3564
3565 static void nfs_lseek_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
3566 {
3567 GETATTR3res *res;
3568 struct lseek_cb_data *data = private_data;
3569 struct nfs_context *nfs = data->nfs;
3570 uint64_t size = 0;
3571
3572 assert(rpc->magic == RPC_CONTEXT_MAGIC);
3573
3574 if (status == RPC_STATUS_ERROR) {
3575 data->cb(-EFAULT, nfs, command_data, data->private_data);
3576 free(data);
3577 return;
3578 }
3579 if (status == RPC_STATUS_CANCEL) {
3580 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
3581 free(data);
3582 return;
3583 }
3584
3585 res = command_data;
3586 if (res->status != NFS3_OK) {
3587 rpc_set_error(nfs->rpc, "NFS: GETATTR failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
3588 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
3589 free(data);
3590 return;
3591 }
3592
3593 size = res->GETATTR3res_u.resok.obj_attributes.size;
3594
3595 if (data->offset < 0 &&
3596 (uint64_t)(-data->offset) > size) {
3597 data->cb(-EINVAL, nfs, &data->nfsfh->offset, data->private_data);
3598 } else {
3599 data->nfsfh->offset = data->offset + size;
3600 data->cb(0, nfs, &data->nfsfh->offset, data->private_data);
3601 }
3602
3603 free(data);
3604 }
3605
3606 int nfs_lseek_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int64_t offset, int whence, nfs_cb cb, void *private_data)
3607 {
3608 struct lseek_cb_data *data;
3609 struct GETATTR3args args;
3610
3611 if (whence == SEEK_SET) {
3612 if (offset < 0) {
3613 cb(-EINVAL, nfs, &nfsfh->offset, private_data);
3614 } else {
3615 nfsfh->offset = offset;
3616 cb(0, nfs, &nfsfh->offset, private_data);
3617 }
3618 return 0;
3619 }
3620 if (whence == SEEK_CUR) {
3621 if (offset < 0 &&
3622 nfsfh->offset < (uint64_t)(-offset)) {
3623 cb(-EINVAL, nfs, &nfsfh->offset, private_data);
3624 } else {
3625 nfsfh->offset += offset;
3626 cb(0, nfs, &nfsfh->offset, private_data);
3627 }
3628 return 0;
3629 }
3630
3631 data = malloc(sizeof(struct lseek_cb_data));
3632 if (data == NULL) {
3633 rpc_set_error(nfs->rpc, "Out Of Memory: Failed to malloc lseek cb data");
3634 return -1;
3635 }
3636
3637 data->nfs = nfs;
3638 data->nfsfh = nfsfh;
3639 data->offset = offset;
3640 data->cb = cb;
3641 data->private_data = private_data;
3642
3643 memset(&args, 0, sizeof(GETATTR3args));
3644 args.object = nfsfh->fh;
3645
3646 if (rpc_nfs3_getattr_async(nfs->rpc, nfs_lseek_1_cb, &args, data) != 0) {
3647 rpc_set_error(nfs->rpc, "RPC error: Failed to send LSEEK GETATTR call");
3648 free(data);
3649 return -1;
3650 }
3651 return 0;
3652 }
3653
3654
3655
3656
3657 /*
3658 * Async statvfs()
3659 */
3660 static void nfs_statvfs_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
3661 {
3662 FSSTAT3res *res;
3663 struct nfs_cb_data *data = private_data;
3664 struct nfs_context *nfs = data->nfs;
3665 struct statvfs svfs;
3666
3667 assert(rpc->magic == RPC_CONTEXT_MAGIC);
3668
3669 if (status == RPC_STATUS_ERROR) {
3670 data->cb(-EFAULT, nfs, command_data, data->private_data);
3671 free_nfs_cb_data(data);
3672 return;
3673 }
3674 if (status == RPC_STATUS_CANCEL) {
3675 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
3676 free_nfs_cb_data(data);
3677 return;
3678 }
3679
3680 res = command_data;
3681 if (res->status != NFS3_OK) {
3682 rpc_set_error(nfs->rpc, "NFS: FSSTAT of %s failed with %s(%d)", data->saved_path, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
3683 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
3684 free_nfs_cb_data(data);
3685 return;
3686 }
3687
3688 svfs.f_bsize = NFS_BLKSIZE;
3689 svfs.f_frsize = NFS_BLKSIZE;
3690 svfs.f_blocks = res->FSSTAT3res_u.resok.tbytes/NFS_BLKSIZE;
3691 svfs.f_bfree = res->FSSTAT3res_u.resok.fbytes/NFS_BLKSIZE;
3692 svfs.f_bavail = res->FSSTAT3res_u.resok.abytes/NFS_BLKSIZE;
3693 svfs.f_files = res->FSSTAT3res_u.resok.tfiles;
3694 svfs.f_ffree = res->FSSTAT3res_u.resok.ffiles;
3695 #if !defined(ANDROID)
3696 svfs.f_favail = res->FSSTAT3res_u.resok.afiles;
3697 svfs.f_fsid = 0;
3698 svfs.f_flag = 0;
3699 svfs.f_namemax = 256;
3700 #endif
3701
3702 data->cb(0, nfs, &svfs, data->private_data);
3703 free_nfs_cb_data(data);
3704 }
3705
3706 static int nfs_statvfs_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
3707 {
3708 FSSTAT3args args;
3709
3710 args.fsroot = data->fh;
3711 if (rpc_nfs3_fsstat_async(nfs->rpc, nfs_statvfs_1_cb, &args, data) != 0) {
3712 rpc_set_error(nfs->rpc, "RPC error: Failed to send FSSTAT call for %s", data->path);
3713 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
3714 free_nfs_cb_data(data);
3715 return -1;
3716 }
3717 return 0;
3718 }
3719
3720 int nfs_statvfs_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
3721 {
3722 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_statvfs_continue_internal, NULL, NULL, 0) != 0) {
3723 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
3724 return -1;
3725 }
3726
3727 return 0;
3728 }
3729
3730
3731
3732
3733 /*
3734 * Async readlink()
3735 */
3736 static void nfs_readlink_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
3737 {
3738 READLINK3res *res;
3739 struct nfs_cb_data *data = private_data;
3740 struct nfs_context *nfs = data->nfs;
3741
3742 assert(rpc->magic == RPC_CONTEXT_MAGIC);
3743
3744 if (status == RPC_STATUS_ERROR) {
3745 data->cb(-EFAULT, nfs, command_data, data->private_data);
3746 free_nfs_cb_data(data);
3747 return;
3748 }
3749 if (status == RPC_STATUS_CANCEL) {
3750 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
3751 free_nfs_cb_data(data);
3752 return;
3753 }
3754
3755 res = command_data;
3756 if (res->status != NFS3_OK) {
3757 rpc_set_error(nfs->rpc, "NFS: READLINK of %s failed with %s(%d)", data->saved_path, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
3758 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
3759 free_nfs_cb_data(data);
3760 return;
3761 }
3762
3763
3764 data->cb(0, nfs, res->READLINK3res_u.resok.data, data->private_data);
3765 free_nfs_cb_data(data);
3766 }
3767
3768 static int nfs_readlink_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
3769 {
3770 READLINK3args args;
3771
3772 args.symlink = data->fh;
3773
3774 if (rpc_nfs3_readlink_async(nfs->rpc, nfs_readlink_1_cb, &args, data) != 0) {
3775 rpc_set_error(nfs->rpc, "RPC error: Failed to send READLINK call for %s", data->path);
3776 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
3777 free_nfs_cb_data(data);
3778 return -1;
3779 }
3780 return 0;
3781 }
3782
3783 int nfs_readlink_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
3784 {
3785 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_readlink_continue_internal, NULL, NULL, 0) != 0) {
3786 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
3787 return -1;
3788 }
3789
3790 return 0;
3791 }
3792
3793
3794
3795
3796 /*
3797 * Async chmod()
3798 */
3799 static void nfs_chmod_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
3800 {
3801 struct nfs_cb_data *data = private_data;
3802 struct nfs_context *nfs = data->nfs;
3803 SETATTR3res *res;
3804
3805 assert(rpc->magic == RPC_CONTEXT_MAGIC);
3806
3807 if (status == RPC_STATUS_ERROR) {
3808 data->cb(-EFAULT, nfs, command_data, data->private_data);
3809 free_nfs_cb_data(data);
3810 return;
3811 }
3812 if (status == RPC_STATUS_CANCEL) {
3813 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
3814 free_nfs_cb_data(data);
3815 return;
3816 }
3817
3818 res = command_data;
3819 if (res->status != NFS3_OK) {
3820 rpc_set_error(nfs->rpc, "NFS: SETATTR failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
3821 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
3822 free_nfs_cb_data(data);
3823 return;
3824 }
3825
3826 data->cb(0, nfs, NULL, data->private_data);
3827 free_nfs_cb_data(data);
3828 }
3829
3830 static int nfs_chmod_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
3831 {
3832 SETATTR3args args;
3833
3834 memset(&args, 0, sizeof(SETATTR3args));
3835 args.object = data->fh;
3836 args.new_attributes.mode.set_it = 1;
3837 args.new_attributes.mode.set_mode3_u.mode = data->continue_int;
3838
3839 if (rpc_nfs3_setattr_async(nfs->rpc, nfs_chmod_cb, &args, data) != 0) {
3840 rpc_set_error(nfs->rpc, "RPC error: Failed to send SETATTR call for %s", data->path);
3841 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
3842 free_nfs_cb_data(data);
3843 return -1;
3844 }
3845 return 0;
3846 }
3847
3848
3849 int nfs_chmod_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data)
3850 {
3851 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_chmod_continue_internal, NULL, NULL, mode) != 0) {
3852 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
3853 return -1;
3854 }
3855
3856 return 0;
3857 }
3858
3859 /*
3860 * Async fchmod()
3861 */
3862 int nfs_fchmod_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int mode, nfs_cb cb, void *private_data)
3863 {
3864 struct nfs_cb_data *data;
3865
3866 data = malloc(sizeof(struct nfs_cb_data));
3867 if (data == NULL) {
3868 rpc_set_error(nfs->rpc, "out of memory. failed to allocate memory for nfs mount data");
3869 return -1;
3870 }
3871 memset(data, 0, sizeof(struct nfs_cb_data));
3872 data->nfs = nfs;
3873 data->cb = cb;
3874 data->private_data = private_data;
3875 data->continue_int = mode;
3876 data->fh.data.data_len = nfsfh->fh.data.data_len;
3877 data->fh.data.data_val = malloc(data->fh.data.data_len);
3878 if (data->fh.data.data_val == NULL) {
3879 rpc_set_error(nfs->rpc, "Out of memory: Failed to allocate fh");
3880 free_nfs_cb_data(data);
3881 return -1;
3882 }
3883 memcpy(data->fh.data.data_val, nfsfh->fh.data.data_val, data->fh.data.data_len);
3884
3885 if (nfs_chmod_continue_internal(nfs, NULL, data) != 0) {
3886 return -1;
3887 }
3888
3889 return 0;
3890 }
3891
3892
3893
3894 /*
3895 * Async chown()
3896 */
3897 static void nfs_chown_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
3898 {
3899 struct nfs_cb_data *data = private_data;
3900 struct nfs_context *nfs = data->nfs;
3901 SETATTR3res *res;
3902
3903 assert(rpc->magic == RPC_CONTEXT_MAGIC);
3904
3905 if (status == RPC_STATUS_ERROR) {
3906 data->cb(-EFAULT, nfs, command_data, data->private_data);
3907 free_nfs_cb_data(data);
3908 return;
3909 }
3910 if (status == RPC_STATUS_CANCEL) {
3911 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
3912 free_nfs_cb_data(data);
3913 return;
3914 }
3915
3916 res = command_data;
3917 if (res->status != NFS3_OK) {
3918 rpc_set_error(nfs->rpc, "NFS: SETATTR failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
3919 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
3920 free_nfs_cb_data(data);
3921 return;
3922 }
3923
3924 data->cb(0, nfs, NULL, data->private_data);
3925 free_nfs_cb_data(data);
3926 }
3927
3928 struct nfs_chown_data {
3929 uid_t uid;
3930 gid_t gid;
3931 };
3932
3933 static int nfs_chown_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
3934 {
3935 SETATTR3args args;
3936 struct nfs_chown_data *chown_data = data->continue_data;
3937
3938 memset(&args, 0, sizeof(SETATTR3args));
3939 args.object = data->fh;
3940 if (chown_data->uid != (uid_t)-1) {
3941 args.new_attributes.uid.set_it = 1;
3942 args.new_attributes.uid.set_uid3_u.uid = chown_data->uid;
3943 }
3944 if (chown_data->gid != (gid_t)-1) {
3945 args.new_attributes.gid.set_it = 1;
3946 args.new_attributes.gid.set_gid3_u.gid = chown_data->gid;
3947 }
3948
3949 if (rpc_nfs3_setattr_async(nfs->rpc, nfs_chown_cb, &args, data) != 0) {
3950 rpc_set_error(nfs->rpc, "RPC error: Failed to send SETATTR call for %s", data->path);
3951 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
3952 free_nfs_cb_data(data);
3953 return -1;
3954 }
3955 return 0;
3956 }
3957
3958
3959 int nfs_chown_async(struct nfs_context *nfs, const char *path, int uid, int gid, nfs_cb cb, void *private_data)
3960 {
3961 struct nfs_chown_data *chown_data;
3962
3963 chown_data = malloc(sizeof(struct nfs_chown_data));
3964 if (chown_data == NULL) {
3965 rpc_set_error(nfs->rpc, "Failed to allocate memory for chown data structure");
3966 return -1;
3967 }
3968
3969 chown_data->uid = uid;
3970 chown_data->gid = gid;
3971
3972 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_chown_continue_internal, chown_data, free, 0) != 0) {
3973 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
3974 return -1;
3975 }
3976
3977 return 0;
3978 }
3979
3980
3981 /*
3982 * Async fchown()
3983 */
3984 int nfs_fchown_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int uid, int gid, nfs_cb cb, void *private_data)
3985 {
3986 struct nfs_cb_data *data;
3987 struct nfs_chown_data *chown_data;
3988
3989 chown_data = malloc(sizeof(struct nfs_chown_data));
3990 if (chown_data == NULL) {
3991 rpc_set_error(nfs->rpc, "Failed to allocate memory for chown data structure");
3992 return -1;
3993 }
3994
3995 chown_data->uid = uid;
3996 chown_data->gid = gid;
3997
3998 data = malloc(sizeof(struct nfs_cb_data));
3999 if (data == NULL) {
4000 rpc_set_error(nfs->rpc, "out of memory. failed to allocate memory for fchown data");
4001 free(chown_data);
4002 return -1;
4003 }
4004 memset(data, 0, sizeof(struct nfs_cb_data));
4005 data->nfs = nfs;
4006 data->cb = cb;
4007 data->private_data = private_data;
4008 data->continue_data = chown_data;
4009 data->free_continue_data = free;
4010 data->fh.data.data_len = nfsfh->fh.data.data_len;
4011 data->fh.data.data_val = malloc(data->fh.data.data_len);
4012 if (data->fh.data.data_val == NULL) {
4013 rpc_set_error(nfs->rpc, "Out of memory: Failed to allocate fh");
4014 free_nfs_cb_data(data);
4015 return -1;
4016 }
4017 memcpy(data->fh.data.data_val, nfsfh->fh.data.data_val, data->fh.data.data_len);
4018
4019 if (nfs_chown_continue_internal(nfs, NULL, data) != 0) {
4020 return -1;
4021 }
4022
4023 return 0;
4024 }
4025
4026
4027
4028
4029
4030 /*
4031 * Async utimes()
4032 */
4033 static void nfs_utimes_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
4034 {
4035 struct nfs_cb_data *data = private_data;
4036 struct nfs_context *nfs = data->nfs;
4037 SETATTR3res *res;
4038
4039 assert(rpc->magic == RPC_CONTEXT_MAGIC);
4040
4041 if (status == RPC_STATUS_ERROR) {
4042 data->cb(-EFAULT, nfs, command_data, data->private_data);
4043 free_nfs_cb_data(data);
4044 return;
4045 }
4046 if (status == RPC_STATUS_CANCEL) {
4047 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
4048 free_nfs_cb_data(data);
4049 return;
4050 }
4051
4052 res = command_data;
4053 if (res->status != NFS3_OK) {
4054 rpc_set_error(nfs->rpc, "NFS: SETATTR failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
4055 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
4056 free_nfs_cb_data(data);
4057 return;
4058 }
4059
4060 data->cb(0, nfs, NULL, data->private_data);
4061 free_nfs_cb_data(data);
4062 }
4063
4064 static int nfs_utimes_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
4065 {
4066 SETATTR3args args;
4067 struct timeval *utimes_data = data->continue_data;
4068
4069 memset(&args, 0, sizeof(SETATTR3args));
4070 args.object = data->fh;
4071 if (utimes_data != NULL) {
4072 args.new_attributes.atime.set_it = SET_TO_CLIENT_TIME;
4073 args.new_attributes.atime.set_atime_u.atime.seconds = utimes_data[0].tv_sec;
4074 args.new_attributes.atime.set_atime_u.atime.nseconds = utimes_data[0].tv_usec * 1000;
4075 args.new_attributes.mtime.set_it = SET_TO_CLIENT_TIME;
4076 args.new_attributes.mtime.set_mtime_u.mtime.seconds = utimes_data[1].tv_sec;
4077 args.new_attributes.mtime.set_mtime_u.mtime.nseconds = utimes_data[1].tv_usec * 1000;
4078 } else {
4079 args.new_attributes.atime.set_it = SET_TO_SERVER_TIME;
4080 args.new_attributes.mtime.set_it = SET_TO_SERVER_TIME;
4081 }
4082
4083 if (rpc_nfs3_setattr_async(nfs->rpc, nfs_utimes_cb, &args, data) != 0) {
4084 rpc_set_error(nfs->rpc, "RPC error: Failed to send SETATTR call for %s", data->path);
4085 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
4086 free_nfs_cb_data(data);
4087 return -1;
4088 }
4089 return 0;
4090 }
4091
4092
4093 int nfs_utimes_async(struct nfs_context *nfs, const char *path, struct timeval *times, nfs_cb cb, void *private_data)
4094 {
4095 struct timeval *new_times = NULL;
4096
4097 if (times != NULL) {
4098 new_times = malloc(sizeof(struct timeval)*2);
4099 if (new_times == NULL) {
4100 rpc_set_error(nfs->rpc, "Failed to allocate memory for timeval structure");
4101 return -1;
4102 }
4103
4104 memcpy(new_times, times, sizeof(struct timeval)*2);
4105 }
4106
4107 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_utimes_continue_internal, new_times, free, 0) != 0) {
4108 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
4109 return -1;
4110 }
4111
4112 return 0;
4113 }
4114
4115 /*
4116 * Async utime()
4117 */
4118 int nfs_utime_async(struct nfs_context *nfs, const char *path, struct utimbuf *times, nfs_cb cb, void *private_data)
4119 {
4120 struct timeval *new_times = NULL;
4121
4122 if (times != NULL) {
4123 new_times = malloc(sizeof(struct timeval)*2);
4124 if (new_times == NULL) {
4125 rpc_set_error(nfs->rpc, "Failed to allocate memory for timeval structure");
4126 return -1;
4127 }
4128
4129 new_times[0].tv_sec = times->actime;
4130 new_times[0].tv_usec = 0;
4131 new_times[1].tv_sec = times->modtime;
4132 new_times[1].tv_usec = 0;
4133 }
4134
4135 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_utimes_continue_internal, new_times, free, 0) != 0) {
4136 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
4137 return -1;
4138 }
4139
4140 return 0;
4141 }
4142
4143
4144 /*
4145 * Async access()
4146 */
4147 static void nfs_access_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
4148 {
4149 ACCESS3res *res;
4150 struct nfs_cb_data *data = private_data;
4151 struct nfs_context *nfs = data->nfs;
4152 unsigned int nfsmode = 0;
4153
4154 assert(rpc->magic == RPC_CONTEXT_MAGIC);
4155
4156 if (status == RPC_STATUS_ERROR) {
4157 data->cb(-EFAULT, nfs, command_data, data->private_data);
4158 free_nfs_cb_data(data);
4159 return;
4160 }
4161 if (status == RPC_STATUS_CANCEL) {
4162 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
4163 free_nfs_cb_data(data);
4164 return;
4165 }
4166
4167 res = command_data;
4168 if (res->status != NFS3_OK) {
4169 rpc_set_error(nfs->rpc, "NFS: ACCESS of %s failed with %s(%d)", data->saved_path, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
4170 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
4171 free_nfs_cb_data(data);
4172 return;
4173 }
4174
4175 if (data->continue_int & R_OK) {
4176 nfsmode |= ACCESS3_READ;
4177 }
4178 if (data->continue_int & W_OK) {
4179 nfsmode |= ACCESS3_MODIFY;
4180 }
4181 if (data->continue_int & X_OK) {
4182 nfsmode |= ACCESS3_EXECUTE;
4183 }
4184
4185 if (res->ACCESS3res_u.resok.access != nfsmode) {
4186 rpc_set_error(nfs->rpc, "NFS: ACCESS denied. Required access %c%c%c. Allowed access %c%c%c",
4187 nfsmode&ACCESS3_READ?'r':'-',
4188 nfsmode&ACCESS3_MODIFY?'w':'-',
4189 nfsmode&ACCESS3_EXECUTE?'x':'-',
4190 res->ACCESS3res_u.resok.access&ACCESS3_READ?'r':'-',
4191 res->ACCESS3res_u.resok.access&ACCESS3_MODIFY?'w':'-',
4192 res->ACCESS3res_u.resok.access&ACCESS3_EXECUTE?'x':'-');
4193 data->cb(-EACCES, nfs, rpc_get_error(nfs->rpc), data->private_data);
4194 free_nfs_cb_data(data);
4195 return;
4196 }
4197
4198 data->cb(0, nfs, NULL, data->private_data);
4199 free_nfs_cb_data(data);
4200 }
4201
4202 static int nfs_access_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
4203 {
4204 int nfsmode = 0;
4205 ACCESS3args args;
4206
4207 if (data->continue_int & R_OK) {
4208 nfsmode |= ACCESS3_READ;
4209 }
4210 if (data->continue_int & W_OK) {
4211 nfsmode |= ACCESS3_MODIFY;
4212 }
4213 if (data->continue_int & X_OK) {
4214 nfsmode |= ACCESS3_EXECUTE;
4215 }
4216
4217 memset(&args, 0, sizeof(ACCESS3args));
4218 args.object = data->fh;
4219 args.access = nfsmode;
4220
4221 if (rpc_nfs3_access_async(nfs->rpc, nfs_access_cb, &args, data) != 0) {
4222 rpc_set_error(nfs->rpc, "RPC error: Failed to send OPEN ACCESS call for %s", data->path);
4223 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
4224 free_nfs_cb_data(data);
4225 return -1;
4226 }
4227 return 0;
4228 }
4229
4230 int nfs_access_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data)
4231 {
4232 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_access_continue_internal, NULL, NULL, mode) != 0) {
4233 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
4234 return -1;
4235 }
4236
4237 return 0;
4238 }
4239
4240
4241
4242 /*
4243 * Async symlink()
4244 */
4245 struct nfs_symlink_data {
4246 char *oldpath;
4247 char *newpathparent;
4248 char *newpathobject;
4249 };
4250
4251 static void free_nfs_symlink_data(void *mem)
4252 {
4253 struct nfs_symlink_data *data = mem;
4254
4255 if (data->oldpath != NULL) {
4256 free(data->oldpath);
4257 }
4258 if (data->newpathparent != NULL) {
4259 free(data->newpathparent);
4260 }
4261 if (data->newpathobject != NULL) {
4262 free(data->newpathobject);
4263 }
4264 free(data);
4265 }
4266
4267 static void nfs_symlink_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
4268 {
4269 SYMLINK3res *res;
4270 struct nfs_cb_data *data = private_data;
4271 struct nfs_context *nfs = data->nfs;
4272 struct nfs_symlink_data *symlink_data = data->continue_data;
4273
4274 assert(rpc->magic == RPC_CONTEXT_MAGIC);
4275
4276 if (status == RPC_STATUS_ERROR) {
4277 data->cb(-EFAULT, nfs, command_data, data->private_data);
4278 free_nfs_cb_data(data);
4279 return;
4280 }
4281 if (status == RPC_STATUS_CANCEL) {
4282 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
4283 free_nfs_cb_data(data);
4284 return;
4285 }
4286
4287 res = command_data;
4288 if (res->status != NFS3_OK) {
4289 rpc_set_error(nfs->rpc, "NFS: SYMLINK %s/%s -> %s failed with %s(%d)", symlink_data->newpathparent, symlink_data->newpathobject, symlink_data->oldpath, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
4290 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
4291 free_nfs_cb_data(data);
4292 return;
4293 }
4294
4295 data->cb(0, nfs, NULL, data->private_data);
4296 free_nfs_cb_data(data);
4297 }
4298
4299 static int nfs_symlink_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
4300 {
4301 struct nfs_symlink_data *symlink_data = data->continue_data;
4302 SYMLINK3args args;
4303
4304 memset(&args, 0, sizeof(SYMLINK3args));
4305 args.where.dir = data->fh;
4306 args.where.name = symlink_data->newpathobject;
4307 args.symlink.symlink_attributes.mode.set_it = 1;
4308 args.symlink.symlink_attributes.mode.set_mode3_u.mode = S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH;
4309 args.symlink.symlink_data = symlink_data->oldpath;
4310
4311 if (rpc_nfs3_symlink_async(nfs->rpc, nfs_symlink_cb, &args, data) != 0) {
4312 rpc_set_error(nfs->rpc, "RPC error: Failed to send SYMLINK call for %s", data->path);
4313 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
4314 free_nfs_cb_data(data);
4315 return -1;
4316 }
4317 return 0;
4318 }
4319
4320 int nfs_symlink_async(struct nfs_context *nfs, const char *oldpath, const char *newpath, nfs_cb cb, void *private_data)
4321 {
4322 char *ptr;
4323 struct nfs_symlink_data *symlink_data;
4324
4325 symlink_data = malloc(sizeof(struct nfs_symlink_data));
4326 if (symlink_data == NULL) {
4327 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for symlink data");
4328 return -1;
4329 }
4330 memset(symlink_data, 0, sizeof(struct nfs_symlink_data));
4331
4332 symlink_data->oldpath = strdup(oldpath);
4333 if (symlink_data->oldpath == NULL) {
4334 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for oldpath");
4335 free_nfs_symlink_data(symlink_data);
4336 return -1;
4337 }
4338
4339 symlink_data->newpathparent = strdup(newpath);
4340 if (symlink_data->newpathparent == NULL) {
4341 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for new path");
4342 free_nfs_symlink_data(symlink_data);
4343 return -1;
4344 }
4345
4346 ptr = strrchr(symlink_data->newpathparent, '/');
4347 if (ptr == NULL) {
4348 rpc_set_error(nfs->rpc, "Invalid path %s", oldpath);
4349 free_nfs_symlink_data(symlink_data);
4350 return -1;
4351 }
4352 *ptr = 0;
4353 ptr++;
4354
4355 symlink_data->newpathobject = strdup(ptr);
4356 if (symlink_data->newpathobject == NULL) {
4357 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for new path");
4358 free_nfs_symlink_data(symlink_data);
4359 return -1;
4360 }
4361
4362 if (nfs_lookuppath_async(nfs, symlink_data->newpathparent, cb, private_data, nfs_symlink_continue_internal, symlink_data, free_nfs_symlink_data, 0) != 0) {
4363 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
4364 return -1;
4365 }
4366
4367 return 0;
4368 }
4369
4370
4371
4372 /*
4373 * Async rename()
4374 */
4375 struct nfs_rename_data {
4376 char *oldpath;
4377 char *oldobject;
4378 struct nfs_fh3 olddir;
4379 char *newpath;
4380 char *newobject;
4381 struct nfs_fh3 newdir;
4382 };
4383
4384 static void free_nfs_rename_data(void *mem)
4385 {
4386 struct nfs_rename_data *data = mem;
4387
4388 if (data->oldpath != NULL) {
4389 free(data->oldpath);
4390 }
4391 if (data->olddir.data.data_val != NULL) {
4392 free(data->olddir.data.data_val);
4393 }
4394 if (data->newpath != NULL) {
4395 free(data->newpath);
4396 }
4397 if (data->newdir.data.data_val != NULL) {
4398 free(data->newdir.data.data_val);
4399 }
4400 free(data);
4401 }
4402
4403 static void nfs_rename_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
4404 {
4405 RENAME3res *res;
4406 struct nfs_cb_data *data = private_data;
4407 struct nfs_context *nfs = data->nfs;
4408 struct nfs_rename_data *rename_data = data->continue_data;
4409
4410 assert(rpc->magic == RPC_CONTEXT_MAGIC);
4411
4412 if (status == RPC_STATUS_ERROR) {
4413 data->cb(-EFAULT, nfs, command_data, data->private_data);
4414 free_nfs_cb_data(data);
4415 return;
4416 }
4417 if (status == RPC_STATUS_CANCEL) {
4418 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
4419 free_nfs_cb_data(data);
4420 return;
4421 }
4422
4423 res = command_data;
4424 if (res->status != NFS3_OK) {
4425 rpc_set_error(nfs->rpc, "NFS: RENAME %s/%s -> %s/%s failed with %s(%d)", rename_data->oldpath, rename_data->oldobject, rename_data->newpath, rename_data->newobject, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
4426 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
4427 free_nfs_cb_data(data);
4428 return;
4429 }
4430
4431 data->cb(0, nfs, NULL, data->private_data);
4432 free_nfs_cb_data(data);
4433 }
4434
4435 static int nfs_rename_continue_2_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
4436 {
4437 struct nfs_rename_data *rename_data = data->continue_data;
4438 RENAME3args args;
4439
4440 /* steal the filehandle */
4441 rename_data->newdir = data->fh;
4442 data->fh.data.data_val = NULL;
4443
4444 args.from.dir = rename_data->olddir;
4445 args.from.name = rename_data->oldobject;
4446 args.to.dir = rename_data->newdir;
4447 args.to.name = rename_data->newobject;
4448 if (rpc_nfs3_rename_async(nfs->rpc, nfs_rename_cb, &args, data) != 0) {
4449 rpc_set_error(nfs->rpc, "RPC error: Failed to send RENAME call for %s", data->path);
4450 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
4451 free_nfs_cb_data(data);
4452 return -1;
4453 }
4454 return 0;
4455 }
4456
4457
4458 static int nfs_rename_continue_1_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
4459 {
4460 struct nfs_rename_data *rename_data = data->continue_data;
4461 char* newpath = strdup(rename_data->newpath);
4462 if (!newpath) {
4463 rpc_set_error(nfs->rpc, "Out of memory. Could not allocate memory to store target path for rename");
4464 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
4465 free_nfs_cb_data(data);
4466 return -1;
4467 }
4468
4469 /* steal the filehandle */
4470 rename_data->olddir = data->fh;
4471 data->fh.data.data_val = NULL;
4472
4473 if (nfs_lookuppath_async(nfs, rename_data->newpath, data->cb, data->private_data, nfs_rename_continue_2_internal, rename_data, free_nfs_rename_data, 0) != 0) {
4474 rpc_set_error(nfs->rpc, "RPC error: Failed to send LOOKUP call for %s", newpath);
4475 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
4476 free_nfs_cb_data(data);
4477 free(newpath);
4478 return -1;
4479 }
4480 data->continue_data = NULL;
4481 free_nfs_cb_data(data);
4482 free(newpath);
4483
4484 return 0;
4485 }
4486
4487
4488 int nfs_rename_async(struct nfs_context *nfs, const char *oldpath, const char *newpath, nfs_cb cb, void *private_data)
4489 {
4490 char *ptr;
4491 struct nfs_rename_data *rename_data;
4492
4493 rename_data = malloc(sizeof(struct nfs_rename_data));
4494 if (rename_data == NULL) {
4495 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for rename data");
4496 return -1;
4497 }
4498 memset(rename_data, 0, sizeof(struct nfs_rename_data));
4499
4500 rename_data->oldpath = strdup(oldpath);
4501 if (rename_data->oldpath == NULL) {
4502 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for oldpath");
4503 free_nfs_rename_data(rename_data);
4504 return -1;
4505 }
4506 ptr = strrchr(rename_data->oldpath, '/');
4507 if (ptr == NULL) {
4508 rpc_set_error(nfs->rpc, "Invalid path %s", oldpath);
4509 free_nfs_rename_data(rename_data);
4510 return -1;
4511 }
4512 *ptr = 0;
4513 ptr++;
4514 rename_data->oldobject = ptr;
4515
4516
4517 rename_data->newpath = strdup(newpath);
4518 if (rename_data->newpath == NULL) {
4519 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for newpath");
4520 free_nfs_rename_data(rename_data);
4521 return -1;
4522 }
4523 ptr = strrchr(rename_data->newpath, '/');
4524 if (ptr == NULL) {
4525 rpc_set_error(nfs->rpc, "Invalid path %s", newpath);
4526 free_nfs_rename_data(rename_data);
4527 return -1;
4528 }
4529 *ptr = 0;
4530 ptr++;
4531 rename_data->newobject = ptr;
4532
4533
4534 if (nfs_lookuppath_async(nfs, rename_data->oldpath, cb, private_data, nfs_rename_continue_1_internal, rename_data, free_nfs_rename_data, 0) != 0) {
4535 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
4536 return -1;
4537 }
4538
4539 return 0;
4540 }
4541
4542
4543 /*
4544 * Async link()
4545 */
4546 struct nfs_link_data {
4547 char *oldpath;
4548 struct nfs_fh3 oldfh;
4549 char *newpath;
4550 char *newobject;
4551 struct nfs_fh3 newdir;
4552 };
4553
4554 static void free_nfs_link_data(void *mem)
4555 {
4556 struct nfs_link_data *data = mem;
4557
4558 if (data->oldpath != NULL) {
4559 free(data->oldpath);
4560 }
4561 if (data->oldfh.data.data_val != NULL) {
4562 free(data->oldfh.data.data_val);
4563 }
4564 if (data->newpath != NULL) {
4565 free(data->newpath);
4566 }
4567 if (data->newdir.data.data_val != NULL) {
4568 free(data->newdir.data.data_val);
4569 }
4570 free(data);
4571 }
4572
4573 static void nfs_link_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
4574 {
4575 LINK3res *res;
4576 struct nfs_cb_data *data = private_data;
4577 struct nfs_context *nfs = data->nfs;
4578 struct nfs_link_data *link_data = data->continue_data;
4579
4580 assert(rpc->magic == RPC_CONTEXT_MAGIC);
4581
4582 if (status == RPC_STATUS_ERROR) {
4583 data->cb(-EFAULT, nfs, command_data, data->private_data);
4584 free_nfs_cb_data(data);
4585 return;
4586 }
4587 if (status == RPC_STATUS_CANCEL) {
4588 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
4589 free_nfs_cb_data(data);
4590 return;
4591 }
4592
4593 res = command_data;
4594 if (res->status != NFS3_OK) {
4595 rpc_set_error(nfs->rpc, "NFS: LINK %s -> %s/%s failed with %s(%d)", link_data->oldpath, link_data->newpath, link_data->newobject, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
4596 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
4597 free_nfs_cb_data(data);
4598 return;
4599 }
4600
4601 data->cb(0, nfs, NULL, data->private_data);
4602 free_nfs_cb_data(data);
4603 }
4604
4605 static int nfs_link_continue_2_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
4606 {
4607 struct nfs_link_data *link_data = data->continue_data;
4608 LINK3args args;
4609
4610 /* steal the filehandle */
4611 link_data->newdir = data->fh;
4612 data->fh.data.data_val = NULL;
4613
4614 memset(&args, 0, sizeof(LINK3args));
4615 args.file = link_data->oldfh;
4616 args.link.dir = link_data->newdir;
4617 args.link.name = link_data->newobject;
4618 if (rpc_nfs3_link_async(nfs->rpc, nfs_link_cb, &args, data) != 0) {
4619 rpc_set_error(nfs->rpc, "RPC error: Failed to send LINK call for %s", data->path);
4620 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
4621 free_nfs_cb_data(data);
4622 return -1;
4623 }
4624 return 0;
4625 }
4626
4627
4628 static int nfs_link_continue_1_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
4629 {
4630 struct nfs_link_data *link_data = data->continue_data;
4631
4632 /* steal the filehandle */
4633 link_data->oldfh = data->fh;
4634 data->fh.data.data_val = NULL;
4635
4636 if (nfs_lookuppath_async(nfs, link_data->newpath, data->cb, data->private_data, nfs_link_continue_2_internal, link_data, free_nfs_link_data, 0) != 0) {
4637 rpc_set_error(nfs->rpc, "RPC error: Failed to send LOOKUP call for %s", link_data->newpath);
4638 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
4639 free_nfs_cb_data(data);
4640 return -1;
4641 }
4642 data->continue_data = NULL;
4643 free_nfs_cb_data(data);
4644
4645 return 0;
4646 }
4647
4648
4649 int nfs_link_async(struct nfs_context *nfs, const char *oldpath, const char *newpath, nfs_cb cb, void *private_data)
4650 {
4651 char *ptr;
4652 struct nfs_link_data *link_data;
4653
4654 link_data = malloc(sizeof(struct nfs_link_data));
4655 if (link_data == NULL) {
4656 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for link data");
4657 return -1;
4658 }
4659 memset(link_data, 0, sizeof(struct nfs_link_data));
4660
4661 link_data->oldpath = strdup(oldpath);
4662 if (link_data->oldpath == NULL) {
4663 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for oldpath");
4664 free_nfs_link_data(link_data);
4665 return -1;
4666 }
4667
4668 link_data->newpath = strdup(newpath);
4669 if (link_data->newpath == NULL) {
4670 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for newpath");
4671 free_nfs_link_data(link_data);
4672 return -1;
4673 }
4674 ptr = strrchr(link_data->newpath, '/');
4675 if (ptr == NULL) {
4676 rpc_set_error(nfs->rpc, "Invalid path %s", newpath);
4677 free_nfs_link_data(link_data);
4678 return -1;
4679 }
4680 *ptr = 0;
4681 ptr++;
4682 link_data->newobject = ptr;
4683
4684
4685 if (nfs_lookuppath_async(nfs, link_data->oldpath, cb, private_data, nfs_link_continue_1_internal, link_data, free_nfs_link_data, 0) != 0) {
4686 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
4687 return -1;
4688 }
4689
4690 return 0;
4691 }
4692
4693
4694 //qqq replace later with lseek()
4695 uint64_t nfs_get_current_offset(struct nfsfh *nfsfh)
4696 {
4697 return nfsfh->offset;
4698 }
4699
4700
4701
4702 /*
4703 * Get the maximum supported READ3 size by the server
4704 */
4705 uint64_t nfs_get_readmax(struct nfs_context *nfs)
4706 {
4707 return nfs->readmax;
4708 }
4709
4710 /*
4711 * Get the maximum supported WRITE3 size by the server
4712 */
4713 uint64_t nfs_get_writemax(struct nfs_context *nfs)
4714 {
4715 return nfs->writemax;
4716 }
4717
4718 void nfs_set_tcp_syncnt(struct nfs_context *nfs, int v) {
4719 rpc_set_tcp_syncnt(nfs->rpc, v);
4720 }
4721
4722 void nfs_set_uid(struct nfs_context *nfs, int uid) {
4723 rpc_set_uid(nfs->rpc, uid);
4724 }
4725
4726 void nfs_set_gid(struct nfs_context *nfs, int gid) {
4727 rpc_set_gid(nfs->rpc, gid);
4728 }
4729
4730 void nfs_set_readahead(struct nfs_context *nfs, uint32_t v) {
4731 rpc_set_readahead(nfs->rpc, v);
4732 }
4733
4734 void nfs_set_error(struct nfs_context *nfs, char *error_string, ...)
4735 {
4736 va_list ap;
4737 char *str = NULL;
4738
4739 va_start(ap, error_string);
4740 str = malloc(1024);
4741 vsnprintf(str, 1024, error_string, ap);
4742 if (nfs->rpc->error_string != NULL) {
4743 free(nfs->rpc->error_string);
4744 }
4745 nfs->rpc->error_string = str;
4746 va_end(ap);
4747 }
4748
4749
4750
4751 struct mount_cb_data {
4752 rpc_cb cb;
4753 void *private_data;
4754 char *server;
4755 };
4756
4757 static void free_mount_cb_data(struct mount_cb_data *data)
4758 {
4759 if (data->server != NULL) {
4760 free(data->server);
4761 data->server = NULL;
4762 }
4763
4764 free(data);
4765 }
4766
4767 static void mount_export_5_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
4768 {
4769 struct mount_cb_data *data = private_data;
4770
4771 assert(rpc->magic == RPC_CONTEXT_MAGIC);
4772
4773 if (status == RPC_STATUS_ERROR) {
4774 data->cb(rpc, -EFAULT, command_data, data->private_data);
4775 free_mount_cb_data(data);
4776 return;
4777 }
4778 if (status == RPC_STATUS_CANCEL) {
4779 data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
4780 free_mount_cb_data(data);
4781 return;
4782 }
4783
4784 data->cb(rpc, 0, command_data, data->private_data);
4785 if (rpc_disconnect(rpc, "normal disconnect") != 0) {
4786 rpc_set_error(rpc, "Failed to disconnect\n");
4787 }
4788 free_mount_cb_data(data);
4789 }
4790
4791 static void mount_export_4_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
4792 {
4793 struct mount_cb_data *data = private_data;
4794
4795 assert(rpc->magic == RPC_CONTEXT_MAGIC);
4796
4797 /* Dont want any more callbacks even if the socket is closed */
4798 rpc->connect_cb = NULL;
4799
4800 if (status == RPC_STATUS_ERROR) {
4801 data->cb(rpc, -EFAULT, command_data, data->private_data);
4802 free_mount_cb_data(data);
4803 return;
4804 }
4805 if (status == RPC_STATUS_CANCEL) {
4806 data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
4807 free_mount_cb_data(data);
4808 return;
4809 }
4810
4811 if (rpc_mount3_export_async(rpc, mount_export_5_cb, data) != 0) {
4812 data->cb(rpc, -ENOMEM, command_data, data->private_data);
4813 free_mount_cb_data(data);
4814 return;
4815 }
4816 }
4817
4818 int mount_getexports_async(struct rpc_context *rpc, const char *server, rpc_cb cb, void *private_data)
4819 {
4820 struct mount_cb_data *data;
4821
4822 assert(rpc->magic == RPC_CONTEXT_MAGIC);
4823
4824 data = malloc(sizeof(struct mount_cb_data));
4825 if (data == NULL) {
4826 return -1;
4827 }
4828 memset(data, 0, sizeof(struct mount_cb_data));
4829 data->cb = cb;
4830 data->private_data = private_data;
4831 data->server = strdup(server);
4832 if (data->server == NULL) {
4833 free_mount_cb_data(data);
4834 return -1;
4835 }
4836 if (rpc_connect_program_async(rpc, data->server, MOUNT_PROGRAM, MOUNT_V3, mount_export_4_cb, data) != 0) {
4837 rpc_set_error(rpc, "Failed to start connection");
4838 free_mount_cb_data(data);
4839 return -1;
4840 }
4841
4842 return 0;
4843 }
4844
4845 struct rpc_context *nfs_get_rpc_context(struct nfs_context *nfs)
4846 {
4847 assert(nfs->rpc->magic == RPC_CONTEXT_MAGIC);
4848 return nfs->rpc;
4849 }
4850
4851 const char *nfs_get_server(struct nfs_context *nfs) {
4852 return nfs->server;
4853 }
4854
4855 const char *nfs_get_export(struct nfs_context *nfs) {
4856 return nfs->export;
4857 }
4858
4859 const struct nfs_fh3 *nfs_get_rootfh(struct nfs_context *nfs) {
4860 return &nfs->rootfh;
4861 }
4862
4863 struct nfs_fh3 *nfs_get_fh(struct nfsfh *nfsfh) {
4864 return &nfsfh->fh;
4865 }