[PATCH 7/7] [cmd] Add full support for copy concatenation and ascii/binary

Ann and Jason Edmeades jason at edmeades.me.uk
Fri Oct 12 04:53:13 CDT 2012


This patch adds full support for concatenation, whether in ascii
or binary modes. Effectively it adds copy a+b filename, or copy
a* filename support, and handles the EOF oddities that such
syntax brings in by honouring the /a and /b options.

[Should fix bugs 26943 and 27899]
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.winehq.org/pipermail/wine-patches/attachments/20121012/eb71abe9/attachment-0001.html>
-------------- next part --------------
From 53c30bad90f406788c0c49ac92077052711f1d6f Mon Sep 17 00:00:00 2001
From: Jason Edmeades <jason at edmeades.me.uk>
Date: Fri, 12 Oct 2012 10:23:24 +0100
Subject: [PATCH 7/7] [cmd] Add full support for copy concatenation and
 ascii/binary

This patch adds full support for concatenation, whether in ascii
or binary modes. Effectively it adds copy a+b filename, or copy
a* filename support, and handles the EOF oddities that such
syntax brings in by honouring the /a and /b options.

[Should fix bugs 26943 and 27899]
---
 programs/cmd/builtins.c                  |  101 +++++++++++++++++++++++++-----
 programs/cmd/tests/test_builtins.cmd     |    4 ++
 programs/cmd/tests/test_builtins.cmd.exp |   29 ++++-----
 3 files changed, 106 insertions(+), 28 deletions(-)

diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c
index 4e452b8..a81fec4 100644
--- a/programs/cmd/builtins.c
+++ b/programs/cmd/builtins.c
@@ -401,6 +401,76 @@ BOOL WCMD_AppendEOF(WCHAR *filename)
 }
 
 /****************************************************************************
+ * WCMD_ManualCopy
+ *
+ * Copies from a file
+ *    optionally reading only until EOF (ascii copy)
+ *    optionally appending onto an existing file (append)
+ * Returns TRUE on success
+ */
+BOOL WCMD_ManualCopy(WCHAR *srcname, WCHAR *dstname, BOOL ascii, BOOL append)
+{
+    HANDLE in,out;
+    BOOL   ok;
+    DWORD  bytesread, byteswritten;
+
+    WINE_TRACE("ASCII Copying %s to %s (append?%d)\n",
+               wine_dbgstr_w(srcname), wine_dbgstr_w(dstname), append);
+
+    in  = CreateFileW(srcname, GENERIC_READ, 0, NULL,
+                      OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (in == NULL) {
+      WINE_ERR("Failed to open %s (%d)\n", wine_dbgstr_w(srcname), GetLastError());
+      return FALSE;
+    }
+
+    /* Open the output file, overwriting if not appending */
+    out = CreateFileW(dstname, GENERIC_WRITE, 0, NULL,
+                      append?OPEN_EXISTING:CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+    if (out == NULL) {
+      WINE_ERR("Failed to open %s (%d)\n", wine_dbgstr_w(dstname), GetLastError());
+      return FALSE;
+    }
+
+    /* Move to end of destination if we are going to append to it */
+    if (append) {
+      SetFilePointer(out, 0, NULL, FILE_END);
+    }
+
+    /* Loop copying data from source to destination until EOF read */
+    ok = TRUE;
+    do
+    {
+      char buffer[MAXSTRING];
+
+      ok = ReadFile(in, buffer, MAXSTRING, &bytesread, NULL);
+      if (ok) {
+
+        /* Stop at first EOF */
+        if (ascii) {
+          char *ptr = (char *)memchr((void *)buffer, '\x1a', bytesread);
+          if (ptr) bytesread = (ptr - buffer);
+        }
+
+        if (bytesread) {
+          ok = WriteFile(out, buffer, bytesread, &byteswritten, NULL);
+          if (!ok || byteswritten != bytesread) {
+            WINE_ERR("Unexpected failure writing to %s, rc=%d\n",
+                     wine_dbgstr_w(dstname), GetLastError());
+          }
+        }
+      } else {
+        WINE_ERR("Unexpected failure reading from %s, rc=%d\n",
+                 wine_dbgstr_w(srcname), GetLastError());
+      }
+    } while (ok && bytesread > 0);
+
+    CloseHandle(out);
+    CloseHandle(in);
+    return ok;
+}
+
+/****************************************************************************
  * WCMD_copy
  *
  * Copy a file or wildcarded set.
@@ -697,11 +767,13 @@ void WCMD_copy(WCHAR * command) {
   } else if (!destisdirectory) {
     /* We have been asked to copy to a filename. Default to ascii IF the
        source contains wildcards (true even if only one match)           */
-    if (destination->binarycopy == -1) {
-      if (strpbrkW(sourcelist->name, wildcardsW) != NULL) {
-        anyconcats = TRUE;  /* We really are concatenating to a single file */
+    if (strpbrkW(sourcelist->name, wildcardsW) != NULL) {
+      anyconcats = TRUE;  /* We really are concatenating to a single file */
+      if (destination->binarycopy == -1) {
         destination->binarycopy = 0;
-      } else {
+      }
+    } else {
+      if (destination->binarycopy == -1) {
         destination->binarycopy = 1;
       }
     }
@@ -731,7 +803,7 @@ void WCMD_copy(WCHAR * command) {
     WCHAR *filenamepart;
     DWORD  attributes;
 
-    /* If it was not explicit, we now know whehter we are concatenating or not and
+    /* If it was not explicit, we now know whether we are concatenating or not and
        hence whether to copy as binary or ascii                                    */
     if (thiscopy->binarycopy == -1) thiscopy->binarycopy = !anyconcats;
 
@@ -820,17 +892,15 @@ void WCMD_copy(WCHAR * command) {
           if (overwrite) {
             if (anyconcats && writtenoneconcat) {
               if (thiscopy->binarycopy) {
-                WINE_FIXME("Need to concatenate %s to %s (read as binary), will overwrite\n",
-                           wine_dbgstr_w(srcpath), wine_dbgstr_w(outname));
+                status = WCMD_ManualCopy(srcpath, outname, FALSE, TRUE);
               } else {
-                WINE_FIXME("Need to concatenate %s to %s (read as ascii), will overwrite\n",
-                           wine_dbgstr_w(srcpath), wine_dbgstr_w(outname));
+                status = WCMD_ManualCopy(srcpath, outname, TRUE, TRUE);
               }
             } else if (!thiscopy->binarycopy) {
-              WINE_FIXME("Need to ascii copy %s to %s - dropping to binary copy\n",
-                         wine_dbgstr_w(srcpath), wine_dbgstr_w(outname));
+              status = WCMD_ManualCopy(srcpath, outname, TRUE, FALSE);
+            } else {
+              status = CopyFileW(srcpath, outname, FALSE);
             }
-            status = CopyFileW(srcpath, outname, FALSE);
             if (!status) {
               WCMD_print_error ();
               errorlevel = 1;
@@ -838,8 +908,11 @@ void WCMD_copy(WCHAR * command) {
               WINE_TRACE("Copied successfully\n");
               if (anyconcats) writtenoneconcat = TRUE;
 
-              /* Append EOF if ascii destination and we are not going to add more onto the end */
-              if (!destination->binarycopy && !anyconcats) {
+              /* Append EOF if ascii destination and we are not going to add more onto the end
+                 Note: Testing shows windows has an optimization whereas if you have a binary
+                 copy of a file to a single destination (ie concatenation) then it does not add
+                 the EOF, hence the check on the source copy type below.                       */
+              if (!destination->binarycopy && !anyconcats && !thiscopy->binarycopy) {
                 if (!WCMD_AppendEOF(outname)) {
                   WCMD_print_error ();
                   errorlevel = 1;
diff --git a/programs/cmd/tests/test_builtins.cmd b/programs/cmd/tests/test_builtins.cmd
index c7795bf..1956c3f 100644
--- a/programs/cmd/tests/test_builtins.cmd
+++ b/programs/cmd/tests/test_builtins.cmd
@@ -1911,6 +1911,10 @@ rem One file has EOF, but doesnt get an extra one, ie 6
 copy /b file1_plus_eof file123_mixed_copy7 /a >nul 2>&1
 call :CheckFileSize file123_mixed_copy7 6
 
+rem Syntax means concatenate so ascii destination kicks in
+copy /b file1_plus_eof* file123_mixed_copy8 /a >nul 2>&1
+call :CheckFileSize file123_mixed_copy8 7
+
 del *.* /q
 cd ..
 
diff --git a/programs/cmd/tests/test_builtins.cmd.exp b/programs/cmd/tests/test_builtins.cmd.exp
index 620e44b..f6e7d11 100644
--- a/programs/cmd/tests/test_builtins.cmd.exp
+++ b/programs/cmd/tests/test_builtins.cmd.exp
@@ -882,21 +882,22 @@ Passed: file size check on file1_default2 [5]@or_broken at Skipping file size check
 Passed: file size check on file1_plus_eof [6]@or_broken at Skipping file size check on NT4
 Passed: file size check on file2_plus_eof [9]@or_broken at Skipping file size check on NT4
 Passed: file size check on file3_plus_eof [12]@or_broken at Skipping file size check on NT4
- at todo_wine@Passed: file size check on file12_plus_eof [14]@or_broken at Skipping file size check on NT4
- at todo_wine@Passed: file size check on file12_no_eof [13]@or_broken at Skipping file size check on NT4
- at todo_wine@Passed: file size check on file12_eof2 [14]@or_broken at Skipping file size check on NT4
+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_binary_srccopy [6]@or_broken at Skipping file size check on NT4
- at todo_wine@Passed: file size check on file1_ascii_srccopy [5]@or_broken at Skipping file size check on NT4
- at todo_wine@Passed: file size check on file123_default_copy [25]@or_broken at Skipping file size check on NT4
- at todo_wine@Passed: file size check on file123_ascii_copy [25]@or_broken at Skipping file size check on NT4
- at todo_wine@Passed: file size check on file123_binary_copy [27]@or_broken at Skipping file size check on NT4
- at todo_wine@Passed: file size check on file123_mixed_copy1 [26]@or_broken at Skipping file size check on NT4
- at todo_wine@Passed: file size check on file123_mixed_copy2 [27]@or_broken at Skipping file size check on NT4
- at todo_wine@Passed: file size check on file123_mixed_copy3 [26]@or_broken at Skipping file size check on NT4
- at todo_wine@Passed: file size check on file123_mixed_copy4 [25]@or_broken at Skipping file size check on NT4
- at todo_wine@Passed: file size check on file123_mixed_copy5 [28]@or_broken at Skipping file size check on NT4
- at todo_wine@Passed: file size check on file123_mixed_copy6 [19]@or_broken at Skipping file size check on NT4
- at todo_wine@Passed: file size check on file123_mixed_copy7 [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
+Passed: file size check on file123_ascii_copy [25]@or_broken at Skipping file size check on NT4
+Passed: file size check on file123_binary_copy [27]@or_broken at Skipping file size check on NT4
+Passed: file size check on file123_mixed_copy1 [26]@or_broken at Skipping file size check on NT4
+Passed: file size check on file123_mixed_copy2 [27]@or_broken at Skipping file size check on NT4
+Passed: file size check on file123_mixed_copy3 [26]@or_broken at Skipping file size check on NT4
+Passed: file size check on file123_mixed_copy4 [25]@or_broken at Skipping file size check on NT4
+Passed: file size check on file123_mixed_copy5 [28]@or_broken at Skipping file size check on NT4
+Passed: file size check on file123_mixed_copy6 [19]@or_broken at Skipping file size check on NT4
+Passed: file size check on file123_mixed_copy7 [6]@or_broken at Skipping file size check on NT4
+Passed: file size check on file123_mixed_copy8 [7]@or_broken at Skipping file size check on NT4
 Passed: errorlevel invalid check 1
 Passed: Did not find dir1\file1
 Passed: errorlevel invalid check 2
-- 
1.7.9.5


More information about the wine-patches mailing list