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