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