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