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