mirror of https://github.com/vitalif/e2fsprogs
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@novalis.org> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>debian
parent
79ffbf251e
commit
188960ea4b
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -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);
|
||||
|
||||
ptr32 = (__u32 *) info->ptr;
|
||||
if (check_suffix(field))
|
||||
return parse_uint(info, field, arg);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue