Merge pull request #90 from rosslagerwall/stat-improvements
authorRonnie Sahlberg <ronniesahlberg@gmail.com>
Thu, 24 Jul 2014 00:30:13 +0000 (17:30 -0700)
committerRonnie Sahlberg <ronniesahlberg@gmail.com>
Thu, 24 Jul 2014 00:30:13 +0000 (17:30 -0700)
Stat improvements

1  2 
include/nfsc/libnfs.h
lib/libnfs.c

diff --combined include/nfsc/libnfs.h
index d3ce1aa4801366545cdd376c4742cc1c0e3f43d5,df102d92985fd377976429827408f6d9eb732bca..2149b8a8fa8ebe1fffe4cc7700569aae7f8f1c93
@@@ -270,6 -270,10 +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 +312,7 @@@ EXTERN int nfs_stat64(struct nfs_contex
   * -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 +326,35 @@@ EXTERN int nfs_fstat(struct nfs_contex
  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);
  
  
  /*
   * Async open(<filename>)
   *
   * mode is a combination of the flags :
 - * O_RDOLNY, O_WRONLY, O_RDWR , O_SYNC, O_APPEND
 + * O_RDOLNY, O_WRONLY, O_RDWR , O_SYNC, O_APPEND, O_TRUNC
   *
   * Function returns
   *  0 : The operation was initiated. Once the operation finishes, the callback will be invoked.
   * O_RDONLY
   * O_WRONLY
   * O_RDWR
 + * O_SYNC
   * O_TRUNC (Only valid with O_RDWR or O_WRONLY. Ignored otherwise.)
   *
   * When the callback is invoked, status indicates the result:
@@@ -690,7 -723,6 +724,7 @@@ EXTERN int nfs_creat(struct nfs_contex
   * O_APPEND
   * O_SYNC
   * O_EXCL
 + * O_TRUNC
   *
   * Function returns
   *  0 : The operation was initiated. Once the operation finishes, the callback will be invoked.
@@@ -815,6 -847,14 +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 --combined lib/libnfs.c
index a134a2c5a1a2a6c1f8d331fd0e43ca1d0e0b759c,30ad41f31470c3d187f500eaa00f529a917cad84..c25ae2d66dbd85c9651459dd1c2a171089e80c7e
  #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>
@@@ -696,16 -704,6 +704,16 @@@ static void free_nfs_cb_data(struct nfs
        free(data);
  }
  
 +static void free_nfsfh(struct nfsfh *nfsfh)
 +{
 +      if (nfsfh->fh.data.data_val != NULL) {
 +              free(nfsfh->fh.data.data_val);
 +              nfsfh->fh.data.data_val = NULL;
 +      }
 +      free(nfsfh->ra.buf);
 +      free(nfsfh);
 +}
 +
  
  static void nfs_mount_10_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
  {
@@@ -1212,6 -1210,15 +1220,15 @@@ static int nfs_lookuppath_async(struct 
  /*
   * 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;
                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 -1357,46 +1367,46 @@@ static void nfs_stat64_1_cb(struct rpc_
                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);
@@@ -2145,7 -2197,13 +2207,7 @@@ int nfs_write_async(struct nfs_context 
  
  int nfs_close_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, void *private_data)
  {
 -      if (nfsfh->fh.data.data_val != NULL){
 -              free(nfsfh->fh.data.data_val);
 -              nfsfh->fh.data.data_val = NULL;
 -      }
 -      free(nfsfh->ra.buf);
 -      free(nfsfh);
 -
 +      free_nfsfh(nfsfh);
        cb(0, nfs, NULL, private_data);
        return 0;
  };
@@@ -2184,6 -2242,36 +2246,36 @@@ int nfs_fstat_async(struct nfs_context 
        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;
+ }
  
  
  /*
@@@ -2545,41 -2633,6 +2637,41 @@@ static void free_create_cb_data(void *p
        free(data);
  }
  
 +static void nfs_create_trunc_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;
 +      struct nfsfh *nfsfh;
 +      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);
 +              free_nfsfh(nfsfh);
 +              return;
 +      }
 +      if (status == RPC_STATUS_CANCEL) {
 +              data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
 +              free_nfs_cb_data(data);
 +              free_nfsfh(nfsfh);
 +              return;
 +      }
 +
 +      res = command_data;
 +      if (res->status != NFS3_OK) {
 +              rpc_set_error(nfs->rpc, "NFS: Setattr failed with %s(%d)", 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);
 +              free_nfsfh(nfsfh);
 +              return;
 +      }
 +
 +      data->cb(0, nfs, data->nfsfh, data->private_data);
 +      free_nfs_cb_data(data);
 +}
 +
  static void nfs_create_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
  {
        LOOKUP3res *res;
        /* 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);
 +      if (nfsfh->fh.data.data_val == NULL) {
 +              rpc_set_error(nfs->rpc, "Out of memory: Failed to allocate fh structure");
 +              data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
 +              free_nfs_cb_data(data);
 +              free(nfsfh);
 +              return -1;
 +      }
        memcpy(nfsfh->fh.data.data_val, res->LOOKUP3res_u.resok.object.data.data_val, nfsfh->fh.data.data_len);
  
 +      /* Try to truncate it if we were requested to */
 +      if (cb_data->flags & O_TRUNC) {
 +              SETATTR3args args;
 +
 +              data->nfsfh = nfsfh;
 +
 +              memset(&args, 0, sizeof(SETATTR3args));
 +              args.object = nfsfh->fh;
 +              args.new_attributes.size.set_it = 1;
 +              args.new_attributes.size.set_size3_u.size = 0;
 +
 +              if (rpc_nfs3_setattr_async(nfs->rpc, nfs_create_trunc_cb,
 +                              &args, data) != 0) {
 +                      rpc_set_error(nfs->rpc, "RPC error: Failed to send "
 +                              "SETATTR call for %s", data->path);
 +                      data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc),
 +                              data->private_data);
 +                      free_nfs_cb_data(data);
 +                      free_nfsfh(nfsfh);
 +                      return;
 +              }
 +              return;
 +      }
 +
        data->cb(0, nfs, nfsfh, data->private_data);
        free_nfs_cb_data(data);
  }
@@@ -3061,13 -3083,21 +3153,21 @@@ static void nfs_opendir3_cb(struct rpc_
  
                        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 -3332,21 +3402,21 @@@ static void nfs_opendir_cb(struct rpc_c
  
                        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;