]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
libext2fs: don't fail when doing a strict rewrite of inline data
authorDarrick J. Wong <darrick.wong@oracle.com>
Fri, 14 Mar 2014 13:23:03 +0000 (09:23 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Fri, 14 Mar 2014 13:23:08 +0000 (09:23 -0400)
ext2fs_inline_data_set() tries to ensure that there is sufficient free
space in the inode to store the inline data.  Unfortunately, it gets
the check wrong -- ext2fs_xattr_inode_max_size() returns the amount of
unused bytes in the EA area, and _data_set() doesn't factor in the
size of the existing inline data.  Therefore, a strict rewrite of an
N-byte inlinedata with another N-byte inlinedata fails.

Fix the code to do the size check correctly.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
lib/ext2fs/inline_data.c

index 9a786fc17ef3e19535c250cb42c1939b609bb1a5..72e8fa3d1f45b0b22bb2ecbdc6b279fa0141c673 100644 (file)
@@ -522,7 +522,7 @@ errcode_t ext2fs_inline_data_set(ext2_filsys fs, ext2_ino_t ino,
        struct ext2_inode inode_buf;
        struct ext2_inline_data data;
        errcode_t retval;
-       size_t max_size;
+       size_t free_ea_size, existing_size, free_inode_size;
 
        if (!inode) {
                retval = ext2fs_read_inode(fs, ino, &inode_buf);
@@ -536,11 +536,20 @@ errcode_t ext2fs_inline_data_set(ext2_filsys fs, ext2_ino_t ino,
                return ext2fs_write_inode(fs, ino, inode);
        }
 
-       retval = ext2fs_xattr_inode_max_size(fs, ino, &max_size);
+       retval = ext2fs_xattr_inode_max_size(fs, ino, &free_ea_size);
        if (retval)
                return retval;
 
-       if (size - EXT4_MIN_INLINE_DATA_SIZE > max_size)
+       retval = ext2fs_inline_data_size(fs, ino, &existing_size);
+       if (retval)
+               return retval;
+
+       if (existing_size < EXT4_MIN_INLINE_DATA_SIZE)
+               free_inode_size = EXT4_MIN_INLINE_DATA_SIZE - existing_size;
+       else
+               free_inode_size = 0;
+
+       if (size > existing_size + free_ea_size + free_inode_size)
                return EXT2_ET_INLINE_DATA_NO_SPACE;
 
        memcpy((void *)inode->i_block, buf, EXT4_MIN_INLINE_DATA_SIZE);