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