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