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