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