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