From 184aa4b5d07d5f3fcc15dd4bb0d4636fba734de3 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Wed, 20 May 2020 15:52:42 +0100 Subject: dd: fix handling of 'conv=notrunc seek=N' Commit e6680912a (dd: create a sparse file when seek=N is used) broke the use of 'conv=notrunc seek=N' to modify existing files. Rename seek_sparse() to make_sparse() and: - add an argument to specify the start of the sparse region; - call make_sparse() before ftruncate(); - call make_sparse() only if: * we can determine the size of the file; * the file is not open in append mode; * the file is being extended. This should fix GitHub issue #186. --- coreutils/dd.c | 25 ++++++++++++++++++++++--- include/mingw.h | 2 +- win32/mingw.c | 6 +++--- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/coreutils/dd.c b/coreutils/dd.c index fc8b1dbb2..042355e24 100644 --- a/coreutils/dd.c +++ b/coreutils/dd.c @@ -466,6 +466,27 @@ int dd_main(int argc UNUSED_PARAM, char **argv) xmove_fd(xopen(outfile, oflag), ofd); +#if ENABLE_PLATFORM_MINGW32 + { + off_t len = (off_t)seek * ((G.flags & FLAG_SEEK_BYTES) ? 1 : obs); + struct stat st; + int ret = fstat(ofd, &st); + + if (ret == 0 && !(G.flags & FLAG_APPEND) && len > st.st_size) + make_sparse(ofd, st.st_size, len); + + if (seek && !(G.flags & FLAG_NOTRUNC)) { + if (ftruncate(ofd, len) < 0) { + if (ret < 0 + || S_ISREG(st.st_mode) + || S_ISDIR(st.st_mode) + ) { + goto die_outfile; + } + } + } + } +#else if (seek && !(G.flags & FLAG_NOTRUNC)) { size_t blocksz = (G.flags & FLAG_SEEK_BYTES) ? 1 : obs; if (ftruncate(ofd, seek * blocksz) < 0) { @@ -479,6 +500,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv) } } } +#endif } else { outfile = bb_msg_standard_output; } @@ -502,9 +524,6 @@ int dd_main(int argc UNUSED_PARAM, char **argv) } if (seek) { size_t blocksz = (G.flags & FLAG_SEEK_BYTES) ? 1 : obs; -#if ENABLE_PLATFORM_MINGW32 - seek_sparse(ofd, seek * blocksz); -#endif if (lseek(ofd, seek * blocksz, SEEK_CUR) < 0) goto die_outfile; } diff --git a/include/mingw.h b/include/mingw.h index 0fead43c9..39d716521 100644 --- a/include/mingw.h +++ b/include/mingw.h @@ -537,5 +537,5 @@ int chdir_system_drive(void); char *xabsolute_path(char *path); char *get_drive_cwd(const char *path, char *buffer, int size); void fix_path_case(char *path); -void seek_sparse(int fd, size_t size); +void make_sparse(int fd, off_t start, off_t end); int skip_ansi_emulation(int reset); diff --git a/win32/mingw.c b/win32/mingw.c index 7f8fecdc3..5c4c39b9d 100644 --- a/win32/mingw.c +++ b/win32/mingw.c @@ -1751,7 +1751,7 @@ void fix_path_case(char *path) } } -void seek_sparse(int fd, size_t size) +void make_sparse(int fd, off_t start, off_t end) { DWORD dwTemp; HANDLE fh; @@ -1762,8 +1762,8 @@ void seek_sparse(int fd, size_t size) DeviceIoControl(fh, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &dwTemp, NULL); - fzdi.FileOffset.QuadPart = 0; - fzdi.BeyondFinalZero.QuadPart = size; + fzdi.FileOffset.QuadPart = start; + fzdi.BeyondFinalZero.QuadPart = end; DeviceIoControl(fh, FSCTL_SET_ZERO_DATA, &fzdi, sizeof(fzdi), NULL, 0, &dwTemp, NULL); } -- cgit v1.2.3-55-g6feb