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