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