Merge branch 'win32' into win32-3
[deb_libnfs.git] / lib / libnfs.c
index 905e9d80656ca99e38c567d50da6211a70f7a3b7..eee5d5a6dbb8e4b6c8f755f7adbe2129289d35e6 100644 (file)
  */
 
 #define _GNU_SOURCE
+
+#if defined(WIN32)
+#include <winsock2.h>
+#define DllExport
+#define O_SYNC 0
+typedef int uid_t;
+typedef int gid_t;
+#else
+#include <strings.h>
+#include <sys/statvfs.h>
+#include <utime.h>
+#include <unistd.h>
+#endif
+
 #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"
@@ -107,7 +117,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)
@@ -144,6 +154,12 @@ struct nfs_context *nfs_init_context(void)
                return NULL;
        }
 
+       nfs->server = NULL;
+       nfs->export = NULL;
+
+       nfs->rootfh.data.data_len = 0;
+       nfs->rootfh.data.data_val = NULL;
+
        return nfs;
 }
 
@@ -470,6 +486,7 @@ 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) {
@@ -477,8 +494,18 @@ int nfs_mount_async(struct nfs_context *nfs, const char *server, const char *exp
                return -1;
        }
        bzero(data, sizeof(struct nfs_cb_data));
-       nfs->server        = strdup(server);
-       nfs->export        = strdup(export);
+       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;
@@ -540,7 +567,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;
@@ -654,8 +681,10 @@ static void nfs_stat_1_cb(struct rpc_context *rpc _U_, int status, void *command
         st.st_gid     = res->GETATTR3res_u.resok.obj_attributes.gid;
         st.st_rdev    = 0;
         st.st_size    = res->GETATTR3res_u.resok.obj_attributes.size;
+#if !defined(WIN32)
         st.st_blksize = 4096;
         st.st_blocks  = res->GETATTR3res_u.resok.obj_attributes.size / 4096;
+#endif
         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;
@@ -859,10 +888,12 @@ static void nfs_pread_mcb(struct rpc_context *rpc _U_, int status, void *command
                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 {
-                       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;
+               } 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;
+                               }
                        }
                }
        }
@@ -888,6 +919,7 @@ static void nfs_pread_mcb(struct rpc_context *rpc _U_, int status, void *command
 
        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);
 }
@@ -923,6 +955,7 @@ int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset,
         * 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);
@@ -1312,7 +1345,7 @@ int nfs_mkdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *
                return -1;
        }
 
-       ptr = rindex(new_path, '/');
+       ptr = strrchr(new_path, '/');
        if (ptr == NULL) {
                rpc_set_error(nfs->rpc, "Invalid path %s", path);
                return -1;
@@ -1393,7 +1426,7 @@ int nfs_rmdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *
                return -1;
        }
 
-       ptr = rindex(new_path, '/');
+       ptr = strrchr(new_path, '/');
        if (ptr == NULL) {
                rpc_set_error(nfs->rpc, "Invalid path %s", path);
                return -1;
@@ -1525,7 +1558,7 @@ int nfs_creat_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb
                return -1;
        }
 
-       ptr = rindex(new_path, '/');
+       ptr = strrchr(new_path, '/');
        if (ptr == NULL) {
                rpc_set_error(nfs->rpc, "Invalid path %s", path);
                return -1;
@@ -1605,7 +1638,7 @@ int nfs_unlink_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void
                return -1;
        }
 
-       ptr = rindex(new_path, '/');
+       ptr = strrchr(new_path, '/');
        if (ptr == NULL) {
                rpc_set_error(nfs->rpc, "Invalid path %s", path);
                return -1;
@@ -1630,13 +1663,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);
@@ -1662,7 +1695,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;
 
@@ -1684,6 +1717,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;
 
@@ -1691,9 +1737,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;
@@ -1716,8 +1762,8 @@ 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);
+       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;
@@ -2507,7 +2553,7 @@ int nfs_symlink_async(struct nfs_context *nfs, const char *oldpath, const char *
                return -1;
        }
 
-       ptr = rindex(symlink_data->newpathparent, '/');
+       ptr = strrchr(symlink_data->newpathparent, '/');
        if (ptr == NULL) {
                rpc_set_error(nfs->rpc, "Invalid path %s", oldpath);
                free_nfs_symlink_data(symlink_data);
@@ -2653,7 +2699,7 @@ int nfs_rename_async(struct nfs_context *nfs, const char *oldpath, const char *n
                free_nfs_rename_data(rename_data);
                return -1;
        }
-       ptr = rindex(rename_data->oldpath, '/');
+       ptr = strrchr(rename_data->oldpath, '/');
        if (ptr == NULL) {
                rpc_set_error(nfs->rpc, "Invalid path %s", oldpath);
                free_nfs_rename_data(rename_data);
@@ -2670,7 +2716,7 @@ int nfs_rename_async(struct nfs_context *nfs, const char *oldpath, const char *n
                free_nfs_rename_data(rename_data);
                return -1;
        }
-       ptr = rindex(rename_data->newpath, '/');
+       ptr = strrchr(rename_data->newpath, '/');
        if (ptr == NULL) {
                rpc_set_error(nfs->rpc, "Invalid path %s", newpath);
                free_nfs_rename_data(rename_data);
@@ -2816,7 +2862,7 @@ int nfs_link_async(struct nfs_context *nfs, const char *oldpath, const char *new
                free_nfs_link_data(link_data);
                return -1;
        }
-       ptr = rindex(link_data->newpath, '/');
+       ptr = strrchr(link_data->newpath, '/');
        if (ptr == NULL) {
                rpc_set_error(nfs->rpc, "Invalid path %s", newpath);
                free_nfs_link_data(link_data);
@@ -2863,13 +2909,14 @@ size_t nfs_get_writemax(struct nfs_context *nfs)
 void nfs_set_error(struct nfs_context *nfs, char *error_string, ...)
 {
         va_list ap;
-       char *str;
+       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);
        }
-        va_start(ap, error_string);
-       vasprintf(&str, error_string, ap);
        nfs->rpc->error_string = str;
         va_end(ap);
 }
@@ -3041,3 +3088,43 @@ 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
+