/// <summary>
        /// Deletes any target files that are not listed in the source array.
        /// </summary>
        private void DeleteSourceFilesFromTarget(IEnumerable <string> sourceFiles, DirectoryInfo targetDirInfo)
        {
            // Get names only as lowercase for comparison
            string[] sourceFileNames = sourceFiles.Select(f => Path.GetFileName(f).ToLower()).ToArray();

            // Get full paths to target (maintain case, UNIX names can be case sensitive.)
            string[] targetFiles = Directory.EnumerateFiles(targetDirInfo.FullName, "*.*", SearchOption.TopDirectoryOnly).ToArray();

            // Need to check for files that exist in target but not in source
            foreach (string file in targetFiles)
            {
                // Compare names as lowercase
                string nameOnly = Path.GetFileName(file).ToLower();

                // Only name will match, full paths are from different locations
                bool remove = !sourceFileNames.Contains(nameOnly);

                // Remove if ext is now excluded
                remove |= BackupSettings.IsFileTypeExcluded(file);

                // Remove if hidden options changed
                remove |= BackupSettings.IgnoreHiddenFiles && (File.GetAttributes(file) & FileAttributes.Hidden) > 0;

                if (remove)
                {
                    // Delete using full path
                    DeleteFile(file);
                }
            }
        }
        /// <summary>
        /// Copies directory from source to target.
        /// </summary>
        /// <param name="sourceDirInfo">Source directory to copy</param>
        /// <param name="targetDirInfo">Target directory where backup is to take place</param>
        /// <returns>Number of files backed up</returns>
        protected int CopyFiles(DirectoryInfo sourceDirInfo, DirectoryInfo targetDirInfo)
        {
            int backupCount = 0;

            // Check source exists and whether hidden should be backup up.
            // (Files within a hidden directory are also considered hidden.)
            if (!BackupSettings.IgnoreHiddenFiles || (sourceDirInfo.Attributes & FileAttributes.Hidden) == 0)
            {
                // Remove common root path
                string sourceSubDir = GetSourceSubDir(sourceDirInfo.FullName, targetDirInfo.FullName);

                // Get target path
                string targetDir = Path.Combine(targetDirInfo.FullName, sourceSubDir);

                // Get qualifying files only
                var files = Directory.EnumerateFiles(sourceDirInfo.FullName, "*.*", SearchOption.TopDirectoryOnly).Where(f => !BackupSettings.IsFileTypeExcluded(f));

                // Copy files in current directory
                backupCount = CopyFiles(files, targetDir);

                // Recursive call for sub directories
                foreach (DirectoryInfo subDirInfo in sourceDirInfo.EnumerateDirectories("*", SearchOption.TopDirectoryOnly).Where(d => !BackupSettings.IsDirectoryExcluded(d.Name)))
                {
                    backupCount += CopyFiles(subDirInfo, targetDirInfo);
                }
            }

            return(backupCount);
        }
        /// <summary>
        /// Remove directories/files from target that are not in source,
        /// then copies in new/updated files.
        /// </summary>
        private int SyncDirectories(string sourceDir, string targetDir)
        {
            DirectoryInfo sourceDirInfo = new(sourceDir);
            DirectoryInfo targetDirInfo = new(targetDir);

            // Get qualifying files only
            var sourceFiles = Directory.EnumerateFiles(sourceDirInfo.FullName, "*.*", SearchOption.TopDirectoryOnly).Where(f => !BackupSettings.IsFileTypeExcluded(f));

            // Check if previous backup taken place
            if (targetDirInfo.Exists)
            {
                //////////////////////////////////////////////////////
                // Remove directories from target not in source
                // (Remove before copying new files to free up space)
                //////////////////////////////////////////////////////
                DeleteSourceDirectoriesFromTarget(sourceDirInfo, targetDirInfo);

                //////////////////////////////////////////////////////
                // Remove files from target not in source
                // (Remove before copying new files to free up space)
                //////////////////////////////////////////////////////
                DeleteSourceFilesFromTarget(sourceFiles, targetDirInfo);
            }

            int backupCount = 0;

            // Check whether backing up hidden directories
            if (!BackupSettings.IgnoreHiddenFiles || (sourceDirInfo.Attributes & FileAttributes.Hidden) == 0)
            {
                //////////////////////////////////////////////////////
                // Copy files from source not in target
                // (Or replace old files)
                //////////////////////////////////////////////////////
                backupCount = CopyFiles(sourceFiles, targetDir);

                /////////////////////////////////////////////
                // Sync sub directories
                /////////////////////////////////////////////
                foreach (DirectoryInfo subDirInfo in sourceDirInfo.EnumerateDirectories("*", SearchOption.TopDirectoryOnly).Where(d => !BackupSettings.IsDirectoryExcluded(d.Name)))
                {
                    // Get sub-directories
                    string subSourceDir = Path.Combine(sourceDir, subDirInfo.Name);
                    string subTargetDir = Path.Combine(targetDir, subDirInfo.Name);

                    // Recursive call
                    backupCount += SyncDirectories(subSourceDir, subTargetDir);
                }
            }

            return(backupCount);
        }