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