Beispiel #1
0
            /// <summary>
            /// Removes any directory at the specified path which has a file  matching the provided name
            /// older than the specified number of days. Used by code that writes a .token file to temp
            /// folders
            /// </summary>
            /// <param name="InPath"></param>
            /// <param name="FileName"></param>
            /// <param name="Days"></param>
            public static void CleanupMarkedDirectories(string InPath, int Days)
            {
                DirectoryInfo Di = new DirectoryInfo(InPath);

                if (Di.Exists == false)
                {
                    return;
                }

                foreach (DirectoryInfo SubDir in Di.GetDirectories())
                {
                    bool HasFile =
                        SubDir.GetFiles().Where(F => {
                        int DaysOld = (DateTime.Now - F.LastWriteTime).Days;

                        if (DaysOld >= Days)
                        {
                            // use the old and new tokennames
                            return(string.Equals(F.Name, "gauntlet.tempdir", StringComparison.OrdinalIgnoreCase) ||
                                   string.Equals(F.Name, "gauntlet.token", StringComparison.OrdinalIgnoreCase));
                        }

                        return(false);
                    }).Count() > 0;

                    if (HasFile)
                    {
                        Log.Info("Removing old directory {0}", SubDir.Name);
                        try
                        {
                            SubDir.Delete(true);
                        }
                        catch (Exception Ex)
                        {
                            Log.Warning("Failed to remove old directory {0}. {1}", SubDir.FullName, Ex.Message);
                        }
                    }
                    else
                    {
                        CleanupMarkedDirectories(SubDir.FullName, Days);
                    }
                }
            }
Beispiel #2
0
            /// <summary>
            /// Copies src to dest by comparing files sizes and time stamps and only copying files that are different in src. Basically a more flexible
            /// robocopy
            /// </summary>
            /// <param name="SourcePath"></param>
            /// <param name="DestPath"></param>
            /// <param name="Verbose"></param>
            public static void CopyDirectory(string SourceDirPath, string DestDirPath, CopyOptions Options, Func <string, string> Transform, int RetryCount = 5)
            {
                DateTime StartTime = DateTime.Now;

                DirectoryInfo SourceDir = new DirectoryInfo(SourceDirPath);
                DirectoryInfo DestDir   = new DirectoryInfo(DestDirPath);

                if (DestDir.Exists == false)
                {
                    DestDir = Directory.CreateDirectory(DestDir.FullName);
                }

                System.IO.FileInfo[] SourceFiles = SourceDir.GetFiles("*", SearchOption.AllDirectories);
                System.IO.FileInfo[] DestFiles   = DestDir.GetFiles("*", SearchOption.AllDirectories);

                // Convert dest into a map of relative paths to absolute
                Dictionary <string, System.IO.FileInfo> DestStructure = new Dictionary <string, System.IO.FileInfo>();

                foreach (FileInfo Info in DestFiles)
                {
                    string RelativePath = Info.FullName.Replace(DestDir.FullName, "");

                    // remove leading seperator
                    if (RelativePath.First() == Path.DirectorySeparatorChar)
                    {
                        RelativePath = RelativePath.Substring(1);
                    }

                    DestStructure[RelativePath] = Info;
                }

                // List of relative-path files to copy to dest
                List <string> CopyList = new List <string>();

                // List of relative path files in dest to delete
                List <string> DeletionList = new List <string>();

                foreach (FileInfo SourceInfo in SourceFiles)
                {
                    string SourceFilePath = SourceInfo.FullName.Replace(SourceDir.FullName, "");

                    // remove leading seperator
                    if (SourceFilePath.First() == Path.DirectorySeparatorChar)
                    {
                        SourceFilePath = SourceFilePath.Substring(1);
                    }

                    string DestFilePath = Transform(SourceFilePath);

                    if (DestStructure.ContainsKey(DestFilePath) == false)
                    {
                        // No copy in dest, add it to the list
                        CopyList.Add(SourceFilePath);
                    }
                    else
                    {
                        // Check the file is the same version
                        FileInfo DestInfo = DestStructure[DestFilePath];

                        // Difference in ticks. Even though we set the dest to the src there still appears to be minute
                        // differences in ticks. 1ms is 10k ticks...
                        Int64 TimeDelta  = Math.Abs(DestInfo.LastWriteTime.Ticks - SourceInfo.LastWriteTime.Ticks);
                        Int64 Threshhold = 100000;

                        if (DestInfo.Length != SourceInfo.Length ||
                            TimeDelta > Threshhold)
                        {
                            CopyList.Add(SourceFilePath);
                        }

                        // Remove it from the map
                        DestStructure.Remove(DestFilePath);
                    }
                }

                // If set to mirror, delete all the files that were not in source
                if ((Options & CopyOptions.Mirror) == CopyOptions.Mirror)
                {
                    // Now go through the remaining map items and delete them
                    foreach (var Pair in DestStructure)
                    {
                        DeletionList.Add(Pair.Key);
                    }

                    foreach (string RelativePath in DeletionList)
                    {
                        FileInfo DestInfo = new FileInfo(Path.Combine(DestDir.FullName, RelativePath));

                        Log.Verbose("Deleting extra file {0}", DestInfo.FullName);

                        try
                        {
                            // avoid an UnauthorizedAccessException by making sure file isn't read only
                            DestInfo.IsReadOnly = false;
                            DestInfo.Delete();
                        }
                        catch (Exception Ex)
                        {
                            Log.Warning("Failed to delete file {0}. {1}", DestInfo.FullName, Ex);
                        }
                    }

                    // delete empty directories
                    DirectoryInfo DestDirInfo = new DirectoryInfo(DestDirPath);

                    DirectoryInfo[] AllSubDirs = DestDirInfo.GetDirectories("*", SearchOption.AllDirectories);

                    foreach (DirectoryInfo SubDir in AllSubDirs)
                    {
                        try
                        {
                            if (SubDir.GetFiles().Length == 0 && SubDir.GetDirectories().Length == 0)
                            {
                                Log.Verbose("Deleting empty dir {0}", SubDir.FullName);

                                SubDir.Delete(true);
                            }
                        }
                        catch (Exception Ex)
                        {
                            // handle the case where a file is locked
                            Log.Info("Failed to delete directory {0}. {1}", SubDir.FullName, Ex);
                        }
                    }
                }

                CancellationTokenSource CTS = new CancellationTokenSource();

                // todo - make param..
                var POptions = new ParallelOptions {
                    MaxDegreeOfParallelism = 1, CancellationToken = CTS.Token
                };

                // install a cancel handler so we can stop parallel-for gracefully
                Action CancelHandler = delegate()
                {
                    CTS.Cancel();
                };

                Globals.AbortHandlers.Add(CancelHandler);

                // now do the work
                Parallel.ForEach(CopyList, POptions, RelativePath =>
                {
                    // ensure path exists
                    string DestPath = Path.Combine(DestDir.FullName, RelativePath);

                    if (Transform != null)
                    {
                        DestPath = Transform(DestPath);
                    }

                    FileInfo DestInfo = new FileInfo(DestPath);
                    FileInfo SrcInfo  = new FileInfo(Path.Combine(SourceDir.FullName, RelativePath));

                    // ensure directory exists
                    DestInfo.Directory.Create();

                    string DestFile = DestInfo.FullName;

                    if (Transform != null)
                    {
                        DestFile = Transform(DestFile);
                    }

                    int Tries   = 0;
                    bool Copied = false;

                    do
                    {
                        try
                        {
                            Log.Verbose("Copying to {0}", DestFile);

                            SrcInfo.CopyTo(DestFile, true);

                            // Clear and read-only attrib and set last write time
                            FileInfo DestFileInfo      = new FileInfo(DestFile);
                            DestFileInfo.IsReadOnly    = false;
                            DestFileInfo.LastWriteTime = SrcInfo.LastWriteTime;
                            Copied = true;
                        }
                        catch (Exception ex)
                        {
                            if (Tries++ < RetryCount)
                            {
                                Log.Info("Copy to {0} failed, retrying {1} of {2} in 30 secs..", DestFile, Tries, RetryCount);
                                // todo - make param..
                                Thread.Sleep(30000);
                            }
                            else
                            {
                                Log.Error("File Copy failed with {0}.", ex.Message);
                                throw new Exception(string.Format("File Copy failed with {0}.", ex.Message));
                            }
                        }
                    } while (Copied == false);
                });

                TimeSpan Duration = DateTime.Now - StartTime;

                if (Duration.TotalSeconds > 10)
                {
                    Log.Verbose("Copied Directory in {0}", Duration.ToString(@"mm\m\:ss\s"));
                }

                // remove cancel handler
                Globals.AbortHandlers.Remove(CancelHandler);
            }
Beispiel #3
0
            /// <summary>
            /// Copies src to dest by comparing files sizes and time stamps and only copying files that are different in src. Basically a more flexible
            /// robocopy
            /// </summary>
            /// <param name="SourcePath"></param>
            /// <param name="DestPath"></param>
            /// <param name="Verbose"></param>
            public static void CopyDirectory(string SourceDirPath, string DestDirPath, CopyDirectoryOptions Options)
            {
                DateTime StartTime = DateTime.Now;

                DirectoryInfo SourceDir = new DirectoryInfo(SourceDirPath);
                DirectoryInfo DestDir   = new DirectoryInfo(DestDirPath);

                if (DestDir.Exists == false)
                {
                    DestDir = Directory.CreateDirectory(DestDir.FullName);
                }

                bool IsMirroring = (Options.Mode & CopyOptions.Mirror) == CopyOptions.Mirror;

                if (IsMirroring && !Options.IsDirectoryPattern)
                {
                    Log.Warning("Can only use mirror with pattern that includes whole directories (e.g. '*')");
                    IsMirroring = false;
                }

                IEnumerable <FileInfo> SourceFiles = null;

                FileInfo[] DestFiles = null;

                // find all files. If a directory get them all, else use the pattern/regex
                if (Options.IsDirectoryPattern)
                {
                    SourceFiles = SourceDir.GetFiles("*", Options.Recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
                }
                else
                {
                    if (Options.Regex == null)
                    {
                        SourceFiles = SourceDir.GetFiles(Options.Pattern, Options.Recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
                    }
                    else
                    {
                        SourceFiles = SourceDir.GetFiles("*", Options.Recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);

                        SourceFiles = SourceFiles.Where(F => Options.Regex.IsMatch(F.Name));
                    }
                }

                // Convert dest into a map of relative paths to absolute
                Dictionary <string, System.IO.FileInfo> DestStructure = new Dictionary <string, System.IO.FileInfo>();

                if (IsMirroring)
                {
                    DestFiles = DestDir.GetFiles("*", SearchOption.AllDirectories);

                    foreach (FileInfo Info in DestFiles)
                    {
                        string RelativePath = Info.FullName.Replace(DestDir.FullName, "");

                        // remove leading seperator
                        if (RelativePath.First() == Path.DirectorySeparatorChar)
                        {
                            RelativePath = RelativePath.Substring(1);
                        }

                        DestStructure[RelativePath] = Info;
                    }
                }

                // List of relative-path files to copy to dest
                List <string> CopyList = new List <string>();

                // List of relative path files in dest to delete
                List <string> DeletionList = new List <string>();

                foreach (FileInfo SourceInfo in SourceFiles)
                {
                    string SourceFilePath = SourceInfo.FullName.Replace(SourceDir.FullName, "");

                    // remove leading seperator
                    if (SourceFilePath.First() == Path.DirectorySeparatorChar)
                    {
                        SourceFilePath = SourceFilePath.Substring(1);
                    }

                    string DestFilePath = Options.Transform(SourceFilePath);

                    FileInfo DestInfo = null;

                    // We may have destination info if mirroring where we prebuild it all, if not
                    // grab it now
                    if (DestStructure.ContainsKey(DestFilePath))
                    {
                        DestInfo = DestStructure[DestFilePath];
                    }
                    else
                    {
                        string FullDestPath = Path.Combine(DestDir.FullName, DestFilePath);
                        if (File.Exists(FullDestPath))
                        {
                            DestInfo = new FileInfo(FullDestPath);
                        }
                    }

                    if (DestInfo == null)
                    {
                        // No copy in dest, add it to the list
                        CopyList.Add(SourceFilePath);
                    }
                    else
                    {
                        // Check the file is the same version

                        // Difference in ticks. Even though we set the dest to the src there still appears to be minute
                        // differences in ticks. 1ms is 10k ticks...
                        Int64 TimeDelta  = Math.Abs(DestInfo.LastWriteTime.Ticks - SourceInfo.LastWriteTime.Ticks);
                        Int64 Threshhold = 100000;

                        if (DestInfo.Length != SourceInfo.Length ||
                            TimeDelta > Threshhold)
                        {
                            CopyList.Add(SourceFilePath);
                        }
                        else
                        {
                            if (Options.Verbose)
                            {
                                Log.Info("Will skip copy to {0}. File up to date.", DestInfo.FullName);
                            }
                            else
                            {
                                Log.Verbose("Will skip copy to {0}. File up to date.", DestInfo.FullName);
                            }
                        }

                        // Remove it from the map
                        DestStructure.Remove(DestFilePath);
                    }
                }

                // If set to mirror, delete all the files that were not in source
                if (IsMirroring)
                {
                    // Now go through the remaining map items and delete them
                    foreach (var Pair in DestStructure)
                    {
                        DeletionList.Add(Pair.Key);
                    }

                    foreach (string RelativePath in DeletionList)
                    {
                        FileInfo DestInfo = new FileInfo(Path.Combine(DestDir.FullName, RelativePath));

                        if (Options.Verbose)
                        {
                            Log.Info("Deleting extra file {0}", DestInfo.FullName);
                        }
                        else
                        {
                            Log.Verbose("Deleting extra file {0}", DestInfo.FullName);
                        }

                        try
                        {
                            // avoid an UnauthorizedAccessException by making sure file isn't read only
                            DestInfo.IsReadOnly = false;
                            DestInfo.Delete();
                        }
                        catch (Exception Ex)
                        {
                            Log.Warning("Failed to delete file {0}. {1}", DestInfo.FullName, Ex);
                        }
                    }

                    // delete empty directories
                    DirectoryInfo DestDirInfo = new DirectoryInfo(DestDirPath);

                    DirectoryInfo[] AllSubDirs = DestDirInfo.GetDirectories("*", SearchOption.AllDirectories);

                    foreach (DirectoryInfo SubDir in AllSubDirs)
                    {
                        try
                        {
                            if (SubDir.GetFiles().Length == 0 && SubDir.GetDirectories().Length == 0)
                            {
                                if (Options.Verbose)
                                {
                                    Log.Info("Deleting empty dir {0}", SubDir.FullName);
                                }
                                else
                                {
                                    Log.Verbose("Deleting empty dir {0}", SubDir.FullName);
                                }

                                SubDir.Delete(true);
                            }
                        }
                        catch (Exception Ex)
                        {
                            // handle the case where a file is locked
                            Log.Info("Failed to delete directory {0}. {1}", SubDir.FullName, Ex);
                        }
                    }
                }

                CancellationTokenSource CTS = new CancellationTokenSource();

                // todo - make param..
                var POptions = new ParallelOptions {
                    MaxDegreeOfParallelism = 1, CancellationToken = CTS.Token
                };

                // install a cancel handler so we can stop parallel-for gracefully
                Action CancelHandler = delegate()
                {
                    CTS.Cancel();
                };

                Globals.AbortHandlers.Add(CancelHandler);

                // now do the work
                Parallel.ForEach(CopyList, POptions, RelativePath =>
                {
                    // ensure path exists
                    string DestPath = Path.Combine(DestDir.FullName, RelativePath);

                    if (Options.Transform != null)
                    {
                        DestPath = Options.Transform(DestPath);
                    }

                    string SourcePath = Path.Combine(SourceDir.FullName, RelativePath);
                    FileInfo DestInfo;
                    FileInfo SrcInfo;

                    // wrap FileInfo creation with exception handler as can throw and want informative error
                    try
                    {
                        DestInfo = new FileInfo(DestPath);
                        SrcInfo  = new FileInfo(SourcePath);
                    }
                    catch (Exception Ex)
                    {
                        throw new Exception(string.Format("FileInfo creation failed for Source:{0}, Dest:{1}, with: {2}", SourcePath, DestPath, Ex.Message));
                    }

                    // ensure directory exists
                    DestInfo.Directory.Create();

                    string DestFile = DestInfo.FullName;

                    if (Options.Transform != null)
                    {
                        DestFile = Options.Transform(DestFile);
                    }

                    int Tries   = 0;
                    bool Copied = false;

                    do
                    {
                        try
                        {
                            if (Options.Verbose)
                            {
                                Log.Info("Copying to {0}", DestFile);
                            }
                            else
                            {
                                Log.Verbose("Copying to {0}", DestFile);
                            }

                            SrcInfo.CopyTo(DestFile, true);

                            // Clear and read-only attrib and set last write time
                            FileInfo DestFileInfo      = new FileInfo(DestFile);
                            DestFileInfo.IsReadOnly    = false;
                            DestFileInfo.LastWriteTime = SrcInfo.LastWriteTime;
                            Copied = true;
                        }
                        catch (Exception ex)
                        {
                            if (Tries++ < Options.Retries)
                            {
                                Log.Info("Copy to {0} failed, retrying {1} of {2} in 30 secs..", DestFile, Tries, Options.Retries);
                                // todo - make param..
                                Thread.Sleep(30000);
                            }
                            else
                            {
                                using (var PauseEC = new ScopedSuspendECErrorParsing())
                                {
                                    Log.Error("File Copy failed with {0}.", ex.Message);
                                }
                                throw new Exception(string.Format("File Copy failed with {0}.", ex.Message));
                            }
                        }
                    } while (Copied == false);
                });

                TimeSpan Duration = DateTime.Now - StartTime;

                if (Duration.TotalSeconds > 10)
                {
                    if (Options.Verbose)
                    {
                        Log.Info("Copied Directory in {0}", Duration.ToString(@"mm\m\:ss\s"));
                    }
                    else
                    {
                        Log.Verbose("Copied Directory in {0}", Duration.ToString(@"mm\m\:ss\s"));
                    }
                }

                // remove cancel handler
                Globals.AbortHandlers.Remove(CancelHandler);
            }