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