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