X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=lib%2Flibnfs.c;h=30ad41f31470c3d187f500eaa00f529a917cad84;hb=3e020c15fd041aea4918103c00c9143a0667c79b;hp=41b8a2b35f01ea0b9a15cd0a575b7009476fa09d;hpb=be243cfa9bedd8ac1b350a3af7c48d01800d8679;p=deb_libnfs.git diff --git a/lib/libnfs.c b/lib/libnfs.c index 41b8a2b..30ad41f 100644 --- a/lib/libnfs.c +++ b/lib/libnfs.c @@ -59,6 +59,14 @@ #include #endif +#ifdef MAJOR_IN_MKDEV +#include +#endif + +#ifdef MAJOR_IN_SYSMACROS +#include +#endif + #include #include #include @@ -77,7 +85,7 @@ #include "libnfs-raw-portmap.h" #include "libnfs-private.h" -#define MAX_DIR_CACHE 1024 +#define MAX_DIR_CACHE 128 struct nfsdir { struct nfs_fh3 fh; @@ -771,6 +779,9 @@ static void nfs_mount_8_cb(struct rpc_context *rpc, int status, void *command_da return; } + /* NFS TCP connections we want to autoreconnect after sessions are torn down (due to inactivity or error) */ + rpc_set_autoreconnect(rpc); + 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); @@ -823,9 +834,6 @@ 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); } @@ -1202,6 +1210,15 @@ static int nfs_lookuppath_async(struct nfs_context *nfs, const char *path, nfs_c /* * Async stat() */ +static dev_t specdata3_to_rdev(struct specdata3 *rdev) +{ +#ifdef makedev + return makedev(rdev->specdata1, rdev->specdata2); +#else + return 0; +#endif +} + static void nfs_stat_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) { GETATTR3res *res; @@ -1234,27 +1251,49 @@ static void nfs_stat_1_cb(struct rpc_context *rpc, int status, void *command_dat return; } - st.st_dev = -1; + st.st_dev = res->GETATTR3res_u.resok.obj_attributes.fsid; 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 ; + switch (res->GETATTR3res_u.resok.obj_attributes.type) { + case NF3REG: + st.st_mode |= S_IFREG; + break; + case NF3DIR: + st.st_mode |= S_IFDIR; + break; + case NF3BLK: + st.st_mode |= S_IFBLK; + break; + case NF3CHR: + st.st_mode |= S_IFCHR; + break; + case NF3LNK: + st.st_mode |= S_IFLNK; + break; + case NF3SOCK: + st.st_mode |= S_IFSOCK; + break; + case NF3FIFO: + st.st_mode |= S_IFIFO; + break; } 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_rdev = specdata3_to_rdev(&res->GETATTR3res_u.resok.obj_attributes.rdev); st.st_size = res->GETATTR3res_u.resok.obj_attributes.size; #ifndef WIN32 st.st_blksize = NFS_BLKSIZE; - st.st_blocks = res->GETATTR3res_u.resok.obj_attributes.size / NFS_BLKSIZE; + st.st_blocks = (res->GETATTR3res_u.resok.obj_attributes.used + 512 - 1) / 512; #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; +#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC + st.st_atim.tv_nsec = res->GETATTR3res_u.resok.obj_attributes.atime.nseconds; + st.st_mtim.tv_nsec = res->GETATTR3res_u.resok.obj_attributes.mtime.nseconds; + st.st_ctim.tv_nsec = res->GETATTR3res_u.resok.obj_attributes.ctime.nseconds; +#endif data->cb(0, nfs, &st, data->private_data); free_nfs_cb_data(data); @@ -1318,23 +1357,46 @@ static void nfs_stat64_1_cb(struct rpc_context *rpc, int status, void *command_d return; } - st.nfs_dev = -1; + st.nfs_dev = res->GETATTR3res_u.resok.obj_attributes.fsid; st.nfs_ino = res->GETATTR3res_u.resok.obj_attributes.fileid; st.nfs_mode = res->GETATTR3res_u.resok.obj_attributes.mode; - if (res->GETATTR3res_u.resok.obj_attributes.type == NF3DIR) { - st.nfs_mode |= S_IFDIR ; - } - if (res->GETATTR3res_u.resok.obj_attributes.type == NF3REG) { - st.nfs_mode |= S_IFREG ; + switch (res->GETATTR3res_u.resok.obj_attributes.type) { + case NF3REG: + st.nfs_mode |= S_IFREG; + break; + case NF3DIR: + st.nfs_mode |= S_IFDIR; + break; + case NF3BLK: + st.nfs_mode |= S_IFBLK; + break; + case NF3CHR: + st.nfs_mode |= S_IFCHR; + break; + case NF3LNK: + st.nfs_mode |= S_IFLNK; + break; + case NF3SOCK: + st.nfs_mode |= S_IFSOCK; + break; + case NF3FIFO: + st.nfs_mode |= S_IFIFO; + break; } st.nfs_nlink = res->GETATTR3res_u.resok.obj_attributes.nlink; st.nfs_uid = res->GETATTR3res_u.resok.obj_attributes.uid; st.nfs_gid = res->GETATTR3res_u.resok.obj_attributes.gid; - st.nfs_rdev = 0; + st.nfs_rdev = specdata3_to_rdev(&res->GETATTR3res_u.resok.obj_attributes.rdev); st.nfs_size = res->GETATTR3res_u.resok.obj_attributes.size; + st.nfs_blksize = NFS_BLKSIZE; + st.nfs_blocks = (res->GETATTR3res_u.resok.obj_attributes.used + 512 - 1) / 512; st.nfs_atime = res->GETATTR3res_u.resok.obj_attributes.atime.seconds; st.nfs_mtime = res->GETATTR3res_u.resok.obj_attributes.mtime.seconds; st.nfs_ctime = res->GETATTR3res_u.resok.obj_attributes.ctime.seconds; + st.nfs_atime_nsec = res->GETATTR3res_u.resok.obj_attributes.atime.nseconds; + st.nfs_mtime_nsec = res->GETATTR3res_u.resok.obj_attributes.mtime.nseconds; + st.nfs_ctime_nsec = res->GETATTR3res_u.resok.obj_attributes.ctime.nseconds; + st.nfs_used = res->GETATTR3res_u.resok.obj_attributes.used; data->cb(0, nfs, &st, data->private_data); free_nfs_cb_data(data); @@ -2180,6 +2242,36 @@ int nfs_fstat_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, voi return 0; } +/* + * Async fstat64() + */ +int nfs_fstat64_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; + } + memset(data, 0, sizeof(struct nfs_cb_data)); + data->nfs = nfs; + data->cb = cb; + data->private_data = private_data; + + memset(&args, 0, sizeof(GETATTR3args)); + args.object = nfsfh->fh; + + if (rpc_nfs3_getattr_async(nfs->rpc, nfs_stat64_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); + return -1; + } + return 0; +} + /* @@ -2527,13 +2619,28 @@ int nfs_rmdir_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void * /* * Async creat() */ +struct create_cb_data { + char *path; + int flags; + int mode; +}; + +static void free_create_cb_data(void *ptr) +{ + struct create_cb_data *data = ptr; + + free(data->path); + free(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; struct nfs_context *nfs = data->nfs; struct nfsfh *nfsfh; - char *str = data->continue_data; + struct create_cb_data *cb_data = data->continue_data; + char *str = cb_data->path; assert(rpc->magic == RPC_CONTEXT_MAGIC); @@ -2566,6 +2673,13 @@ static void nfs_create_2_cb(struct rpc_context *rpc, int status, void *command_d } memset(nfsfh, 0, sizeof(struct nfsfh)); + if (cb_data->flags & O_SYNC) { + nfsfh->is_sync = 1; + } + if (cb_data->flags & O_APPEND) { + nfsfh->is_append = 1; + } + /* 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); @@ -2577,12 +2691,13 @@ static void nfs_create_2_cb(struct rpc_context *rpc, int status, void *command_d -static void nfs_creat_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) +static void nfs_create_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; + struct create_cb_data *cb_data = data->continue_data; + char *str = cb_data->path; LOOKUP3args args; assert(rpc->magic == RPC_CONTEXT_MAGIC); @@ -2620,9 +2735,10 @@ static void nfs_creat_1_cb(struct rpc_context *rpc, int status, void *command_da return; } -static int nfs_creat_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data) +static int nfs_create_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data) { - char *str = data->continue_data; + struct create_cb_data *cb_data = data->continue_data; + char *str = cb_data->path; CREATE3args args; str = &str[strlen(str) + 1]; @@ -2630,11 +2746,11 @@ static int nfs_creat_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_ memset(&args, 0, sizeof(CREATE3args)); args.where.dir = data->fh; args.where.name = str; - args.how.mode = UNCHECKED; + args.how.mode = (cb_data->flags & O_EXCL) ? GUARDED : 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; + args.how.createhow3_u.obj_attributes.mode.set_mode3_u.mode = cb_data->mode; - if (rpc_nfs3_create_async(nfs->rpc, nfs_creat_1_cb, &args, data) != 0) { + if (rpc_nfs3_create_async(nfs->rpc, nfs_create_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); @@ -2643,27 +2759,37 @@ static int nfs_creat_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_ return 0; } -int nfs_creat_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data) +int nfs_create_async(struct nfs_context *nfs, const char *path, int flags, int mode, nfs_cb cb, void *private_data) { - char *new_path; + struct create_cb_data *cb_data; char *ptr; - new_path = strdup(path); - if (new_path == NULL) { + cb_data = malloc(sizeof(struct create_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(new_path, '/'); + ptr = strrchr(cb_data->path, '/'); if (ptr == NULL) { rpc_set_error(nfs->rpc, "Invalid path %s", path); - free(new_path); + free_create_cb_data(cb_data); return -1; } *ptr = 0; + cb_data->flags = flags; + cb_data->mode = mode; + /* 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) { + if (nfs_lookuppath_async(nfs, cb_data->path, cb, private_data, nfs_create_continue_internal, cb_data, free_create_cb_data, 0) != 0) { rpc_set_error(nfs->rpc, "Out of memory: failed to start parsing the path components"); return -1; } @@ -2671,6 +2797,11 @@ int nfs_creat_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb return 0; } +int nfs_creat_async(struct nfs_context *nfs, const char *path, int mode, nfs_cb cb, void *private_data) +{ + return nfs_create_async(nfs, path, 0, mode, cb, private_data); +} + @@ -2952,13 +3083,21 @@ static void nfs_opendir3_cb(struct rpc_context *rpc, int status, void *command_d nfsdirent->atime.tv_sec = attributes->atime.seconds; nfsdirent->atime.tv_usec = attributes->atime.nseconds/1000; + nfsdirent->atime_nsec = attributes->atime.nseconds; nfsdirent->mtime.tv_sec = attributes->mtime.seconds; nfsdirent->mtime.tv_usec = attributes->mtime.nseconds/1000; + nfsdirent->mtime_nsec = attributes->mtime.nseconds; nfsdirent->ctime.tv_sec = attributes->ctime.seconds; nfsdirent->ctime.tv_usec = attributes->ctime.nseconds/1000; + nfsdirent->ctime_nsec = attributes->ctime.nseconds; nfsdirent->uid = attributes->uid; nfsdirent->gid = attributes->gid; nfsdirent->nlink = attributes->nlink; + nfsdirent->dev = attributes->fsid; + nfsdirent->rdev = specdata3_to_rdev(&attributes->rdev); + nfsdirent->blksize = NFS_BLKSIZE; + nfsdirent->blocks = (attributes->used + 512 - 1) / 512; + nfsdirent->used = attributes->used; } } @@ -3193,13 +3332,21 @@ static void nfs_opendir_cb(struct rpc_context *rpc, int status, void *command_da 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->atime_nsec = entry->name_attributes.post_op_attr_u.attributes.atime.nseconds; 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->mtime_nsec = entry->name_attributes.post_op_attr_u.attributes.mtime.nseconds; 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->ctime_nsec = entry->name_attributes.post_op_attr_u.attributes.ctime.nseconds; nfsdirent->uid = entry->name_attributes.post_op_attr_u.attributes.uid; nfsdirent->gid = entry->name_attributes.post_op_attr_u.attributes.gid; nfsdirent->nlink = entry->name_attributes.post_op_attr_u.attributes.nlink; + nfsdirent->dev = entry->name_attributes.post_op_attr_u.attributes.fsid; + nfsdirent->rdev = specdata3_to_rdev(&entry->name_attributes.post_op_attr_u.attributes.rdev); + nfsdirent->blksize = NFS_BLKSIZE; + nfsdirent->blocks = (entry->name_attributes.post_op_attr_u.attributes.used + 512 - 1) / 512; + nfsdirent->used = entry->name_attributes.post_op_attr_u.attributes.used; } nfsdirent->next = nfsdir->entries;