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