Whamcloud - gitweb
Add fallocate.c to lib/exte2fs/Android.mk
[tools/e2fsprogs.git] / lib / ext2fs / punch.c
index 25d7953..3cce1f8 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "ext2_fs.h"
 #include "ext2fs.h"
+#include "ext2fsP.h"
 
 #undef PUNCH_DEBUG
 
@@ -288,8 +289,12 @@ static errcode_t ext2fs_punch_extent(ext2_filsys fs, ext2_ino_t ino,
                           (unsigned long long) end,
                           (unsigned long long) next);
                if (start <= extent.e_lblk) {
+                       /*
+                        * Have we iterated past the end of the punch region?
+                        * If so, we can stop.
+                        */
                        if (end < extent.e_lblk)
-                               goto next_extent;
+                               break;
                        dbg_printf("Case #%d\n", 1);
                        /* Start of deleted region before extent; 
                           adjust beginning of extent */
@@ -303,8 +308,13 @@ static errcode_t ext2fs_punch_extent(ext2_filsys fs, ext2_ino_t ino,
                        extent.e_lblk += free_count;
                        extent.e_pblk += free_count;
                } else if (end >= next-1) {
+                       /*
+                        * Is the punch region beyond this extent?  This can
+                        * happen if start is already inside a hole.  Try to
+                        * advance to the next extent if this is the case.
+                        */
                        if (start >= next)
-                               break;
+                               goto next_extent;
                        /* End of deleted region after extent;
                           adjust end of extent */
                        dbg_printf("Case #%d\n", 2);
@@ -334,16 +344,25 @@ static errcode_t ext2fs_punch_extent(ext2_filsys fs, ext2_ino_t ino,
                                        EXT2_EXTENT_INSERT_AFTER, &newex);
                        if (retval)
                                goto errout;
-                       /* Now pointing at inserted extent; so go back */
-                       retval = ext2fs_extent_get(handle,
-                                                  EXT2_EXTENT_PREV_LEAF,
-                                                  &newex);
+                       retval = ext2fs_extent_fix_parents(handle);
+                       if (retval)
+                               goto errout;
+                       /*
+                        * Now pointing at inserted extent; so go back.
+                        *
+                        * We cannot use EXT2_EXTENT_PREV to go back; note the
+                        * subtlety in the comment for fix_parents().
+                        */
+                       retval = ext2fs_extent_goto(handle, extent.e_lblk);
                        if (retval)
                                goto errout;
                } 
                if (extent.e_len) {
                        dbg_print_extent("replacing", &extent);
                        retval = ext2fs_extent_replace(handle, 0, &extent);
+                       if (retval)
+                               goto errout;
+                       retval = ext2fs_extent_fix_parents(handle);
                } else {
                        struct ext2fs_extent    newex;
                        blk64_t                 old_lblk, next_lblk;
@@ -378,8 +397,17 @@ static errcode_t ext2fs_punch_extent(ext2_filsys fs, ext2_ino_t ino,
                        if (retval)
                                goto errout;
 
-                       /* Jump forward to the next extent. */
-                       ext2fs_extent_goto(handle, next_lblk);
+                       retval = ext2fs_extent_fix_parents(handle);
+                       if (retval && retval != EXT2_ET_NO_CURRENT_NODE)
+                               goto errout;
+                       retval = 0;
+
+                       /*
+                        * Jump forward to the next extent.  If there are
+                        * errors, the ext2fs_extent_get down below will
+                        * capture them for us.
+                        */
+                       (void)ext2fs_extent_goto(handle, next_lblk);
                        op = EXT2_EXTENT_CURRENT;
                }
                if (retval)
@@ -406,6 +434,30 @@ errout:
        return retval;
 }
        
+static errcode_t ext2fs_punch_inline_data(ext2_filsys fs, ext2_ino_t ino,
+                                         struct ext2_inode *inode,
+                                         blk64_t start, blk64_t end)
+{
+       errcode_t retval;
+
+       /*
+        * In libext2fs ext2fs_punch is based on block unit.  So that
+        * means that if start > 0 we don't need to do nothing.  Due
+        * to this we will remove all inline data in ext2fs_punch()
+        * now.
+        */
+       if (start > 0)
+               return 0;
+
+       memset((char *)inode->i_block, 0, EXT4_MIN_INLINE_DATA_SIZE);
+       inode->i_size = 0;
+       retval = ext2fs_write_inode(fs, ino, inode);
+       if (retval)
+               return retval;
+
+       return ext2fs_inline_data_ea_remove(fs, ino);
+}
+
 /*
  * Deallocate all logical blocks starting at start to end, inclusive.
  * If end is ~0, then this is effectively truncate.
@@ -428,7 +480,9 @@ errcode_t ext2fs_punch(ext2_filsys fs, ext2_ino_t ino,
                        return retval;
                inode = &inode_buf;
        }
-       if (inode->i_flags & EXT4_EXTENTS_FL)
+       if (inode->i_flags & EXT4_INLINE_DATA_FL)
+               return ext2fs_punch_inline_data(fs, ino, inode, start, end);
+       else if (inode->i_flags & EXT4_EXTENTS_FL)
                retval = ext2fs_punch_extent(fs, ino, inode, start, end);
        else {
                blk_t   count;