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