From: Ronnie Sahlberg Date: Thu, 24 Jul 2014 00:30:13 +0000 (-0700) Subject: Merge pull request #90 from rosslagerwall/stat-improvements X-Git-Tag: upstream/1.9.6^2~16 X-Git-Url: https://git.piment-noir.org/?p=deb_libnfs.git;a=commitdiff_plain;h=42f916635d2d799c1d3c923a377f40f100c0633c;hp=0672f75b57b9e0fbf56079944fde5b2fc9de27be Merge pull request #90 from rosslagerwall/stat-improvements Stat improvements --- diff --git a/configure.ac b/configure.ac index b84a8c5..c4fe184 100644 --- a/configure.ac +++ b/configure.ac @@ -153,6 +153,11 @@ AC_CHECK_MEMBER([struct sockaddr_storage.ss_family], #include ]) +AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec]) + +# check where makedev is defined +AC_HEADER_MAJOR + #output AC_CONFIG_FILES([Makefile] [doc/Makefile] diff --git a/include/nfsc/libnfs.h b/include/nfsc/libnfs.h index d3ce1aa..2149b8a 100644 --- a/include/nfsc/libnfs.h +++ b/include/nfsc/libnfs.h @@ -270,6 +270,10 @@ struct nfs_stat_64 { uint64_t nfs_atime; uint64_t nfs_mtime; uint64_t nfs_ctime; + uint64_t nfs_atime_nsec; + uint64_t nfs_mtime_nsec; + uint64_t nfs_ctime_nsec; + uint64_t nfs_used; }; /* @@ -308,6 +312,7 @@ EXTERN int nfs_stat64(struct nfs_context *nfs, const char *path, struct nfs_stat * -errno : An error occured. * data is the error string. */ +/* This function is deprecated. Use nfs_fstat64_async() instead */ EXTERN int nfs_fstat_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data); /* * Sync fstat(nfsfh *) @@ -321,6 +326,35 @@ EXTERN int nfs_fstat(struct nfs_context *nfs, struct nfsfh *nfsfh, struct __stat EXTERN int nfs_fstat(struct nfs_context *nfs, struct nfsfh *nfsfh, struct stat *st); #endif +/* nfs_fstat64 + * 64 bit version of fstat. All fields are always 64bit. + * Use these functions instead of nfs_fstat[_async](), especially if you + * have weird stat structures. + */ +/* + * FSTAT() + */ +/* + * Async fstat(nfsfh *) + * Function returns + * 0 : The operation was initiated. Once the operation finishes, the callback will be invoked. + * <0 : An error occured when trying to set up the operation. The callback will not be invoked. + * + * When the callback is invoked, status indicates the result: + * 0 : Success. + * data is struct stat * + * -errno : An error occured. + * data is the error string. + */ +EXTERN int nfs_fstat64_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data); +/* + * Sync fstat(nfsfh *) + * Function returns + * 0 : The operation was successfull. + * -errno : The command failed. + */ +EXTERN int nfs_fstat64(struct nfs_context *nfs, struct nfsfh *nfsfh, struct nfs_stat_64 *st); + /* @@ -815,6 +849,14 @@ struct nfsdirent { uint32_t uid; uint32_t gid; uint32_t nlink; + uint64_t dev; + uint64_t rdev; + uint64_t blksize; + uint64_t blocks; + uint64_t used; + uint32_t atime_nsec; + uint32_t mtime_nsec; + uint32_t ctime_nsec; }; /* * nfs_readdir() never blocks, so no special sync/async versions are available diff --git a/lib/libnfs-sync.c b/lib/libnfs-sync.c index 39c68c6..9d351f7 100644 --- a/lib/libnfs-sync.c +++ b/lib/libnfs-sync.c @@ -453,6 +453,26 @@ int nfs_fstat(struct nfs_context *nfs, struct nfsfh *nfsfh, struct stat *st) return cb_data.status; } +/* + * fstat64() + */ +int nfs_fstat64(struct nfs_context *nfs, struct nfsfh *nfsfh, struct nfs_stat_64 *st) +{ + struct sync_cb_data cb_data; + + cb_data.is_finished = 0; + cb_data.return_data = st; + + if (nfs_fstat64_async(nfs, nfsfh, stat64_cb, &cb_data) != 0) { + nfs_set_error(nfs, "nfs_fstat64_async failed"); + return -1; + } + + wait_for_nfs_reply(nfs, &cb_data); + + return cb_data.status; +} + /* * pwrite() diff --git a/lib/libnfs.c b/lib/libnfs.c index a134a2c..c25ae2d 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 @@ -1212,6 +1220,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; @@ -1244,27 +1261,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); @@ -1328,23 +1367,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); @@ -2184,6 +2246,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; +} + /* @@ -3061,13 +3153,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; } } @@ -3302,13 +3402,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;