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