libnfs: Set as much stat information as possible
authorRoss Lagerwall <rosslagerwall@gmail.com>
Sun, 20 Jul 2014 20:39:06 +0000 (21:39 +0100)
committerRoss Lagerwall <rosslagerwall@gmail.com>
Sun, 20 Jul 2014 21:06:34 +0000 (22:06 +0100)
Set as much stat information as possible for stat, stat64, fstat and
readdir.

Fill in dev to the given fsid.
Fill in rdev to the given major and minor numbers.
Set the file type bits in the mode from the type returned by the server.
Set the number of blocks used based on the number of bytes used in
blocks of size 512 (which is what stat(2) uses), rounded up.
Fill in the nanosecond timestamps.

Signed-off-by: Ross Lagerwall <rosslagerwall@gmail.com>
configure.ac
include/nfsc/libnfs.h
lib/libnfs.c

index b84a8c52db40c017202669beee7ea43beecbf46a..c4fe184a3c00a43de75b7bceeab29ea88efafc18 100644 (file)
@@ -153,6 +153,11 @@ AC_CHECK_MEMBER([struct sockaddr_storage.ss_family],
 #include <sys/socket.h>
 ])
 
+AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec])
+
+# check where makedev is defined
+AC_HEADER_MAJOR
+
 #output
 AC_CONFIG_FILES([Makefile]
                 [doc/Makefile]
index ff0d4e4ad4b4bcdfae7f38a9c502e0389faa7e3a..5d5d54264d94be7d9f84f646e9b3491264a8fc56 100644 (file)
@@ -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;
 };
 
 /*
@@ -813,6 +817,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
index 459ebd7bf80e3e18e73dd24087a5653051dd6b81..e9a55262320c0c8b9f227da7d5b6d71ec084d762 100644 (file)
 #include <strings.h>
 #endif
 
+#ifdef MAJOR_IN_MKDEV
+#include <sys/mkdev.h>
+#endif
+
+#ifdef MAJOR_IN_SYSMACROS
+#include <sys/sysmacros.h>
+#endif
+
 #include <stdio.h>
 #include <stdarg.h>
 #include <stdlib.h>
@@ -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);
@@ -2991,13 +3053,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;
                }
        }
 
@@ -3232,13 +3302,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;