Implements the /XN and /XO flags, which prevent older / newer files in the destination folder from being overwritten
Signed-off-by: Florian Eder others.meder@gmail.com --- programs/robocopy/main.c | 46 ++++++++++++++++++++++++++++++++---- programs/robocopy/robocopy.h | 2 ++ 2 files changed, 43 insertions(+), 5 deletions(-)
diff --git a/programs/robocopy/main.c b/programs/robocopy/main.c index 17d991e7435..2fc0c39503d 100644 --- a/programs/robocopy/main.c +++ b/programs/robocopy/main.c @@ -232,6 +232,16 @@ static void parse_arguments(int argc, WCHAR *argv[]) options.purge_source = TRUE; options.purge_source_files = TRUE; } + /* xn - Don't overwrite files that are newer (in the destination) */ + else if (!wcsicmp(argv[i], L"/xn")) + { + options.dont_overwrite_newer_files = TRUE; + } + /* xo - Don't overwrite files that are older (in the destination) */ + else if (!wcsicmp(argv[i], L"/xo")) + { + options.dont_overwrite_older_files = TRUE; + } /* xf - Excluded Files */ else if (!wcsicmp(argv[i], L"/xf")) { @@ -444,11 +454,12 @@ static void get_file_paths_in_folder(WCHAR *directory_path, struct list *paths, } }
-static BOOL is_valid_file(WCHAR *source) +static BOOL is_valid_file(WCHAR *source, WCHAR *destination) { - HANDLE source_handle; + HANDLE source_handle, destination_handle; LARGE_INTEGER source_size; - FILETIME source_creation_time, source_access_time, source_modified_time; + FILETIME source_creation_time, source_access_time, source_modified_time, + destination_creation_time, destination_access_time, destination_modified_time; source_handle = CreateFileW(source, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (source_handle == INVALID_HANDLE_VALUE) return FALSE; GetFileSizeEx(source_handle, &source_size); @@ -467,7 +478,24 @@ static BOOL is_valid_file(WCHAR *source) CloseHandle(source_handle); return FALSE; } + + destination_handle = CreateFileW(destination, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if (destination_handle == INVALID_HANDLE_VALUE) + { + CloseHandle(source_handle); + return TRUE; + } + GetFileTime(destination_handle, &destination_creation_time, &destination_access_time, &destination_modified_time); + /* don't overwrite newer or older files if set to do so */ + if ((options.dont_overwrite_newer_files && CompareFileTime(&source_creation_time, &destination_creation_time) > 0) || + (options.dont_overwrite_older_files && CompareFileTime(&source_creation_time, &destination_creation_time) < 0)) + { + CloseHandle(source_handle); + CloseHandle(destination_handle); + return FALSE; + } CloseHandle(source_handle); + CloseHandle(destination_handle); return TRUE; }
@@ -515,8 +543,8 @@ static BOOL perform_copy(struct robocopy_statistics *statistics) } else { - /* ignore file if the file size is not within the allowed limits */ - if (!is_valid_file(current_absolute_path)) continue; + /* ignore file if the file size is not within the allowed limits (or would cause an illegal overwrite) */ + if (!is_valid_file(current_absolute_path, target_path)) continue;
if (options.dry_run || copy_or_move_file(current_absolute_path, target_path, options.purge_source_files)) { @@ -626,6 +654,14 @@ static WCHAR *get_option_string(void) wcscat(temp_string, L"/MOV "); }
+ /* Ignore newer files */ + if (options.dont_overwrite_newer_files) + wcscat(temp_string, L"/XN "); + + /* Ignore older files */ + if (options.dont_overwrite_older_files) + wcscat(temp_string, L"/XO "); + /* Max File Size */ if (options.max_size != MAXLONGLONG) swprintf(temp_string + wcslen(temp_string), ARRAY_SIZE(temp_string) - wcslen(temp_string), diff --git a/programs/robocopy/robocopy.h b/programs/robocopy/robocopy.h index 27c32d20262..cf396f88dfc 100644 --- a/programs/robocopy/robocopy.h +++ b/programs/robocopy/robocopy.h @@ -50,6 +50,8 @@ struct robocopy_options { LONGLONG max_size; FILETIME min_time; FILETIME max_time; + BOOL dont_overwrite_newer_files; + BOOL dont_overwrite_older_files; };
struct robocopy_statistics {