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