[PATCH v7 4/4] robocopy: Add basic output

Florian Eder others.meder at gmail.com
Sat Oct 16 06:13:43 CDT 2021


Adds output methods to output copied files and errors

Signed-off-by: Florian Eder <others.meder at gmail.com>
---
v7: More or less equal to patch 3 and parts of patch 4 from v6
---
 programs/robocopy/main.c      | 87 +++++++++++++++++++++++++++++++++--
 programs/robocopy/robocopy.h  | 24 ++++++++++
 programs/robocopy/robocopy.rc | 13 ++++++
 3 files changed, 120 insertions(+), 4 deletions(-)
 create mode 100644 programs/robocopy/robocopy.h

diff --git a/programs/robocopy/main.c b/programs/robocopy/main.c
index 6e19170712d..ca3388d7ad0 100644
--- a/programs/robocopy/main.c
+++ b/programs/robocopy/main.c
@@ -26,6 +26,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(robocopy);
 #include <shlwapi.h>
 #include <wine/list.h>
 
+#include "robocopy.h"
+
 struct path_array
 {
     UINT size;
@@ -50,6 +52,62 @@ struct robocopy_options
 
 struct robocopy_options options;
 
+static const WCHAR *format_string(UINT format_string_id)
+{
+    WCHAR format_string[2048];
+    if (!LoadStringW(GetModuleHandleW(NULL), format_string_id, format_string, ARRAY_SIZE(format_string)))
+    {
+        WINE_ERR("invalid string loaded");
+        return L"";
+    }
+    return wcsdup(format_string);
+}
+
+static void output_message(const WCHAR *format_string, ...)
+{
+    __ms_va_list va_args;
+    WCHAR *string;
+    DWORD length, bytes_written;
+
+    __ms_va_start(va_args, format_string);
+    length = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
+                            format_string, 0, 0, (WCHAR *)&string, 0, &va_args);
+    __ms_va_end(va_args);
+    if (!length)
+    {
+        WINE_ERR("string formation failed");
+        return;
+    }
+
+    /* If WriteConsole fails, the output is being redirected to a file */
+    if (!WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), string, wcslen(string), &bytes_written, NULL))
+    {
+        CHAR *string_multibyte;
+        DWORD length_multibyte;
+
+        length_multibyte = WideCharToMultiByte(GetConsoleOutputCP(), 0, string, wcslen(string), NULL, 0, NULL, NULL);
+        string_multibyte = malloc(length_multibyte);
+
+        WideCharToMultiByte(GetConsoleOutputCP(), 0, string, wcslen(string), string_multibyte, length_multibyte, NULL, NULL);
+        WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), string_multibyte, length_multibyte, &bytes_written, NULL);
+        free(string_multibyte);
+    }
+
+    LocalFree(string);
+}
+
+static void output_error(UINT format_string_id, HRESULT error_code, WCHAR* path)
+{
+    WCHAR *error_string;
+
+    FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
+                   NULL, error_code, 0, (WCHAR *)&error_string, 0, NULL);
+
+    output_message(format_string(format_string_id), path, error_string);
+
+    LocalFree(error_string);
+}
+
 static WCHAR *get_absolute_path(const WCHAR *path)
 {
     DWORD size;
@@ -80,7 +138,16 @@ static BOOL create_directory_path(WCHAR *path)
     while (pointer != NULL)
     {
         if (!lstrcpynW(current_folder, path, pointer - path + 2)) return FALSE;
-        if (!CreateDirectoryW(current_folder, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) return FALSE;
+        if (!CreateDirectoryW(current_folder, NULL))
+        {
+            if (GetLastError() != ERROR_ALREADY_EXISTS)
+            {
+                output_error(STRING_ERROR_WRITE_DIRECTORY, GetLastError(), current_folder);
+                return FALSE;
+            }
+        }
+        else
+            output_message(format_string(STRING_CREATE_DIRECTORY), current_folder);
         pointer = wcschr(pointer + 1, L'\\');
     }
     return TRUE;
@@ -140,7 +207,11 @@ static BOOL perform_copy(void)
 
     list_init(&paths_source);
 
-    if (!PathIsDirectoryW(options.source)) return FALSE;
+    if (!PathIsDirectoryW(options.source))
+    {
+        output_error(STRING_ERROR_READ_DIRECTORY, ERROR_FILE_NOT_FOUND, options.source);
+        return FALSE;
+    }
 
     create_directory_path(options.destination);
 
@@ -158,10 +229,18 @@ static BOOL perform_copy(void)
                          PATHCCH_ALLOW_LONG_PATHS | PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS,
                          &target_path);
 
-        if (!PathIsDirectoryW(current_absolute_path))
+        if (PathIsDirectoryW(current_absolute_path))
+        {
+            if (!create_directory_path(target_path))
+                output_error(STRING_ERROR_WRITE_DIRECTORY, GetLastError(), target_path);
+        }
+        else
         {
             create_directory_path(target_path);
-            CopyFileW(current_absolute_path, target_path, FALSE);
+            if (!CopyFileW(current_absolute_path, target_path, FALSE))
+                output_error(STRING_ERROR_WRITE_FILE, GetLastError(), target_path);
+            else
+                output_message(format_string(STRING_CREATE_FILE), target_path);
         }
     }
     return TRUE;
diff --git a/programs/robocopy/robocopy.h b/programs/robocopy/robocopy.h
new file mode 100644
index 00000000000..4add81dd208
--- /dev/null
+++ b/programs/robocopy/robocopy.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2021 Florian Eder
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define STRING_MISSING_DESTINATION_OR_SOURCE  1010
+#define STRING_ERROR_READ_DIRECTORY           1011
+#define STRING_ERROR_WRITE_DIRECTORY          1012
+#define STRING_ERROR_WRITE_FILE               1014
+#define STRING_CREATE_DIRECTORY               1019
+#define STRING_CREATE_FILE                    1022
diff --git a/programs/robocopy/robocopy.rc b/programs/robocopy/robocopy.rc
index edae5b71d86..92dc8796d8c 100644
--- a/programs/robocopy/robocopy.rc
+++ b/programs/robocopy/robocopy.rc
@@ -17,9 +17,22 @@
  */
 
 #include <windef.h>
+#include "robocopy.h"
 
 #pragma makedep po
 
+LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
+
+STRINGTABLE
+{
+    STRING_MISSING_DESTINATION_OR_SOURCE, "No destination or source specified, can't copy anything\n"
+    STRING_ERROR_READ_DIRECTORY, "Error occurred reading directory \"%1\":\n%2\n"
+    STRING_ERROR_WRITE_DIRECTORY, "Error occurred writing directory \"%1\":\n%2\n"
+    STRING_ERROR_WRITE_FILE, "Error occurred writing file \"%1\":\n%2\n"
+    STRING_CREATE_DIRECTORY, " Created Dir: %1\n"
+    STRING_CREATE_FILE, " Copied File: %1\n"
+}
+
 LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
 
 #define WINE_FILEDESCRIPTION_STR "Wine Robocopy"
-- 
2.32.0




More information about the wine-devel mailing list