From: Florian Eder Subject: [PATCH 28/41] robocopy: add min / max file size flag (/MIN, /MAX) Message-Id: <20210906145518.346132-28-others.meder@gmail.com> Date: Mon, 6 Sep 2021 14:55:05 +0000 In-Reply-To: <20210906145518.346132-1-others.meder@gmail.com> References: <20210906145518.346132-1-others.meder@gmail.com> Implements the /MIN:n and /MAX:n switches, which causes only files smaller or bigger than the set values to be included in any copy operation Signed-off-by: Florian Eder --- Both switches in one patch, as both are very closely connected and share some code --- programs/robocopy/main.c | 46 ++++++++++++++++++++++++++++++++++++ programs/robocopy/robocopy.h | 2 ++ 2 files changed, 48 insertions(+) diff --git a/programs/robocopy/main.c b/programs/robocopy/main.c index 4f1b07e8954..47ed5a12371 100644 --- a/programs/robocopy/main.c +++ b/programs/robocopy/main.c @@ -141,6 +141,7 @@ static void parse_arguments(int argc, WCHAR *argv[]) /* default values */ options.max_subdirectories_depth = 1; + options.max_size = MAXLONGLONG; for (i = 1; i < argc; i++) { @@ -216,6 +217,20 @@ static void parse_arguments(int argc, WCHAR *argv[]) options.user_limited_subdirectories_depth = TRUE; } } + /* max - Include only smaller files */ + else if (!wcsnicmp(argv[i], L"/max:", 5)) + { + LONGLONG value = 0; + if (swscanf(&(argv[i][5]), L"%lld", &value) == 1 && value >= 0) + options.max_size = value; + } + /* min - Include only bigger files */ + else if (!wcsnicmp(argv[i], L"/min:", 5)) + { + LONGLONG value = 0; + if (swscanf(&(argv[i][5]), L"%lld", &value) == 1 && value >= 0) + options.min_size = value; + } else { WINE_FIXME("encountered an unknown robocopy flag: %S\n", argv[i]); @@ -381,6 +396,24 @@ static void get_file_paths_in_folder(WCHAR *directory_path, struct list *paths, } } +static BOOL is_valid_file(WCHAR *source) +{ + HANDLE source_handle; + LARGE_INTEGER source_size; + 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); + /* ignore file if source is not within max / min size */ + if (source_size.QuadPart < options.min_size || + source_size.QuadPart > options.max_size) + { + CloseHandle(source_handle); + return FALSE; + } + CloseHandle(source_handle); + return TRUE; +} + static BOOL perform_copy(struct robocopy_statistics *statistics) { struct list paths_source, paths_destination; @@ -425,6 +458,9 @@ 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; + if (options.dry_run || copy_or_move_file(current_absolute_path, target_path, options.purge_source_files)) { output_message(options.purge_source_files ? STRING_MOVE_FILE : STRING_CREATE_FILE, strip_path_prefix(target_path)); @@ -532,6 +568,16 @@ static WCHAR *get_option_string(void) wcscat(temp_string, L"/MOV "); } + /* Max File Size */ + if (options.max_size != MAXLONGLONG) + swprintf(temp_string + wcslen(temp_string), ARRAY_SIZE(temp_string) - wcslen(temp_string), + L"/MAX:%lld ", options.max_size); + + /* Min File Size */ + if (options.min_size != 0) + swprintf(temp_string + wcslen(temp_string), ARRAY_SIZE(temp_string) - wcslen(temp_string), + L"/MIN:%lld ", options.min_size); + string = wcsdup(temp_string); return string; } diff --git a/programs/robocopy/robocopy.h b/programs/robocopy/robocopy.h index 9e3137109b8..0d498a9649c 100644 --- a/programs/robocopy/robocopy.h +++ b/programs/robocopy/robocopy.h @@ -46,6 +46,8 @@ struct robocopy_options { BOOL purge_destination; BOOL mirror; BOOL dry_run; + LONGLONG min_size; + LONGLONG max_size; }; struct robocopy_statistics { -- 2.32.0