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