[PATCH 23/41] robocopy: add excluded file / directory parser (/XF, /XD)

Florian Eder others.meder at gmail.com
Mon Sep 6 09:55:00 CDT 2021


Implements the /XF and /XD switches, which set file and directory names that
are excluded from any robocopy operation

Signed-off-by: Florian Eder <others.meder at gmail.com>
---
Both switches in one patch because the code is almost identical for both
---
 programs/robocopy/main.c      | 46 +++++++++++++++++++++++++++++++++--
 programs/robocopy/robocopy.h  |  4 +++
 programs/robocopy/robocopy.rc |  2 ++
 3 files changed, 50 insertions(+), 2 deletions(-)

diff --git a/programs/robocopy/main.c b/programs/robocopy/main.c
index 1cfbe65e94b..41ed29f1725 100644
--- a/programs/robocopy/main.c
+++ b/programs/robocopy/main.c
@@ -132,9 +132,12 @@ WCHAR *get_absolute_path_with_trailing_backslash(WCHAR *path)
 static void parse_arguments(int argc, WCHAR *argv[])
 {
     int i;
+    BOOL is_xd = FALSE, is_xf = FALSE;
 
     memset(&options, 0, sizeof(options));
     options.files = calloc(1, offsetof(struct path_array, array) + (argc * sizeof(WCHAR*)));
+    options.excluded_filenames = calloc(1, offsetof(struct path_array, array) + (argc * sizeof(WCHAR*)));
+    options.excluded_directories = calloc(1, offsetof(struct path_array, array) + (argc * sizeof(WCHAR*)));
 
     /* default values */
     options.max_subdirectories_depth = 1;
@@ -142,6 +145,8 @@ static void parse_arguments(int argc, WCHAR *argv[])
     for (i = 1; i < argc; i++)
     {
         if (is_valid_robocopy_flag(argv[i]))
+        {
+            is_xd = FALSE; is_xf = FALSE;
             /* s - Copy Subdirectories */
             if (!wcsicmp(argv[i], L"/s"))
             {
@@ -183,6 +188,18 @@ static void parse_arguments(int argc, WCHAR *argv[])
                 options.purge_source = TRUE;
                 options.purge_source_files = TRUE;
             }
+            /* xf - Excluded Files */
+            else if (!wcsicmp(argv[i], L"/xf"))
+            {
+                /* xf includes all following files, until the next option / flag */
+                is_xf = TRUE;
+            }
+            /* xd - Excluded Directories */
+            else if (!wcsicmp(argv[i], L"/xd"))
+            {
+                /* xd includes all following directories, until the next option / flag */
+                is_xd = TRUE;
+            }
             /* lev - Limit depth of subdirectories */
             else if (!wcsnicmp(argv[i], L"/lev:", 5))
             {
@@ -198,13 +215,26 @@ static void parse_arguments(int argc, WCHAR *argv[])
             {
                 WINE_FIXME("encountered an unknown robocopy flag: %S\n", argv[i]);
             }
+        }
         else
         {
             /*
             *(Probably) not a flag, we can parse it as the source / the destination / a filename
-            * Priority: Source > Destination > (more than one) File
+            * Priority: Excluded > Source > Destination > (more than one) File
             */
-            if (!options.source)
+            if (is_xf)
+            {
+                options.excluded_filenames->array[options.excluded_filenames->size] = calloc(wcslen(argv[i]) + 1, sizeof(WCHAR));
+                wcscpy(options.excluded_filenames->array[options.excluded_filenames->size], argv[i]);
+                options.excluded_filenames->size++;
+            }
+            else if (is_xd)
+            {
+                options.excluded_directories->array[options.excluded_directories->size] = calloc(wcslen(argv[i]) + 1, sizeof(WCHAR));
+                wcscpy(options.excluded_directories->array[options.excluded_directories->size], argv[i]);
+                options.excluded_directories->size++;
+            }
+            else if (!options.source)
             {
                 options.source = get_absolute_path_with_trailing_backslash(argv[i]);
             }
@@ -327,6 +357,10 @@ static void get_file_paths_in_folder(WCHAR *directory_path, struct list *paths,
                 current_relative_path = get_combined_path(current_path->name, entry_data.cFileName);
                 current_absolute_path = get_combined_path(directory_path, current_relative_path);
 
+                /* Ignore if it's an excluded folder or file */
+                if (matches_array_entry(entry_data.cFileName, PathIsDirectoryW(current_absolute_path) ?
+                                                              options.excluded_directories : options.excluded_filenames)) continue;
+
                 /* If this entry is a matching file or empty directory, add it to the list of results */
                 if ((!PathIsDirectoryW(current_absolute_path) && matches_array_entry(entry_data.cFileName, options.files)) ||
                      (PathIsDirectoryW(current_absolute_path) && (!depth || depth > current_path->level)))
@@ -509,6 +543,14 @@ static void print_header(void)
     for (i = 1; i < options.files->size; i++)
         output_message(STRING_ADDITIONAL_INFO, options.files->array[i]);
 
+    if (options.excluded_filenames->size > 0) output_message(STRING_EXCLUDED_FILES, options.excluded_filenames->array[0]);
+    for (i = 1; i < options.excluded_filenames->size; i++)
+        output_message(STRING_ADDITIONAL_INFO, options.excluded_filenames->array[i]);
+
+    if (options.excluded_directories->size > 0) output_message(STRING_EXCLUDED_DIRECTORIES, options.excluded_directories->array[0]);
+    for (i = 1; i < options.excluded_directories->size; i++)
+        output_message(STRING_ADDITIONAL_INFO, options.excluded_directories->array[i]);
+
     options_string = get_option_string();
     if (options_string != NULL) output_message(STRING_OPTIONS, options_string);
 }
diff --git a/programs/robocopy/robocopy.h b/programs/robocopy/robocopy.h
index aa58240d8cc..1818fdf90f1 100644
--- a/programs/robocopy/robocopy.h
+++ b/programs/robocopy/robocopy.h
@@ -35,6 +35,8 @@ struct robocopy_options {
     WCHAR *destination;
     WCHAR *source;
     struct path_array* files;
+    struct path_array* excluded_filenames;
+    struct path_array* excluded_directories;
     UINT max_subdirectories_depth;
     BOOL user_limited_subdirectories_depth;
     BOOL copy_subdirectories;
@@ -62,6 +64,8 @@ struct robocopy_statistics {
 #define STRING_SOURCE                         1003
 #define STRING_DESTINATION                    1004
 #define STRING_FILES                          1005
+#define STRING_EXCLUDED_FILES                 1006
+#define STRING_EXCLUDED_DIRECTORIES           1007
 #define STRING_ADDITIONAL_INFO                1008
 #define STRING_OPTIONS                        1009
 #define STRING_MISSING_DESTINATION_OR_SOURCE  1010
diff --git a/programs/robocopy/robocopy.rc b/programs/robocopy/robocopy.rc
index cdb03085315..315dce5f947 100644
--- a/programs/robocopy/robocopy.rc
+++ b/programs/robocopy/robocopy.rc
@@ -29,6 +29,8 @@ STRINGTABLE
     STRING_SOURCE, "         Source: %1\n"
     STRING_DESTINATION, "    Destination: %1\n\n"
     STRING_FILES, "          Files: %1\n"
+    STRING_EXCLUDED_FILES, "\n Excluded Files: %1\n"
+    STRING_EXCLUDED_DIRECTORIES, "\n  Excluded Dirs: %1\n"
     STRING_ADDITIONAL_INFO, "                 %1\n"
     STRING_OPTIONS, "\n        Options: %1\n\n"
     STRING_MISSING_DESTINATION_OR_SOURCE, "No destination or source specified, can't copy anything\n"
-- 
2.32.0




More information about the wine-devel mailing list