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