[PATCH v2] cmd: Fix copying when the dest is one of the sources.
Lauri Kenttä
lauri.kentta at gmail.com
Mon Dec 5 10:44:13 CST 2016
"COPY a+b a" appends b to a.
"COPY a+b b" skips b from the sources.
(Previously Wine just fails.)
Fixes the main issue of bug 35495.
v2: Detect same file properly with GetFileInformationByHandle
instead of simply comparing paths.
Signed-off-by: Lauri Kenttä <lauri.kentta at gmail.com>
---
programs/cmd/builtins.c | 44 ++++++++++++++++++++++++++++++--
programs/cmd/tests/test_builtins.cmd | 16 ++++++++++++
programs/cmd/tests/test_builtins.cmd.exp | 3 +++
3 files changed, 61 insertions(+), 2 deletions(-)
diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c
index a29a502..a225351 100644
--- a/programs/cmd/builtins.c
+++ b/programs/cmd/builtins.c
@@ -460,6 +460,36 @@ static BOOL WCMD_AppendEOF(WCHAR *filename)
}
/****************************************************************************
+ * WCMD_IsSameFile
+ *
+ * Checks if the two paths reference to the same file
+ */
+static BOOL WCMD_IsSameFile(const WCHAR *name1, const WCHAR *name2)
+{
+ BOOL ret = FALSE;
+ HANDLE file1 = 0, file2 = 0;
+ BY_HANDLE_FILE_INFORMATION info1, info2;
+
+ file1 = CreateFileW(name1, 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
+ if (!file1 || !GetFileInformationByHandle(file1, &info1))
+ goto end;
+
+ file2 = CreateFileW(name2, 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
+ if (!file2 || !GetFileInformationByHandle(file2, &info2))
+ goto end;
+
+ ret = info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber
+ && info1.nFileIndexHigh == info2.nFileIndexHigh
+ && info1.nFileIndexLow == info2.nFileIndexLow;
+end:
+ if (file1)
+ CloseHandle(file1);
+ if (file2)
+ CloseHandle(file2);
+ return ret;
+}
+
+/****************************************************************************
* WCMD_ManualCopy
*
* Copies from a file
@@ -922,6 +952,7 @@ void WCMD_copy(WCHAR * args) {
do {
WCHAR outname[MAX_PATH];
BOOL overwrite;
+ BOOL appendtofirstfile = FALSE;
/* Skip . and .., and directories */
if (!srcisdevice && fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
@@ -946,8 +977,14 @@ void WCMD_copy(WCHAR * args) {
WINE_TRACE("Flags: srcbinary(%d), dstbinary(%d), over(%d), prompt(%d)\n",
thiscopy->binarycopy, destination->binarycopy, overwrite, prompt);
+ if (!writtenoneconcat) {
+ appendtofirstfile = anyconcats && WCMD_IsSameFile(srcpath, outname);
+ }
+
/* Prompt before overwriting */
- if (!overwrite) {
+ if (appendtofirstfile) {
+ overwrite = TRUE;
+ } else if (!overwrite) {
DWORD attributes = GetFileAttributesW(outname);
if (attributes != INVALID_FILE_ATTRIBUTES) {
WCHAR* question;
@@ -969,7 +1006,10 @@ void WCMD_copy(WCHAR * args) {
/* Do the copy as appropriate */
if (overwrite) {
- if (anyconcats && writtenoneconcat) {
+ if (anyconcats && WCMD_IsSameFile(srcpath, outname)) {
+ /* Silently skip if the destination file is also a source file */
+ status = TRUE;
+ } else if (anyconcats && writtenoneconcat) {
if (thiscopy->binarycopy) {
status = WCMD_ManualCopy(srcpath, outname, FALSE, TRUE);
} else {
diff --git a/programs/cmd/tests/test_builtins.cmd b/programs/cmd/tests/test_builtins.cmd
index b49f90a..02d9750 100644
--- a/programs/cmd/tests/test_builtins.cmd
+++ b/programs/cmd/tests/test_builtins.cmd
@@ -2584,6 +2584,22 @@ rem Concat 2 files, default mode - (one EOF on the end 5+8+1)
copy ..\file1+..\file2 file12_eof2 >nul 2>&1
call :CheckFileSize file12_eof2 14
+rem Test copying when destination is one of the sources.
+rem Concat file1+file2+file3 into file1, should produce file1+file2+file3 = 24
+copy /y ..\file? .\ >nul 2>&1
+copy /y /b file1+file2+file3 file1 >nul 2>&1
+call :CheckFileSize file1 24
+
+rem Concat file1+file2+file3 into file2, should produce file1+file3 = 16
+copy /y ..\file? .\ >nul 2>&1
+copy /y /b file1+file2+file3 file2 >nul 2>&1
+call :CheckFileSize file2 16
+
+rem Concat file1+file2+file3 into file3, should produce file1+file2 = 13
+copy /y ..\file? .\ >nul 2>&1
+copy /y /b file1+file2+file3 file3 >nul 2>&1
+call :CheckFileSize file3 13
+
rem --------------------------------------------------------------
rem Show ascii source copy stops at first EOF, binary does the lot
rem --------------------------------------------------------------
diff --git a/programs/cmd/tests/test_builtins.cmd.exp b/programs/cmd/tests/test_builtins.cmd.exp
index e81fbcb..796550e 100644
--- a/programs/cmd/tests/test_builtins.cmd.exp
+++ b/programs/cmd/tests/test_builtins.cmd.exp
@@ -1462,6 +1462,9 @@ Passed: file size check on file3_plus_eof [12]@or_broken at Skipping file size chec
Passed: file size check on file12_plus_eof [14]@or_broken at Skipping file size check on NT4
Passed: file size check on file12_no_eof [13]@or_broken at Skipping file size check on NT4
Passed: file size check on file12_eof2 [14]@or_broken at Skipping file size check on NT4
+Passed: file size check on file1 [24]@or_broken at Skipping file size check on NT4
+Passed: file size check on file2 [16]@or_broken at Skipping file size check on NT4
+Passed: file size check on file3 [13]@or_broken at Skipping file size check on NT4
Passed: file size check on file1_binary_srccopy [6]@or_broken at Skipping file size check on NT4
Passed: file size check on file1_ascii_srccopy [5]@or_broken at Skipping file size check on NT4
Passed: file size check on file123_default_copy [25]@or_broken at Skipping file size check on NT4
--
2.10.2
More information about the wine-patches
mailing list