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