[PATCH 30/41] robocopy: add min / max age of file flag (/MINAGE, /MAXAGE)

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


Implements the /MINAGE and /MAXAGE flags, which causes only files
older or newer than the set values to be included in any copy operation

Signed-off-by: Florian Eder <others.meder at gmail.com>
---
Again, both switches in one patch, as both are tightly connected
---
 programs/robocopy/main.c     | 70 ++++++++++++++++++++++++++++++++++++
 programs/robocopy/robocopy.h |  2 ++
 2 files changed, 72 insertions(+)

diff --git a/programs/robocopy/main.c b/programs/robocopy/main.c
index 47ed5a12371..17d991e7435 100644
--- a/programs/robocopy/main.c
+++ b/programs/robocopy/main.c
@@ -129,6 +129,44 @@ WCHAR *get_absolute_path_with_trailing_backslash(WCHAR *path)
     return absolute_path;
 }
 
+static void parse_date_to_filetime(const WCHAR *date_string, FILETIME *filetime_pointer)
+{
+    /*
+     * robocopy interprets values between [0, 1899] as a relative offset (in days) from the current date,
+     * otherwise as an absolute date in the YYYYMMDD format (regardless of user locale)
+     */
+    long value;
+    FILETIME time;
+    value = wcstol(date_string, NULL, 10);
+    if (value >= 0 && value < 1900)
+    {
+        /* relative offset of n days into the past */
+        LARGE_INTEGER time_as_integer;
+        GetSystemTimeAsFileTime(&time);
+        /* FILETIME is no union with LONGLONG / LONG64, casting could be unsafe */
+        time_as_integer.HighPart = time.dwHighDateTime;
+        time_as_integer.LowPart = time.dwLowDateTime;
+        /* 1000 * 1000 * 60 * 60 * 24 = 86400000000ns per day */
+        time_as_integer.QuadPart -= 864000000000LL * value;
+        filetime_pointer->dwHighDateTime = time_as_integer.HighPart;
+        filetime_pointer->dwLowDateTime = time_as_integer.LowPart;
+    }
+    else if (value >= 19000101 && value <= 99991231)
+    {
+        /* absolute date in YYYYMMDD format */
+        SYSTEMTIME time_as_systemtime;
+        memset(&time_as_systemtime, 0, sizeof(time_as_systemtime));
+        if (swscanf(date_string, L"%4hu%2hu%2hu", &time_as_systemtime.wYear, &time_as_systemtime.wMonth, &time_as_systemtime.wDay) == 3 &&
+            time_as_systemtime.wMonth > 0 && time_as_systemtime.wMonth <= 12 &&
+            time_as_systemtime.wDay > 0 && time_as_systemtime.wDay <= 31 &&
+            SystemTimeToFileTime(&time_as_systemtime, &time))
+        {
+            filetime_pointer->dwHighDateTime = time.dwHighDateTime;
+            filetime_pointer->dwLowDateTime = time.dwLowDateTime;
+        }
+    }
+}
+
 static void parse_arguments(int argc, WCHAR *argv[])
 {
     int i;
@@ -231,6 +269,16 @@ static void parse_arguments(int argc, WCHAR *argv[])
                 if (swscanf(&(argv[i][5]), L"%lld", &value) == 1 && value >= 0)
                     options.min_size = value;
             }
+            /* maxage - Include only newer files */
+            else if (!wcsnicmp(argv[i], L"/maxage:", 8))
+            {
+                parse_date_to_filetime(&(argv[i][8]), &options.max_time);
+            }
+            /* minage - Include only older files */
+            else if (!wcsnicmp(argv[i], L"/minage:", 8))
+            {
+                parse_date_to_filetime(&(argv[i][8]), &options.min_time);
+            }
             else
             {
                 WINE_FIXME("encountered an unknown robocopy flag: %S\n", argv[i]);
@@ -400,6 +448,7 @@ static BOOL is_valid_file(WCHAR *source)
 {
     HANDLE source_handle;
     LARGE_INTEGER source_size;
+    FILETIME source_creation_time, source_access_time, source_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);
@@ -410,6 +459,14 @@ static BOOL is_valid_file(WCHAR *source)
         CloseHandle(source_handle);
         return FALSE;
     }
+    GetFileTime(source_handle, &source_creation_time, &source_access_time, &source_modified_time);
+    /* ignore file if source is not within max / min age (if set) */
+    if ((options.min_time.dwHighDateTime != 0 && CompareFileTime(&source_creation_time, &options.min_time) > 0) ||
+        (options.max_time.dwHighDateTime != 0 && CompareFileTime(&source_creation_time, &options.max_time) < 0))
+    {
+        CloseHandle(source_handle);
+        return FALSE;
+    }
     CloseHandle(source_handle);
     return TRUE;
 }
@@ -526,6 +583,7 @@ static BOOL perform_copy(struct robocopy_statistics *statistics)
 
 static WCHAR *get_option_string(void)
 {
+    SYSTEMTIME time;
     WCHAR *string, temp_string[512];
     memset(temp_string, 0, sizeof(temp_string));
 
@@ -578,6 +636,18 @@ static WCHAR *get_option_string(void)
         swprintf(temp_string + wcslen(temp_string), ARRAY_SIZE(temp_string) - wcslen(temp_string),
                  L"/MIN:%lld ", options.min_size);
 
+    /* Min Age*/
+    if (options.min_time.dwHighDateTime != 0)
+        if (FileTimeToSystemTime(&options.min_time, &time))
+            swprintf(temp_string + wcslen(temp_string), ARRAY_SIZE(temp_string) - wcslen(temp_string),
+                     L"/MINAGE:%hu-%02hu-%02hu ", time.wYear, time.wMonth, time.wDay);
+
+    /* Max Age */
+    if (options.max_time.dwHighDateTime != 0)
+        if (FileTimeToSystemTime(&options.max_time, &time))
+            swprintf(temp_string + wcslen(temp_string), ARRAY_SIZE(temp_string) - wcslen(temp_string),
+                     L"/MAXAGE:%hu-%02hu-%02hu ", time.wYear, time.wMonth, time.wDay);
+
     string = wcsdup(temp_string);
     return string;
 }
diff --git a/programs/robocopy/robocopy.h b/programs/robocopy/robocopy.h
index 0d498a9649c..27c32d20262 100644
--- a/programs/robocopy/robocopy.h
+++ b/programs/robocopy/robocopy.h
@@ -48,6 +48,8 @@ struct robocopy_options {
     BOOL dry_run;
     LONGLONG min_size;
     LONGLONG max_size;
+    FILETIME min_time;
+    FILETIME max_time;
 };
 
 struct robocopy_statistics {
-- 
2.32.0




More information about the wine-devel mailing list