summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDmitry Monakhov <dmonakhov@openvz.org>2015-10-30 22:04:46 +0000
committerPádraig Brady <P@draigBrady.com>2015-11-24 00:49:03 +0000
commiteea6b49210edf69682b2d0606bee17bbccb3765b (patch)
tree84e120fb2c31c0345b729a8ffe731e477ff4db78 /src
parent6df26278d6cf5c6fad04d3fbaed4c06a223fb0bd (diff)
downloadcoreutils-eea6b49210edf69682b2d0606bee17bbccb3765b.tar.xz
copy: fix copying of extents beyond the apparent file size
fallocate can allocate extents beyond EOF via FALLOC_FL_KEEP_SIZE. Where there is a gap (hole) between the extents, and EOF is within that gap, the final hole wasn't reproduced, resulting in silent data corruption in the copied file (size too small). * src/copy.c (extent_copy): Ensure we don't process extents beyond the apparent file size, since processing and allocating those is not currently supported. * tests/cp/fiemap-extents.sh: Renamed from tests/cp/fiemap-empty.sh and re-enable parts checking the extents at and beyond EOF. * tests/local.mk: Reference the renamed test. * NEWS: Mention the bug fix. Fixes http://bugs.gnu.org/21790
Diffstat (limited to 'src')
-rw-r--r--src/copy.c19
1 files changed, 18 insertions, 1 deletions
diff --git a/src/copy.c b/src/copy.c
index dc1cd2904..6771bb53b 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -432,6 +432,20 @@ extent_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
ext_len = 0;
}
+ /* Truncate extent to EOF. Extents starting after EOF are
+ treated as zero length extents starting right after EOF.
+ Generally this will trigger with an extent starting after
+ src_total_size, and result in creating a hole or zeros until EOF.
+ Though in a file in which extents have changed since src_total_size
+ was determined, we might have an extent spanning that size,
+ in which case we'll only copy data up to that size. */
+ if (src_total_size < ext_start + ext_len)
+ {
+ if (src_total_size < ext_start)
+ ext_start = src_total_size;
+ ext_len = src_total_size - ext_start;
+ }
+
ext_hole_size = ext_start - last_ext_start - last_ext_len;
wrote_hole_at_eof = false;
@@ -495,14 +509,17 @@ extent_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
off_t n_read;
empty_extent = false;
last_ext_len = ext_len;
+ bool read_hole;
if ( ! sparse_copy (src_fd, dest_fd, buf, buf_size,
sparse_mode == SPARSE_ALWAYS ? hole_size: 0,
true, src_name, dst_name, ext_len, &n_read,
- &wrote_hole_at_eof))
+ &read_hole))
goto fail;
dest_pos = ext_start + n_read;
+ if (n_read)
+ wrote_hole_at_eof = read_hole;
}
/* If the file ends with unwritten extents not accounted for in the