X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=lib%2Flibnfs.c;h=543b0ce9ec89a7293e129213e7158c6d150ded77;hb=728970051cb7420c08c3c4860f09f971880e3244;hp=c637a7518f172d696ed63b4d54f9df62333280b6;hpb=cdb19ec1642636497881215a69166fd5f1d0cda2;p=deb_libnfs.git diff --git a/lib/libnfs.c b/lib/libnfs.c index c637a75..543b0ce 100644 --- a/lib/libnfs.c +++ b/lib/libnfs.c @@ -17,20 +17,53 @@ /* * High level api to nfs filesystems */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef AROS +#include "aros_compat.h" +#endif + +#ifdef WIN32 +#include "win32_compat.h" +#else +#include +#include +#endif /*WIN32*/ + +#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 + #include #include #include #include -#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" @@ -45,7 +78,7 @@ struct nfsdir { struct nfsfh { struct nfs_fh3 fh; int is_sync; - off_t offset; + uint64_t offset; }; struct nfs_context { @@ -53,8 +86,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) @@ -92,14 +125,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); @@ -107,7 +140,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) @@ -115,6 +148,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); @@ -144,6 +182,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; } @@ -199,11 +243,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); @@ -225,6 +271,8 @@ static void nfs_mount_9_cb(struct rpc_context *rpc, int status, void *command_da struct nfs_context *nfs = data->nfs; FSINFO3res *res = command_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); @@ -251,6 +299,8 @@ 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; + 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); @@ -275,6 +325,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); @@ -300,6 +355,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); @@ -335,6 +392,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); } @@ -343,6 +402,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); @@ -366,6 +427,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); @@ -390,6 +456,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); @@ -423,6 +491,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); @@ -434,7 +504,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; @@ -446,6 +516,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); @@ -470,15 +545,24 @@ static void nfs_mount_1_cb(struct rpc_context *rpc, int status, void *command_da int nfs_mount_async(struct nfs_context *nfs, const char *server, const char *export, nfs_cb cb, void *private_data) { struct nfs_cb_data *data; + char *new_server, *new_export; data = malloc(sizeof(struct nfs_cb_data)); if (data == NULL) { rpc_set_error(nfs->rpc, "out of memory. failed to allocate memory for nfs mount data"); return -1; } - bzero(data, sizeof(struct nfs_cb_data)); - nfs->server = strdup(server); - nfs->export = strdup(export); + memset(data, 0, sizeof(struct nfs_cb_data)); + new_server = strdup(server); + new_export = strdup(export); + if (nfs->server != NULL) { + free(nfs->server); + } + nfs->server = new_server; + if (nfs->export != NULL) { + free(nfs->export); + } + nfs->export = new_export; data->nfs = nfs; data->cb = cb; data->private_data = private_data; @@ -498,12 +582,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); @@ -540,7 +626,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; @@ -577,8 +663,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; } @@ -587,7 +673,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; @@ -617,13 +703,15 @@ 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; struct stat st; + 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); @@ -646,13 +734,21 @@ static void nfs_stat_1_cb(struct rpc_context *rpc _U_, int status, void *command st.st_dev = -1; st.st_ino = res->GETATTR3res_u.resok.obj_attributes.fileid; st.st_mode = res->GETATTR3res_u.resok.obj_attributes.mode; + if (res->GETATTR3res_u.resok.obj_attributes.type == NF3DIR) { + st.st_mode |= S_IFDIR ; + } + 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; +#ifndef WIN32 st.st_blksize = 4096; st.st_blocks = res->GETATTR3res_u.resok.obj_attributes.size / 4096; +#endif//WIN32 st.st_atime = res->GETATTR3res_u.resok.obj_attributes.atime.seconds; st.st_mtime = res->GETATTR3res_u.resok.obj_attributes.mtime.seconds; st.st_ctime = res->GETATTR3res_u.resok.obj_attributes.ctime.seconds; @@ -689,7 +785,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; @@ -697,6 +793,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); @@ -747,7 +845,7 @@ static void nfs_open_cb(struct rpc_context *rpc _U_, int status, void *command_d free_nfs_cb_data(data); return; } - bzero(nfsfh, sizeof(struct nfsfh)); + memset(nfsfh, 0, sizeof(struct nfsfh)); if (data->continue_int & O_SYNC) { nfsfh->is_sync = 1; @@ -802,12 +900,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); @@ -832,13 +932,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) { @@ -856,10 +958,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; + } } } } @@ -885,11 +989,12 @@ 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); } -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; @@ -898,7 +1003,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; @@ -920,6 +1025,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); @@ -931,7 +1037,7 @@ 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; if (readcount > nfs_get_readmax(nfs)) { @@ -943,7 +1049,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_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; @@ -965,7 +1071,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); } @@ -975,12 +1081,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); @@ -1005,7 +1113,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; @@ -1014,26 +1183,68 @@ 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)) { + 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; + } + 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 parallell 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; + + 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; + + if (rpc_nfs_write_async(nfs->rpc, nfs_pwrite_mcb, &nfsfh->fh, &buf[offset - data->start_offset], offset, writecount, nfsfh->is_sync?FILE_SYNC:UNSTABLE, mdata) != 0) { + 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); } @@ -1073,7 +1284,7 @@ int nfs_fstat_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, voi 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; @@ -1092,12 +1303,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); @@ -1130,7 +1343,7 @@ int nfs_fsync_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, voi 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; @@ -1150,12 +1363,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); @@ -1179,7 +1394,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; @@ -1189,12 +1404,12 @@ 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)); + memset(&args, 0, sizeof(SETATTR3args)); args.object.data.data_len = nfsfh->fh.data.data_len; args.object.data.data_val = nfsfh->fh.data.data_val; args.new_attributes.size.set_it = 1; @@ -1215,7 +1430,7 @@ 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; @@ -1231,9 +1446,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; @@ -1251,13 +1466,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) { @@ -1286,10 +1503,18 @@ 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.data_len = data->fh.data.data_len; + args.where.dir.data.data_val = data->fh.data.data_val; + args.where.name = str; + args.attributes.mode.set_it = 1; + args.attributes.mode.set_mode3_u.mode = 0755; + + if (rpc_nfs_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); @@ -1309,7 +1534,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; @@ -1332,13 +1557,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) { @@ -1390,7 +1617,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; @@ -1412,7 +1639,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; @@ -1420,6 +1647,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); @@ -1447,12 +1676,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); @@ -1460,13 +1689,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; + 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); @@ -1499,10 +1730,19 @@ 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.data_len = data->fh.data.data_len; + args.where.dir.data.data_val = data->fh.data.data_val; + 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_nfs_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); @@ -1522,14 +1762,14 @@ 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; } *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; @@ -1544,13 +1784,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) { @@ -1602,7 +1844,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; @@ -1619,21 +1861,199 @@ 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; + + str = &str[strlen(str) + 1]; + + if (rpc_nfs_mknod_async(nfs->rpc, nfs_mknod_cb, &data->fh, str, cb_data->mode, cb_data->major, cb_data->minor, 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; + } + } + + 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 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); @@ -1641,6 +2061,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); @@ -1649,7 +2070,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); @@ -1661,8 +2081,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); @@ -1671,7 +2089,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); @@ -1681,6 +2099,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; @@ -1689,7 +2108,7 @@ 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) { + if (rpc_nfs_readdir_async(nfs->rpc, nfs_opendir2_cb, &data->fh, cookie, res->READDIR3res_u.resok.cookieverf, 8192, 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); @@ -1700,6 +2119,141 @@ static void nfs_opendir_cb(struct rpc_context *rpc _U_, int status, void *comman 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; + + rdpe_lookup_cb_data = malloc(sizeof(struct rdpe_lookup_cb_data)); + rdpe_lookup_cb_data->rdpe_cb_data = rdpe_cb_data; + rdpe_lookup_cb_data->nfsdirent = nfsdirent; + + if (rpc_nfs_lookup_async(nfs->rpc, nfs_opendir3_cb, &data->fh, nfsdirent->name, rdpe_lookup_cb_data) != 0) { + 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) ){ + cookieverf3 cv; + + if (rpc_nfs_readdir_async(nfs->rpc, nfs_opendir2_cb, &data->fh, 0, (char *)&cv, 8192, 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; + } + + 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->next = nfsdir->entries; + nfsdir->entries = nfsdirent; + + cookie = entry->cookie; + entry = entry->nextentry; + } + + 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; + free_nfs_cb_data(data); + return; + } + return; + } + /* steal the dirhandle */ data->continue_data = NULL; nfsdir->current = nfsdir->entries; @@ -1712,9 +2266,9 @@ static int nfs_opendir_continue_internal(struct nfs_context *nfs, struct nfs_cb_ { cookieverf3 cv; - bzero(cv, sizeof(cookieverf3)); - if (rpc_nfs_readdir_async(nfs->rpc, nfs_opendir_cb, &data->fh, 0, (char *)&cv, 20000, data) != 0) { - rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR call for %s", data->path); + memset(cv, 0, sizeof(cookieverf3)); + if (rpc_nfs_readdirplus_async(nfs->rpc, nfs_opendir_cb, &data->fh, 0, (char *)&cv, 8192, data) != 0) { + rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIRPLUS call for %s", data->path); data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); free_nfs_cb_data(data); return -1; @@ -1731,7 +2285,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"); @@ -1770,17 +2324,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); @@ -1805,7 +2361,7 @@ 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; @@ -1846,13 +2402,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); @@ -1879,10 +2437,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); @@ -1915,12 +2475,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); @@ -1947,7 +2509,12 @@ 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.data_len = data->fh.data.data_len; + args.symlink.data.data_val = data->fh.data.data_val; + + if (rpc_nfs_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); @@ -1972,12 +2539,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); @@ -2005,7 +2574,7 @@ static int nfs_chmod_continue_internal(struct nfs_context *nfs, struct nfs_cb_da { SETATTR3args args; - bzero(&args, sizeof(SETATTR3args)); + memset(&args, 0, sizeof(SETATTR3args)); args.object.data.data_len = data->fh.data.data_len; args.object.data.data_val = data->fh.data.data_val; args.new_attributes.mode.set_it = 1; @@ -2043,7 +2612,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; @@ -2070,12 +2639,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); @@ -2109,7 +2680,7 @@ static int nfs_chown_continue_internal(struct nfs_context *nfs, struct nfs_cb_da SETATTR3args args; struct nfs_chown_data *chown_data = data->continue_data; - bzero(&args, sizeof(SETATTR3args)); + memset(&args, 0, sizeof(SETATTR3args)); args.object.data.data_len = data->fh.data.data_len; args.object.data.data_val = data->fh.data.data_val; if (chown_data->uid != (uid_t)-1) { @@ -2176,7 +2747,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; @@ -2206,12 +2777,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); @@ -2240,7 +2813,7 @@ static int nfs_utimes_continue_internal(struct nfs_context *nfs, struct nfs_cb_d SETATTR3args args; struct timeval *utimes_data = data->continue_data; - bzero(&args, sizeof(SETATTR3args)); + memset(&args, 0, sizeof(SETATTR3args)); args.object.data.data_len = data->fh.data.data_len; args.object.data.data_val = data->fh.data.data_val; if (utimes_data != NULL) { @@ -2322,13 +2895,15 @@ 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); @@ -2435,13 +3010,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); @@ -2468,8 +3045,17 @@ 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 sa; + + memset(&sa, 0, sizeof(SYMLINK3args)); + sa.where.dir.data.data_len = data->fh.data.data_len; + sa.where.dir.data.data_val = data->fh.data.data_val; + sa.where.name = symlink_data->newpathobject; + sa.symlink.symlink_attributes.mode.set_it = 1; + sa.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; + sa.symlink.symlink_data = symlink_data->oldpath; - if (rpc_nfs_symlink_async(nfs->rpc, nfs_symlink_cb, &data->fh, symlink_data->newpathobject, symlink_data->oldpath, data) != 0) { + if (rpc_nfs_symlink_async(nfs->rpc, nfs_symlink_cb, &sa, 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); @@ -2488,7 +3074,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) { @@ -2504,7 +3090,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); @@ -2561,13 +3147,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); @@ -2642,7 +3230,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) { @@ -2650,7 +3238,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); @@ -2667,7 +3255,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); @@ -2717,13 +3305,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); @@ -2798,7 +3388,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) { @@ -2813,7 +3403,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); @@ -2834,7 +3424,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; } @@ -2844,7 +3434,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; } @@ -2852,23 +3442,28 @@ 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; + /* Some ZDR libraries can not marshall PDUs bigger than this */ + if (nfs->writemax < 32768) { + return nfs->writemax; + } + return 32768; } 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); + va_end(ap); } @@ -2893,7 +3488,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; @@ -2915,6 +3512,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); @@ -2938,7 +3540,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; @@ -2969,6 +3573,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); @@ -2980,7 +3586,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; @@ -2991,6 +3597,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); @@ -3013,11 +3624,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); @@ -3035,6 +3648,22 @@ 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; } +const char *nfs_get_server(struct nfs_context *nfs) { + return nfs->server; +} + +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; +}