X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=lib%2Flibnfs.c;h=29a276fb5ee0b1d6f3ccfa06b696b428589efa92;hb=6a14f02fb2e18e66bbfd48ff3c5a7a5b677b51ed;hp=80a7394d6d239c999ac70ee3e626b6d4908a6281;hpb=a671a46510c03fcf06e7a4c5812aa4a20fdc850d;p=deb_libnfs.git diff --git a/lib/libnfs.c b/lib/libnfs.c index 80a7394..29a276f 100644 --- a/lib/libnfs.c +++ b/lib/libnfs.c @@ -17,19 +17,25 @@ /* * High level api to nfs filesystems */ +#ifdef WIN32 +#include "win32_compat.h" +#define DllExport +#else +#include +#include +#include +#include +#endif/*WIN32*/ #define _GNU_SOURCE + #include #include #include #include -#include #include #include #include -#include -#include -#include #include #include "libnfs.h" #include "libnfs-raw.h" @@ -115,6 +121,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); @@ -483,7 +494,7 @@ 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) { @@ -604,7 +615,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; @@ -671,8 +682,10 @@ static void nfs_stat_1_cb(struct rpc_context *rpc _U_, int status, void *command st.st_gid = res->GETATTR3res_u.resok.obj_attributes.gid; st.st_rdev = 0; st.st_size = res->GETATTR3res_u.resok.obj_attributes.size; +#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; @@ -767,7 +780,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; @@ -921,7 +934,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; @@ -967,7 +980,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; @@ -1029,6 +1042,65 @@ static void nfs_pwrite_cb(struct rpc_context *rpc _U_, int status, void *command free_nfs_cb_data(data); } +static void nfs_pwrite_mcb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) +{ + struct nfs_mcb_data *mdata = private_data; + struct nfs_cb_data *data = mdata->data; + struct nfs_context *nfs = data->nfs; + WRITE3res *res; + + data->num_calls--; + + if (status == RPC_STATUS_ERROR) { + /* flag the failure but do not invoke callback until we have received all responses */ + data->error = 1; + } + if (status == RPC_STATUS_CANCEL) { + /* flag the cancellation but do not invoke callback until we have received all responses */ + data->cancel = 1; + } + + 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, off_t offset, size_t count, char *buf, nfs_cb cb, void *private_data) { struct nfs_cb_data *data; @@ -1038,19 +1110,61 @@ 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) { + size_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; } @@ -1097,7 +1211,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; @@ -1154,7 +1268,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; @@ -1213,12 +1327,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; @@ -1471,7 +1585,7 @@ static void nfs_create_2_cb(struct rpc_context *rpc _U_, int status, void *comma free_nfs_cb_data(data); return; } - bzero(nfsfh, sizeof(struct nfsfh)); + memset(nfsfh, 0, sizeof(struct nfsfh)); /* steal the filehandle */ nfsfh->fh.data.data_len = data->fh.data.data_len; @@ -1651,13 +1765,13 @@ int nfs_unlink_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void */ static void nfs_opendir_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) { - READDIR3res *res; + READDIRPLUS3res *res; struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; - struct nfsdir *nfsdir = data->continue_data;; - struct entry3 *entry; + struct nfsdir *nfsdir = data->continue_data; + struct entryplus3 *entry; uint64_t cookie; - + if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); nfs_free_nfsdir(nfsdir); @@ -1683,7 +1797,7 @@ static void nfs_opendir_cb(struct rpc_context *rpc _U_, int status, void *comman return; } - entry =res->READDIR3res_u.resok.reply.entries; + entry =res->READDIRPLUS3res_u.resok.reply.entries; while (entry != NULL) { struct nfsdirent *nfsdirent; @@ -1695,7 +1809,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); @@ -1705,6 +1819,19 @@ static void nfs_opendir_cb(struct rpc_context *rpc _U_, int status, void *comman return; } nfsdirent->inode = entry->fileid; + if (entry->name_attributes.attributes_follow) { + nfsdirent->type = entry->name_attributes.post_op_attr_u.attributes.type; + nfsdirent->mode = entry->name_attributes.post_op_attr_u.attributes.mode; + nfsdirent->size = entry->name_attributes.post_op_attr_u.attributes.size; + + nfsdirent->atime.tv_sec = entry->name_attributes.post_op_attr_u.attributes.atime.seconds; + nfsdirent->atime.tv_usec = entry->name_attributes.post_op_attr_u.attributes.atime.nseconds/1000; + nfsdirent->mtime.tv_sec = entry->name_attributes.post_op_attr_u.attributes.mtime.seconds; + nfsdirent->mtime.tv_usec = entry->name_attributes.post_op_attr_u.attributes.mtime.nseconds/1000; + nfsdirent->ctime.tv_sec = entry->name_attributes.post_op_attr_u.attributes.ctime.seconds; + nfsdirent->ctime.tv_usec = entry->name_attributes.post_op_attr_u.attributes.ctime.nseconds/1000; + } + nfsdirent->next = nfsdir->entries; nfsdir->entries = nfsdirent; @@ -1712,9 +1839,9 @@ static void nfs_opendir_cb(struct rpc_context *rpc _U_, int status, void *comman entry = entry->nextentry; } - if (res->READDIR3res_u.resok.reply.eof == 0) { - if (rpc_nfs_readdir_async(nfs->rpc, nfs_opendir_cb, &data->fh, cookie, res->READDIR3res_u.resok.cookieverf, 20000, data) != 0) { - rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR call for %s", data->path); + if (res->READDIRPLUS3res_u.resok.reply.eof == 0) { + if (rpc_nfs_readdirplus_async(nfs->rpc, nfs_opendir_cb, &data->fh, cookie, res->READDIRPLUS3res_u.resok.cookieverf, 8192, data) != 0) { + rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIRPLUS call for %s", data->path); data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); nfs_free_nfsdir(nfsdir); data->continue_data = NULL; @@ -1736,9 +1863,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; @@ -1755,7 +1882,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"); @@ -2029,7 +2156,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; @@ -2067,7 +2194,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; @@ -2133,7 +2260,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) { @@ -2200,7 +2327,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; @@ -2264,7 +2391,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) { @@ -2512,7 +2639,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) { @@ -2666,7 +2793,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) { @@ -2822,7 +2949,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) { @@ -2878,7 +3005,11 @@ size_t nfs_get_readmax(struct nfs_context *nfs) */ size_t nfs_get_writemax(struct nfs_context *nfs) { - return nfs->writemax; + /* Some XDR 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, ...) @@ -2887,12 +3018,13 @@ void nfs_set_error(struct nfs_context *nfs, char *error_string, ...) char *str = NULL; va_start(ap, error_string); - vasprintf(&str, error_string, 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); + va_end(ap); } @@ -3041,7 +3173,7 @@ int mount_getexports_async(struct rpc_context *rpc, const char *server, rpc_cb c 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); @@ -3069,3 +3201,4 @@ const char *nfs_get_server(struct nfs_context *nfs) { const char *nfs_get_export(struct nfs_context *nfs) { return nfs->export; } +