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