public bool FilesMatchBasedOnPaths(FileExtended f1, FileExtended f2) { var filesMatch = false; var basePathsCompatible = false; foreach (var folderMapping in SyncConfig.FolderMappings) { var f1BasePathMatchesKey = f1.basePath == folderMapping.Value.Item1; var f1BasePathMatchesValue = f1.basePath == folderMapping.Value.Item2; var f2BasePathMatchesKey = f2.basePath == folderMapping.Value.Item1; var f2BasePathMatchesValue = f2.basePath == folderMapping.Value.Item2; if ( (f1BasePathMatchesKey && f2BasePathMatchesValue) || (f1BasePathMatchesValue && f2BasePathMatchesKey) ) { basePathsCompatible = true; break; } } if (basePathsCompatible && f1.RelativePath == f2.RelativePath) { filesMatch = true; } return(filesMatch); }
private void ActionRenameMove(FileExtended sourceFileExtended, FileExtended destFileExtended, Direction actionDirection) { string sourceFile = sourceFileExtended.fullPath; string destFile = destFileExtended.fullPath; try { var newFile = GetOldAndNewFile(sourceFile, destFile, actionDirection)["new"]; var oldFile = GetOldAndNewFile(sourceFile, destFile, actionDirection)["old"]; string oldFileExpectedFullPath = oldFile.basePath + newFile.RelativePath; string oldFileExpectedDirectory = Path.GetDirectoryName(oldFileExpectedFullPath); if (!Directory.Exists(oldFileExpectedDirectory)) { Directory.CreateDirectory(oldFileExpectedDirectory); } File.Move(oldFile.fullPath, oldFileExpectedFullPath); var oldFileExpected = new FileExtended(oldFile.fileType, oldFile.basePath, oldFileExpectedFullPath, oldFile.fileID); UpdateFileInMapping(oldFile, oldFileExpected); } catch (Exception ex) { throw new Exception("Error occured during move operation: \n" + ex.Message); } }
private void ActionDelete(FileExtended sourceFileExtended, FileExtended destFileExtended, Direction actionDirection) { FileExtended fileToDelete = null; switch (actionDirection) { case Direction.SourceToDestination: fileToDelete = destFileExtended; FileMappingFromCsv.Remove(destFileExtended); break; case Direction.DestinationToSource: fileToDelete = sourceFileExtended; FileMappingFromCsv.Remove(sourceFileExtended); break; } if (fileToDelete != null) { string pathForArchival = Path.Combine(SyncConfig.Parameters["ArchiveFolder"], DateTime.Now.ToString("yyyy-MM-dd")); string logFile = SyncConfig.SyncLog; WorkingWithFiles.ArchiveFile(fileToDelete, logFile, pathForArchival, "deletion"); } }
public FileExtended GetFileById(FileType fileType, string id) { FileExtended resultingFile = null; Dictionary <string, FileExtended> listToSearch; switch (fileType) { case FileType.Source: listToSearch = SourceFiles; break; case FileType.Destination: listToSearch = DestFiles; break; default: throw new Exception("Unknown file type!"); } if (listToSearch.ContainsKey(id)) { resultingFile = listToSearch[id]; } return(resultingFile); }
public static Dictionary <FileType, FileExtended> GetSourceAndDestFile(FileExtended file1, FileExtended file2) { var files = new Dictionary <FileType, FileExtended>(); FileExtended sourceFile; FileExtended destFile; if (file1 == null) { sourceFile = file2.fileType == FileType.Source ? file2 : null; destFile = file2.fileType == FileType.Destination ? file2 : null; } else if (file2 == null) { sourceFile = file1.fileType == FileType.Source ? file1 : null; destFile = file1.fileType == FileType.Destination ? file1 : null; } else { sourceFile = file1.fileType == FileType.Source ? file1 : file2; destFile = file2.fileType == FileType.Destination ? file2 : file1; } files.Add(FileType.Source, sourceFile); files.Add(FileType.Destination, destFile); return(files); }
public static void ArchiveFile(FileExtended fileToArchive, string log, string archiveFolder, string reason) { string logMessage = ""; try { string newFilePath = archiveFolder + @"\" + fileToArchive.fullPath.Replace(":", ""); string dir = Path.GetDirectoryName(newFilePath); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } if (File.Exists(newFilePath)) { var fileInfo = new FileInfo(newFilePath); string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileInfo.Name); long existingFileSize = fileInfo.Length; if (existingFileSize != fileToArchive.FileSize) { newFilePath = newFilePath.Replace(fileNameWithoutExtension, fileNameWithoutExtension + "_2"); File.Move(fileToArchive.fullPath, newFilePath); logMessage = "Archived file " + fileToArchive.fullPath + "(size " + fileToArchive.FileSize / (1024) + "KB) and changed its name to " + Path.GetFileName(newFilePath); } else { File.Delete(fileToArchive.fullPath); logMessage = "Deleted file " + fileToArchive.fullPath + "(size " + fileToArchive.FileSize / (1024) + "KB)"; } } else { string fullPath = fileToArchive.fullPath; int sizeKb = (int)Math.Floor((double)fileToArchive.FileSize / 1024); File.Move(fileToArchive.fullPath, newFilePath); logMessage = reason + ": archived file " + fullPath + " (size " + sizeKb + "KB)"; } } catch (Exception e) { logMessage = "Could not archive file " + fileToArchive.FileName + ": \n" + e.Message; } using (var logWriter = File.AppendText(log)) { string timestamp = DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToLongTimeString(); logWriter.WriteLine(timestamp + ": " + logMessage); } }
private static Dictionary <string, FileExtended> GetFilesDictionary(SyncConfig confInstance, string path, List <string> filesPaths, FileType fileType) { bool someFilesFailed = false; var filesInFolder = filesPaths.FindAll(x => x.Contains(path)); int filesAdded = 0; int totalFilesCount = filesPaths.Count; FileExtended[] filesArray = new FileExtended[totalFilesCount]; foreach (var filePath in filesInFolder) { var timeStamp = DateTime.Now; try { if (filePath.Length >= 260) { var error = new AppError(timeStamp, "InitializeFiles", filePath, "the file path length greater than 260 is not supported by the app. Move it up the hierarchy or rename to a shorter name"); ErrorHandling.WriteErrorLog(confInstance, error); someFilesFailed = true; continue; } var fileInfo = new FileInfo(filePath); var fileExtended = new FileExtended ( fileType, path, fileInfo.FullName, Kernel32.GetCustomFileId(filePath) ); filesArray[filesAdded] = fileExtended; filesAdded++; DisplayCompletionInfo("completion percentage", filesAdded, totalFilesCount); } catch (Exception ex) { var error = new AppError(timeStamp, "InitializeFiles", filePath, "the file cannot be read: " + ex.Message); ErrorHandling.WriteErrorLog(confInstance, error); throw ex; } } if (someFilesFailed) { Console.WriteLine("\nSome files could not be added, please see the error log for details:"); Console.WriteLine(confInstance.ErrorLogFile); } return(filesArray.Where(f => f != null).ToDictionary(f => f.fileID, f => f)); }
public void AppendActionListWithDeleteRenameMove(FileExtended firstFileExtended, FileExtended secondFileExtended, CsvRow row) { var filePairAction = new FilePairAction(firstFileExtended, secondFileExtended); FileExtended sourceFile = WorkingWithFiles.GetSourceAndDestFile(firstFileExtended, secondFileExtended)[FileType.Source]; FileExtended destFile = WorkingWithFiles.GetSourceAndDestFile(firstFileExtended, secondFileExtended)[FileType.Destination]; // handle deletions bool deletion = IdentifyDeletion(sourceFile, destFile, filePairAction); if (deletion) { //_actionList.Add(filePairAction); return; } // handle renaming and moving var oldFirstFileType = (FileType)Enum.Parse(typeof(FileType), row[0]); var oldFirstBasePath = row[1]; var oldFirstFileFullPath = row[2]; var oldFirstFileId = row[3]; var oldFirstFile = new FileExtended(oldFirstFileType, oldFirstBasePath, oldFirstFileFullPath, oldFirstFileId); var oldSecondFileType = (FileType)Enum.Parse(typeof(FileType), row[4]); var oldSecondBasePath = row[5]; var oldSecondFileFullPath = row[6]; var oldSecondFileId = row[7]; var oldSecondFile = new FileExtended(oldSecondFileType, oldSecondBasePath, oldSecondFileFullPath, oldSecondFileId); var oldSourceFile = oldFirstFileType == FileType.Source ? oldFirstFile : oldSecondFile; var oldDestFile = oldSecondFileType == FileType.Destination ? oldSecondFile : oldFirstFile; IdentifyRenameMove(sourceFile, oldSourceFile, destFile, oldDestFile, filePairAction); if (filePairAction.ActionType == ActionType.RenameMove || filePairAction.ActionType == ActionType.Rename || filePairAction.ActionType == ActionType.Move // || //filePairAction.ActionType == ActionType.Delete ) { AddFilePairWithCheck(filePairAction); } }
private void ActionUpdate(FileExtended sourceFileExtended, FileExtended destFileExtended, Direction actionDirection) { string sourceFile = sourceFileExtended.fullPath; string destFile = destFileExtended.fullPath; FileExtended newFile = GetOldAndNewFile(sourceFile, destFile, actionDirection)["new"]; FileExtended oldFile = GetOldAndNewFile(sourceFile, destFile, actionDirection)["old"]; string newFileFullPath = newFile.fullPath; string oldFileFullPath = oldFile.fullPath; // update file2 with file1 // update direction: newFileFullPath => oldFileFullPath File.Copy(newFileFullPath, oldFileFullPath, true); }
public FileExtended GetFileCounterpart(FileExtended f) { FileExtended resultingFile = null; Dictionary <string, FileExtended> filesListToSearch; filesListToSearch = f.fileType == FileType.Source ? DestFiles : SourceFiles; foreach (var candidateFile in filesListToSearch) { if (FilesMatchBasedOnPaths(f, candidateFile.Value)) { resultingFile = candidateFile.Value; break; } } return(resultingFile); }
private bool IdentifyDeletion(FileExtended sourceFile, FileExtended destFile, FilePairAction filePairAction) { bool res = false; if (sourceFile == null && destFile != null) { //filePairAction.ActionType = ActionType.Delete; //filePairAction.ActionDirection = Direction.SourceToDestination; res = true; } else if (sourceFile != null && destFile == null) { //filePairAction.ActionType = ActionType.Delete; //filePairAction.ActionDirection = Direction.DestinationToSource; res = true; } return(res); }
//internal bool ActionListContainsFilePairAction(KeyValuePair<FileExtended,FileExtended> filePair) //{ // bool res = false; // foreach (var action in actionList) // { // if ( // action.ActionType == filePair. // ((action.File1 == filePair.Key && action.File2 == filePair.Value) // || // (action.File1 == filePair.Value && action.File2 == filePair.Key) // ) // ) // { // res = true; // break; // } // } // return res; //} internal void UpdateFileInMapping(FileExtended oldFile, FileExtended newFile) { FileExtended counterpartFile; if (FileMappingFromCsv.ContainsKey(oldFile)) { counterpartFile = FileMappingFromCsv[oldFile]; FileMappingFromCsv.Remove(oldFile); FileMappingFromCsv.Add(newFile, counterpartFile); } else if (FileMappingFromCsv.ContainsValue(oldFile)) { counterpartFile = FileMappingFromCsv.FirstOrDefault(x => x.Value == oldFile).Key; FileMappingFromCsv[counterpartFile] = newFile; } else { throw new Exception("Could not find specified file in mapping: \n" + oldFile.fullPath); } }
private void ActionCreate(FileExtended sourceFileExtended, FileExtended destFileExtended, Direction actionDirection) { // declare fields for a file to be created FileType newFileType; string newFileBasePath; string newFileFullPath; string newFileLastWriteDate; string newFileId; int availableSpaceForFile; string sourceFile = sourceFileExtended != null ? sourceFileExtended.fullPath : ""; string destFile = destFileExtended != null ? destFileExtended.fullPath : ""; // determine which file needs copying: source or destination string fileToCopy; FileType fileType; string basePath; switch (actionDirection) { case Direction.SourceToDestination: fileToCopy = sourceFile; fileType = FileType.Source; newFileType = FileType.Destination; // get base path for this file: basePath = sourceFileExtended.basePath; break; case Direction.DestinationToSource: fileToCopy = destFile; fileType = FileType.Destination; newFileType = FileType.Source; // get base path for this file: basePath = destFileExtended.basePath; break; default: throw new Exception("Invalid action direction for Create operation!"); } switch (fileType) { case FileType.Source: newFileBasePath = SyncConfig.FolderMappings.FirstOrDefault(x => x.Value.Item1 == basePath).Value.Item2; break; case FileType.Destination: newFileBasePath = SyncConfig.FolderMappings.FirstOrDefault(x => x.Value.Item2 == basePath).Value.Item1; break; default: throw new Exception("Invalid file type!"); } // calculate new directory name where to copy the file to: newFileFullPath = fileToCopy.Replace(basePath, newFileBasePath); string targetPath = Path.GetDirectoryName(newFileFullPath); // Create a new target folder, if necessary. if (!Directory.Exists(targetPath)) { Directory.CreateDirectory(targetPath); } // Copy a file to another location and // not overwrite the destination file if it already exists. File.Copy(fileToCopy, newFileFullPath, false); // assuming the file has been successfully copied, compute its ID // then update the corresponding entry in file mapping newFileId = Kernel32.GetCustomFileId(newFileFullPath); newFileLastWriteDate = (new FileInfo(newFileFullPath)).LastWriteTime.ToString(CultureInfo.InvariantCulture); // construct FileExtended instance for newly created file: var newFileExtended = new FileExtended(newFileType, newFileBasePath, newFileFullPath, newFileLastWriteDate, newFileId); // append source files or destination files with this new file: Dictionary <string, FileExtended> listToUpdate; switch (newFileType) { case FileType.Source: listToUpdate = SourceFiles; break; case FileType.Destination: listToUpdate = DestFiles; break; default: throw new Exception("Invalid file type"); } listToUpdate.Add(newFileExtended.fileID, newFileExtended); var fileToCopyInstance = GetFileByFullPath(fileToCopy); // update file mapping from paths FileMappingFromPaths[fileToCopyInstance] = newFileExtended; }
private static void AddMissingFileMappingFromPaths(SyncExecution syncExec) { //if (syncExec.SourceFiles.Count > 0) //{ // launch timer var watchAddMissingFilesToMapping = new Stopwatch(); watchAddMissingFilesToMapping.Start(); //var relativePathComparer = new RelativePathComparer(); var sourceFilesMissingInMapping = syncExec.FilesMissingInMapping. Where(x => x.fileType == FileType.Source).ToList(); var destFilesMissingInMapping = syncExec.FilesMissingInMapping. Where(x => x.fileType == FileType.Destination).ToList(); Console.WriteLine("Sorting files missing in mapping..."); sourceFilesMissingInMapping.Sort(); destFilesMissingInMapping.Sort(); Console.WriteLine("sorting complete"); int expectedFileMappingEntriesCount = Math.Max(sourceFilesMissingInMapping.Count, destFilesMissingInMapping.Count); var fileMappingFromPaths = syncExec.FileMappingFromPaths; var sourceFilesWithoutCounterpart = new List <FileExtended> { Capacity = expectedFileMappingEntriesCount }; var sourceFilesToProcess = new List <FileExtended>(sourceFilesMissingInMapping); var destFilesToProcess = new List <FileExtended>(destFilesMissingInMapping); int filesToProcessTotal = sourceFilesToProcess.Count + destFilesToProcess.Count; Console.WriteLine(); Console.WriteLine("Populating missing FileMapping from paths:"); int filesProcessed = 0; while (sourceFilesToProcess.Count > 0) { filesProcessed++; int lastInd = sourceFilesToProcess.Count - 1; FileExtended sourceFile = sourceFilesToProcess[lastInd]; FileExtended destMatch = null; for (int i = destFilesToProcess.Count - 1; i >= 0; i--) { FileExtended destFile = destFilesToProcess[i]; if (destFile.RelativePath == sourceFile.RelativePath) { destMatch = destFile; break; } } if (destMatch != null) { destFilesToProcess.Remove(destMatch); fileMappingFromPaths.Add(sourceFile, destMatch); filesProcessed++; } else { for (int i = destFilesToProcess.Count - 1; i >= 0; i--) { FileExtended destFile = destFilesToProcess[i]; if (destFile.FileNameAndSize == sourceFile.FileNameAndSize) { destMatch = destFile; break; } } if (destMatch != null) { destFilesToProcess.Remove(destMatch); fileMappingFromPaths.Add(sourceFile, destMatch); filesProcessed++; } else { sourceFilesWithoutCounterpart.Add(sourceFile); } } sourceFilesToProcess.Remove(sourceFile); DisplayCompletionInfo("files processed", filesProcessed, filesToProcessTotal); } foreach (var sourceFile in sourceFilesWithoutCounterpart) { filesProcessed++; fileMappingFromPaths.Add(sourceFile, null); DisplayCompletionInfo("files processed", filesProcessed, filesToProcessTotal); } while (destFilesToProcess.Count > 0) { int destFileInd = destFilesToProcess.Count - 1; var destFile = destFilesToProcess[destFileInd]; filesProcessed++; fileMappingFromPaths.Add(destFile, null); destFilesToProcess.Remove(destFile); DisplayCompletionInfo("files processed", filesProcessed, filesToProcessTotal); } Console.Write("\rfinished populating missing FileMapping from paths. Added " + fileMappingFromPaths.Count + " entries."); Console.WriteLine("\nelapsed time: " + FormatTime(watchAddMissingFilesToMapping.ElapsedMilliseconds)); //} //else //{ // throw new Exception("Source files not loaded yet"); //} }
private void IdentifyRenameMove(FileExtended sourceFile, FileExtended oldSourceFile, FileExtended destFile, FileExtended oldDestFile, FilePairAction filePairAction) { string sourceName = Path.GetFileName(sourceFile.fullPath); string sourceDirectory = Path.GetDirectoryName(sourceFile.fullPath); string oldSourceName = Path.GetFileName(oldSourceFile.fullPath); string oldSourceDirectory = Path.GetDirectoryName(oldSourceFile.fullPath); string destName = Path.GetFileName(destFile.fullPath); string destDirectory = Path.GetDirectoryName(destFile.fullPath); string oldDestName = Path.GetFileName(oldDestFile.fullPath); string oldDestDirectory = Path.GetDirectoryName(oldDestFile.fullPath); // identify RenameMove if ( (sourceName != oldSourceName || destName != oldDestName) && (sourceDirectory != oldSourceDirectory || destDirectory != oldDestDirectory) && !(sourceName == destName && sourceFile.RelativePath == destFile.RelativePath) ) { filePairAction.ActionType = ActionType.RenameMove; if (sourceFile.fullPath != oldSourceFile.fullPath && destFile.fullPath == oldDestFile.fullPath) { filePairAction.ActionDirection = Direction.SourceToDestination; } else if (sourceFile.fullPath == oldSourceFile.fullPath && destFile.fullPath != oldDestFile.fullPath) { filePairAction.ActionDirection = Direction.DestinationToSource; } else if (sourceFile.fullPath != oldSourceFile.fullPath && destFile.fullPath != oldDestFile.fullPath) { filePairAction.ActionDirection = Direction.Unknown; } return; } // identify Rename if ( (sourceName != oldSourceName || destName != oldDestName) && (sourceName != destName) ) { filePairAction.ActionType = ActionType.Rename; if (sourceName != oldSourceName && destName == oldDestName) { filePairAction.ActionDirection = Direction.SourceToDestination; } else if (sourceName == oldSourceName && destName != oldDestName) { filePairAction.ActionDirection = Direction.DestinationToSource; } else if (sourceName != oldSourceName && destName != oldDestName) { filePairAction.ActionDirection = Direction.Unknown; } return; } // identify Move if ( (sourceDirectory != oldSourceDirectory || destDirectory != oldDestDirectory) && sourceFile.RelativePath != destFile.RelativePath ) { filePairAction.ActionType = ActionType.Move; if (sourceDirectory != oldSourceDirectory && destDirectory == oldDestDirectory) { filePairAction.ActionDirection = Direction.SourceToDestination; } else if (sourceDirectory == oldSourceDirectory && destDirectory != oldDestDirectory) { filePairAction.ActionDirection = Direction.DestinationToSource; } else if (sourceDirectory != oldSourceDirectory && destDirectory != oldDestDirectory) { filePairAction.ActionDirection = Direction.Unknown; } } }
public void PerformActions() { Console.WriteLine(); var actionsToPerform = _actionList.FindAll(x => x.ActionType != ActionType.None); if (actionsToPerform.Count == 0) { Console.WriteLine("No changes have been detected - no actions needed"); return; } var syncWatch = new Stopwatch(); syncWatch.Start(); Console.WriteLine("Starting synchronization...."); foreach (var action in actionsToPerform) { var filesDict = WorkingWithFiles.GetSourceAndDestFile(action.File1, action.File2); FileExtended sourceFile = filesDict[FileType.Source]; FileExtended destFile = filesDict[FileType.Destination]; try { switch (action.ActionType) { case ActionType.Create: var creatingFileOp = action.ActionDirection == Direction.SourceToDestination ? sourceFile.fullPath : destFile.fullPath; DisplaySyncProcessStats("Copying file " + creatingFileOp); ActionCreate(sourceFile, destFile, action.ActionDirection); _filesCreated++; //Init.DisplayCompletionInfo("actions performed", // _filesCreated + _filesDeleted + _filesMoved + _filesRenamed + _filesRenamedMoved + _filesUpdated, // ActionsList.Count); break; case ActionType.Update: var updatingFile = action.ActionDirection == Direction.SourceToDestination ? destFile.fullPath : sourceFile.fullPath; DisplaySyncProcessStats("Updating file " + updatingFile); ActionUpdate(sourceFile, destFile, action.ActionDirection); _filesUpdated++; break; case ActionType.RenameMove: var movingFile = action.ActionDirection == Direction.SourceToDestination ? destFile.fullPath : sourceFile.fullPath; DisplaySyncProcessStats("Renaming and moving file " + movingFile); ActionRenameMove(sourceFile, destFile, action.ActionDirection); _filesRenamedMoved++; break; case ActionType.Rename: var renamingFile = action.ActionDirection == Direction.SourceToDestination ? destFile.fullPath : sourceFile.fullPath; DisplaySyncProcessStats("Renaming file " + renamingFile); ActionRenameMove(sourceFile, destFile, action.ActionDirection); _filesRenamed++; break; case ActionType.Move: var movingFile2 = action.ActionDirection == Direction.SourceToDestination ? destFile.fullPath : sourceFile.fullPath; DisplaySyncProcessStats("Renaming and moving file " + movingFile2); ActionRenameMove(sourceFile, destFile, action.ActionDirection); _filesMoved++; break; //case ActionType.Delete: // var archivingFile = action.ActionDirection == Direction.SourceToDestination // ? destFile.fullPath // : sourceFile.fullPath; // DisplaySyncProcessStats("Archiving file " + archivingFile); // ActionDelete(sourceFile, destFile, action.ActionDirection); // _filesDeleted++; // break; } action.SyncSuccess = true; } catch (Exception ex) { action.SyncSuccess = false; action.ExceptionMessage = ex.Message; _failedActions.Add(action); } } syncWatch.Stop(); Console.WriteLine("\n\nSynchronization complete! Elapsed time: " + Init.FormatTime(syncWatch.ElapsedMilliseconds)); }
public FilePairAction(FileExtended file1, FileExtended file2) { this.File1 = file1; this.File2 = file2; }