//Appends the any xml file/folder nodes onto the folder private void AddXmlNodes(FolderCompareObject folder, int numOfPaths, XmlDocument xmlDoc) { List<XMLCompareObject> xmlObjList = new List<XMLCompareObject>(); List<string> xmlFolderList = new List<string>(); for (int i = 0; i < numOfPaths; i++) { string path = Path.Combine(folder.GetSmartParentPath(i), folder.Name); if (Directory.Exists(path)) { DirectoryInfo dirInfo = new DirectoryInfo(path); FileInfo[] fileList = dirInfo.GetFiles(); DirectoryInfo[] dirInfoList = dirInfo.GetDirectories(); string xmlPath = Path.Combine(path, CommonXMLConstants.MetadataPath); if (!File.Exists(xmlPath)) continue; CommonMethods.LoadXML(ref xmlDoc, xmlPath); xmlObjList = GetAllFilesInXML(xmlDoc); xmlFolderList = GetAllFoldersInXML(xmlDoc); RemoveSimilarFiles(xmlObjList, fileList); RemoveSimilarFolders(xmlFolderList, dirInfoList); } AddFileToChild(xmlObjList, folder, i, numOfPaths); AddFolderToChild(xmlFolderList, folder, i, numOfPaths); xmlObjList.Clear(); xmlFolderList.Clear(); } }
/// <summary> /// Visit implementaton for <see cref="FolderCompareObject"/>. /// </summary> /// <param name="folder">The <see cref="FolderCompareObject"/> to process.</param> /// <param name="numOfPaths">The total number of folders to sync.</param> public void Visit(FolderCompareObject folder, int numOfPaths) { _nodesCount++; _syncProgress.Message = folder.Name; if (folder.Invalid) { _syncProgress.Fail(); return; } int maxPriorityPos = folder.SourcePosition; // Get the position of the source file. if (folder.Priority[maxPriorityPos] > 0) { switch (folder.ChangeType[maxPriorityPos]) { case MetaChangeType.Delete: DeleteFolder(folder, numOfPaths, maxPriorityPos); break; case MetaChangeType.New: case MetaChangeType.NoChange: CreateFolder(folder, numOfPaths, maxPriorityPos); break; case MetaChangeType.Rename: MoveFolder(folder, numOfPaths, maxPriorityPos); break; } } _syncProgress.Complete(); }
/// <summary> /// Visit <see cref="FolderCompareObject"/> implementation for BuilderVisitor. /// </summary> /// <param name="folder">The <see cref="FolderCompareObject"/> to build and process.</param> /// <param name="numOfPaths">The total number of folders to keep in sync.</param> public void Visit(FolderCompareObject folder, int numOfPaths) { try { RootCompareObject root = folder as RootCompareObject; for (int index = 0; index < numOfPaths; index++) { string path = root == null ? Path.Combine(folder.GetSmartParentPath(index), folder.Name) : root.Paths[index]; DirectoryInfo f = new DirectoryInfo(path); if (f.Exists) { if (_progress != null) { _progress.Message = f.FullName; _progress.Update(); } ProcessFolders(folder, numOfPaths, f, index); ProcessFiles(folder, numOfPaths, f, index); } } } catch (UnauthorizedAccessException e) { ServiceLocator.GetLogger(ServiceLocator.DEBUG_LOG).Write(e); ServiceLocator.GetLogger(ServiceLocator.USER_LOG).Write(new LogData(LogEventType.UNKNOWN, "Error retrieving contents of folder due to unauthorized access.")); } catch (PathTooLongException e) { ServiceLocator.GetLogger(ServiceLocator.DEBUG_LOG).Write(e); ServiceLocator.GetLogger(ServiceLocator.USER_LOG).Write(new LogData(LogEventType.UNKNOWN, "Error retrieving contents of folder due to path being too long.")); } }
/// <summary> /// Visit implementation for <see cref="FolderCompareObject"/>. /// </summary> /// <param name="folder">The <see cref="FolderCompareObject"/> to process.</param> /// <param name="numOfPaths">The total number of folders to keep in sync.</param> public void Visit(FolderCompareObject folder, int numOfPaths) { if (folder.Invalid) return; CompareFolders(folder, numOfPaths); _totalNodes++; }
private long[] _metaLastWriteTimeUtc; // Array to store the last write time of each file based on metadata. /// <summary> /// Initializes a <c>FileCompareObject</c> given the name of the file, the number of paths to synchronize, and the parent of this file. /// </summary> /// <param name="name">A <see cref="string"/> containing the name of this <c>FileCompareObject</c>.</param> /// <param name="numOfPaths">An <see cref="int"/> containing the number of paths to synchronize.</param> /// <param name="parent">The <see cref="FolderCompareObject"/> which is the parent of this <c>FileCompareObject</c>.</param> public FileCompareObject(string name, int numOfPaths, FolderCompareObject parent) : base(name, numOfPaths, parent) { _hash = new string[numOfPaths]; _length = new long[numOfPaths]; _lastWriteTimeUtc = new long[numOfPaths]; _metaHash = new string[numOfPaths]; _metaLength = new long[numOfPaths]; _metaLastWriteTimeUtc = new long[numOfPaths]; }
/// <summary> /// Helper Method to traverse a FolderCompareObjects and all foldercompareobjects and filecompareobjects under it /// </summary> /// <param name="folder">FolderCompareObject to start the traversal</param> /// <param name="numOfPaths">No. of paths available</param> /// <param name="visitor">A particular visit to visit the RCOs. In this case, it will be the PreviewVisitor</param> private static void TraverseFolderHelper(FolderCompareObject folder, int numOfPaths, IVisitor visitor) { visitor.Visit(folder, numOfPaths); Dictionary<string, BaseCompareObject>.ValueCollection values = folder.Contents.Values; FolderCompareObject fco; foreach (BaseCompareObject o in values) { if ((fco = o as FolderCompareObject) != null) TraverseFolderHelper(fco, numOfPaths, visitor); else visitor.Visit(o as FileCompareObject, numOfPaths); } }
// Detect folder renames, if any. private void DetectFolderRename(FolderCompareObject folder, int numOfPaths) { List<int> deleteIndexes = new List<int>(); // Keeps a list of deleted indexes List<int> unchangedIndexes = new List<int>(); // Keeps a list of unchanged indexes for (int i = 0; i < numOfPaths; i++) { switch (folder.ChangeType[i]) { case MetaChangeType.Delete: deleteIndexes.Add(i); break; case MetaChangeType.NoChange: unchangedIndexes.Add(i); break; } } // 1. If there exists a folder for which meta exists is true and exists is false, it is (aka changeType.delete) // highly probable that it is a folder rename // 2. We check all folders which has the same meta name but different name as the non-existent folder // 3. If the count is 1, we shall proceed to rename FolderCompareObject folderObject; if (deleteIndexes.Count > 0) { int renameCount; folderObject = folder.Parent.GetRenamedFolder(folder.Name, out renameCount); if (renameCount > 1) // Multiple renames detected, set all unchanged to New so they will be propagated again { foreach (int j in unchangedIndexes) folder.ChangeType[j] = MetaChangeType.New; return; // Exit } if (folderObject != null) // If folderObject != null and we reach here implies renameCounter is 1. { for (int i = 0; i < numOfPaths; i++) { if (!folderObject.Exists[i]) // Remove all delete indexes if folder object does not exist at specified index deleteIndexes.Remove(i); // so that only those that exist will be merged } MergeRenamedFolder(folder, folderObject, deleteIndexes); } } }
private LastKnownState?[] _lastKnownState; // Stores the last known state, eg. delete, if the file system object is no longer found. /// <summary> /// Initializes a <c>BaseCompareObject</c> given the name, the number of paths to synchronize, and the parent of it. /// </summary> /// <param name="name">A <see cref="string"/> containing the name.</param> /// <param name="numOfPaths">An <see cref="int"/> with the number of paths to synchronize.</param> /// <param name="parent">A <see cref="FolderCompareObject"/> which is the parent of this object. It can be null, in the case where this object is a <see cref="RootCompareObject"/>.</param> protected BaseCompareObject(string name, int numOfPaths, FolderCompareObject parent) { _name = name; _creationTimeUtc = new long[numOfPaths]; _exists = new bool[numOfPaths]; _finalState = new FinalState?[numOfPaths]; _metaCreationTimeUtc = new long[numOfPaths]; _metaExists = new bool[numOfPaths]; _metaUpdated = new long[numOfPaths]; _changeType = new MetaChangeType?[numOfPaths]; _priority = new int[numOfPaths]; _parent = parent; _invalid = false; _lastKnownState = new LastKnownState?[numOfPaths]; }
/// <summary> /// Visits each folder node and return them and it will update the values either through the meta data /// or the last known state document /// </summary> /// <param name="folder"></param> /// <param name="numOfPaths"></param> public void Visit(FolderCompareObject folder, int numOfPaths) { XmlDocument xmlDoc = new XmlDocument(); PopulateFolderMetaName(folder, numOfPaths); for (int i = 0; i < numOfPaths; i++) { string path = Path.Combine(folder.GetSmartParentPath(i), CommonXMLConstants.MetadataPath); if (!File.Exists(path)) continue; CommonMethods.LoadXML(ref xmlDoc, path); folder = PopulateFolderWithMetaData(xmlDoc, folder, i); } AddXmlNodes(folder, numOfPaths, xmlDoc); }
/// <summary> /// It calls ProcessFolderFinalState method and if either needLastKnownState or the method is true, /// it will call GenerateFolderLastKnownState method to write a last known state document /// </summary> /// <param name="folder"></param> /// <param name="numOfPaths"></param> public void Visit(FolderCompareObject folder, int numOfPaths) { if (folder.Invalid) return; bool needLastKnownState = false; for (int i = 0; i < numOfPaths; i++) { _progress.Message = Path.Combine(folder.GetSmartParentPath(i), folder.Name); needLastKnownState = ProcessFolderFinalState(folder, i) || needLastKnownState; } if (needLastKnownState) GenerateFolderLastKnownState(folder, numOfPaths); _progress.Complete(); }
private void MoveFolder(FolderCompareObject folder, int numOfPaths, int srcFolderPos) { bool changed = false; for (int i = 0; i < numOfPaths; i++) { if (i != srcFolderPos && folder.Priority[i] != folder.Priority[srcFolderPos]) { string oldFolderName = Path.Combine(folder.GetSmartParentPath(i), folder.Name); string newFolderName = Path.Combine(folder.GetSmartParentPath(i), folder.NewName); string srcFolderName = Path.Combine(folder.GetSmartParentPath(srcFolderPos), folder.NewName); try { if (Directory.Exists(oldFolderName)) { CommonMethods.MoveFolder(oldFolderName, newFolderName); // Rename the old folder to the new name if it exists. folder.FinalState[i] = FinalState.Renamed; ServiceLocator.GetLogger(ServiceLocator.USER_LOG).Write(new LogData(LogEventType.FSCHANGE_RENAMED, "Folder renamed from " + oldFolderName + " to " + newFolderName)); } else { CommonMethods.CopyDirectory(srcFolderName, newFolderName); // Copy the directory from the source folder if the old folder does not exist. folder.Exists[i] = true; folder.CreationTimeUtc[i] = Directory.GetCreationTimeUtc(newFolderName).Ticks; folder.FinalState[i] = FinalState.CreatedRenamed; ServiceLocator.GetLogger(ServiceLocator.USER_LOG).Write(new LogData(LogEventType.FSCHANGE_CREATED, "Folder copied from " + srcFolderName + " to " + newFolderName)); } changed = true; } catch (MoveFolderException) { folder.FinalState[i] = FinalState.Error; ServiceLocator.GetLogger(ServiceLocator.USER_LOG).Write(new LogData(LogEventType.FSCHANGE_ERROR, "Error renaming folder from " + oldFolderName + " to " + newFolderName)); } catch (CopyFolderException) { folder.FinalState[i] = FinalState.Error; ServiceLocator.GetLogger(ServiceLocator.USER_LOG).Write(new LogData(LogEventType.FSCHANGE_ERROR, "Error copying folder: " + srcFolderName + " to " + newFolderName)); } } else { folder.FinalState[i] = FinalState.Renamed; changed = true; } } folder.FinalState[srcFolderPos] = changed ? FinalState.Renamed : FinalState.Unchanged; // If changed is true, that means at least one file has been affected, set the FinalState to renamed. Otherwise, leave it as Unchanged. }
private void DeleteFolder(FolderCompareObject folder, int numOfPaths, int srcFolderPos) { bool changed = false; for (int i = 0; i < numOfPaths; i++) { if (i != srcFolderPos && folder.Priority[i] != folder.Priority[srcFolderPos]) { string destFolder = Path.Combine(folder.GetSmartParentPath(i), folder.Name); try { if (_syncConfig.ArchiveLimit > 0) { CommonMethods.ArchiveFolder(destFolder, _syncConfig.ArchiveName, _syncConfig.ArchiveLimit); ServiceLocator.GetLogger(ServiceLocator.USER_LOG).Write(new LogData(LogEventType.FSCHANGE_ARCHIVED, "Folder archived " + destFolder)); } } catch (ArchiveFolderException) { folder.FinalState[i] = FinalState.Error; ServiceLocator.GetLogger(ServiceLocator.USER_LOG).Write(new LogData(LogEventType.FSCHANGE_ERROR, "Error archiving folder " + destFolder)); } try { if (_syncConfig.Recycle) CommonMethods.DeleteFolderToRecycleBin(destFolder); else CommonMethods.DeleteFolder(destFolder); folder.Exists[i] = false; folder.FinalState[i] = FinalState.Deleted; changed = true; // Set it to true since the change has propaged to at least one folder if (_syncConfig.Recycle) ServiceLocator.GetLogger(ServiceLocator.USER_LOG).Write(new LogData(LogEventType.FSCHANGE_DELETED, "Folder deleted to recycle bin " + destFolder)); else ServiceLocator.GetLogger(ServiceLocator.USER_LOG).Write(new LogData(LogEventType.FSCHANGE_DELETED, "Folder deleted " + destFolder)); } catch (DeleteFolderException) { folder.FinalState[i] = FinalState.Error; ServiceLocator.GetLogger(ServiceLocator.USER_LOG).Write(new LogData(LogEventType.FSCHANGE_ERROR, "Error deleting folder " + destFolder)); } } else { folder.FinalState[i] = folder.MetaExists[i] ? FinalState.Deleted : FinalState.Unchanged; changed = true; // Set it to true since the change has propaged to at least one folder } } folder.FinalState[srcFolderPos] = changed ? FinalState.Deleted : FinalState.Unchanged; // Set the FinalState to deleted if changed is true, otherwise set it as Unchanged. }
private void CreateFolder(FolderCompareObject folder, int numOfPaths, int srcFolderPos) { for (int i = 0; i < numOfPaths; i++) { if (i != srcFolderPos && folder.Priority[i] != folder.Priority[srcFolderPos]) { string folderToCreate = Path.Combine(folder.GetSmartParentPath(i), folder.Name); if (!Directory.Exists(folderToCreate)) { try { CommonMethods.CreateFolder(folderToCreate); // Create the folder since it does not exist folder.Exists[i] = true; // Update the state of the folder folder.CreationTimeUtc[i] = Directory.GetCreationTimeUtc(folderToCreate).Ticks; folder.FinalState[i] = FinalState.Created; ServiceLocator.GetLogger(ServiceLocator.USER_LOG).Write(new LogData(LogEventType.FSCHANGE_CREATED, "Folder created " + folderToCreate)); } catch (CreateFolderException) { folder.FinalState[i] = FinalState.Error; ServiceLocator.GetLogger(ServiceLocator.USER_LOG).Write(new LogData(LogEventType.FSCHANGE_ERROR, "Error creating folder " + folderToCreate)); } } } else { folder.FinalState[i] = folder.MetaExists[i] ? FinalState.Unchanged : FinalState.Created; // Set the FinalState to unchanged if the metadata already exists, else set it to created. } } folder.FinalState[srcFolderPos] = folder.MetaExists[srcFolderPos] ? FinalState.Unchanged : FinalState.Created; // Set the FinalState to unchanged if the metadata exists, else set it to created. }
// Based on the folder and counter , it will load the xml document and delete the folder node private void DeleteFolderObject(FolderCompareObject folder, int counter) { XmlDocument xmlDoc = new XmlDocument(); string xmlPath = Path.Combine(folder.GetSmartParentPath(counter), CommonXMLConstants.MetadataPath); if (File.Exists(xmlPath)) { CommonMethods.LoadXML(ref xmlDoc, xmlPath); XmlNode node = xmlDoc.SelectSingleNode(CommonXMLConstants.XPathExpr + CommonXMLConstants.XPathFolder + "[name=" + CommonMethods.ParseXPathString(folder.Name) + "]"); if (node == null) return; node.ParentNode.RemoveChild(node); CommonMethods.SaveXML(ref xmlDoc, xmlPath); } }
// Populate the folder's meta name if it exists private void PopulateFolderMetaName(FolderCompareObject folder, int numOfPaths) { for (int i = 0; i < numOfPaths; i++) { string currMetaData = Path.Combine(Path.Combine(folder.GetSmartParentPath(i), folder.Name), CommonXMLConstants.MetadataPath); if (File.Exists(currMetaData)) { XmlDocument xmlDoc = new XmlDocument(); CommonMethods.LoadXML(ref xmlDoc, currMetaData); XmlNode xmlNode = xmlDoc.SelectSingleNode(CommonXMLConstants.XPathExpr + "/name"); if (xmlNode != null) folder.MetaName = xmlNode.InnerText; } } }
// For any folder name in the list , create them as a node and append them to the folder node private void AddFolderToChild(List<string> folderName, FolderCompareObject folder, int counter, int length) { for (int i = 0; i < folderName.Count; i++) { BaseCompareObject o = folder.GetChild(folderName[i]); FolderCompareObject fco; if (o == null) fco = new FolderCompareObject(folderName[i], length, folder); else fco = (FolderCompareObject)o; fco.MetaExists[counter] = true; if (o == null) folder.AddChild(fco); } }
// Method will return any time the state of the sync progress becomes cancelled. private static void TraverseFolderHelper(FolderCompareObject folder, int numOfPaths, IVisitor visitor, TraverseType type, Progress syncProgress) { if (syncProgress != null && syncProgress.State == SyncState.Cancelled) return; if (type == TraverseType.Pre) visitor.Visit(folder, numOfPaths); Dictionary<string, BaseCompareObject>.ValueCollection values = folder.Contents.Values; foreach (BaseCompareObject o in values) { if (syncProgress != null && syncProgress.State == SyncState.Cancelled) return; FolderCompareObject fco; if ((fco = o as FolderCompareObject) != null) TraverseFolderHelper(fco, numOfPaths, visitor, type, syncProgress); else visitor.Visit(o as FileCompareObject, numOfPaths); } if (type == TraverseType.Post) visitor.Visit(folder, numOfPaths); }
// Checks if the last known state document exists and calls the AppendActionFolderLastKnownState method private void GenerateFolderLastKnownState(FolderCompareObject folder, int numOfPaths) { for (int i = 0; i < numOfPaths; i++) { string parentPath = folder.GetSmartParentPath(i); XmlDocument xmlTodoDoc = new XmlDocument(); string todoPath = Path.Combine(parentPath, CommonXMLConstants.LastKnownStatePath); CommonMethods.CreateLastKnownStateFile(parentPath); CommonMethods.LoadXML(ref xmlTodoDoc, todoPath); CommonMethods.DoFolderLastKnownCleanUp(xmlTodoDoc, folder.Name); AppendActionFolderLastKnownState(xmlTodoDoc, folder, CommonXMLConstants.ActionDeleted); CommonMethods.SaveXML(ref xmlTodoDoc, todoPath); } }
// Deletes a folder node in the last known state file by searching for the name private void DeleteFolderLastKnownState(FolderCompareObject folder, int counter) { string todoXMLPath = Path.Combine(folder.GetSmartParentPath(counter), CommonXMLConstants.LastKnownStatePath); if (!File.Exists(todoXMLPath)) return; XmlDocument todoXMLDoc = new XmlDocument(); CommonMethods.LoadXML(ref todoXMLDoc, todoXMLPath); XmlNode folderNode = todoXMLDoc.SelectSingleNode(CommonXMLConstants.XPathLastKnownState + CommonXMLConstants.XPathFolder + "[name=" + CommonMethods.ParseXPathString(folder.Name) + "]"); if (folderNode != null) folderNode.ParentNode.RemoveChild(folderNode); CommonMethods.SaveXML(ref todoXMLDoc, todoXMLPath); }
// Creates a folder node in the last known state file based on the values in FolderCompareObject private void AppendActionFolderLastKnownState(XmlDocument xmlDoc, FolderCompareObject folder, string changeType) { string name = folder.MetaName ?? folder.Name; XmlText nameText = xmlDoc.CreateTextNode(name); XmlText action = xmlDoc.CreateTextNode(changeType); XmlText lastUpdatedUtcText = xmlDoc.CreateTextNode(_dateTime.ToString()); XmlElement folderElement = xmlDoc.CreateElement(CommonXMLConstants.NodeFolder); XmlElement nameElement = xmlDoc.CreateElement(CommonXMLConstants.NodeName); XmlElement actionElement = xmlDoc.CreateElement(CommonXMLConstants.NodeAction); XmlElement lastUpdatedElement = xmlDoc.CreateElement(CommonXMLConstants.NodeLastUpdatedUtc); nameElement.AppendChild(nameText); actionElement.AppendChild(action); lastUpdatedElement.AppendChild(lastUpdatedUtcText); folderElement.AppendChild(nameElement); folderElement.AppendChild(actionElement); folderElement.AppendChild(lastUpdatedElement); XmlNode rootNode = xmlDoc.SelectSingleNode(CommonXMLConstants.XPathLastKnownState); if(rootNode == null) return; rootNode.AppendChild(folderElement); }
// Based on the folder and path , it will load the xml document in the sub folder and modify the name private void ModifyFolderName(FolderCompareObject folder, string subFolderPath) { string name = folder.NewName ?? folder.Name; string xmlPath = Path.Combine(Path.Combine(subFolderPath, name), CommonXMLConstants.MetadataPath); XmlDocument subFolderDoc = new XmlDocument(); CommonMethods.LoadXML(ref subFolderDoc, xmlPath); XmlNode xmlNameNode = subFolderDoc.SelectSingleNode(CommonXMLConstants.XPathExpr + CommonXMLConstants.XPathName); if (xmlNameNode != null) xmlNameNode.InnerText = name; CommonMethods.SaveXML(ref subFolderDoc, xmlPath); }
// Based on the final state of the folder , it will let the respective method handle it private bool ProcessFolderFinalState(FolderCompareObject folder, int counter) { FinalState?[] finalStateList = folder.FinalState; FinalState? changeType = finalStateList[counter]; bool needLastKnownState = false; switch (changeType) { case FinalState.Created: CreateFolderObject(folder, counter, false); break; case FinalState.Deleted: DeleteFolderObject(folder, counter); needLastKnownState = true; break; case FinalState.Renamed: RenameFolderObject(folder, counter); needLastKnownState = true; break; case FinalState.CreatedRenamed: CreateFolderObject(folder, counter, true); DeleteFolderObject(folder, counter); needLastKnownState = true; break; } return needLastKnownState; }
// For any XMLCompareObjects in the list , create them as a node and append them to the folder node private void AddFileToChild(List<XMLCompareObject> xmlFileList, FolderCompareObject folder, int counter, int length) { for (int i = 0; i < xmlFileList.Count; i++) { BaseCompareObject o = folder.GetChild(xmlFileList[i].Name); FileCompareObject fco; if (o == null) fco = new FileCompareObject(xmlFileList[i].Name, length, folder); else fco = (FileCompareObject)o; fco.MetaCreationTimeUtc[counter] = xmlFileList[i].CreatedTimeUtc; fco.MetaHash[counter] = xmlFileList[i].Hash; fco.MetaLastWriteTimeUtc[counter] = xmlFileList[i].LastModifiedTimeUtc; fco.MetaLength[counter] = xmlFileList[i].Size; fco.MetaUpdated[counter] = xmlFileList[i].LastUpdatedTimeUtc; fco.MetaExists[counter] = true; if (o == null) folder.AddChild(fco); } }
/// <summary> /// Processes and adds files to the tree. /// </summary> /// <param name="folder"><see cref="FolderCompareObject"/> to process and add files to.</param> /// <param name="numOfPaths">The total number of sync folders.</param> /// <param name="f">The <see cref="DirectoryInfo"/> to process and get files from.</param> /// <param name="index">The index indicating which sync folder it belongs to.</param> private void ProcessFiles(FolderCompareObject folder, int numOfPaths, DirectoryInfo f, int index) { try { FileInfo[] fileInfos = f.GetFiles(); foreach (FileInfo info in fileInfos) { if (_filterChain.ApplyFilter(_filter, info.FullName)) { if (_progress != null) { _progress.Message = info.FullName; _progress.Update(); } BaseCompareObject o = folder.GetChild(info.Name); // Gets a child with the same name. FileCompareObject fco = null; bool conflict = false; if (o == null) // If o is null, create a new file compare object fco = new FileCompareObject(info.Name, numOfPaths, folder); else { try { fco = (FileCompareObject)o; // Case o to a FileCompareObject is o is not null } catch (InvalidCastException) // If invalid cast, it means there is a FolderCompareObject with the exact same name. { _typeConflicts.Add(info.FullName); // Add to to conflicts conflict = true; ServiceLocator.GetLogger(ServiceLocator.USER_LOG).Write( new LogData(LogEventType.FSCHANGE_CONFLICT, "Conflicted file detected " + info.FullName)); } } if (!conflict) { fco.CreationTimeUtc[index] = info.CreationTimeUtc.Ticks; fco.LastWriteTimeUtc[index] = info.LastWriteTimeUtc.Ticks; fco.Length[index] = info.Length; fco.Exists[index] = true; if (o == null) folder.AddChild(fco); // Add the newly created FileCompareObject to this current folder } } } } catch (UnauthorizedAccessException e) { ServiceLocator.GetLogger(ServiceLocator.DEBUG_LOG).Write(e); ServiceLocator.GetLogger(ServiceLocator.USER_LOG).Write(new LogData(LogEventType.UNKNOWN, "Error retrieving contents of folder due to unauthorized access.")); } catch (DirectoryNotFoundException e) { ServiceLocator.GetLogger(ServiceLocator.DEBUG_LOG).Write(e); ServiceLocator.GetLogger(ServiceLocator.USER_LOG).Write(new LogData(LogEventType.UNKNOWN, "Error retrieving contents of folder due to directory not being found.")); } }
// For each list of folder names , create a node and append them to the root node private void AddFolderToRoot(List<string> folderName, RootCompareObject root, int counter, int length) { if (folderName.Count == 0) return; for (int i = 0; i < folderName.Count; i++) { BaseCompareObject o = root.GetChild(folderName[i]); FolderCompareObject fco; if (o == null) fco = new FolderCompareObject(folderName[i], length, root); else fco = (FolderCompareObject)o; fco.MetaExists[counter] = true; if (o == null) root.AddChild(fco); } }
/// <summary> /// Processes and adds folders to the tree. /// </summary> /// <param name="folder"><see cref="FolderCompareObject"/> to process and add folders to.</param> /// <param name="numOfPaths">The total number of sync folders.</param> /// <param name="f">The <see cref="DirectoryInfo"/> to process and get folders from.</param> /// <param name="index">The index indicating which sync folder it belongs to.</param> private void ProcessFolders(FolderCompareObject folder, int numOfPaths, DirectoryInfo f, int index) { try { DirectoryInfo[] infos = f.GetDirectories(); foreach (DirectoryInfo info in infos) { if (_filterChain.ApplyFilter(_filter, info.FullName)) { if (_progress != null) { _progress.Message = info.FullName; _progress.Update(); } BaseCompareObject o = folder.GetChild(info.Name); // Gets a child with the same name. FolderCompareObject fco; bool conflict = false; if (o == null) // If o is null, create a new folder compare object. fco = new FolderCompareObject(info.Name, numOfPaths, folder); // Create a new folder compare object else { try { fco = (FolderCompareObject)o; // Cast o to a FolderCompareObject. } catch (InvalidCastException) // Happens when a file has the same name as the folder. { for (int i = 0; i < numOfPaths; i++) { if (o.Exists[i]) _typeConflicts.Add(Path.Combine(o.GetSmartParentPath(i), o.Name)); } folder.RemoveChild(info.Name); //Remove file object fco = new FolderCompareObject(info.Name, numOfPaths, folder); // Create a new folder compare object conflict = true; ServiceLocator.GetLogger(ServiceLocator.USER_LOG).Write( new LogData(LogEventType.FSCHANGE_CONFLICT, "Conflicted file detected " + info.FullName)); } } fco.CreationTimeUtc[index] = info.CreationTimeUtc.Ticks; fco.Exists[index] = true; if (o == null || conflict) folder.AddChild(fco); // Add the newly created FolderCompareObject to this current folder } } } catch (UnauthorizedAccessException e) { ServiceLocator.GetLogger(ServiceLocator.DEBUG_LOG).Write(e); ServiceLocator.GetLogger(ServiceLocator.USER_LOG).Write(new LogData(LogEventType.UNKNOWN, "Error retrieving contents of folder due to unauthorized access.")); } catch (DirectoryNotFoundException e) { ServiceLocator.GetLogger(ServiceLocator.DEBUG_LOG).Write(e); ServiceLocator.GetLogger(ServiceLocator.USER_LOG).Write(new LogData(LogEventType.UNKNOWN, "Error retrieving contents of folder due to directory not being found.")); } }
// Checks the meta data by the folder name , if it exists , set it MetaExists to true. // If not , look up the last known state and populate the values from that document private FolderCompareObject PopulateFolderWithMetaData(XmlDocument xmlDoc, FolderCompareObject folder, int counter) { XmlNode node = xmlDoc.SelectSingleNode(CommonXMLConstants.XPathExpr + CommonXMLConstants.XPathFolder + "[name=" + CommonMethods.ParseXPathString(folder.Name) + "]"); if (node != null) { folder.MetaExists[counter] = true; } else { string path = Path.Combine(folder.GetSmartParentPath(counter), CommonXMLConstants.LastKnownStatePath); if (File.Exists(path)) { XmlDocument lastKnownXmlDoc = new XmlDocument(); CommonMethods.LoadXML(ref lastKnownXmlDoc, path); XmlNode folderNode = lastKnownXmlDoc.SelectSingleNode(CommonXMLConstants.XPathLastKnownState + CommonXMLConstants.XPathFolder + "[name=" + CommonMethods.ParseXPathString(folder.Name) + "]"); if (folderNode != null) { XmlNodeList nodeList = folderNode.ChildNodes; for (int i = 0; i < nodeList.Count; i++) { XmlNode childNode = nodeList[i]; switch (childNode.Name) { case CommonXMLConstants.NodeAction: string action = childNode.InnerText; if (action.Equals("deleted")) folder.LastKnownState[counter] = LastKnownState.Deleted; else folder.LastKnownState[counter] = LastKnownState.Renamed; break; case CommonXMLConstants.NodeLastUpdatedUtc: folder.MetaUpdated[counter] = long.Parse(childNode.InnerText); break; } } } } } return folder; }
// Based on the folder and counter , it will create a folder node in the meta data private void CreateFolderObject(FolderCompareObject folder, int counter, bool useNewName) { string name = useNewName ? folder.NewName : folder.Name; XmlDocument xmlDoc = new XmlDocument(); string xmlPath = Path.Combine(folder.GetSmartParentPath(counter), CommonXMLConstants.MetadataPath); CommonMethods.CreateFileIfNotExist(folder.GetSmartParentPath(counter)); CommonMethods.LoadXML(ref xmlDoc, xmlPath); CommonMethods.DoFolderCleanUp(xmlDoc, name); XmlText nameText = xmlDoc.CreateTextNode(name); XmlText lastUpdatedUtcText = xmlDoc.CreateTextNode(_dateTime.ToString()); XmlElement nameElement = xmlDoc.CreateElement(CommonXMLConstants.NodeName); XmlElement lastUpdatedElement = xmlDoc.CreateElement(CommonXMLConstants.NodeLastUpdatedUtc); XmlElement folderElement = xmlDoc.CreateElement(CommonXMLConstants.NodeFolder); nameElement.AppendChild(nameText); lastUpdatedElement.AppendChild(lastUpdatedUtcText); folderElement.AppendChild(nameElement); folderElement.AppendChild(lastUpdatedElement); XmlNode node = xmlDoc.SelectSingleNode(CommonXMLConstants.XPathExpr); if (node == null) return; node.AppendChild(folderElement); string subFolderXML = Path.Combine(folder.GetSmartParentPath(counter), name); CommonMethods.CreateFileIfNotExist(subFolderXML); CommonMethods.SaveXML(ref xmlDoc, xmlPath); ModifyFolderName(folder, folder.GetSmartParentPath(counter)); DeleteFolderLastKnownState(folder, counter); }
private string _metaName; // The name of the folder based on the metadata. /// <summary> /// Initializes a <c>FolderCompareObject</c> given the name of the file, the number of paths to synchronize, and the parent of this file. /// </summary> /// <param name="name">A <see cref="string"/> containing the name of this <c>FolderCompareObject</c>.</param> /// <param name="numOfPaths">An <see cref="int"/> containing the number of paths to synchronize.</param> /// <param name="parent">The <see cref="FolderCompareObject"/> which is the parent of this <c>FolderCompareObject</c>.</param> public FolderCompareObject(string name, int numOfPaths, FolderCompareObject parent) : base(name, numOfPaths, parent) { _contents = new Dictionary<string, BaseCompareObject>(StringComparer.OrdinalIgnoreCase); }
// Based on the folder and counter , it will load the xml document and rename it private void RenameFolderObject(FolderCompareObject folder, int counter) { if (Directory.Exists(Path.Combine(folder.GetSmartParentPath(counter), folder.Name))) { XmlDocument xmlDoc = new XmlDocument(); string xmlPath = Path.Combine(folder.GetSmartParentPath(counter), CommonXMLConstants.MetadataPath); CommonMethods.LoadXML(ref xmlDoc, xmlPath); XmlNode node = xmlDoc.SelectSingleNode(CommonXMLConstants.XPathExpr + CommonXMLConstants.XPathFolder + "[name=" + CommonMethods.ParseXPathString(folder.Name) + "]"); if (node == null) { CreateFolderObject(folder, counter, true); return; } node.FirstChild.InnerText = folder.NewName; node.LastChild.InnerText = _dateTime.ToString(); CommonMethods.SaveXML(ref xmlDoc, xmlPath); } else { XmlDocument newXmlDoc = new XmlDocument(); string editOldXML = Path.Combine(Path.Combine(folder.GetSmartParentPath(counter), folder.NewName), CommonXMLConstants.MetadataPath); CommonMethods.CreateFileIfNotExist(Path.Combine(folder.GetSmartParentPath(counter), folder.NewName)); CommonMethods.LoadXML(ref newXmlDoc, editOldXML); XmlNode xmlNameNode = newXmlDoc.SelectSingleNode(CommonXMLConstants.XPathExpr + CommonXMLConstants.XPathName); if (xmlNameNode != null) xmlNameNode.InnerText = folder.NewName; CommonMethods.SaveXML(ref newXmlDoc, editOldXML); string parentXML = Path.Combine(folder.GetSmartParentPath(counter), CommonXMLConstants.MetadataPath); XmlDocument parentXmlDoc = new XmlDocument(); CommonMethods.CreateFileIfNotExist(folder.GetSmartParentPath(counter)); CommonMethods.LoadXML(ref parentXmlDoc, parentXML); XmlNode parentXmlFolderNode = parentXmlDoc.SelectSingleNode(CommonXMLConstants.XPathExpr + CommonXMLConstants.XPathFolder + "[name=" + CommonMethods.ParseXPathString(folder.Name) + "]"); if (parentXmlFolderNode != null) { parentXmlFolderNode.FirstChild.InnerText = folder.NewName; parentXmlFolderNode.LastChild.InnerText = _dateTime.ToString(); } CommonMethods.SaveXML(ref parentXmlDoc, Path.Combine(folder.GetSmartParentPath(counter), CommonXMLConstants.MetadataPath)); } }