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