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