[win32] - make it compile on win32
[deb_libnfs.git] / lib / libnfs.c
index 06eea35a343c9a3d63a0bfe72f02b3761bd85131..1f64bd0fef4acfb16afb19feabc6657ddfea33bb 100644 (file)
 /*
  * High level api to nfs filesystems
  */
+#ifdef WIN32
+#include "win32_compat.h"
+#define DllExport
+#else
+#include <strings.h>
+#include <sys/statvfs.h>
+#include <utime.h>
+#include <unistd.h>
+#endif/*WIN32*/
+
+#define _GNU_SOURCE
 
 #include <stdio.h>
+#include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
-#include <strings.h>
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <sys/statvfs.h>
-#include <utime.h>
-#include <unistd.h>
 #include <fcntl.h>
 #include "libnfs.h"
 #include "libnfs-raw.h"
 #include "libnfs-raw-mount.h"
 #include "libnfs-raw-nfs.h"
+#include "libnfs-private.h"
+
+struct nfsdir {
+       struct nfsdirent *entries;
+       struct nfsdirent *current;
+};
 
 struct nfsfh {
        struct nfs_fh3 fh;
@@ -40,9 +54,13 @@ struct nfsfh {
        off_t offset;
 };
 
-struct nfsdir {
-       struct nfsdirent *entries;
-       struct nfsdirent *current;
+struct nfs_context {
+       struct rpc_context *rpc;
+       char *server;
+       char *export;
+       struct nfs_fh3 rootfh;
+       size_t readmax;
+       size_t writemax;
 };
 
 void nfs_free_nfsdir(struct nfsdir *nfsdir)
@@ -58,15 +76,6 @@ void nfs_free_nfsdir(struct nfsdir *nfsdir)
        free(nfsdir);
 }
 
-struct nfs_context {
-       struct rpc_context *rpc;
-       char *server;
-       char *export;
-       struct nfs_fh3 rootfh;
-       size_t readmax;
-       size_t writemax;
-};
-
 struct nfs_cb_data;
 typedef int (*continue_func)(struct nfs_context *nfs, struct nfs_cb_data *data);
 
@@ -84,6 +93,19 @@ struct nfs_cb_data {
        int continue_int;
 
        struct nfs_fh3 fh;
+
+       /* for multi-read/write calls. */
+       int error;
+       int cancel;
+       int num_calls;
+       off_t start_offset, max_offset;
+       char *buffer;
+};
+
+struct nfs_mcb_data {
+       struct nfs_cb_data *data;
+       off_t offset;
+       size_t count;
 };
 
 static int nfs_lookup_path_async_internal(struct nfs_context *nfs, struct nfs_cb_data *data, struct nfs_fh3 *fh);
@@ -91,7 +113,7 @@ static int nfs_lookup_path_async_internal(struct nfs_context *nfs, struct nfs_cb
 
 void nfs_set_auth(struct nfs_context *nfs, struct AUTH *auth)
 {
-       return rpc_set_auth(nfs->rpc, auth);
+       rpc_set_auth(nfs->rpc, auth);
 }
 
 int nfs_get_fd(struct nfs_context *nfs)
@@ -120,16 +142,20 @@ struct nfs_context *nfs_init_context(void)
 
        nfs = malloc(sizeof(struct nfs_context));
        if (nfs == NULL) {
-               printf("Failed to allocate nfs context\n");
                return NULL;
        }
        nfs->rpc = rpc_init_context();
        if (nfs->rpc == NULL) {
-               printf("Failed to allocate rpc sub-context\n");
                free(nfs);
                return NULL;
        }
 
+       nfs->server = NULL;
+       nfs->export = NULL;
+
+       nfs->rootfh.data.data_len = 0;
+       nfs->rootfh.data.data_val = NULL;
+
        return nfs;
 }
 
@@ -173,6 +199,11 @@ void free_nfs_cb_data(struct nfs_cb_data *data)
                data->fh.data.data_val = NULL;
        }
 
+       if (data->buffer != NULL) {
+               free(data->buffer);
+               data->buffer = NULL;
+       }
+
        free(data);
 }
 
@@ -451,24 +482,34 @@ static void nfs_mount_1_cb(struct rpc_context *rpc, int status, void *command_da
 int nfs_mount_async(struct nfs_context *nfs, const char *server, const char *export, nfs_cb cb, void *private_data)
 {
        struct nfs_cb_data *data;
+       char *new_server, *new_export;
 
        data = malloc(sizeof(struct nfs_cb_data));
        if (data == NULL) {
-               rpc_set_error(nfs->rpc, "out of memory");
-               printf("failed to allocate memory for nfs mount data\n");
+               rpc_set_error(nfs->rpc, "out of memory. failed to allocate memory for nfs mount data");
                return -1;
        }
-       bzero(data, sizeof(struct nfs_cb_data));
-       nfs->server        = strdup(server);
-       nfs->export        = strdup(export);
+       memset(data, 0, sizeof(struct nfs_cb_data));
+       new_server = strdup(server);
+       new_export = strdup(export);
+       if (nfs->server != NULL) {
+               free(nfs->server);
+               nfs->server = NULL;
+       }
+       nfs->server        = new_server;
+       if (nfs->export != NULL) {
+               free(nfs->export);
+               nfs->export = NULL;
+       }
+       nfs->export        = new_export;
        data->nfs          = nfs;
        data->cb           = cb;
        data->private_data = private_data;
 
        if (rpc_connect_async(nfs->rpc, server, 111, nfs_mount_1_cb, data) != 0) {
-               printf("Failed to start connection\n");
+               rpc_set_error(nfs->rpc, "Failed to start connection");
                free_nfs_cb_data(data);
-               return -4;
+               return -1;
        }
 
        return 0;
@@ -522,7 +563,7 @@ static int nfs_lookup_path_async_internal(struct nfs_context *nfs, struct nfs_cb
        }
 
        path = data->path;
-       str = index(path, '/');
+       str = strchr(path, '/');
        if (str != NULL) {
                *str = 0;
                data->path = str+1;
@@ -567,11 +608,9 @@ static int nfs_lookuppath_async(struct nfs_context *nfs, const char *path, nfs_c
        data = malloc(sizeof(struct nfs_cb_data));
        if (data == NULL) {
                rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
-               printf("failed to allocate memory for nfs cb data\n");
-               free_nfs_cb_data(data);
-               return -2;
+               return -1;
        }
-       bzero(data, sizeof(struct nfs_cb_data));
+       memset(data, 0, sizeof(struct nfs_cb_data));
        data->nfs                = nfs;
        data->cb                 = cb;
        data->continue_cb        = continue_cb;
@@ -582,14 +621,12 @@ static int nfs_lookuppath_async(struct nfs_context *nfs, const char *path, nfs_c
        data->saved_path         = strdup(path);
        if (data->saved_path == NULL) {
                rpc_set_error(nfs->rpc, "out of memory: failed to copy path string");
-               printf("failed to allocate memory for path string\n");
                free_nfs_cb_data(data);
-               return -2;
+               return -1;
        }
        data->path = data->saved_path;
 
        if (nfs_lookup_path_async_internal(nfs, data, &nfs->rootfh) != 0) {
-               printf("failed to lookup path\n");
                /* return 0 here since the callback will be invoked if there is a failure */
                return 0;
        }
@@ -632,13 +669,18 @@ static void nfs_stat_1_cb(struct rpc_context *rpc _U_, int status, void *command
         st.st_dev     = -1;
         st.st_ino     = res->GETATTR3res_u.resok.obj_attributes.fileid;
         st.st_mode    = res->GETATTR3res_u.resok.obj_attributes.mode;
+       if (res->GETATTR3res_u.resok.obj_attributes.type == NF3DIR) {
+               st.st_mode |= S_IFDIR ;
+       }
         st.st_nlink   = res->GETATTR3res_u.resok.obj_attributes.nlink;
         st.st_uid     = res->GETATTR3res_u.resok.obj_attributes.uid;
         st.st_gid     = res->GETATTR3res_u.resok.obj_attributes.gid;
         st.st_rdev    = 0;
         st.st_size    = res->GETATTR3res_u.resok.obj_attributes.size;
+#ifndef WIN32
         st.st_blksize = 4096;
         st.st_blocks  = res->GETATTR3res_u.resok.obj_attributes.size / 4096;
+#endif//WIN32        
         st.st_atime   = res->GETATTR3res_u.resok.obj_attributes.atime.seconds;
         st.st_mtime   = res->GETATTR3res_u.resok.obj_attributes.mtime.seconds;
         st.st_ctime   = res->GETATTR3res_u.resok.obj_attributes.ctime.seconds;
@@ -661,7 +703,7 @@ static int nfs_stat_continue_internal(struct nfs_context *nfs, struct nfs_cb_dat
 int nfs_stat_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
 {
        if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_stat_continue_internal, NULL, NULL, 0) != 0) {
-               printf("Out of memory: failed to start parsing the path components\n");
+               rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
                return -1;
        }
 
@@ -733,7 +775,7 @@ static void nfs_open_cb(struct rpc_context *rpc _U_, int status, void *command_d
                free_nfs_cb_data(data);
                return;
        }
-       bzero(nfsfh, sizeof(struct nfsfh));
+       memset(nfsfh, 0, sizeof(struct nfsfh));
 
        if (data->continue_int & O_SYNC) {
                nfsfh->is_sync = 1;
@@ -774,8 +816,8 @@ static int nfs_open_continue_internal(struct nfs_context *nfs, struct nfs_cb_dat
 int nfs_open_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data)
 {
        if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_open_continue_internal, NULL, NULL, mode) != 0) {
-               printf("Out of memory: failed to start parsing the path components\n");
-               return -2;
+               rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
+               return -1;
        }
 
        return 0;
@@ -818,6 +860,66 @@ static void nfs_pread_cb(struct rpc_context *rpc _U_, int status, void *command_
        free_nfs_cb_data(data);
 }
 
+static void nfs_pread_mcb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
+{
+       struct nfs_mcb_data *mdata = private_data;
+       struct nfs_cb_data *data = mdata->data;
+       struct nfs_context *nfs = data->nfs;
+       READ3res *res;
+
+       data->num_calls--;
+
+       if (status == RPC_STATUS_ERROR) {
+               /* flag the failure but do not invoke callback until we have received all responses */
+               data->error = 1;
+       }
+       if (status == RPC_STATUS_CANCEL) {
+               /* flag the cancellation but do not invoke callback until we have received all responses */
+               data->cancel = 1;
+       }
+
+       /* reassemble the data into the buffer */
+       if (status == RPC_STATUS_SUCCESS) {
+               res = command_data;
+               if (res->status != NFS3_OK) {
+                       rpc_set_error(nfs->rpc, "NFS: Read failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
+                       data->error = 1;
+               } else  {
+                       if (res->READ3res_u.resok.count > 0) {
+                               memcpy(&data->buffer[mdata->offset - data->start_offset], res->READ3res_u.resok.data.data_val, res->READ3res_u.resok.count);
+                               if ((unsigned)data->max_offset < mdata->offset + res->READ3res_u.resok.count) {
+                                       data->max_offset = mdata->offset + res->READ3res_u.resok.count;
+                               }
+                       }
+               }
+       }
+
+       if (data->num_calls > 0) {
+               /* still waiting for more replies */
+               free(mdata);
+               return;
+       }
+
+       if (data->error != 0) {
+               data->cb(-EFAULT, nfs, command_data, data->private_data);
+               free_nfs_cb_data(data);
+               free(mdata);
+               return;
+       }
+       if (data->cancel != 0) {
+               data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
+               free_nfs_cb_data(data);
+               free(mdata);
+               return;
+       }
+
+       data->nfsfh->offset = data->max_offset;
+       data->cb(data->max_offset - data->start_offset, nfs, data->buffer, data->private_data);
+
+       free_nfs_cb_data(data);
+       free(mdata);
+}
+
 int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, size_t count, nfs_cb cb, void *private_data)
 {
        struct nfs_cb_data *data;
@@ -825,24 +927,71 @@ int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset,
        data = malloc(sizeof(struct nfs_cb_data));
        if (data == NULL) {
                rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
-               printf("failed to allocate memory for nfs cb data\n");
-               free_nfs_cb_data(data);
                return -1;
        }
-       bzero(data, sizeof(struct nfs_cb_data));
+       memset(data, 0, sizeof(struct nfs_cb_data));
        data->nfs          = nfs;
        data->cb           = cb;
        data->private_data = private_data;
        data->nfsfh        = nfsfh;
 
        nfsfh->offset = offset;
-       if (rpc_nfs_read_async(nfs->rpc, nfs_pread_cb, &nfsfh->fh, offset, count, data) != 0) {
-               rpc_set_error(nfs->rpc, "RPC error: Failed to send READ call for %s", data->path);
+
+       if (count <= nfs_get_readmax(nfs)) {
+               if (rpc_nfs_read_async(nfs->rpc, nfs_pread_cb, &nfsfh->fh, offset, count, 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);
+                       return -1;
+               }
+               return 0;
+       }
+
+       /* 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.
+        */
+       data->max_offset = offset;
+       data->start_offset = offset;
+
+       data->buffer =  malloc(count);
+       if (data->buffer == NULL) {
+               rpc_set_error(nfs->rpc, "Out-Of-Memory: Failed to allocate reassembly buffer for %d bytes", (int)count);
                data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
                free_nfs_cb_data(data);
                return -1;
        }
-       return 0;
+
+       while (count > 0) {
+               size_t readcount = count;
+               struct nfs_mcb_data *mdata;
+
+               if (readcount > nfs_get_readmax(nfs)) {
+                       readcount = nfs_get_readmax(nfs);
+               }
+
+               mdata = malloc(sizeof(struct nfs_mcb_data));
+               if (mdata == NULL) {
+                       rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_mcb_data structure");
+                       return -1;
+               }
+               memset(mdata, 0, sizeof(struct nfs_mcb_data));
+               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) {
+                       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);
+                       return -1;
+               }
+
+               count               -= readcount;
+               offset              += readcount;
+               data->num_calls++;
+        }
+
+        return 0;
 }
 
 /*
@@ -895,11 +1044,9 @@ int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset,
        data = malloc(sizeof(struct nfs_cb_data));
        if (data == NULL) {
                rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
-               printf("failed to allocate memory for nfs cb data\n");
-               free_nfs_cb_data(data);
                return -1;
        }
-       bzero(data, sizeof(struct nfs_cb_data));
+       memset(data, 0, sizeof(struct nfs_cb_data));
        data->nfs          = nfs;
        data->cb           = cb;
        data->private_data = private_data;
@@ -956,11 +1103,9 @@ int nfs_fstat_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, voi
        data = malloc(sizeof(struct nfs_cb_data));
        if (data == NULL) {
                rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
-               printf("failed to allocate memory for nfs cb data\n");
-               free_nfs_cb_data(data);
                return -1;
        }
-       bzero(data, sizeof(struct nfs_cb_data));
+       memset(data, 0, sizeof(struct nfs_cb_data));
        data->nfs          = nfs;
        data->cb           = cb;
        data->private_data = private_data;
@@ -1015,11 +1160,9 @@ int nfs_fsync_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, voi
        data = malloc(sizeof(struct nfs_cb_data));
        if (data == NULL) {
                rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
-               printf("failed to allocate memory for nfs cb data\n");
-               free_nfs_cb_data(data);
                return -1;
        }
-       bzero(data, sizeof(struct nfs_cb_data));
+       memset(data, 0, sizeof(struct nfs_cb_data));
        data->nfs          = nfs;
        data->cb           = cb;
        data->private_data = private_data;
@@ -1076,16 +1219,14 @@ int nfs_ftruncate_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t leng
        data = malloc(sizeof(struct nfs_cb_data));
        if (data == NULL) {
                rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
-               printf("failed to allocate memory for nfs cb data\n");
-               free_nfs_cb_data(data);
                return -1;
        }
-       bzero(data, sizeof(struct nfs_cb_data));
+       memset(data, 0, sizeof(struct nfs_cb_data));
        data->nfs          = nfs;
        data->cb           = cb;
        data->private_data = private_data;
 
-       bzero(&args, sizeof(SETATTR3args));
+       memset(&args, 0, sizeof(SETATTR3args));
        args.object.data.data_len = nfsfh->fh.data.data_len;
        args.object.data.data_val = nfsfh->fh.data.data_val;
        args.new_attributes.size.set_it = 1;
@@ -1129,8 +1270,8 @@ int nfs_truncate_async(struct nfs_context *nfs, const char *path, off_t length,
        offset = length;
 
        if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_truncate_continue_internal, NULL, NULL, offset) != 0) {
-               printf("Out of memory: failed to start parsing the path components\n");
-               return -2;
+               rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
+               return -1;
        }
 
        return 0;
@@ -1196,21 +1337,21 @@ int nfs_mkdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *
 
        new_path = strdup(path);
        if (new_path == NULL) {
-               printf("Out of memory, failed to allocate mode buffer for path\n");
+               rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for path");
                return -1;
        }
 
-       ptr = rindex(new_path, '/');
+       ptr = strrchr(new_path, '/');
        if (ptr == NULL) {
-               printf("Invalid path %s\n", path);
-               return -2;
+               rpc_set_error(nfs->rpc, "Invalid path %s", path);
+               return -1;
        }
        *ptr = 0;
 
        /* new_path now points to the parent directory,  and beyond the nul terminateor is the new directory to create */
        if (nfs_lookuppath_async(nfs, new_path, cb, private_data, nfs_mkdir_continue_internal, new_path, free, 0) != 0) {
-               printf("Out of memory: failed to start parsing the path components\n");
-               return -3;
+               rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path component");
+               return -1;
        }
 
        return 0;
@@ -1277,21 +1418,21 @@ int nfs_rmdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *
 
        new_path = strdup(path);
        if (new_path == NULL) {
-               printf("Out of memory, failed to allocate mode buffer for path\n");
+               rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for path");
                return -1;
        }
 
-       ptr = rindex(new_path, '/');
+       ptr = strrchr(new_path, '/');
        if (ptr == NULL) {
-               printf("Invalid path %s\n", path);
-               return -2;
+               rpc_set_error(nfs->rpc, "Invalid path %s", path);
+               return -1;
        }
        *ptr = 0;
 
        /* new_path now points to the parent directory,  and beyond the nul terminateor is the new directory to create */
        if (nfs_lookuppath_async(nfs, new_path, cb, private_data, nfs_rmdir_continue_internal, new_path, free, 0) != 0) {
-               printf("Out of memory: failed to start parsing the path components\n");
-               return -3;
+               rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
+               return -1;
        }
 
        return 0;
@@ -1338,7 +1479,7 @@ static void nfs_create_2_cb(struct rpc_context *rpc _U_, int status, void *comma
                free_nfs_cb_data(data);
                return;
        }
-       bzero(nfsfh, sizeof(struct nfsfh));
+       memset(nfsfh, 0, sizeof(struct nfsfh));
 
        /* steal the filehandle */
        nfsfh->fh.data.data_len = data->fh.data.data_len;
@@ -1409,21 +1550,21 @@ int nfs_creat_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb
 
        new_path = strdup(path);
        if (new_path == NULL) {
-               printf("Out of memory, failed to allocate mode buffer for path\n");
+               rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for path");
                return -1;
        }
 
-       ptr = rindex(new_path, '/');
+       ptr = strrchr(new_path, '/');
        if (ptr == NULL) {
-               printf("Invalid path %s\n", path);
-               return -2;
+               rpc_set_error(nfs->rpc, "Invalid path %s", path);
+               return -1;
        }
        *ptr = 0;
 
        /* new_path now points to the parent directory,  and beyond the nul terminateor 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) {
-               printf("Out of memory: failed to start parsing the path components\n");
-               return -3;
+               rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
+               return -1;
        }
 
        return 0;
@@ -1489,21 +1630,21 @@ int nfs_unlink_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void
 
        new_path = strdup(path);
        if (new_path == NULL) {
-               printf("Out of memory, failed to allocate mode buffer for path\n");
+               rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for path");
                return -1;
        }
 
-       ptr = rindex(new_path, '/');
+       ptr = strrchr(new_path, '/');
        if (ptr == NULL) {
-               printf("Invalid path %s\n", path);
-               return -2;
+               rpc_set_error(nfs->rpc, "Invalid path %s", path);
+               return -1;
        }
        *ptr = 0;
 
        /* new_path now points to the parent directory,  and beyond the nul terminateor is the new directory to create */
        if (nfs_lookuppath_async(nfs, new_path, cb, private_data, nfs_unlink_continue_internal, new_path, free, 0) != 0) {
-               printf("Out of memory: failed to start parsing the path components\n");
-               return -3;
+               rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
+               return -1;
        }
 
        return 0;
@@ -1518,13 +1659,13 @@ int nfs_unlink_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void
  */
 static void nfs_opendir_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data)
 {
-       READDIR3res *res;
+       READDIRPLUS3res *res;
        struct nfs_cb_data *data = private_data;
        struct nfs_context *nfs = data->nfs;
-       struct nfsdir *nfsdir = data->continue_data;;
-       struct entry3 *entry;
+       struct nfsdir *nfsdir = data->continue_data;
+       struct entryplus3 *entry;
        uint64_t cookie;
-       
+
        if (status == RPC_STATUS_ERROR) {
                data->cb(-EFAULT, nfs, command_data, data->private_data);
                nfs_free_nfsdir(nfsdir);
@@ -1550,7 +1691,7 @@ static void nfs_opendir_cb(struct rpc_context *rpc _U_, int status, void *comman
                return;
        }
 
-       entry =res->READDIR3res_u.resok.reply.entries;
+       entry =res->READDIRPLUS3res_u.resok.reply.entries;
        while (entry != NULL) {
                struct nfsdirent *nfsdirent;
 
@@ -1562,7 +1703,7 @@ static void nfs_opendir_cb(struct rpc_context *rpc _U_, int status, void *comman
                        free_nfs_cb_data(data);
                        return;
                }
-               bzero(nfsdirent, sizeof(struct nfsdirent));
+               memset(nfsdirent, 0, sizeof(struct nfsdirent));
                nfsdirent->name = strdup(entry->name);
                if (nfsdirent->name == NULL) {
                        data->cb(-ENOMEM, nfs, "Failed to allocate dirent->name", data->private_data);
@@ -1572,6 +1713,19 @@ static void nfs_opendir_cb(struct rpc_context *rpc _U_, int status, void *comman
                        return;
                }
                nfsdirent->inode = entry->fileid;
+               if (entry->name_attributes.attributes_follow) {
+                       nfsdirent->type = entry->name_attributes.post_op_attr_u.attributes.type;
+                       nfsdirent->mode = entry->name_attributes.post_op_attr_u.attributes.mode;
+                       nfsdirent->size = entry->name_attributes.post_op_attr_u.attributes.size;
+
+                       nfsdirent->atime.tv_sec  = entry->name_attributes.post_op_attr_u.attributes.atime.seconds;
+                       nfsdirent->atime.tv_usec = entry->name_attributes.post_op_attr_u.attributes.atime.nseconds/1000;
+                       nfsdirent->mtime.tv_sec  = entry->name_attributes.post_op_attr_u.attributes.mtime.seconds;
+                       nfsdirent->mtime.tv_usec = entry->name_attributes.post_op_attr_u.attributes.mtime.nseconds/1000;
+                       nfsdirent->ctime.tv_sec  = entry->name_attributes.post_op_attr_u.attributes.ctime.seconds;
+                       nfsdirent->ctime.tv_usec = entry->name_attributes.post_op_attr_u.attributes.ctime.nseconds/1000;
+               }
+
                nfsdirent->next  = nfsdir->entries;
                nfsdir->entries  = nfsdirent;
 
@@ -1579,9 +1733,9 @@ static void nfs_opendir_cb(struct rpc_context *rpc _U_, int status, void *comman
                entry  = entry->nextentry;
        }
 
-       if (res->READDIR3res_u.resok.reply.eof == 0) {
-               if (rpc_nfs_readdir_async(nfs->rpc, nfs_opendir_cb, &data->fh, cookie, res->READDIR3res_u.resok.cookieverf, 20000, data) != 0) {
-                       rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR call for %s", data->path);
+       if (res->READDIRPLUS3res_u.resok.reply.eof == 0) {
+               if (rpc_nfs_readdirplus_async(nfs->rpc, nfs_opendir_cb, &data->fh, cookie, res->READDIRPLUS3res_u.resok.cookieverf, 8192, data) != 0) {
+                       rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIRPLUS call for %s", data->path);
                        data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
                        nfs_free_nfsdir(nfsdir);
                        data->continue_data = NULL;
@@ -1603,9 +1757,9 @@ static int nfs_opendir_continue_internal(struct nfs_context *nfs, struct nfs_cb_
 {
        cookieverf3 cv;
 
-       bzero(cv, sizeof(cookieverf3));
-       if (rpc_nfs_readdir_async(nfs->rpc, nfs_opendir_cb, &data->fh, 0, (char *)&cv, 20000, data) != 0) {
-               rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR call for %s", data->path);
+       memset(cv, 0, sizeof(cookieverf3));
+       if (rpc_nfs_readdirplus_async(nfs->rpc, nfs_opendir_cb, &data->fh, 0, (char *)&cv, 8192, data) != 0) {
+               rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIRPLUS call for %s", data->path);
                data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
                free_nfs_cb_data(data);
                return -1;
@@ -1619,14 +1773,14 @@ int nfs_opendir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void
 
        nfsdir = malloc(sizeof(struct nfsdir));
        if (nfsdir == NULL) {
-               printf("failed to allocate buffer for nfsdir\n");
+               rpc_set_error(nfs->rpc, "failed to allocate buffer for nfsdir");
                return -1;
        }
-       bzero(nfsdir, sizeof(struct nfsdir));
+       memset(nfsdir, 0, sizeof(struct nfsdir));
 
        if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_opendir_continue_internal, nfsdir, free, 0) != 0) {
-               printf("Out of memory: failed to start parsing the path components\n");
-               return -2;
+               rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
+               return -1;
        }
 
        return 0;
@@ -1726,7 +1880,7 @@ int nfs_lseek_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset,
        if (rpc_nfs_getattr_async(nfs->rpc, nfs_lseek_1_cb, &nfsfh->fh, data) != 0) {
                rpc_set_error(nfs->rpc, "RPC error: Failed to send LSEEK GETATTR call");
                free(data);
-               return -2;
+               return -1;
        }
        return 0;
 }
@@ -1742,7 +1896,9 @@ static void nfs_statvfs_1_cb(struct rpc_context *rpc _U_, int status, void *comm
        FSSTAT3res *res;
        struct nfs_cb_data *data = private_data;
        struct nfs_context *nfs = data->nfs;
+#ifndef WIN32
        struct statvfs svfs;
+#endif/*WIN32*/
 
        if (status == RPC_STATUS_ERROR) {
                data->cb(-EFAULT, nfs, command_data, data->private_data);
@@ -1763,6 +1919,7 @@ static void nfs_statvfs_1_cb(struct rpc_context *rpc _U_, int status, void *comm
                return;
        }
 
+#ifndef WIN32
        svfs.f_bsize   = 4096;
        svfs.f_frsize  = 4096;
        svfs.f_blocks  = res->FSSTAT3res_u.resok.tbytes/4096;
@@ -1776,6 +1933,9 @@ static void nfs_statvfs_1_cb(struct rpc_context *rpc _U_, int status, void *comm
        svfs.f_namemax = 256;
 
        data->cb(0, nfs, &svfs, data->private_data);
+#else
+  data->cb(0, nfs,NULL, data->private_data);  
+#endif/*WIN32*/
        free_nfs_cb_data(data);
 }
 
@@ -1793,7 +1953,7 @@ static int nfs_statvfs_continue_internal(struct nfs_context *nfs, struct nfs_cb_
 int nfs_statvfs_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
 {
        if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_statvfs_continue_internal, NULL, NULL, 0) != 0) {
-               printf("Out of memory: failed to start parsing the path components\n");
+               rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
                return -1;
        }
 
@@ -1850,7 +2010,7 @@ static int nfs_readlink_continue_internal(struct nfs_context *nfs, struct nfs_cb
 int nfs_readlink_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data)
 {
        if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_readlink_continue_internal, NULL, NULL, 0) != 0) {
-               printf("Out of memory: failed to start parsing the path components\n");
+               rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
                return -1;
        }
 
@@ -1896,7 +2056,7 @@ static int nfs_chmod_continue_internal(struct nfs_context *nfs, struct nfs_cb_da
 {
        SETATTR3args args;
 
-       bzero(&args, sizeof(SETATTR3args));
+       memset(&args, 0, sizeof(SETATTR3args));
        args.object.data.data_len = data->fh.data.data_len;
        args.object.data.data_val = data->fh.data.data_val;
        args.new_attributes.mode.set_it = 1;
@@ -1915,7 +2075,7 @@ static int nfs_chmod_continue_internal(struct nfs_context *nfs, struct nfs_cb_da
 int nfs_chmod_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data)
 {
        if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_chmod_continue_internal, NULL, NULL, mode) != 0) {
-               printf("Out of memory: failed to start parsing the path components\n");
+               rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
                return -1;
        }
 
@@ -1931,11 +2091,10 @@ int nfs_fchmod_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int mode, nfs
 
        data = malloc(sizeof(struct nfs_cb_data));
        if (data == NULL) {
-               rpc_set_error(nfs->rpc, "out of memory");
-               printf("failed to allocate memory for nfs mount data\n");
+               rpc_set_error(nfs->rpc, "out of memory. failed to allocate memory for nfs mount data");
                return -1;
        }
-       bzero(data, sizeof(struct nfs_cb_data));
+       memset(data, 0, sizeof(struct nfs_cb_data));
        data->nfs          = nfs;
        data->cb           = cb;
        data->private_data = private_data;
@@ -2001,7 +2160,7 @@ static int nfs_chown_continue_internal(struct nfs_context *nfs, struct nfs_cb_da
        SETATTR3args args;
        struct nfs_chown_data *chown_data = data->continue_data;
 
-       bzero(&args, sizeof(SETATTR3args));
+       memset(&args, 0, sizeof(SETATTR3args));
        args.object.data.data_len = data->fh.data.data_len;
        args.object.data.data_val = data->fh.data.data_val;
        if (chown_data->uid != (uid_t)-1) {
@@ -2029,7 +2188,7 @@ int nfs_chown_async(struct nfs_context *nfs, const char *path, int uid, int gid,
 
        chown_data = malloc(sizeof(struct nfs_chown_data));
        if (chown_data == NULL) {
-               printf("Failed to allocate memory for chown data structure\n");
+               rpc_set_error(nfs->rpc, "Failed to allocate memory for chown data structure");
                return -1;
        }
 
@@ -2037,7 +2196,7 @@ int nfs_chown_async(struct nfs_context *nfs, const char *path, int uid, int gid,
        chown_data->gid = gid;
 
        if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_chown_continue_internal, chown_data, free, 0) != 0) {
-               printf("Out of memory: failed to start parsing the path components\n");
+               rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
                return -1;
        }
 
@@ -2055,7 +2214,7 @@ int nfs_fchown_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int uid, int
 
        chown_data = malloc(sizeof(struct nfs_chown_data));
        if (chown_data == NULL) {
-               printf("Failed to allocate memory for chown data structure\n");
+               rpc_set_error(nfs->rpc, "Failed to allocate memory for chown data structure");
                return -1;
        }
 
@@ -2065,11 +2224,10 @@ int nfs_fchown_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int uid, int
 
        data = malloc(sizeof(struct nfs_cb_data));
        if (data == NULL) {
-               rpc_set_error(nfs->rpc, "out of memory");
-               printf("failed to allocate memory for fchown data\n");
+               rpc_set_error(nfs->rpc, "out of memory. failed to allocate memory for fchown data");
                return -1;
        }
-       bzero(data, sizeof(struct nfs_cb_data));
+       memset(data, 0, sizeof(struct nfs_cb_data));
        data->nfs           = nfs;
        data->cb            = cb;
        data->private_data  = private_data;
@@ -2133,7 +2291,7 @@ static int nfs_utimes_continue_internal(struct nfs_context *nfs, struct nfs_cb_d
        SETATTR3args args;
        struct timeval *utimes_data = data->continue_data;
 
-       bzero(&args, sizeof(SETATTR3args));
+       memset(&args, 0, sizeof(SETATTR3args));
        args.object.data.data_len = data->fh.data.data_len;
        args.object.data.data_val = data->fh.data.data_val;
        if (utimes_data != NULL) {
@@ -2165,7 +2323,7 @@ int nfs_utimes_async(struct nfs_context *nfs, const char *path, struct timeval *
        if (times != NULL) {
                new_times = malloc(sizeof(struct timeval)*2);
                if (new_times == NULL) {
-                       printf("Failed to allocate memory for timeval structure\n");
+                       rpc_set_error(nfs->rpc, "Failed to allocate memory for timeval structure");
                        return -1;
                }
 
@@ -2173,7 +2331,7 @@ int nfs_utimes_async(struct nfs_context *nfs, const char *path, struct timeval *
        }
 
        if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_utimes_continue_internal, new_times, free, 0) != 0) {
-               printf("Out of memory: failed to start parsing the path components\n");
+               rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
                return -1;
        }
 
@@ -2190,7 +2348,7 @@ int nfs_utime_async(struct nfs_context *nfs, const char *path, struct utimbuf *t
        if (times != NULL) {
                new_times = malloc(sizeof(struct timeval)*2);
                if (new_times == NULL) {
-                       printf("Failed to allocate memory for timeval structure\n");
+                       rpc_set_error(nfs->rpc, "Failed to allocate memory for timeval structure");
                        return -1;
                }
 
@@ -2201,7 +2359,7 @@ int nfs_utime_async(struct nfs_context *nfs, const char *path, struct utimbuf *t
        }
 
        if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_utimes_continue_internal, new_times, free, 0) != 0) {
-               printf("Out of memory: failed to start parsing the path components\n");
+               rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
                return -1;
        }
 
@@ -2294,8 +2452,8 @@ static int nfs_access_continue_internal(struct nfs_context *nfs, struct nfs_cb_d
 int nfs_access_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data)
 {
        if (nfs_lookuppath_async(nfs, path, cb, private_data, nfs_access_continue_internal, NULL, NULL, mode) != 0) {
-               printf("Out of memory: failed to start parsing the path components\n");
-               return -2;
+               rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
+               return -1;
        }
 
        return 0;
@@ -2378,44 +2536,44 @@ int nfs_symlink_async(struct nfs_context *nfs, const char *oldpath, const char *
 
        symlink_data = malloc(sizeof(struct nfs_symlink_data));
        if (symlink_data == NULL) {
-               printf("Out of memory, failed to allocate buffer for symlink data\n");
+               rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for symlink data");
                return -1;
        }
-       bzero(symlink_data, sizeof(struct nfs_symlink_data));
+       memset(symlink_data, 0, sizeof(struct nfs_symlink_data));
 
        symlink_data->oldpath = strdup(oldpath);
        if (symlink_data->oldpath == NULL) {
-               printf("Out of memory, failed to allocate buffer for oldpath\n");
+               rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for oldpath");
                free_nfs_symlink_data(symlink_data);
-               return -2;
+               return -1;
        }
 
        symlink_data->newpathparent = strdup(newpath);
        if (symlink_data->newpathparent == NULL) {
-               printf("Out of memory, failed to allocate mode buffer for new path\n");
+               rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for new path");
                free_nfs_symlink_data(symlink_data);
-               return -3;
+               return -1;
        }
 
-       ptr = rindex(symlink_data->newpathparent, '/');
+       ptr = strrchr(symlink_data->newpathparent, '/');
        if (ptr == NULL) {
-               printf("Invalid path %s\n", oldpath);
+               rpc_set_error(nfs->rpc, "Invalid path %s", oldpath);
                free_nfs_symlink_data(symlink_data);
-               return -4;
+               return -1;
        }
        *ptr = 0;
        ptr++;
 
        symlink_data->newpathobject = strdup(ptr);
        if (symlink_data->newpathobject == NULL) {
-               printf("Out of memory, failed to allocate mode buffer for new path\n");
+               rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for new path");
                free_nfs_symlink_data(symlink_data);
-               return -5;
+               return -1;
        }
 
        if (nfs_lookuppath_async(nfs, symlink_data->newpathparent, cb, private_data, nfs_symlink_continue_internal, symlink_data, free_nfs_symlink_data, 0) != 0) {
-               printf("Out of memory: failed to start parsing the path components\n");
-               return -6;
+               rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
+               return -1;
        }
 
        return 0;
@@ -2532,22 +2690,22 @@ int nfs_rename_async(struct nfs_context *nfs, const char *oldpath, const char *n
 
        rename_data = malloc(sizeof(struct nfs_rename_data));
        if (rename_data == NULL) {
-               printf("Out of memory, failed to allocate buffer for rename data\n");
+               rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for rename data");
                return -1;
        }
-       bzero(rename_data, sizeof(struct nfs_rename_data));
+       memset(rename_data, 0, sizeof(struct nfs_rename_data));
 
        rename_data->oldpath = strdup(oldpath);
        if (rename_data->oldpath == NULL) {
-               printf("Out of memory, failed to allocate buffer for oldpath\n");
+               rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for oldpath");
                free_nfs_rename_data(rename_data);
-               return -2;
+               return -1;
        }
-       ptr = rindex(rename_data->oldpath, '/');
+       ptr = strrchr(rename_data->oldpath, '/');
        if (ptr == NULL) {
-               printf("Invalid path %s\n", oldpath);
+               rpc_set_error(nfs->rpc, "Invalid path %s", oldpath);
                free_nfs_rename_data(rename_data);
-               return -3;
+               return -1;
        }
        *ptr = 0;
        ptr++;
@@ -2556,15 +2714,15 @@ int nfs_rename_async(struct nfs_context *nfs, const char *oldpath, const char *n
 
        rename_data->newpath = strdup(newpath);
        if (rename_data->newpath == NULL) {
-               printf("Out of memory, failed to allocate buffer for newpath\n");
+               rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for newpath");
                free_nfs_rename_data(rename_data);
-               return -4;
+               return -1;
        }
-       ptr = rindex(rename_data->newpath, '/');
+       ptr = strrchr(rename_data->newpath, '/');
        if (ptr == NULL) {
-               printf("Invalid path %s\n", newpath);
+               rpc_set_error(nfs->rpc, "Invalid path %s", newpath);
                free_nfs_rename_data(rename_data);
-               return -5;
+               return -1;
        }
        *ptr = 0;
        ptr++;
@@ -2572,8 +2730,8 @@ int nfs_rename_async(struct nfs_context *nfs, const char *oldpath, const char *n
 
 
        if (nfs_lookuppath_async(nfs, rename_data->oldpath, cb, private_data, nfs_rename_continue_1_internal, rename_data, free_nfs_rename_data, 0) != 0) {
-               printf("Out of memory: failed to start parsing the path components\n");
-               return -6;
+               rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
+               return -1;
        }
 
        return 0;
@@ -2688,29 +2846,29 @@ int nfs_link_async(struct nfs_context *nfs, const char *oldpath, const char *new
 
        link_data = malloc(sizeof(struct nfs_link_data));
        if (link_data == NULL) {
-               printf("Out of memory, failed to allocate buffer for link data\n");
+               rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for link data");
                return -1;
        }
-       bzero(link_data, sizeof(struct nfs_link_data));
+       memset(link_data, 0, sizeof(struct nfs_link_data));
 
        link_data->oldpath = strdup(oldpath);
        if (link_data->oldpath == NULL) {
-               printf("Out of memory, failed to allocate buffer for oldpath\n");
+               rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for oldpath");
                free_nfs_link_data(link_data);
-               return -2;
+               return -1;
        }
 
        link_data->newpath = strdup(newpath);
        if (link_data->newpath == NULL) {
-               printf("Out of memory, failed to allocate buffer for newpath\n");
+               rpc_set_error(nfs->rpc, "Out of memory, failed to allocate buffer for newpath");
                free_nfs_link_data(link_data);
-               return -4;
+               return -1;
        }
-       ptr = rindex(link_data->newpath, '/');
+       ptr = strrchr(link_data->newpath, '/');
        if (ptr == NULL) {
-               printf("Invalid path %s\n", newpath);
+               rpc_set_error(nfs->rpc, "Invalid path %s", newpath);
                free_nfs_link_data(link_data);
-               return -5;
+               return -1;
        }
        *ptr = 0;
        ptr++;
@@ -2718,8 +2876,8 @@ int nfs_link_async(struct nfs_context *nfs, const char *oldpath, const char *new
 
 
        if (nfs_lookuppath_async(nfs, link_data->oldpath, cb, private_data, nfs_link_continue_1_internal, link_data, free_nfs_link_data, 0) != 0) {
-               printf("Out of memory: failed to start parsing the path components\n");
-               return -6;
+               rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components");
+               return -1;
        }
 
        return 0;
@@ -2749,3 +2907,226 @@ size_t nfs_get_writemax(struct nfs_context *nfs)
 {
        return nfs->writemax;
 }
+
+void nfs_set_error(struct nfs_context *nfs, char *error_string, ...)
+{
+        va_list ap;
+       char *str = NULL;
+
+        va_start(ap, error_string);
+       str = malloc(1024);
+       vsnprintf(str, 1024, error_string, ap);
+       if (nfs->rpc->error_string != NULL) {
+               free(nfs->rpc->error_string);
+       }
+       nfs->rpc->error_string = str;
+    va_end(ap);
+}
+
+
+
+struct mount_cb_data {
+       rpc_cb cb;
+       void *private_data;
+       char *server;
+};
+
+static void free_mount_cb_data(struct mount_cb_data *data)
+{
+       if (data->server != NULL) {
+               free(data->server);
+               data->server = NULL;
+       }
+
+       free(data);
+}
+
+static void mount_export_5_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+       struct mount_cb_data *data = private_data;
+
+       if (status == RPC_STATUS_ERROR) {       
+               data->cb(rpc, -EFAULT, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+       if (status == RPC_STATUS_CANCEL) {
+               data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+
+       data->cb(rpc, 0, command_data, data->private_data);
+       if (rpc_disconnect(rpc, "normal disconnect") != 0) {
+               rpc_set_error(rpc, "Failed to disconnect\n");
+       }
+       free_mount_cb_data(data);
+}
+
+static void mount_export_4_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+       struct mount_cb_data *data = private_data;
+
+       if (status == RPC_STATUS_ERROR) {       
+               data->cb(rpc, -EFAULT, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+       if (status == RPC_STATUS_CANCEL) {
+               data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+
+       if (rpc_mount_export_async(rpc, mount_export_5_cb, data) != 0) {
+               data->cb(rpc, -ENOMEM, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+}
+
+static void mount_export_3_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+       struct mount_cb_data *data = private_data;
+       uint32_t mount_port;
+
+       if (status == RPC_STATUS_ERROR) {       
+               data->cb(rpc, -EFAULT, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+       if (status == RPC_STATUS_CANCEL) {
+               data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+
+       mount_port = *(uint32_t *)command_data;
+       if (mount_port == 0) {
+               rpc_set_error(rpc, "RPC error. Mount program is not available");
+               data->cb(rpc, -ENOENT, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+
+       rpc_disconnect(rpc, "normal disconnect");
+       if (rpc_connect_async(rpc, data->server, mount_port, mount_export_4_cb, data) != 0) {
+               data->cb(rpc, -ENOMEM, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+}
+
+static void mount_export_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+       struct mount_cb_data *data = private_data;
+
+       if (status == RPC_STATUS_ERROR) {
+               data->cb(rpc, -EFAULT, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+       if (status == RPC_STATUS_CANCEL) {
+               data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+
+       if (rpc_pmap_getport_async(rpc, MOUNT_PROGRAM, MOUNT_V3, mount_export_3_cb, private_data) != 0) {
+               data->cb(rpc, -ENOMEM, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+}
+
+static void mount_export_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+       struct mount_cb_data *data = private_data;
+
+       if (status == RPC_STATUS_ERROR) {
+               data->cb(rpc, -EFAULT, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+       if (status == RPC_STATUS_CANCEL) {
+               data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+
+       if (rpc_pmap_null_async(rpc, mount_export_2_cb, data) != 0) {
+               data->cb(rpc, -ENOMEM, command_data, data->private_data);
+               free_mount_cb_data(data);
+               return;
+       }
+}
+
+int mount_getexports_async(struct rpc_context *rpc, const char *server, rpc_cb cb, void *private_data)
+{
+       struct mount_cb_data *data;
+
+       data = malloc(sizeof(struct mount_cb_data));
+       if (data == NULL) {
+               return -1;
+       }
+       memset(data, 0, sizeof(struct mount_cb_data));
+       data->cb           = cb;
+       data->private_data = private_data;
+       data->server       = strdup(server);
+       if (data->server == NULL) {
+               free_mount_cb_data(data);
+               return -1;
+       }       
+       if (rpc_connect_async(rpc, data->server, 111, mount_export_1_cb, data) != 0) {
+               free_mount_cb_data(data);
+               return -1;
+       }
+
+       return 0;
+}
+
+struct rpc_context *nfs_get_rpc_context(struct nfs_context *nfs)
+{
+       return nfs->rpc;
+}
+
+const char *nfs_get_server(struct nfs_context *nfs) {
+       return nfs->server;
+}
+
+const char *nfs_get_export(struct nfs_context *nfs) {
+       return nfs->export;
+}
+
+
+#if defined(WIN32)
+int poll(struct pollfd *fds, int nfsd, int timeout)
+{
+       fd_set rfds, wfds, efds;
+       int ret;
+
+       FD_ZERO(&rfds);
+       FD_ZERO(&wfds);
+       FD_ZERO(&efds);
+       if (fds->events & POLLIN) {
+               FD_SET(fds->fd, &rfds);
+       }
+       if (fds->events & POLLOUT) {
+               FD_SET(fds->fd, &wfds);
+       }
+       FD_SET(fds->fd, &efds);
+       select(fds->fd + 1, &rfds, &wfds, &efds, NULL);
+       fds->revents = 0;
+       if (FD_ISSET(fds->fd, &rfds)) {
+               fds->revents |= POLLIN;
+       }
+       if (FD_ISSET(fds->fd, &wfds)) {
+               fds->revents |= POLLOUT;
+       }
+       if (FD_ISSET(fds->fd, &efds)) {
+               fds->revents |= POLLHUP;
+       }
+       return 1;
+}
+#endif
+