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