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