X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=lib%2Flibnfs.c;h=61837196bb1ff28bd4ead9cd44c71a8636943744;hb=d43a8953f531478fa8bfd9eb60a0de257cd06814;hp=5fd91ea03e6379ea55e246ef2396976bb1f8444a;hpb=f4442bec270bed165ecac69451ea72f6c821d168;p=deb_libnfs.git diff --git a/lib/libnfs.c b/lib/libnfs.c index 5fd91ea..6183719 100644 --- a/lib/libnfs.c +++ b/lib/libnfs.c @@ -17,30 +17,58 @@ /* * High level api to nfs filesystems */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif -#define _GNU_SOURCE +#ifdef AROS +#include "aros_compat.h" +#endif -#if defined(WIN32) -#include -#define DllExport -#define O_SYNC 0 -typedef int uid_t; -typedef int gid_t; -#else -#include -#include +#ifdef WIN32 +#include "win32_compat.h" +#endif + +#ifdef HAVE_UTIME_H #include +#endif + +#ifdef ANDROID +#define statvfs statfs +#endif + +#define _GNU_SOURCE + +#ifdef HAVE_UNISTD_H #include #endif +#ifdef HAVE_SYS_VFS_H +#include +#endif + +#ifdef HAVE_SYS_STATVFS_H +#include +#endif + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#ifdef HAVE_STRINGS_H +#include +#endif + #include #include #include #include +#include #include #include #include #include +#include "libnfs-zdr.h" #include "libnfs.h" #include "libnfs-raw.h" #include "libnfs-raw-mount.h" @@ -55,7 +83,7 @@ struct nfsdir { struct nfsfh { struct nfs_fh3 fh; int is_sync; - off_t offset; + uint64_t offset; }; struct nfs_context { @@ -63,8 +91,8 @@ struct nfs_context { char *server; char *export; struct nfs_fh3 rootfh; - size_t readmax; - size_t writemax; + uint64_t readmax; + uint64_t writemax; }; void nfs_free_nfsdir(struct nfsdir *nfsdir) @@ -102,14 +130,14 @@ struct nfs_cb_data { int error; int cancel; int num_calls; - off_t start_offset, max_offset; + uint64_t start_offset, max_offset; char *buffer; }; struct nfs_mcb_data { struct nfs_cb_data *data; - off_t offset; - size_t count; + uint64_t offset; + uint64_t count; }; static int nfs_lookup_path_async_internal(struct nfs_context *nfs, struct nfs_cb_data *data, struct nfs_fh3 *fh); @@ -125,6 +153,11 @@ int nfs_get_fd(struct nfs_context *nfs) return rpc_get_fd(nfs->rpc); } +int nfs_queue_length(struct nfs_context *nfs) +{ + return rpc_queue_length(nfs->rpc); +} + int nfs_which_events(struct nfs_context *nfs) { return rpc_which_events(nfs->rpc); @@ -140,6 +173,159 @@ char *nfs_get_error(struct nfs_context *nfs) return rpc_get_error(nfs->rpc); }; +static int nfs_set_context_args(struct nfs_context *nfs, char *arg, char *val) +{ + if (!strncmp(arg, "tcp-syncnt", 10)) { + rpc_set_tcp_syncnt(nfs_get_rpc_context(nfs), atoi(val)); + } else if (!strncmp(arg, "uid", 3)) { + rpc_set_uid(nfs_get_rpc_context(nfs), atoi(val)); + } else if (!strncmp(arg, "gid", 3)) { + rpc_set_gid(nfs_get_rpc_context(nfs), atoi(val)); + } + return 0; +} + +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; + } + + memset(urls, 0x00, sizeof(struct nfs_url)); + 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; + } + } + + while (flagsp != NULL && *(flagsp+1) != 0) { + strp = flagsp + 1; + flagsp = strchr(strp, '&'); + if (flagsp) { + *flagsp = 0; + } + strp2 = strchr(strp, '='); + if (strp2) { + *strp2 = 0; + strp2++; + nfs_set_context_args(nfs, strp, strp2); + } + } + + if (urls->server && strlen(urls->server) <= 1) { + free(urls->server); + urls->server = NULL; + } + + 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; @@ -186,6 +372,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) { @@ -215,11 +550,13 @@ void free_nfs_cb_data(struct nfs_cb_data *data) -static void nfs_mount_10_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) +static void nfs_mount_10_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); free_nfs_cb_data(data); @@ -240,6 +577,9 @@ 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); if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); @@ -255,7 +595,10 @@ 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 = nfs->rootfh; + + 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; @@ -266,6 +609,9 @@ static void nfs_mount_8_cb(struct rpc_context *rpc, int status, void *command_da { struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; + struct FSINFO3args args; + + assert(rpc->magic == RPC_CONTEXT_MAGIC); if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); @@ -278,7 +624,8 @@ static void nfs_mount_8_cb(struct rpc_context *rpc, int status, void *command_da return; } - if (rpc_nfs_fsinfo_async(rpc, nfs_mount_9_cb, &nfs->rootfh, data) != 0) { + args.fsroot = nfs->rootfh; + if (rpc_nfs3_fsinfo_async(rpc, nfs_mount_9_cb, &args, data) != 0) { data->cb(-ENOMEM, nfs, command_data, data->private_data); free_nfs_cb_data(data); return; @@ -291,6 +638,11 @@ static void nfs_mount_7_cb(struct rpc_context *rpc, int status, void *command_da struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; + 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(-EFAULT, nfs, command_data, data->private_data); free_nfs_cb_data(data); @@ -302,7 +654,7 @@ static void nfs_mount_7_cb(struct rpc_context *rpc, int status, void *command_da return; } - if (rpc_nfs_null_async(rpc, nfs_mount_8_cb, data) != 0) { + if (rpc_nfs3_null_async(rpc, nfs_mount_8_cb, data) != 0) { data->cb(-ENOMEM, nfs, command_data, data->private_data); free_nfs_cb_data(data); return; @@ -316,6 +668,8 @@ static void nfs_mount_6_cb(struct rpc_context *rpc, int status, void *command_da struct nfs_context *nfs = data->nfs; mountres3 *res; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); free_nfs_cb_data(data); @@ -351,6 +705,8 @@ static void nfs_mount_6_cb(struct rpc_context *rpc, int status, void *command_da free_nfs_cb_data(data); return; } + /* NFS TCP connections we want to autoreconnect after sessions are torn down (due to inactivity or error) */ + rpc_set_autoreconnect(rpc); } @@ -359,6 +715,8 @@ static void nfs_mount_5_cb(struct rpc_context *rpc, int status, void *command_da struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); free_nfs_cb_data(data); @@ -370,7 +728,7 @@ static void nfs_mount_5_cb(struct rpc_context *rpc, int status, void *command_da return; } - if (rpc_mount_mnt_async(rpc, nfs_mount_6_cb, nfs->export, data) != 0) { + if (rpc_mount3_mnt_async(rpc, nfs_mount_6_cb, nfs->export, data) != 0) { data->cb(-ENOMEM, nfs, command_data, data->private_data); free_nfs_cb_data(data); return; @@ -382,6 +740,11 @@ static void nfs_mount_4_cb(struct rpc_context *rpc, int status, void *command_da struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; + 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(-EFAULT, nfs, command_data, data->private_data); free_nfs_cb_data(data); @@ -393,7 +756,7 @@ static void nfs_mount_4_cb(struct rpc_context *rpc, int status, void *command_da return; } - if (rpc_mount_null_async(rpc, nfs_mount_5_cb, data) != 0) { + if (rpc_mount3_null_async(rpc, nfs_mount_5_cb, data) != 0) { data->cb(-ENOMEM, nfs, command_data, data->private_data); free_nfs_cb_data(data); return; @@ -406,6 +769,8 @@ static void nfs_mount_3_cb(struct rpc_context *rpc, int status, void *command_da struct nfs_context *nfs = data->nfs; uint32_t mount_port; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); free_nfs_cb_data(data); @@ -439,6 +804,8 @@ static void nfs_mount_2_cb(struct rpc_context *rpc, int status, void *command_da struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); free_nfs_cb_data(data); @@ -450,7 +817,7 @@ static void nfs_mount_2_cb(struct rpc_context *rpc, int status, void *command_da return; } - if (rpc_pmap_getport_async(rpc, MOUNT_PROGRAM, MOUNT_V3, nfs_mount_3_cb, private_data) != 0) { + if (rpc_pmap_getport_async(rpc, MOUNT_PROGRAM, MOUNT_V3, IPPROTO_TCP, nfs_mount_3_cb, private_data) != 0) { data->cb(-ENOMEM, nfs, command_data, data->private_data); free_nfs_cb_data(data); return; @@ -462,6 +829,11 @@ static void nfs_mount_1_cb(struct rpc_context *rpc, int status, void *command_da struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; + 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(-EFAULT, nfs, command_data, data->private_data); free_nfs_cb_data(data); @@ -493,17 +865,15 @@ int nfs_mount_async(struct nfs_context *nfs, const char *server, const char *exp 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)); 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; @@ -525,12 +895,14 @@ int nfs_mount_async(struct nfs_context *nfs, const char *server, const char *exp * Functions to first look up a path, component by component, and then finally call a specific function once * the filehandle for the final component is found. */ -static void nfs_lookup_path_1_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) +static void nfs_lookup_path_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; LOOKUP3res *res; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); free_nfs_cb_data(data); @@ -561,6 +933,7 @@ static void nfs_lookup_path_1_cb(struct rpc_context *rpc _U_, int status, void * 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++; @@ -591,7 +964,12 @@ 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 = *fh; + 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); @@ -604,8 +982,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; } @@ -614,7 +992,7 @@ static int nfs_lookuppath_async(struct nfs_context *nfs, const char *path, nfs_c rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure"); 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; @@ -644,12 +1022,18 @@ static int nfs_lookuppath_async(struct nfs_context *nfs, const char *path, nfs_c /* * Async stat() */ -static void nfs_stat_1_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) +static void nfs_stat_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { GETATTR3res *res; struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; +#ifdef WIN32 + struct __stat64 st; +#else struct stat st; +#endif + + assert(rpc->magic == RPC_CONTEXT_MAGIC); if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); @@ -676,15 +1060,18 @@ static void nfs_stat_1_cb(struct rpc_context *rpc _U_, int status, void *command if (res->GETATTR3res_u.resok.obj_attributes.type == NF3DIR) { st.st_mode |= S_IFDIR ; } + if (res->GETATTR3res_u.resok.obj_attributes.type == NF3REG) { + st.st_mode |= S_IFREG ; + } 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; -#if !defined(WIN32) +#ifndef WIN32 st.st_blksize = 4096; st.st_blocks = res->GETATTR3res_u.resok.obj_attributes.size / 4096; -#endif +#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; @@ -695,7 +1082,12 @@ static void nfs_stat_1_cb(struct rpc_context *rpc _U_, int status, void *command 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->fh; + + 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); @@ -721,7 +1113,7 @@ int nfs_stat_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *p /* * Async open() */ -static void nfs_open_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) +static void nfs_open_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { ACCESS3res *res; struct nfs_cb_data *data = private_data; @@ -729,6 +1121,8 @@ static void nfs_open_cb(struct rpc_context *rpc _U_, int status, void *command_d struct nfsfh *nfsfh; unsigned int nfsmode = 0; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); free_nfs_cb_data(data); @@ -779,15 +1173,14 @@ 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; } /* steal the filehandle */ - nfsfh->fh.data.data_len = data->fh.data.data_len; - nfsfh->fh.data.data_val = data->fh.data.data_val; + nfsfh->fh = data->fh; data->fh.data.data_val = NULL; data->cb(0, nfs, nfsfh, data->private_data); @@ -797,6 +1190,7 @@ static void nfs_open_cb(struct rpc_context *rpc _U_, int status, void *command_d 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; @@ -808,7 +1202,11 @@ 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->fh; + 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); @@ -834,12 +1232,14 @@ int nfs_open_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb c /* * Async pread() */ -static void nfs_pread_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) +static void nfs_pread_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; READ3res *res; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); free_nfs_cb_data(data); @@ -864,13 +1264,15 @@ 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) +static void nfs_pread_mcb(struct rpc_context *rpc, 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; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + data->num_calls--; if (status == RPC_STATUS_ERROR) { @@ -924,7 +1326,7 @@ static void nfs_pread_mcb(struct rpc_context *rpc _U_, int status, void *command 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) +int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, nfs_cb cb, void *private_data) { struct nfs_cb_data *data; @@ -933,7 +1335,7 @@ int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure"); 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; @@ -942,7 +1344,14 @@ int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, 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 = nfsfh->fh; + 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); @@ -953,7 +1362,7 @@ int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, /* 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; @@ -967,8 +1376,9 @@ int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, } while (count > 0) { - size_t readcount = count; + uint64_t readcount = count; struct nfs_mcb_data *mdata; + READ3args args; if (readcount > nfs_get_readmax(nfs)) { readcount = nfs_get_readmax(nfs); @@ -979,11 +1389,17 @@ int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_mcb_data structure"); return -1; } - bzero(mdata, sizeof(struct nfs_mcb_data)); + 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) { + + memset(&args, 0, sizeof(READ3args)); + args.file = nfsfh->fh; + 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); @@ -1001,7 +1417,7 @@ int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, /* * Async read() */ -int nfs_read_async(struct nfs_context *nfs, struct nfsfh *nfsfh, size_t count, nfs_cb cb, void *private_data) +int nfs_read_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, nfs_cb cb, void *private_data) { return nfs_pread_async(nfs, nfsfh, nfsfh->offset, count, cb, private_data); } @@ -1011,12 +1427,14 @@ int nfs_read_async(struct nfs_context *nfs, struct nfsfh *nfsfh, size_t count, n /* * Async pwrite() */ -static void nfs_pwrite_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) +static void nfs_pwrite_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; WRITE3res *res; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); free_nfs_cb_data(data); @@ -1041,7 +1459,68 @@ static void nfs_pwrite_cb(struct rpc_context *rpc _U_, int status, void *command free_nfs_cb_data(data); } -int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, size_t count, char *buf, nfs_cb cb, void *private_data) +static void nfs_pwrite_mcb(struct rpc_context *rpc, 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; + WRITE3res *res; + + assert(rpc->magic == RPC_CONTEXT_MAGIC); + + 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; + } + + if (status == RPC_STATUS_SUCCESS) { + res = command_data; + if (res->status != NFS3_OK) { + rpc_set_error(nfs->rpc, "NFS: Write failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status)); + data->error = 1; + } else { + if (res->WRITE3res_u.resok.count > 0) { + if ((unsigned)data->max_offset < mdata->offset + res->WRITE3res_u.resok.count) { + data->max_offset = mdata->offset + res->WRITE3res_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, NULL, data->private_data); + + free_nfs_cb_data(data); + free(mdata); +} + + +int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buf, nfs_cb cb, void *private_data) { struct nfs_cb_data *data; @@ -1050,26 +1529,87 @@ int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure"); 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_write_async(nfs->rpc, nfs_pwrite_cb, &nfsfh->fh, buf, offset, count, nfsfh->is_sync?FILE_SYNC:UNSTABLE, 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); - return -1; + + if (count <= nfs_get_writemax(nfs)) { + WRITE3args args; + + memset(&args, 0, sizeof(WRITE3args)); + args.file = nfsfh->fh; + 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); + return -1; + } + return 0; } + + /* trying to write more than maximum server write size, we has to chop it up into smaller + * chunks. + * we send all writes in parallel so that performance is still good. + */ + data->max_offset = offset; + data->start_offset = offset; + + 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); + } + + 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 = writecount; + + memset(&args, 0, sizeof(WRITE3args)); + args.file = nfsfh->fh; + 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); + return -1; + } + + count -= writecount; + offset += writecount; + data->num_calls++; + } + return 0; } /* * Async write() */ -int nfs_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, size_t count, char *buf, nfs_cb cb, void *private_data) +int nfs_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buf, nfs_cb cb, void *private_data) { return nfs_pwrite_async(nfs, nfsfh, nfsfh->offset, count, buf, cb, private_data); } @@ -1103,18 +1643,22 @@ 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) { rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure"); 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; - if (rpc_nfs_getattr_async(nfs->rpc, nfs_stat_1_cb, &nfsfh->fh, data) != 0) { + memset(&args, 0, sizeof(GETATTR3args)); + args.object = nfsfh->fh; + + 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); @@ -1128,12 +1672,14 @@ int nfs_fstat_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, voi /* * Async fsync() */ -static void nfs_fsync_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) +static void nfs_fsync_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; COMMIT3res *res; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); free_nfs_cb_data(data); @@ -1160,18 +1706,22 @@ static void nfs_fsync_cb(struct rpc_context *rpc _U_, int status, void *command_ int nfs_fsync_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data) { struct nfs_cb_data *data; + struct COMMIT3args args; 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"); 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; - if (rpc_nfs_commit_async(nfs->rpc, nfs_fsync_cb, &nfsfh->fh, data) != 0) { + args.file = nfsfh->fh; + args.offset = 0; + args.count = 0; + if (rpc_nfs3_commit_async(nfs->rpc, nfs_fsync_cb, &args, data) != 0) { rpc_set_error(nfs->rpc, "RPC error: Failed to send COMMIT call for %s", data->path); data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); free_nfs_cb_data(data); @@ -1186,12 +1736,14 @@ int nfs_fsync_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, voi /* * Async ftruncate() */ -static void nfs_ftruncate_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) +static void nfs_ftruncate_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; SETATTR3res *res; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); free_nfs_cb_data(data); @@ -1215,7 +1767,7 @@ static void nfs_ftruncate_cb(struct rpc_context *rpc _U_, int status, void *comm free_nfs_cb_data(data); } -int nfs_ftruncate_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t length, nfs_cb cb, void *private_data) +int nfs_ftruncate_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t length, nfs_cb cb, void *private_data) { struct nfs_cb_data *data; SETATTR3args args; @@ -1225,18 +1777,17 @@ int nfs_ftruncate_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t leng rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure"); 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)); - args.object.data.data_len = nfsfh->fh.data.data_len; - args.object.data.data_val = nfsfh->fh.data.data_val; + memset(&args, 0, sizeof(SETATTR3args)); + args.object = nfsfh->fh; args.new_attributes.size.set_it = 1; args.new_attributes.size.set_size3_u.size = length; - if (rpc_nfs_setattr_async(nfs->rpc, nfs_ftruncate_cb, &args, data) != 0) { + if (rpc_nfs3_setattr_async(nfs->rpc, nfs_ftruncate_cb, &args, data) != 0) { rpc_set_error(nfs->rpc, "RPC error: Failed to send SETATTR call for %s", data->path); data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); free_nfs_cb_data(data); @@ -1251,11 +1802,10 @@ int nfs_ftruncate_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t leng */ static int nfs_truncate_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data) { - off_t offset = data->continue_int; + uint64_t offset = data->continue_int; struct nfsfh nfsfh; - nfsfh.fh.data.data_val = data->fh.data.data_val; - nfsfh.fh.data.data_len = data->fh.data.data_len; + nfsfh.fh = data->fh; if (nfs_ftruncate_async(nfs, &nfsfh, offset, data->cb, data->private_data) != 0) { rpc_set_error(nfs->rpc, "RPC error: Failed to send SETATTR call for %s", data->path); @@ -1267,9 +1817,9 @@ static int nfs_truncate_continue_internal(struct nfs_context *nfs, struct nfs_cb return 0; } -int nfs_truncate_async(struct nfs_context *nfs, const char *path, off_t length, nfs_cb cb, void *private_data) +int nfs_truncate_async(struct nfs_context *nfs, const char *path, uint64_t length, nfs_cb cb, void *private_data) { - off_t offset; + uint64_t offset; offset = length; @@ -1287,13 +1837,15 @@ int nfs_truncate_async(struct nfs_context *nfs, const char *path, off_t length, /* * Async mkdir() */ -static void nfs_mkdir_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) +static void nfs_mkdir_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { MKDIR3res *res; struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; char *str = data->continue_data; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + str = &str[strlen(str) + 1]; if (status == RPC_STATUS_ERROR) { @@ -1322,10 +1874,17 @@ static void nfs_mkdir_cb(struct rpc_context *rpc _U_, int status, void *command_ static int nfs_mkdir_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data) { char *str = data->continue_data; - + MKDIR3args args; + str = &str[strlen(str) + 1]; - if (rpc_nfs_mkdir_async(nfs->rpc, nfs_mkdir_cb, &data->fh, str, data) != 0) { + memset(&args, 0, sizeof(MKDIR3args)); + args.where.dir = data->fh; + args.where.name = str; + args.attributes.mode.set_it = 1; + args.attributes.mode.set_mode3_u.mode = 0755; + + if (rpc_nfs3_mkdir_async(nfs->rpc, nfs_mkdir_cb, &args, data) != 0) { rpc_set_error(nfs->rpc, "RPC error: Failed to send MKDIR call for %s", data->path); data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); free_nfs_cb_data(data); @@ -1368,13 +1927,15 @@ int nfs_mkdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void * /* * Async rmdir() */ -static void nfs_rmdir_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) +static void nfs_rmdir_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { RMDIR3res *res; struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; char *str = data->continue_data; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + str = &str[strlen(str) + 1]; if (status == RPC_STATUS_ERROR) { @@ -1403,10 +1964,13 @@ static void nfs_rmdir_cb(struct rpc_context *rpc _U_, int status, void *command_ static int nfs_rmdir_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data) { char *str = data->continue_data; - + RMDIR3args args; + str = &str[strlen(str) + 1]; - if (rpc_nfs_rmdir_async(nfs->rpc, nfs_rmdir_cb, &data->fh, str, data) != 0) { + args.object.dir = data->fh; + args.object.name = str; + if (rpc_nfs3_rmdir_async(nfs->rpc, nfs_rmdir_cb, &args, data) != 0) { rpc_set_error(nfs->rpc, "RPC error: Failed to send RMDIR call for %s", data->path); data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); free_nfs_cb_data(data); @@ -1448,7 +2012,7 @@ int nfs_rmdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void * /* * Async creat() */ -static void nfs_create_2_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) +static void nfs_create_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { LOOKUP3res *res; struct nfs_cb_data *data = private_data; @@ -1456,6 +2020,8 @@ static void nfs_create_2_cb(struct rpc_context *rpc _U_, int status, void *comma struct nfsfh *nfsfh; char *str = data->continue_data; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); free_nfs_cb_data(data); @@ -1483,12 +2049,12 @@ 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; - 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); @@ -1496,12 +2062,15 @@ static void nfs_create_2_cb(struct rpc_context *rpc _U_, int status, void *comma -static void nfs_creat_1_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) +static void nfs_creat_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { CREATE3res *res; 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); if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); @@ -1519,11 +2088,15 @@ static void nfs_creat_1_cb(struct rpc_context *rpc _U_, int status, void *comman 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->fh; + 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); @@ -1535,10 +2108,18 @@ static void nfs_creat_1_cb(struct rpc_context *rpc _U_, int status, void *comman static int nfs_creat_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data) { char *str = data->continue_data; - + CREATE3args args; + str = &str[strlen(str) + 1]; - if (rpc_nfs_create_async(nfs->rpc, nfs_creat_1_cb, &data->fh, str, data->continue_int, data) != 0) { + memset(&args, 0, sizeof(CREATE3args)); + args.where.dir = data->fh; + args.where.name = str; + args.how.mode = UNCHECKED; + args.how.createhow3_u.obj_attributes.mode.set_it = 1; + args.how.createhow3_u.obj_attributes.mode.set_mode3_u.mode = data->continue_int; + + if (rpc_nfs3_create_async(nfs->rpc, nfs_creat_1_cb, &args, data) != 0) { rpc_set_error(nfs->rpc, "RPC error: Failed to send CREATE call for %s/%s", data->path, str); data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); free_nfs_cb_data(data); @@ -1565,7 +2146,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; @@ -1580,13 +2161,15 @@ int nfs_creat_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb /* * Async unlink() */ -static void nfs_unlink_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) +static void nfs_unlink_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { REMOVE3res *res; struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; char *str = data->continue_data; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + str = &str[strlen(str) + 1]; if (status == RPC_STATUS_ERROR) { @@ -1615,10 +2198,13 @@ static void nfs_unlink_cb(struct rpc_context *rpc _U_, int status, void *command static int nfs_unlink_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data) { char *str = data->continue_data; - + struct REMOVE3args args; + str = &str[strlen(str) + 1]; - if (rpc_nfs_remove_async(nfs->rpc, nfs_unlink_cb, &data->fh, str, data) != 0) { + args.object.dir = data->fh; + args.object.name = str; + if (rpc_nfs3_remove_async(nfs->rpc, nfs_unlink_cb, &args, data) != 0) { rpc_set_error(nfs->rpc, "RPC error: Failed to send REMOVE call for %s", data->path); data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); free_nfs_cb_data(data); @@ -1655,21 +2241,235 @@ int nfs_unlink_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void } +/* + * Async mknod() + */ +struct mknod_cb_data { + char *path; + int mode; + int major; + int minor; +}; + +static void free_mknod_cb_data(void *ptr) +{ + struct mknod_cb_data *data = ptr; + + free(data->path); + free(data); +} + +static void nfs_mknod_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) +{ + MKNOD3res *res; + struct nfs_cb_data *data = private_data; + struct nfs_context *nfs = data->nfs; + char *str = data->continue_data; + + assert(rpc->magic == RPC_CONTEXT_MAGIC); + + str = &str[strlen(str) + 1]; + + if (status == RPC_STATUS_ERROR) { + data->cb(-EFAULT, nfs, command_data, data->private_data); + free_nfs_cb_data(data); + return; + } + if (status == RPC_STATUS_CANCEL) { + data->cb(-EINTR, nfs, "Command was cancelled", data->private_data); + free_nfs_cb_data(data); + return; + } + + res = command_data; + if (res->status != NFS3_OK) { + rpc_set_error(nfs->rpc, "NFS: MKNOD 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; + } + + data->cb(0, nfs, NULL, data->private_data); + free_nfs_cb_data(data); +} + +static int nfs_mknod_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data) +{ + struct mknod_cb_data *cb_data = data->continue_data; + char *str = cb_data->path; + MKNOD3args args; + + str = &str[strlen(str) + 1]; + + args.where.dir = data->fh; + args.where.name = str; + switch (cb_data->mode & S_IFMT) { + case S_IFCHR: + args.what.type = NF3CHR; + args.what.mknoddata3_u.chr_device.dev_attributes.mode.set_it = 1; + args.what.mknoddata3_u.chr_device.dev_attributes.mode.set_mode3_u.mode = cb_data->mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH); + args.what.mknoddata3_u.chr_device.spec.specdata1 = cb_data->major; + args.what.mknoddata3_u.chr_device.spec.specdata2 = cb_data->minor; + break; + case S_IFBLK: + args.what.type = NF3BLK; + args.what.mknoddata3_u.blk_device.dev_attributes.mode.set_it = 1; + args.what.mknoddata3_u.blk_device.dev_attributes.mode.set_mode3_u.mode = cb_data->mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH); + args.what.mknoddata3_u.blk_device.spec.specdata1 = cb_data->major; + args.what.mknoddata3_u.blk_device.spec.specdata2 = cb_data->minor; + case S_IFSOCK: + args.what.type = NF3SOCK; + args.what.mknoddata3_u.sock_attributes.mode.set_it = 1; + args.what.mknoddata3_u.sock_attributes.mode.set_mode3_u.mode = cb_data->mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH); + break; + case S_IFIFO: + args.what.type = NF3FIFO; + args.what.mknoddata3_u.pipe_attributes.mode.set_it = 1; + args.what.mknoddata3_u.pipe_attributes.mode.set_mode3_u.mode = cb_data->mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH); + break; + default: + rpc_set_error(nfs->rpc, "Invalid file type for NFS3/MKNOD call"); + data->cb(-EINVAL, nfs, rpc_get_error(nfs->rpc), data->private_data); + free_nfs_cb_data(data); + return -1; + } + + if (rpc_nfs3_mknod_async(nfs->rpc, nfs_mknod_cb, &args, data) != 0) { + data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); + free_nfs_cb_data(data); + return -1; + } + return 0; +} + +int nfs_mknod_async(struct nfs_context *nfs, const char *path, int mode, int dev, nfs_cb cb, void *private_data) +{ + char *ptr; + struct mknod_cb_data *cb_data; + + cb_data = malloc(sizeof(struct mknod_cb_data)); + if (cb_data == NULL) { + rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for cb data"); + return -1; + } + + cb_data->path = strdup(path); + if (cb_data->path == NULL) { + rpc_set_error(nfs->rpc, "Out of memory, failed to allocate mode buffer for path"); + free(cb_data); + return -1; + } + + ptr = strrchr(cb_data->path, '/'); + if (ptr == NULL) { + rpc_set_error(nfs->rpc, "Invalid path %s", path); + return -1; + } + *ptr = 0; + + cb_data->mode = mode; + cb_data->major = major(dev); + cb_data->minor = minor(dev); + /* data->path now points to the parent directory, and beyond the nul terminateor is the new directory to create */ + if (nfs_lookuppath_async(nfs, cb_data->path, cb, private_data, nfs_mknod_continue_internal, cb_data, free_mknod_cb_data, 0) != 0) { + rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components"); + free_mknod_cb_data(cb_data); + return -1; + } + return 0; +} /* * Async opendir() */ -static void nfs_opendir_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) + +/* ReadDirPlus Emulation Callback data */ +struct rdpe_cb_data { + int getattrcount; + int status; + struct nfs_cb_data *data; +}; + +/* ReadDirPlus Emulation LOOKUP Callback data */ +struct rdpe_lookup_cb_data { + struct rdpe_cb_data *rdpe_cb_data; + struct nfsdirent *nfsdirent; +}; + +/* Workaround for servers lacking READDIRPLUS, use READDIR instead and a GETATTR-loop */ +static void nfs_opendir3_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) +{ + LOOKUP3res *res = command_data; + struct rdpe_lookup_cb_data *rdpe_lookup_cb_data = private_data; + struct rdpe_cb_data *rdpe_cb_data = rdpe_lookup_cb_data->rdpe_cb_data; + struct nfs_cb_data *data = rdpe_cb_data->data; + struct nfsdir *nfsdir = data->continue_data; + struct nfs_context *nfs = data->nfs; + struct nfsdirent *nfsdirent = rdpe_lookup_cb_data->nfsdirent; + + assert(rpc->magic == RPC_CONTEXT_MAGIC); + + free(rdpe_lookup_cb_data); + + rdpe_cb_data->getattrcount--; + + if (status == RPC_STATUS_ERROR) { + rdpe_cb_data->status = RPC_STATUS_ERROR; + } + if (status == RPC_STATUS_CANCEL) { + rdpe_cb_data->status = RPC_STATUS_CANCEL; + } + if (status == RPC_STATUS_SUCCESS && res->status != NFS3_OK) { + rdpe_cb_data->status = RPC_STATUS_ERROR; + } + if (status == RPC_STATUS_SUCCESS && res->status == NFS3_OK) { + if (res->LOOKUP3res_u.resok.obj_attributes.attributes_follow) { + fattr3 *attributes = &res->LOOKUP3res_u.resok.obj_attributes.post_op_attr_u.attributes; + + nfsdirent->type = attributes->type; + nfsdirent->mode = attributes->mode; + nfsdirent->size = attributes->size; + + nfsdirent->atime.tv_sec = attributes->atime.seconds; + nfsdirent->atime.tv_usec = attributes->atime.nseconds/1000; + nfsdirent->mtime.tv_sec = attributes->mtime.seconds; + nfsdirent->mtime.tv_usec = attributes->mtime.nseconds/1000; + nfsdirent->ctime.tv_sec = attributes->ctime.seconds; + nfsdirent->ctime.tv_usec = attributes->ctime.nseconds/1000; + nfsdirent->uid = attributes->uid; + nfsdirent->gid = attributes->gid; + } + } + + if (rdpe_cb_data->getattrcount == 0) { + if (rdpe_cb_data->status != RPC_STATUS_SUCCESS) { + data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); + nfs_free_nfsdir(nfsdir); + } else { + data->cb(0, nfs, nfsdir, data->private_data); + } + free(rdpe_cb_data); + + data->continue_data = NULL; + free_nfs_cb_data(data); + } +} + +static void nfs_opendir2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { - READDIR3res *res; + READDIR3res *res = command_data; struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; struct nfsdir *nfsdir = data->continue_data; + struct nfsdirent *nfsdirent; struct entry3 *entry; uint64_t cookie; + struct rdpe_cb_data *rdpe_cb_data; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); nfs_free_nfsdir(nfsdir); @@ -1677,6 +2477,7 @@ static void nfs_opendir_cb(struct rpc_context *rpc _U_, int status, void *comman free_nfs_cb_data(data); return; } + if (status == RPC_STATUS_CANCEL) { data->cb(-EINTR, nfs, "Command was cancelled", data->private_data); nfs_free_nfsdir(nfsdir); @@ -1685,7 +2486,6 @@ static void nfs_opendir_cb(struct rpc_context *rpc _U_, int status, void *comman return; } - res = command_data; if (res->status != NFS3_OK) { rpc_set_error(nfs->rpc, "NFS: READDIR of %s failed with %s(%d)", data->saved_path, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status)); data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data); @@ -1697,8 +2497,6 @@ static void nfs_opendir_cb(struct rpc_context *rpc _U_, int status, void *comman entry =res->READDIR3res_u.resok.reply.entries; while (entry != NULL) { - struct nfsdirent *nfsdirent; - nfsdirent = malloc(sizeof(struct nfsdirent)); if (nfsdirent == NULL) { data->cb(-ENOMEM, nfs, "Failed to allocate dirent", data->private_data); @@ -1707,7 +2505,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); @@ -1717,6 +2515,7 @@ static void nfs_opendir_cb(struct rpc_context *rpc _U_, int status, void *comman return; } nfsdirent->inode = entry->fileid; + nfsdirent->next = nfsdir->entries; nfsdir->entries = nfsdirent; @@ -1725,7 +2524,88 @@ static void nfs_opendir_cb(struct rpc_context *rpc _U_, int status, void *comman } 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) { + READDIR3args args; + + args.dir = data->fh; + args.cookie = cookie; + memcpy(&args.cookieverf, res->READDIR3res_u.resok.cookieverf, sizeof(cookieverf3)); + args.count = 8192; + + if (rpc_nfs3_readdir_async(nfs->rpc, nfs_opendir2_cb, &args, data) != 0) { + rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR 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; + free_nfs_cb_data(data); + return; + } + return; + } + + /* steal the dirhandle */ + nfsdir->current = nfsdir->entries; + + rdpe_cb_data = malloc(sizeof(struct rdpe_cb_data)); + rdpe_cb_data->getattrcount = 0; + rdpe_cb_data->status = RPC_STATUS_SUCCESS; + 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; + + memset(&args, 0, sizeof(LOOKUP3args)); + args.what.dir = data->fh; + 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 + * commands in flight to complete + */ + if (rdpe_cb_data->getattrcount > 0) { + rdpe_cb_data->status = RPC_STATUS_ERROR; + free(rdpe_lookup_cb_data); + return; + } + + data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); + nfs_free_nfsdir(nfsdir); + data->continue_data = NULL; + free_nfs_cb_data(data); + free(rdpe_lookup_cb_data); + free(rdpe_cb_data); + return; + } + rdpe_cb_data->getattrcount++; + } +} + + +static void nfs_opendir_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) +{ + READDIRPLUS3res *res = command_data; + struct nfs_cb_data *data = private_data; + struct nfs_context *nfs = data->nfs; + struct nfsdir *nfsdir = data->continue_data; + struct entryplus3 *entry; + uint64_t cookie; + + assert(rpc->magic == RPC_CONTEXT_MAGIC); + + if (status == RPC_STATUS_ERROR || (status == RPC_STATUS_SUCCESS && res->status == NFS3ERR_NOTSUPP) ){ + READDIR3args args; + + args.dir = data->fh; + args.cookie = cookie; + memset(&args.cookieverf, 0, sizeof(cookieverf3)); + args.count = 8192; + + if (rpc_nfs3_readdir_async(nfs->rpc, nfs_opendir2_cb, &args, data) != 0) { rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR call for %s", data->path); data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); nfs_free_nfsdir(nfsdir); @@ -1736,6 +2616,87 @@ static void nfs_opendir_cb(struct rpc_context *rpc _U_, int status, void *comman return; } + if (status == RPC_STATUS_CANCEL) { + data->cb(-EINTR, nfs, "Command was cancelled", data->private_data); + nfs_free_nfsdir(nfsdir); + data->continue_data = NULL; + free_nfs_cb_data(data); + return; + } + + if (res->status != NFS3_OK) { + rpc_set_error(nfs->rpc, "NFS: READDIRPLUS of %s failed with %s(%d)", data->saved_path, 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); + nfs_free_nfsdir(nfsdir); + data->continue_data = NULL; + free_nfs_cb_data(data); + return; + } + + entry =res->READDIRPLUS3res_u.resok.reply.entries; + while (entry != NULL) { + struct nfsdirent *nfsdirent; + + nfsdirent = malloc(sizeof(struct nfsdirent)); + if (nfsdirent == NULL) { + data->cb(-ENOMEM, nfs, "Failed to allocate dirent", data->private_data); + nfs_free_nfsdir(nfsdir); + data->continue_data = NULL; + free_nfs_cb_data(data); + return; + } + 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); + nfs_free_nfsdir(nfsdir); + data->continue_data = NULL; + free_nfs_cb_data(data); + 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->uid = entry->name_attributes.post_op_attr_u.attributes.uid; + nfsdirent->gid = entry->name_attributes.post_op_attr_u.attributes.gid; + } + + nfsdirent->next = nfsdir->entries; + nfsdir->entries = nfsdirent; + + cookie = entry->cookie; + entry = entry->nextentry; + } + + if (res->READDIRPLUS3res_u.resok.reply.eof == 0) { + READDIRPLUS3args args; + + args.dir = data->fh; + args.cookie = cookie; + memcpy(&args.cookieverf, res->READDIRPLUS3res_u.resok.cookieverf, sizeof(cookieverf3)); + args.dircount = 8192; + args.maxcount = 8192; + + if (rpc_nfs3_readdirplus_async(nfs->rpc, nfs_opendir_cb, &args, 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; + free_nfs_cb_data(data); + return; + } + return; + } + /* steal the dirhandle */ data->continue_data = NULL; nfsdir->current = nfsdir->entries; @@ -1746,11 +2707,15 @@ static void nfs_opendir_cb(struct rpc_context *rpc _U_, int status, void *comman static int nfs_opendir_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data) { - 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); + READDIRPLUS3args args; + + args.dir = data->fh; + args.cookie = 0; + memset(&args.cookieverf, 0, sizeof(cookieverf3)); + args.dircount = 8192; + args.maxcount = 8192; + if (rpc_nfs3_readdirplus_async(nfs->rpc, nfs_opendir_cb, &args, 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; @@ -1767,7 +2732,7 @@ int nfs_opendir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void 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) { rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components"); @@ -1806,17 +2771,19 @@ void nfs_closedir(struct nfs_context *nfs _U_, struct nfsdir *nfsdir) struct lseek_cb_data { struct nfs_context *nfs; struct nfsfh *nfsfh; - off_t offset; + uint64_t offset; nfs_cb cb; void *private_data; }; -static void nfs_lseek_1_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) +static void nfs_lseek_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { GETATTR3res *res; struct lseek_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); free(data); @@ -1841,9 +2808,10 @@ static void nfs_lseek_1_cb(struct rpc_context *rpc _U_, int status, void *comman free(data); } -int nfs_lseek_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, int whence, nfs_cb cb, void *private_data) +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; @@ -1868,7 +2836,10 @@ int nfs_lseek_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, 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 = nfsfh->fh; + + 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; @@ -1882,13 +2853,15 @@ int nfs_lseek_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, /* * Async statvfs() */ -static void nfs_statvfs_1_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) +static void nfs_statvfs_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { FSSTAT3res *res; struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; struct statvfs svfs; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); free_nfs_cb_data(data); @@ -1915,10 +2888,12 @@ static void nfs_statvfs_1_cb(struct rpc_context *rpc _U_, int status, void *comm svfs.f_bavail = res->FSSTAT3res_u.resok.abytes/4096; svfs.f_files = res->FSSTAT3res_u.resok.tfiles; svfs.f_ffree = res->FSSTAT3res_u.resok.ffiles; +#if !defined(ANDROID) svfs.f_favail = res->FSSTAT3res_u.resok.afiles; svfs.f_fsid = 0; svfs.f_flag = 0; svfs.f_namemax = 256; +#endif data->cb(0, nfs, &svfs, data->private_data); free_nfs_cb_data(data); @@ -1926,7 +2901,10 @@ static void nfs_statvfs_1_cb(struct rpc_context *rpc _U_, int status, void *comm static int nfs_statvfs_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data) { - if (rpc_nfs_fsstat_async(nfs->rpc, nfs_statvfs_1_cb, &data->fh, data) != 0) { + FSSTAT3args args; + + args.fsroot = data->fh; + if (rpc_nfs3_fsstat_async(nfs->rpc, nfs_statvfs_1_cb, &args, data) != 0) { rpc_set_error(nfs->rpc, "RPC error: Failed to send FSSTAT call for %s", data->path); data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); free_nfs_cb_data(data); @@ -1951,12 +2929,14 @@ int nfs_statvfs_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void /* * Async readlink() */ -static void nfs_readlink_1_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) +static void nfs_readlink_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { READLINK3res *res; struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); free_nfs_cb_data(data); @@ -1983,7 +2963,11 @@ static void nfs_readlink_1_cb(struct rpc_context *rpc _U_, int status, void *com static int nfs_readlink_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data) { - if (rpc_nfs_readlink_async(nfs->rpc, nfs_readlink_1_cb, &data->fh, data) != 0) { + READLINK3args args; + + args.symlink = data->fh; + + if (rpc_nfs3_readlink_async(nfs->rpc, nfs_readlink_1_cb, &args, data) != 0) { rpc_set_error(nfs->rpc, "RPC error: Failed to send READLINK call for %s", data->path); data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); free_nfs_cb_data(data); @@ -2008,12 +2992,14 @@ int nfs_readlink_async(struct nfs_context *nfs, const char *path, nfs_cb cb, voi /* * Async chmod() */ -static void nfs_chmod_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) +static void nfs_chmod_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; SETATTR3res *res; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); free_nfs_cb_data(data); @@ -2041,13 +3027,12 @@ static int nfs_chmod_continue_internal(struct nfs_context *nfs, struct nfs_cb_da { SETATTR3args args; - bzero(&args, sizeof(SETATTR3args)); - args.object.data.data_len = data->fh.data.data_len; - args.object.data.data_val = data->fh.data.data_val; + memset(&args, 0, sizeof(SETATTR3args)); + args.object = data->fh; args.new_attributes.mode.set_it = 1; args.new_attributes.mode.set_mode3_u.mode = data->continue_int; - if (rpc_nfs_setattr_async(nfs->rpc, nfs_chmod_cb, &args, data) != 0) { + if (rpc_nfs3_setattr_async(nfs->rpc, nfs_chmod_cb, &args, data) != 0) { rpc_set_error(nfs->rpc, "RPC error: Failed to send SETATTR call for %s", data->path); data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); free_nfs_cb_data(data); @@ -2079,7 +3064,7 @@ int nfs_fchmod_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int mode, nfs 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; @@ -2106,12 +3091,14 @@ int nfs_fchmod_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int mode, nfs /* * Async chown() */ -static void nfs_chown_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) +static void nfs_chown_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; SETATTR3res *res; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); free_nfs_cb_data(data); @@ -2145,9 +3132,8 @@ 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)); - args.object.data.data_len = data->fh.data.data_len; - args.object.data.data_val = data->fh.data.data_val; + memset(&args, 0, sizeof(SETATTR3args)); + args.object = data->fh; if (chown_data->uid != (uid_t)-1) { args.new_attributes.uid.set_it = 1; args.new_attributes.uid.set_uid3_u.uid = chown_data->uid; @@ -2157,7 +3143,7 @@ static int nfs_chown_continue_internal(struct nfs_context *nfs, struct nfs_cb_da args.new_attributes.gid.set_gid3_u.gid = chown_data->gid; } - if (rpc_nfs_setattr_async(nfs->rpc, nfs_chown_cb, &args, data) != 0) { + if (rpc_nfs3_setattr_async(nfs->rpc, nfs_chown_cb, &args, data) != 0) { rpc_set_error(nfs->rpc, "RPC error: Failed to send SETATTR call for %s", data->path); data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); free_nfs_cb_data(data); @@ -2212,7 +3198,7 @@ int nfs_fchown_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int uid, int 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; @@ -2242,12 +3228,14 @@ int nfs_fchown_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int uid, int /* * Async utimes() */ -static void nfs_utimes_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) +static void nfs_utimes_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; SETATTR3res *res; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); free_nfs_cb_data(data); @@ -2276,9 +3264,8 @@ 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)); - args.object.data.data_len = data->fh.data.data_len; - args.object.data.data_val = data->fh.data.data_val; + memset(&args, 0, sizeof(SETATTR3args)); + args.object = data->fh; if (utimes_data != NULL) { args.new_attributes.atime.set_it = SET_TO_CLIENT_TIME; args.new_attributes.atime.set_atime_u.atime.seconds = utimes_data[0].tv_sec; @@ -2291,7 +3278,7 @@ static int nfs_utimes_continue_internal(struct nfs_context *nfs, struct nfs_cb_d args.new_attributes.mtime.set_it = SET_TO_SERVER_TIME; } - if (rpc_nfs_setattr_async(nfs->rpc, nfs_utimes_cb, &args, data) != 0) { + if (rpc_nfs3_setattr_async(nfs->rpc, nfs_utimes_cb, &args, data) != 0) { rpc_set_error(nfs->rpc, "RPC error: Failed to send SETATTR call for %s", data->path); data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); free_nfs_cb_data(data); @@ -2352,19 +3339,18 @@ int nfs_utime_async(struct nfs_context *nfs, const char *path, struct utimbuf *t } - - - /* * Async access() */ -static void nfs_access_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) +static void nfs_access_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { ACCESS3res *res; struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; unsigned int nfsmode = 0; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); free_nfs_cb_data(data); @@ -2414,6 +3400,7 @@ static void nfs_access_cb(struct rpc_context *rpc _U_, int status, void *command 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; @@ -2425,7 +3412,11 @@ 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->fh; + 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); @@ -2471,13 +3462,15 @@ static void free_nfs_symlink_data(void *mem) free(data); } -static void nfs_symlink_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) +static void nfs_symlink_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { SYMLINK3res *res; struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; struct nfs_symlink_data *symlink_data = data->continue_data; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); free_nfs_cb_data(data); @@ -2504,8 +3497,16 @@ static void nfs_symlink_cb(struct rpc_context *rpc _U_, int status, void *comman static int nfs_symlink_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data) { struct nfs_symlink_data *symlink_data = data->continue_data; + SYMLINK3args args; - if (rpc_nfs_symlink_async(nfs->rpc, nfs_symlink_cb, &data->fh, symlink_data->newpathobject, symlink_data->oldpath, data) != 0) { + memset(&args, 0, sizeof(SYMLINK3args)); + args.where.dir = data->fh; + args.where.name = symlink_data->newpathobject; + args.symlink.symlink_attributes.mode.set_it = 1; + args.symlink.symlink_attributes.mode.set_mode3_u.mode = S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH; + args.symlink.symlink_data = symlink_data->oldpath; + + if (rpc_nfs3_symlink_async(nfs->rpc, nfs_symlink_cb, &args, data) != 0) { rpc_set_error(nfs->rpc, "RPC error: Failed to send SYMLINK call for %s", data->path); data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); free_nfs_cb_data(data); @@ -2524,7 +3525,7 @@ int nfs_symlink_async(struct nfs_context *nfs, const char *oldpath, const char * 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) { @@ -2597,13 +3598,15 @@ static void free_nfs_rename_data(void *mem) free(data); } -static void nfs_rename_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) +static void nfs_rename_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { RENAME3res *res; struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; struct nfs_rename_data *rename_data = data->continue_data; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); free_nfs_cb_data(data); @@ -2630,13 +3633,17 @@ static void nfs_rename_cb(struct rpc_context *rpc _U_, int status, void *command static int nfs_rename_continue_2_internal(struct nfs_context *nfs, struct nfs_cb_data *data) { struct nfs_rename_data *rename_data = data->continue_data; + RENAME3args args; /* steal the filehandle */ - rename_data->newdir.data.data_len = data->fh.data.data_len; - rename_data->newdir.data.data_val = data->fh.data.data_val; + rename_data->newdir = data->fh; data->fh.data.data_val = NULL; - if (rpc_nfs_rename_async(nfs->rpc, nfs_rename_cb, &rename_data->olddir, rename_data->oldobject, &rename_data->newdir, rename_data->newobject, data) != 0) { + args.from.dir = rename_data->olddir; + args.from.name = rename_data->oldobject; + args.to.dir = rename_data->newdir; + args.to.name = rename_data->newobject; + if (rpc_nfs3_rename_async(nfs->rpc, nfs_rename_cb, &args, data) != 0) { rpc_set_error(nfs->rpc, "RPC error: Failed to send RENAME call for %s", data->path); data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); free_nfs_cb_data(data); @@ -2651,8 +3658,7 @@ static int nfs_rename_continue_1_internal(struct nfs_context *nfs, struct nfs_cb struct nfs_rename_data *rename_data = data->continue_data; /* steal the filehandle */ - rename_data->olddir.data.data_len = data->fh.data.data_len; - rename_data->olddir.data.data_val = data->fh.data.data_val; + rename_data->olddir = data->fh; data->fh.data.data_val = NULL; if (nfs_lookuppath_async(nfs, rename_data->newpath, data->cb, data->private_data, nfs_rename_continue_2_internal, rename_data, free_nfs_rename_data, 0) != 0) { @@ -2678,7 +3684,7 @@ int nfs_rename_async(struct nfs_context *nfs, const char *oldpath, const char *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) { @@ -2753,13 +3759,15 @@ static void free_nfs_link_data(void *mem) free(data); } -static void nfs_link_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) +static void nfs_link_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { LINK3res *res; struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; struct nfs_link_data *link_data = data->continue_data; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); free_nfs_cb_data(data); @@ -2786,13 +3794,17 @@ static void nfs_link_cb(struct rpc_context *rpc _U_, int status, void *command_d static int nfs_link_continue_2_internal(struct nfs_context *nfs, struct nfs_cb_data *data) { struct nfs_link_data *link_data = data->continue_data; + LINK3args args; /* steal the filehandle */ - link_data->newdir.data.data_len = data->fh.data.data_len; - link_data->newdir.data.data_val = data->fh.data.data_val; + link_data->newdir = data->fh; data->fh.data.data_val = NULL; - if (rpc_nfs_link_async(nfs->rpc, nfs_link_cb, &link_data->oldfh, &link_data->newdir, link_data->newobject, data) != 0) { + memset(&args, 0, sizeof(LINK3args)); + args.file = link_data->oldfh; + args.link.dir = link_data->newdir; + args.link.name = link_data->newobject; + if (rpc_nfs3_link_async(nfs->rpc, nfs_link_cb, &args, data) != 0) { rpc_set_error(nfs->rpc, "RPC error: Failed to send LINK call for %s", data->path); data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); free_nfs_cb_data(data); @@ -2807,8 +3819,7 @@ static int nfs_link_continue_1_internal(struct nfs_context *nfs, struct nfs_cb_d struct nfs_link_data *link_data = data->continue_data; /* steal the filehandle */ - link_data->oldfh.data.data_len = data->fh.data.data_len; - link_data->oldfh.data.data_val = data->fh.data.data_val; + link_data->oldfh = data->fh; data->fh.data.data_val = NULL; if (nfs_lookuppath_async(nfs, link_data->newpath, data->cb, data->private_data, nfs_link_continue_2_internal, link_data, free_nfs_link_data, 0) != 0) { @@ -2834,7 +3845,7 @@ int nfs_link_async(struct nfs_context *nfs, const char *oldpath, const char *new 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) { @@ -2870,7 +3881,7 @@ int nfs_link_async(struct nfs_context *nfs, const char *oldpath, const char *new //qqq replace later with lseek() -off_t nfs_get_current_offset(struct nfsfh *nfsfh) +uint64_t nfs_get_current_offset(struct nfsfh *nfsfh) { return nfsfh->offset; } @@ -2880,7 +3891,7 @@ off_t nfs_get_current_offset(struct nfsfh *nfsfh) /* * Get the maximum supported READ3 size by the server */ -size_t nfs_get_readmax(struct nfs_context *nfs) +uint64_t nfs_get_readmax(struct nfs_context *nfs) { return nfs->readmax; } @@ -2888,23 +3899,36 @@ size_t nfs_get_readmax(struct nfs_context *nfs) /* * Get the maximum supported WRITE3 size by the server */ -size_t nfs_get_writemax(struct nfs_context *nfs) +uint64_t nfs_get_writemax(struct nfs_context *nfs) { return nfs->writemax; } +void nfs_set_tcp_syncnt(struct nfs_context *nfs, int v) { + rpc_set_tcp_syncnt(nfs->rpc, v); +} + +void nfs_set_uid(struct nfs_context *nfs, int uid) { + rpc_set_uid(nfs->rpc, uid); +} + +void nfs_set_gid(struct nfs_context *nfs, int gid) { + rpc_set_gid(nfs->rpc, gid); +} + void nfs_set_error(struct nfs_context *nfs, char *error_string, ...) { va_list ap; char *str = NULL; va_start(ap, error_string); - // vasprintf(&str, error_string, ap); - // if (nfs->rpc->error_string != NULL) { - // free(nfs->rpc->error_string); - //} - //nfs->rpc->error_string = str; - va_end(ap); + 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); } @@ -2929,7 +3953,9 @@ static void mount_export_5_cb(struct rpc_context *rpc, int status, void *command { struct mount_cb_data *data = private_data; - if (status == RPC_STATUS_ERROR) { + assert(rpc->magic == RPC_CONTEXT_MAGIC); + + if (status == RPC_STATUS_ERROR) { data->cb(rpc, -EFAULT, command_data, data->private_data); free_mount_cb_data(data); return; @@ -2951,6 +3977,11 @@ static void mount_export_4_cb(struct rpc_context *rpc, int status, void *command { struct mount_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, -EFAULT, command_data, data->private_data); free_mount_cb_data(data); @@ -2962,7 +3993,7 @@ static void mount_export_4_cb(struct rpc_context *rpc, int status, void *command return; } - if (rpc_mount_export_async(rpc, mount_export_5_cb, data) != 0) { + if (rpc_mount3_export_async(rpc, mount_export_5_cb, data) != 0) { data->cb(rpc, -ENOMEM, command_data, data->private_data); free_mount_cb_data(data); return; @@ -2974,7 +4005,9 @@ static void mount_export_3_cb(struct rpc_context *rpc, int status, void *command struct mount_cb_data *data = private_data; uint32_t mount_port; - if (status == RPC_STATUS_ERROR) { + assert(rpc->magic == RPC_CONTEXT_MAGIC); + + if (status == RPC_STATUS_ERROR) { data->cb(rpc, -EFAULT, command_data, data->private_data); free_mount_cb_data(data); return; @@ -3005,6 +4038,8 @@ static void mount_export_2_cb(struct rpc_context *rpc, int status, void *command { struct mount_cb_data *data = private_data; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (status == RPC_STATUS_ERROR) { data->cb(rpc, -EFAULT, command_data, data->private_data); free_mount_cb_data(data); @@ -3016,7 +4051,7 @@ static void mount_export_2_cb(struct rpc_context *rpc, int status, void *command return; } - if (rpc_pmap_getport_async(rpc, MOUNT_PROGRAM, MOUNT_V3, mount_export_3_cb, private_data) != 0) { + if (rpc_pmap_getport_async(rpc, MOUNT_PROGRAM, MOUNT_V3, IPPROTO_TCP, mount_export_3_cb, private_data) != 0) { data->cb(rpc, -ENOMEM, command_data, data->private_data); free_mount_cb_data(data); return; @@ -3027,6 +4062,11 @@ static void mount_export_1_cb(struct rpc_context *rpc, int status, void *command { struct mount_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, -EFAULT, command_data, data->private_data); free_mount_cb_data(data); @@ -3049,11 +4089,13 @@ int mount_getexports_async(struct rpc_context *rpc, const char *server, rpc_cb c { struct mount_cb_data *data; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + data = malloc(sizeof(struct mount_cb_data)); if (data == NULL) { return -1; } - bzero(data, sizeof(struct mount_cb_data)); + memset(data, 0, sizeof(struct mount_cb_data)); data->cb = cb; data->private_data = private_data; data->server = strdup(server); @@ -3071,6 +4113,7 @@ int mount_getexports_async(struct rpc_context *rpc, const char *server, rpc_cb c struct rpc_context *nfs_get_rpc_context(struct nfs_context *nfs) { + assert(nfs->rpc->magic == RPC_CONTEXT_MAGIC); return nfs->rpc; } @@ -3081,3 +4124,11 @@ const char *nfs_get_server(struct nfs_context *nfs) { const char *nfs_get_export(struct nfs_context *nfs) { return nfs->export; } + +const struct nfs_fh3 *nfs_get_rootfh(struct nfs_context *nfs) { + return &nfs->rootfh; +} + +struct nfs_fh3 *nfs_get_fh(struct nfsfh *nfsfh) { + return &nfsfh->fh; +}