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