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