Merge pull request #43 from plieven/master
[deb_libnfs.git] / lib / libnfs.c
index deab4f1c1036ef1e1584ea904d3f2cd28214c6a3..b6bd822ebabf2eda89eef9b04ecee4a845055c91 100644 (file)
 /*
  * High level api to nfs filesystems
  */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef AROS
+#include "aros_compat.h"
+#endif
+
 #ifdef WIN32
 #include "win32_compat.h"
-#define DllExport
-#else
-#include <strings.h>
-#ifndef ANDROID
-#include <sys/statvfs.h>
-#else
-#include <sys/vfs.h>
-#define statvfs statfs
 #endif
+
+#ifdef HAVE_UTIME_H
 #include <utime.h>
-#include <unistd.h>
-#endif/*WIN32*/
+#endif
+
+#ifdef ANDROID
+#define statvfs statfs
+#endif
 
 #define _GNU_SOURCE
 
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_VFS_H
+#include <sys/vfs.h>
+#endif
+
+#ifdef HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
 #include <stdio.h>
 #include <stdarg.h>
 #include <stdlib.h>
@@ -43,7 +68,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
-#include <netinet/in.h>
 #include "libnfs-zdr.h"
 #include "libnfs.h"
 #include "libnfs-raw.h"
@@ -149,6 +173,152 @@ char *nfs_get_error(struct nfs_context *nfs)
        return rpc_get_error(nfs->rpc);
 };
 
+static struct nfs_url *nfs_parse_url(struct nfs_context *nfs, const char *url, int dir, int incomplete)
+{
+       struct nfs_url *urls;
+       char *strp, *flagsp, *strp2;
+
+       if (strncmp(url, "nfs://", 6)) {
+               rpc_set_error(nfs->rpc, "Invalid URL specified");
+               return NULL;
+       }
+
+       urls = malloc(sizeof(struct nfs_url));
+       if (urls == NULL) {
+               rpc_set_error(nfs->rpc, "Out of memory");
+               return NULL;
+       }
+
+       urls->server = strdup(url + 6);
+       if (urls->server == NULL) {
+               nfs_destroy_url(urls);
+               rpc_set_error(nfs->rpc, "Out of memory");
+               return NULL;
+       }
+
+       if (urls->server[0] == '/' || urls->server[0] == '\0' ||
+               urls->server[0] == '?') {
+               if (incomplete) {
+                       flagsp = strchr(urls->server, '?');
+                       goto flags;
+               }
+               nfs_destroy_url(urls);
+               rpc_set_error(nfs->rpc, "Invalid server string");
+               return NULL;
+       }
+
+       strp = strchr(urls->server, '/');
+       if (strp == NULL) {
+               if (incomplete) {
+                       flagsp = strchr(urls->server, '?');
+                       goto flags;
+               }
+               nfs_destroy_url(urls);
+               rpc_set_error(nfs->rpc, "Incomplete or invalid URL specified.");
+               return NULL;
+       }
+
+       urls->path = strdup(strp);
+       if (urls->path == NULL) {
+               nfs_destroy_url(urls);
+               rpc_set_error(nfs->rpc, "Out of memory");
+               return NULL;
+       }
+       *strp = 0;
+
+       if (dir) {
+               flagsp = strchr(urls->path, '?');
+               goto flags;
+       }
+
+       strp = strrchr(urls->path, '/');
+       if (strp == NULL) {
+               if (incomplete) {
+                       flagsp = strchr(urls->path, '?');
+                       goto flags;
+               }
+               nfs_destroy_url(urls);
+               rpc_set_error(nfs->rpc, "Incomplete or invalid URL specified.");
+               return NULL;
+       }
+       urls->file = strdup(strp);
+       if (urls->path == NULL) {
+               nfs_destroy_url(urls);
+               rpc_set_error(nfs->rpc, "Out of memory");
+               return NULL;
+       }
+       *strp = 0;
+       flagsp = strchr(urls->file, '?');
+
+flags:
+       if (flagsp) {
+               *flagsp = 0;
+       }
+
+       if (urls->file && !strlen(urls->file)) {
+               free(urls->file);
+               urls->file = NULL;
+               if (!incomplete) {
+                       nfs_destroy_url(urls);
+                       rpc_set_error(nfs->rpc, "Incomplete or invalid URL specified.");
+                       return NULL;
+               }
+       }
+
+       if (urls->server && strlen(urls->server) <= 1) {
+               free(urls->server);
+               urls->server = NULL;
+       }
+
+       while (flagsp != NULL && *(flagsp+1) != 0) {
+               strp = flagsp + 1;
+               flagsp = strchr(strp, '&');
+               if (flagsp) {
+                       *flagsp = 0;
+               }
+               strp2 = strchr(strp, '=');
+               if (strp2) {
+                       *strp2 = 0;
+                       strp2++;
+                       if (!strncmp(strp, "tcp-syncnt", 10)) {
+                               rpc_set_tcp_syncnt(nfs->rpc, atoi(strp2));
+                       } else if (!strncmp(strp, "uid", 3)) {
+                               rpc_set_uid(nfs->rpc, atoi(strp2));
+                       } else if (!strncmp(strp, "gid", 3)) {
+                               rpc_set_gid(nfs->rpc, atoi(strp2));
+                       }
+               }
+       }
+
+       return urls;
+}
+
+struct nfs_url *nfs_parse_url_full(struct nfs_context *nfs, const char *url)
+{
+       return nfs_parse_url(nfs, url, 0, 0);
+}
+
+struct nfs_url *nfs_parse_url_dir(struct nfs_context *nfs, const char *url)
+{
+       return nfs_parse_url(nfs, url, 1, 0);
+}
+
+struct nfs_url *nfs_parse_url_incomplete(struct nfs_context *nfs, const char *url)
+{
+       return nfs_parse_url(nfs, url, 0, 1);
+}
+
+
+void nfs_destroy_url(struct nfs_url *url)
+{
+       if (url) {
+               free(url->server);
+               free(url->path);
+               free(url->file);
+       }
+       free(url);
+}
+
 struct nfs_context *nfs_init_context(void)
 {
        struct nfs_context *nfs;
@@ -195,6 +365,155 @@ void nfs_destroy_context(struct nfs_context *nfs)
        free(nfs);
 }
 
+struct rpc_cb_data {
+       char *server;
+       uint32_t program;
+       uint32_t version;
+
+       rpc_cb cb;
+       void *private_data;
+};       
+
+void free_rpc_cb_data(struct rpc_cb_data *data)
+{
+       free(data->server);
+       data->server = NULL;
+       free(data);
+}
+
+static void rpc_connect_program_4_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+       struct rpc_cb_data *data = private_data;
+
+       assert(rpc->magic == RPC_CONTEXT_MAGIC);
+
+       /* Dont want any more callbacks even if the socket is closed */
+       rpc->connect_cb = NULL;
+
+       if (status == RPC_STATUS_ERROR) {
+               data->cb(rpc, status, command_data, data->private_data);
+               free_rpc_cb_data(data);
+               return;
+       }
+       if (status == RPC_STATUS_CANCEL) {
+               data->cb(rpc, status, "Command was cancelled", data->private_data);
+               free_rpc_cb_data(data);
+               return;
+       }
+
+       data->cb(rpc, status, NULL, data->private_data);
+       free_rpc_cb_data(data);
+}
+
+static void rpc_connect_program_3_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+       struct rpc_cb_data *data = private_data;
+       uint32_t rpc_port;
+
+       assert(rpc->magic == RPC_CONTEXT_MAGIC);
+
+       if (status == RPC_STATUS_ERROR) {       
+               data->cb(rpc, status, command_data, data->private_data);
+               free_rpc_cb_data(data);
+               return;
+       }
+       if (status == RPC_STATUS_CANCEL) {
+               data->cb(rpc, status, "Command was cancelled", data->private_data);
+               free_rpc_cb_data(data);
+               return;
+       }
+
+       rpc_port = *(uint32_t *)command_data;
+       if (rpc_port == 0) {
+               rpc_set_error(rpc, "RPC error. Program is not available on %s", data->server);
+               data->cb(rpc, RPC_STATUS_ERROR, rpc_get_error(rpc), data->private_data);
+               free_rpc_cb_data(data);
+               return;
+       }
+
+       rpc_disconnect(rpc, "normal disconnect");
+       if (rpc_connect_async(rpc, data->server, rpc_port, rpc_connect_program_4_cb, data) != 0) {
+               data->cb(rpc, status, command_data, data->private_data);
+               free_rpc_cb_data(data);
+               return;
+       }
+}
+
+static void rpc_connect_program_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+       struct rpc_cb_data *data = private_data;
+
+       assert(rpc->magic == RPC_CONTEXT_MAGIC);
+
+       if (status == RPC_STATUS_ERROR) {
+               data->cb(rpc, status, command_data, data->private_data);
+               free_rpc_cb_data(data);
+               return;
+       }
+       if (status == RPC_STATUS_CANCEL) {
+               data->cb(rpc, status, "Command was cancelled", data->private_data);
+               free_rpc_cb_data(data);
+               return;
+       }
+
+       if (rpc_pmap_getport_async(rpc, data->program, data->version, IPPROTO_TCP, rpc_connect_program_3_cb, private_data) != 0) {
+               data->cb(rpc, status, command_data, data->private_data);
+               free_rpc_cb_data(data);
+               return;
+       }
+}
+
+static void rpc_connect_program_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+       struct rpc_cb_data *data = private_data;
+
+       assert(rpc->magic == RPC_CONTEXT_MAGIC);
+
+       /* Dont want any more callbacks even if the socket is closed */
+       rpc->connect_cb = NULL;
+
+       if (status == RPC_STATUS_ERROR) {
+               data->cb(rpc, status, command_data, data->private_data);
+               free_rpc_cb_data(data);
+               return;
+       }
+       if (status == RPC_STATUS_CANCEL) {
+               data->cb(rpc, status, "Command was cancelled", data->private_data);
+               free_rpc_cb_data(data);
+               return;
+       }
+
+       if (rpc_pmap_null_async(rpc, rpc_connect_program_2_cb, data) != 0) {
+               data->cb(rpc, status, command_data, data->private_data);
+               free_rpc_cb_data(data);
+               return;
+       }
+}
+
+int rpc_connect_program_async(struct rpc_context *rpc, char *server, int program, int version, rpc_cb cb, void *private_data)
+{
+       struct rpc_cb_data *data;
+
+       data = malloc(sizeof(struct rpc_cb_data));
+       if (data == NULL) {
+               return -1;
+       }
+       memset(data, 0, sizeof(struct rpc_cb_data));
+       data->server       = strdup(server);
+       data->program      = program;
+       data->version      = version;
+
+       data->cb           = cb;
+       data->private_data = private_data;
+
+       if (rpc_connect_async(rpc, server, 111, rpc_connect_program_1_cb, data) != 0) {
+               rpc_set_error(rpc, "Failed to start connection");
+               free_rpc_cb_data(data);
+               return -1;
+       }
+       return 0;
+}
+
 void free_nfs_cb_data(struct nfs_cb_data *data)
 {
        if (data->saved_path != NULL) {
@@ -251,6 +570,7 @@ static void nfs_mount_9_cb(struct rpc_context *rpc, int status, void *command_da
        struct nfs_cb_data *data = private_data;
        struct nfs_context *nfs = data->nfs;
        FSINFO3res *res = command_data;
+       struct GETATTR3args args;
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
@@ -268,7 +588,11 @@ static void nfs_mount_9_cb(struct rpc_context *rpc, int status, void *command_da
        nfs->readmax = res->FSINFO3res_u.resok.rtmax;
        nfs->writemax = res->FSINFO3res_u.resok.wtmax;
 
-       if (rpc_nfs_getattr_async(rpc, nfs_mount_10_cb, &nfs->rootfh, data) != 0) {
+       memset(&args, 0, sizeof(GETATTR3args));
+       args.object.data.data_len = nfs->rootfh.data.data_len; 
+       args.object.data.data_val = nfs->rootfh.data.data_val; 
+
+       if (rpc_nfs3_getattr_async(rpc, nfs_mount_10_cb, &args, data) != 0) {
                data->cb(-ENOMEM, nfs, command_data, data->private_data);
                free_nfs_cb_data(data);
                return;
@@ -601,6 +925,7 @@ static void nfs_lookup_path_1_cb(struct rpc_context *rpc, int status, void *comm
 static int nfs_lookup_path_async_internal(struct nfs_context *nfs, struct nfs_cb_data *data, struct nfs_fh3 *fh)
 {
        char *path, *str;
+       LOOKUP3args args;
 
        while (*data->path == '/') {
              data->path++;
@@ -631,7 +956,13 @@ static int nfs_lookup_path_async_internal(struct nfs_context *nfs, struct nfs_cb
                return 0;
        }
 
-       if (rpc_nfs_lookup_async(nfs->rpc, nfs_lookup_path_1_cb, fh, path, data) != 0) {
+
+       memset(&args, 0, sizeof(LOOKUP3args));
+       args.what.dir.data.data_len = fh->data.data_len; 
+       args.what.dir.data.data_val = fh->data.data_val; 
+       args.what.name              = path;
+
+       if (rpc_nfs3_lookup_async(nfs->rpc, nfs_lookup_path_1_cb, &args, data) != 0) {
                rpc_set_error(nfs->rpc, "RPC error: Failed to send lookup call for %s", data->path);
                data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
                free_nfs_cb_data(data);
@@ -644,8 +975,8 @@ static int nfs_lookuppath_async(struct nfs_context *nfs, const char *path, nfs_c
 {
        struct nfs_cb_data *data;
 
-       if (path[0] != '/') {
-               rpc_set_error(nfs->rpc, "Pathname is not absulute %s", path);
+       if (path[0] != 0 && path[0] != '/') {
+               rpc_set_error(nfs->rpc, "Pathname is not absolute %s", path);
                return -1;
        }
 
@@ -740,7 +1071,13 @@ static void nfs_stat_1_cb(struct rpc_context *rpc, int status, void *command_dat
 
 static int nfs_stat_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
 {
-       if (rpc_nfs_getattr_async(nfs->rpc, nfs_stat_1_cb, &data->fh, data) != 0) {
+       struct GETATTR3args args;
+
+       memset(&args, 0, sizeof(GETATTR3args));
+       args.object.data.data_len = data->fh.data.data_len; 
+       args.object.data.data_val = data->fh.data.data_val; 
+
+       if (rpc_nfs3_getattr_async(nfs->rpc, nfs_stat_1_cb, &args, data) != 0) {
                rpc_set_error(nfs->rpc, "RPC error: Failed to send STAT GETATTR call for %s", data->path);
                data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
                free_nfs_cb_data(data);
@@ -844,6 +1181,7 @@ static void nfs_open_cb(struct rpc_context *rpc, int status, void *command_data,
 static int nfs_open_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
 {
        int nfsmode = 0;
+       ACCESS3args args;
 
        if (data->continue_int & O_WRONLY) {
                nfsmode |= ACCESS3_MODIFY;
@@ -855,7 +1193,12 @@ static int nfs_open_continue_internal(struct nfs_context *nfs, struct nfs_cb_dat
                nfsmode |= ACCESS3_READ;
        }
 
-       if (rpc_nfs_access_async(nfs->rpc, nfs_open_cb, &data->fh, nfsmode, data) != 0) {
+       memset(&args, 0, sizeof(ACCESS3args));
+       args.object.data.data_len = data->fh.data.data_len;
+       args.object.data.data_val = data->fh.data.data_val;
+       args.access = nfsmode;
+
+       if (rpc_nfs3_access_async(nfs->rpc, nfs_open_cb, &args, data) != 0) {
                rpc_set_error(nfs->rpc, "RPC error: Failed to send OPEN ACCESS call for %s", data->path);
                data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
                free_nfs_cb_data(data);
@@ -993,7 +1336,15 @@ int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offse
        nfsfh->offset = offset;
 
        if (count <= nfs_get_readmax(nfs)) {
-               if (rpc_nfs_read_async(nfs->rpc, nfs_pread_cb, &nfsfh->fh, offset, count, data) != 0) {
+               READ3args args;
+
+               memset(&args, 0, sizeof(READ3args));
+               args.file.data.data_len = nfsfh->fh.data.data_len;
+               args.file.data.data_val = nfsfh->fh.data.data_val;
+               args.offset = offset;
+               args.count = count;
+
+               if (rpc_nfs3_read_async(nfs->rpc, nfs_pread_cb, &args, data) != 0) {
                        rpc_set_error(nfs->rpc, "RPC error: Failed to send READ call for %s", data->path);
                        data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
                        free_nfs_cb_data(data);
@@ -1004,7 +1355,7 @@ int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offse
 
        /* trying to read more than maximum server read size, we has to chop it up into smaller
         * reads and collect into a reassembly buffer.
-        * we send all reads in parallell so that performance is still good.
+        * we send all reads in parallel so that performance is still good.
         */
        data->max_offset = offset;
        data->start_offset = offset;
@@ -1020,6 +1371,7 @@ int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offse
        while (count > 0) {
                uint64_t readcount = count;
                struct nfs_mcb_data *mdata;
+               READ3args args;
 
                if (readcount > nfs_get_readmax(nfs)) {
                        readcount = nfs_get_readmax(nfs);
@@ -1034,7 +1386,14 @@ int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offse
                mdata->data   = data;
                mdata->offset = offset;
                mdata->count  = readcount;
-               if (rpc_nfs_read_async(nfs->rpc, nfs_pread_mcb, &nfsfh->fh, offset, readcount, mdata) != 0) {
+
+               memset(&args, 0, sizeof(READ3args));
+               args.file.data.data_len = nfsfh->fh.data.data_len;
+               args.file.data.data_val = nfsfh->fh.data.data_val;
+               args.offset = offset;
+               args.count = readcount;
+
+               if (rpc_nfs3_read_async(nfs->rpc, nfs_pread_mcb, &args, mdata) != 0) {
                        rpc_set_error(nfs->rpc, "RPC error: Failed to send READ call for %s", data->path);
                        data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
                        free(mdata);
@@ -1173,7 +1532,18 @@ int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offs
        nfsfh->offset = offset;
 
        if (count <= nfs_get_writemax(nfs)) {
-               if (rpc_nfs_write_async(nfs->rpc, nfs_pwrite_cb, &nfsfh->fh, buf, offset, count, nfsfh->is_sync?FILE_SYNC:UNSTABLE, data) != 0) {
+               WRITE3args args;
+
+               memset(&args, 0, sizeof(WRITE3args));
+               args.file.data.data_len = nfsfh->fh.data.data_len;
+               args.file.data.data_val = nfsfh->fh.data.data_val;
+               args.offset = offset;
+               args.count  = count;
+               args.stable = nfsfh->is_sync?FILE_SYNC:UNSTABLE;
+               args.data.data_len = count;
+               args.data.data_val = buf;
+
+               if (rpc_nfs3_write_async(nfs->rpc, nfs_pwrite_cb, &args, data) != 0) {
                        rpc_set_error(nfs->rpc, "RPC error: Failed to send WRITE call for %s", data->path);
                        data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
                        free_nfs_cb_data(data);
@@ -1184,7 +1554,7 @@ int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offs
 
        /* trying to write more than maximum server write size, we has to chop it up into smaller
         * chunks.
-        * we send all writes in parallell so that performance is still good.
+        * we send all writes in parallel so that performance is still good.
         */
        data->max_offset = offset;
        data->start_offset = offset;
@@ -1192,6 +1562,7 @@ int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offs
        while (count > 0) {
                uint64_t writecount = count;
                struct nfs_mcb_data *mdata;
+               WRITE3args args;
 
                if (writecount > nfs_get_writemax(nfs)) {
                        writecount = nfs_get_writemax(nfs);
@@ -1207,7 +1578,16 @@ int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offs
                mdata->offset = offset;
                mdata->count  = writecount;
 
-               if (rpc_nfs_write_async(nfs->rpc, nfs_pwrite_mcb, &nfsfh->fh, &buf[offset - data->start_offset], offset, writecount, nfsfh->is_sync?FILE_SYNC:UNSTABLE, mdata) != 0) {
+               memset(&args, 0, sizeof(WRITE3args));
+               args.file.data.data_len = nfsfh->fh.data.data_len;
+               args.file.data.data_val = nfsfh->fh.data.data_val;
+               args.offset = offset;
+               args.count  = writecount;
+               args.stable = nfsfh->is_sync?FILE_SYNC:UNSTABLE;
+               args.data.data_len = writecount;
+               args.data.data_val = &buf[offset - data->start_offset];
+
+               if (rpc_nfs3_write_async(nfs->rpc, nfs_pwrite_mcb, &args, mdata) != 0) {
                        rpc_set_error(nfs->rpc, "RPC error: Failed to send WRITE call for %s", data->path);
                        data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
                        free(mdata);
@@ -1259,6 +1639,7 @@ int nfs_close_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, voi
 int nfs_fstat_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data)
 {
        struct nfs_cb_data *data;
+       struct GETATTR3args args;
 
        data = malloc(sizeof(struct nfs_cb_data));
        if (data == NULL) {
@@ -1270,7 +1651,11 @@ int nfs_fstat_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, voi
        data->cb           = cb;
        data->private_data = private_data;
 
-       if (rpc_nfs_getattr_async(nfs->rpc, nfs_stat_1_cb, &nfsfh->fh, data) != 0) {
+       memset(&args, 0, sizeof(GETATTR3args));
+       args.object.data.data_len = nfsfh->fh.data.data_len; 
+       args.object.data.data_val = nfsfh->fh.data.data_val; 
+
+       if (rpc_nfs3_getattr_async(nfs->rpc, nfs_stat_1_cb, &args, data) != 0) {
                rpc_set_error(nfs->rpc, "RPC error: Failed to send STAT GETATTR call for %s", data->path);
                data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
                free_nfs_cb_data(data);
@@ -1659,10 +2044,10 @@ static void nfs_create_2_cb(struct rpc_context *rpc, int status, void *command_d
        }
        memset(nfsfh, 0, sizeof(struct nfsfh));
 
-       /* steal the filehandle */
-       nfsfh->fh.data.data_len = data->fh.data.data_len;
-       nfsfh->fh.data.data_val = data->fh.data.data_val;
-       data->fh.data.data_val = NULL;
+       /* copy the filehandle */
+       nfsfh->fh.data.data_len = res->LOOKUP3res_u.resok.object.data.data_len;
+       nfsfh->fh.data.data_val = malloc(nfsfh->fh.data.data_len);
+       memcpy(nfsfh->fh.data.data_val, res->LOOKUP3res_u.resok.object.data.data_val, nfsfh->fh.data.data_len);
 
        data->cb(0, nfs, nfsfh, data->private_data);
        free_nfs_cb_data(data);
@@ -1676,6 +2061,7 @@ static void nfs_creat_1_cb(struct rpc_context *rpc, int status, void *command_da
        struct nfs_cb_data *data = private_data;
        struct nfs_context *nfs = data->nfs;
        char *str = data->continue_data;
+       LOOKUP3args args;
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
@@ -1695,11 +2081,16 @@ static void nfs_creat_1_cb(struct rpc_context *rpc, int status, void *command_da
        if (res->status != NFS3_OK) {
                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));
                data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
-
+               free_nfs_cb_data(data);
                return;
        }
 
-       if (rpc_nfs_lookup_async(nfs->rpc, nfs_create_2_cb, &data->fh, str, data) != 0) {
+       memset(&args, 0, sizeof(LOOKUP3args));
+       args.what.dir.data.data_len = data->fh.data.data_len; 
+       args.what.dir.data.data_val = data->fh.data.data_val; 
+       args.what.name              = str;
+
+       if (rpc_nfs3_lookup_async(nfs->rpc, nfs_create_2_cb, &args, data) != 0) {
                rpc_set_error(nfs->rpc, "RPC error: Failed to send lookup call for %s/%s", data->saved_path, str);
                data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
                free_nfs_cb_data(data);
@@ -1715,7 +2106,6 @@ static int nfs_creat_continue_internal(struct nfs_context *nfs, struct nfs_cb_da
 
        str = &str[strlen(str) + 1];
 
-
        memset(&args, 0, sizeof(CREATE3args));
        args.where.dir.data.data_len = data->fh.data.data_len;
        args.where.dir.data.data_val = data->fh.data.data_val;
@@ -1751,7 +2141,7 @@ int nfs_creat_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb
        }
        *ptr = 0;
 
-       /* new_path now points to the parent directory,  and beyond the nul terminateor is the new directory to create */
+       /* new_path now points to the parent directory,  and beyond the nul terminator is the new directory to create */
        if (nfs_lookuppath_async(nfs, new_path, cb, private_data, nfs_creat_continue_internal, new_path, free, mode) != 0) {
                rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
                return -1;
@@ -2110,12 +2500,18 @@ static void nfs_opendir2_cb(struct rpc_context *rpc, int status, void *command_d
        rdpe_cb_data->data = data;
        for (nfsdirent = nfsdir->entries; nfsdirent; nfsdirent = nfsdirent->next) {
                struct rdpe_lookup_cb_data *rdpe_lookup_cb_data;
+               LOOKUP3args args;
 
                rdpe_lookup_cb_data = malloc(sizeof(struct rdpe_lookup_cb_data));
                rdpe_lookup_cb_data->rdpe_cb_data = rdpe_cb_data;
                rdpe_lookup_cb_data->nfsdirent = nfsdirent;
 
-               if (rpc_nfs_lookup_async(nfs->rpc, nfs_opendir3_cb, &data->fh, nfsdirent->name, rdpe_lookup_cb_data) != 0) {
+               memset(&args, 0, sizeof(LOOKUP3args));
+               args.what.dir.data.data_len = data->fh.data.data_len; 
+               args.what.dir.data.data_val = data->fh.data.data_val; 
+               args.what.name              = nfsdirent->name;
+
+               if (rpc_nfs3_lookup_async(nfs->rpc, nfs_opendir3_cb, &args, rdpe_lookup_cb_data) != 0) {
                        rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR LOOKUP call");
 
                        /* if we have already commands in flight, we cant just stop, we have to wait for the
@@ -2346,6 +2742,7 @@ static void nfs_lseek_1_cb(struct rpc_context *rpc, int status, void *command_da
 int nfs_lseek_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, int whence, nfs_cb cb, void *private_data)
 {
        struct lseek_cb_data *data;
+       struct GETATTR3args args;
 
        if (whence == SEEK_SET) {
                nfsfh->offset = offset;
@@ -2370,7 +2767,11 @@ int nfs_lseek_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offse
        data->cb           = cb;
        data->private_data = private_data;
 
-       if (rpc_nfs_getattr_async(nfs->rpc, nfs_lseek_1_cb, &nfsfh->fh, data) != 0) {
+       memset(&args, 0, sizeof(GETATTR3args));
+       args.object.data.data_len = nfsfh->fh.data.data_len; 
+       args.object.data.data_val = nfsfh->fh.data.data_val; 
+
+       if (rpc_nfs3_getattr_async(nfs->rpc, nfs_lseek_1_cb, &args, data) != 0) {
                rpc_set_error(nfs->rpc, "RPC error: Failed to send LSEEK GETATTR call");
                free(data);
                return -1;
@@ -2871,9 +3272,6 @@ int nfs_utime_async(struct nfs_context *nfs, const char *path, struct utimbuf *t
 }
 
 
-
-
-
 /*
  * Async access()
  */
@@ -2935,6 +3333,7 @@ static void nfs_access_cb(struct rpc_context *rpc, int status, void *command_dat
 static int nfs_access_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
 {
        int nfsmode = 0;
+       ACCESS3args args;
 
        if (data->continue_int & R_OK) {
                nfsmode |= ACCESS3_READ;
@@ -2946,7 +3345,12 @@ static int nfs_access_continue_internal(struct nfs_context *nfs, struct nfs_cb_d
                nfsmode |= ACCESS3_EXECUTE;
        }
 
-       if (rpc_nfs_access_async(nfs->rpc, nfs_access_cb, &data->fh, nfsmode, data) != 0) {
+       memset(&args, 0, sizeof(ACCESS3args));
+       args.object.data.data_len = data->fh.data.data_len;
+       args.object.data.data_val = data->fh.data.data_val;
+       args.access = nfsmode;
+
+       if (rpc_nfs3_access_async(nfs->rpc, nfs_access_cb, &args, data) != 0) {
                rpc_set_error(nfs->rpc, "RPC error: Failed to send OPEN ACCESS call for %s", data->path);
                data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
                free_nfs_cb_data(data);
@@ -3426,11 +3830,7 @@ uint64_t nfs_get_readmax(struct nfs_context *nfs)
  */
 uint64_t nfs_get_writemax(struct nfs_context *nfs)
 {
-       /* Some ZDR libraries can not marshall PDUs bigger than this */
-        if (nfs->writemax < 32768) {
-               return nfs->writemax;
-       }
-       return 32768;
+       return nfs->writemax;
 }
 
 void nfs_set_error(struct nfs_context *nfs, char *error_string, ...)