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@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"