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