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