Files
FSI.BT.IR.Tools/RoboSharp/CopyOptions.cs
Stephan Maier 647f938eee v1.2
2024-08-27 08:10:27 +02:00

685 lines
31 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Runtime.CompilerServices;
namespace RoboSharp
{
/// <summary>
/// Source, Destination, and options for how to move or copy files.
/// </summary>
/// <remarks>
/// <see href="https://github.com/tjscience/RoboSharp/wiki/CopyOptions"/>
/// </remarks>
public class CopyOptions : ICloneable
{
#region Constructors
/// <summary>
/// Create new CopyOptions with Default Settings
/// </summary>
public CopyOptions() { }
/// <summary>
/// Create a new CopyOptions object with the provided settings
/// </summary>
/// <param name="source"><inheritdoc cref="Source" path="*"/></param>
/// <param name="destination"><inheritdoc cref="Destination" path="*"/></param>
/// <param name="flags"><inheritdoc cref="CopyActionFlags" path="*"/></param>
public CopyOptions(string source, string destination, CopyActionFlags flags)
{
this.Source = source ?? string.Empty;
this.Destination = destination ?? string.Empty;
this.ApplyActionFlags(flags);
}
/// <summary>
/// Clone a CopyOptions Object
/// </summary>
/// <param name="copyOptions">CopyOptions object to clone</param>
/// <param name="NewSource">Specify a new source if desired. If left as null, will use Source from <paramref name="copyOptions"/></param>
/// <param name="NewDestination">Specify a new source if desired. If left as null, will use Destination from <paramref name="copyOptions"/></param>
public CopyOptions(CopyOptions copyOptions, string NewSource = null, string NewDestination = null)
{
Source = NewSource ?? copyOptions.Source;
Destination = NewDestination ?? copyOptions.Destination;
AddAttributes = copyOptions.AddAttributes;
CheckPerFile = copyOptions.CheckPerFile;
CopyAll = copyOptions.CopyAll;
CopyFilesWithSecurity = copyOptions.CopyFilesWithSecurity;
CopyFlags = copyOptions.CopyFlags;
CopySubdirectories = copyOptions.CopySubdirectories;
CopySubdirectoriesIncludingEmpty = copyOptions.CopySubdirectoriesIncludingEmpty;
CopySymbolicLink = copyOptions.CopySymbolicLink;
CreateDirectoryAndFileTree = copyOptions.CreateDirectoryAndFileTree;
Depth = copyOptions.Depth;
DirectoryCopyFlags = copyOptions.DirectoryCopyFlags;
DoNotCopyDirectoryInfo = copyOptions.DoNotCopyDirectoryInfo;
DoNotUseWindowsCopyOffload = copyOptions.DoNotUseWindowsCopyOffload;
EnableBackupMode = copyOptions.EnableBackupMode;
EnableEfsRawMode = copyOptions.EnableEfsRawMode;
EnableRestartMode = copyOptions.EnableRestartMode;
EnableRestartModeWithBackupFallback = copyOptions.EnableRestartModeWithBackupFallback;
FatFiles = copyOptions.FatFiles;
FileFilter = copyOptions.FileFilter;
FixFileSecurityOnAllFiles = copyOptions.FixFileSecurityOnAllFiles;
FixFileTimesOnAllFiles = copyOptions.FixFileTimesOnAllFiles;
InterPacketGap = copyOptions.InterPacketGap;
Mirror = copyOptions.Mirror;
MonitorSourceChangesLimit = copyOptions.MonitorSourceChangesLimit;
MonitorSourceTimeLimit = copyOptions.MonitorSourceTimeLimit;
MoveFiles = copyOptions.MoveFiles;
MoveFilesAndDirectories = copyOptions.MoveFilesAndDirectories;
MultiThreadedCopiesCount = copyOptions.MultiThreadedCopiesCount;
Purge = copyOptions.Purge;
RemoveAttributes = copyOptions.RemoveAttributes;
RemoveFileInformation = copyOptions.RemoveFileInformation;
RunHours = copyOptions.RunHours;
TurnLongPathSupportOff = copyOptions.TurnLongPathSupportOff;
UseUnbufferedIo = copyOptions.UseUnbufferedIo;
}
/// <inheritdoc cref="CopyOptions.CopyOptions(CopyOptions, string, string)"/>
public CopyOptions Clone(string NewSource = null, string NewDestination = null) => new CopyOptions(this, NewSource, NewDestination);
object ICloneable.Clone() => Clone();
#endregion
#region Option Constants
internal const string COPY_SUBDIRECTORIES = "/S ";
internal const string COPY_SUBDIRECTORIES_INCLUDING_EMPTY = "/E ";
internal const string DEPTH = "/LEV:{0} ";
internal const string ENABLE_RESTART_MODE = "/Z ";
internal const string ENABLE_BACKUP_MODE = "/B ";
internal const string ENABLE_RESTART_MODE_WITH_BACKUP_FALLBACK = "/ZB ";
internal const string USE_UNBUFFERED_IO = "/J ";
internal const string ENABLE_EFSRAW_MODE = "/EFSRAW ";
internal const string COPY_FLAGS = "/COPY:{0} ";
internal const string COPY_FILES_WITH_SECURITY = "/SEC ";
internal const string COPY_ALL = "/COPYALL ";
internal const string REMOVE_FILE_INFORMATION = "/NOCOPY ";
internal const string FIX_FILE_SECURITY_ON_ALL_FILES = "/SECFIX ";
internal const string FIX_FILE_TIMES_ON_ALL_FILES = "/TIMFIX ";
internal const string PURGE = "/PURGE ";
internal const string MIRROR = "/MIR ";
internal const string MOVE_FILES = "/MOV ";
internal const string MOVE_FILES_AND_DIRECTORIES = "/MOVE ";
internal const string ADD_ATTRIBUTES = "/A+:{0} ";
internal const string REMOVE_ATTRIBUTES = "/A-:{0} ";
internal const string CREATE_DIRECTORY_AND_FILE_TREE = "/CREATE ";
internal const string FAT_FILES = "/FAT ";
internal const string TURN_LONG_PATH_SUPPORT_OFF = "/256 ";
internal const string MONITOR_SOURCE_CHANGES_LIMIT = "/MON:{0} ";
internal const string MONITOR_SOURCE_TIME_LIMIT = "/MOT:{0} ";
internal const string RUN_HOURS = "/RH:{0} ";
internal const string CHECK_PER_FILE = "/PF ";
internal const string INTER_PACKET_GAP = "/IPG:{0} ";
internal const string COPY_SYMBOLIC_LINK = "/SL ";
internal const string MULTITHREADED_COPIES_COUNT = "/MT:{0} ";
internal const string DIRECTORY_COPY_FLAGS = "/DCOPY:{0} ";
internal const string DO_NOT_COPY_DIRECTORY_INFO = "/NODCOPY ";
internal const string DO_NOT_USE_WINDOWS_COPY_OFFLOAD = "/NOOFFLOAD ";
#endregion Option Constants
#region Option Defaults
/// <summary>
/// The Default File Filter used that will allow copying of all files
/// </summary>
public const string DefaultFileFilter = "*.*" ;
private IEnumerable<string> fileFilter = new[] { DefaultFileFilter };
private string copyFlags = "DAT";
private string directoryCopyFlags = VersionManager.Version >= 6.2 ? "DA" : "T";
#endregion Option Defaults
#region Public Properties
/// <summary>
/// The source file path where the RoboCommand is copying files from.
/// </summary>
public virtual string Source { get { return _source; } set { _source = value.CleanDirectoryPath(); } }
private string _source;
/// <summary>
/// The destination file path where the RoboCommand is copying files to.
/// </summary>
public virtual string Destination { get { return _destination; } set { _destination = value.CleanDirectoryPath(); } }
private string _destination;
/// <summary>
/// Allows you to supply a set of files to copy or use wildcard characters (* or ?). <br/>
/// JobOptions file saves these into the /IF (Include Files) section
/// </summary>
public IEnumerable<string> FileFilter
{
get
{
return fileFilter;
}
set
{
fileFilter = value;
}
}
/// <summary>
/// Copies subdirectories. Note that this option excludes empty directories.
/// [/S]
/// </summary>
public virtual bool CopySubdirectories { get; set; }
/// <summary>
/// Copies subdirectories. Note that this option includes empty directories.
/// [/E]
/// </summary>
public virtual bool CopySubdirectoriesIncludingEmpty { get; set; }
/// <summary>
/// Copies only the top N levels of the source directory tree. The default is
/// zero which does not limit the depth.
/// [/LEV:N]
/// </summary>
public virtual int Depth { get; set; }
/// <summary>
/// Copies files in Restart mode.
/// [/Z]
/// </summary>
public virtual bool EnableRestartMode { get; set; }
/// <summary>
/// Copies files in Backup mode.
/// [/B]
/// </summary>
public virtual bool EnableBackupMode { get; set; }
/// <summary>
/// Uses Restart mode. If access is denied, this option uses Backup mode.
/// [/ZB]
/// </summary>
public virtual bool EnableRestartModeWithBackupFallback { get; set; }
/// <summary>
/// Copy using unbuffered I/O (recommended for large files).
/// [/J]
/// </summary>
public virtual bool UseUnbufferedIo { get; set; }
/// <summary>
/// Copies all encrypted files in EFS RAW mode.
/// [/EFSRAW]
/// </summary>
public virtual bool EnableEfsRawMode { get; set; }
/// <summary>
/// This property should be set to a string consisting of all the flags to include (eg. DAT; DATSOU)
/// Specifies the file properties to be copied. The following are the valid values for this option:
///D Data
///A Attributes
///T Time stamps
///S NTFS access control list (ACL)
///O Owner information
///U Auditing information
///The default value for copyflags is DAT (data, attributes, and time stamps).
///[/COPY:copyflags]
/// </summary>
public string CopyFlags
{
get
{
return copyFlags;
}
set => copyFlags = value;
}
/// <summary>
/// Copies files with security (equivalent to /copy:DAT).
/// [/SEC]
/// </summary>
public virtual bool CopyFilesWithSecurity { get; set; }
/// <summary>
/// Copies all file information (equivalent to /copy:DATSOU).
/// [/COPYALL]
/// </summary>
public virtual bool CopyAll { get; set; }
/// <summary>
/// Copies no file information (useful with Purge option).
/// [/NOCOPY]
/// </summary>
public virtual bool RemoveFileInformation { get; set; }
/// <summary>
/// Fixes file security on all files, even skipped ones.
/// [/SECFIX]
/// </summary>
public virtual bool FixFileSecurityOnAllFiles { get; set; }
/// <summary>
/// Fixes file times on all files, even skipped ones.
/// [/TIMFIX]
/// </summary>
public virtual bool FixFileTimesOnAllFiles { get; set; }
/// <summary>
/// Deletes destination files and directories that no longer exist in the source.
/// [/PURGE]
/// </summary>
public virtual bool Purge { get; set; }
/// <summary>
/// Mirrors a directory tree (equivalent to CopySubdirectoriesIncludingEmpty plus Purge).
/// [/MIR]
/// </summary>
public virtual bool Mirror { get; set; }
/// <summary>
/// Moves files, and deletes them from the source after they are copied.
/// [/MOV]
/// </summary>
public virtual bool MoveFiles { get; set; }
/// <summary>
/// Moves files and directories, and deletes them from the source after they are copied.
/// [/MOVE]
/// </summary>
public virtual bool MoveFilesAndDirectories { get; set; }
/// <summary>
/// This property should be set to a string consisting of all the attributes to add (eg. AH; RASHCNET).
/// Adds the specified attributes to copied files.
/// [/A+:attributes]
/// </summary>
public string AddAttributes { get; set; }
/// <summary>
/// This property should be set to a string consisting of all the attributes to remove (eg. AH; RASHCNET).
/// Removes the specified attributes from copied files.
/// [/A-:attributes]
/// </summary>
public string RemoveAttributes { get; set; }
/// <summary>
/// Creates a directory tree and zero-length files only.
/// [/CREATE]
/// </summary>
public virtual bool CreateDirectoryAndFileTree { get; set; }
/// <summary>
/// Creates destination files by using 8.3 character-length FAT file names only.
/// [/FAT]
/// </summary>
public virtual bool FatFiles { get; set; }
/// <summary>
/// Turns off support for very long paths (longer than 256 characters).
/// [/256]
/// </summary>
public virtual bool TurnLongPathSupportOff { get; set; }
/// <summary>
/// The default value of zero indicates that you do not wish to monitor for changes.
/// Monitors the source, and runs again when more than N changes are detected.
/// [/MON:N]
/// </summary>
public virtual int MonitorSourceChangesLimit { get; set; }
/// <summary>
/// The default value of zero indicates that you do not wish to monitor for changes.
/// Monitors source, and runs again in M minutes if changes are detected.
/// [/MOT:M]
/// </summary>
public virtual int MonitorSourceTimeLimit { get; set; }
/// <summary>
/// Specifies run times when new copies may be started. ( Copy Operation is scheduled to only operate within specified timeframe )
/// [/rh:hhmm-hhmm] <br/>
/// If copy operation is unfinished, robocopy will remain active in idle state until the specified time, at which it will resume copying.<br/>
/// Must be in correct format. Incorrectly formatted strings will be ignored. <para/>
/// Examples:<br/>
/// 1500-1800 -> Robocopy will only copy between 3 PM and 5 PM <br/>
/// 0015-0530 -> Robocopy will only copy between 12:15 AM and 5:30 AM <br/>
/// </summary>
/// <remarks>
/// If this is set up, then the robocopy process will remain active after the program exits if the calling asemmbly does not call <see cref="RoboCommand.Stop()"/> prior to exiting the application.
/// </remarks>
public string RunHours
{
get => runHours;
set
{
if (String.IsNullOrWhiteSpace(value))
runHours = value?.Trim() ?? string.Empty;
else if (CheckRunHoursString(value))
runHours = value.Trim();
}
}
private string runHours;
/// <summary>
/// Checks the scheduled /RH (run hours) per file instead of per pass.
/// [/PF]
/// </summary>
public virtual bool CheckPerFile { get; set; }
/// <summary>
/// The default value of zero indicates that this feature is turned off.
/// Specifies the inter-packet gap to free bandwidth on slow lines.
/// [/IPG:N]
/// </summary>
public virtual int InterPacketGap { get; set; }
/// <summary>
/// Copies the symbolic link instead of the target.
/// [/SL]
/// </summary>
public virtual bool CopySymbolicLink { get; set; }
/// <summary>
/// The default value of zero indicates that this feature is turned off.
/// Creates multi-threaded copies with N threads. Must be an integer between 1 and 128.
/// The MultiThreadedCopiesCount parameter cannot be used with the /IPG and EnableEfsRawMode parameters.
/// [/MT:N]
/// </summary>
public virtual int MultiThreadedCopiesCount { get; set; }
/// <summary>
/// What to copy for directories (default is DA).
/// (copyflags: D=Data, A=Attributes, T=Timestamps).
/// [/DCOPY:copyflags]
/// </summary>
public string DirectoryCopyFlags
{
get { return directoryCopyFlags; }
set { directoryCopyFlags = value; }
}
/// <summary>
/// Do not copy any directory info.
/// [/NODCOPY]
/// </summary>
public virtual bool DoNotCopyDirectoryInfo { get; set; }
/// <summary>
/// Copy files without using the Windows Copy Offload mechanism.
/// [/NOOFFLOAD]
/// </summary>
public virtual bool DoNotUseWindowsCopyOffload { get; set; }
#endregion Public Properties
#region < Parse (INTERNAL) >
/// <summary>
/// Used by the Parse method to sanitize path for the command options.<br/>
/// Evaluate the path. If needed, wrap it in quotes. <br/>
/// If the path ends in a DirectorySeperatorChar, santize it to work as expected. <br/>
/// </summary>
/// <param name="path"></param>
/// <returns>Each return string includes a space at the end of the string to seperate it from the next option variable.</returns>
private string WrapPath(string path)
{
if (!path.Contains(" ")) return $"{path} "; //No spaces, just return the path
//Below this line, the path contains a space, so it must be wrapped in quotes.
if (path.EndsWithDirectorySeperator()) return $"\"{path}.\" "; // Ends with a directory seperator - Requires a '.' to denote using that directory. ex: "F:\."
return $"\"{path}\" ";
}
/// <summary>
/// Parse the class properties and generate the command arguments
/// </summary>
/// <returns></returns>
internal string Parse()
{
Debugger.Instance.DebugMessage("Parsing CopyOptions...");
var version = VersionManager.Version;
var options = new StringBuilder();
// Set Source and Destination
options.Append(WrapPath(Source));
options.Append(WrapPath(Destination));
// Set FileFilter
// Quote each FileFilter item. The quotes are trimmed first to ensure that they are applied only once.
var fileFilterQuotedItems = FileFilter.Select(word => "\"" + word.Trim('"') + "\"");
string fileFilter = String.Join(" ", fileFilterQuotedItems);
options.Append($"{fileFilter} ");
Debugger.Instance.DebugMessage(string.Format("Parsing CopyOptions progress ({0}).", options.ToString()));
#region Set Options
var cleanedCopyFlags = CopyFlags.CleanOptionInput();
var cleanedDirectoryCopyFlags = DirectoryCopyFlags.CleanOptionInput();
if (!cleanedCopyFlags.IsNullOrWhiteSpace())
{
options.Append(string.Format(COPY_FLAGS, cleanedCopyFlags));
Debugger.Instance.DebugMessage(string.Format("Parsing CopyOptions progress ({0}).", options.ToString()));
}
if (!cleanedDirectoryCopyFlags.IsNullOrWhiteSpace() && version >= 5.1260026)
{
options.Append(string.Format(DIRECTORY_COPY_FLAGS, cleanedDirectoryCopyFlags));
Debugger.Instance.DebugMessage(string.Format("Parsing CopyOptions progress ({0}).", options.ToString()));
}
if (CopySubdirectories)
{
options.Append(COPY_SUBDIRECTORIES);
Debugger.Instance.DebugMessage(string.Format("Parsing CopyOptions progress ({0}).", options.ToString()));
}
if (CopySubdirectoriesIncludingEmpty)
options.Append(COPY_SUBDIRECTORIES_INCLUDING_EMPTY);
if (Depth > 0)
options.Append(string.Format(DEPTH, Depth));
if (EnableRestartMode)
options.Append(ENABLE_RESTART_MODE);
if (EnableBackupMode)
options.Append(ENABLE_BACKUP_MODE);
if (EnableRestartModeWithBackupFallback)
options.Append(ENABLE_RESTART_MODE_WITH_BACKUP_FALLBACK);
if (UseUnbufferedIo && version >= 6.2)
options.Append(USE_UNBUFFERED_IO);
if (EnableEfsRawMode)
options.Append(ENABLE_EFSRAW_MODE);
if (CopyFilesWithSecurity)
options.Append(COPY_FILES_WITH_SECURITY);
if (CopyAll)
options.Append(COPY_ALL);
if (RemoveFileInformation)
options.Append(REMOVE_FILE_INFORMATION);
if (FixFileSecurityOnAllFiles)
options.Append(FIX_FILE_SECURITY_ON_ALL_FILES);
if (FixFileTimesOnAllFiles)
options.Append(FIX_FILE_TIMES_ON_ALL_FILES);
if (Purge)
options.Append(PURGE);
if (Mirror)
options.Append(MIRROR);
if (MoveFiles)
options.Append(MOVE_FILES);
if (MoveFilesAndDirectories)
options.Append(MOVE_FILES_AND_DIRECTORIES);
if (!AddAttributes.IsNullOrWhiteSpace())
options.Append(string.Format(ADD_ATTRIBUTES, AddAttributes.CleanOptionInput()));
if (!RemoveAttributes.IsNullOrWhiteSpace())
options.Append(string.Format(REMOVE_ATTRIBUTES, RemoveAttributes.CleanOptionInput()));
if (CreateDirectoryAndFileTree)
options.Append(CREATE_DIRECTORY_AND_FILE_TREE);
if (FatFiles)
options.Append(FAT_FILES);
if (TurnLongPathSupportOff)
options.Append(TURN_LONG_PATH_SUPPORT_OFF);
if (MonitorSourceChangesLimit > 0)
options.Append(string.Format(MONITOR_SOURCE_CHANGES_LIMIT, MonitorSourceChangesLimit));
if (MonitorSourceTimeLimit > 0)
options.Append(string.Format(MONITOR_SOURCE_TIME_LIMIT, MonitorSourceTimeLimit));
if (!RunHours.IsNullOrWhiteSpace())
options.Append(string.Format(RUN_HOURS, RunHours.CleanOptionInput()));
if (CheckPerFile)
options.Append(CHECK_PER_FILE);
if (InterPacketGap > 0)
options.Append(string.Format(INTER_PACKET_GAP, InterPacketGap));
if (CopySymbolicLink)
options.Append(COPY_SYMBOLIC_LINK);
if (MultiThreadedCopiesCount > 0)
options.Append(string.Format(MULTITHREADED_COPIES_COUNT, MultiThreadedCopiesCount));
if (DoNotCopyDirectoryInfo && version >= 6.2)
options.Append(DO_NOT_COPY_DIRECTORY_INFO);
if (DoNotUseWindowsCopyOffload && version >= 6.2)
options.Append(DO_NOT_USE_WINDOWS_COPY_OFFLOAD);
#endregion Set Options
var parsedOptions = options.ToString();
Debugger.Instance.DebugMessage(string.Format("CopyOptions parsed ({0}).", parsedOptions));
return parsedOptions;
}
#endregion
#region < RunHours (Public) >
private static Regex RunHours_OverallRegex = new Regex("^(?<StartTime>[0-2][0-9][0-5][0-9])-(?<EndTime>[0-2][0-9][0-5][0-9])$", RegexOptions.Compiled | RegexOptions.ExplicitCapture);
private static Regex RunHours_Check1 = new Regex("^[0-1][0-9][0-5][0-9]$", RegexOptions.Compiled); // Checks 0000 - 1959
private static Regex RunHours_Check2 = new Regex("^[2][0-3][0-5][0-9]$", RegexOptions.Compiled); // Checks 2000 - 2359
private GroupCollection RunHoursGroups => RunHours_OverallRegex.Match(RunHours).Groups;
/// <summary>
/// Get the StartTime portion of <see cref="RunHours"/>
/// </summary>
/// <returns>hhmm or String.Empty</returns>
public string GetRunHours_StartTime()
{
if (RunHours.IsNullOrWhiteSpace()) return string.Empty;
return RunHoursGroups["StartTime"]?.Value ?? String.Empty;
}
/// <summary>
/// Get the EndTime portion of <see cref="RunHours"/>
/// </summary>
/// <returns>hhmm or String.Empty</returns>
public string GetRunHours_EndTime()
{
if (RunHours.IsNullOrWhiteSpace()) return string.Empty;
return RunHoursGroups["EndTime"]?.Value ?? String.Empty;
}
/// <summary>
/// Method to check if some string is valid for use as with the <see cref="RunHours"/> property.
/// </summary>
/// <param name="runHours"></param>
/// <returns>True if correct format, otherwise false</returns>
public bool CheckRunHoursString(string runHours)
{
if (string.IsNullOrWhiteSpace(runHours)) return true;
if (!RunHours_OverallRegex.IsMatch(runHours.Trim())) return false;
var times = RunHours_OverallRegex.Match(runHours.Trim());
bool StartMatch = RunHours_Check1.IsMatch(times.Groups["StartTime"].Value) || RunHours_Check2.IsMatch(times.Groups["StartTime"].Value);
bool EndMatch = RunHours_Check1.IsMatch(times.Groups["EndTime"].Value) || RunHours_Check2.IsMatch(times.Groups["EndTime"].Value);
return StartMatch && EndMatch;
}
#endregion
#region < Flags >
/// <summary>
/// Enum to define the high-level copy action to be taken by RoboCopy process.
/// </summary>
[Flags]
public enum CopyActionFlags
{
/// <summary>
/// Default Functionality is to only copy the files within the source directory - does not copy any files within the subfolders.
/// </summary>
Default = 0,
/// <inheritdoc cref="CopyOptions.CopySubdirectories"/>
CopySubdirectories = 1,
/// <inheritdoc cref="CopyOptions.CopySubdirectoriesIncludingEmpty"/>
CopySubdirectoriesIncludingEmpty = 2,
/// <inheritdoc cref="CopyOptions.Purge"/>
Purge = 4,
/// <inheritdoc cref="CopyOptions.CreateDirectoryAndFileTree"/>
CreateDirectoryAndFileTree = 8,
/// <inheritdoc cref="CopyOptions.MoveFiles"/>
MoveFiles = 16,
/// <inheritdoc cref="CopyOptions.MoveFilesAndDirectories"/>
MoveFilesAndDirectories = 32,
/// <inheritdoc cref="CopyOptions.Mirror"/>
Mirror = CopySubdirectoriesIncludingEmpty | Purge, //6
}
/// <summary>
/// Apply the <see cref="CopyActionFlags"/> to the command
/// </summary>
/// <param name="flags">Options to apply</param>
public virtual void ApplyActionFlags(CopyActionFlags flags)
{
this.CopySubdirectories = flags.HasFlag(CopyActionFlags.CopySubdirectories);
this.CopySubdirectoriesIncludingEmpty = flags.HasFlag(CopyActionFlags.CopySubdirectoriesIncludingEmpty);
this.Purge = flags.HasFlag(CopyActionFlags.Purge);
this.Mirror = flags.HasFlag(CopyActionFlags.Mirror);
this.MoveFiles = flags.HasFlag(CopyActionFlags.MoveFiles);
this.MoveFilesAndDirectories = flags.HasFlag(CopyActionFlags.MoveFilesAndDirectories);
}
/// <summary>
/// Get the <see cref="CopyActionFlags"/> representation of this object
/// </summary>
public virtual CopyActionFlags GetCopyActionFlags()
{
var flags = CopyActionFlags.Default;
if (this.CopySubdirectories) flags |=CopyActionFlags.CopySubdirectories;
if (this.CopySubdirectoriesIncludingEmpty) flags |=CopyActionFlags.CopySubdirectoriesIncludingEmpty;
if (this.Purge) flags |=CopyActionFlags.Purge;
if (this.Mirror) flags |=CopyActionFlags.Mirror;
if (this.MoveFiles) flags |=CopyActionFlags.MoveFiles;
if (this.MoveFilesAndDirectories) flags |=CopyActionFlags.MoveFilesAndDirectories;
return flags;
}
#endregion
#region < Other Public Methods >
/// <summary>
/// Combine this object with another CopyOptions object. <br/>
/// Any properties marked as true take priority. IEnumerable items are combined.
/// </summary>
/// <remarks>
/// Source and Destination are only taken from the merged item if this object's Source/Destination values are null/empty. <br/>
/// RunHours follows the same rules.
///
/// </remarks>
/// <param name="copyOptions"></param>
public void Merge(CopyOptions copyOptions)
{
Source = Source.ReplaceIfEmpty(copyOptions.Source);
Destination = Destination.ReplaceIfEmpty(copyOptions.Destination);
RunHours = RunHours.ReplaceIfEmpty(copyOptions.RunHours);
//int -> Take Greater Value
Depth = Depth.GetGreaterVal(copyOptions.Depth);
InterPacketGap = InterPacketGap.GetGreaterVal(copyOptions.InterPacketGap);
MonitorSourceChangesLimit = MonitorSourceChangesLimit.GetGreaterVal(copyOptions.MonitorSourceChangesLimit);
MonitorSourceTimeLimit = MonitorSourceTimeLimit.GetGreaterVal(copyOptions.MonitorSourceTimeLimit);
MultiThreadedCopiesCount = MultiThreadedCopiesCount.GetGreaterVal(copyOptions.MultiThreadedCopiesCount);
//Flags
AddAttributes = AddAttributes.CombineCharArr(copyOptions.AddAttributes);
CopyFlags = CopyFlags.CombineCharArr(copyOptions.CopyFlags);
DirectoryCopyFlags = DirectoryCopyFlags.CombineCharArr(copyOptions.DirectoryCopyFlags);
RemoveAttributes = RemoveAttributes.CombineCharArr(copyOptions.RemoveAttributes);
//IEnumerable
var list = new List<String>(FileFilter);
list.AddRange(copyOptions.FileFilter);
FileFilter = list;
//Bool
CheckPerFile |= copyOptions.CheckPerFile;
CopyAll |= copyOptions.CopyAll;
CopyFilesWithSecurity |= copyOptions.CopyFilesWithSecurity;
CopySubdirectories |= copyOptions.CopySubdirectories;
CopySubdirectoriesIncludingEmpty |= copyOptions.CopySubdirectoriesIncludingEmpty;
CopySymbolicLink |= copyOptions.CopySymbolicLink;
CreateDirectoryAndFileTree |= copyOptions.CreateDirectoryAndFileTree;
DoNotCopyDirectoryInfo |= copyOptions.DoNotCopyDirectoryInfo;
DoNotUseWindowsCopyOffload |= copyOptions.DoNotUseWindowsCopyOffload;
EnableBackupMode |= copyOptions.EnableBackupMode;
EnableEfsRawMode |= copyOptions.EnableEfsRawMode;
EnableRestartMode |= copyOptions.EnableRestartMode;
EnableRestartModeWithBackupFallback |= copyOptions.EnableRestartModeWithBackupFallback;
FatFiles |= copyOptions.FatFiles;
FixFileSecurityOnAllFiles |= copyOptions.FixFileSecurityOnAllFiles;
FixFileTimesOnAllFiles |= copyOptions.FixFileTimesOnAllFiles;
Mirror |= copyOptions.Mirror;
MoveFiles |= copyOptions.MoveFiles;
MoveFilesAndDirectories |= copyOptions.MoveFilesAndDirectories;
Purge |= copyOptions.Purge;
RemoveFileInformation |= copyOptions.RemoveFileInformation;
TurnLongPathSupportOff |= copyOptions.TurnLongPathSupportOff;
UseUnbufferedIo |= copyOptions.UseUnbufferedIo;
}
#endregion
}
}