Currently btrfs-convert only copies ext2 inode timestamps
i_[cma]time from ext4, while filling 0 to nsec and crtime fields.

This change copies nsec and crtime by parsing i_[cma]time_extra fields.
---
 convert/source-ext2.c | 81 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 80 insertions(+), 1 deletion(-)

diff --git a/convert/source-ext2.c b/convert/source-ext2.c
index efe73742..e397e89f 100644
--- a/convert/source-ext2.c
+++ b/convert/source-ext2.c
@@ -691,6 +691,77 @@ static void ext2_copy_inode_item(struct btrfs_inode_item 
*dst,
        }
        memset(&dst->reserved, 0, sizeof(dst->reserved));
 }
+
+/*
+ * Copied and modified from fs/ext4/ext4.h
+ */
+static inline void ext4_decode_extra_time(__le32 * tv_sec, __le32 * tv_nsec,
+                                          __le32 extra)
+{
+        if (extra & cpu_to_le32(EXT4_EPOCH_MASK))
+                *tv_sec += (u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK) << 32;
+        *tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
+}
+
+#define EXT4_COPY_XTIME(xtime, dst, tv_sec, tv_nsec)                           
        \
+do {                                                                           
        \
+       tv_sec = src->i_ ## xtime ;                                             
        \
+       if(inode_includes(inode_size, i_ ## xtime ## _extra)) {                 
        \
+               tv_sec = src->i_ ## xtime ;                                     
        \
+               ext4_decode_extra_time(&tv_sec, &tv_nsec, src->i_ ## xtime ## 
_extra);  \
+               btrfs_set_stack_timespec_sec(&dst->xtime , tv_sec);             
        \
+               btrfs_set_stack_timespec_nsec(&dst->xtime , tv_nsec);           
        \
+       }else{                                                                  
        \
+               btrfs_set_stack_timespec_sec(&dst->xtime , tv_sec);             
        \
+               btrfs_set_stack_timespec_nsec(&dst->xtime , 0);                 
        \
+       }                                                                       
        \
+}while (0);
+
+/*
+ * Decode and copy i_[cma]time_extra and i_crtime{,_extra} field
+ */
+static int ext4_copy_inode_timespec_extra(struct btrfs_inode_item *dst,
+                               ext2_ino_t ext2_ino, u32 s_inode_size, 
ext2_filsys ext2_fs)
+{
+
+       struct ext2_inode_large *src;
+       u32 inode_size, tv_sec, tv_nsec;
+       int ret, err;
+       ret = 0;
+
+       src = (struct ext2_inode_large *)malloc(s_inode_size);
+       if (!src)
+               return -ENOMEM;
+       err = ext2fs_read_inode_full(ext2_fs, ext2_ino, (void *)src,
+                                    s_inode_size);
+       if (err) {
+               fprintf(stderr, "ext2fs_read_inode_full: %s\n",
+                       error_message(err));
+               ret = -1;
+               goto out;
+       }
+
+       inode_size = EXT2_GOOD_OLD_INODE_SIZE + src->i_extra_isize;
+
+       EXT4_COPY_XTIME(atime, dst, tv_sec, tv_nsec);
+       EXT4_COPY_XTIME(mtime, dst, tv_sec, tv_nsec);
+       EXT4_COPY_XTIME(ctime, dst, tv_sec, tv_nsec);
+
+       tv_sec = src->i_crtime ;
+       if(inode_includes(inode_size, i_crtime_extra)) {
+               tv_sec = src->i_crtime;
+               ext4_decode_extra_time(&tv_sec, &tv_nsec, src->i_crtime_extra);
+               btrfs_set_stack_timespec_sec(&dst-> otime , tv_sec);
+               btrfs_set_stack_timespec_nsec(&dst-> otime , tv_nsec);
+       }else{
+               btrfs_set_stack_timespec_sec(&dst-> otime , tv_sec);
+               btrfs_set_stack_timespec_nsec(&dst-> otime , 0);
+       }
+out:
+       free(src);
+       return ret;
+}
+
 static int ext2_check_state(struct btrfs_convert_context *cctx)
 {
        ext2_filsys fs = cctx->fs_data;
@@ -738,13 +809,21 @@ static int ext2_copy_single_inode(struct 
btrfs_trans_handle *trans,
                             struct ext2_inode *ext2_inode,
                             u32 convert_flags)
 {
-       int ret;
+       int ret, s_inode_size;
        struct btrfs_inode_item btrfs_inode;
 
        if (ext2_inode->i_links_count == 0)
                return 0;
 
        ext2_copy_inode_item(&btrfs_inode, ext2_inode, ext2_fs->blocksize);
+       s_inode_size = EXT2_INODE_SIZE(ext2_fs->super);
+       if (s_inode_size > EXT2_GOOD_OLD_INODE_SIZE) {
+               ret = ext4_copy_inode_timespec_extra(&btrfs_inode,
+                       ext2_ino, s_inode_size, ext2_fs);
+               if (ret)
+                   return ret;
+       }
+
        if (!(convert_flags & CONVERT_FLAG_DATACSUM)
            && S_ISREG(ext2_inode->i_mode)) {
                u32 flags = btrfs_stack_inode_flags(&btrfs_inode) |
-- 
2.29.2

Reply via email to