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