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