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