Add a high-level async function to read the export list
[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;
649 st.st_nlink = res->GETATTR3res_u.resok.obj_attributes.nlink;
650 st.st_uid = res->GETATTR3res_u.resok.obj_attributes.uid;
651 st.st_gid = res->GETATTR3res_u.resok.obj_attributes.gid;
652 st.st_rdev = 0;
653 st.st_size = res->GETATTR3res_u.resok.obj_attributes.size;
654 st.st_blksize = 4096;
655 st.st_blocks = res->GETATTR3res_u.resok.obj_attributes.size / 4096;
656 st.st_atime = res->GETATTR3res_u.resok.obj_attributes.atime.seconds;
657 st.st_mtime = res->GETATTR3res_u.resok.obj_attributes.mtime.seconds;
658 st.st_ctime = res->GETATTR3res_u.resok.obj_attributes.ctime.seconds;
659
660 data->cb(0, nfs, &st, data->private_data);
661 free_nfs_cb_data(data);
662}
663
664static int nfs_stat_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
665{
666 if (rpc_nfs_getattr_async(nfs->rpc, nfs_stat_1_cb, &data->fh, data) != 0) {
667 rpc_set_error(nfs->rpc, "RPC error: Failed to send STAT GETATTR call for %s", data->path);
668 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
669 free_nfs_cb_data(data);
670 return -1;
671 }
672 return 0;
673}
674
675int nfs_stat_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
676{
677 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_stat_continue_internal, NULL, NULL, 0) != 0) {
cbbf9d3e 678 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
84004dbf
RS
679 return -1;
680 }
681
682 return 0;
683}
684
685
686
687
688
689/*
690 * Async open()
691 */
692static void nfs_open_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
693{
694 ACCESS3res *res;
695 struct nfs_cb_data *data = private_data;
696 struct nfs_context *nfs = data->nfs;
697 struct nfsfh *nfsfh;
698 unsigned int nfsmode = 0;
699
700 if (status == RPC_STATUS_ERROR) {
701 data->cb(-EFAULT, nfs, command_data, data->private_data);
702 free_nfs_cb_data(data);
703 return;
704 }
705 if (status == RPC_STATUS_CANCEL) {
706 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
707 free_nfs_cb_data(data);
708 return;
709 }
710
711 res = command_data;
712 if (res->status != NFS3_OK) {
713 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));
714 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
715 free_nfs_cb_data(data);
716 return;
717 }
718
719 if (data->continue_int & O_WRONLY) {
720 nfsmode |= ACCESS3_MODIFY;
721 }
722 if (data->continue_int & O_RDWR) {
723 nfsmode |= ACCESS3_READ|ACCESS3_MODIFY;
724 }
725 if (!(data->continue_int & (O_WRONLY|O_RDWR))) {
726 nfsmode |= ACCESS3_READ;
727 }
728
729
730 if (res->ACCESS3res_u.resok.access != nfsmode) {
731 rpc_set_error(nfs->rpc, "NFS: ACCESS denied. Required access %c%c%c. Allowed access %c%c%c",
732 nfsmode&ACCESS3_READ?'r':'-',
733 nfsmode&ACCESS3_MODIFY?'w':'-',
734 nfsmode&ACCESS3_EXECUTE?'x':'-',
735 res->ACCESS3res_u.resok.access&ACCESS3_READ?'r':'-',
736 res->ACCESS3res_u.resok.access&ACCESS3_MODIFY?'w':'-',
737 res->ACCESS3res_u.resok.access&ACCESS3_EXECUTE?'x':'-');
738 data->cb(-EACCES, nfs, rpc_get_error(nfs->rpc), data->private_data);
739 free_nfs_cb_data(data);
740 return;
741 }
742
743 nfsfh = malloc(sizeof(struct nfsfh));
744 if (nfsfh == NULL) {
745 rpc_set_error(nfs->rpc, "NFS: Failed to allocate nfsfh structure");
746 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
747 free_nfs_cb_data(data);
748 return;
749 }
750 bzero(nfsfh, sizeof(struct nfsfh));
751
752 if (data->continue_int & O_SYNC) {
753 nfsfh->is_sync = 1;
754 }
755
756 /* steal the filehandle */
757 nfsfh->fh.data.data_len = data->fh.data.data_len;
758 nfsfh->fh.data.data_val = data->fh.data.data_val;
759 data->fh.data.data_val = NULL;
760
761 data->cb(0, nfs, nfsfh, data->private_data);
762 free_nfs_cb_data(data);
763}
764
765static int nfs_open_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
766{
767 int nfsmode = 0;
768
769 if (data->continue_int & O_WRONLY) {
770 nfsmode |= ACCESS3_MODIFY;
771 }
772 if (data->continue_int & O_RDWR) {
773 nfsmode |= ACCESS3_READ|ACCESS3_MODIFY;
774 }
775 if (!(data->continue_int & (O_WRONLY|O_RDWR))) {
776 nfsmode |= ACCESS3_READ;
777 }
778
779 if (rpc_nfs_access_async(nfs->rpc, nfs_open_cb, &data->fh, nfsmode, data) != 0) {
780 rpc_set_error(nfs->rpc, "RPC error: Failed to send OPEN ACCESS call for %s", data->path);
781 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
782 free_nfs_cb_data(data);
783 return -1;
784 }
785 return 0;
786}
787
788int nfs_open_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data)
789{
790 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_open_continue_internal, NULL, NULL, mode) != 0) {
cbbf9d3e
RS
791 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
792 return -1;
84004dbf
RS
793 }
794
795 return 0;
796}
797
798
799
800
801
802/*
803 * Async pread()
804 */
805static void nfs_pread_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
806{
807 struct nfs_cb_data *data = private_data;
808 struct nfs_context *nfs = data->nfs;
809 READ3res *res;
810
811 if (status == RPC_STATUS_ERROR) {
812 data->cb(-EFAULT, nfs, command_data, data->private_data);
813 free_nfs_cb_data(data);
814 return;
815 }
816 if (status == RPC_STATUS_CANCEL) {
817 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
818 free_nfs_cb_data(data);
819 return;
820 }
821
822 res = command_data;
823 if (res->status != NFS3_OK) {
824 rpc_set_error(nfs->rpc, "NFS: Read failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
825 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
826 free_nfs_cb_data(data);
827 return;
828 }
829
830 data->nfsfh->offset += res->READ3res_u.resok.count;
831 data->cb(res->READ3res_u.resok.count, nfs, res->READ3res_u.resok.data.data_val, data->private_data);
832 free_nfs_cb_data(data);
833}
834
921f877b
RS
835static void nfs_pread_mcb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
836{
837 struct nfs_mcb_data *mdata = private_data;
838 struct nfs_cb_data *data = mdata->data;
839 struct nfs_context *nfs = data->nfs;
840 READ3res *res;
841
842 data->num_calls--;
843
844 if (status == RPC_STATUS_ERROR) {
845 /* flag the failure but do not invoke callback until we have received all responses */
846 data->error = 1;
847 }
848 if (status == RPC_STATUS_CANCEL) {
849 /* flag the cancellation but do not invoke callback until we have received all responses */
850 data->cancel = 1;
851 }
852
853 /* reassemble the data into the buffer */
854 if (status == RPC_STATUS_SUCCESS) {
855 res = command_data;
856 if (res->status != NFS3_OK) {
857 rpc_set_error(nfs->rpc, "NFS: Read failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
858 data->error = 1;
859 } else {
860 memcpy(&data->buffer[mdata->offset], res->READ3res_u.resok.data.data_val, res->READ3res_u.resok.count);
5f9d02f8 861 if ((unsigned)data->max_offset < mdata->offset + res->READ3res_u.resok.count) {
921f877b
RS
862 data->max_offset = mdata->offset + res->READ3res_u.resok.count;
863 }
864 }
865 }
866
867 if (data->num_calls > 0) {
868 /* still waiting for more replies */
869 free(mdata);
870 return;
871 }
872
873
874 if (data->error != 0) {
875 data->cb(-EFAULT, nfs, command_data, data->private_data);
876 free_nfs_cb_data(data);
877 free(mdata);
878 return;
879 }
880 if (data->cancel != 0) {
881 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
882 free_nfs_cb_data(data);
883 free(mdata);
884 return;
885 }
886
887 data->nfsfh->offset = data->max_offset;
888 data->cb(data->max_offset - data->start_offset, nfs, data->buffer, data->private_data);
889 free_nfs_cb_data(data);
890 free(mdata);
891}
892
84004dbf
RS
893int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, size_t count, nfs_cb cb, void *private_data)
894{
895 struct nfs_cb_data *data;
896
897 data = malloc(sizeof(struct nfs_cb_data));
898 if (data == NULL) {
899 rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
84004dbf
RS
900 return -1;
901 }
902 bzero(data, sizeof(struct nfs_cb_data));
903 data->nfs = nfs;
904 data->cb = cb;
905 data->private_data = private_data;
906 data->nfsfh = nfsfh;
907
908 nfsfh->offset = offset;
921f877b
RS
909
910 if (count <= nfs_get_readmax(nfs)) {
911 if (rpc_nfs_read_async(nfs->rpc, nfs_pread_cb, &nfsfh->fh, offset, count, data) != 0) {
912 rpc_set_error(nfs->rpc, "RPC error: Failed to send READ call for %s", data->path);
913 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
914 free_nfs_cb_data(data);
915 return -1;
916 }
917 return 0;
918 }
919
920 /* trying to read more than maximum server read size, we has to chop it up into smaller
921 * reads and collect into a reassembly buffer.
922 * we send all reads in parallell so that performance is still good.
923 */
924 data->start_offset = offset;
925
926 data->buffer = malloc(count);
927 if (data->buffer == NULL) {
928 rpc_set_error(nfs->rpc, "Out-Of-Memory: Failed to allocate reassembly buffer for %d bytes", (int)count);
84004dbf
RS
929 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
930 free_nfs_cb_data(data);
931 return -1;
932 }
921f877b
RS
933
934 while (count > 0) {
935 size_t readcount = count;
936 struct nfs_mcb_data *mdata;
937
938 if (readcount > nfs_get_readmax(nfs)) {
939 readcount = nfs_get_readmax(nfs);
940 }
941
942 mdata = malloc(sizeof(struct nfs_mcb_data));
943 if (mdata == NULL) {
944 rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_mcb_data structure");
921f877b
RS
945 return -1;
946 }
947 bzero(mdata, sizeof(struct nfs_mcb_data));
948 mdata->data = data;
949 mdata->offset = offset;
950 mdata->count = readcount;
951
952 if (rpc_nfs_read_async(nfs->rpc, nfs_pread_mcb, &nfsfh->fh, offset, readcount, mdata) != 0) {
953 rpc_set_error(nfs->rpc, "RPC error: Failed to send READ call for %s", data->path);
954 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
955 free(mdata);
956 return -1;
957 }
958
959 count -= readcount;
960 offset += readcount;
961 data->num_calls++;
962 }
963
964 return 0;
84004dbf
RS
965}
966
967/*
968 * Async read()
969 */
970int nfs_read_async(struct nfs_context *nfs, struct nfsfh *nfsfh, size_t count, nfs_cb cb, void *private_data)
971{
972 return nfs_pread_async(nfs, nfsfh, nfsfh->offset, count, cb, private_data);
973}
974
975
976
977/*
978 * Async pwrite()
979 */
980static void nfs_pwrite_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
981{
982 struct nfs_cb_data *data = private_data;
983 struct nfs_context *nfs = data->nfs;
984 WRITE3res *res;
985
986 if (status == RPC_STATUS_ERROR) {
987 data->cb(-EFAULT, nfs, command_data, data->private_data);
988 free_nfs_cb_data(data);
989 return;
990 }
991 if (status == RPC_STATUS_CANCEL) {
992 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
993 free_nfs_cb_data(data);
994 return;
995 }
996
997 res = command_data;
998 if (res->status != NFS3_OK) {
999 rpc_set_error(nfs->rpc, "NFS: Write failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
1000 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
1001 free_nfs_cb_data(data);
1002 return;
1003 }
1004
1005 data->nfsfh->offset += res->WRITE3res_u.resok.count;
1006 data->cb(res->WRITE3res_u.resok.count, nfs, NULL, data->private_data);
1007 free_nfs_cb_data(data);
1008}
1009
1010int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, size_t count, char *buf, nfs_cb cb, void *private_data)
1011{
1012 struct nfs_cb_data *data;
1013
1014 data = malloc(sizeof(struct nfs_cb_data));
1015 if (data == NULL) {
1016 rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
84004dbf
RS
1017 return -1;
1018 }
1019 bzero(data, sizeof(struct nfs_cb_data));
1020 data->nfs = nfs;
1021 data->cb = cb;
1022 data->private_data = private_data;
1023 data->nfsfh = nfsfh;
1024
1025 nfsfh->offset = offset;
1026 if (rpc_nfs_write_async(nfs->rpc, nfs_pwrite_cb, &nfsfh->fh, buf, offset, count, nfsfh->is_sync?FILE_SYNC:UNSTABLE, data) != 0) {
1027 rpc_set_error(nfs->rpc, "RPC error: Failed to send WRITE call for %s", data->path);
1028 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1029 free_nfs_cb_data(data);
1030 return -1;
1031 }
1032 return 0;
1033}
1034
1035/*
1036 * Async write()
1037 */
1038int nfs_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, size_t count, char *buf, nfs_cb cb, void *private_data)
1039{
1040 return nfs_pwrite_async(nfs, nfsfh, nfsfh->offset, count, buf, cb, private_data);
1041}
1042
1043
1044
1045
1046/*
1047 * close
1048 */
1049
1050int nfs_close_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data)
1051{
1052 if (nfsfh->fh.data.data_val != NULL){
1053 free(nfsfh->fh.data.data_val);
1054 nfsfh->fh.data.data_val = NULL;
1055 }
1056 free(nfsfh);
1057
1058 cb(0, nfs, NULL, private_data);
1059 return 0;
1060};
1061
1062
1063
1064
1065
1066/*
1067 * Async fstat()
1068 */
1069int nfs_fstat_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data)
1070{
1071 struct nfs_cb_data *data;
1072
1073 data = malloc(sizeof(struct nfs_cb_data));
1074 if (data == NULL) {
1075 rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
84004dbf
RS
1076 return -1;
1077 }
1078 bzero(data, sizeof(struct nfs_cb_data));
1079 data->nfs = nfs;
1080 data->cb = cb;
1081 data->private_data = private_data;
1082
1083 if (rpc_nfs_getattr_async(nfs->rpc, nfs_stat_1_cb, &nfsfh->fh, data) != 0) {
1084 rpc_set_error(nfs->rpc, "RPC error: Failed to send STAT GETATTR call for %s", data->path);
1085 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1086 free_nfs_cb_data(data);
1087 return -1;
1088 }
1089 return 0;
1090}
1091
1092
1093
1094/*
1095 * Async fsync()
1096 */
1097static void nfs_fsync_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
1098{
1099 struct nfs_cb_data *data = private_data;
1100 struct nfs_context *nfs = data->nfs;
1101 COMMIT3res *res;
1102
1103 if (status == RPC_STATUS_ERROR) {
1104 data->cb(-EFAULT, nfs, command_data, data->private_data);
1105 free_nfs_cb_data(data);
1106 return;
1107 }
1108 if (status == RPC_STATUS_CANCEL) {
1109 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1110 free_nfs_cb_data(data);
1111 return;
1112 }
1113
1114 res = command_data;
1115 if (res->status != NFS3_OK) {
1116 rpc_set_error(nfs->rpc, "NFS: Commit failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
1117 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
1118 free_nfs_cb_data(data);
1119 return;
1120 }
1121
1122 data->cb(0, nfs, NULL, data->private_data);
1123 free_nfs_cb_data(data);
1124}
1125
1126int nfs_fsync_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data)
1127{
1128 struct nfs_cb_data *data;
1129
1130 data = malloc(sizeof(struct nfs_cb_data));
1131 if (data == NULL) {
1132 rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
84004dbf
RS
1133 return -1;
1134 }
1135 bzero(data, sizeof(struct nfs_cb_data));
1136 data->nfs = nfs;
1137 data->cb = cb;
1138 data->private_data = private_data;
1139
1140 if (rpc_nfs_commit_async(nfs->rpc, nfs_fsync_cb, &nfsfh->fh, data) != 0) {
1141 rpc_set_error(nfs->rpc, "RPC error: Failed to send COMMIT call for %s", data->path);
1142 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1143 free_nfs_cb_data(data);
1144 return -1;
1145 }
1146 return 0;
1147}
1148
1149
1150
1151
1152/*
1153 * Async ftruncate()
1154 */
1155static void nfs_ftruncate_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
1156{
1157 struct nfs_cb_data *data = private_data;
1158 struct nfs_context *nfs = data->nfs;
1159 SETATTR3res *res;
1160
1161 if (status == RPC_STATUS_ERROR) {
1162 data->cb(-EFAULT, nfs, command_data, data->private_data);
1163 free_nfs_cb_data(data);
1164 return;
1165 }
1166 if (status == RPC_STATUS_CANCEL) {
1167 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1168 free_nfs_cb_data(data);
1169 return;
1170 }
1171
1172 res = command_data;
1173 if (res->status != NFS3_OK) {
1174 rpc_set_error(nfs->rpc, "NFS: Setattr failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
1175 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
1176 free_nfs_cb_data(data);
1177 return;
1178 }
1179
1180 data->cb(0, nfs, NULL, data->private_data);
1181 free_nfs_cb_data(data);
1182}
1183
1184int nfs_ftruncate_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t length, nfs_cb cb, void *private_data)
1185{
1186 struct nfs_cb_data *data;
1187 SETATTR3args args;
1188
1189 data = malloc(sizeof(struct nfs_cb_data));
1190 if (data == NULL) {
1191 rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
84004dbf
RS
1192 return -1;
1193 }
1194 bzero(data, sizeof(struct nfs_cb_data));
1195 data->nfs = nfs;
1196 data->cb = cb;
1197 data->private_data = private_data;
1198
1199 bzero(&args, sizeof(SETATTR3args));
1200 args.object.data.data_len = nfsfh->fh.data.data_len;
1201 args.object.data.data_val = nfsfh->fh.data.data_val;
1202 args.new_attributes.size.set_it = 1;
1203 args.new_attributes.size.set_size3_u.size = length;
1204
1205 if (rpc_nfs_setattr_async(nfs->rpc, nfs_ftruncate_cb, &args, data) != 0) {
1206 rpc_set_error(nfs->rpc, "RPC error: Failed to send SETATTR call for %s", data->path);
1207 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1208 free_nfs_cb_data(data);
1209 return -1;
1210 }
1211 return 0;
1212}
1213
1214
1215/*
1216 * Async truncate()
1217 */
1218static int nfs_truncate_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
1219{
1220 off_t offset = data->continue_int;
1221 struct nfsfh nfsfh;
1222
1223 nfsfh.fh.data.data_val = data->fh.data.data_val;
1224 nfsfh.fh.data.data_len = data->fh.data.data_len;
1225
1226 if (nfs_ftruncate_async(nfs, &nfsfh, offset, data->cb, data->private_data) != 0) {
1227 rpc_set_error(nfs->rpc, "RPC error: Failed to send SETATTR call for %s", data->path);
1228 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1229 free_nfs_cb_data(data);
1230 return -1;
1231 }
1232 free_nfs_cb_data(data);
1233 return 0;
1234}
1235
1236int nfs_truncate_async(struct nfs_context *nfs, const char *path, off_t length, nfs_cb cb, void *private_data)
1237{
1238 off_t offset;
1239
1240 offset = length;
1241
1242 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_truncate_continue_internal, NULL, NULL, offset) != 0) {
cbbf9d3e
RS
1243 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
1244 return -1;
84004dbf
RS
1245 }
1246
1247 return 0;
1248}
1249
1250
1251
1252
1253/*
1254 * Async mkdir()
1255 */
1256static void nfs_mkdir_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
1257{
1258 MKDIR3res *res;
1259 struct nfs_cb_data *data = private_data;
1260 struct nfs_context *nfs = data->nfs;
1261 char *str = data->continue_data;
1262
1263 str = &str[strlen(str) + 1];
1264
1265 if (status == RPC_STATUS_ERROR) {
1266 data->cb(-EFAULT, nfs, command_data, data->private_data);
1267 free_nfs_cb_data(data);
1268 return;
1269 }
1270 if (status == RPC_STATUS_CANCEL) {
1271 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1272 free_nfs_cb_data(data);
1273 return;
1274 }
1275
1276 res = command_data;
1277 if (res->status != NFS3_OK) {
1278 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));
1279 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
1280 free_nfs_cb_data(data);
1281 return;
1282 }
1283
1284 data->cb(0, nfs, NULL, data->private_data);
1285 free_nfs_cb_data(data);
1286}
1287
1288static int nfs_mkdir_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
1289{
1290 char *str = data->continue_data;
1291
1292 str = &str[strlen(str) + 1];
1293
1294 if (rpc_nfs_mkdir_async(nfs->rpc, nfs_mkdir_cb, &data->fh, str, data) != 0) {
1295 rpc_set_error(nfs->rpc, "RPC error: Failed to send MKDIR call for %s", data->path);
1296 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1297 free_nfs_cb_data(data);
1298 return -1;
1299 }
1300 return 0;
1301}
1302
1303int nfs_mkdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
1304{
1305 char *new_path;
1306 char *ptr;
1307
1308 new_path = strdup(path);
1309 if (new_path == NULL) {
cbbf9d3e 1310 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for path");
84004dbf
RS
1311 return -1;
1312 }
1313
1314 ptr = rindex(new_path, '/');
1315 if (ptr == NULL) {
cbbf9d3e
RS
1316 rpc_set_error(nfs->rpc, "Invalid path %s", path);
1317 return -1;
84004dbf
RS
1318 }
1319 *ptr = 0;
1320
1321 /* new_path now points to the parent directory, and beyond the nul terminateor is the new directory to create */
1322 if (nfs_lookuppath_async(nfs, new_path, cb, private_data, nfs_mkdir_continue_internal, new_path, free, 0) != 0) {
cbbf9d3e
RS
1323 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path component");
1324 return -1;
84004dbf
RS
1325 }
1326
1327 return 0;
1328}
1329
1330
1331
1332
1333
1334/*
1335 * Async rmdir()
1336 */
1337static void nfs_rmdir_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
1338{
1339 RMDIR3res *res;
1340 struct nfs_cb_data *data = private_data;
1341 struct nfs_context *nfs = data->nfs;
1342 char *str = data->continue_data;
1343
1344 str = &str[strlen(str) + 1];
1345
1346 if (status == RPC_STATUS_ERROR) {
1347 data->cb(-EFAULT, nfs, command_data, data->private_data);
1348 free_nfs_cb_data(data);
1349 return;
1350 }
1351 if (status == RPC_STATUS_CANCEL) {
1352 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1353 free_nfs_cb_data(data);
1354 return;
1355 }
1356
1357 res = command_data;
1358 if (res->status != NFS3_OK) {
1359 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));
1360 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
1361 free_nfs_cb_data(data);
1362 return;
1363 }
1364
1365 data->cb(0, nfs, NULL, data->private_data);
1366 free_nfs_cb_data(data);
1367}
1368
1369static int nfs_rmdir_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
1370{
1371 char *str = data->continue_data;
1372
1373 str = &str[strlen(str) + 1];
1374
1375 if (rpc_nfs_rmdir_async(nfs->rpc, nfs_rmdir_cb, &data->fh, str, data) != 0) {
1376 rpc_set_error(nfs->rpc, "RPC error: Failed to send RMDIR call for %s", data->path);
1377 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1378 free_nfs_cb_data(data);
1379 return -1;
1380 }
1381 return 0;
1382}
1383
1384int nfs_rmdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
1385{
1386 char *new_path;
1387 char *ptr;
1388
1389 new_path = strdup(path);
1390 if (new_path == NULL) {
cbbf9d3e 1391 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for path");
84004dbf
RS
1392 return -1;
1393 }
1394
1395 ptr = rindex(new_path, '/');
1396 if (ptr == NULL) {
cbbf9d3e
RS
1397 rpc_set_error(nfs->rpc, "Invalid path %s", path);
1398 return -1;
84004dbf
RS
1399 }
1400 *ptr = 0;
1401
1402 /* new_path now points to the parent directory, and beyond the nul terminateor is the new directory to create */
1403 if (nfs_lookuppath_async(nfs, new_path, cb, private_data, nfs_rmdir_continue_internal, new_path, free, 0) != 0) {
cbbf9d3e
RS
1404 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
1405 return -1;
84004dbf
RS
1406 }
1407
1408 return 0;
1409}
1410
1411
1412
1413
1414/*
1415 * Async creat()
1416 */
1417static void nfs_create_2_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
1418{
1419 LOOKUP3res *res;
1420 struct nfs_cb_data *data = private_data;
1421 struct nfs_context *nfs = data->nfs;
1422 struct nfsfh *nfsfh;
1423 char *str = data->continue_data;
1424
1425 if (status == RPC_STATUS_ERROR) {
1426 data->cb(-EFAULT, nfs, command_data, data->private_data);
1427 free_nfs_cb_data(data);
1428 return;
1429 }
1430 if (status == RPC_STATUS_CANCEL) {
1431 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1432 free_nfs_cb_data(data);
1433 return;
1434 }
1435
1436 str = &str[strlen(str) + 1];
1437 res = command_data;
1438 if (res->status != NFS3_OK) {
1439 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));
1440 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
1441
1442 return;
1443 }
1444
1445 nfsfh = malloc(sizeof(struct nfsfh));
1446 if (nfsfh == NULL) {
1447 rpc_set_error(nfs->rpc, "NFS: Failed to allocate nfsfh structure");
1448 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1449 free_nfs_cb_data(data);
1450 return;
1451 }
1452 bzero(nfsfh, sizeof(struct nfsfh));
1453
1454 /* steal the filehandle */
1455 nfsfh->fh.data.data_len = data->fh.data.data_len;
1456 nfsfh->fh.data.data_val = data->fh.data.data_val;
1457 data->fh.data.data_val = NULL;
1458
1459 data->cb(0, nfs, nfsfh, data->private_data);
1460 free_nfs_cb_data(data);
1461}
1462
1463
1464
1465static void nfs_creat_1_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
1466{
1467 CREATE3res *res;
1468 struct nfs_cb_data *data = private_data;
1469 struct nfs_context *nfs = data->nfs;
1470 char *str = data->continue_data;
1471
1472 if (status == RPC_STATUS_ERROR) {
1473 data->cb(-EFAULT, nfs, command_data, data->private_data);
1474 free_nfs_cb_data(data);
1475 return;
1476 }
1477 if (status == RPC_STATUS_CANCEL) {
1478 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1479 free_nfs_cb_data(data);
1480 return;
1481 }
1482
1483 str = &str[strlen(str) + 1];
1484 res = command_data;
1485 if (res->status != NFS3_OK) {
1486 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));
1487 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
1488
1489 return;
1490 }
1491
1492 if (rpc_nfs_lookup_async(nfs->rpc, nfs_create_2_cb, &data->fh, str, data) != 0) {
1493 rpc_set_error(nfs->rpc, "RPC error: Failed to send lookup call for %s/%s", data->saved_path, str);
1494 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1495 free_nfs_cb_data(data);
1496 return;
1497 }
1498 return;
1499}
1500
1501static int nfs_creat_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
1502{
1503 char *str = data->continue_data;
1504
1505 str = &str[strlen(str) + 1];
1506
1507 if (rpc_nfs_create_async(nfs->rpc, nfs_creat_1_cb, &data->fh, str, data->continue_int, data) != 0) {
1508 rpc_set_error(nfs->rpc, "RPC error: Failed to send CREATE call for %s/%s", data->path, str);
1509 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1510 free_nfs_cb_data(data);
1511 return -1;
1512 }
1513 return 0;
1514}
1515
1516int nfs_creat_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data)
1517{
1518 char *new_path;
1519 char *ptr;
1520
1521 new_path = strdup(path);
1522 if (new_path == NULL) {
cbbf9d3e 1523 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for path");
84004dbf
RS
1524 return -1;
1525 }
1526
1527 ptr = rindex(new_path, '/');
1528 if (ptr == NULL) {
cbbf9d3e
RS
1529 rpc_set_error(nfs->rpc, "Invalid path %s", path);
1530 return -1;
84004dbf
RS
1531 }
1532 *ptr = 0;
1533
1534 /* new_path now points to the parent directory, and beyond the nul terminateor is the new directory to create */
1535 if (nfs_lookuppath_async(nfs, new_path, cb, private_data, nfs_creat_continue_internal, new_path, free, mode) != 0) {
cbbf9d3e
RS
1536 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
1537 return -1;
84004dbf
RS
1538 }
1539
1540 return 0;
1541}
1542
1543
1544
1545
1546/*
1547 * Async unlink()
1548 */
1549static void nfs_unlink_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
1550{
1551 REMOVE3res *res;
1552 struct nfs_cb_data *data = private_data;
1553 struct nfs_context *nfs = data->nfs;
1554 char *str = data->continue_data;
1555
1556 str = &str[strlen(str) + 1];
1557
1558 if (status == RPC_STATUS_ERROR) {
1559 data->cb(-EFAULT, nfs, command_data, data->private_data);
1560 free_nfs_cb_data(data);
1561 return;
1562 }
1563 if (status == RPC_STATUS_CANCEL) {
1564 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1565 free_nfs_cb_data(data);
1566 return;
1567 }
1568
1569 res = command_data;
1570 if (res->status != NFS3_OK) {
1571 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));
1572 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
1573 free_nfs_cb_data(data);
1574 return;
1575 }
1576
1577 data->cb(0, nfs, NULL, data->private_data);
1578 free_nfs_cb_data(data);
1579}
1580
1581static int nfs_unlink_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
1582{
1583 char *str = data->continue_data;
1584
1585 str = &str[strlen(str) + 1];
1586
1587 if (rpc_nfs_remove_async(nfs->rpc, nfs_unlink_cb, &data->fh, str, data) != 0) {
1588 rpc_set_error(nfs->rpc, "RPC error: Failed to send REMOVE call for %s", data->path);
1589 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1590 free_nfs_cb_data(data);
1591 return -1;
1592 }
1593 return 0;
1594}
1595
1596int nfs_unlink_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
1597{
1598 char *new_path;
1599 char *ptr;
1600
1601 new_path = strdup(path);
1602 if (new_path == NULL) {
cbbf9d3e 1603 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for path");
84004dbf
RS
1604 return -1;
1605 }
1606
1607 ptr = rindex(new_path, '/');
1608 if (ptr == NULL) {
cbbf9d3e
RS
1609 rpc_set_error(nfs->rpc, "Invalid path %s", path);
1610 return -1;
84004dbf
RS
1611 }
1612 *ptr = 0;
1613
1614 /* new_path now points to the parent directory, and beyond the nul terminateor is the new directory to create */
1615 if (nfs_lookuppath_async(nfs, new_path, cb, private_data, nfs_unlink_continue_internal, new_path, free, 0) != 0) {
cbbf9d3e
RS
1616 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
1617 return -1;
84004dbf
RS
1618 }
1619
1620 return 0;
1621}
1622
1623
1624
1625
1626
1627/*
1628 * Async opendir()
1629 */
1630static void nfs_opendir_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
1631{
1632 READDIR3res *res;
1633 struct nfs_cb_data *data = private_data;
1634 struct nfs_context *nfs = data->nfs;
1635 struct nfsdir *nfsdir = data->continue_data;;
1636 struct entry3 *entry;
1637 uint64_t cookie;
1638
1639 if (status == RPC_STATUS_ERROR) {
1640 data->cb(-EFAULT, nfs, command_data, data->private_data);
1641 nfs_free_nfsdir(nfsdir);
1642 data->continue_data = NULL;
1643 free_nfs_cb_data(data);
1644 return;
1645 }
1646 if (status == RPC_STATUS_CANCEL) {
1647 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1648 nfs_free_nfsdir(nfsdir);
1649 data->continue_data = NULL;
1650 free_nfs_cb_data(data);
1651 return;
1652 }
1653
1654 res = command_data;
1655 if (res->status != NFS3_OK) {
1656 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));
1657 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
1658 nfs_free_nfsdir(nfsdir);
1659 data->continue_data = NULL;
1660 free_nfs_cb_data(data);
1661 return;
1662 }
1663
1664 entry =res->READDIR3res_u.resok.reply.entries;
1665 while (entry != NULL) {
1666 struct nfsdirent *nfsdirent;
1667
1668 nfsdirent = malloc(sizeof(struct nfsdirent));
1669 if (nfsdirent == NULL) {
1670 data->cb(-ENOMEM, nfs, "Failed to allocate dirent", data->private_data);
1671 nfs_free_nfsdir(nfsdir);
1672 data->continue_data = NULL;
1673 free_nfs_cb_data(data);
1674 return;
1675 }
1676 bzero(nfsdirent, sizeof(struct nfsdirent));
1677 nfsdirent->name = strdup(entry->name);
1678 if (nfsdirent->name == NULL) {
1679 data->cb(-ENOMEM, nfs, "Failed to allocate dirent->name", data->private_data);
1680 nfs_free_nfsdir(nfsdir);
1681 data->continue_data = NULL;
1682 free_nfs_cb_data(data);
1683 return;
1684 }
1685 nfsdirent->inode = entry->fileid;
1686 nfsdirent->next = nfsdir->entries;
1687 nfsdir->entries = nfsdirent;
1688
1689 cookie = entry->cookie;
1690 entry = entry->nextentry;
1691 }
1692
1693 if (res->READDIR3res_u.resok.reply.eof == 0) {
1694 if (rpc_nfs_readdir_async(nfs->rpc, nfs_opendir_cb, &data->fh, cookie, res->READDIR3res_u.resok.cookieverf, 20000, data) != 0) {
1695 rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR call for %s", data->path);
1696 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1697 nfs_free_nfsdir(nfsdir);
1698 data->continue_data = NULL;
1699 free_nfs_cb_data(data);
1700 return;
1701 }
1702 return;
1703 }
1704
1705 /* steal the dirhandle */
1706 data->continue_data = NULL;
1707 nfsdir->current = nfsdir->entries;
1708
1709 data->cb(0, nfs, nfsdir, data->private_data);
1710 free_nfs_cb_data(data);
1711}
1712
1713static int nfs_opendir_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
1714{
1715 cookieverf3 cv;
1716
1717 bzero(cv, sizeof(cookieverf3));
1718 if (rpc_nfs_readdir_async(nfs->rpc, nfs_opendir_cb, &data->fh, 0, (char *)&cv, 20000, data) != 0) {
1719 rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR call for %s", data->path);
1720 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1721 free_nfs_cb_data(data);
1722 return -1;
1723 }
1724 return 0;
1725}
1726
1727int nfs_opendir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
1728{
1729 struct nfsdir *nfsdir;
1730
1731 nfsdir = malloc(sizeof(struct nfsdir));
1732 if (nfsdir == NULL) {
cbbf9d3e 1733 rpc_set_error(nfs->rpc, "failed to allocate buffer for nfsdir");
84004dbf
RS
1734 return -1;
1735 }
1736 bzero(nfsdir, sizeof(struct nfsdir));
1737
1738 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_opendir_continue_internal, nfsdir, free, 0) != 0) {
cbbf9d3e
RS
1739 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
1740 return -1;
84004dbf
RS
1741 }
1742
1743 return 0;
1744}
1745
1746
1747struct nfsdirent *nfs_readdir(struct nfs_context *nfs _U_, struct nfsdir *nfsdir)
1748{
1749 struct nfsdirent *nfsdirent = nfsdir->current;
1750
1751 if (nfsdir->current != NULL) {
1752 nfsdir->current = nfsdir->current->next;
1753 }
1754 return nfsdirent;
1755}
1756
1757
1758void nfs_closedir(struct nfs_context *nfs _U_, struct nfsdir *nfsdir)
1759{
1760 nfs_free_nfsdir(nfsdir);
1761}
1762
1763
1764
1765
1766
1767
1768
1769/*
1770 * Async lseek()
1771 */
1772struct lseek_cb_data {
1773 struct nfs_context *nfs;
1774 struct nfsfh *nfsfh;
1775 off_t offset;
1776 nfs_cb cb;
1777 void *private_data;
1778};
1779
1780static void nfs_lseek_1_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
1781{
1782 GETATTR3res *res;
1783 struct lseek_cb_data *data = private_data;
1784 struct nfs_context *nfs = data->nfs;
1785
1786 if (status == RPC_STATUS_ERROR) {
1787 data->cb(-EFAULT, nfs, command_data, data->private_data);
1788 free(data);
1789 return;
1790 }
1791 if (status == RPC_STATUS_CANCEL) {
1792 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1793 free(data);
1794 return;
1795 }
1796
1797 res = command_data;
1798 if (res->status != NFS3_OK) {
1799 rpc_set_error(nfs->rpc, "NFS: GETATTR failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
1800 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
1801 free(data);
1802 return;
1803 }
1804
1805 data->nfsfh->offset = data->offset + res->GETATTR3res_u.resok.obj_attributes.size;
1806 data->cb(0, nfs, &data->nfsfh->offset, data->private_data);
1807 free(data);
1808}
1809
1810int nfs_lseek_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, int whence, nfs_cb cb, void *private_data)
1811{
1812 struct lseek_cb_data *data;
1813
1814 if (whence == SEEK_SET) {
1815 nfsfh->offset = offset;
1816 cb(0, nfs, &nfsfh->offset, private_data);
1817 return 0;
1818 }
1819 if (whence == SEEK_CUR) {
1820 nfsfh->offset += offset;
1821 cb(0, nfs, &nfsfh->offset, private_data);
1822 return 0;
1823 }
1824
1825 data = malloc(sizeof(struct lseek_cb_data));
1826 if (data == NULL) {
1827 rpc_set_error(nfs->rpc, "Out Of Memory: Failed to malloc lseek cb data");
1828 return -1;
1829 }
1830
1831 data->nfs = nfs;
1832 data->nfsfh = nfsfh;
1833 data->offset = offset;
1834 data->cb = cb;
1835 data->private_data = private_data;
1836
1837 if (rpc_nfs_getattr_async(nfs->rpc, nfs_lseek_1_cb, &nfsfh->fh, data) != 0) {
1838 rpc_set_error(nfs->rpc, "RPC error: Failed to send LSEEK GETATTR call");
1839 free(data);
cbbf9d3e 1840 return -1;
84004dbf
RS
1841 }
1842 return 0;
1843}
1844
1845
1846
1847
1848/*
1849 * Async statvfs()
1850 */
1851static void nfs_statvfs_1_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
1852{
1853 FSSTAT3res *res;
1854 struct nfs_cb_data *data = private_data;
1855 struct nfs_context *nfs = data->nfs;
1856 struct statvfs svfs;
1857
1858 if (status == RPC_STATUS_ERROR) {
1859 data->cb(-EFAULT, nfs, command_data, data->private_data);
1860 free_nfs_cb_data(data);
1861 return;
1862 }
1863 if (status == RPC_STATUS_CANCEL) {
1864 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1865 free_nfs_cb_data(data);
1866 return;
1867 }
1868
1869 res = command_data;
1870 if (res->status != NFS3_OK) {
1871 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));
1872 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
1873 free_nfs_cb_data(data);
1874 return;
1875 }
1876
1877 svfs.f_bsize = 4096;
1878 svfs.f_frsize = 4096;
1879 svfs.f_blocks = res->FSSTAT3res_u.resok.tbytes/4096;
1880 svfs.f_bfree = res->FSSTAT3res_u.resok.fbytes/4096;
1881 svfs.f_bavail = res->FSSTAT3res_u.resok.abytes/4096;
1882 svfs.f_files = res->FSSTAT3res_u.resok.tfiles;
1883 svfs.f_ffree = res->FSSTAT3res_u.resok.ffiles;
1884 svfs.f_favail = res->FSSTAT3res_u.resok.afiles;
1885 svfs.f_fsid = 0;
1886 svfs.f_flag = 0;
1887 svfs.f_namemax = 256;
1888
1889 data->cb(0, nfs, &svfs, data->private_data);
1890 free_nfs_cb_data(data);
1891}
1892
1893static int nfs_statvfs_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
1894{
1895 if (rpc_nfs_fsstat_async(nfs->rpc, nfs_statvfs_1_cb, &data->fh, data) != 0) {
1896 rpc_set_error(nfs->rpc, "RPC error: Failed to send FSSTAT call for %s", data->path);
1897 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1898 free_nfs_cb_data(data);
1899 return -1;
1900 }
1901 return 0;
1902}
1903
1904int nfs_statvfs_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
1905{
1906 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_statvfs_continue_internal, NULL, NULL, 0) != 0) {
cbbf9d3e 1907 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
84004dbf
RS
1908 return -1;
1909 }
1910
1911 return 0;
1912}
1913
1914
1915
1916
1917/*
1918 * Async readlink()
1919 */
1920static void nfs_readlink_1_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
1921{
1922 READLINK3res *res;
1923 struct nfs_cb_data *data = private_data;
1924 struct nfs_context *nfs = data->nfs;
1925
1926 if (status == RPC_STATUS_ERROR) {
1927 data->cb(-EFAULT, nfs, command_data, data->private_data);
1928 free_nfs_cb_data(data);
1929 return;
1930 }
1931 if (status == RPC_STATUS_CANCEL) {
1932 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1933 free_nfs_cb_data(data);
1934 return;
1935 }
1936
1937 res = command_data;
1938 if (res->status != NFS3_OK) {
1939 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));
1940 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
1941 free_nfs_cb_data(data);
1942 return;
1943 }
1944
1945
1946 data->cb(0, nfs, res->READLINK3res_u.resok.data, data->private_data);
1947 free_nfs_cb_data(data);
1948}
1949
1950static int nfs_readlink_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
1951{
1952 if (rpc_nfs_readlink_async(nfs->rpc, nfs_readlink_1_cb, &data->fh, data) != 0) {
1953 rpc_set_error(nfs->rpc, "RPC error: Failed to send READLINK call for %s", data->path);
1954 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
1955 free_nfs_cb_data(data);
1956 return -1;
1957 }
1958 return 0;
1959}
1960
1961int nfs_readlink_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
1962{
1963 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_readlink_continue_internal, NULL, NULL, 0) != 0) {
cbbf9d3e 1964 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
84004dbf
RS
1965 return -1;
1966 }
1967
1968 return 0;
1969}
1970
1971
1972
1973
1974/*
1975 * Async chmod()
1976 */
1977static void nfs_chmod_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
1978{
1979 struct nfs_cb_data *data = private_data;
1980 struct nfs_context *nfs = data->nfs;
1981 SETATTR3res *res;
1982
1983 if (status == RPC_STATUS_ERROR) {
1984 data->cb(-EFAULT, nfs, command_data, data->private_data);
1985 free_nfs_cb_data(data);
1986 return;
1987 }
1988 if (status == RPC_STATUS_CANCEL) {
1989 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
1990 free_nfs_cb_data(data);
1991 return;
1992 }
1993
1994 res = command_data;
1995 if (res->status != NFS3_OK) {
1996 rpc_set_error(nfs->rpc, "NFS: SETATTR failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
1997 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
1998 free_nfs_cb_data(data);
1999 return;
2000 }
2001
2002 data->cb(0, nfs, NULL, data->private_data);
2003 free_nfs_cb_data(data);
2004}
2005
2006static int nfs_chmod_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
2007{
2008 SETATTR3args args;
2009
2010 bzero(&args, sizeof(SETATTR3args));
2011 args.object.data.data_len = data->fh.data.data_len;
2012 args.object.data.data_val = data->fh.data.data_val;
2013 args.new_attributes.mode.set_it = 1;
2014 args.new_attributes.mode.set_mode3_u.mode = data->continue_int;
2015
2016 if (rpc_nfs_setattr_async(nfs->rpc, nfs_chmod_cb, &args, data) != 0) {
2017 rpc_set_error(nfs->rpc, "RPC error: Failed to send SETATTR call for %s", data->path);
2018 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2019 free_nfs_cb_data(data);
2020 return -1;
2021 }
2022 return 0;
2023}
2024
2025
2026int nfs_chmod_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data)
2027{
2028 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_chmod_continue_internal, NULL, NULL, mode) != 0) {
cbbf9d3e 2029 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
84004dbf
RS
2030 return -1;
2031 }
2032
2033 return 0;
2034}
2035
2036/*
2037 * Async fchmod()
2038 */
2039int nfs_fchmod_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int mode, nfs_cb cb, void *private_data)
2040{
2041 struct nfs_cb_data *data;
2042
2043 data = malloc(sizeof(struct nfs_cb_data));
2044 if (data == NULL) {
cbbf9d3e 2045 rpc_set_error(nfs->rpc, "out of memory. failed to allocate memory for nfs mount data");
84004dbf
RS
2046 return -1;
2047 }
2048 bzero(data, sizeof(struct nfs_cb_data));
2049 data->nfs = nfs;
2050 data->cb = cb;
2051 data->private_data = private_data;
2052 data->continue_int = mode;
2053 data->fh.data.data_len = nfsfh->fh.data.data_len;
2054 data->fh.data.data_val = malloc(data->fh.data.data_len);
2055 if (data->fh.data.data_val == NULL) {
2056 rpc_set_error(nfs->rpc, "Out of memory: Failed to allocate fh");
2057 free_nfs_cb_data(data);
2058 return -1;
2059 }
2060 memcpy(data->fh.data.data_val, nfsfh->fh.data.data_val, data->fh.data.data_len);
2061
2062 if (nfs_chmod_continue_internal(nfs, data) != 0) {
2063 free_nfs_cb_data(data);
2064 return -1;
2065 }
2066
2067 return 0;
2068}
2069
2070
2071
2072/*
2073 * Async chown()
2074 */
2075static void nfs_chown_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
2076{
2077 struct nfs_cb_data *data = private_data;
2078 struct nfs_context *nfs = data->nfs;
2079 SETATTR3res *res;
2080
2081 if (status == RPC_STATUS_ERROR) {
2082 data->cb(-EFAULT, nfs, command_data, data->private_data);
2083 free_nfs_cb_data(data);
2084 return;
2085 }
2086 if (status == RPC_STATUS_CANCEL) {
2087 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2088 free_nfs_cb_data(data);
2089 return;
2090 }
2091
2092 res = command_data;
2093 if (res->status != NFS3_OK) {
2094 rpc_set_error(nfs->rpc, "NFS: SETATTR failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
2095 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
2096 free_nfs_cb_data(data);
2097 return;
2098 }
2099
2100 data->cb(0, nfs, NULL, data->private_data);
2101 free_nfs_cb_data(data);
2102}
2103
2104struct nfs_chown_data {
2105 uid_t uid;
2106 gid_t gid;
2107};
2108
2109static int nfs_chown_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
2110{
2111 SETATTR3args args;
2112 struct nfs_chown_data *chown_data = data->continue_data;
2113
2114 bzero(&args, sizeof(SETATTR3args));
2115 args.object.data.data_len = data->fh.data.data_len;
2116 args.object.data.data_val = data->fh.data.data_val;
2117 if (chown_data->uid != (uid_t)-1) {
2118 args.new_attributes.uid.set_it = 1;
2119 args.new_attributes.uid.set_uid3_u.uid = chown_data->uid;
2120 }
2121 if (chown_data->gid != (gid_t)-1) {
2122 args.new_attributes.gid.set_it = 1;
2123 args.new_attributes.gid.set_gid3_u.gid = chown_data->gid;
2124 }
2125
2126 if (rpc_nfs_setattr_async(nfs->rpc, nfs_chown_cb, &args, data) != 0) {
2127 rpc_set_error(nfs->rpc, "RPC error: Failed to send SETATTR call for %s", data->path);
2128 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2129 free_nfs_cb_data(data);
2130 return -1;
2131 }
2132 return 0;
2133}
2134
2135
2136int nfs_chown_async(struct nfs_context *nfs, const char *path, int uid, int gid, nfs_cb cb, void *private_data)
2137{
2138 struct nfs_chown_data *chown_data;
2139
2140 chown_data = malloc(sizeof(struct nfs_chown_data));
2141 if (chown_data == NULL) {
cbbf9d3e 2142 rpc_set_error(nfs->rpc, "Failed to allocate memory for chown data structure");
84004dbf
RS
2143 return -1;
2144 }
2145
2146 chown_data->uid = uid;
2147 chown_data->gid = gid;
2148
2149 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_chown_continue_internal, chown_data, free, 0) != 0) {
cbbf9d3e 2150 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
84004dbf
RS
2151 return -1;
2152 }
2153
2154 return 0;
2155}
2156
2157
2158/*
2159 * Async fchown()
2160 */
2161int nfs_fchown_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int uid, int gid, nfs_cb cb, void *private_data)
2162{
2163 struct nfs_cb_data *data;
2164 struct nfs_chown_data *chown_data;
2165
2166 chown_data = malloc(sizeof(struct nfs_chown_data));
2167 if (chown_data == NULL) {
cbbf9d3e 2168 rpc_set_error(nfs->rpc, "Failed to allocate memory for chown data structure");
84004dbf
RS
2169 return -1;
2170 }
2171
2172 chown_data->uid = uid;
2173 chown_data->gid = gid;
2174
2175
2176 data = malloc(sizeof(struct nfs_cb_data));
2177 if (data == NULL) {
cbbf9d3e 2178 rpc_set_error(nfs->rpc, "out of memory. failed to allocate memory for fchown data");
84004dbf
RS
2179 return -1;
2180 }
2181 bzero(data, sizeof(struct nfs_cb_data));
2182 data->nfs = nfs;
2183 data->cb = cb;
2184 data->private_data = private_data;
2185 data->continue_data = chown_data;
2186 data->fh.data.data_len = nfsfh->fh.data.data_len;
2187 data->fh.data.data_val = malloc(data->fh.data.data_len);
2188 if (data->fh.data.data_val == NULL) {
2189 rpc_set_error(nfs->rpc, "Out of memory: Failed to allocate fh");
2190 free_nfs_cb_data(data);
2191 return -1;
2192 }
2193 memcpy(data->fh.data.data_val, nfsfh->fh.data.data_val, data->fh.data.data_len);
2194
2195
2196 if (nfs_chown_continue_internal(nfs, data) != 0) {
2197 free_nfs_cb_data(data);
2198 return -1;
2199 }
2200
2201 return 0;
2202}
2203
2204
2205
2206
2207
2208/*
2209 * Async utimes()
2210 */
2211static void nfs_utimes_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
2212{
2213 struct nfs_cb_data *data = private_data;
2214 struct nfs_context *nfs = data->nfs;
2215 SETATTR3res *res;
2216
2217 if (status == RPC_STATUS_ERROR) {
2218 data->cb(-EFAULT, nfs, command_data, data->private_data);
2219 free_nfs_cb_data(data);
2220 return;
2221 }
2222 if (status == RPC_STATUS_CANCEL) {
2223 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2224 free_nfs_cb_data(data);
2225 return;
2226 }
2227
2228 res = command_data;
2229 if (res->status != NFS3_OK) {
2230 rpc_set_error(nfs->rpc, "NFS: SETATTR failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
2231 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
2232 free_nfs_cb_data(data);
2233 return;
2234 }
2235
2236 data->cb(0, nfs, NULL, data->private_data);
2237 free_nfs_cb_data(data);
2238}
2239
2240static int nfs_utimes_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
2241{
2242 SETATTR3args args;
2243 struct timeval *utimes_data = data->continue_data;
2244
2245 bzero(&args, sizeof(SETATTR3args));
2246 args.object.data.data_len = data->fh.data.data_len;
2247 args.object.data.data_val = data->fh.data.data_val;
2248 if (utimes_data != NULL) {
2249 args.new_attributes.atime.set_it = SET_TO_CLIENT_TIME;
2250 args.new_attributes.atime.set_atime_u.atime.seconds = utimes_data[0].tv_sec;
2251 args.new_attributes.atime.set_atime_u.atime.nseconds = utimes_data[0].tv_usec * 1000;
2252 args.new_attributes.mtime.set_it = SET_TO_CLIENT_TIME;
2253 args.new_attributes.mtime.set_mtime_u.mtime.seconds = utimes_data[1].tv_sec;
2254 args.new_attributes.mtime.set_mtime_u.mtime.nseconds = utimes_data[1].tv_usec * 1000;
2255 } else {
2256 args.new_attributes.atime.set_it = SET_TO_SERVER_TIME;
2257 args.new_attributes.mtime.set_it = SET_TO_SERVER_TIME;
2258 }
2259
2260 if (rpc_nfs_setattr_async(nfs->rpc, nfs_utimes_cb, &args, data) != 0) {
2261 rpc_set_error(nfs->rpc, "RPC error: Failed to send SETATTR call for %s", data->path);
2262 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2263 free_nfs_cb_data(data);
2264 return -1;
2265 }
2266 return 0;
2267}
2268
2269
2270int nfs_utimes_async(struct nfs_context *nfs, const char *path, struct timeval *times, nfs_cb cb, void *private_data)
2271{
2272 struct timeval *new_times = NULL;
2273
2274 if (times != NULL) {
2275 new_times = malloc(sizeof(struct timeval)*2);
2276 if (new_times == NULL) {
cbbf9d3e 2277 rpc_set_error(nfs->rpc, "Failed to allocate memory for timeval structure");
84004dbf
RS
2278 return -1;
2279 }
2280
2281 memcpy(new_times, times, sizeof(struct timeval)*2);
2282 }
2283
2284 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_utimes_continue_internal, new_times, free, 0) != 0) {
cbbf9d3e 2285 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
84004dbf
RS
2286 return -1;
2287 }
2288
2289 return 0;
2290}
2291
2292/*
2293 * Async utime()
2294 */
2295int nfs_utime_async(struct nfs_context *nfs, const char *path, struct utimbuf *times, nfs_cb cb, void *private_data)
2296{
2297 struct timeval *new_times = NULL;
2298
2299 if (times != NULL) {
2300 new_times = malloc(sizeof(struct timeval)*2);
2301 if (new_times == NULL) {
cbbf9d3e 2302 rpc_set_error(nfs->rpc, "Failed to allocate memory for timeval structure");
84004dbf
RS
2303 return -1;
2304 }
2305
2306 new_times[0].tv_sec = times->actime;
2307 new_times[0].tv_usec = 0;
2308 new_times[1].tv_sec = times->modtime;
2309 new_times[1].tv_usec = 0;
2310 }
2311
2312 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_utimes_continue_internal, new_times, free, 0) != 0) {
cbbf9d3e 2313 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
84004dbf
RS
2314 return -1;
2315 }
2316
2317 return 0;
2318}
2319
2320
2321
2322
2323
2324/*
2325 * Async access()
2326 */
2327static void nfs_access_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
2328{
2329 ACCESS3res *res;
2330 struct nfs_cb_data *data = private_data;
2331 struct nfs_context *nfs = data->nfs;
2332 unsigned int nfsmode = 0;
2333
2334 if (status == RPC_STATUS_ERROR) {
2335 data->cb(-EFAULT, nfs, command_data, data->private_data);
2336 free_nfs_cb_data(data);
2337 return;
2338 }
2339 if (status == RPC_STATUS_CANCEL) {
2340 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2341 free_nfs_cb_data(data);
2342 return;
2343 }
2344
2345 res = command_data;
2346 if (res->status != NFS3_OK) {
2347 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));
2348 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
2349 free_nfs_cb_data(data);
2350 return;
2351 }
2352
2353 if (data->continue_int & R_OK) {
2354 nfsmode |= ACCESS3_READ;
2355 }
2356 if (data->continue_int & W_OK) {
2357 nfsmode |= ACCESS3_MODIFY;
2358 }
2359 if (data->continue_int & X_OK) {
2360 nfsmode |= ACCESS3_EXECUTE;
2361 }
2362
2363 if (res->ACCESS3res_u.resok.access != nfsmode) {
2364 rpc_set_error(nfs->rpc, "NFS: ACCESS denied. Required access %c%c%c. Allowed access %c%c%c",
2365 nfsmode&ACCESS3_READ?'r':'-',
2366 nfsmode&ACCESS3_MODIFY?'w':'-',
2367 nfsmode&ACCESS3_EXECUTE?'x':'-',
2368 res->ACCESS3res_u.resok.access&ACCESS3_READ?'r':'-',
2369 res->ACCESS3res_u.resok.access&ACCESS3_MODIFY?'w':'-',
2370 res->ACCESS3res_u.resok.access&ACCESS3_EXECUTE?'x':'-');
2371 data->cb(-EACCES, nfs, rpc_get_error(nfs->rpc), data->private_data);
2372 free_nfs_cb_data(data);
2373 return;
2374 }
2375
2376 data->cb(0, nfs, NULL, data->private_data);
2377 free_nfs_cb_data(data);
2378}
2379
2380static int nfs_access_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
2381{
2382 int nfsmode = 0;
2383
2384 if (data->continue_int & R_OK) {
2385 nfsmode |= ACCESS3_READ;
2386 }
2387 if (data->continue_int & W_OK) {
2388 nfsmode |= ACCESS3_MODIFY;
2389 }
2390 if (data->continue_int & X_OK) {
2391 nfsmode |= ACCESS3_EXECUTE;
2392 }
2393
2394 if (rpc_nfs_access_async(nfs->rpc, nfs_access_cb, &data->fh, nfsmode, data) != 0) {
2395 rpc_set_error(nfs->rpc, "RPC error: Failed to send OPEN ACCESS call for %s", data->path);
2396 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2397 free_nfs_cb_data(data);
2398 return -1;
2399 }
2400 return 0;
2401}
2402
2403int nfs_access_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data)
2404{
2405 if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_access_continue_internal, NULL, NULL, mode) != 0) {
cbbf9d3e
RS
2406 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
2407 return -1;
84004dbf
RS
2408 }
2409
2410 return 0;
2411}
2412
2413
2414
2415/*
2416 * Async symlink()
2417 */
2418struct nfs_symlink_data {
2419 char *oldpath;
2420 char *newpathparent;
2421 char *newpathobject;
2422};
2423
2424static void free_nfs_symlink_data(void *mem)
2425{
2426 struct nfs_symlink_data *data = mem;
2427
2428 if (data->oldpath != NULL) {
2429 free(data->oldpath);
2430 }
2431 if (data->newpathparent != NULL) {
2432 free(data->newpathparent);
2433 }
2434 if (data->newpathobject != NULL) {
2435 free(data->newpathobject);
2436 }
2437 free(data);
2438}
2439
2440static void nfs_symlink_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
2441{
2442 SYMLINK3res *res;
2443 struct nfs_cb_data *data = private_data;
2444 struct nfs_context *nfs = data->nfs;
2445 struct nfs_symlink_data *symlink_data = data->continue_data;
2446
2447 if (status == RPC_STATUS_ERROR) {
2448 data->cb(-EFAULT, nfs, command_data, data->private_data);
2449 free_nfs_cb_data(data);
2450 return;
2451 }
2452 if (status == RPC_STATUS_CANCEL) {
2453 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2454 free_nfs_cb_data(data);
2455 return;
2456 }
2457
2458 res = command_data;
2459 if (res->status != NFS3_OK) {
2460 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));
2461 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
2462 free_nfs_cb_data(data);
2463 return;
2464 }
2465
2466 data->cb(0, nfs, NULL, data->private_data);
2467 free_nfs_cb_data(data);
2468}
2469
2470static int nfs_symlink_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
2471{
2472 struct nfs_symlink_data *symlink_data = data->continue_data;
2473
2474 if (rpc_nfs_symlink_async(nfs->rpc, nfs_symlink_cb, &data->fh, symlink_data->newpathobject, symlink_data->oldpath, data) != 0) {
2475 rpc_set_error(nfs->rpc, "RPC error: Failed to send SYMLINK call for %s", data->path);
2476 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2477 free_nfs_cb_data(data);
2478 return -1;
2479 }
2480 return 0;
2481}
2482
2483int nfs_symlink_async(struct nfs_context *nfs, const char *oldpath, const char *newpath, nfs_cb cb, void *private_data)
2484{
2485 char *ptr;
2486 struct nfs_symlink_data *symlink_data;
2487
2488 symlink_data = malloc(sizeof(struct nfs_symlink_data));
2489 if (symlink_data == NULL) {
cbbf9d3e 2490 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for symlink data");
84004dbf
RS
2491 return -1;
2492 }
2493 bzero(symlink_data, sizeof(struct nfs_symlink_data));
2494
2495 symlink_data->oldpath = strdup(oldpath);
2496 if (symlink_data->oldpath == NULL) {
cbbf9d3e 2497 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for oldpath");
84004dbf 2498 free_nfs_symlink_data(symlink_data);
cbbf9d3e 2499 return -1;
84004dbf
RS
2500 }
2501
2502 symlink_data->newpathparent = strdup(newpath);
2503 if (symlink_data->newpathparent == NULL) {
cbbf9d3e 2504 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for new path");
84004dbf 2505 free_nfs_symlink_data(symlink_data);
cbbf9d3e 2506 return -1;
84004dbf
RS
2507 }
2508
2509 ptr = rindex(symlink_data->newpathparent, '/');
2510 if (ptr == NULL) {
cbbf9d3e 2511 rpc_set_error(nfs->rpc, "Invalid path %s", oldpath);
84004dbf 2512 free_nfs_symlink_data(symlink_data);
cbbf9d3e 2513 return -1;
84004dbf
RS
2514 }
2515 *ptr = 0;
2516 ptr++;
2517
2518 symlink_data->newpathobject = strdup(ptr);
2519 if (symlink_data->newpathobject == NULL) {
cbbf9d3e 2520 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for new path");
84004dbf 2521 free_nfs_symlink_data(symlink_data);
cbbf9d3e 2522 return -1;
84004dbf
RS
2523 }
2524
2525 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
2526 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
2527 return -1;
84004dbf
RS
2528 }
2529
2530 return 0;
2531}
2532
2533
2534
2535/*
2536 * Async rename()
2537 */
2538struct nfs_rename_data {
2539 char *oldpath;
2540 char *oldobject;
2541 struct nfs_fh3 olddir;
2542 char *newpath;
2543 char *newobject;
2544 struct nfs_fh3 newdir;
2545};
2546
2547static void free_nfs_rename_data(void *mem)
2548{
2549 struct nfs_rename_data *data = mem;
2550
2551 if (data->oldpath != NULL) {
2552 free(data->oldpath);
2553 }
2554 if (data->olddir.data.data_val != NULL) {
2555 free(data->olddir.data.data_val);
2556 }
2557 if (data->newpath != NULL) {
2558 free(data->newpath);
2559 }
2560 if (data->newdir.data.data_val != NULL) {
2561 free(data->newdir.data.data_val);
2562 }
2563 free(data);
2564}
2565
2566static void nfs_rename_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
2567{
2568 RENAME3res *res;
2569 struct nfs_cb_data *data = private_data;
2570 struct nfs_context *nfs = data->nfs;
2571 struct nfs_rename_data *rename_data = data->continue_data;
2572
2573 if (status == RPC_STATUS_ERROR) {
2574 data->cb(-EFAULT, nfs, command_data, data->private_data);
2575 free_nfs_cb_data(data);
2576 return;
2577 }
2578 if (status == RPC_STATUS_CANCEL) {
2579 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2580 free_nfs_cb_data(data);
2581 return;
2582 }
2583
2584 res = command_data;
2585 if (res->status != NFS3_OK) {
2586 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));
2587 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
2588 free_nfs_cb_data(data);
2589 return;
2590 }
2591
2592 data->cb(0, nfs, NULL, data->private_data);
2593 free_nfs_cb_data(data);
2594}
2595
2596static int nfs_rename_continue_2_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
2597{
2598 struct nfs_rename_data *rename_data = data->continue_data;
2599
2600 /* steal the filehandle */
2601 rename_data->newdir.data.data_len = data->fh.data.data_len;
2602 rename_data->newdir.data.data_val = data->fh.data.data_val;
2603 data->fh.data.data_val = NULL;
2604
2605 if (rpc_nfs_rename_async(nfs->rpc, nfs_rename_cb, &rename_data->olddir, rename_data->oldobject, &rename_data->newdir, rename_data->newobject, data) != 0) {
2606 rpc_set_error(nfs->rpc, "RPC error: Failed to send RENAME call for %s", data->path);
2607 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2608 free_nfs_cb_data(data);
2609 return -1;
2610 }
2611 return 0;
2612}
2613
2614
2615static int nfs_rename_continue_1_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
2616{
2617 struct nfs_rename_data *rename_data = data->continue_data;
2618
2619 /* steal the filehandle */
2620 rename_data->olddir.data.data_len = data->fh.data.data_len;
2621 rename_data->olddir.data.data_val = data->fh.data.data_val;
2622 data->fh.data.data_val = NULL;
2623
2624 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) {
2625 rpc_set_error(nfs->rpc, "RPC error: Failed to send LOOKUP call for %s", rename_data->newpath);
2626 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2627 free_nfs_cb_data(data);
2628 return -1;
2629 }
2630 data->continue_data = NULL;
2631 free_nfs_cb_data(data);
2632
2633 return 0;
2634}
2635
2636
2637int nfs_rename_async(struct nfs_context *nfs, const char *oldpath, const char *newpath, nfs_cb cb, void *private_data)
2638{
2639 char *ptr;
2640 struct nfs_rename_data *rename_data;
2641
2642 rename_data = malloc(sizeof(struct nfs_rename_data));
2643 if (rename_data == NULL) {
cbbf9d3e 2644 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for rename data");
84004dbf
RS
2645 return -1;
2646 }
2647 bzero(rename_data, sizeof(struct nfs_rename_data));
2648
2649 rename_data->oldpath = strdup(oldpath);
2650 if (rename_data->oldpath == NULL) {
cbbf9d3e 2651 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for oldpath");
84004dbf 2652 free_nfs_rename_data(rename_data);
cbbf9d3e 2653 return -1;
84004dbf
RS
2654 }
2655 ptr = rindex(rename_data->oldpath, '/');
2656 if (ptr == NULL) {
cbbf9d3e 2657 rpc_set_error(nfs->rpc, "Invalid path %s", oldpath);
84004dbf 2658 free_nfs_rename_data(rename_data);
cbbf9d3e 2659 return -1;
84004dbf
RS
2660 }
2661 *ptr = 0;
2662 ptr++;
2663 rename_data->oldobject = ptr;
2664
2665
2666 rename_data->newpath = strdup(newpath);
2667 if (rename_data->newpath == NULL) {
cbbf9d3e 2668 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for newpath");
84004dbf 2669 free_nfs_rename_data(rename_data);
cbbf9d3e 2670 return -1;
84004dbf
RS
2671 }
2672 ptr = rindex(rename_data->newpath, '/');
2673 if (ptr == NULL) {
cbbf9d3e 2674 rpc_set_error(nfs->rpc, "Invalid path %s", newpath);
84004dbf 2675 free_nfs_rename_data(rename_data);
cbbf9d3e 2676 return -1;
84004dbf
RS
2677 }
2678 *ptr = 0;
2679 ptr++;
2680 rename_data->newobject = ptr;
2681
2682
2683 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
2684 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
2685 return -1;
84004dbf
RS
2686 }
2687
2688 return 0;
2689}
2690
2691
2692/*
2693 * Async link()
2694 */
2695struct nfs_link_data {
2696 char *oldpath;
2697 struct nfs_fh3 oldfh;
2698 char *newpath;
2699 char *newobject;
2700 struct nfs_fh3 newdir;
2701};
2702
2703static void free_nfs_link_data(void *mem)
2704{
2705 struct nfs_link_data *data = mem;
2706
2707 if (data->oldpath != NULL) {
2708 free(data->oldpath);
2709 }
2710 if (data->oldfh.data.data_val != NULL) {
2711 free(data->oldfh.data.data_val);
2712 }
2713 if (data->newpath != NULL) {
2714 free(data->newpath);
2715 }
2716 if (data->newdir.data.data_val != NULL) {
2717 free(data->newdir.data.data_val);
2718 }
2719 free(data);
2720}
2721
2722static void nfs_link_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
2723{
2724 LINK3res *res;
2725 struct nfs_cb_data *data = private_data;
2726 struct nfs_context *nfs = data->nfs;
2727 struct nfs_link_data *link_data = data->continue_data;
2728
2729 if (status == RPC_STATUS_ERROR) {
2730 data->cb(-EFAULT, nfs, command_data, data->private_data);
2731 free_nfs_cb_data(data);
2732 return;
2733 }
2734 if (status == RPC_STATUS_CANCEL) {
2735 data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
2736 free_nfs_cb_data(data);
2737 return;
2738 }
2739
2740 res = command_data;
2741 if (res->status != NFS3_OK) {
2742 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));
2743 data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
2744 free_nfs_cb_data(data);
2745 return;
2746 }
2747
2748 data->cb(0, nfs, NULL, data->private_data);
2749 free_nfs_cb_data(data);
2750}
2751
2752static int nfs_link_continue_2_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
2753{
2754 struct nfs_link_data *link_data = data->continue_data;
2755
2756 /* steal the filehandle */
2757 link_data->newdir.data.data_len = data->fh.data.data_len;
2758 link_data->newdir.data.data_val = data->fh.data.data_val;
2759 data->fh.data.data_val = NULL;
2760
2761 if (rpc_nfs_link_async(nfs->rpc, nfs_link_cb, &link_data->oldfh, &link_data->newdir, link_data->newobject, data) != 0) {
2762 rpc_set_error(nfs->rpc, "RPC error: Failed to send LINK call for %s", data->path);
2763 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2764 free_nfs_cb_data(data);
2765 return -1;
2766 }
2767 return 0;
2768}
2769
2770
2771static int nfs_link_continue_1_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
2772{
2773 struct nfs_link_data *link_data = data->continue_data;
2774
2775 /* steal the filehandle */
2776 link_data->oldfh.data.data_len = data->fh.data.data_len;
2777 link_data->oldfh.data.data_val = data->fh.data.data_val;
2778 data->fh.data.data_val = NULL;
2779
2780 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) {
2781 rpc_set_error(nfs->rpc, "RPC error: Failed to send LOOKUP call for %s", link_data->newpath);
2782 data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
2783 free_nfs_cb_data(data);
2784 return -1;
2785 }
2786 data->continue_data = NULL;
2787 free_nfs_cb_data(data);
2788
2789 return 0;
2790}
2791
2792
2793int nfs_link_async(struct nfs_context *nfs, const char *oldpath, const char *newpath, nfs_cb cb, void *private_data)
2794{
2795 char *ptr;
2796 struct nfs_link_data *link_data;
2797
2798 link_data = malloc(sizeof(struct nfs_link_data));
2799 if (link_data == NULL) {
cbbf9d3e 2800 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for link data");
84004dbf
RS
2801 return -1;
2802 }
2803 bzero(link_data, sizeof(struct nfs_link_data));
2804
2805 link_data->oldpath = strdup(oldpath);
2806 if (link_data->oldpath == NULL) {
cbbf9d3e 2807 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for oldpath");
84004dbf 2808 free_nfs_link_data(link_data);
cbbf9d3e 2809 return -1;
84004dbf
RS
2810 }
2811
2812 link_data->newpath = strdup(newpath);
2813 if (link_data->newpath == NULL) {
cbbf9d3e 2814 rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for newpath");
84004dbf 2815 free_nfs_link_data(link_data);
cbbf9d3e 2816 return -1;
84004dbf
RS
2817 }
2818 ptr = rindex(link_data->newpath, '/');
2819 if (ptr == NULL) {
cbbf9d3e 2820 rpc_set_error(nfs->rpc, "Invalid path %s", newpath);
84004dbf 2821 free_nfs_link_data(link_data);
cbbf9d3e 2822 return -1;
84004dbf
RS
2823 }
2824 *ptr = 0;
2825 ptr++;
2826 link_data->newobject = ptr;
2827
2828
2829 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
2830 rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
2831 return -1;
84004dbf
RS
2832 }
2833
2834 return 0;
2835}
2836
2837
2838//qqq replace later with lseek()
2839off_t nfs_get_current_offset(struct nfsfh *nfsfh)
2840{
2841 return nfsfh->offset;
2842}
2843
17ef62fa
RS
2844
2845
2846/*
2847 * Get the maximum supported READ3 size by the server
2848 */
2849size_t nfs_get_readmax(struct nfs_context *nfs)
2850{
2851 return nfs->readmax;
2852}
2853
2854/*
2855 * Get the maximum supported WRITE3 size by the server
2856 */
2857size_t nfs_get_writemax(struct nfs_context *nfs)
2858{
2859 return nfs->writemax;
2860}
1896d37b
RS
2861
2862void nfs_set_error(struct nfs_context *nfs, char *error_string, ...)
2863{
2864 va_list ap;
2865 char *str;
2866
2867 if (nfs->rpc->error_string != NULL) {
2868 free(nfs->rpc->error_string);
2869 }
2870 va_start(ap, error_string);
2871 vasprintf(&str, error_string, ap);
2872 nfs->rpc->error_string = str;
2873 va_end(ap);
2874}
7f0242ca
RS
2875
2876
2877
2878struct mount_cb_data {
2879 rpc_cb cb;
2880 void *private_data;
2881 char *server;
2882};
2883
2884static void free_mount_cb_data(struct mount_cb_data *data)
2885{
2886 if (data->server != NULL) {
2887 free(data->server);
2888 data->server = NULL;
2889 }
2890
2891 free(data);
2892}
2893
2894static void mount_export_5_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
2895{
2896 struct mount_cb_data *data = private_data;
2897
2898 if (status == RPC_STATUS_ERROR) {
2899 data->cb(rpc, -EFAULT, command_data, data->private_data);
2900 free_mount_cb_data(data);
2901 return;
2902 }
2903 if (status == RPC_STATUS_CANCEL) {
2904 data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
2905 free_mount_cb_data(data);
2906 return;
2907 }
2908
2909 data->cb(rpc, 0, command_data, data->private_data);
2910 if (rpc_disconnect(rpc, "normal disconnect") != 0) {
2911 rpc_set_error(rpc, "Failed to disconnect\n");
2912 }
2913 free_mount_cb_data(data);
2914}
2915
2916static void mount_export_4_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
2917{
2918 struct mount_cb_data *data = private_data;
2919
2920 if (status == RPC_STATUS_ERROR) {
2921 data->cb(rpc, -EFAULT, command_data, data->private_data);
2922 free_mount_cb_data(data);
2923 return;
2924 }
2925 if (status == RPC_STATUS_CANCEL) {
2926 data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
2927 free_mount_cb_data(data);
2928 return;
2929 }
2930
2931 if (rpc_mount_export_async(rpc, mount_export_5_cb, data) != 0) {
2932 data->cb(rpc, -ENOMEM, command_data, data->private_data);
2933 free_mount_cb_data(data);
2934 return;
2935 }
2936}
2937
2938static void mount_export_3_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
2939{
2940 struct mount_cb_data *data = private_data;
2941 uint32_t mount_port;
2942
2943 if (status == RPC_STATUS_ERROR) {
2944 data->cb(rpc, -EFAULT, command_data, data->private_data);
2945 free_mount_cb_data(data);
2946 return;
2947 }
2948 if (status == RPC_STATUS_CANCEL) {
2949 data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
2950 free_mount_cb_data(data);
2951 return;
2952 }
2953
2954 mount_port = *(uint32_t *)command_data;
2955 if (mount_port == 0) {
2956 rpc_set_error(rpc, "RPC error. Mount program is not available");
2957 data->cb(rpc, -ENOENT, command_data, data->private_data);
2958 free_mount_cb_data(data);
2959 return;
2960 }
2961
2962 rpc_disconnect(rpc, "normal disconnect");
2963 if (rpc_connect_async(rpc, data->server, mount_port, mount_export_4_cb, data) != 0) {
2964 data->cb(rpc, -ENOMEM, command_data, data->private_data);
2965 free_mount_cb_data(data);
2966 return;
2967 }
2968}
2969
2970static void mount_export_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
2971{
2972 struct mount_cb_data *data = private_data;
2973
2974 if (status == RPC_STATUS_ERROR) {
2975 data->cb(rpc, -EFAULT, command_data, data->private_data);
2976 free_mount_cb_data(data);
2977 return;
2978 }
2979 if (status == RPC_STATUS_CANCEL) {
2980 data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
2981 free_mount_cb_data(data);
2982 return;
2983 }
2984
2985 if (rpc_pmap_getport_async(rpc, MOUNT_PROGRAM, MOUNT_V3, mount_export_3_cb, private_data) != 0) {
2986 data->cb(rpc, -ENOMEM, command_data, data->private_data);
2987 free_mount_cb_data(data);
2988 return;
2989 }
2990}
2991
2992static void mount_export_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
2993{
2994 struct mount_cb_data *data = private_data;
2995
2996 if (status == RPC_STATUS_ERROR) {
2997 data->cb(rpc, -EFAULT, command_data, data->private_data);
2998 free_mount_cb_data(data);
2999 return;
3000 }
3001 if (status == RPC_STATUS_CANCEL) {
3002 data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
3003 free_mount_cb_data(data);
3004 return;
3005 }
3006
3007 if (rpc_pmap_null_async(rpc, mount_export_2_cb, data) != 0) {
3008 data->cb(rpc, -ENOMEM, command_data, data->private_data);
3009 free_mount_cb_data(data);
3010 return;
3011 }
3012}
3013
3014int mount_getexports_async(struct rpc_context *rpc, const char *server, rpc_cb cb, void *private_data)
3015{
3016 struct mount_cb_data *data;
3017
3018 data = malloc(sizeof(struct mount_cb_data));
3019 if (data == NULL) {
3020 return -1;
3021 }
3022 bzero(data, sizeof(struct mount_cb_data));
3023 data->cb = cb;
3024 data->private_data = private_data;
3025 data->server = strdup(server);
3026 if (data->server == NULL) {
3027 free_mount_cb_data(data);
3028 return -1;
3029 }
3030 if (rpc_connect_async(rpc, data->server, 111, mount_export_1_cb, data) != 0) {
3031 free_mount_cb_data(data);
3032 return -1;
3033 }
3034
3035 return 0;
3036}
3037