[PATCH] debugfs: add support to properly set and display extended timestamps

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



In order to properly test the changes for extended timestamps, I
extracted portions of David Turner's patches to e2fsprogs, so we could
have a single commit which only adds the extended timestamps to e2fsprogs.

I moved things around a bit, to avoid the new header file
lib/extract_epoch.h with only two lines.  I also added proper support
to parse_time so that you can now have commands such as:

debugfs: set_inode_file /test ctime_lo 0x10203040
debugfs: set_inode_file /test ctime_hi 3
debugfs: set_inode_file /test ctime 205012143045
debugfs: set_inode_file /test ctime @4386555179

David, let me know what you think.  One thing which I'm still thinking
about adding is support encoding and decoding for the older style
encoding for pre-1970 dates, so we can properly test the e2fsck and
kernel patches.  What I'm still thinking about is what's the best way
to toggle between the legacy and new encoding for pre-1970 dates.

   	  	      	     	     	      - Ted

commit 05c2f96e19b6a7b769369f11538a0f93adf747a5
Author: Theodore Ts'o <tytso@xxxxxxx>
Date:   Mon Dec 9 13:55:23 2013 -0500

    debugfs: add support to properly set and display extended timestamps
    
    This code is partially derived from patches from David Turner to allow
    debugfs to properly support extended timestamps.
    
    Cc: David Turner <novalis@xxxxxxxxxxx>
    Signed-off-by: "Theodore Ts'o" <tytso@xxxxxxx>

diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
index 902ee66..7746629 100644
--- a/debugfs/debugfs.c
+++ b/debugfs/debugfs.c
@@ -793,27 +793,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);
@@ -2149,7 +2159,7 @@ void do_set_current_time(int argc, char *argv[])
 		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;
diff --git a/debugfs/debugfs.h b/debugfs/debugfs.h
index 45175cf..32d32cc 100644
--- a/debugfs/debugfs.h
+++ b/debugfs/debugfs.h
@@ -33,8 +33,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,
diff --git a/debugfs/lsdel.c b/debugfs/lsdel.c
index bed0ce6..da2ad11 100644
--- a/debugfs/lsdel.c
+++ b/debugfs/lsdel.c
@@ -166,7 +166,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++;
diff --git a/debugfs/set_fields.c b/debugfs/set_fields.c
index b09e2f8..1cffeca 100644
--- a/debugfs/set_fields.c
+++ b/debugfs/set_fields.c
@@ -160,10 +160,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, &set_inode.i_ctime_extra,
+		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 },
@@ -199,7 +203,8 @@ static struct field_set_info inode_fields[] = {
 		4, parse_uint },
 	{ "atime_extra", &set_inode.i_atime_extra, NULL,
 		4, parse_uint },
-	{ "crtime", &set_inode.i_crtime, NULL, 4, parse_uint },
+	{ "crtime", &set_inode.i_crtime, &set_inode.i_crtime_extra,
+		4, parse_time },
 	{ "crtime_extra", &set_inode.i_crtime_extra, NULL,
 		4, parse_uint },
 	{ "bmap", NULL, NULL, 4, parse_bmap, FLAG_ARRAY },
@@ -474,21 +479,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;
 }
 
diff --git a/debugfs/util.c b/debugfs/util.c
index cf3a6c6..4a0abd8 100644
--- a/debugfs/util.c
+++ b/debugfs/util.c
@@ -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.
  */
-extern 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) {
@@ -222,9 +230,9 @@ extern time_t string_to_time(const char *arg)
 	}
 	if (arg[0] == '@') {
 		/* interpret it as an integer */
-		ret = strtoul(arg+1, &tmp, 0);
+		ret = strtoll(arg+1, &tmp, 0);
 		if (*tmp)
-			return ((time_t) -1);
+			return -1;
 		return ret;
 	}
 	memset(&ts, 0, sizeof(ts));
@@ -244,9 +252,9 @@ extern time_t string_to_time(const char *arg)
 	ret = mktime(&ts);
 	if (ts.tm_mday == 0 || ret == ((time_t) -1)) {
 		/* Try it as an integer... */
-		ret = strtoul(arg, &tmp, 0);
+		ret = strtoll(arg, &tmp, 0);
 		if (*tmp)
-			return ((time_t) -1);
+			return -1;
 	}
 	return ret;
 }
diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index fb3f7cc..fb10e7f 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -809,6 +809,13 @@ struct ext2_dir_entry_2 {
 					 ~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.
  * Programs that check MMP should assume that if SEQ_FSCK (or any unknown
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Reiser Filesystem Development]     [Ceph FS]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite National Park]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Device Mapper]     [Linux Media]

  Powered by Linux