Add support for chdir and getcwd
[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
RS
1101 if (path[0] == '\0') {
1102 rpc_set_error(nfs->rpc, "Path is empty");
84004dbf
RS
1103 return -1;
1104 }
1105
1106 data = malloc(sizeof(struct nfs_cb_data));
1107 if (data == NULL) {
f893b680
RS
1108 rpc_set_error(nfs->rpc, "out of memory: failed to allocate "
1109 "nfs_cb_data structure");
cbbf9d3e 1110 return -1;
84004dbf 1111 }
ea98629a 1112 memset(data, 0, sizeof(struct nfs_cb_data));
84004dbf
RS
1113 data->nfs = nfs;
1114 data->cb = cb;
1115 data->continue_cb = continue_cb;
1116 data->continue_data = continue_data;
1117 data->free_continue_data = free_continue_data;
1118 data->continue_int = continue_int;
1119 data->private_data = private_data;
f893b680
RS
1120 if (path[0] == '/') {
1121 data->saved_path = strdup(path);
1122 } else {
1123 data->saved_path = malloc(strlen(path) + strlen(nfs->cwd) + 2);
1124 if (data->saved_path == NULL) {
1125 rpc_set_error(nfs->rpc, "out of memory: failed to "
1126 "malloc path string");
1127 free_nfs_cb_data(data);
1128 return -1;
1129 }
1130 sprintf(data->saved_path, "%s/%s", nfs->cwd, path);
1131 }
1132
84004dbf
RS
1133 if (data->saved_path == NULL) {
1134 rpc_set_error(nfs->rpc, "out of memory: failed to copy path string");
84004dbf 1135 free_nfs_cb_data(data);
cbbf9d3e 1136 return -1;
84004dbf 1137 }
f893b680
RS
1138 if (nfs_normalize_path(nfs, data->saved_path) != 0) {
1139 free_nfs_cb_data(data);
1140 return -1;
1141 }
1142
84004dbf
RS
1143 data->path = data->saved_path;
1144
1145 if (nfs_lookup_path_async_internal(nfs, data, &nfs->rootfh) != 0) {
84004dbf
RS
1146 /* return 0 here since the callback will be invoked if there is a failure */
1147 return 0;
1148 }
1149 return 0;
1150}
1151
1152
1153
1154
1155
1156/*
1157 * Async stat()
1158 */
f3a75078 1159static void nfs_stat_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
84004dbf
RS
1160{
1161 GETATTR3res *res;
1162 struct nfs_cb_data *data = private_data;
1163 struct nfs_context *nfs = data->nfs;
be184101
M
1164#ifdef WIN32
1165 struct __stat64 st;
1166#else
84004dbf 1167 struct stat st;
be184101 1168#endif
84004dbf 1169
f3a75078
RS
1170 assert(rpc->magic == RPC_CONTEXT_MAGIC);
1171
84004dbf
RS
1172 if (status == RPC_STATUS_ERROR) {
1173 data->cb(-EFAULT, nfs, command_data, data->private_data);
1174 free_nfs_cb_data(data);
1175 return;
1176 }
1177 if (status == RPC_STATUS_CANCEL) {
1178 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1179 free_nfs_cb_data(data);
1180 return;
1181 }
1182
1183 res = command_data;
1184 if (res->status != NFS3_OK) {
1185 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));
1186 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
1187 free_nfs_cb_data(data);
1188 return;
1189 }
1190
1191 st.st_dev = -1;
1192 st.st_ino = res->GETATTR3res_u.resok.obj_attributes.fileid;
1193 st.st_mode = res->GETATTR3res_u.resok.obj_attributes.mode;
e8cab72a
RS
1194 if (res->GETATTR3res_u.resok.obj_attributes.type == NF3DIR) {
1195 st.st_mode |= S_IFDIR ;
1196 }
d7ec001f
RS
1197 if (res->GETATTR3res_u.resok.obj_attributes.type == NF3REG) {
1198 st.st_mode |= S_IFREG ;
1199 }
84004dbf
RS
1200 st.st_nlink = res->GETATTR3res_u.resok.obj_attributes.nlink;
1201 st.st_uid = res->GETATTR3res_u.resok.obj_attributes.uid;
1202 st.st_gid = res->GETATTR3res_u.resok.obj_attributes.gid;
1203 st.st_rdev = 0;
1204 st.st_size = res->GETATTR3res_u.resok.obj_attributes.size;
a8a1b858 1205#ifndef WIN32
84004dbf
RS
1206 st.st_blksize = 4096;
1207 st.st_blocks = res->GETATTR3res_u.resok.obj_attributes.size / 4096;
a8a1b858 1208#endif//WIN32
84004dbf
RS
1209 st.st_atime = res->GETATTR3res_u.resok.obj_attributes.atime.seconds;
1210 st.st_mtime = res->GETATTR3res_u.resok.obj_attributes.mtime.seconds;
1211 st.st_ctime = res->GETATTR3res_u.resok.obj_attributes.ctime.seconds;
1212
1213 data->cb(0, nfs, &st, data->private_data);
1214 free_nfs_cb_data(data);
1215}
1216
1217static int nfs_stat_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
1218{
463d59bf
RS
1219 struct GETATTR3args args;
1220
1221 memset(&args, 0, sizeof(GETATTR3args));
2452c57f 1222 args.object = data->fh;
463d59bf
RS
1223
1224 if (rpc_nfs3_getattr_async(nfs->rpc, nfs_stat_1_cb, &args, data) != 0) {
84004dbf
RS
1225 rpc_set_error(nfs->rpc, "RPC error: Failed to send STAT GETATTR call for %s", data->path);
1226 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1227 free_nfs_cb_data(data);
1228 return -1;
1229 }
1230 return 0;
1231}
1232
1233int nfs_stat_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
1234{
1235 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_stat_continue_internal, NULL, NULL, 0) != 0) {
cbbf9d3e 1236 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
84004dbf
RS
1237 return -1;
1238 }
1239
1240 return 0;
1241}
1242
1243
1244
84004dbf
RS
1245/*
1246 * Async open()
1247 */
f3a75078 1248static void nfs_open_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
84004dbf
RS
1249{
1250 ACCESS3res *res;
1251 struct nfs_cb_data *data = private_data;
1252 struct nfs_context *nfs = data->nfs;
1253 struct nfsfh *nfsfh;
1254 unsigned int nfsmode = 0;
1255
f3a75078
RS
1256 assert(rpc->magic == RPC_CONTEXT_MAGIC);
1257
84004dbf
RS
1258 if (status == RPC_STATUS_ERROR) {
1259 data->cb(-EFAULT, nfs, command_data, data->private_data);
1260 free_nfs_cb_data(data);
1261 return;
1262 }
1263 if (status == RPC_STATUS_CANCEL) {
1264 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1265 free_nfs_cb_data(data);
1266 return;
1267 }
1268
1269 res = command_data;
1270 if (res->status != NFS3_OK) {
1271 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));
1272 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
1273 free_nfs_cb_data(data);
1274 return;
1275 }
1276
1277 if (data->continue_int & O_WRONLY) {
1278 nfsmode |= ACCESS3_MODIFY;
1279 }
1280 if (data->continue_int & O_RDWR) {
1281 nfsmode |= ACCESS3_READ|ACCESS3_MODIFY;
1282 }
1283 if (!(data->continue_int & (O_WRONLY|O_RDWR))) {
1284 nfsmode |= ACCESS3_READ;
1285 }
1286
1287
1288 if (res->ACCESS3res_u.resok.access != nfsmode) {
1289 rpc_set_error(nfs->rpc, "NFS: ACCESS denied. Required access %c%c%c. Allowed access %c%c%c",
1290 nfsmode&ACCESS3_READ?'r':'-',
1291 nfsmode&ACCESS3_MODIFY?'w':'-',
1292 nfsmode&ACCESS3_EXECUTE?'x':'-',
1293 res->ACCESS3res_u.resok.access&ACCESS3_READ?'r':'-',
1294 res->ACCESS3res_u.resok.access&ACCESS3_MODIFY?'w':'-',
1295 res->ACCESS3res_u.resok.access&ACCESS3_EXECUTE?'x':'-');
1296 data->cb(-EACCES, nfs, rpc_get_error(nfs->rpc), data->private_data);
1297 free_nfs_cb_data(data);
1298 return;
1299 }
1300
1301 nfsfh = malloc(sizeof(struct nfsfh));
1302 if (nfsfh == NULL) {
1303 rpc_set_error(nfs->rpc, "NFS: Failed to allocate nfsfh structure");
1304 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1305 free_nfs_cb_data(data);
1306 return;
1307 }
ea98629a 1308 memset(nfsfh, 0, sizeof(struct nfsfh));
84004dbf
RS
1309
1310 if (data->continue_int & O_SYNC) {
1311 nfsfh->is_sync = 1;
1312 }
1313
1314 /* steal the filehandle */
2452c57f 1315 nfsfh->fh = data->fh;
84004dbf
RS
1316 data->fh.data.data_val = NULL;
1317
1318 data->cb(0, nfs, nfsfh, data->private_data);
1319 free_nfs_cb_data(data);
1320}
1321
1322static int nfs_open_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
1323{
1324 int nfsmode = 0;
463d59bf 1325 ACCESS3args args;
84004dbf
RS
1326
1327 if (data->continue_int & O_WRONLY) {
1328 nfsmode |= ACCESS3_MODIFY;
1329 }
1330 if (data->continue_int & O_RDWR) {
1331 nfsmode |= ACCESS3_READ|ACCESS3_MODIFY;
1332 }
1333 if (!(data->continue_int & (O_WRONLY|O_RDWR))) {
1334 nfsmode |= ACCESS3_READ;
1335 }
1336
463d59bf 1337 memset(&args, 0, sizeof(ACCESS3args));
2452c57f 1338 args.object = data->fh;
463d59bf
RS
1339 args.access = nfsmode;
1340
1341 if (rpc_nfs3_access_async(nfs->rpc, nfs_open_cb, &args, data) != 0) {
84004dbf
RS
1342 rpc_set_error(nfs->rpc, "RPC error: Failed to send OPEN ACCESS call for %s", data->path);
1343 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1344 free_nfs_cb_data(data);
1345 return -1;
1346 }
1347 return 0;
1348}
1349
1350int nfs_open_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data)
1351{
1352 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_open_continue_internal, NULL, NULL, mode) != 0) {
cbbf9d3e
RS
1353 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
1354 return -1;
84004dbf
RS
1355 }
1356
1357 return 0;
1358}
1359
1360
f893b680
RS
1361/*
1362 * Async chdir()
1363 */
1364static int nfs_chdir_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
1365{
1366 /* steal saved_path */
1367 free(nfs->cwd);
1368 nfs->cwd = data->saved_path;
1369 data->saved_path = NULL;
84004dbf 1370
f893b680
RS
1371 data->cb(0, nfs, NULL, data->private_data);
1372 free_nfs_cb_data(data);
1373
1374 return 0;
1375}
1376
1377int nfs_chdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
1378{
1379 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_chdir_continue_internal, NULL, NULL, 0) != 0) {
1380 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
1381 return -1;
1382 }
1383
1384 return 0;
1385}
84004dbf
RS
1386
1387
1388/*
1389 * Async pread()
1390 */
f3a75078 1391static void nfs_pread_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
84004dbf
RS
1392{
1393 struct nfs_cb_data *data = private_data;
1394 struct nfs_context *nfs = data->nfs;
1395 READ3res *res;
1396
f3a75078
RS
1397 assert(rpc->magic == RPC_CONTEXT_MAGIC);
1398
84004dbf
RS
1399 if (status == RPC_STATUS_ERROR) {
1400 data->cb(-EFAULT, nfs, command_data, data->private_data);
1401 free_nfs_cb_data(data);
1402 return;
1403 }
1404 if (status == RPC_STATUS_CANCEL) {
1405 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1406 free_nfs_cb_data(data);
1407 return;
1408 }
1409
1410 res = command_data;
1411 if (res->status != NFS3_OK) {
1412 rpc_set_error(nfs->rpc, "NFS: Read failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
1413 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
1414 free_nfs_cb_data(data);
1415 return;
1416 }
1417
1418 data->nfsfh->offset += res->READ3res_u.resok.count;
1419 data->cb(res->READ3res_u.resok.count, nfs, res->READ3res_u.resok.data.data_val, data->private_data);
1420 free_nfs_cb_data(data);
1421}
1422
f3a75078 1423static void nfs_pread_mcb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
921f877b
RS
1424{
1425 struct nfs_mcb_data *mdata = private_data;
1426 struct nfs_cb_data *data = mdata->data;
1427 struct nfs_context *nfs = data->nfs;
1428 READ3res *res;
1429
f3a75078
RS
1430 assert(rpc->magic == RPC_CONTEXT_MAGIC);
1431
921f877b
RS
1432 data->num_calls--;
1433
1434 if (status == RPC_STATUS_ERROR) {
1435 /* flag the failure but do not invoke callback until we have received all responses */
1436 data->error = 1;
1437 }
1438 if (status == RPC_STATUS_CANCEL) {
1439 /* flag the cancellation but do not invoke callback until we have received all responses */
1440 data->cancel = 1;
1441 }
1442
1443 /* reassemble the data into the buffer */
1444 if (status == RPC_STATUS_SUCCESS) {
1445 res = command_data;
1446 if (res->status != NFS3_OK) {
1447 rpc_set_error(nfs->rpc, "NFS: Read failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
1448 data->error = 1;
e4a5ba42
RS
1449 } else {
1450 if (res->READ3res_u.resok.count > 0) {
1451 memcpy(&data->buffer[mdata->offset - data->start_offset], res->READ3res_u.resok.data.data_val, res->READ3res_u.resok.count);
1452 if ((unsigned)data->max_offset < mdata->offset + res->READ3res_u.resok.count) {
1453 data->max_offset = mdata->offset + res->READ3res_u.resok.count;
1454 }
921f877b
RS
1455 }
1456 }
1457 }
1458
1459 if (data->num_calls > 0) {
1460 /* still waiting for more replies */
1461 free(mdata);
1462 return;
1463 }
1464
921f877b
RS
1465 if (data->error != 0) {
1466 data->cb(-EFAULT, nfs, command_data, data->private_data);
1467 free_nfs_cb_data(data);
1468 free(mdata);
1469 return;
1470 }
1471 if (data->cancel != 0) {
1472 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1473 free_nfs_cb_data(data);
1474 free(mdata);
1475 return;
1476 }
1477
1478 data->nfsfh->offset = data->max_offset;
7ed9d87a
RS
1479 data->cb(data->max_offset - data->start_offset, nfs, data->buffer, data->private_data);
1480
921f877b
RS
1481 free_nfs_cb_data(data);
1482 free(mdata);
1483}
1484
183451cf 1485int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, nfs_cb cb, void *private_data)
84004dbf
RS
1486{
1487 struct nfs_cb_data *data;
1488
1489 data = malloc(sizeof(struct nfs_cb_data));
1490 if (data == NULL) {
1491 rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
84004dbf
RS
1492 return -1;
1493 }
ea98629a 1494 memset(data, 0, sizeof(struct nfs_cb_data));
84004dbf
RS
1495 data->nfs = nfs;
1496 data->cb = cb;
1497 data->private_data = private_data;
1498 data->nfsfh = nfsfh;
1499
1500 nfsfh->offset = offset;
921f877b
RS
1501
1502 if (count <= nfs_get_readmax(nfs)) {
463d59bf
RS
1503 READ3args args;
1504
1505 memset(&args, 0, sizeof(READ3args));
2452c57f 1506 args.file = nfsfh->fh;
463d59bf
RS
1507 args.offset = offset;
1508 args.count = count;
1509
1510 if (rpc_nfs3_read_async(nfs->rpc, nfs_pread_cb, &args, data) != 0) {
921f877b
RS
1511 rpc_set_error(nfs->rpc, "RPC error: Failed to send READ call for %s", data->path);
1512 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1513 free_nfs_cb_data(data);
1514 return -1;
1515 }
1516 return 0;
1517 }
1518
1519 /* trying to read more than maximum server read size, we has to chop it up into smaller
1520 * reads and collect into a reassembly buffer.
cd67ec7d 1521 * we send all reads in parallel so that performance is still good.
921f877b 1522 */
7ed9d87a 1523 data->max_offset = offset;
921f877b
RS
1524 data->start_offset = offset;
1525
1526 data->buffer = malloc(count);
1527 if (data->buffer == NULL) {
1528 rpc_set_error(nfs->rpc, "Out-Of-Memory: Failed to allocate reassembly buffer for %d bytes", (int)count);
84004dbf
RS
1529 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1530 free_nfs_cb_data(data);
1531 return -1;
1532 }
921f877b
RS
1533
1534 while (count > 0) {
183451cf 1535 uint64_t readcount = count;
921f877b 1536 struct nfs_mcb_data *mdata;
463d59bf 1537 READ3args args;
921f877b
RS
1538
1539 if (readcount > nfs_get_readmax(nfs)) {
1540 readcount = nfs_get_readmax(nfs);
1541 }
1542
1543 mdata = malloc(sizeof(struct nfs_mcb_data));
1544 if (mdata == NULL) {
1545 rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_mcb_data structure");
921f877b
RS
1546 return -1;
1547 }
ea98629a 1548 memset(mdata, 0, sizeof(struct nfs_mcb_data));
921f877b
RS
1549 mdata->data = data;
1550 mdata->offset = offset;
1551 mdata->count = readcount;
463d59bf
RS
1552
1553 memset(&args, 0, sizeof(READ3args));
2452c57f 1554 args.file = nfsfh->fh;
463d59bf
RS
1555 args.offset = offset;
1556 args.count = readcount;
1557
1558 if (rpc_nfs3_read_async(nfs->rpc, nfs_pread_mcb, &args, mdata) != 0) {
921f877b
RS
1559 rpc_set_error(nfs->rpc, "RPC error: Failed to send READ call for %s", data->path);
1560 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1561 free(mdata);
1562 return -1;
1563 }
1564
1565 count -= readcount;
1566 offset += readcount;
1567 data->num_calls++;
1568 }
1569
1570 return 0;
84004dbf
RS
1571}
1572
1573/*
1574 * Async read()
1575 */
183451cf 1576int nfs_read_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, nfs_cb cb, void *private_data)
84004dbf
RS
1577{
1578 return nfs_pread_async(nfs, nfsfh, nfsfh->offset, count, cb, private_data);
1579}
1580
1581
1582
1583/*
1584 * Async pwrite()
1585 */
f3a75078 1586static void nfs_pwrite_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
84004dbf
RS
1587{
1588 struct nfs_cb_data *data = private_data;
1589 struct nfs_context *nfs = data->nfs;
1590 WRITE3res *res;
1591
f3a75078
RS
1592 assert(rpc->magic == RPC_CONTEXT_MAGIC);
1593
84004dbf
RS
1594 if (status == RPC_STATUS_ERROR) {
1595 data->cb(-EFAULT, nfs, command_data, data->private_data);
1596 free_nfs_cb_data(data);
1597 return;
1598 }
1599 if (status == RPC_STATUS_CANCEL) {
1600 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1601 free_nfs_cb_data(data);
1602 return;
1603 }
1604
1605 res = command_data;
1606 if (res->status != NFS3_OK) {
1607 rpc_set_error(nfs->rpc, "NFS: Write failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
1608 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
1609 free_nfs_cb_data(data);
1610 return;
1611 }
1612
1613 data->nfsfh->offset += res->WRITE3res_u.resok.count;
1614 data->cb(res->WRITE3res_u.resok.count, nfs, NULL, data->private_data);
1615 free_nfs_cb_data(data);
1616}
1617
f3a75078 1618static void nfs_pwrite_mcb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
18c27b73
RS
1619{
1620 struct nfs_mcb_data *mdata = private_data;
1621 struct nfs_cb_data *data = mdata->data;
1622 struct nfs_context *nfs = data->nfs;
1623 WRITE3res *res;
1624
f3a75078
RS
1625 assert(rpc->magic == RPC_CONTEXT_MAGIC);
1626
18c27b73
RS
1627 data->num_calls--;
1628
1629 if (status == RPC_STATUS_ERROR) {
1630 /* flag the failure but do not invoke callback until we have received all responses */
1631 data->error = 1;
1632 }
1633 if (status == RPC_STATUS_CANCEL) {
1634 /* flag the cancellation but do not invoke callback until we have received all responses */
1635 data->cancel = 1;
1636 }
1637
1638 if (status == RPC_STATUS_SUCCESS) {
1639 res = command_data;
1640 if (res->status != NFS3_OK) {
1641 rpc_set_error(nfs->rpc, "NFS: Write failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
1642 data->error = 1;
1643 } else {
1644 if (res->WRITE3res_u.resok.count > 0) {
1645 if ((unsigned)data->max_offset < mdata->offset + res->WRITE3res_u.resok.count) {
1646 data->max_offset = mdata->offset + res->WRITE3res_u.resok.count;
1647 }
1648 }
1649 }
1650 }
1651
1652 if (data->num_calls > 0) {
1653 /* still waiting for more replies */
1654 free(mdata);
1655 return;
1656 }
1657
1658 if (data->error != 0) {
1659 data->cb(-EFAULT, nfs, command_data, data->private_data);
1660 free_nfs_cb_data(data);
1661 free(mdata);
1662 return;
1663 }
1664 if (data->cancel != 0) {
1665 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1666 free_nfs_cb_data(data);
1667 free(mdata);
1668 return;
1669 }
1670
1671 data->nfsfh->offset = data->max_offset;
1672 data->cb(data->max_offset - data->start_offset, nfs, NULL, data->private_data);
1673
1674 free_nfs_cb_data(data);
1675 free(mdata);
1676}
1677
1678
183451cf 1679int 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
1680{
1681 struct nfs_cb_data *data;
1682
1683 data = malloc(sizeof(struct nfs_cb_data));
1684 if (data == NULL) {
1685 rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
84004dbf
RS
1686 return -1;
1687 }
ea98629a 1688 memset(data, 0, sizeof(struct nfs_cb_data));
84004dbf
RS
1689 data->nfs = nfs;
1690 data->cb = cb;
1691 data->private_data = private_data;
1692 data->nfsfh = nfsfh;
1693
1694 nfsfh->offset = offset;
18c27b73
RS
1695
1696 if (count <= nfs_get_writemax(nfs)) {
463d59bf
RS
1697 WRITE3args args;
1698
1699 memset(&args, 0, sizeof(WRITE3args));
2452c57f 1700 args.file = nfsfh->fh;
463d59bf
RS
1701 args.offset = offset;
1702 args.count = count;
1703 args.stable = nfsfh->is_sync?FILE_SYNC:UNSTABLE;
1704 args.data.data_len = count;
1705 args.data.data_val = buf;
1706
1707 if (rpc_nfs3_write_async(nfs->rpc, nfs_pwrite_cb, &args, data) != 0) {
18c27b73
RS
1708 rpc_set_error(nfs->rpc, "RPC error: Failed to send WRITE call for %s", data->path);
1709 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1710 free_nfs_cb_data(data);
1711 return -1;
1712 }
1713 return 0;
84004dbf 1714 }
18c27b73
RS
1715
1716 /* trying to write more than maximum server write size, we has to chop it up into smaller
1717 * chunks.
cd67ec7d 1718 * we send all writes in parallel so that performance is still good.
18c27b73
RS
1719 */
1720 data->max_offset = offset;
1721 data->start_offset = offset;
1722
1723 while (count > 0) {
183451cf 1724 uint64_t writecount = count;
18c27b73 1725 struct nfs_mcb_data *mdata;
463d59bf 1726 WRITE3args args;
18c27b73
RS
1727
1728 if (writecount > nfs_get_writemax(nfs)) {
1729 writecount = nfs_get_writemax(nfs);
1730 }
1731
1732 mdata = malloc(sizeof(struct nfs_mcb_data));
1733 if (mdata == NULL) {
1734 rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_mcb_data structure");
1735 return -1;
1736 }
1737 memset(mdata, 0, sizeof(struct nfs_mcb_data));
1738 mdata->data = data;
1739 mdata->offset = offset;
1740 mdata->count = writecount;
1741
463d59bf 1742 memset(&args, 0, sizeof(WRITE3args));
2452c57f 1743 args.file = nfsfh->fh;
463d59bf
RS
1744 args.offset = offset;
1745 args.count = writecount;
1746 args.stable = nfsfh->is_sync?FILE_SYNC:UNSTABLE;
1747 args.data.data_len = writecount;
1748 args.data.data_val = &buf[offset - data->start_offset];
1749
1750 if (rpc_nfs3_write_async(nfs->rpc, nfs_pwrite_mcb, &args, mdata) != 0) {
18c27b73
RS
1751 rpc_set_error(nfs->rpc, "RPC error: Failed to send WRITE call for %s", data->path);
1752 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1753 free(mdata);
1754 return -1;
1755 }
1756
1757 count -= writecount;
1758 offset += writecount;
1759 data->num_calls++;
1760 }
1761
84004dbf
RS
1762 return 0;
1763}
1764
1765/*
1766 * Async write()
1767 */
183451cf 1768int nfs_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buf, nfs_cb cb, void *private_data)
84004dbf
RS
1769{
1770 return nfs_pwrite_async(nfs, nfsfh, nfsfh->offset, count, buf, cb, private_data);
1771}
1772
1773
1774
1775
1776/*
1777 * close
1778 */
1779
1780int nfs_close_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data)
1781{
1782 if (nfsfh->fh.data.data_val != NULL){
1783 free(nfsfh->fh.data.data_val);
1784 nfsfh->fh.data.data_val = NULL;
1785 }
1786 free(nfsfh);
1787
1788 cb(0, nfs, NULL, private_data);
1789 return 0;
1790};
1791
1792
1793
1794
1795
1796/*
1797 * Async fstat()
1798 */
1799int nfs_fstat_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data)
1800{
1801 struct nfs_cb_data *data;
463d59bf 1802 struct GETATTR3args args;
84004dbf
RS
1803
1804 data = malloc(sizeof(struct nfs_cb_data));
1805 if (data == NULL) {
1806 rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
84004dbf
RS
1807 return -1;
1808 }
ea98629a 1809 memset(data, 0, sizeof(struct nfs_cb_data));
84004dbf
RS
1810 data->nfs = nfs;
1811 data->cb = cb;
1812 data->private_data = private_data;
1813
463d59bf 1814 memset(&args, 0, sizeof(GETATTR3args));
2452c57f 1815 args.object = nfsfh->fh;
463d59bf
RS
1816
1817 if (rpc_nfs3_getattr_async(nfs->rpc, nfs_stat_1_cb, &args, data) != 0) {
84004dbf
RS
1818 rpc_set_error(nfs->rpc, "RPC error: Failed to send STAT GETATTR call for %s", data->path);
1819 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1820 free_nfs_cb_data(data);
1821 return -1;
1822 }
1823 return 0;
1824}
1825
1826
1827
1828/*
1829 * Async fsync()
1830 */
f3a75078 1831static void nfs_fsync_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
84004dbf
RS
1832{
1833 struct nfs_cb_data *data = private_data;
1834 struct nfs_context *nfs = data->nfs;
1835 COMMIT3res *res;
1836
f3a75078
RS
1837 assert(rpc->magic == RPC_CONTEXT_MAGIC);
1838
84004dbf
RS
1839 if (status == RPC_STATUS_ERROR) {
1840 data->cb(-EFAULT, nfs, command_data, data->private_data);
1841 free_nfs_cb_data(data);
1842 return;
1843 }
1844 if (status == RPC_STATUS_CANCEL) {
1845 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1846 free_nfs_cb_data(data);
1847 return;
1848 }
1849
1850 res = command_data;
1851 if (res->status != NFS3_OK) {
1852 rpc_set_error(nfs->rpc, "NFS: Commit failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
1853 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
1854 free_nfs_cb_data(data);
1855 return;
1856 }
1857
1858 data->cb(0, nfs, NULL, data->private_data);
1859 free_nfs_cb_data(data);
1860}
1861
1862int nfs_fsync_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data)
1863{
1864 struct nfs_cb_data *data;
1a5636ff 1865 struct COMMIT3args args;
84004dbf
RS
1866
1867 data = malloc(sizeof(struct nfs_cb_data));
1868 if (data == NULL) {
1869 rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
84004dbf
RS
1870 return -1;
1871 }
ea98629a 1872 memset(data, 0, sizeof(struct nfs_cb_data));
84004dbf
RS
1873 data->nfs = nfs;
1874 data->cb = cb;
1875 data->private_data = private_data;
1876
1a5636ff
RS
1877 args.file = nfsfh->fh;
1878 args.offset = 0;
1879 args.count = 0;
1880 if (rpc_nfs3_commit_async(nfs->rpc, nfs_fsync_cb, &args, data) != 0) {
84004dbf
RS
1881 rpc_set_error(nfs->rpc, "RPC error: Failed to send COMMIT call for %s", data->path);
1882 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1883 free_nfs_cb_data(data);
1884 return -1;
1885 }
1886 return 0;
1887}
1888
1889
1890
1891
1892/*
1893 * Async ftruncate()
1894 */
f3a75078 1895static void nfs_ftruncate_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
84004dbf
RS
1896{
1897 struct nfs_cb_data *data = private_data;
1898 struct nfs_context *nfs = data->nfs;
1899 SETATTR3res *res;
1900
f3a75078
RS
1901 assert(rpc->magic == RPC_CONTEXT_MAGIC);
1902
84004dbf
RS
1903 if (status == RPC_STATUS_ERROR) {
1904 data->cb(-EFAULT, nfs, command_data, data->private_data);
1905 free_nfs_cb_data(data);
1906 return;
1907 }
1908 if (status == RPC_STATUS_CANCEL) {
1909 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1910 free_nfs_cb_data(data);
1911 return;
1912 }
1913
1914 res = command_data;
1915 if (res->status != NFS3_OK) {
1916 rpc_set_error(nfs->rpc, "NFS: Setattr failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
1917 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
1918 free_nfs_cb_data(data);
1919 return;
1920 }
1921
1922 data->cb(0, nfs, NULL, data->private_data);
1923 free_nfs_cb_data(data);
1924}
1925
183451cf 1926int nfs_ftruncate_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t length, nfs_cb cb, void *private_data)
84004dbf
RS
1927{
1928 struct nfs_cb_data *data;
1929 SETATTR3args args;
1930
1931 data = malloc(sizeof(struct nfs_cb_data));
1932 if (data == NULL) {
1933 rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
84004dbf
RS
1934 return -1;
1935 }
ea98629a 1936 memset(data, 0, sizeof(struct nfs_cb_data));
84004dbf
RS
1937 data->nfs = nfs;
1938 data->cb = cb;
1939 data->private_data = private_data;
1940
ea98629a 1941 memset(&args, 0, sizeof(SETATTR3args));
2452c57f 1942 args.object = nfsfh->fh;
84004dbf
RS
1943 args.new_attributes.size.set_it = 1;
1944 args.new_attributes.size.set_size3_u.size = length;
1945
b701254d 1946 if (rpc_nfs3_setattr_async(nfs->rpc, nfs_ftruncate_cb, &args, data) != 0) {
84004dbf
RS
1947 rpc_set_error(nfs->rpc, "RPC error: Failed to send SETATTR call for %s", data->path);
1948 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1949 free_nfs_cb_data(data);
1950 return -1;
1951 }
1952 return 0;
1953}
1954
1955
1956/*
1957 * Async truncate()
1958 */
1959static int nfs_truncate_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
1960{
183451cf 1961 uint64_t offset = data->continue_int;
84004dbf
RS
1962 struct nfsfh nfsfh;
1963
2452c57f 1964 nfsfh.fh = data->fh;
84004dbf
RS
1965
1966 if (nfs_ftruncate_async(nfs, &nfsfh, offset, data->cb, data->private_data) != 0) {
1967 rpc_set_error(nfs->rpc, "RPC error: Failed to send SETATTR call for %s", data->path);
1968 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1969 free_nfs_cb_data(data);
1970 return -1;
1971 }
1972 free_nfs_cb_data(data);
1973 return 0;
1974}
1975
183451cf 1976int nfs_truncate_async(struct nfs_context *nfs, const char *path, uint64_t length, nfs_cb cb, void *private_data)
84004dbf 1977{
183451cf 1978 uint64_t offset;
84004dbf
RS
1979
1980 offset = length;
1981
1982 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_truncate_continue_internal, NULL, NULL, offset) != 0) {
cbbf9d3e
RS
1983 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
1984 return -1;
84004dbf
RS
1985 }
1986
1987 return 0;
1988}
1989
1990
1991
1992
1993/*
1994 * Async mkdir()
1995 */
f3a75078 1996static void nfs_mkdir_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
84004dbf
RS
1997{
1998 MKDIR3res *res;
1999 struct nfs_cb_data *data = private_data;
2000 struct nfs_context *nfs = data->nfs;
2001 char *str = data->continue_data;
2002
f3a75078
RS
2003 assert(rpc->magic == RPC_CONTEXT_MAGIC);
2004
84004dbf
RS
2005 str = &str[strlen(str) + 1];
2006
2007 if (status == RPC_STATUS_ERROR) {
2008 data->cb(-EFAULT, nfs, command_data, data->private_data);
2009 free_nfs_cb_data(data);
2010 return;
2011 }
2012 if (status == RPC_STATUS_CANCEL) {
2013 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2014 free_nfs_cb_data(data);
2015 return;
2016 }
2017
2018 res = command_data;
2019 if (res->status != NFS3_OK) {
2020 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));
2021 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
2022 free_nfs_cb_data(data);
2023 return;
2024 }
2025
2026 data->cb(0, nfs, NULL, data->private_data);
2027 free_nfs_cb_data(data);
2028}
2029
2030static int nfs_mkdir_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
2031{
2032 char *str = data->continue_data;
7edc9026
RS
2033 MKDIR3args args;
2034
84004dbf
RS
2035 str = &str[strlen(str) + 1];
2036
7edc9026 2037 memset(&args, 0, sizeof(MKDIR3args));
2452c57f 2038 args.where.dir = data->fh;
7edc9026
RS
2039 args.where.name = str;
2040 args.attributes.mode.set_it = 1;
2041 args.attributes.mode.set_mode3_u.mode = 0755;
2042
acabd6bf 2043 if (rpc_nfs3_mkdir_async(nfs->rpc, nfs_mkdir_cb, &args, data) != 0) {
84004dbf
RS
2044 rpc_set_error(nfs->rpc, "RPC error: Failed to send MKDIR call for %s", data->path);
2045 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2046 free_nfs_cb_data(data);
2047 return -1;
2048 }
2049 return 0;
2050}
2051
2052int nfs_mkdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
2053{
2054 char *new_path;
2055 char *ptr;
2056
2057 new_path = strdup(path);
2058 if (new_path == NULL) {
cbbf9d3e 2059 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for path");
84004dbf
RS
2060 return -1;
2061 }
2062
93e9306f 2063 ptr = strrchr(new_path, '/');
84004dbf 2064 if (ptr == NULL) {
cbbf9d3e
RS
2065 rpc_set_error(nfs->rpc, "Invalid path %s", path);
2066 return -1;
84004dbf
RS
2067 }
2068 *ptr = 0;
2069
2070 /* new_path now points to the parent directory, and beyond the nul terminateor is the new directory to create */
2071 if (nfs_lookuppath_async(nfs, new_path, cb, private_data, nfs_mkdir_continue_internal, new_path, free, 0) != 0) {
cbbf9d3e
RS
2072 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path component");
2073 return -1;
84004dbf
RS
2074 }
2075
2076 return 0;
2077}
2078
2079
2080
2081
2082
2083/*
2084 * Async rmdir()
2085 */
f3a75078 2086static void nfs_rmdir_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
84004dbf
RS
2087{
2088 RMDIR3res *res;
2089 struct nfs_cb_data *data = private_data;
2090 struct nfs_context *nfs = data->nfs;
2091 char *str = data->continue_data;
2092
f3a75078
RS
2093 assert(rpc->magic == RPC_CONTEXT_MAGIC);
2094
84004dbf
RS
2095 str = &str[strlen(str) + 1];
2096
2097 if (status == RPC_STATUS_ERROR) {
2098 data->cb(-EFAULT, nfs, command_data, data->private_data);
2099 free_nfs_cb_data(data);
2100 return;
2101 }
2102 if (status == RPC_STATUS_CANCEL) {
2103 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2104 free_nfs_cb_data(data);
2105 return;
2106 }
2107
2108 res = command_data;
2109 if (res->status != NFS3_OK) {
2110 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));
2111 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
2112 free_nfs_cb_data(data);
2113 return;
2114 }
2115
2116 data->cb(0, nfs, NULL, data->private_data);
2117 free_nfs_cb_data(data);
2118}
2119
2120static int nfs_rmdir_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
2121{
2122 char *str = data->continue_data;
bf817ee6
RS
2123 RMDIR3args args;
2124
84004dbf
RS
2125 str = &str[strlen(str) + 1];
2126
bf817ee6
RS
2127 args.object.dir = data->fh;
2128 args.object.name = str;
2129 if (rpc_nfs3_rmdir_async(nfs->rpc, nfs_rmdir_cb, &args, data) != 0) {
84004dbf
RS
2130 rpc_set_error(nfs->rpc, "RPC error: Failed to send RMDIR call for %s", data->path);
2131 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2132 free_nfs_cb_data(data);
2133 return -1;
2134 }
2135 return 0;
2136}
2137
2138int nfs_rmdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
2139{
2140 char *new_path;
2141 char *ptr;
2142
2143 new_path = strdup(path);
2144 if (new_path == NULL) {
cbbf9d3e 2145 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for path");
84004dbf
RS
2146 return -1;
2147 }
2148
93e9306f 2149 ptr = strrchr(new_path, '/');
84004dbf 2150 if (ptr == NULL) {
cbbf9d3e
RS
2151 rpc_set_error(nfs->rpc, "Invalid path %s", path);
2152 return -1;
84004dbf
RS
2153 }
2154 *ptr = 0;
2155
2156 /* new_path now points to the parent directory, and beyond the nul terminateor is the new directory to create */
2157 if (nfs_lookuppath_async(nfs, new_path, cb, private_data, nfs_rmdir_continue_internal, new_path, free, 0) != 0) {
cbbf9d3e
RS
2158 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
2159 return -1;
84004dbf
RS
2160 }
2161
2162 return 0;
2163}
2164
2165
2166
2167
2168/*
2169 * Async creat()
2170 */
f3a75078 2171static void nfs_create_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
84004dbf
RS
2172{
2173 LOOKUP3res *res;
2174 struct nfs_cb_data *data = private_data;
2175 struct nfs_context *nfs = data->nfs;
2176 struct nfsfh *nfsfh;
2177 char *str = data->continue_data;
2178
f3a75078
RS
2179 assert(rpc->magic == RPC_CONTEXT_MAGIC);
2180
84004dbf
RS
2181 if (status == RPC_STATUS_ERROR) {
2182 data->cb(-EFAULT, nfs, command_data, data->private_data);
2183 free_nfs_cb_data(data);
2184 return;
2185 }
2186 if (status == RPC_STATUS_CANCEL) {
2187 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2188 free_nfs_cb_data(data);
2189 return;
2190 }
2191
2192 str = &str[strlen(str) + 1];
2193 res = command_data;
2194 if (res->status != NFS3_OK) {
2195 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));
2196 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
2197
2198 return;
2199 }
2200
2201 nfsfh = malloc(sizeof(struct nfsfh));
2202 if (nfsfh == NULL) {
2203 rpc_set_error(nfs->rpc, "NFS: Failed to allocate nfsfh structure");
2204 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2205 free_nfs_cb_data(data);
2206 return;
2207 }
ea98629a 2208 memset(nfsfh, 0, sizeof(struct nfsfh));
84004dbf 2209
0c1a9d7a
RS
2210 /* copy the filehandle */
2211 nfsfh->fh.data.data_len = res->LOOKUP3res_u.resok.object.data.data_len;
2212 nfsfh->fh.data.data_val = malloc(nfsfh->fh.data.data_len);
2213 memcpy(nfsfh->fh.data.data_val, res->LOOKUP3res_u.resok.object.data.data_val, nfsfh->fh.data.data_len);
84004dbf
RS
2214
2215 data->cb(0, nfs, nfsfh, data->private_data);
2216 free_nfs_cb_data(data);
2217}
2218
2219
2220
f3a75078 2221static void nfs_creat_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
84004dbf
RS
2222{
2223 CREATE3res *res;
2224 struct nfs_cb_data *data = private_data;
2225 struct nfs_context *nfs = data->nfs;
2226 char *str = data->continue_data;
463d59bf 2227 LOOKUP3args args;
84004dbf 2228
f3a75078
RS
2229 assert(rpc->magic == RPC_CONTEXT_MAGIC);
2230
84004dbf
RS
2231 if (status == RPC_STATUS_ERROR) {
2232 data->cb(-EFAULT, nfs, command_data, data->private_data);
2233 free_nfs_cb_data(data);
2234 return;
2235 }
2236 if (status == RPC_STATUS_CANCEL) {
2237 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2238 free_nfs_cb_data(data);
2239 return;
2240 }
2241
2242 str = &str[strlen(str) + 1];
2243 res = command_data;
2244 if (res->status != NFS3_OK) {
2245 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));
2246 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
fadbf8cf 2247 free_nfs_cb_data(data);
84004dbf
RS
2248 return;
2249 }
2250
463d59bf 2251 memset(&args, 0, sizeof(LOOKUP3args));
2452c57f
RS
2252 args.what.dir = data->fh;
2253 args.what.name = str;
463d59bf
RS
2254
2255 if (rpc_nfs3_lookup_async(nfs->rpc, nfs_create_2_cb, &args, data) != 0) {
84004dbf
RS
2256 rpc_set_error(nfs->rpc, "RPC error: Failed to send lookup call for %s/%s", data->saved_path, str);
2257 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2258 free_nfs_cb_data(data);
2259 return;
2260 }
2261 return;
2262}
2263
2264static int nfs_creat_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
2265{
2266 char *str = data->continue_data;
c985c015
RS
2267 CREATE3args args;
2268
84004dbf
RS
2269 str = &str[strlen(str) + 1];
2270
c985c015 2271 memset(&args, 0, sizeof(CREATE3args));
2452c57f 2272 args.where.dir = data->fh;
c985c015
RS
2273 args.where.name = str;
2274 args.how.mode = UNCHECKED;
2275 args.how.createhow3_u.obj_attributes.mode.set_it = 1;
2276 args.how.createhow3_u.obj_attributes.mode.set_mode3_u.mode = data->continue_int;
2277
789c3f12 2278 if (rpc_nfs3_create_async(nfs->rpc, nfs_creat_1_cb, &args, data) != 0) {
84004dbf
RS
2279 rpc_set_error(nfs->rpc, "RPC error: Failed to send CREATE call for %s/%s", data->path, str);
2280 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2281 free_nfs_cb_data(data);
2282 return -1;
2283 }
2284 return 0;
2285}
2286
2287int nfs_creat_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data)
2288{
2289 char *new_path;
2290 char *ptr;
2291
2292 new_path = strdup(path);
2293 if (new_path == NULL) {
cbbf9d3e 2294 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for path");
84004dbf
RS
2295 return -1;
2296 }
2297
93e9306f 2298 ptr = strrchr(new_path, '/');
84004dbf 2299 if (ptr == NULL) {
cbbf9d3e
RS
2300 rpc_set_error(nfs->rpc, "Invalid path %s", path);
2301 return -1;
84004dbf
RS
2302 }
2303 *ptr = 0;
2304
73f4ae7c 2305 /* new_path now points to the parent directory, and beyond the nul terminator is the new directory to create */
84004dbf 2306 if (nfs_lookuppath_async(nfs, new_path, cb, private_data, nfs_creat_continue_internal, new_path, free, mode) != 0) {
cbbf9d3e
RS
2307 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
2308 return -1;
84004dbf
RS
2309 }
2310
2311 return 0;
2312}
2313
2314
2315
2316
2317/*
2318 * Async unlink()
2319 */
f3a75078 2320static void nfs_unlink_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
84004dbf
RS
2321{
2322 REMOVE3res *res;
2323 struct nfs_cb_data *data = private_data;
2324 struct nfs_context *nfs = data->nfs;
2325 char *str = data->continue_data;
2326
f3a75078
RS
2327 assert(rpc->magic == RPC_CONTEXT_MAGIC);
2328
84004dbf
RS
2329 str = &str[strlen(str) + 1];
2330
2331 if (status == RPC_STATUS_ERROR) {
2332 data->cb(-EFAULT, nfs, command_data, data->private_data);
2333 free_nfs_cb_data(data);
2334 return;
2335 }
2336 if (status == RPC_STATUS_CANCEL) {
2337 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2338 free_nfs_cb_data(data);
2339 return;
2340 }
2341
2342 res = command_data;
2343 if (res->status != NFS3_OK) {
2344 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));
2345 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
2346 free_nfs_cb_data(data);
2347 return;
2348 }
2349
2350 data->cb(0, nfs, NULL, data->private_data);
2351 free_nfs_cb_data(data);
2352}
2353
2354static int nfs_unlink_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
2355{
2356 char *str = data->continue_data;
a0a5aa26
RS
2357 struct REMOVE3args args;
2358
84004dbf
RS
2359 str = &str[strlen(str) + 1];
2360
a0a5aa26
RS
2361 args.object.dir = data->fh;
2362 args.object.name = str;
2363 if (rpc_nfs3_remove_async(nfs->rpc, nfs_unlink_cb, &args, data) != 0) {
84004dbf
RS
2364 rpc_set_error(nfs->rpc, "RPC error: Failed to send REMOVE call for %s", data->path);
2365 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2366 free_nfs_cb_data(data);
2367 return -1;
2368 }
2369 return 0;
2370}
2371
2372int nfs_unlink_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
2373{
2374 char *new_path;
2375 char *ptr;
2376
2377 new_path = strdup(path);
2378 if (new_path == NULL) {
cbbf9d3e 2379 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for path");
84004dbf
RS
2380 return -1;
2381 }
2382
93e9306f 2383 ptr = strrchr(new_path, '/');
84004dbf 2384 if (ptr == NULL) {
cbbf9d3e
RS
2385 rpc_set_error(nfs->rpc, "Invalid path %s", path);
2386 return -1;
84004dbf
RS
2387 }
2388 *ptr = 0;
2389
2390 /* new_path now points to the parent directory, and beyond the nul terminateor is the new directory to create */
2391 if (nfs_lookuppath_async(nfs, new_path, cb, private_data, nfs_unlink_continue_internal, new_path, free, 0) != 0) {
cbbf9d3e
RS
2392 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
2393 return -1;
84004dbf
RS
2394 }
2395
2396 return 0;
2397}
2398
2399
1ec6b50a
RS
2400/*
2401 * Async mknod()
2402 */
2403struct mknod_cb_data {
2404 char *path;
2405 int mode;
2406 int major;
2407 int minor;
2408};
2409
2410static void free_mknod_cb_data(void *ptr)
2411{
2412 struct mknod_cb_data *data = ptr;
2413
2414 free(data->path);
2415 free(data);
2416}
2417
f3a75078 2418static void nfs_mknod_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
1ec6b50a
RS
2419{
2420 MKNOD3res *res;
2421 struct nfs_cb_data *data = private_data;
2422 struct nfs_context *nfs = data->nfs;
2423 char *str = data->continue_data;
2424
f3a75078
RS
2425 assert(rpc->magic == RPC_CONTEXT_MAGIC);
2426
1ec6b50a
RS
2427 str = &str[strlen(str) + 1];
2428
2429 if (status == RPC_STATUS_ERROR) {
2430 data->cb(-EFAULT, nfs, command_data, data->private_data);
2431 free_nfs_cb_data(data);
2432 return;
2433 }
2434 if (status == RPC_STATUS_CANCEL) {
2435 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2436 free_nfs_cb_data(data);
2437 return;
2438 }
2439
2440 res = command_data;
2441 if (res->status != NFS3_OK) {
2442 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));
2443 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
2444 free_nfs_cb_data(data);
2445 return;
2446 }
2447
2448 data->cb(0, nfs, NULL, data->private_data);
2449 free_nfs_cb_data(data);
2450}
2451
2452static int nfs_mknod_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
2453{
2454 struct mknod_cb_data *cb_data = data->continue_data;
2455 char *str = cb_data->path;
b17cb0a2 2456 MKNOD3args args;
1ec6b50a
RS
2457
2458 str = &str[strlen(str) + 1];
2459
b17cb0a2
RS
2460 args.where.dir = data->fh;
2461 args.where.name = str;
2462 switch (cb_data->mode & S_IFMT) {
2463 case S_IFCHR:
2464 args.what.type = NF3CHR;
2465 args.what.mknoddata3_u.chr_device.dev_attributes.mode.set_it = 1;
2466 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);
2467 args.what.mknoddata3_u.chr_device.spec.specdata1 = cb_data->major;
2468 args.what.mknoddata3_u.chr_device.spec.specdata2 = cb_data->minor;
2469 break;
2470 case S_IFBLK:
2471 args.what.type = NF3BLK;
2472 args.what.mknoddata3_u.blk_device.dev_attributes.mode.set_it = 1;
2473 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);
2474 args.what.mknoddata3_u.blk_device.spec.specdata1 = cb_data->major;
2475 args.what.mknoddata3_u.blk_device.spec.specdata2 = cb_data->minor;
2476 case S_IFSOCK:
2477 args.what.type = NF3SOCK;
2478 args.what.mknoddata3_u.sock_attributes.mode.set_it = 1;
2479 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);
2480 break;
2481 case S_IFIFO:
2482 args.what.type = NF3FIFO;
2483 args.what.mknoddata3_u.pipe_attributes.mode.set_it = 1;
2484 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);
2485 break;
2486 default:
2487 rpc_set_error(nfs->rpc, "Invalid file type for NFS3/MKNOD call");
2488 data->cb(-EINVAL, nfs, rpc_get_error(nfs->rpc), data->private_data);
2489 free_nfs_cb_data(data);
2490 return -1;
2491 }
2492
2493 if (rpc_nfs3_mknod_async(nfs->rpc, nfs_mknod_cb, &args, data) != 0) {
1ec6b50a
RS
2494 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2495 free_nfs_cb_data(data);
2496 return -1;
2497 }
2498 return 0;
2499}
2500
2501int nfs_mknod_async(struct nfs_context *nfs, const char *path, int mode, int dev, nfs_cb cb, void *private_data)
2502{
2503 char *ptr;
2504 struct mknod_cb_data *cb_data;
2505
2506 cb_data = malloc(sizeof(struct mknod_cb_data));
2507 if (cb_data == NULL) {
2508 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for cb data");
2509 return -1;
2510 }
2511
2512 cb_data->path = strdup(path);
2513 if (cb_data->path == NULL) {
2514 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for path");
2515 free(cb_data);
2516 return -1;
2517 }
2518
2519 ptr = strrchr(cb_data->path, '/');
2520 if (ptr == NULL) {
2521 rpc_set_error(nfs->rpc, "Invalid path %s", path);
2522 return -1;
2523 }
2524 *ptr = 0;
2525
2526 cb_data->mode = mode;
2527 cb_data->major = major(dev);
2528 cb_data->minor = minor(dev);
2529
2530 /* data->path now points to the parent directory, and beyond the nul terminateor is the new directory to create */
2531 if (nfs_lookuppath_async(nfs, cb_data->path, cb, private_data, nfs_mknod_continue_internal, cb_data, free_mknod_cb_data, 0) != 0) {
2532 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
2533 free_mknod_cb_data(cb_data);
2534 return -1;
2535 }
2536
2537 return 0;
2538}
84004dbf 2539
84004dbf
RS
2540/*
2541 * Async opendir()
2542 */
fb69c64c
RS
2543
2544/* ReadDirPlus Emulation Callback data */
2545struct rdpe_cb_data {
2546 int getattrcount;
2547 int status;
2548 struct nfs_cb_data *data;
2549};
2550
2551/* ReadDirPlus Emulation LOOKUP Callback data */
2552struct rdpe_lookup_cb_data {
2553 struct rdpe_cb_data *rdpe_cb_data;
2554 struct nfsdirent *nfsdirent;
2555};
2556
2557/* Workaround for servers lacking READDIRPLUS, use READDIR instead and a GETATTR-loop */
f3a75078 2558static void nfs_opendir3_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
84004dbf 2559{
fb69c64c
RS
2560 LOOKUP3res *res = command_data;
2561 struct rdpe_lookup_cb_data *rdpe_lookup_cb_data = private_data;
2562 struct rdpe_cb_data *rdpe_cb_data = rdpe_lookup_cb_data->rdpe_cb_data;
2563 struct nfs_cb_data *data = rdpe_cb_data->data;
2564 struct nfsdir *nfsdir = data->continue_data;
2565 struct nfs_context *nfs = data->nfs;
2566 struct nfsdirent *nfsdirent = rdpe_lookup_cb_data->nfsdirent;
2567
f3a75078
RS
2568 assert(rpc->magic == RPC_CONTEXT_MAGIC);
2569
fb69c64c
RS
2570 free(rdpe_lookup_cb_data);
2571
2572 rdpe_cb_data->getattrcount--;
2573
2574 if (status == RPC_STATUS_ERROR) {
2575 rdpe_cb_data->status = RPC_STATUS_ERROR;
2576 }
2577 if (status == RPC_STATUS_CANCEL) {
2578 rdpe_cb_data->status = RPC_STATUS_CANCEL;
2579 }
2580 if (status == RPC_STATUS_SUCCESS && res->status != NFS3_OK) {
2581 rdpe_cb_data->status = RPC_STATUS_ERROR;
2582 }
2583 if (status == RPC_STATUS_SUCCESS && res->status == NFS3_OK) {
2584 if (res->LOOKUP3res_u.resok.obj_attributes.attributes_follow) {
2585 fattr3 *attributes = &res->LOOKUP3res_u.resok.obj_attributes.post_op_attr_u.attributes;
2586
2587 nfsdirent->type = attributes->type;
2588 nfsdirent->mode = attributes->mode;
2589 nfsdirent->size = attributes->size;
2590
2591 nfsdirent->atime.tv_sec = attributes->atime.seconds;
2592 nfsdirent->atime.tv_usec = attributes->atime.nseconds/1000;
2593 nfsdirent->mtime.tv_sec = attributes->mtime.seconds;
2594 nfsdirent->mtime.tv_usec = attributes->mtime.nseconds/1000;
2595 nfsdirent->ctime.tv_sec = attributes->ctime.seconds;
2596 nfsdirent->ctime.tv_usec = attributes->ctime.nseconds/1000;
7bda8bad
RS
2597 nfsdirent->uid = attributes->uid;
2598 nfsdirent->gid = attributes->gid;
fb69c64c
RS
2599 }
2600 }
2601
2602 if (rdpe_cb_data->getattrcount == 0) {
2603 if (rdpe_cb_data->status != RPC_STATUS_SUCCESS) {
2604 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2605 nfs_free_nfsdir(nfsdir);
2606 } else {
2607 data->cb(0, nfs, nfsdir, data->private_data);
2608 }
2609 free(rdpe_cb_data);
2610
2611 data->continue_data = NULL;
2612 free_nfs_cb_data(data);
2613 }
2614}
2615
f3a75078 2616static void nfs_opendir2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
fb69c64c
RS
2617{
2618 READDIR3res *res = command_data;
84004dbf
RS
2619 struct nfs_cb_data *data = private_data;
2620 struct nfs_context *nfs = data->nfs;
fb6510bb 2621 struct nfsdir *nfsdir = data->continue_data;
fb69c64c
RS
2622 struct nfsdirent *nfsdirent;
2623 struct entry3 *entry;
ecbd14a1 2624 uint64_t cookie = 0;
fb69c64c
RS
2625 struct rdpe_cb_data *rdpe_cb_data;
2626
f3a75078
RS
2627 assert(rpc->magic == RPC_CONTEXT_MAGIC);
2628
84004dbf
RS
2629 if (status == RPC_STATUS_ERROR) {
2630 data->cb(-EFAULT, nfs, command_data, data->private_data);
2631 nfs_free_nfsdir(nfsdir);
2632 data->continue_data = NULL;
2633 free_nfs_cb_data(data);
2634 return;
2635 }
fb69c64c 2636
84004dbf
RS
2637 if (status == RPC_STATUS_CANCEL) {
2638 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2639 nfs_free_nfsdir(nfsdir);
2640 data->continue_data = NULL;
2641 free_nfs_cb_data(data);
2642 return;
2643 }
2644
84004dbf
RS
2645 if (res->status != NFS3_OK) {
2646 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));
2647 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
2648 nfs_free_nfsdir(nfsdir);
2649 data->continue_data = NULL;
2650 free_nfs_cb_data(data);
2651 return;
fb69c64c
RS
2652 }
2653
2654 entry =res->READDIR3res_u.resok.reply.entries;
2655 while (entry != NULL) {
2656 nfsdirent = malloc(sizeof(struct nfsdirent));
2657 if (nfsdirent == NULL) {
2658 data->cb(-ENOMEM, nfs, "Failed to allocate dirent", data->private_data);
2659 nfs_free_nfsdir(nfsdir);
2660 data->continue_data = NULL;
2661 free_nfs_cb_data(data);
2662 return;
2663 }
2664 memset(nfsdirent, 0, sizeof(struct nfsdirent));
2665 nfsdirent->name = strdup(entry->name);
2666 if (nfsdirent->name == NULL) {
2667 data->cb(-ENOMEM, nfs, "Failed to allocate dirent->name", data->private_data);
2668 nfs_free_nfsdir(nfsdir);
2669 data->continue_data = NULL;
2670 free_nfs_cb_data(data);
2671 return;
2672 }
2673 nfsdirent->inode = entry->fileid;
2674
2675 nfsdirent->next = nfsdir->entries;
2676 nfsdir->entries = nfsdirent;
2677
2678 cookie = entry->cookie;
2679 entry = entry->nextentry;
2680 }
2681
2682 if (res->READDIR3res_u.resok.reply.eof == 0) {
a64a16a2
RS
2683 READDIR3args args;
2684
2685 args.dir = data->fh;
2686 args.cookie = cookie;
2452c57f 2687 memcpy(&args.cookieverf, res->READDIR3res_u.resok.cookieverf, sizeof(cookieverf3));
a64a16a2
RS
2688 args.count = 8192;
2689
2690 if (rpc_nfs3_readdir_async(nfs->rpc, nfs_opendir2_cb, &args, data) != 0) {
fb69c64c
RS
2691 rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR call for %s", data->path);
2692 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2693 nfs_free_nfsdir(nfsdir);
2694 data->continue_data = NULL;
2695 free_nfs_cb_data(data);
2696 return;
2697 }
2698 return;
2699 }
2700
2701 /* steal the dirhandle */
2702 nfsdir->current = nfsdir->entries;
2703
2704 rdpe_cb_data = malloc(sizeof(struct rdpe_cb_data));
2705 rdpe_cb_data->getattrcount = 0;
2706 rdpe_cb_data->status = RPC_STATUS_SUCCESS;
2707 rdpe_cb_data->data = data;
2708 for (nfsdirent = nfsdir->entries; nfsdirent; nfsdirent = nfsdirent->next) {
2709 struct rdpe_lookup_cb_data *rdpe_lookup_cb_data;
463d59bf 2710 LOOKUP3args args;
fb69c64c
RS
2711
2712 rdpe_lookup_cb_data = malloc(sizeof(struct rdpe_lookup_cb_data));
2713 rdpe_lookup_cb_data->rdpe_cb_data = rdpe_cb_data;
2714 rdpe_lookup_cb_data->nfsdirent = nfsdirent;
2715
463d59bf 2716 memset(&args, 0, sizeof(LOOKUP3args));
2452c57f
RS
2717 args.what.dir = data->fh;
2718 args.what.name = nfsdirent->name;
463d59bf
RS
2719
2720 if (rpc_nfs3_lookup_async(nfs->rpc, nfs_opendir3_cb, &args, rdpe_lookup_cb_data) != 0) {
fb69c64c
RS
2721 rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR LOOKUP call");
2722
2723 /* if we have already commands in flight, we cant just stop, we have to wait for the
2724 * commands in flight to complete
2725 */
2726 if (rdpe_cb_data->getattrcount > 0) {
2727 rdpe_cb_data->status = RPC_STATUS_ERROR;
2728 free(rdpe_lookup_cb_data);
2729 return;
2730 }
2731
2732 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2733 nfs_free_nfsdir(nfsdir);
2734 data->continue_data = NULL;
2735 free_nfs_cb_data(data);
2736 free(rdpe_lookup_cb_data);
2737 free(rdpe_cb_data);
2738 return;
2739 }
2740 rdpe_cb_data->getattrcount++;
2741 }
2742}
2743
2744
f3a75078 2745static void nfs_opendir_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
fb69c64c
RS
2746{
2747 READDIRPLUS3res *res = command_data;
2748 struct nfs_cb_data *data = private_data;
2749 struct nfs_context *nfs = data->nfs;
2750 struct nfsdir *nfsdir = data->continue_data;
2751 struct entryplus3 *entry;
ecbd14a1 2752 uint64_t cookie = 0;
fb69c64c 2753
f3a75078 2754 assert(rpc->magic == RPC_CONTEXT_MAGIC);
fb69c64c
RS
2755
2756 if (status == RPC_STATUS_ERROR || (status == RPC_STATUS_SUCCESS && res->status == NFS3ERR_NOTSUPP) ){
a64a16a2
RS
2757 READDIR3args args;
2758
2759 args.dir = data->fh;
2760 args.cookie = cookie;
2452c57f 2761 memset(&args.cookieverf, 0, sizeof(cookieverf3));
a64a16a2 2762 args.count = 8192;
fb69c64c 2763
a64a16a2 2764 if (rpc_nfs3_readdir_async(nfs->rpc, nfs_opendir2_cb, &args, data) != 0) {
fb69c64c
RS
2765 rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR call for %s", data->path);
2766 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2767 nfs_free_nfsdir(nfsdir);
2768 data->continue_data = NULL;
2769 free_nfs_cb_data(data);
2770 return;
2771 }
2772 return;
2773 }
2774
2775 if (status == RPC_STATUS_CANCEL) {
2776 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2777 nfs_free_nfsdir(nfsdir);
2778 data->continue_data = NULL;
2779 free_nfs_cb_data(data);
2780 return;
2781 }
2782
2783 if (res->status != NFS3_OK) {
2784 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));
2785 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
2786 nfs_free_nfsdir(nfsdir);
2787 data->continue_data = NULL;
2788 free_nfs_cb_data(data);
2789 return;
84004dbf
RS
2790 }
2791
f390f181 2792 entry =res->READDIRPLUS3res_u.resok.reply.entries;
84004dbf
RS
2793 while (entry != NULL) {
2794 struct nfsdirent *nfsdirent;
2795
2796 nfsdirent = malloc(sizeof(struct nfsdirent));
2797 if (nfsdirent == NULL) {
2798 data->cb(-ENOMEM, nfs, "Failed to allocate dirent", data->private_data);
2799 nfs_free_nfsdir(nfsdir);
2800 data->continue_data = NULL;
2801 free_nfs_cb_data(data);
2802 return;
2803 }
ea98629a 2804 memset(nfsdirent, 0, sizeof(struct nfsdirent));
84004dbf
RS
2805 nfsdirent->name = strdup(entry->name);
2806 if (nfsdirent->name == NULL) {
2807 data->cb(-ENOMEM, nfs, "Failed to allocate dirent->name", data->private_data);
2808 nfs_free_nfsdir(nfsdir);
2809 data->continue_data = NULL;
2810 free_nfs_cb_data(data);
2811 return;
2812 }
2813 nfsdirent->inode = entry->fileid;
0804e67d
RS
2814 if (entry->name_attributes.attributes_follow) {
2815 nfsdirent->type = entry->name_attributes.post_op_attr_u.attributes.type;
2816 nfsdirent->mode = entry->name_attributes.post_op_attr_u.attributes.mode;
2817 nfsdirent->size = entry->name_attributes.post_op_attr_u.attributes.size;
2818
2819 nfsdirent->atime.tv_sec = entry->name_attributes.post_op_attr_u.attributes.atime.seconds;
2820 nfsdirent->atime.tv_usec = entry->name_attributes.post_op_attr_u.attributes.atime.nseconds/1000;
2821 nfsdirent->mtime.tv_sec = entry->name_attributes.post_op_attr_u.attributes.mtime.seconds;
2822 nfsdirent->mtime.tv_usec = entry->name_attributes.post_op_attr_u.attributes.mtime.nseconds/1000;
2823 nfsdirent->ctime.tv_sec = entry->name_attributes.post_op_attr_u.attributes.ctime.seconds;
2824 nfsdirent->ctime.tv_usec = entry->name_attributes.post_op_attr_u.attributes.ctime.nseconds/1000;
7bda8bad
RS
2825 nfsdirent->uid = entry->name_attributes.post_op_attr_u.attributes.uid;
2826 nfsdirent->gid = entry->name_attributes.post_op_attr_u.attributes.gid;
0804e67d
RS
2827 }
2828
84004dbf
RS
2829 nfsdirent->next = nfsdir->entries;
2830 nfsdir->entries = nfsdirent;
2831
2832 cookie = entry->cookie;
2833 entry = entry->nextentry;
2834 }
2835
f390f181 2836 if (res->READDIRPLUS3res_u.resok.reply.eof == 0) {
1a5b83c9
RS
2837 READDIRPLUS3args args;
2838
2839 args.dir = data->fh;
2840 args.cookie = cookie;
2841 memcpy(&args.cookieverf, res->READDIRPLUS3res_u.resok.cookieverf, sizeof(cookieverf3));
2842 args.dircount = 8192;
2843 args.maxcount = 8192;
2844
2845 if (rpc_nfs3_readdirplus_async(nfs->rpc, nfs_opendir_cb, &args, data) != 0) {
f390f181 2846 rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIRPLUS call for %s", data->path);
84004dbf
RS
2847 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2848 nfs_free_nfsdir(nfsdir);
2849 data->continue_data = NULL;
2850 free_nfs_cb_data(data);
2851 return;
2852 }
2853 return;
2854 }
2855
2856 /* steal the dirhandle */
2857 data->continue_data = NULL;
2858 nfsdir->current = nfsdir->entries;
2859
2860 data->cb(0, nfs, nfsdir, data->private_data);
2861 free_nfs_cb_data(data);
2862}
2863
2864static int nfs_opendir_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
2865{
1a5b83c9 2866 READDIRPLUS3args args;
84004dbf 2867
1a5b83c9
RS
2868 args.dir = data->fh;
2869 args.cookie = 0;
2870 memset(&args.cookieverf, 0, sizeof(cookieverf3));
2871 args.dircount = 8192;
2872 args.maxcount = 8192;
2873 if (rpc_nfs3_readdirplus_async(nfs->rpc, nfs_opendir_cb, &args, data) != 0) {
f390f181 2874 rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIRPLUS call for %s", data->path);
84004dbf
RS
2875 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2876 free_nfs_cb_data(data);
2877 return -1;
2878 }
2879 return 0;
2880}
2881
2882int nfs_opendir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
2883{
2884 struct nfsdir *nfsdir;
2885
2886 nfsdir = malloc(sizeof(struct nfsdir));
2887 if (nfsdir == NULL) {
cbbf9d3e 2888 rpc_set_error(nfs->rpc, "failed to allocate buffer for nfsdir");
84004dbf
RS
2889 return -1;
2890 }
ea98629a 2891 memset(nfsdir, 0, sizeof(struct nfsdir));
84004dbf
RS
2892
2893 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_opendir_continue_internal, nfsdir, free, 0) != 0) {
cbbf9d3e
RS
2894 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
2895 return -1;
84004dbf
RS
2896 }
2897
2898 return 0;
2899}
2900
2901
2902struct nfsdirent *nfs_readdir(struct nfs_context *nfs _U_, struct nfsdir *nfsdir)
2903{
2904 struct nfsdirent *nfsdirent = nfsdir->current;
2905
2906 if (nfsdir->current != NULL) {
2907 nfsdir->current = nfsdir->current->next;
2908 }
2909 return nfsdirent;
2910}
2911
2912
f893b680
RS
2913/*
2914 * closedir()
2915 */
84004dbf
RS
2916void nfs_closedir(struct nfs_context *nfs _U_, struct nfsdir *nfsdir)
2917{
2918 nfs_free_nfsdir(nfsdir);
2919}
2920
2921
f893b680
RS
2922/*
2923 * getcwd()
2924 */
2925void nfs_getcwd(struct nfs_context *nfs, const char **cwd)
2926{
2927 if (cwd) {
2928 *cwd = nfs->cwd;
2929 }
2930}
84004dbf
RS
2931
2932
2933/*
2934 * Async lseek()
2935 */
2936struct lseek_cb_data {
2937 struct nfs_context *nfs;
2938 struct nfsfh *nfsfh;
183451cf 2939 uint64_t offset;
84004dbf
RS
2940 nfs_cb cb;
2941 void *private_data;
2942};
2943
f3a75078 2944static void nfs_lseek_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
84004dbf
RS
2945{
2946 GETATTR3res *res;
2947 struct lseek_cb_data *data = private_data;
2948 struct nfs_context *nfs = data->nfs;
2949
f3a75078
RS
2950 assert(rpc->magic == RPC_CONTEXT_MAGIC);
2951
84004dbf
RS
2952 if (status == RPC_STATUS_ERROR) {
2953 data->cb(-EFAULT, nfs, command_data, data->private_data);
2954 free(data);
2955 return;
2956 }
2957 if (status == RPC_STATUS_CANCEL) {
2958 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2959 free(data);
2960 return;
2961 }
2962
2963 res = command_data;
2964 if (res->status != NFS3_OK) {
2965 rpc_set_error(nfs->rpc, "NFS: GETATTR failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
2966 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
2967 free(data);
2968 return;
2969 }
2970
2971 data->nfsfh->offset = data->offset + res->GETATTR3res_u.resok.obj_attributes.size;
2972 data->cb(0, nfs, &data->nfsfh->offset, data->private_data);
2973 free(data);
2974}
2975
183451cf 2976int nfs_lseek_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, int whence, nfs_cb cb, void *private_data)
84004dbf
RS
2977{
2978 struct lseek_cb_data *data;
463d59bf 2979 struct GETATTR3args args;
84004dbf
RS
2980
2981 if (whence == SEEK_SET) {
2982 nfsfh->offset = offset;
2983 cb(0, nfs, &nfsfh->offset, private_data);
2984 return 0;
2985 }
2986 if (whence == SEEK_CUR) {
2987 nfsfh->offset += offset;
2988 cb(0, nfs, &nfsfh->offset, private_data);
2989 return 0;
2990 }
2991
2992 data = malloc(sizeof(struct lseek_cb_data));
2993 if (data == NULL) {
2994 rpc_set_error(nfs->rpc, "Out Of Memory: Failed to malloc lseek cb data");
2995 return -1;
2996 }
2997
2998 data->nfs = nfs;
2999 data->nfsfh = nfsfh;
3000 data->offset = offset;
3001 data->cb = cb;
3002 data->private_data = private_data;
3003
463d59bf 3004 memset(&args, 0, sizeof(GETATTR3args));
2452c57f 3005 args.object = nfsfh->fh;
463d59bf
RS
3006
3007 if (rpc_nfs3_getattr_async(nfs->rpc, nfs_lseek_1_cb, &args, data) != 0) {
84004dbf
RS
3008 rpc_set_error(nfs->rpc, "RPC error: Failed to send LSEEK GETATTR call");
3009 free(data);
cbbf9d3e 3010 return -1;
84004dbf
RS
3011 }
3012 return 0;
3013}
3014
3015
3016
3017
3018/*
3019 * Async statvfs()
3020 */
f3a75078 3021static void nfs_statvfs_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
84004dbf
RS
3022{
3023 FSSTAT3res *res;
3024 struct nfs_cb_data *data = private_data;
3025 struct nfs_context *nfs = data->nfs;
3026 struct statvfs svfs;
3027
f3a75078
RS
3028 assert(rpc->magic == RPC_CONTEXT_MAGIC);
3029
84004dbf
RS
3030 if (status == RPC_STATUS_ERROR) {
3031 data->cb(-EFAULT, nfs, command_data, data->private_data);
3032 free_nfs_cb_data(data);
3033 return;
3034 }
3035 if (status == RPC_STATUS_CANCEL) {
3036 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
3037 free_nfs_cb_data(data);
3038 return;
3039 }
3040
3041 res = command_data;
3042 if (res->status != NFS3_OK) {
3043 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));
3044 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
3045 free_nfs_cb_data(data);
3046 return;
3047 }
3048
3049 svfs.f_bsize = 4096;
3050 svfs.f_frsize = 4096;
3051 svfs.f_blocks = res->FSSTAT3res_u.resok.tbytes/4096;
3052 svfs.f_bfree = res->FSSTAT3res_u.resok.fbytes/4096;
3053 svfs.f_bavail = res->FSSTAT3res_u.resok.abytes/4096;
3054 svfs.f_files = res->FSSTAT3res_u.resok.tfiles;
3055 svfs.f_ffree = res->FSSTAT3res_u.resok.ffiles;
252aa90d 3056#if !defined(ANDROID)
84004dbf
RS
3057 svfs.f_favail = res->FSSTAT3res_u.resok.afiles;
3058 svfs.f_fsid = 0;
3059 svfs.f_flag = 0;
3060 svfs.f_namemax = 256;
252aa90d 3061#endif
84004dbf
RS
3062
3063 data->cb(0, nfs, &svfs, data->private_data);
3064 free_nfs_cb_data(data);
3065}
3066
3067static int nfs_statvfs_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
3068{
0249c17b
RS
3069 FSSTAT3args args;
3070
3071 args.fsroot = data->fh;
3072 if (rpc_nfs3_fsstat_async(nfs->rpc, nfs_statvfs_1_cb, &args, data) != 0) {
84004dbf
RS
3073 rpc_set_error(nfs->rpc, "RPC error: Failed to send FSSTAT call for %s", data->path);
3074 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
3075 free_nfs_cb_data(data);
3076 return -1;
3077 }
3078 return 0;
3079}
3080
3081int nfs_statvfs_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
3082{
3083 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_statvfs_continue_internal, NULL, NULL, 0) != 0) {
cbbf9d3e 3084 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
84004dbf
RS
3085 return -1;
3086 }
3087
3088 return 0;
3089}
3090
3091
3092
3093
3094/*
3095 * Async readlink()
3096 */
f3a75078 3097static void nfs_readlink_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
84004dbf
RS
3098{
3099 READLINK3res *res;
3100 struct nfs_cb_data *data = private_data;
3101 struct nfs_context *nfs = data->nfs;
3102
f3a75078
RS
3103 assert(rpc->magic == RPC_CONTEXT_MAGIC);
3104
84004dbf
RS
3105 if (status == RPC_STATUS_ERROR) {
3106 data->cb(-EFAULT, nfs, command_data, data->private_data);
3107 free_nfs_cb_data(data);
3108 return;
3109 }
3110 if (status == RPC_STATUS_CANCEL) {
3111 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
3112 free_nfs_cb_data(data);
3113 return;
3114 }
3115
3116 res = command_data;
3117 if (res->status != NFS3_OK) {
3118 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));
3119 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
3120 free_nfs_cb_data(data);
3121 return;
3122 }
3123
3124
3125 data->cb(0, nfs, res->READLINK3res_u.resok.data, data->private_data);
3126 free_nfs_cb_data(data);
3127}
3128
3129static int nfs_readlink_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
3130{
16104b27
RS
3131 READLINK3args args;
3132
2452c57f 3133 args.symlink = data->fh;
16104b27 3134
7cd23ccc 3135 if (rpc_nfs3_readlink_async(nfs->rpc, nfs_readlink_1_cb, &args, data) != 0) {
84004dbf
RS
3136 rpc_set_error(nfs->rpc, "RPC error: Failed to send READLINK call for %s", data->path);
3137 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
3138 free_nfs_cb_data(data);
3139 return -1;
3140 }
3141 return 0;
3142}
3143
3144int nfs_readlink_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
3145{
3146 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_readlink_continue_internal, NULL, NULL, 0) != 0) {
cbbf9d3e 3147 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
84004dbf
RS
3148 return -1;
3149 }
3150
3151 return 0;
3152}
3153
3154
3155
3156
3157/*
3158 * Async chmod()
3159 */
f3a75078 3160static void nfs_chmod_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
84004dbf
RS
3161{
3162 struct nfs_cb_data *data = private_data;
3163 struct nfs_context *nfs = data->nfs;
3164 SETATTR3res *res;
3165
f3a75078
RS
3166 assert(rpc->magic == RPC_CONTEXT_MAGIC);
3167
84004dbf
RS
3168 if (status == RPC_STATUS_ERROR) {
3169 data->cb(-EFAULT, nfs, command_data, data->private_data);
3170 free_nfs_cb_data(data);
3171 return;
3172 }
3173 if (status == RPC_STATUS_CANCEL) {
3174 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
3175 free_nfs_cb_data(data);
3176 return;
3177 }
3178
3179 res = command_data;
3180 if (res->status != NFS3_OK) {
3181 rpc_set_error(nfs->rpc, "NFS: SETATTR failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
3182 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
3183 free_nfs_cb_data(data);
3184 return;
3185 }
3186
3187 data->cb(0, nfs, NULL, data->private_data);
3188 free_nfs_cb_data(data);
3189}
3190
3191static int nfs_chmod_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
3192{
3193 SETATTR3args args;
3194
ea98629a 3195 memset(&args, 0, sizeof(SETATTR3args));
2452c57f 3196 args.object = data->fh;
84004dbf
RS
3197 args.new_attributes.mode.set_it = 1;
3198 args.new_attributes.mode.set_mode3_u.mode = data->continue_int;
3199
b701254d 3200 if (rpc_nfs3_setattr_async(nfs->rpc, nfs_chmod_cb, &args, data) != 0) {
84004dbf
RS
3201 rpc_set_error(nfs->rpc, "RPC error: Failed to send SETATTR call for %s", data->path);
3202 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
3203 free_nfs_cb_data(data);
3204 return -1;
3205 }
3206 return 0;
3207}
3208
3209
3210int nfs_chmod_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data)
3211{
3212 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_chmod_continue_internal, NULL, NULL, mode) != 0) {
cbbf9d3e 3213 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
84004dbf
RS
3214 return -1;
3215 }
3216
3217 return 0;
3218}
3219
3220/*
3221 * Async fchmod()
3222 */
3223int nfs_fchmod_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int mode, nfs_cb cb, void *private_data)
3224{
3225 struct nfs_cb_data *data;
3226
3227 data = malloc(sizeof(struct nfs_cb_data));
3228 if (data == NULL) {
cbbf9d3e 3229 rpc_set_error(nfs->rpc, "out of memory. failed to allocate memory for nfs mount data");
84004dbf
RS
3230 return -1;
3231 }
ea98629a 3232 memset(data, 0, sizeof(struct nfs_cb_data));
84004dbf
RS
3233 data->nfs = nfs;
3234 data->cb = cb;
3235 data->private_data = private_data;
3236 data->continue_int = mode;
3237 data->fh.data.data_len = nfsfh->fh.data.data_len;
3238 data->fh.data.data_val = malloc(data->fh.data.data_len);
3239 if (data->fh.data.data_val == NULL) {
3240 rpc_set_error(nfs->rpc, "Out of memory: Failed to allocate fh");
3241 free_nfs_cb_data(data);
3242 return -1;
3243 }
3244 memcpy(data->fh.data.data_val, nfsfh->fh.data.data_val, data->fh.data.data_len);
3245
3246 if (nfs_chmod_continue_internal(nfs, data) != 0) {
3247 free_nfs_cb_data(data);
3248 return -1;
3249 }
3250
3251 return 0;
3252}
3253
3254
3255
3256/*
3257 * Async chown()
3258 */
f3a75078 3259static void nfs_chown_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
84004dbf
RS
3260{
3261 struct nfs_cb_data *data = private_data;
3262 struct nfs_context *nfs = data->nfs;
3263 SETATTR3res *res;
3264
f3a75078
RS
3265 assert(rpc->magic == RPC_CONTEXT_MAGIC);
3266
84004dbf
RS
3267 if (status == RPC_STATUS_ERROR) {
3268 data->cb(-EFAULT, nfs, command_data, data->private_data);
3269 free_nfs_cb_data(data);
3270 return;
3271 }
3272 if (status == RPC_STATUS_CANCEL) {
3273 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
3274 free_nfs_cb_data(data);
3275 return;
3276 }
3277
3278 res = command_data;
3279 if (res->status != NFS3_OK) {
3280 rpc_set_error(nfs->rpc, "NFS: SETATTR failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
3281 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
3282 free_nfs_cb_data(data);
3283 return;
3284 }
3285
3286 data->cb(0, nfs, NULL, data->private_data);
3287 free_nfs_cb_data(data);
3288}
3289
3290struct nfs_chown_data {
3291 uid_t uid;
3292 gid_t gid;
3293};
3294
3295static int nfs_chown_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
3296{
3297 SETATTR3args args;
3298 struct nfs_chown_data *chown_data = data->continue_data;
3299
ea98629a 3300 memset(&args, 0, sizeof(SETATTR3args));
2452c57f 3301 args.object = data->fh;
84004dbf
RS
3302 if (chown_data->uid != (uid_t)-1) {
3303 args.new_attributes.uid.set_it = 1;
3304 args.new_attributes.uid.set_uid3_u.uid = chown_data->uid;
3305 }
3306 if (chown_data->gid != (gid_t)-1) {
3307 args.new_attributes.gid.set_it = 1;
3308 args.new_attributes.gid.set_gid3_u.gid = chown_data->gid;
3309 }
3310
b701254d 3311 if (rpc_nfs3_setattr_async(nfs->rpc, nfs_chown_cb, &args, data) != 0) {
84004dbf
RS
3312 rpc_set_error(nfs->rpc, "RPC error: Failed to send SETATTR call for %s", data->path);
3313 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
3314 free_nfs_cb_data(data);
3315 return -1;
3316 }
3317 return 0;
3318}
3319
3320
3321int nfs_chown_async(struct nfs_context *nfs, const char *path, int uid, int gid, nfs_cb cb, void *private_data)
3322{
3323 struct nfs_chown_data *chown_data;
3324
3325 chown_data = malloc(sizeof(struct nfs_chown_data));
3326 if (chown_data == NULL) {
cbbf9d3e 3327 rpc_set_error(nfs->rpc, "Failed to allocate memory for chown data structure");
84004dbf
RS
3328 return -1;
3329 }
3330
3331 chown_data->uid = uid;
3332 chown_data->gid = gid;
3333
3334 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_chown_continue_internal, chown_data, free, 0) != 0) {
cbbf9d3e 3335 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
84004dbf
RS
3336 return -1;
3337 }
3338
3339 return 0;
3340}
3341
3342
3343/*
3344 * Async fchown()
3345 */
3346int nfs_fchown_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int uid, int gid, nfs_cb cb, void *private_data)
3347{
3348 struct nfs_cb_data *data;
3349 struct nfs_chown_data *chown_data;
3350
3351 chown_data = malloc(sizeof(struct nfs_chown_data));
3352 if (chown_data == NULL) {
cbbf9d3e 3353 rpc_set_error(nfs->rpc, "Failed to allocate memory for chown data structure");
84004dbf
RS
3354 return -1;
3355 }
3356
3357 chown_data->uid = uid;
3358 chown_data->gid = gid;
3359
3360
3361 data = malloc(sizeof(struct nfs_cb_data));
3362 if (data == NULL) {
cbbf9d3e 3363 rpc_set_error(nfs->rpc, "out of memory. failed to allocate memory for fchown data");
84004dbf
RS
3364 return -1;
3365 }
ea98629a 3366 memset(data, 0, sizeof(struct nfs_cb_data));
84004dbf
RS
3367 data->nfs = nfs;
3368 data->cb = cb;
3369 data->private_data = private_data;
3370 data->continue_data = chown_data;
3371 data->fh.data.data_len = nfsfh->fh.data.data_len;
3372 data->fh.data.data_val = malloc(data->fh.data.data_len);
3373 if (data->fh.data.data_val == NULL) {
3374 rpc_set_error(nfs->rpc, "Out of memory: Failed to allocate fh");
3375 free_nfs_cb_data(data);
3376 return -1;
3377 }
3378 memcpy(data->fh.data.data_val, nfsfh->fh.data.data_val, data->fh.data.data_len);
3379
3380
3381 if (nfs_chown_continue_internal(nfs, data) != 0) {
3382 free_nfs_cb_data(data);
3383 return -1;
3384 }
3385
3386 return 0;
3387}
3388
3389
3390
3391
3392
3393/*
3394 * Async utimes()
3395 */
f3a75078 3396static void nfs_utimes_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
84004dbf
RS
3397{
3398 struct nfs_cb_data *data = private_data;
3399 struct nfs_context *nfs = data->nfs;
3400 SETATTR3res *res;
3401
f3a75078
RS
3402 assert(rpc->magic == RPC_CONTEXT_MAGIC);
3403
84004dbf
RS
3404 if (status == RPC_STATUS_ERROR) {
3405 data->cb(-EFAULT, nfs, command_data, data->private_data);
3406 free_nfs_cb_data(data);
3407 return;
3408 }
3409 if (status == RPC_STATUS_CANCEL) {
3410 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
3411 free_nfs_cb_data(data);
3412 return;
3413 }
3414
3415 res = command_data;
3416 if (res->status != NFS3_OK) {
3417 rpc_set_error(nfs->rpc, "NFS: SETATTR failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
3418 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
3419 free_nfs_cb_data(data);
3420 return;
3421 }
3422
3423 data->cb(0, nfs, NULL, data->private_data);
3424 free_nfs_cb_data(data);
3425}
3426
3427static int nfs_utimes_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
3428{
3429 SETATTR3args args;
3430 struct timeval *utimes_data = data->continue_data;
3431
ea98629a 3432 memset(&args, 0, sizeof(SETATTR3args));
2452c57f 3433 args.object = data->fh;
84004dbf
RS
3434 if (utimes_data != NULL) {
3435 args.new_attributes.atime.set_it = SET_TO_CLIENT_TIME;
3436 args.new_attributes.atime.set_atime_u.atime.seconds = utimes_data[0].tv_sec;
3437 args.new_attributes.atime.set_atime_u.atime.nseconds = utimes_data[0].tv_usec * 1000;
3438 args.new_attributes.mtime.set_it = SET_TO_CLIENT_TIME;
3439 args.new_attributes.mtime.set_mtime_u.mtime.seconds = utimes_data[1].tv_sec;
3440 args.new_attributes.mtime.set_mtime_u.mtime.nseconds = utimes_data[1].tv_usec * 1000;
3441 } else {
3442 args.new_attributes.atime.set_it = SET_TO_SERVER_TIME;
3443 args.new_attributes.mtime.set_it = SET_TO_SERVER_TIME;
3444 }
3445
b701254d 3446 if (rpc_nfs3_setattr_async(nfs->rpc, nfs_utimes_cb, &args, data) != 0) {
84004dbf
RS
3447 rpc_set_error(nfs->rpc, "RPC error: Failed to send SETATTR call for %s", data->path);
3448 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
3449 free_nfs_cb_data(data);
3450 return -1;
3451 }
3452 return 0;
3453}
3454
3455
3456int nfs_utimes_async(struct nfs_context *nfs, const char *path, struct timeval *times, nfs_cb cb, void *private_data)
3457{
3458 struct timeval *new_times = NULL;
3459
3460 if (times != NULL) {
3461 new_times = malloc(sizeof(struct timeval)*2);
3462 if (new_times == NULL) {
cbbf9d3e 3463 rpc_set_error(nfs->rpc, "Failed to allocate memory for timeval structure");
84004dbf
RS
3464 return -1;
3465 }
3466
3467 memcpy(new_times, times, sizeof(struct timeval)*2);
3468 }
3469
3470 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_utimes_continue_internal, new_times, free, 0) != 0) {
cbbf9d3e 3471 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
84004dbf
RS
3472 return -1;
3473 }
3474
3475 return 0;
3476}
3477
3478/*
3479 * Async utime()
3480 */
3481int nfs_utime_async(struct nfs_context *nfs, const char *path, struct utimbuf *times, nfs_cb cb, void *private_data)
3482{
3483 struct timeval *new_times = NULL;
3484
3485 if (times != NULL) {
3486 new_times = malloc(sizeof(struct timeval)*2);
3487 if (new_times == NULL) {
cbbf9d3e 3488 rpc_set_error(nfs->rpc, "Failed to allocate memory for timeval structure");
84004dbf
RS
3489 return -1;
3490 }
3491
3492 new_times[0].tv_sec = times->actime;
3493 new_times[0].tv_usec = 0;
3494 new_times[1].tv_sec = times->modtime;
3495 new_times[1].tv_usec = 0;
3496 }
3497
3498 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_utimes_continue_internal, new_times, free, 0) != 0) {
cbbf9d3e 3499 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
84004dbf
RS
3500 return -1;
3501 }
3502
3503 return 0;
3504}
84004dbf
RS
3505
3506
3507/*
3508 * Async access()
3509 */
f3a75078 3510static void nfs_access_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
84004dbf
RS
3511{
3512 ACCESS3res *res;
3513 struct nfs_cb_data *data = private_data;
3514 struct nfs_context *nfs = data->nfs;
3515 unsigned int nfsmode = 0;
3516
f3a75078
RS
3517 assert(rpc->magic == RPC_CONTEXT_MAGIC);
3518
84004dbf
RS
3519 if (status == RPC_STATUS_ERROR) {
3520 data->cb(-EFAULT, nfs, command_data, data->private_data);
3521 free_nfs_cb_data(data);
3522 return;
3523 }
3524 if (status == RPC_STATUS_CANCEL) {
3525 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
3526 free_nfs_cb_data(data);
3527 return;
3528 }
3529
3530 res = command_data;
3531 if (res->status != NFS3_OK) {
3532 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));
3533 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
3534 free_nfs_cb_data(data);
3535 return;
3536 }
3537
3538 if (data->continue_int & R_OK) {
3539 nfsmode |= ACCESS3_READ;
3540 }
3541 if (data->continue_int & W_OK) {
3542 nfsmode |= ACCESS3_MODIFY;
3543 }
3544 if (data->continue_int & X_OK) {
3545 nfsmode |= ACCESS3_EXECUTE;
3546 }
3547
3548 if (res->ACCESS3res_u.resok.access != nfsmode) {
3549 rpc_set_error(nfs->rpc, "NFS: ACCESS denied. Required access %c%c%c. Allowed access %c%c%c",
3550 nfsmode&ACCESS3_READ?'r':'-',
3551 nfsmode&ACCESS3_MODIFY?'w':'-',
3552 nfsmode&ACCESS3_EXECUTE?'x':'-',
3553 res->ACCESS3res_u.resok.access&ACCESS3_READ?'r':'-',
3554 res->ACCESS3res_u.resok.access&ACCESS3_MODIFY?'w':'-',
3555 res->ACCESS3res_u.resok.access&ACCESS3_EXECUTE?'x':'-');
3556 data->cb(-EACCES, nfs, rpc_get_error(nfs->rpc), data->private_data);
3557 free_nfs_cb_data(data);
3558 return;
3559 }
3560
3561 data->cb(0, nfs, NULL, data->private_data);
3562 free_nfs_cb_data(data);
3563}
3564
3565static int nfs_access_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
3566{
3567 int nfsmode = 0;
463d59bf 3568 ACCESS3args args;
84004dbf
RS
3569
3570 if (data->continue_int & R_OK) {
3571 nfsmode |= ACCESS3_READ;
3572 }
3573 if (data->continue_int & W_OK) {
3574 nfsmode |= ACCESS3_MODIFY;
3575 }
3576 if (data->continue_int & X_OK) {
3577 nfsmode |= ACCESS3_EXECUTE;
3578 }
3579
463d59bf 3580 memset(&args, 0, sizeof(ACCESS3args));
2452c57f 3581 args.object = data->fh;
463d59bf
RS
3582 args.access = nfsmode;
3583
3584 if (rpc_nfs3_access_async(nfs->rpc, nfs_access_cb, &args, data) != 0) {
84004dbf
RS
3585 rpc_set_error(nfs->rpc, "RPC error: Failed to send OPEN ACCESS call for %s", data->path);
3586 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
3587 free_nfs_cb_data(data);
3588 return -1;
3589 }
3590 return 0;
3591}
3592
3593int nfs_access_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data)
3594{
3595 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_access_continue_internal, NULL, NULL, mode) != 0) {
cbbf9d3e
RS
3596 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
3597 return -1;
84004dbf
RS
3598 }
3599
3600 return 0;
3601}
3602
3603
3604
3605/*
3606 * Async symlink()
3607 */
3608struct nfs_symlink_data {
3609 char *oldpath;
3610 char *newpathparent;
3611 char *newpathobject;
3612};
3613
3614static void free_nfs_symlink_data(void *mem)
3615{
3616 struct nfs_symlink_data *data = mem;
3617
3618 if (data->oldpath != NULL) {
3619 free(data->oldpath);
3620 }
3621 if (data->newpathparent != NULL) {
3622 free(data->newpathparent);
3623 }
3624 if (data->newpathobject != NULL) {
3625 free(data->newpathobject);
3626 }
3627 free(data);
3628}
3629
f3a75078 3630static void nfs_symlink_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
84004dbf
RS
3631{
3632 SYMLINK3res *res;
3633 struct nfs_cb_data *data = private_data;
3634 struct nfs_context *nfs = data->nfs;
3635 struct nfs_symlink_data *symlink_data = data->continue_data;
3636
f3a75078
RS
3637 assert(rpc->magic == RPC_CONTEXT_MAGIC);
3638
84004dbf
RS
3639 if (status == RPC_STATUS_ERROR) {
3640 data->cb(-EFAULT, nfs, command_data, data->private_data);
3641 free_nfs_cb_data(data);
3642 return;
3643 }
3644 if (status == RPC_STATUS_CANCEL) {
3645 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
3646 free_nfs_cb_data(data);
3647 return;
3648 }
3649
3650 res = command_data;
3651 if (res->status != NFS3_OK) {
3652 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));
3653 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
3654 free_nfs_cb_data(data);
3655 return;
3656 }
3657
3658 data->cb(0, nfs, NULL, data->private_data);
3659 free_nfs_cb_data(data);
3660}
3661
3662static int nfs_symlink_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
3663{
3664 struct nfs_symlink_data *symlink_data = data->continue_data;
87f81c85 3665 SYMLINK3args args;
84004dbf 3666
87f81c85 3667 memset(&args, 0, sizeof(SYMLINK3args));
2452c57f 3668 args.where.dir = data->fh;
87f81c85
RS
3669 args.where.name = symlink_data->newpathobject;
3670 args.symlink.symlink_attributes.mode.set_it = 1;
3671 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;
3672 args.symlink.symlink_data = symlink_data->oldpath;
8e255816 3673
87f81c85 3674 if (rpc_nfs3_symlink_async(nfs->rpc, nfs_symlink_cb, &args, data) != 0) {
84004dbf
RS
3675 rpc_set_error(nfs->rpc, "RPC error: Failed to send SYMLINK call for %s", data->path);
3676 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
3677 free_nfs_cb_data(data);
3678 return -1;
3679 }
3680 return 0;
3681}
3682
3683int nfs_symlink_async(struct nfs_context *nfs, const char *oldpath, const char *newpath, nfs_cb cb, void *private_data)
3684{
3685 char *ptr;
3686 struct nfs_symlink_data *symlink_data;
3687
3688 symlink_data = malloc(sizeof(struct nfs_symlink_data));
3689 if (symlink_data == NULL) {
cbbf9d3e 3690 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for symlink data");
84004dbf
RS
3691 return -1;
3692 }
ea98629a 3693 memset(symlink_data, 0, sizeof(struct nfs_symlink_data));
84004dbf
RS
3694
3695 symlink_data->oldpath = strdup(oldpath);
3696 if (symlink_data->oldpath == NULL) {
cbbf9d3e 3697 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for oldpath");
84004dbf 3698 free_nfs_symlink_data(symlink_data);
cbbf9d3e 3699 return -1;
84004dbf
RS
3700 }
3701
3702 symlink_data->newpathparent = strdup(newpath);
3703 if (symlink_data->newpathparent == NULL) {
cbbf9d3e 3704 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for new path");
84004dbf 3705 free_nfs_symlink_data(symlink_data);
cbbf9d3e 3706 return -1;
84004dbf
RS
3707 }
3708
93e9306f 3709 ptr = strrchr(symlink_data->newpathparent, '/');
84004dbf 3710 if (ptr == NULL) {
cbbf9d3e 3711 rpc_set_error(nfs->rpc, "Invalid path %s", oldpath);
84004dbf 3712 free_nfs_symlink_data(symlink_data);
cbbf9d3e 3713 return -1;
84004dbf
RS
3714 }
3715 *ptr = 0;
3716 ptr++;
3717
3718 symlink_data->newpathobject = strdup(ptr);
3719 if (symlink_data->newpathobject == NULL) {
cbbf9d3e 3720 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for new path");
84004dbf 3721 free_nfs_symlink_data(symlink_data);
cbbf9d3e 3722 return -1;
84004dbf
RS
3723 }
3724
3725 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
3726 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
3727 return -1;
84004dbf
RS
3728 }
3729
3730 return 0;
3731}
3732
3733
3734
3735/*
3736 * Async rename()
3737 */
3738struct nfs_rename_data {
3739 char *oldpath;
3740 char *oldobject;
3741 struct nfs_fh3 olddir;
3742 char *newpath;
3743 char *newobject;
3744 struct nfs_fh3 newdir;
3745};
3746
3747static void free_nfs_rename_data(void *mem)
3748{
3749 struct nfs_rename_data *data = mem;
3750
3751 if (data->oldpath != NULL) {
3752 free(data->oldpath);
3753 }
3754 if (data->olddir.data.data_val != NULL) {
3755 free(data->olddir.data.data_val);
3756 }
3757 if (data->newpath != NULL) {
3758 free(data->newpath);
3759 }
3760 if (data->newdir.data.data_val != NULL) {
3761 free(data->newdir.data.data_val);
3762 }
3763 free(data);
3764}
3765
f3a75078 3766static void nfs_rename_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
84004dbf
RS
3767{
3768 RENAME3res *res;
3769 struct nfs_cb_data *data = private_data;
3770 struct nfs_context *nfs = data->nfs;
3771 struct nfs_rename_data *rename_data = data->continue_data;
3772
f3a75078
RS
3773 assert(rpc->magic == RPC_CONTEXT_MAGIC);
3774
84004dbf
RS
3775 if (status == RPC_STATUS_ERROR) {
3776 data->cb(-EFAULT, nfs, command_data, data->private_data);
3777 free_nfs_cb_data(data);
3778 return;
3779 }
3780 if (status == RPC_STATUS_CANCEL) {
3781 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
3782 free_nfs_cb_data(data);
3783 return;
3784 }
3785
3786 res = command_data;
3787 if (res->status != NFS3_OK) {
3788 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));
3789 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
3790 free_nfs_cb_data(data);
3791 return;
3792 }
3793
3794 data->cb(0, nfs, NULL, data->private_data);
3795 free_nfs_cb_data(data);
3796}
3797
3798static int nfs_rename_continue_2_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
3799{
3800 struct nfs_rename_data *rename_data = data->continue_data;
5940c705 3801 RENAME3args args;
84004dbf
RS
3802
3803 /* steal the filehandle */
2452c57f 3804 rename_data->newdir = data->fh;
84004dbf
RS
3805 data->fh.data.data_val = NULL;
3806
5940c705
RS
3807 args.from.dir = rename_data->olddir;
3808 args.from.name = rename_data->oldobject;
3809 args.to.dir = rename_data->newdir;
3810 args.to.name = rename_data->newobject;
3811 if (rpc_nfs3_rename_async(nfs->rpc, nfs_rename_cb, &args, data) != 0) {
84004dbf
RS
3812 rpc_set_error(nfs->rpc, "RPC error: Failed to send RENAME call for %s", data->path);
3813 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
3814 free_nfs_cb_data(data);
3815 return -1;
3816 }
3817 return 0;
3818}
3819
3820
3821static int nfs_rename_continue_1_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
3822{
3823 struct nfs_rename_data *rename_data = data->continue_data;
3824
3825 /* steal the filehandle */
2452c57f 3826 rename_data->olddir = data->fh;
84004dbf
RS
3827 data->fh.data.data_val = NULL;
3828
3829 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) {
3830 rpc_set_error(nfs->rpc, "RPC error: Failed to send LOOKUP call for %s", rename_data->newpath);
3831 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
3832 free_nfs_cb_data(data);
3833 return -1;
3834 }
3835 data->continue_data = NULL;
3836 free_nfs_cb_data(data);
3837
3838 return 0;
3839}
3840
3841
3842int nfs_rename_async(struct nfs_context *nfs, const char *oldpath, const char *newpath, nfs_cb cb, void *private_data)
3843{
3844 char *ptr;
3845 struct nfs_rename_data *rename_data;
3846
3847 rename_data = malloc(sizeof(struct nfs_rename_data));
3848 if (rename_data == NULL) {
cbbf9d3e 3849 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for rename data");
84004dbf
RS
3850 return -1;
3851 }
ea98629a 3852 memset(rename_data, 0, sizeof(struct nfs_rename_data));
84004dbf
RS
3853
3854 rename_data->oldpath = strdup(oldpath);
3855 if (rename_data->oldpath == NULL) {
cbbf9d3e 3856 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for oldpath");
84004dbf 3857 free_nfs_rename_data(rename_data);
cbbf9d3e 3858 return -1;
84004dbf 3859 }
93e9306f 3860 ptr = strrchr(rename_data->oldpath, '/');
84004dbf 3861 if (ptr == NULL) {
cbbf9d3e 3862 rpc_set_error(nfs->rpc, "Invalid path %s", oldpath);
84004dbf 3863 free_nfs_rename_data(rename_data);
cbbf9d3e 3864 return -1;
84004dbf
RS
3865 }
3866 *ptr = 0;
3867 ptr++;
3868 rename_data->oldobject = ptr;
3869
3870
3871 rename_data->newpath = strdup(newpath);
3872 if (rename_data->newpath == NULL) {
cbbf9d3e 3873 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for newpath");
84004dbf 3874 free_nfs_rename_data(rename_data);
cbbf9d3e 3875 return -1;
84004dbf 3876 }
93e9306f 3877 ptr = strrchr(rename_data->newpath, '/');
84004dbf 3878 if (ptr == NULL) {
cbbf9d3e 3879 rpc_set_error(nfs->rpc, "Invalid path %s", newpath);
84004dbf 3880 free_nfs_rename_data(rename_data);
cbbf9d3e 3881 return -1;
84004dbf
RS
3882 }
3883 *ptr = 0;
3884 ptr++;
3885 rename_data->newobject = ptr;
3886
3887
3888 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
3889 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
3890 return -1;
84004dbf
RS
3891 }
3892
3893 return 0;
3894}
3895
3896
3897/*
3898 * Async link()
3899 */
3900struct nfs_link_data {
3901 char *oldpath;
3902 struct nfs_fh3 oldfh;
3903 char *newpath;
3904 char *newobject;
3905 struct nfs_fh3 newdir;
3906};
3907
3908static void free_nfs_link_data(void *mem)
3909{
3910 struct nfs_link_data *data = mem;
3911
3912 if (data->oldpath != NULL) {
3913 free(data->oldpath);
3914 }
3915 if (data->oldfh.data.data_val != NULL) {
3916 free(data->oldfh.data.data_val);
3917 }
3918 if (data->newpath != NULL) {
3919 free(data->newpath);
3920 }
3921 if (data->newdir.data.data_val != NULL) {
3922 free(data->newdir.data.data_val);
3923 }
3924 free(data);
3925}
3926
f3a75078 3927static void nfs_link_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
84004dbf
RS
3928{
3929 LINK3res *res;
3930 struct nfs_cb_data *data = private_data;
3931 struct nfs_context *nfs = data->nfs;
3932 struct nfs_link_data *link_data = data->continue_data;
3933
f3a75078
RS
3934 assert(rpc->magic == RPC_CONTEXT_MAGIC);
3935
84004dbf
RS
3936 if (status == RPC_STATUS_ERROR) {
3937 data->cb(-EFAULT, nfs, command_data, data->private_data);
3938 free_nfs_cb_data(data);
3939 return;
3940 }
3941 if (status == RPC_STATUS_CANCEL) {
3942 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
3943 free_nfs_cb_data(data);
3944 return;
3945 }
3946
3947 res = command_data;
3948 if (res->status != NFS3_OK) {
3949 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));
3950 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
3951 free_nfs_cb_data(data);
3952 return;
3953 }
3954
3955 data->cb(0, nfs, NULL, data->private_data);
3956 free_nfs_cb_data(data);
3957}
3958
3959static int nfs_link_continue_2_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
3960{
3961 struct nfs_link_data *link_data = data->continue_data;
560f9434 3962 LINK3args args;
84004dbf
RS
3963
3964 /* steal the filehandle */
2452c57f 3965 link_data->newdir = data->fh;
84004dbf
RS
3966 data->fh.data.data_val = NULL;
3967
560f9434
RS
3968 memset(&args, 0, sizeof(LINK3args));
3969 args.file = link_data->oldfh;
3970 args.link.dir = link_data->newdir;
3971 args.link.name = link_data->newobject;
3972 if (rpc_nfs3_link_async(nfs->rpc, nfs_link_cb, &args, data) != 0) {
84004dbf
RS
3973 rpc_set_error(nfs->rpc, "RPC error: Failed to send LINK call for %s", data->path);
3974 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
3975 free_nfs_cb_data(data);
3976 return -1;
3977 }
3978 return 0;
3979}
3980
3981
3982static int nfs_link_continue_1_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
3983{
3984 struct nfs_link_data *link_data = data->continue_data;
3985
3986 /* steal the filehandle */
2452c57f 3987 link_data->oldfh = data->fh;
84004dbf
RS
3988 data->fh.data.data_val = NULL;
3989
3990 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) {
3991 rpc_set_error(nfs->rpc, "RPC error: Failed to send LOOKUP call for %s", link_data->newpath);
3992 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
3993 free_nfs_cb_data(data);
3994 return -1;
3995 }
3996 data->continue_data = NULL;
3997 free_nfs_cb_data(data);
3998
3999 return 0;
4000}
4001
4002
4003int nfs_link_async(struct nfs_context *nfs, const char *oldpath, const char *newpath, nfs_cb cb, void *private_data)
4004{
4005 char *ptr;
4006 struct nfs_link_data *link_data;
4007
4008 link_data = malloc(sizeof(struct nfs_link_data));
4009 if (link_data == NULL) {
cbbf9d3e 4010 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for link data");
84004dbf
RS
4011 return -1;
4012 }
ea98629a 4013 memset(link_data, 0, sizeof(struct nfs_link_data));
84004dbf
RS
4014
4015 link_data->oldpath = strdup(oldpath);
4016 if (link_data->oldpath == NULL) {
cbbf9d3e 4017 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for oldpath");
84004dbf 4018 free_nfs_link_data(link_data);
cbbf9d3e 4019 return -1;
84004dbf
RS
4020 }
4021
4022 link_data->newpath = strdup(newpath);
4023 if (link_data->newpath == NULL) {
cbbf9d3e 4024 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for newpath");
84004dbf 4025 free_nfs_link_data(link_data);
cbbf9d3e 4026 return -1;
84004dbf 4027 }
93e9306f 4028 ptr = strrchr(link_data->newpath, '/');
84004dbf 4029 if (ptr == NULL) {
cbbf9d3e 4030 rpc_set_error(nfs->rpc, "Invalid path %s", newpath);
84004dbf 4031 free_nfs_link_data(link_data);
cbbf9d3e 4032 return -1;
84004dbf
RS
4033 }
4034 *ptr = 0;
4035 ptr++;
4036 link_data->newobject = ptr;
4037
4038
4039 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
4040 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
4041 return -1;
84004dbf
RS
4042 }
4043
4044 return 0;
4045}
4046
4047
4048//qqq replace later with lseek()
183451cf 4049uint64_t nfs_get_current_offset(struct nfsfh *nfsfh)
84004dbf
RS
4050{
4051 return nfsfh->offset;
4052}
4053
17ef62fa
RS
4054
4055
4056/*
4057 * Get the maximum supported READ3 size by the server
4058 */
183451cf 4059uint64_t nfs_get_readmax(struct nfs_context *nfs)
17ef62fa
RS
4060{
4061 return nfs->readmax;
4062}
4063
4064/*
4065 * Get the maximum supported WRITE3 size by the server
4066 */
183451cf 4067uint64_t nfs_get_writemax(struct nfs_context *nfs)
17ef62fa 4068{
e7f3a781 4069 return nfs->writemax;
17ef62fa 4070}
1896d37b 4071
d43a8953
PL
4072void nfs_set_tcp_syncnt(struct nfs_context *nfs, int v) {
4073 rpc_set_tcp_syncnt(nfs->rpc, v);
4074}
4075
4076void nfs_set_uid(struct nfs_context *nfs, int uid) {
4077 rpc_set_uid(nfs->rpc, uid);
4078}
4079
4080void nfs_set_gid(struct nfs_context *nfs, int gid) {
4081 rpc_set_gid(nfs->rpc, gid);
4082}
4083
1896d37b
RS
4084void nfs_set_error(struct nfs_context *nfs, char *error_string, ...)
4085{
4086 va_list ap;
1e8994af 4087 char *str = NULL;
1896d37b 4088
1e8994af 4089 va_start(ap, error_string);
2606f9bb
RS
4090 str = malloc(1024);
4091 vsnprintf(str, 1024, error_string, ap);
1896d37b
RS
4092 if (nfs->rpc->error_string != NULL) {
4093 free(nfs->rpc->error_string);
4094 }
1896d37b 4095 nfs->rpc->error_string = str;
f893b680 4096 va_end(ap);
1896d37b 4097}
7f0242ca
RS
4098
4099
4100
4101struct mount_cb_data {
4102 rpc_cb cb;
4103 void *private_data;
4104 char *server;
4105};
4106
4107static void free_mount_cb_data(struct mount_cb_data *data)
4108{
4109 if (data->server != NULL) {
4110 free(data->server);
4111 data->server = NULL;
4112 }
4113
4114 free(data);
4115}
4116
4117static void mount_export_5_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
4118{
4119 struct mount_cb_data *data = private_data;
4120
f3a75078
RS
4121 assert(rpc->magic == RPC_CONTEXT_MAGIC);
4122
4123 if (status == RPC_STATUS_ERROR) {
7f0242ca
RS
4124 data->cb(rpc, -EFAULT, command_data, data->private_data);
4125 free_mount_cb_data(data);
4126 return;
4127 }
4128 if (status == RPC_STATUS_CANCEL) {
4129 data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
4130 free_mount_cb_data(data);
4131 return;
4132 }
4133
4134 data->cb(rpc, 0, command_data, data->private_data);
4135 if (rpc_disconnect(rpc, "normal disconnect") != 0) {
4136 rpc_set_error(rpc, "Failed to disconnect\n");
4137 }
4138 free_mount_cb_data(data);
4139}
4140
4141static void mount_export_4_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
4142{
4143 struct mount_cb_data *data = private_data;
4144
f3a75078
RS
4145 assert(rpc->magic == RPC_CONTEXT_MAGIC);
4146
14a062eb
RS
4147 /* Dont want any more callbacks even if the socket is closed */
4148 rpc->connect_cb = NULL;
4149
7f0242ca
RS
4150 if (status == RPC_STATUS_ERROR) {
4151 data->cb(rpc, -EFAULT, command_data, data->private_data);
4152 free_mount_cb_data(data);
4153 return;
4154 }
4155 if (status == RPC_STATUS_CANCEL) {
4156 data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
4157 free_mount_cb_data(data);
4158 return;
4159 }
4160
eda77ec3 4161 if (rpc_mount3_export_async(rpc, mount_export_5_cb, data) != 0) {
7f0242ca
RS
4162 data->cb(rpc, -ENOMEM, command_data, data->private_data);
4163 free_mount_cb_data(data);
4164 return;
4165 }
4166}
4167
4168static void mount_export_3_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
4169{
4170 struct mount_cb_data *data = private_data;
4171 uint32_t mount_port;
4172
f3a75078
RS
4173 assert(rpc->magic == RPC_CONTEXT_MAGIC);
4174
4175 if (status == RPC_STATUS_ERROR) {
7f0242ca
RS
4176 data->cb(rpc, -EFAULT, command_data, data->private_data);
4177 free_mount_cb_data(data);
4178 return;
4179 }
4180 if (status == RPC_STATUS_CANCEL) {
4181 data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
4182 free_mount_cb_data(data);
4183 return;
4184 }
4185
4186 mount_port = *(uint32_t *)command_data;
4187 if (mount_port == 0) {
4188 rpc_set_error(rpc, "RPC error. Mount program is not available");
4189 data->cb(rpc, -ENOENT, command_data, data->private_data);
4190 free_mount_cb_data(data);
4191 return;
4192 }
4193
4194 rpc_disconnect(rpc, "normal disconnect");
4195 if (rpc_connect_async(rpc, data->server, mount_port, mount_export_4_cb, data) != 0) {
4196 data->cb(rpc, -ENOMEM, command_data, data->private_data);
4197 free_mount_cb_data(data);
4198 return;
4199 }
4200}
4201
4202static void mount_export_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
4203{
4204 struct mount_cb_data *data = private_data;
4205
f3a75078
RS
4206 assert(rpc->magic == RPC_CONTEXT_MAGIC);
4207
7f0242ca
RS
4208 if (status == RPC_STATUS_ERROR) {
4209 data->cb(rpc, -EFAULT, command_data, data->private_data);
4210 free_mount_cb_data(data);
4211 return;
4212 }
4213 if (status == RPC_STATUS_CANCEL) {
4214 data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
4215 free_mount_cb_data(data);
4216 return;
4217 }
4218
5c6b1176 4219 if (rpc_pmap_getport_async(rpc, MOUNT_PROGRAM, MOUNT_V3, IPPROTO_TCP, mount_export_3_cb, private_data) != 0) {
7f0242ca
RS
4220 data->cb(rpc, -ENOMEM, command_data, data->private_data);
4221 free_mount_cb_data(data);
4222 return;
4223 }
4224}
4225
4226static void mount_export_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
4227{
4228 struct mount_cb_data *data = private_data;
4229
f3a75078
RS
4230 assert(rpc->magic == RPC_CONTEXT_MAGIC);
4231
14a062eb
RS
4232 /* Dont want any more callbacks even if the socket is closed */
4233 rpc->connect_cb = NULL;
4234
7f0242ca
RS
4235 if (status == RPC_STATUS_ERROR) {
4236 data->cb(rpc, -EFAULT, command_data, data->private_data);
4237 free_mount_cb_data(data);
4238 return;
4239 }
4240 if (status == RPC_STATUS_CANCEL) {
4241 data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
4242 free_mount_cb_data(data);
4243 return;
4244 }
4245
4246 if (rpc_pmap_null_async(rpc, mount_export_2_cb, data) != 0) {
4247 data->cb(rpc, -ENOMEM, command_data, data->private_data);
4248 free_mount_cb_data(data);
4249 return;
4250 }
4251}
4252
4253int mount_getexports_async(struct rpc_context *rpc, const char *server, rpc_cb cb, void *private_data)
4254{
4255 struct mount_cb_data *data;
4256
f3a75078
RS
4257 assert(rpc->magic == RPC_CONTEXT_MAGIC);
4258
7f0242ca
RS
4259 data = malloc(sizeof(struct mount_cb_data));
4260 if (data == NULL) {
4261 return -1;
4262 }
ea98629a 4263 memset(data, 0, sizeof(struct mount_cb_data));
7f0242ca
RS
4264 data->cb = cb;
4265 data->private_data = private_data;
4266 data->server = strdup(server);
4267 if (data->server == NULL) {
4268 free_mount_cb_data(data);
4269 return -1;
4270 }
4271 if (rpc_connect_async(rpc, data->server, 111, mount_export_1_cb, data) != 0) {
4272 free_mount_cb_data(data);
4273 return -1;
4274 }
4275
4276 return 0;
4277}
4278
df5af25f
RS
4279struct rpc_context *nfs_get_rpc_context(struct nfs_context *nfs)
4280{
f3a75078 4281 assert(nfs->rpc->magic == RPC_CONTEXT_MAGIC);
df5af25f
RS
4282 return nfs->rpc;
4283}
4284
b077fdeb
RS
4285const char *nfs_get_server(struct nfs_context *nfs) {
4286 return nfs->server;
4287}
4288
4289const char *nfs_get_export(struct nfs_context *nfs) {
4290 return nfs->export;
4291}
0ad9a1f1 4292
8724c833
RS
4293const struct nfs_fh3 *nfs_get_rootfh(struct nfs_context *nfs) {
4294 return &nfs->rootfh;
4295}
fa3c25be
RS
4296
4297struct nfs_fh3 *nfs_get_fh(struct nfsfh *nfsfh) {
4298 return &nfsfh->fh;
4299}