erofs-utils: lib: fix truncated uncompressed files
authorGao Xiang <hsiangkao@linux.alibaba.com>
Fri, 9 Aug 2024 03:37:47 +0000 (11:37 +0800)
committerGao Xiang <hsiangkao@linux.alibaba.com>
Fri, 9 Aug 2024 03:41:45 +0000 (11:41 +0800)
Some uncompressed files which are more than 4GiB can be truncated
incorrectly.

Fixes: 358177730598 ("erofs-utils: optimize write_uncompressed_file_from_fd()")
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20240809033747.3178912-1-hsiangkao@linux.alibaba.com
lib/inode.c

index b3547bfd905bc3d9e837092bdef31f3c650779ee..b9dbbd609b8b56205e7f812eeccbc652a5b8ec1b 100644 (file)
@@ -515,7 +515,8 @@ static bool erofs_file_is_compressible(struct erofs_inode *inode)
 static int write_uncompressed_file_from_fd(struct erofs_inode *inode, int fd)
 {
        int ret;
-       unsigned int nblocks;
+       erofs_blk_t nblocks, i;
+       unsigned int len;
        struct erofs_sb_info *sbi = inode->sbi;
 
        inode->datalayout = EROFS_INODE_FLAT_INLINE;
@@ -525,12 +526,16 @@ static int write_uncompressed_file_from_fd(struct erofs_inode *inode, int fd)
        if (ret)
                return ret;
 
-       ret = erofs_io_xcopy(&sbi->bdev, erofs_pos(sbi, inode->u.i_blkaddr),
-                            &((struct erofs_vfile){ .fd = fd }),
-                            erofs_pos(sbi, nblocks),
+       for (i = 0; i < nblocks; i += (len >> sbi->blkszbits)) {
+               len = min_t(u64, round_down(UINT_MAX, 1U << sbi->blkszbits),
+                           erofs_pos(sbi, nblocks - i));
+               ret = erofs_io_xcopy(&sbi->bdev,
+                                    erofs_pos(sbi, inode->u.i_blkaddr + i),
+                                    &((struct erofs_vfile){ .fd = fd }), len,
                        inode->datasource == EROFS_INODE_DATA_SOURCE_DISKBUF);
-       if (ret)
-               return ret;
+               if (ret)
+                       return ret;
+       }
 
        /* read the tail-end data */
        inode->idata_size = inode->i_size % erofs_blksiz(sbi);