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