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