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