]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
debugfs: add support to properly set and display extended timestamps
authorTheodore Ts'o <tytso@mit.edu>
Mon, 9 Dec 2013 18:55:23 +0000 (13:55 -0500)
committerTheodore Ts'o <tytso@mit.edu>
Mon, 30 Nov 2015 16:42:00 +0000 (11:42 -0500)
This code is partially derived from patches from David Turner to allow
debugfs to properly support extended timestamps.

Cc: David Turner <novalis@novalis.org>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
debugfs/debugfs.c
debugfs/debugfs.h
debugfs/lsdel.c
debugfs/set_fields.c
debugfs/util.c
lib/ext2fs/ext2_fs.h

index 175fb90f306535d4760e93bd83c2454a86465f10..735117eb3d3946b405b2862dc61b1dcb74ec5bdc 100644 (file)
@@ -866,27 +866,37 @@ void internal_dump_inode(FILE *out, const char *prefix,
        if (is_large_inode && large_inode->i_extra_isize >= 24) {
                fprintf(out, "%s ctime: 0x%08x:%08x -- %s", prefix,
                        inode->i_ctime, large_inode->i_ctime_extra,
-                       time_to_string(inode->i_ctime));
+                       inode_time_to_string(inode->i_ctime,
+                                            large_inode->i_ctime_extra));
                fprintf(out, "%s atime: 0x%08x:%08x -- %s", prefix,
                        inode->i_atime, large_inode->i_atime_extra,
-                       time_to_string(inode->i_atime));
+                       inode_time_to_string(inode->i_atime,
+                                            large_inode->i_atime_extra));
                fprintf(out, "%s mtime: 0x%08x:%08x -- %s", prefix,
                        inode->i_mtime, large_inode->i_mtime_extra,
-                       time_to_string(inode->i_mtime));
+                       inode_time_to_string(inode->i_mtime,
+                                            large_inode->i_mtime_extra));
                fprintf(out, "%scrtime: 0x%08x:%08x -- %s", prefix,
                        large_inode->i_crtime, large_inode->i_crtime_extra,
-                       time_to_string(large_inode->i_crtime));
+                       inode_time_to_string(large_inode->i_crtime,
+                                            large_inode->i_crtime_extra));
+               if (inode->i_dtime)
+                       fprintf(out, "%scrtime: 0x%08x:(%08x) -- %s", prefix,
+                               large_inode->i_dtime, large_inode->i_ctime_extra,
+                               inode_time_to_string(inode->i_dtime,
+                                                    large_inode->i_ctime_extra));
        } else {
                fprintf(out, "%sctime: 0x%08x -- %s", prefix, inode->i_ctime,
-                       time_to_string(inode->i_ctime));
+                       time_to_string((__s32) inode->i_ctime));
                fprintf(out, "%satime: 0x%08x -- %s", prefix, inode->i_atime,
-                       time_to_string(inode->i_atime));
+                       time_to_string((__s32) inode->i_atime));
                fprintf(out, "%smtime: 0x%08x -- %s", prefix, inode->i_mtime,
-                       time_to_string(inode->i_mtime));
+                       time_to_string((__s32) inode->i_mtime));
+               if (inode->i_dtime)
+                       fprintf(out, "%sdtime: 0x%08x -- %s", prefix,
+                               inode->i_dtime,
+                               time_to_string((__s32) inode->i_dtime));
        }
-       if (inode->i_dtime)
-         fprintf(out, "%sdtime: 0x%08x -- %s", prefix, inode->i_dtime,
-                 time_to_string(inode->i_dtime));
        if (EXT2_INODE_SIZE(current_fs->super) > EXT2_GOOD_OLD_INODE_SIZE)
                internal_dump_inode_extra(out, prefix, inode_num,
                                          (struct ext2_inode_large *) inode);
@@ -2074,14 +2084,14 @@ err:
 #ifndef READ_ONLY
 void do_set_current_time(int argc, char *argv[])
 {
-       time_t now;
+       __s64 now;
 
        if (common_args_process(argc, argv, 2, 2, argv[0],
                                "<time>", 0))
                return;
 
        now = string_to_time(argv[1]);
-       if (now == ((time_t) -1)) {
+       if (now == -1) {
                com_err(argv[0], 0, "Couldn't parse argument as a time: %s\n",
                        argv[1]);
                return;
index fa2aacb1743e44a6cb0246507ab4fa1aa0289a25..4f25850d4ccfd05058da5fe3b145d211e932c611 100644 (file)
@@ -36,8 +36,9 @@ extern int check_fs_not_open(char *name);
 extern int check_fs_read_write(char *name);
 extern int check_fs_bitmaps(char *name);
 extern ext2_ino_t string_to_inode(char *str);
-extern char *time_to_string(__u32);
-extern time_t string_to_time(const char *);
+extern char *inode_time_to_string(__u32 xtime, __u32 xtime_extra);
+extern char *time_to_string(__s64);
+extern __s64 string_to_time(const char *);
 extern unsigned long parse_ulong(const char *str, const char *cmd,
                                 const char *descr, int *err);
 extern unsigned long long parse_ulonglong(const char *str, const char *cmd,
@@ -188,7 +189,7 @@ extern void do_list_quota(int argc, char *argv[]);
 extern void do_get_quota(int argc, char *argv[]);
 
 /* util.c */
-extern time_t string_to_time(const char *arg);
+extern __s64 string_to_time(const char *arg);
 errcode_t read_list(char *str, blk64_t **list, size_t *len);
 
 /* xattrs.c */
index a7c30b3eff10cca2a772b00e35e262a6930c978c..7d5e7d856cef124fc6bef68baf55af7b63be69d3 100644 (file)
@@ -170,7 +170,7 @@ void do_lsdel(int argc, char **argv)
                        delarray[num_delarray].mode = inode.i_mode;
                        delarray[num_delarray].uid = inode_uid(inode);
                        delarray[num_delarray].size = EXT2_I_SIZE(&inode);
-                       delarray[num_delarray].dtime = inode.i_dtime;
+                       delarray[num_delarray].dtime = (__s32) inode.i_dtime;
                        delarray[num_delarray].num_blocks = lsd.num_blocks;
                        delarray[num_delarray].free_blocks = lsd.free_blocks;
                        num_delarray++;
index b14fec991392a7281f4c2ded8bf3e03afdbaf9a0..ec2340d5793c80302c1e6d25f631b789264b9604 100644 (file)
@@ -181,10 +181,14 @@ static struct field_set_info inode_fields[] = {
        { "uid", &set_inode.i_uid, &set_inode.osd2.linux2.l_i_uid_high,
                2, parse_uint },
        { "size", &set_inode.i_size, &set_inode.i_size_high, 4, parse_uint },
-       { "atime", &set_inode.i_atime, NULL, 4, parse_time },
-       { "ctime", &set_inode.i_ctime, NULL, 4, parse_time },
-       { "mtime", &set_inode.i_mtime, NULL, 4, parse_time },
-       { "dtime", &set_inode.i_dtime, NULL, 4, parse_time },
+       { "atime", &set_inode.i_atime, &set_inode.i_atime_extra,
+               4, parse_time },
+       { "ctime", &set_inode.i_ctime, &set_inode.i_ctime_extra,
+               4, parse_time },
+       { "mtime", &set_inode.i_mtime, &set_inode.i_mtime_extra,
+               4, parse_time },
+       { "dtime", &set_inode.i_dtime, NULL,
+               4, parse_time },
        { "gid", &set_inode.i_gid, &set_inode.osd2.linux2.l_i_gid_high,
                2, parse_uint },
        { "links_count", &set_inode.i_links_count, NULL, 2, parse_uint },
@@ -216,14 +220,15 @@ static struct field_set_info inode_fields[] = {
        { "extra_isize", &set_inode.i_extra_isize, NULL,
                2, parse_uint },
        { "ctime_extra", &set_inode.i_ctime_extra, NULL,
-               4, parse_uint },
+               4, parse_uint, FLAG_ALIAS },
        { "mtime_extra", &set_inode.i_mtime_extra, NULL,
-               4, parse_uint },
+               4, parse_uint, FLAG_ALIAS  },
        { "atime_extra", &set_inode.i_atime_extra, NULL,
-               4, parse_uint },
-       { "crtime", &set_inode.i_crtime, NULL, 4, parse_uint },
+               4, parse_uint, FLAG_ALIAS },
+       { "crtime", &set_inode.i_crtime, &set_inode.i_crtime_extra,
+               4, parse_time },
        { "crtime_extra", &set_inode.i_crtime_extra, NULL,
-               4, parse_uint },
+               4, parse_uint, FLAG_ALIAS },
        { "bmap", NULL, NULL, 4, parse_bmap, FLAG_ARRAY },
        { 0, 0, 0, 0 }
 };
@@ -555,21 +560,31 @@ static errcode_t parse_string(struct field_set_info *info,
 }
 
 static errcode_t parse_time(struct field_set_info *info,
-                           char *field EXT2FS_ATTR((unused)), char *arg)
+                           char *field, char *arg)
 {
-       time_t          t;
-       __u32           *ptr32;
+       __s64           t;
+       __u32           t_low, t_high;
+       __u32           *ptr_low, *ptr_high;
+       int             suffix = check_suffix(field);
+
+       if (check_suffix(field))
+               return parse_uint(info, field, arg);
 
-       ptr32 = (__u32 *) info->ptr;
+       ptr_low  = (__u32 *) info->ptr;
+       ptr_high = (__u32 *) info->ptr2;
 
        t = string_to_time(arg);
 
-       if (t == ((time_t) -1)) {
+       if (t == -1) {
                fprintf(stderr, "Couldn't parse '%s' for field %s.\n",
                        arg, info->name);
                return EINVAL;
        }
-       *ptr32 = t;
+       t_low = (__u32) t;
+       t_high = ((t - (__s32)t) >> 32) & EXT4_EPOCH_MASK;
+       *ptr_low = t_low;
+       if (ptr_high)
+               *ptr_high = (*ptr_high & ~EXT4_EPOCH_MASK) | t_high;
        return 0;
 }
 
index 56ea695c32c166d9060ebe099479ce46ff960ece..770e7e10c23c9fff3a82b8945c462cd5634bcf83 100644 (file)
@@ -186,11 +186,19 @@ int check_fs_bitmaps(char *name)
        return 0;
 }
 
+char *inode_time_to_string(__u32 xtime, __u32 xtime_extra)
+{
+       __s64 t = (__s32) xtime;
+
+       t += (__s64) (xtime_extra & EXT4_EPOCH_MASK) << 32;
+       return time_to_string(t);
+}
+
 /*
- * This function takes a __u32 time value and converts it to a string,
+ * This function takes a __s64 time value and converts it to a string,
  * using ctime
  */
-char *time_to_string(__u32 cl)
+char *time_to_string(__s64 cl)
 {
        static int      do_gmt = -1;
        time_t          t = (time_t) cl;
@@ -211,10 +219,10 @@ char *time_to_string(__u32 cl)
  * Parse a string as a time.  Return ((time_t)-1) if the string
  * doesn't appear to be a sane time.
  */
-time_t string_to_time(const char *arg)
+extern __s64 string_to_time(const char *arg)
 {
        struct  tm      ts;
-       time_t          ret;
+       __s64           ret;
        char *tmp;
 
        if (strcmp(arg, "now") == 0) {
@@ -224,14 +232,18 @@ time_t string_to_time(const char *arg)
                /* interpret it as an integer */
                arg++;
        fallback:
-               ret = strtoul(arg, &tmp, 0);
+               ret = strtoll(arg+1, &tmp, 0);
                if (*tmp)
-                       return ((time_t) -1);
+                       return -1;
                return ret;
        }
        memset(&ts, 0, sizeof(ts));
 #ifdef HAVE_STRPTIME
        tmp = strptime(arg, "%Y%m%d%H%M%S", &ts);
+       if (tmp == NULL)
+               tmp = strptime(arg, "%Y%m%d%H%M", &ts);
+       if (tmp == NULL)
+               tmp = strptime(arg, "%Y%m%d", &ts);
        if (tmp == NULL)
                goto fallback;
 #else
@@ -240,9 +252,9 @@ time_t string_to_time(const char *arg)
        ts.tm_year -= 1900;
        ts.tm_mon -= 1;
        if (ts.tm_year < 0 || ts.tm_mon < 0 || ts.tm_mon > 11 ||
-           ts.tm_mday < 0 || ts.tm_mday > 31 || ts.tm_hour > 23 ||
+           ts.tm_mday <= 0 || ts.tm_mday > 31 || ts.tm_hour > 23 ||
            ts.tm_min > 59 || ts.tm_sec > 61)
-               ts.tm_mday = 0;
+               goto fallback;
 #endif
        ts.tm_isdst = -1;
        /* strptime() may only update the specified fields, which does not
@@ -260,8 +272,10 @@ time_t string_to_time(const char *arg)
                        ((ts.tm_mon - (ts.tm_mon > 7)) / 2) -
                        2 * (ts.tm_mon > 1) + ts.tm_mday - 1;
        ret = ts.tm_sec + ts.tm_min*60 + ts.tm_hour*3600 + ts.tm_yday*86400 +
-               (ts.tm_year-70)*31536000 + ((ts.tm_year-69)/4)*86400 -
-               ((ts.tm_year-1)/100)*86400 + ((ts.tm_year+299)/400)*86400;
+               ((__s64) ts.tm_year-70)*31536000 +
+               (((__s64) ts.tm_year-69)/4)*86400 -
+               (((__s64) ts.tm_year-1)/100)*86400 +
+               (((__s64) ts.tm_year+299)/400)*86400;
        return ret;
 }
 
index 709838df751784ba4bb1f2756b5d9cdff86d10e0..1f62c58777d283d78de3913b51f25fc1bb5620d8 100644 (file)
@@ -1010,6 +1010,13 @@ struct ext2_dir_entry_tail {
                                          EXT2_DIR_ROUND) & \
                                         ~EXT2_DIR_ROUND)
 
+/*
+ * Constants for ext4's extended time encoding
+ */
+#define EXT4_EPOCH_BITS 2
+#define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1)
+#define EXT4_NSEC_MASK  (~0UL << EXT4_EPOCH_BITS)
+
 /*
  * This structure is used for multiple mount protection. It is written
  * into the block number saved in the s_mmp_block field in the superblock.