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