/// <summary> /// Solve the specified situation by using localFile and remote object. /// </summary> /// <param name="localFileSystemInfo">Local filesystem info instance.</param> /// <param name="remoteId">Remote identifier or object.</param> /// <param name="localContent">Hint if the local content has been changed.</param> /// <param name="remoteContent">Information if the remote content has been changed.</param> public override void Solve( IFileSystemInfo localFileSystemInfo, IObjectId remoteId, ContentChangeType localContent, ContentChangeType remoteContent) { if (localFileSystemInfo is IDirectoryInfo) { IDirectoryInfo localFolder = localFileSystemInfo as IDirectoryInfo; IDirectoryInfo localParent = localFolder.Parent; IFolder remoteFolder = remoteId as IFolder; string remoteParentId = remoteFolder.ParentId; IMappedObject mappedParent = this.Storage.GetObjectByRemoteId(remoteFolder.ParentId); IMappedObject mappedObject = this.Storage.GetObjectByRemoteId(remoteFolder.Id); if (localParent.Uuid == mappedParent.Guid) { // Both folders are in the same parent folder this.SyncNamesAndDates(localFolder, remoteFolder, mappedObject); } else { throw new NotImplementedException(); } } else { throw new NotImplementedException(); } }
/// <summary> /// Solve the specified situation by using localFile and remote object. /// </summary> /// <param name="localFileSystemInfo">Local filesystem info instance.</param> /// <param name="remoteId">Remote identifier or object.</param> /// <param name="localContent">Hint if the local content has been changed.</param> /// <param name="remoteContent">Information if the remote content has been changed.</param> public override void Solve( IFileSystemInfo localFileSystemInfo, IObjectId remoteId, ContentChangeType localContent, ContentChangeType remoteContent) { if (localFileSystemInfo is IDirectoryInfo) { IDirectoryInfo localFolder = localFileSystemInfo as IDirectoryInfo; IDirectoryInfo localParent = localFolder.Parent; IFolder remoteFolder = remoteId as IFolder; string remoteParentId = remoteFolder.ParentId; IMappedObject mappedParent = this.Storage.GetObjectByRemoteId(remoteParentId); IMappedObject mappedObject = this.Storage.GetObjectByRemoteId(remoteFolder.Id); if (localParent.Uuid == mappedParent.Guid) { // Both folders are in the same parent folder this.SyncNamesAndDates(localFolder, remoteFolder, mappedObject); } else { OperationsLogger.Warn( string.Format( "Synchronization Conflict: The local directory {0} has been moved to {1} with id {2},{4}" + "but the remote folder was moved to {3}{4}You can fix this situation by moving them into the same folder", localFileSystemInfo.Name, localFileSystemInfo.FullName, remoteFolder.Path, Environment.NewLine)); return; } } else if (localFileSystemInfo is IFileInfo) { IFileInfo localFile = localFileSystemInfo as IFileInfo; IDirectoryInfo localParent = localFile.Directory; IDocument remoteFile = remoteId as IDocument; string remoteParentId = remoteFile.Parents[0].Id; IMappedObject mappedParent = this.Storage.GetObjectByRemoteId(remoteParentId); IMappedObject mappedObject = this.Storage.GetObjectByRemoteId(remoteFile.Id); if (localParent.Uuid == mappedParent.Guid) { // Both files are in the same parent folder this.SyncNamesAndDates(localFile, remoteFile, mappedObject); return; } else { OperationsLogger.Warn( string.Format( "Synchronization Conflict: The local file {0} has been moved to {1} with id {2},{4}" + "but the remote file was moved to {3}{4}You can fix this situation by moving them into the same folder", localFileSystemInfo.Name, localFileSystemInfo.FullName, remoteFile.Paths[0], Environment.NewLine)); return; } } }
private void HandleAsIFolder(ContentChangeEvent contentChangeEvent) { IFolder folder = contentChangeEvent.CmisObject as IFolder; IMappedObject dir = this.storage.GetObjectByRemoteId(folder.Id); IDirectoryInfo dirInfo = (dir == null) ? null : this.fsFactory.CreateDirectoryInfo(this.storage.GetLocalPath(dir)); var folderEvent = new FolderEvent(dirInfo, folder, this); switch (contentChangeEvent.Type) { case DotCMIS.Enums.ChangeType.Created: Logger.Debug("Created Folder Event"); folderEvent.Remote = MetaDataChangeType.CREATED; break; case DotCMIS.Enums.ChangeType.Updated: folderEvent.Remote = MetaDataChangeType.CHANGED; break; case DotCMIS.Enums.ChangeType.Security: folderEvent.Remote = MetaDataChangeType.CHANGED; break; } Queue.AddEvent(folderEvent); }
public CrawlEventCollection GenerateEvents(DescendantsTreeCollection trees) { IObjectTree <IMappedObject> storedTree = trees.StoredTree; IObjectTree <IFileSystemInfo> localTree = trees.LocalTree; IObjectTree <IFileableCmisObject> remoteTree = trees.RemoteTree; CrawlEventCollection createdEvents = new CrawlEventCollection(); List <IMappedObject> storedObjectsForRemote = storedTree.ToList(); List <IMappedObject> storedObjectsForLocal = new List <IMappedObject>(storedObjectsForRemote); Dictionary <string, Tuple <AbstractFolderEvent, AbstractFolderEvent> > eventMap = new Dictionary <string, Tuple <AbstractFolderEvent, AbstractFolderEvent> >(); createdEvents.creationEvents = this.remoteEventGenerator.CreateEvents(storedObjectsForRemote, remoteTree, eventMap); createdEvents.creationEvents.AddRange(this.localEventGenerator.CreateEvents(storedObjectsForLocal, localTree, eventMap)); createdEvents.mergableEvents = eventMap; IMappedObject rootNode = storedTree.Item; storedObjectsForLocal.Remove(rootNode); storedObjectsForRemote.Remove(rootNode); createdEvents.removedLocalObjects = this.TransformToFileSystemInfoDict(storedObjectsForLocal); createdEvents.removedRemoteObjects = this.TransformToFileSystemInfoDict(storedObjectsForRemote); return(createdEvents); }
private string GetParentId(IFileSystemInfo fileInfo, IMetaDataStorage storage) { IDirectoryInfo parent = null; if (fileInfo is IDirectoryInfo) { IDirectoryInfo localDirInfo = fileInfo as IDirectoryInfo; parent = localDirInfo.Parent; } else { IFileInfo localFileInfo = fileInfo as IFileInfo; parent = localFileInfo.Directory; } try { Guid uuid; if (Guid.TryParse(parent.GetExtendedAttribute(MappedObject.ExtendedAttributeKey), out uuid)) { return(storage.GetObjectByGuid(uuid).RemoteObjectId); } } catch (IOException) { } IMappedObject mappedParent = storage.GetObjectByLocalPath(parent); return(mappedParent.RemoteObjectId); }
/// <summary> /// Gets the local path. Return null if not exists. /// </summary> /// <returns> /// The local path. /// </returns> /// <param name='mappedObject'> /// Mapped object. Must not be null. /// </param> public string GetLocalPath(IMappedObject mappedObject) { string id = this.GetId(mappedObject); using (var tran = this.engine.GetTransaction()) { string[] segments = this.GetRelativePathSegments(tran, id); if (segments == null) { return(null); } if (segments.Length > 0 && segments[0].Equals("/")) { string[] temp = new string[segments.Length - 1]; for (int i = 1; i < segments.Length; i++) { temp[i - 1] = segments[i]; } segments = temp; } return(Path.Combine(this.matcher.LocalTargetRootPath, Path.Combine(segments))); } }
/// <summary> /// Gets the children of the given parent object. /// </summary> /// <returns> /// The saved children. /// </returns> /// <param name='parent'> /// Parent of the children. /// </param> public List <IMappedObject> GetChildren(IMappedObject parent) { string parentId = this.GetId(parent); List <IMappedObject> results = new List <IMappedObject>(); bool parentExists = false; using (var tran = this.engine.GetTransaction()) { foreach (var row in tran.SelectForward <string, DbCustomSerializer <MappedObject> >(MappedObjectsTable)) { var data = row.Value.Get; if (data == null) { continue; } if (parentId == data.ParentId) { results.Add(new MappedObject(data)); } else if (data.RemoteObjectId == parentId) { parentExists = true; } } } if (!parentExists) { throw new EntryNotFoundException(); } return(results); }
/// <summary> /// Determines if file content is changed to the specified obj. /// </summary> /// <returns><c>true</c> if is the file content is different to the specified obj otherwise, <c>false</c>.</returns> /// <param name="file">File instance.</param> /// <param name="obj">Object to check the file content against.</param> /// <param name="actualHash">Contains the hash of the local file if scanned, or null if file wasn't scanned</param> /// <param name="scanOnlyIfModificationDateDiffers">If set to <c>true</c> content scan runs only if the modification date differs to given one.</param> public static bool IsContentChangedTo(this IFileInfo file, IMappedObject obj, out byte[] actualHash, bool scanOnlyIfModificationDateDiffers = false) { actualHash = null; if (obj == null) { throw new ArgumentNullException("obj"); } if (obj.LastContentSize < 0) { throw new ArgumentOutOfRangeException(string.Format("Given LastContentSize {0} is invalid for files", obj.LastContentSize.ToString())); } if (!file.Exists) { throw new FileNotFoundException(string.Format("File {0} does not exists", file.FullName)); } if (obj.LastChecksum == null) { return true; } if (file.Length == obj.LastContentSize) { if (scanOnlyIfModificationDateDiffers && obj.LastLocalWriteTimeUtc == file.LastWriteTimeUtc) { return false; } else { using (var f = file.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete)) { byte[] fileHash = SHA1Managed.Create().ComputeHash(f); actualHash = fileHash; return !fileHash.SequenceEqual(obj.LastChecksum); } } } else { return true; } }
/// <summary> /// Saves the mapped object. /// </summary> /// <param name='obj'> /// The MappedObject instance. /// </param> /// <exception cref="DublicateGuidException">Is thrown when guid already in database</exception> public void SaveMappedObject(IMappedObject obj) { string id = this.GetId(obj); using (var tran = this.engine.GetTransaction()) { var byteGuid = obj.Guid.ToByteArray(); var row = tran.Select <byte[], string>(MappedObjectsGuidsTable, byteGuid); if (row.Exists && row.Value != id) { tran.Rollback(); throw new DublicateGuidException(string.Format("An entry with Guid {0} already exists", obj.Guid)); } if (this.fullValidationOnEachManipulation && obj.ParentId != null) { DbCustomSerializer <MappedObject> value = tran.Select <string, DbCustomSerializer <MappedObject> >(MappedObjectsTable, obj.ParentId).Value; if (value == null) { tran.Rollback(); throw new InvalidDataException(); } } obj.LastTimeStoredInStorage = DateTime.UtcNow; tran.Insert <string, DbCustomSerializer <MappedObject> >(MappedObjectsTable, id, obj as MappedObject); if (!obj.Guid.Equals(Guid.Empty)) { tran.Insert <byte[], string>(MappedObjectsGuidsTable, obj.Guid.ToByteArray(), id); } tran.Commit(); } this.ValidateObjectStructureIfFullValidationIsEnabled(); }
private void HandleDeletion(ContentChangeEvent contentChangeEvent) { Logger.Debug(contentChangeEvent.ObjectId); IMappedObject savedObject = this.storage.GetObjectByRemoteId(contentChangeEvent.ObjectId); if (savedObject != null) { IMappedObject obj = savedObject as IMappedObject; if (obj != null) { if (obj.Type == MappedObjectType.Folder) { var dirInfo = this.fsFactory.CreateDirectoryInfo(this.storage.GetLocalPath(obj)); Queue.AddEvent(new FolderEvent(dirInfo, null, this) { Remote = MetaDataChangeType.DELETED }); return; } else { var fileInfo = this.fsFactory.CreateFileInfo(this.storage.GetLocalPath(obj)); Queue.AddEvent(new FileEvent(fileInfo, null) { Remote = MetaDataChangeType.DELETED }); return; } } } Logger.Debug("nothing found in local storage; it has never been synced"); }
private string GetParentId(IFileSystemInfo fileInfo, IMetaDataStorage storage) { IDirectoryInfo parent = null; if (fileInfo is IDirectoryInfo) { IDirectoryInfo localDirInfo = fileInfo as IDirectoryInfo; parent = localDirInfo.Parent; } else { IFileInfo localFileInfo = fileInfo as IFileInfo; parent = localFileInfo.Directory; } try { Guid?uuid = parent.Uuid; if (uuid != null) { return(storage.GetObjectByGuid((Guid)uuid).RemoteObjectId); } } catch (IOException) { } IMappedObject mappedParent = storage.GetObjectByLocalPath(parent); return(mappedParent.RemoteObjectId); }
/// <summary> /// Creates the local events and returns the creationEvents, the other Events are stored in the eventMap, handled objects are removed from storedObjects /// </summary> /// <returns> /// The local events. /// </returns> /// <param name='storedObjects'> /// Stored objects. /// </param> /// <param name='localTree'> /// Local tree. /// </param> /// <param name='eventMap'> /// Event map. /// </param> public List <AbstractFolderEvent> CreateEvents( List <IMappedObject> storedObjects, IObjectTree <IFileSystemInfo> localTree, Dictionary <string, Tuple <AbstractFolderEvent, AbstractFolderEvent> > eventMap) { List <AbstractFolderEvent> creationEvents = new List <AbstractFolderEvent>(); var parent = localTree.Item; IMappedObject storedParent = null; Guid? guid = parent.Uuid; if (guid != null) { storedParent = storedObjects.Find(o => o.Guid.Equals((Guid)guid)); } foreach (var child in localTree.Children) { bool removeStoredMappedChild = false; IMappedObject storedMappedChild = this.FindStoredObjectByFileSystemInfo(storedObjects, child.Item); if (storedMappedChild != null) { var localPath = this.storage.GetLocalPath(storedMappedChild); #if __COCOA__ if ((!localPath.Normalize(NormalizationForm.FormD).Equals(child.Item.FullName.Normalize(NormalizationForm.FormD))) && this.fsFactory.IsDirectory(localPath) != null) { #else if ((!localPath.Equals(child.Item.FullName)) && this.fsFactory.IsDirectory(localPath) != null) { #endif // Copied creationEvents.Add(this.GenerateCreatedEvent(child.Item)); } else { // Moved, Renamed, Updated or Equal AbstractFolderEvent correspondingRemoteEvent = GetCorrespondingRemoteEvent(eventMap, storedMappedChild); AbstractFolderEvent createdEvent = this.CreateLocalEventBasedOnStorage(child.Item, storedParent, storedMappedChild); eventMap[storedMappedChild.RemoteObjectId] = new Tuple <AbstractFolderEvent, AbstractFolderEvent>(createdEvent, correspondingRemoteEvent); removeStoredMappedChild = true; } } else { // Added creationEvents.Add(this.GenerateCreatedEvent(child.Item)); } creationEvents.AddRange(this.CreateEvents(storedObjects, child, eventMap)); if (removeStoredMappedChild) { storedObjects.Remove(storedMappedChild); } } return(creationEvents); }
private static bool VerifyMappedObject( IMappedObject o, MappedObjectType type, string remoteId, string name, string parentId, string changeToken, bool extendedAttributeAvailable, DateTime?lastLocalModification, DateTime?lastRemoteModification, byte[] checksum, long contentSize, bool ignored) { Assert.That(o.RemoteObjectId, Is.EqualTo(remoteId), "Object remote Id is wrong"); Assert.That(o.Name, Is.EqualTo(name), "Object name is wrong"); Assert.That(o.ParentId, Is.EqualTo(parentId), "Object parent Id is wrong"); Assert.That(o.LastChangeToken, Is.EqualTo(changeToken), "Object change token is wrong"); Assert.That(o.Type, Is.EqualTo(type), "Object type is wrong"); Assert.That(o.Ignored, Is.EqualTo(ignored), "Object ignore flag is wrong"); if (extendedAttributeAvailable) { Assert.That(o.Guid, Is.Not.EqualTo(Guid.Empty), "Given Guid must not be empty"); } else { Assert.That(o.Guid, Is.EqualTo(Guid.Empty), "Given Guid must be empty"); } if (lastLocalModification != null) { Assert.That(o.LastLocalWriteTimeUtc, Is.EqualTo(lastLocalModification), "Last local modification date is wrong"); } if (lastRemoteModification != null) { Assert.That(o.LastRemoteWriteTimeUtc, Is.EqualTo(lastRemoteModification), "Last remote modification date is wrong"); } if (checksum != null) { Assert.That(o.ChecksumAlgorithmName, Is.EqualTo("SHA-1")); Assert.That(o.LastChecksum, Is.EqualTo(checksum), "Given checksum is not equal to last saved checksum"); } if (type == MappedObjectType.File) { Assert.That(o.LastContentSize, Is.GreaterThanOrEqualTo(0), "Last content size is wrong"); Assert.That(o.LastContentSize, Is.EqualTo(contentSize), "Last content size is wrong"); } if (type == MappedObjectType.Folder) { Assert.That(o.LastContentSize, Is.EqualTo(-1), "Folder content size is wrong"); } return(true); }
/// <summary> /// Solve the specified situation by using the session, storage, localFile and remoteId. /// If a folder is affected, simply update the local change time of the corresponding local folder. /// If it is a file and the changeToken is not equal to the saved, the new content is downloaded. /// </summary> /// <param name="localFile">Local file.</param> /// <param name="remoteId">Remote identifier.</param> /// <param name="localContent">Hint if the local content has been changed.</param> /// <param name="remoteContent">Information if the remote content has been changed.</param> public override void Solve( IFileSystemInfo localFile, IObjectId remoteId, ContentChangeType localContent = ContentChangeType.NONE, ContentChangeType remoteContent = ContentChangeType.NONE) { IMappedObject obj = this.Storage.GetObjectByRemoteId(remoteId.Id); if (remoteId is IFolder) { var remoteFolder = remoteId as IFolder; DateTime?lastModified = remoteFolder.LastModificationDate; obj.LastChangeToken = remoteFolder.ChangeToken; if (lastModified != null) { try { localFile.LastWriteTimeUtc = (DateTime)lastModified; } catch (IOException e) { Logger.Debug("Couldn't set the server side modification date", e); } obj.Ignored = remoteFolder.AreAllChildrenIgnored(); obj.LastLocalWriteTimeUtc = localFile.LastWriteTimeUtc; } } else if (remoteId is IDocument) { var remoteDocument = remoteId as IDocument; DateTime?lastModified = remoteDocument.LastModificationDate; if ((lastModified != null && lastModified != obj.LastRemoteWriteTimeUtc) || obj.LastChangeToken != remoteDocument.ChangeToken) { if (remoteContent != ContentChangeType.NONE) { if (obj.LastLocalWriteTimeUtc != localFile.LastWriteTimeUtc) { throw new ArgumentException("The local file has been changed since last write => aborting update"); } obj.LastChecksum = DownloadChanges(localFile as IFileInfo, remoteDocument, obj, this.fsFactory, this.transmissonManager, Logger); } obj.LastRemoteWriteTimeUtc = remoteDocument.LastModificationDate; if (remoteDocument.LastModificationDate != null) { localFile.LastWriteTimeUtc = (DateTime)remoteDocument.LastModificationDate; } obj.LastLocalWriteTimeUtc = localFile.LastWriteTimeUtc; obj.LastContentSize = remoteDocument.ContentStreamLength ?? 0; } obj.LastChangeToken = remoteDocument.ChangeToken; obj.LastRemoteWriteTimeUtc = lastModified; } this.Storage.SaveMappedObject(obj); }
private bool VerifySavedFolder(IMappedObject folder, MappedObjectType type, string id, string name, string parentId, string changeToken, DateTime modifiedTime) { Assert.That(folder.Type, Is.EqualTo(type)); Assert.That(folder.RemoteObjectId, Is.EqualTo(id)); Assert.That(folder.ParentId, Is.EqualTo(parentId)); Assert.That(folder.Name, Is.EqualTo(name)); Assert.That(folder.LastChangeToken, Is.EqualTo(changeToken)); Assert.That(folder.LastRemoteWriteTimeUtc, Is.EqualTo(modifiedTime)); return(true); }
public static void AddMappedFile(this Mock <IMetaDataStorage> db, IMappedObject file, string localPath = null, string remotePath = null) { db.Setup(foo => foo.GetObjectByLocalPath(It.Is <IFileInfo>(f => f.FullName == localPath))).Returns(file); db.Setup(foo => foo.GetObjectByRemoteId(It.Is <string>(s => s == file.RemoteObjectId))).Returns(file); db.Setup(foo => foo.GetLocalPath(It.Is <IMappedObject>(o => o.Equals(file)))).Returns(localPath); db.Setup(foo => foo.GetRemotePath(It.Is <IMappedObject>(o => o.Equals(file)))).Returns(remotePath); if (!file.Guid.Equals(Guid.Empty)) { db.Setup(foo => foo.GetObjectByGuid(It.Is <Guid>(g => g.Equals(file.Guid)))).Returns(file); } }
// Don't use this method twice per test public static void AddMappedFolder(this Mock <IMetaDataStorage> db, IMappedObject folder, string localPath = null, string remotePath = null) { db.Setup(foo => foo.GetObjectByLocalPath(It.IsAny <IDirectoryInfo>())).Returns(folder); db.Setup(foo => foo.GetObjectByRemoteId(It.Is <string>(s => s == folder.RemoteObjectId))).Returns(folder); db.Setup(foo => foo.GetLocalPath(It.Is <IMappedObject>(o => o.Equals(folder)))).Returns(localPath); db.Setup(foo => foo.GetRemotePath(It.Is <IMappedObject>(o => o.Equals(folder)))).Returns(remotePath); if (!folder.Guid.Equals(Guid.Empty)) { db.Setup(foo => foo.GetObjectByGuid(It.Is <Guid>(g => g.Equals(folder.Guid)))).Returns(folder); } }
public void SetUp() { this.session = new Mock<ISession>(); this.session.SetupTypeSystem(); this.storage = new Mock<IMetaDataStorage>(); this.remoteObject = new Mock<IObjectId>(MockBehavior.Strict); this.remoteObject.Setup(o => o.Id).Returns(RemoteId); this.deletedFsObject = new Mock<IFileSystemInfo>(); this.mappedObject = Mock.Of<IMappedObject>(o => o.RemoteObjectId == RemoteId); this.underTest = new LocalObjectDeletedRemoteObjectRenamedOrMoved( this.session.Object, this.storage.Object); }
private void AccumulateEvent(AbstractFolderEvent abstractFolderEvent, IMappedObject storedObject) { Logger.Debug("Accumulating: " + this.storage.GetLocalPath(storedObject)); if (abstractFolderEvent is FolderEvent) { (abstractFolderEvent as FolderEvent).LocalFolder = this.fsFactory.CreateDirectoryInfo(this.storage.GetLocalPath(storedObject)); } if (abstractFolderEvent is FileEvent) { (abstractFolderEvent as FileEvent).LocalFile = this.fsFactory.CreateFileInfo(this.storage.GetLocalPath(storedObject)); } }
/// <summary> /// Gets the remote identifier by trying to read the Uuid of the given directory. If this fails or returns null, /// the local path is used to request the remote object id from the storage. /// </summary> /// <returns>The stored remote identifier, or null if there is no entry found.</returns> /// <param name="storage">Meta data storage instance.</param> /// <param name="info">File system item info.</param> public static string GetRemoteId(this IMetaDataStorage storage, IFileSystemInfo info) { IMappedObject mappedObject = storage.GetObject(info); if (mappedObject != null) { return(mappedObject.RemoteObjectId); } else { return(null); } }
public void SetUp() { this.session = new Mock <ISession>(); this.session.SetupTypeSystem(); this.storage = new Mock <IMetaDataStorage>(); this.remoteObject = new Mock <IObjectId>(MockBehavior.Strict); this.remoteObject.Setup(o => o.Id).Returns(RemoteId); this.deletedFsObject = new Mock <IFileSystemInfo>(); this.mappedObject = Mock.Of <IMappedObject>(o => o.RemoteObjectId == RemoteId); this.underTest = new LocalObjectDeletedRemoteObjectRenamedOrMoved( this.session.Object, this.storage.Object); }
protected byte[] DownloadChanges(IFileInfo target, IDocument remoteDocument, IMappedObject obj, IFileSystemInfoFactory fsFactory, ITransmissionManager transmissionManager, ILog logger) { // Download changes byte[] hash = null; var cacheFile = fsFactory.CreateDownloadCacheFileInfo(target); var transmission = transmissionManager.CreateTransmission(TransmissionType.DOWNLOAD_MODIFIED_FILE, target.FullName, cacheFile.FullName); hash = this.DownloadCacheFile(cacheFile, remoteDocument, transmission, fsFactory); obj.ChecksumAlgorithmName = "SHA-1"; try { var backupFile = fsFactory.CreateFileInfo(target.FullName + ".bak.sync"); Guid?uuid = target.Uuid; cacheFile.Replace(target, backupFile, true); try { target.Uuid = uuid; } catch (RestoreModificationDateException e) { logger.Debug("Failed to restore modification date of original file", e); } try { backupFile.Uuid = null; } catch (RestoreModificationDateException e) { logger.Debug("Failed to restore modification date of backup file", e); } byte[] checksumOfOldFile = null; using (var oldFileStream = backupFile.Open(FileMode.Open, FileAccess.Read, FileShare.None)) { checksumOfOldFile = SHA1Managed.Create().ComputeHash(oldFileStream); } if (!obj.LastChecksum.SequenceEqual(checksumOfOldFile)) { var conflictFile = fsFactory.CreateConflictFileInfo(target); backupFile.MoveTo(conflictFile.FullName); OperationsLogger.Info(string.Format("Updated local content of \"{0}\" with content of remote document {1} and created conflict file {2}", target.FullName, remoteDocument.Id, conflictFile.FullName)); } else { backupFile.Delete(); OperationsLogger.Info(string.Format("Updated local content of \"{0}\" with content of remote document {1}", target.FullName, remoteDocument.Id)); } } catch (Exception ex) { transmission.FailedException = ex; throw; } transmission.Status = TransmissionStatus.FINISHED; return(hash); }
private static AbstractFolderEvent GetCorrespondingRemoteEvent( Dictionary <string, Tuple <AbstractFolderEvent, AbstractFolderEvent> > eventMap, IMappedObject storedMappedChild) { AbstractFolderEvent correspondingRemoteEvent = null; Tuple <AbstractFolderEvent, AbstractFolderEvent> tuple; if (eventMap.TryGetValue(storedMappedChild.RemoteObjectId, out tuple)) { correspondingRemoteEvent = tuple.Item2; } return(correspondingRemoteEvent); }
private static bool AssertMappedObjectEqualExceptGUID(IMappedObject expected, IMappedObject actual) { Assert.AreEqual(actual.ParentId, expected.ParentId); Assert.AreEqual(actual.Type, expected.Type); Assert.AreEqual(actual.RemoteObjectId, expected.RemoteObjectId); Assert.AreEqual(actual.LastChangeToken, expected.LastChangeToken); Assert.AreEqual(actual.LastRemoteWriteTimeUtc, expected.LastRemoteWriteTimeUtc); Assert.AreEqual(actual.LastLocalWriteTimeUtc, expected.LastLocalWriteTimeUtc); Assert.AreEqual(actual.LastChecksum, expected.LastChecksum); Assert.AreEqual(actual.ChecksumAlgorithmName, expected.ChecksumAlgorithmName); Assert.AreEqual(actual.Name, expected.Name); Assert.AreNotEqual(actual.Guid, Guid.Empty); return(true); }
/// <summary> /// Gets the remote path. /// </summary> /// <returns> /// The remote path. /// </returns> /// <param name='obj'> /// The MappedObject instance. /// </param> public string GetRemotePath(IMappedObject obj) { string id = this.GetId(obj); using (var tran = this.engine.GetTransaction()) { string[] segments = this.GetRelativePathSegments(tran, id); StringBuilder pathBuilder = new StringBuilder(this.matcher.RemoteTargetRootPath); foreach (var name in segments) { pathBuilder.Append("/").Append(name); } return(this.slashRegex.Replace(pathBuilder.ToString(), @"/")); } }
/// <summary> /// Gets the identifier of the given object and throws Exceptions if object or remote object id is null /// </summary> /// <returns> /// The identifier. /// </returns> /// <param name='obj'> /// Object with the containing remote id. /// </param> private string GetId(IMappedObject obj) { if (obj == null) { throw new ArgumentNullException("The given obj is null"); } string id = obj.RemoteObjectId; if (id == null) { throw new ArgumentException("The given object has no remote object id"); } return(id); }
/// <summary> /// Removes the saved object. /// </summary> /// <param name='obj'> /// Object to be removed. /// </param> public void RemoveObject(IMappedObject obj) { string id = this.GetId(obj); using (var tran = this.engine.GetTransaction()) { MappedObject root = null; List <MappedObject> objects = new List <MappedObject>(); foreach (var row in tran.SelectForward <string, DbCustomSerializer <MappedObject> >(MappedObjectsTable)) { var value = row.Value; if (value == null) { continue; } var data = value.Get; if (data == null) { continue; } if (row.Key.Equals(id)) { root = data; } else { objects.Add(data); } } if (root == null) { return; } this.RemoveChildren(tran, root, ref objects); tran.RemoveKey <string>(MappedObjectsTable, id); tran.RemoveKey <byte[]>(MappedObjectsGuidsTable, root.Guid.ToByteArray()); tran.Commit(); } this.ValidateObjectStructureIfFullValidationIsEnabled(); }
/// <summary> /// Gets the remote path. /// </summary> /// <returns> /// The remote path. /// </returns> /// <param name='obj'> /// The MappedObject instance. /// </param> public string GetRemotePath(IMappedObject obj) { Stopwatch watch = Stopwatch.StartNew(); string id = this.GetId(obj); using (var tran = this.engine.GetTransaction()) { string[] segments = this.GetRelativePathSegments(tran, id); string path = this.matcher.RemoteTargetRootPath; foreach (var name in segments) { path += name.StartsWith("/") ? name : "/" + name; } watch.Stop(); Logger.Debug(string.Format("Method GetRemotePath returned after {0} ms", watch.ElapsedMilliseconds)); return(path.Replace("//", "/")); } }
/// <summary> /// Determines if file content is changed to the specified obj. /// </summary> /// <returns><c>true</c> if is the file content is different to the specified obj otherwise, <c>false</c>.</returns> /// <param name="file">File instance.</param> /// <param name="obj">Object to check the file content against.</param> /// <param name="actualHash">Contains the hash of the local file if scanned, or null if file wasn't scanned</param> /// <param name="scanOnlyIfModificationDateDiffers">If set to <c>true</c> content scan runs only if the modification date differs to given one.</param> public static bool IsContentChangedTo(this IFileInfo file, IMappedObject obj, out byte[] actualHash, bool scanOnlyIfModificationDateDiffers = false) { actualHash = null; if (obj == null) { throw new ArgumentNullException("obj"); } if (obj.LastContentSize < 0) { throw new ArgumentOutOfRangeException(string.Format("Given LastContentSize {0} is invalid for files", obj.LastContentSize.ToString())); } if (!file.Exists) { throw new FileNotFoundException(string.Format("File {0} does not exists", file.FullName)); } if (obj.LastChecksum == null) { return(true); } if (file.Length == obj.LastContentSize) { if (scanOnlyIfModificationDateDiffers && obj.LastLocalWriteTimeUtc == file.LastWriteTimeUtc) { return(false); } else { using (var f = file.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete)) { byte[] fileHash = SHA1Managed.Create().ComputeHash(f); actualHash = fileHash; return(!fileHash.SequenceEqual(obj.LastChecksum)); } } } else { return(true); } }
public static IMappedObject GetObject(this IMetaDataStorage storage, IFileSystemInfo info) { IMappedObject mappedObject = null; try { Guid?guid = info.Uuid; if (guid != null) { mappedObject = storage.GetObjectByGuid((Guid)guid); } } catch (Exception) { } if (mappedObject == null) { mappedObject = storage.GetObjectByLocalPath(info); } return(mappedObject); }
/// <summary> /// Saves the mapped object. /// </summary> /// <param name='obj'> /// The MappedObject instance. /// </param> /// <exception cref="DublicateGuidException">Is thrown when guid already in database</exception> public void SaveMappedObject(IMappedObject obj) { string id = this.GetId(obj); using (var tran = this.engine.GetTransaction()) { var byteGuid = obj.Guid.ToByteArray(); var row = tran.Select <byte[], string>(MappedObjectsGuidsTable, byteGuid); if (row.Exists && row.Value != id) { tran.Rollback(); throw new DublicateGuidException(string.Format("An entry with Guid {0} already exists", obj.Guid)); } tran.Insert <string, DbCustomSerializer <MappedObject> >(MappedObjectsTable, id, obj as MappedObject); if (!obj.Guid.Equals(Guid.Empty)) { tran.Insert <byte[], string>(MappedObjectsGuidsTable, obj.Guid.ToByteArray(), id); } tran.Commit(); } }
/// <summary> /// Gets the children of the given parent object. /// </summary> /// <returns> /// The saved children. /// </returns> /// <param name='parent'> /// Parent of the children. /// </param> public List <IMappedObject> GetChildren(IMappedObject parent) { Stopwatch watch = Stopwatch.StartNew(); string parentId = this.GetId(parent); List <IMappedObject> results = new List <IMappedObject>(); bool parentExists = false; using (var tran = this.engine.GetTransaction()) { foreach (var row in tran.SelectForward <string, DbCustomSerializer <MappedObject> >(MappedObjectsTable)) { var data = row.Value.Get; if (data == null) { continue; } if (parentId == data.ParentId) { results.Add(new MappedObject(data)); } else if (data.RemoteObjectId == parentId) { parentExists = true; } } } if (!parentExists) { throw new EntryNotFoundException(); } watch.Stop(); Logger.Debug(string.Format("Method GetChildren returned after {0} ms", watch.ElapsedMilliseconds)); return(results); }
private static void AddRemoteContentChangeTypeToFileEvent(FileEvent fileEvent, IMappedObject obj, IDocument remoteDoc) { if (fileEvent == null || obj == null || remoteDoc == null) { return; } byte[] remoteHash = remoteDoc.ContentStreamHash(obj.ChecksumAlgorithmName); if (remoteHash != null && remoteHash.SequenceEqual(obj.LastChecksum)) { fileEvent.RemoteContent = ContentChangeType.NONE; } else { fileEvent.RemoteContent = ContentChangeType.CHANGED; } }
/// <summary> /// Gets the remote path. /// </summary> /// <returns> /// The remote path. /// </returns> /// <param name='obj'> /// The MappedObject instance. /// </param> public string GetRemotePath(IMappedObject obj) { string id = this.GetId(obj); using(var tran = this.engine.GetTransaction()) { string[] segments = this.GetRelativePathSegments(tran, id); StringBuilder pathBuilder = new StringBuilder(this.matcher.RemoteTargetRootPath); foreach (var name in segments) { pathBuilder.Append("/").Append(name); } return this.slashRegex.Replace(pathBuilder.ToString(), @"/"); } }
private static AbstractFolderEvent GetCorrespondingRemoteEvent( Dictionary<string, Tuple<AbstractFolderEvent, AbstractFolderEvent>> eventMap, IMappedObject storedMappedChild) { AbstractFolderEvent correspondingRemoteEvent = null; Tuple<AbstractFolderEvent, AbstractFolderEvent> tuple; if (eventMap.TryGetValue(storedMappedChild.RemoteObjectId, out tuple)) { correspondingRemoteEvent = tuple.Item2; } return correspondingRemoteEvent; }
private AbstractFolderEvent CreateLocalEventBasedOnStorage(IFileSystemInfo fsObject, IMappedObject storedParent, IMappedObject storedMappedChild) { AbstractFolderEvent createdEvent = null; if (storedParent == null) { throw new ArgumentNullException("storedParent", "stored parent is null. Stored child: " + storedMappedChild.ToString() + Environment.NewLine + "local object is: " + fsObject.FullName); } if (storedMappedChild.ParentId == storedParent.RemoteObjectId) { // Renamed, Updated or Equal #if __COCOA__ if (fsObject.Name.Normalize(NormalizationForm.FormD) == storedMappedChild.Name.Normalize(NormalizationForm.FormD) && fsObject.LastWriteTimeUtc == storedMappedChild.LastLocalWriteTimeUtc) { #else if (fsObject.Name == storedMappedChild.Name && fsObject.LastWriteTimeUtc == storedMappedChild.LastLocalWriteTimeUtc && fsObject.ReadOnly == storedMappedChild.IsReadOnly) { #endif // Equal createdEvent = null; } else { // Updated or Renamed createdEvent = FileOrFolderEventFactory.CreateEvent(null, fsObject, localChange: MetaDataChangeType.CHANGED, src: this); } } else { // Moved IFileSystemInfo oldLocalPath = fsObject is IFileInfo ? (IFileSystemInfo)this.fsFactory.CreateFileInfo(this.storage.GetLocalPath(storedMappedChild)) : (IFileSystemInfo)this.fsFactory.CreateDirectoryInfo(this.storage.GetLocalPath(storedMappedChild)); createdEvent = FileOrFolderEventFactory.CreateEvent(null, fsObject, localChange: MetaDataChangeType.MOVED, oldLocalObject: oldLocalPath, src: this); } return createdEvent; } private IMappedObject FindStoredObjectByFileSystemInfo(List<IMappedObject> storedObjects, IFileSystemInfo fsInfo) { Guid? childGuid = fsInfo.Uuid; if (childGuid != null) { return storedObjects.Find(o => o.Guid == (Guid)childGuid); } return null; } }
private static bool AssertMappedObjectEqualExceptGUID(IMappedObject expected, IMappedObject actual) { Assert.AreEqual(actual.ParentId, expected.ParentId); Assert.AreEqual(actual.Type, expected.Type); Assert.AreEqual(actual.RemoteObjectId, expected.RemoteObjectId); Assert.AreEqual(actual.LastChangeToken, expected.LastChangeToken); Assert.AreEqual(actual.LastRemoteWriteTimeUtc, expected.LastRemoteWriteTimeUtc); Assert.AreEqual(actual.LastLocalWriteTimeUtc, expected.LastLocalWriteTimeUtc); Assert.AreEqual(actual.LastChecksum, expected.LastChecksum); Assert.AreEqual(actual.ChecksumAlgorithmName, expected.ChecksumAlgorithmName); Assert.AreEqual(actual.Name, expected.Name); Assert.AreNotEqual(actual.Guid, Guid.Empty); return true; }
private AbstractFolderEvent CreateRemoteEventBasedOnStorage(IFileableCmisObject cmisObject, IMappedObject storedParent, IMappedObject storedMappedChild) { AbstractFolderEvent newEvent = null; if (storedParent != null && storedMappedChild.ParentId == storedParent.RemoteObjectId) { // Renamed or Equal if (storedMappedChild.Name == cmisObject.Name) { // Equal or property update if (storedMappedChild.LastChangeToken != cmisObject.ChangeToken) { // Update newEvent = FileOrFolderEventFactory.CreateEvent(cmisObject, null, MetaDataChangeType.CHANGED, src: this); AddRemoteContentChangeTypeToFileEvent(newEvent as FileEvent, storedMappedChild, cmisObject as IDocument); } else { // Equal newEvent = null; } } else { // Renamed newEvent = FileOrFolderEventFactory.CreateEvent(cmisObject, null, MetaDataChangeType.CHANGED, src: this); AddRemoteContentChangeTypeToFileEvent(newEvent as FileEvent, storedMappedChild, cmisObject as IDocument); } } else { // Moved newEvent = FileOrFolderEventFactory.CreateEvent(cmisObject, null, MetaDataChangeType.MOVED, oldRemotePath: this.storage.GetRemotePath(storedMappedChild), src: this); AddRemoteContentChangeTypeToFileEvent(newEvent as FileEvent, storedMappedChild, cmisObject as IDocument); } return newEvent; }
public byte[] CallUploadFileWithPWC(IFileInfo localFile, ref IDocument doc, Transmission transmission, IMappedObject mappedObject = null) { return this.UploadFileWithPWC(localFile, ref doc, transmission, mappedObject); }
private void SyncNamesAndDates(IFileSystemInfo local, IFileableCmisObject remote, IMappedObject mappedObject) { DateTime? oldRemoteModificationDate = remote.LastModificationDate; DateTime oldLocalModificationDate = local.LastWriteTimeUtc; // Sync Names if (mappedObject.Name != local.Name && mappedObject.Name == remote.Name) { // local has been renamed => rename remote remote.Rename(local.Name, true); mappedObject.Name = local.Name; } else if (mappedObject.Name == local.Name && mappedObject.Name != remote.Name) { // remote has been renamed => rename local if (local is IFileInfo) { IFileInfo localFile = local as IFileInfo; localFile.MoveTo(Path.Combine(localFile.Directory.FullName, remote.Name)); } else if (local is IDirectoryInfo) { IDirectoryInfo localFolder = local as IDirectoryInfo; localFolder.MoveTo(Path.Combine(localFolder.Parent.FullName, remote.Name)); } else { throw new ArgumentException("Solved move conflict => invoke crawl sync to detect other changes"); } mappedObject.Name = remote.Name; } else if (mappedObject.Name != local.Name && mappedObject.Name != remote.Name) { // both are renamed => rename to the latest change DateTime localModification = local.LastWriteTimeUtc; DateTime remoteModification = (DateTime)remote.LastModificationDate; if (localModification > remoteModification) { // local modification is newer remote.Rename(local.Name, true); mappedObject.Name = local.Name; } else { // remote modification is newer if (local is IFileInfo) { IFileInfo localFile = local as IFileInfo; localFile.MoveTo(Path.Combine(localFile.Directory.FullName, remote.Name)); } else if (local is IDirectoryInfo) { IDirectoryInfo localFolder = local as IDirectoryInfo; localFolder.MoveTo(Path.Combine(localFolder.Parent.FullName, remote.Name)); } else { throw new ArgumentException("Solved move conflict => invoke crawl sync to detect other changes"); } local.LastWriteTimeUtc = (DateTime)remote.LastModificationDate; mappedObject.Name = remote.Name; } } // Sync modification dates if (oldRemoteModificationDate != null) { if (oldLocalModificationDate > oldRemoteModificationDate && this.ServerCanModifyDateTimes) { remote.UpdateLastWriteTimeUtc(oldLocalModificationDate); local.LastWriteTimeUtc = oldLocalModificationDate; } else if (oldLocalModificationDate < (DateTime)oldRemoteModificationDate) { local.LastWriteTimeUtc = (DateTime)oldRemoteModificationDate; } } mappedObject.LastLocalWriteTimeUtc = local.LastWriteTimeUtc; mappedObject.LastRemoteWriteTimeUtc = (DateTime)remote.LastModificationDate; mappedObject.ParentId = remote.Parents[0].Id; mappedObject.LastChangeToken = remote.ChangeToken; mappedObject.Ignored = remote.AreAllChildrenIgnored(); this.Storage.SaveMappedObject(mappedObject); }
/// <summary> /// Determines if file content is changed to the specified obj. /// </summary> /// <returns><c>true</c> if is the file content is different to the specified obj otherwise, <c>false</c>.</returns> /// <param name="file">File instance.</param> /// <param name="obj">Object to check the file content against.</param> /// <param name="scanOnlyIfModificationDateDiffers">If set to <c>true</c> content scan runs only if the modification date differs to given one.</param> public static bool IsContentChangedTo(this IFileInfo file, IMappedObject obj, bool scanOnlyIfModificationDateDiffers = false) { byte[] actualHash; return file.IsContentChangedTo(obj, out actualHash, scanOnlyIfModificationDateDiffers); }
// Don't use this method twice per test public static void AddMappedFolder(this Mock<IMetaDataStorage> db, IMappedObject folder, string localPath = null, string remotePath = null) { db.Setup(foo => foo.GetObjectByLocalPath(It.Is<IFileSystemInfo>(d => d.FullName == localPath))).Returns(folder); db.Setup(foo => foo.GetObjectByLocalPath(It.Is<IDirectoryInfo>(d => d.FullName == localPath))).Returns(folder); db.Setup(foo => foo.GetObjectByLocalPath(It.Is<IFileInfo>(d => d.FullName == localPath))).Returns(folder); db.Setup(foo => foo.GetObjectByRemoteId(It.Is<string>(s => s == folder.RemoteObjectId))).Returns(folder); db.Setup(foo => foo.GetLocalPath(It.Is<IMappedObject>(o => o.Equals(folder)))).Returns(localPath); db.Setup(foo => foo.GetRemotePath(It.Is<IMappedObject>(o => o.Equals(folder)))).Returns(remotePath); if (!folder.Guid.Equals(Guid.Empty)) { db.Setup(foo => foo.GetObjectByGuid(It.Is<Guid>(g => g.Equals(folder.Guid)))).Returns(folder); } }
/// <summary> /// Gets the local path. Return null if not exists. /// </summary> /// <returns> /// The local path. /// </returns> /// <param name='mappedObject'> /// Mapped object. Must not be null. /// </param> public string GetLocalPath(IMappedObject mappedObject) { string id = this.GetId(mappedObject); using(var tran = this.engine.GetTransaction()) { string[] segments = this.GetRelativePathSegments(tran, id); if (segments == null) { return null; } if (segments.Length > 0 && segments[0].Equals("/")) { string[] temp = new string[segments.Length - 1]; for (int i = 1; i < segments.Length; i++) { temp[i - 1] = segments[i]; } segments = temp; } return Path.Combine(this.matcher.LocalTargetRootPath, Path.Combine(segments)); } }
/// <summary> /// Gets the children of the given parent object. /// </summary> /// <returns> /// The saved children. /// </returns> /// <param name='parent'> /// Parent of the children. /// </param> public List<IMappedObject> GetChildren(IMappedObject parent) { string parentId = this.GetId(parent); List<IMappedObject> results = new List<IMappedObject>(); bool parentExists = false; using(var tran = this.engine.GetTransaction()) { foreach (var row in tran.SelectForward<string, DbCustomSerializer<MappedObject>>(MappedObjectsTable)) { var data = row.Value.Get; if (data == null) { continue; } if (parentId == data.ParentId) { results.Add(new MappedObject(data)); } else if(data.RemoteObjectId == parentId) { parentExists = true; } } } if (!parentExists) { throw new EntryNotFoundException(); } return results; }
/// <summary> /// Gets the identifier of the given object and throws Exceptions if object or remote object id is null /// </summary> /// <returns> /// The identifier. /// </returns> /// <param name='obj'> /// Object with the containing remote id. /// </param> private string GetId(IMappedObject obj) { if (obj == null) { throw new ArgumentNullException("obj"); } string id = obj.RemoteObjectId; if (id == null) { throw new ArgumentException("The given object has no remote object id", "obj"); } return id; }
/// <summary> /// Uploads the file content to the remote document. /// </summary> /// <returns>The SHA-1 hash of the uploaded file content.</returns> /// <param name="localFile">Local file.</param> /// <param name="doc">Remote document.</param> /// <param name="transmissionManager">Transmission manager.</param> /// <param name="transmissionEvent">File Transmission event.</param> /// <param name="mappedObject">Mapped object saved in <c>Storage</c></param> protected byte[] UploadFileWithPWC(IFileInfo localFile, ref IDocument doc, Transmission transmission, IMappedObject mappedObject = null) { byte[] checksum = null; var docPWC = this.LoadRemotePWCDocument(doc, ref checksum); using (var file = localFile.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete)) { if (checksum != null) { // check PWC checksum for integration using (var hashAlg = new SHA1Managed()) { int bufsize = 8 * 1024; byte[] buffer = new byte[bufsize]; for (long offset = 0; offset < docPWC.ContentStreamLength.GetValueOrDefault();) { int readsize = bufsize; if (readsize + offset > docPWC.ContentStreamLength.GetValueOrDefault()) { readsize = (int)(docPWC.ContentStreamLength.GetValueOrDefault() - offset); } readsize = file.Read(buffer, 0, readsize); hashAlg.TransformBlock(buffer, 0, readsize, buffer, 0); offset += readsize; if (readsize == 0) { break; } } hashAlg.TransformFinalBlock(new byte[0], 0, 0); if (!hashAlg.Hash.SequenceEqual(checksum)) { docPWC.DeleteContentStream(); } file.Seek(0, SeekOrigin.Begin); } } byte[] hash = null; var uploader = FileTransmission.ContentTaskUtils.CreateUploader(this.TransmissionStorage.ChunkSize); using (var hashAlg = new SHA1Reuse()) { try { using (var hashstream = new NonClosingHashStream(file, hashAlg, CryptoStreamMode.Read)) { int bufsize = 8 * 1024; byte[] buffer = new byte[bufsize]; for (long offset = 0; offset < docPWC.ContentStreamLength.GetValueOrDefault();) { int readsize = bufsize; if (readsize + offset > docPWC.ContentStreamLength.GetValueOrDefault()) { readsize = (int)(docPWC.ContentStreamLength.GetValueOrDefault() - offset); } readsize = hashstream.Read(buffer, 0, readsize); offset += readsize; if (readsize == 0) { break; } } } var document = doc; uploader.UploadFile(docPWC, file, transmission, hashAlg, false, (byte[] checksumUpdate, long length) => this.SaveRemotePWCDocument(localFile, document, docPWC, checksumUpdate, transmission)); hash = hashAlg.Hash; } catch (Exception ex) { transmission.FailedException = ex; throw; } } this.TransmissionStorage.RemoveObjectByRemoteObjectId(doc.Id); var properties = new Dictionary<string, object>(); properties.Add(PropertyIds.LastModificationDate, localFile.LastWriteTimeUtc); doc = this.Session.GetObject(docPWC.CheckIn(true, properties, null, string.Empty)) as IDocument; // Refresh is required, or DotCMIS will use cached one only doc.Refresh(); transmission.Status = TransmissionStatus.FINISHED; return hash; } }
public static void AddMappedFile(this Mock<IMetaDataStorage> db, IMappedObject file, string localPath = null, string remotePath = null) { db.Setup(foo => foo.GetObjectByLocalPath(It.Is<IFileInfo>(f => f.FullName == localPath))).Returns(file); db.Setup(foo => foo.GetObjectByRemoteId(It.Is<string>(s => s == file.RemoteObjectId))).Returns(file); db.Setup(foo => foo.GetLocalPath(It.Is<IMappedObject>(o => o.Equals(file)))).Returns(localPath); db.Setup(foo => foo.GetRemotePath(It.Is<IMappedObject>(o => o.Equals(file)))).Returns(remotePath); if (!file.Guid.Equals(Guid.Empty)) { db.Setup(foo => foo.GetObjectByGuid(It.Is<Guid>(g => g.Equals(file.Guid)))).Returns(file); } }
/// <summary> /// Removes the saved object. /// </summary> /// <param name='obj'> /// Object to be removed. /// </param> public void RemoveObject(IMappedObject obj) { string id = this.GetId(obj); using (var tran = this.engine.GetTransaction()) { MappedObject root = null; List<MappedObject> objects = new List<MappedObject>(); foreach (var row in tran.SelectForward<string, DbCustomSerializer<MappedObject>>(MappedObjectsTable)) { var value = row.Value; if (value == null) { continue; } var data = value.Get; if (data == null) { continue; } if (row.Key.Equals(id)) { root = data; } else { objects.Add(data); } } if (root == null) { return; } this.RemoveChildren(tran, root, ref objects); tran.RemoveKey<string>(MappedObjectsTable, id); tran.RemoveKey<byte[]>(MappedObjectsGuidsTable, root.Guid.ToByteArray()); tran.Commit(); } this.ValidateObjectStructureIfFullValidationIsEnabled(); }
private static bool VerifyMappedObject( IMappedObject o, MappedObjectType type, string remoteId, string name, string parentId, string changeToken, bool extendedAttributeAvailable, DateTime? lastLocalModification, DateTime? lastRemoteModification, byte[] checksum, long contentSize, bool ignored) { Assert.That(o.RemoteObjectId, Is.EqualTo(remoteId), "Object remote Id is wrong"); Assert.That(o.Name, Is.EqualTo(name), "Object name is wrong"); Assert.That(o.ParentId, Is.EqualTo(parentId), "Object parent Id is wrong"); Assert.That(o.LastChangeToken, Is.EqualTo(changeToken), "Object change token is wrong"); Assert.That(o.Type, Is.EqualTo(type), "Object type is wrong"); Assert.That(o.Ignored, Is.EqualTo(ignored), "Object ignore flag is wrong"); if (extendedAttributeAvailable) { Assert.That(o.Guid, Is.Not.EqualTo(Guid.Empty), "Given Guid must not be empty"); } else { Assert.That(o.Guid, Is.EqualTo(Guid.Empty), "Given Guid must be empty"); } if (lastLocalModification != null) { Assert.That(o.LastLocalWriteTimeUtc, Is.EqualTo(lastLocalModification), "Last local modification date is wrong"); } if (lastRemoteModification != null) { Assert.That(o.LastRemoteWriteTimeUtc, Is.EqualTo(lastRemoteModification), "Last remote modification date is wrong"); } if (checksum != null) { Assert.That(o.ChecksumAlgorithmName, Is.EqualTo("SHA-1")); Assert.That(o.LastChecksum, Is.EqualTo(checksum), "Given checksum is not equal to last saved checksum"); } if (type == MappedObjectType.File) { Assert.That(o.LastContentSize, Is.GreaterThanOrEqualTo(0), "Last content size is wrong"); Assert.That(o.LastContentSize, Is.EqualTo(contentSize), "Last content size is wrong"); } if (type == MappedObjectType.Folder) { Assert.That(o.LastContentSize, Is.EqualTo(-1), "Folder content size is wrong"); } return true; }
/// <summary> /// Saves the mapped object. /// </summary> /// <param name='obj'> /// The MappedObject instance. /// </param> /// <exception cref="DublicateGuidException">Is thrown when guid already in database</exception> public void SaveMappedObject(IMappedObject obj) { string id = this.GetId(obj); using(var tran = this.engine.GetTransaction()) { var byteGuid = obj.Guid.ToByteArray(); var row = tran.Select<byte[], string>(MappedObjectsGuidsTable, byteGuid); if (row.Exists && row.Value != id) { tran.Rollback(); throw new DublicateGuidException(string.Format("An entry with Guid {0} already exists", obj.Guid)); } if (this.fullValidationOnEachManipulation && obj.ParentId != null) { DbCustomSerializer<MappedObject> value = tran.Select<string, DbCustomSerializer<MappedObject>>(MappedObjectsTable, obj.ParentId).Value; if (value == null) { tran.Rollback(); throw new InvalidDataException(); } } obj.LastTimeStoredInStorage = DateTime.UtcNow; tran.Insert<string, DbCustomSerializer<MappedObject>>(MappedObjectsTable, id, obj as MappedObject); if (!obj.Guid.Equals(Guid.Empty)) { tran.Insert<byte[], string>(MappedObjectsGuidsTable, obj.Guid.ToByteArray(), id); } tran.Commit(); } this.ValidateObjectStructureIfFullValidationIsEnabled(); }
private bool VerifySavedObject(IMappedObject obj, MappedObjectType type, string id, string name, string parentId, string changeToken, DateTime modifiedTime) { Assert.That(obj.Type, Is.EqualTo(type)); Assert.That(obj.RemoteObjectId, Is.EqualTo(id)); Assert.That(obj.ParentId, Is.EqualTo(parentId)); Assert.That(obj.Name, Is.EqualTo(name)); Assert.That(obj.LastChangeToken, Is.EqualTo(changeToken)); Assert.That(obj.LastRemoteWriteTimeUtc, Is.EqualTo(modifiedTime)); Assert.That(obj.LastLocalWriteTimeUtc, Is.EqualTo(modifiedTime)); return true; }
protected byte[] DownloadChanges(IFileInfo target, IDocument remoteDocument, IMappedObject obj, IFileSystemInfoFactory fsFactory, ITransmissionManager transmissionManager, ILog logger) { // Download changes byte[] hash = null; var cacheFile = fsFactory.CreateDownloadCacheFileInfo(target); var transmission = transmissionManager.CreateTransmission(TransmissionType.DOWNLOAD_MODIFIED_FILE, target.FullName, cacheFile.FullName); hash = this.DownloadCacheFile(cacheFile, remoteDocument, transmission, fsFactory); obj.ChecksumAlgorithmName = "SHA-1"; try { var backupFile = fsFactory.CreateFileInfo(target.FullName + ".bak.sync"); Guid? uuid = target.Uuid; cacheFile.Replace(target, backupFile, true); try { target.Uuid = uuid; } catch (RestoreModificationDateException e) { logger.Debug("Failed to restore modification date of original file", e); } try { backupFile.Uuid = null; } catch (RestoreModificationDateException e) { logger.Debug("Failed to restore modification date of backup file", e); } byte[] checksumOfOldFile = null; using (var oldFileStream = backupFile.Open(FileMode.Open, FileAccess.Read, FileShare.None)) { checksumOfOldFile = SHA1Managed.Create().ComputeHash(oldFileStream); } if (!obj.LastChecksum.SequenceEqual(checksumOfOldFile)) { var conflictFile = fsFactory.CreateConflictFileInfo(target); backupFile.MoveTo(conflictFile.FullName); OperationsLogger.Info(string.Format("Updated local content of \"{0}\" with content of remote document {1} and created conflict file {2}", target.FullName, remoteDocument.Id, conflictFile.FullName)); } else { backupFile.Delete(); OperationsLogger.Info(string.Format("Updated local content of \"{0}\" with content of remote document {1}", target.FullName, remoteDocument.Id)); } } catch(Exception ex) { transmission.FailedException = ex; throw; } transmission.Status = TransmissionStatus.FINISHED; return hash; }