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