public void RemoteFolderDeletion(string ignoredCanonicalName, string ignoredLocalPath, string remoteFolderPath, string url, string user, string password, string repositoryId) { // Prepare remote folder and CmisSync process. IFolder remoteBaseFolder = ClearRemoteCMISFolder(url, user, password, repositoryId, remoteFolderPath); sync = new CmisSyncProcess(remoteFolderPath, url, user, password, repositoryId); // Create remote folder string foldername = "folder1"; IDictionary <string, object> properties = new Dictionary <string, object>(); properties[PropertyIds.Name] = foldername; properties[PropertyIds.ObjectTypeId] = "cmis:folder"; IFolder folder = remoteBaseFolder.CreateFolder(properties); // Wait for a few seconds so that sync gets a chance to sync things. Thread.Sleep(20 * 1000); // Check locally Assert.True(Directory.Exists(Path.Combine(sync.Folder(), (String)properties[PropertyIds.Name]))); // Delete the folder. folder.DeleteTree(true, null, true); // Wait for 10 seconds so that sync gets a chance to sync things. Thread.Sleep(10 * 1000); // Check locally Assert.False(Directory.Exists(Path.Combine(sync.Folder(), (String)properties[PropertyIds.Name]))); }
public void RemovingRemoteFolderAndAddingADocumentToItShouldThrowException( string canonical_name, string localPath, string remoteFolderPath, string url, string user, string password, string repositoryId, string binding) { string subFolderName = "subFolder"; ISession session = DotCMISSessionTests.CreateSession(user, password, url, repositoryId, binding); try { IFolder dir = session.GetObjectByPath(remoteFolderPath.TrimEnd('/') + "/" + subFolderName) as IFolder; if (dir != null) { dir.DeleteTree(true, null, true); } } catch (CmisObjectNotFoundException) { } IFolder folder = (IFolder)session.GetObjectByPath(remoteFolderPath); IFolder subFolder = folder.CreateFolder(subFolderName); IFolder subFolderInstanceCopy = (IFolder)session.GetObject(subFolder.Id); subFolder.DeleteTree(true, null, true); Assert.Throws <CmisObjectNotFoundException>(() => subFolderInstanceCopy.CreateDocument("testFile.bin", "testContent")); }
/// <summary> /// Sync deletions. /// </summary> private void WatchSyncDelete(string remoteFolder, string localFolder, string pathname) { sleepWhileSuspended(); string filename = Path.GetFileName(pathname); if (!Utils.WorthSyncing(Path.GetDirectoryName(pathname), filename, repoinfo)) { return; } try { string name = pathname.Substring(localFolder.Length + 1); string remoteName = Path.Combine(remoteFolder, name).Replace('\\', '/'); if (database.ContainsFile(pathname)) { Logger.InfoFormat("Removing locally deleted file on server: {0}", pathname); try { IDocument remote = (IDocument)session.GetObjectByPath(remoteName); if (remote != null) { remote.DeleteAllVersions(); } } catch (Exception ex) { Logger.Warn(String.Format("Exception when operate remote {0}", remoteName), ex); } database.RemoveFile(pathname); } else if (database.ContainsFolder(pathname)) { Logger.InfoFormat("Removing locally deleted folder on server: {0}", pathname); try { IFolder remote = (IFolder)session.GetObjectByPath(remoteName); if (remote != null) { remote.DeleteTree(true, null, true); } } catch (Exception ex) { Logger.Warn(String.Format("Exception when operate remote {0}", remoteName), ex); } database.RemoveFolder(pathname); } else { Logger.InfoFormat("Ignore the delete action for the local created and deleted file/folder: {0}", pathname); } } catch (Exception e) { ProcessRecoverableException("Could process watcher sync update: " + pathname, e); } }
/// <summary> /// Crawl remote subfolder, syncing down if needed. /// Meanwhile, cache and remoteFolders, they are output parameters that are used in CrawlLocalFiles/CrawlLocalFolders /// </summary> private void CrawlRemoteFolder(IFolder remoteSubFolder, string localFolder, IList remoteFolders) { sleepWhileSuspended(); try { if (Utils.WorthSyncing(localFolder, remoteSubFolder.Name, repoinfo)) { //Logger.Debug("CrawlRemote dir: " + localFolder + Path.DirectorySeparatorChar.ToString() + remoteSubFolder.Name); remoteFolders.Add(remoteSubFolder.Name); string localSubFolder = Path.Combine(localFolder, remoteSubFolder.Name); // Check whether local folder exists. if (Directory.Exists(localSubFolder)) { // Recurse into folder. CrawlSync(remoteSubFolder, localSubFolder); } else { // If there was previously a file with this name, delete it. // TODO warn if local changes in the file. if (File.Exists(localSubFolder)) { File.Delete(localSubFolder); } if (database.ContainsFolder(localSubFolder)) { // If there was previously a folder with this name, it means that // the user has deleted it voluntarily, so delete it from server too. // Delete the folder from the remote server. remoteSubFolder.DeleteTree(true, null, true); // Delete the folder from database. database.RemoveFolder(localSubFolder); } else { // The folder has been recently created on server, so download it. Directory.CreateDirectory(localSubFolder); // Create database entry for this folder. // TODO - Yannick - Add metadata database.AddFolder(localSubFolder, remoteSubFolder.LastModificationDate); Logger.Info("Added folder to database: " + localSubFolder); // Recursive copy of the whole folder. RecursiveFolderCopy(remoteSubFolder, localSubFolder); } } } } catch (Exception e) { ProcessRecoverableException("Could not crawl sync remote folder: " + remoteSubFolder.Path, e); } }
public static ISession Connect() { IDictionary <string, string> parameters = DefaultTestValues.SessionParameters; DefaultDocumentType = DefaultTestValues.DefaultDocumentType; DefaultFolderType = DefaultTestValues.DefaulFolderType; SessionFactory factory = SessionFactory.NewInstance(); ISession session = null; if (parameters.ContainsKey(SessionParameter.RepositoryId)) { session = factory.CreateSession(parameters); } else { session = factory.GetRepositories(parameters)[0].CreateSession(); } Assert.IsNotNull(session); Assert.IsNotNull(session.Binding); Assert.IsNotNull(session.RepositoryInfo); Assert.IsNotNull(session.RepositoryInfo.Id); string testRootFolderPath = DefaultTestValues.TestRootFolder; if (testRootFolderPath == null) { TestFolder = session.GetRootFolder(); } else { TestFolder = session.GetObjectByPath(testRootFolderPath) as IFolder; } Assert.IsNotNull(TestFolder); Assert.IsNotNull(TestFolder.Id); foreach (ICmisObject cmisObject in TestFolder.GetChildren()) { IFolder folder = cmisObject as IFolder; if (folder == null) { cmisObject.Delete(true); } else { folder.DeleteTree(true, null, true); } } return(session); }
public void RenameRemoteFolderChangesChangeLogToken( string canonical_name, string localPath, string remoteFolderPath, string url, string user, string password, string repositoryId, string binding) { ISession session = DotCMISSessionTests.CreateSession(user, password, url, repositoryId, binding); IFolder rootFolder = (IFolder)session.GetObjectByPath(remoteFolderPath); string folderName = "1"; string newFolderName = "2"; try { IFolder folder = session.GetObjectByPath(remoteFolderPath.TrimEnd('/') + "/" + folderName) as IFolder; if (folder != null) { folder.DeleteTree(true, null, true); } folder = session.GetObjectByPath(remoteFolderPath.TrimEnd('/') + "/" + newFolderName) as IFolder; if (folder != null) { folder.DeleteTree(true, null, true); } } catch (CmisObjectNotFoundException) { } IFolder newFolder = rootFolder.CreateFolder(folderName); string changeLogToken = session.RepositoryInfo.LatestChangeLogToken; string changeToken = newFolder.ChangeToken; newFolder.Rename(newFolderName, true); Assert.That(newFolder.ChangeToken, Is.Not.EqualTo(changeToken)); newFolder.DeleteTree(true, null, true); }
/// <summary> /// Upload folder recursively. /// After execution, the hierarchy on server will be: .../remoteBaseFolder/localFolder/... /// </summary> private void UploadFolderRecursively(IFolder remoteBaseFolder, string localFolder) { // Create remote folder. Dictionary <string, object> properties = new Dictionary <string, object>(); properties.Add(PropertyIds.Name, Path.GetFileName(localFolder)); properties.Add(PropertyIds.ObjectTypeId, "cmis:folder"); IFolder folder = remoteBaseFolder.CreateFolder(properties); // Create database entry for this folder // TODO Add metadata database.AddFolder(localFolder, folder.LastModificationDate); try { // Upload each file in this folder. foreach (string file in Directory.GetFiles(localFolder)) { if (Utils.WorthSyncing(file)) { UploadFile(file, folder); } } // Recurse for each subfolder in this folder. foreach (string subfolder in Directory.GetDirectories(localFolder)) { string path = subfolder.Substring(repoinfo.TargetDirectory.Length); path = path.Replace("\\\\", "/"); if (Utils.WorthSyncing(subfolder) && !repoinfo.isPathIgnored(path)) { UploadFolderRecursively(folder, subfolder); } } } catch (Exception e) { if (e is System.IO.DirectoryNotFoundException || e is IOException) { Logger.Warn("Folder deleted while trying to upload it, reverting."); // Folder has been deleted while we were trying to upload/checksum/add. // In this case, revert the upload. folder.DeleteTree(true, null, true); } else { throw; } } }
public void CheckoutTest( string canonical_name, string localPath, string remoteFolderPath, string url, string user, string password, string repositoryId, string binding) { string subFolderName = "subFolder"; string fileName = "testFile.bin"; string subFolderPath = remoteFolderPath.TrimEnd('/') + "/" + subFolderName; string filePath = subFolderPath + "/" + fileName; ISession session = DotCMISSessionTests.CreateSession(user, password, url, repositoryId, binding); if (!session.ArePrivateWorkingCopySupported()) { Assert.Ignore("PWCs are not supported"); } try { IFolder dir = session.GetObjectByPath(remoteFolderPath.TrimEnd('/') + "/" + subFolderName) as IFolder; if (dir != null) { dir.DeleteTree(true, null, true); } } catch (CmisObjectNotFoundException) { } IFolder folder = (IFolder)session.GetObjectByPath(remoteFolderPath); IFolder subFolder = folder.CreateFolder(subFolderName); IDocument doc = subFolder.CreateDocument(fileName, "testContent", checkedOut: true); IObjectId checkoutId = doc.CheckOut(); IDocument docCheckout = (IDocument)session.GetObject(checkoutId); Assert.AreEqual(doc.ContentStreamLength, docCheckout.ContentStreamLength); doc.Refresh(); Assert.IsTrue(doc.IsVersionSeriesCheckedOut.GetValueOrDefault()); Assert.AreEqual(checkoutId.Id, doc.VersionSeriesCheckedOutId); docCheckout.CancelCheckOut(); doc.Refresh(); Assert.IsFalse(doc.IsVersionSeriesCheckedOut.GetValueOrDefault()); Assert.IsNull(doc.VersionSeriesCheckedOutId); }
public void TestUpdateProperties() { string name1 = "port-test-folder1"; string name2 = "port-test-folder2"; string name3 = "port-test-folder3"; IOperationContext oc = Session.CreateOperationContext(); oc.CacheEnabled = false; IFolder newFolder = null; try { // create folder IFolder root = Session.GetRootFolder(); newFolder = CreateFolder(root, name1); Assert.IsNotNull(newFolder); IFolder newFolder2 = (IFolder)Session.GetObject(newFolder, oc); Assert.IsNotNull(newFolder2); Assert.IsNotNull(name1, newFolder2.Name); IDictionary <string, object> updateProps = new Dictionary <string, object>(); updateProps[PropertyIds.Name] = name2; newFolder2.UpdateProperties(updateProps); IFolder newFolder3 = (IFolder)Session.GetObject(newFolder, oc); Assert.IsNotNull(newFolder3); Assert.IsNotNull(name2, newFolder3.Name); newFolder3.Rename(name3); IFolder newFolder4 = (IFolder)Session.GetObject(newFolder, oc); Assert.IsNotNull(newFolder4); Assert.IsNotNull(name3, newFolder4.Name); } finally { if (newFolder != null) { newFolder.DeleteTree(true, UnfileObject.Delete, true); Assert.IsFalse(Session.Exists(newFolder)); } } }
private IFolder ClearRemoteCMISFolderAndGetFolder(ISession session, string remoteFolderPath) { var folder = (IFolder)session.GetObjectByPath(remoteFolderPath, true); foreach (var child in folder.GetChildren()) { if (child is IFolder) { IFolder folderChild = (IFolder)child; folderChild.DeleteTree(true, UnfileObject.Delete, true); } else { child.Delete(true); } } return(folder); }
public void RemovingRemoteFolderAndAddingADocumentToItShouldThrowException( string canonical_name, string localPath, string remoteFolderPath, string url, string user, string password, string repositoryId) { ISession session = DotCMISSessionTests.CreateSession(user, password, url, repositoryId); IFolder folder = (IFolder)session.GetObjectByPath(remoteFolderPath); IFolder subFolder = folder.CreateFolder("subFolder"); IFolder subFolderInstanceCopy = (IFolder)session.GetObject(subFolder.Id); subFolder.DeleteTree(true, null, true); Assert.Throws <CmisObjectNotFoundException>(() => subFolderInstanceCopy.CreateDocument("testFile.bin", "testContent")); }
public void TestCopy() { IFolder rootFolder = Session.GetRootFolder(); IFolder folder1 = null; IFolder folder2 = null; IDocument doc1 = null; IDocument doc2 = null; string content = "I'm unique!"; try { folder1 = CreateFolder(rootFolder, "copy1"); folder2 = CreateFolder(rootFolder, "copy2"); doc1 = CreateTextDocument(folder1, "copydoc.xt", content); doc2 = doc1.Copy(folder2); Assert.IsNotNull(doc2); Assert.AreEqual(doc1.Name, doc2.Name); Assert.AreEqual(ConvertStreamToString(doc1.GetContentStream().Stream), ConvertStreamToString(doc2.GetContentStream().Stream)); Assert.AreEqual(folder2.Id, doc2.Parents[0].Id); } finally { if (folder1 != null) { folder1.DeleteTree(true, UnfileObject.Delete, true); Assert.IsFalse(Session.Exists(folder1)); } if (folder2 != null) { folder2.DeleteTree(true, UnfileObject.Delete, true); Assert.IsFalse(Session.Exists(folder2)); } } }
/// <summary> /// Crawl remote subfolder, syncing down if needed. /// Meanwhile, cache all contained remote folders, they are output parameters that are used in CrawlLocalFiles/CrawlLocalFolders /// </summary> private void CrawlRemoteFolder(IFolder remoteSubFolder, string localFolder, IList <string> remoteFolders) { SleepWhileSuspended(); try { if (Utils.WorthSyncing(localFolder, remoteSubFolder.Name, repoinfo)) { // Logger.Debug("CrawlRemote localFolder:\"" + localFolder + "\" remoteSubFolder.Path:\"" + remoteSubFolder.Path + "\" remoteSubFolder.Name:\"" + remoteSubFolder.Name + "\""); remoteFolders.Add(remoteSubFolder.Name); var subFolderItem = database.GetFolderSyncItemFromRemotePath(remoteSubFolder.Path); if (null == subFolderItem) { subFolderItem = SyncItemFactory.CreateFromRemotePath(remoteSubFolder.Path, repoinfo); } // Check whether local folder exists. if (Directory.Exists(subFolderItem.LocalPath)) { // Recurse into folder. CrawlSync(remoteSubFolder, subFolderItem.LocalPath); } else { // If there was previously a file with this name, delete it. // TODO warn if local changes in the file. if (File.Exists(subFolderItem.LocalPath)) { activityListener.ActivityStarted(); File.Delete(subFolderItem.LocalPath); activityListener.ActivityStopped(); } if (database.ContainsFolder(subFolderItem)) { // If there was previously a folder with this name, it means that // the user has deleted it voluntarily, so delete it from server too. activityListener.ActivityStarted(); // Delete the folder from the remote server. remoteSubFolder.DeleteTree(true, null, true); Logger.Debug("Remove remote folder tree: " + remoteSubFolder.Path); // Delete the folder from database. database.RemoveFolder(subFolderItem); activityListener.ActivityStopped(); } else { if (Utils.IsInvalidFileName(remoteSubFolder.Name)) { Logger.Warn("Skipping remote folder with name invalid on local filesystem: " + remoteSubFolder.Name); } else { // The folder has been recently created on server, so download it. activityListener.ActivityStarted(); Directory.CreateDirectory(subFolderItem.LocalPath); // Create database entry for this folder. // TODO - Yannick - Add metadata database.AddFolder(subFolderItem, remoteSubFolder.Id, remoteSubFolder.LastModificationDate); Logger.Info("Added folder to database: " + subFolderItem.LocalPath); // Recursive copy of the whole folder. RecursiveFolderCopy(remoteSubFolder, subFolderItem.LocalPath); activityListener.ActivityStopped(); } } } } } catch (Exception e) { activityListener.ActivityStopped(); ProcessRecoverableException("Could not crawl sync remote folder: " + remoteSubFolder.Path, e); } }
private void WatcherSyncDelete(string remoteFolder, string localFolder, string pathname) { string name = pathname.Substring(localFolder.Length + 1); string remoteName = Path.Combine(remoteFolder, name).Replace('\\', '/'); DbTransaction transaction = null; try { transaction = database.BeginTransaction(); if (database.ContainsFile(pathname)) { Logger.Info("Removing locally deleted file on server: " + pathname); try { IDocument remote = (IDocument)session.GetObjectByPath(remoteName); if (remote != null) { remote.DeleteAllVersions(); } } catch (Exception e) { Logger.Warn(String.Format("Exception when operate remote {0}: ", remoteName), e); } database.RemoveFile(pathname); } else if (database.ContainsFolder(pathname)) { Logger.Info("Removing locally deleted folder on server: " + pathname); try { IFolder remote = (IFolder)session.GetObjectByPath(remoteName); if (remote != null) { remote.DeleteTree(true, null, true); } } catch (Exception e) { Logger.Warn(String.Format("Exception when operate remote {0}: ", remoteName), e); } database.RemoveFolder(pathname); } else { Logger.Info("Ignore the delete action for the local created and deleted file/folder: " + pathname); } transaction.Commit(); } catch (Exception e) { if (transaction != null) { transaction.Rollback(); } Logger.Warn(String.Format("Exception while sync to delete file/folder {0}: ", pathname), e); return; } finally { if (transaction != null) { transaction.Dispose(); } } repo.Watcher.RemoveChange(pathname, Watcher.ChangeTypes.Deleted); return; }
/// <summary> /// Crawl remote subfolder, syncing down if needed. /// Meanwhile, cache all contained remote folders, they are output parameters that are used in CrawlLocalFiles/CrawlLocalFolders /// </summary> private void CrawlRemoteFolder(IFolder remoteSubFolder, string remotePath, string localFolder, IList <string> remoteFolders) { SleepWhileSuspended(); try { if (Utils.WorthSyncing(localFolder, remoteSubFolder.Name, repoInfo)) { // Logger.Debug("CrawlRemote localFolder:\"" + localFolder + "\" remoteSubFolder.Path:\"" + remoteSubFolder.Path + "\" remoteSubFolder.Name:\"" + remoteSubFolder.Name + "\""); remoteFolders.Add(remoteSubFolder.Name); var subFolderItem = database.GetFolderSyncItemFromRemotePath(remoteSubFolder.Path); if (null == subFolderItem) { subFolderItem = SyncItemFactory.CreateFromRemotePath(remoteSubFolder.Path, repoInfo); } // Check whether local folder exists. if (Directory.Exists(subFolderItem.LocalPath)) { // Recurse into folder. CrawlSync(remoteSubFolder, remotePath, subFolderItem.LocalPath); } else { // If there was previously a file with this name, delete it. // TODO warn if local changes in the file. if (File.Exists(subFolderItem.LocalPath)) { activityListener.ActivityStarted(); Utils.DeleteEvenIfReadOnly(subFolderItem.LocalPath); activityListener.ActivityStopped(); } if (database.ContainsFolder(subFolderItem)) { // If there was previously a folder with this name, it means that // the user has deleted it voluntarily, so delete it from server too. activityListener.ActivityStarted(); // Delete the folder from the remote server. try { Logger.Debug("Removing remote folder tree: " + remoteSubFolder.Path); IList <string> failedIDs = remoteSubFolder.DeleteTree(true, null, true); if (failedIDs == null || failedIDs.Count != 0) { Logger.Error("Failed to completely delete remote folder " + remoteSubFolder.Path); // TODO Should we retry? Maybe at least once, as a manual recursion instead of a DeleteTree. } } catch (CmisPermissionDeniedException e) { // We don't have the permission to delete this folder. Warn and recreate it. Utils.NotifyUser("You don't have the necessary permissions to delete folder " + remoteSubFolder.Path + "\nIf you feel you should be able to delete it, please contact your server administrator"); RecursiveFolderCopy(remoteSubFolder, remotePath, subFolderItem.LocalPath); } // Delete the folder from database. database.RemoveFolder(subFolderItem); activityListener.ActivityStopped(); } else { if (Utils.IsInvalidFileName(remoteSubFolder.Name)) { Logger.Warn("Skipping remote folder with name invalid on local filesystem: " + remoteSubFolder.Name); } else { // The folder has been recently created on server, so download it. activityListener.ActivityStarted(); Directory.CreateDirectory(subFolderItem.LocalPath); // Create database entry for this folder. // TODO - Yannick - Add metadata database.AddFolder(subFolderItem, remoteSubFolder.Id, remoteSubFolder.LastModificationDate); Logger.Info("Added folder to database: " + subFolderItem.LocalPath); // Recursive copy of the whole folder. RecursiveFolderCopy(remoteSubFolder, remotePath, subFolderItem.LocalPath); activityListener.ActivityStopped(); } } } } } catch (Exception e) { activityListener.ActivityStopped(); ProcessRecoverableException("Could not crawl sync remote folder: " + remoteSubFolder.Path, e); } }
/// <summary> /// Crawl remote subfolder, syncing down if needed. /// Meanwhile, cache all contained remote folders, they are output parameters that are used in CrawlLocalFiles/CrawlLocalFolders /// </summary> private void CrawlRemoteFolder(IFolder remoteSubFolder, string localFolder, IList<string> remoteFolders) { SleepWhileSuspended(); try { if (Utils.WorthSyncing(localFolder, remoteSubFolder.Name, repoinfo)) { // Logger.Debug("CrawlRemote localFolder:\"" + localFolder + "\" remoteSubFolder.Path:\"" + remoteSubFolder.Path + "\" remoteSubFolder.Name:\"" + remoteSubFolder.Name + "\""); remoteFolders.Add(remoteSubFolder.Name); var subFolderItem = database.GetFolderSyncItemFromRemotePath(remoteSubFolder.Path); if (null == subFolderItem) { subFolderItem = SyncItemFactory.CreateFromRemotePath(remoteSubFolder.Path, repoinfo); } // Check whether local folder exists. if (Directory.Exists(subFolderItem.LocalPath)) { // Recurse into folder. CrawlSync(remoteSubFolder, subFolderItem.LocalPath); } else { // If there was previously a file with this name, delete it. // TODO warn if local changes in the file. if (File.Exists(subFolderItem.LocalPath)) { activityListener.ActivityStarted(); File.Delete(subFolderItem.LocalPath); activityListener.ActivityStopped(); } if (database.ContainsFolder(subFolderItem)) { // If there was previously a folder with this name, it means that // the user has deleted it voluntarily, so delete it from server too. activityListener.ActivityStarted(); // Delete the folder from the remote server. try { Logger.Debug("Removing remote folder tree: " + remoteSubFolder.Path); IList<string> failedIDs = remoteSubFolder.DeleteTree(true, null, true); if (failedIDs == null || failedIDs.Count != 0) { Logger.Error("Failed to completely delete remote folder " + remoteSubFolder.Path); // TODO Should we retry? Maybe at least once, as a manual recursion instead of a DeleteTree. } } catch (CmisPermissionDeniedException e) { // We don't have the permission to delete this folder. Warn and recreate it. Utils.NotifyUser("You don't have the necessary permissions to delete folder " + remoteSubFolder.Path + "\nIf you feel you should be able to delete it, please contact your server administrator"); DownloadFolder(remoteSubFolder, localFolder); } // Delete the folder from database. database.RemoveFolder(subFolderItem); activityListener.ActivityStopped(); } else { if (Utils.IsInvalidFileName(remoteSubFolder.Name)) { Logger.Warn("Skipping remote folder with name invalid on local filesystem: " + remoteSubFolder.Name); } else { // The folder has been recently created on server, so download it. activityListener.ActivityStarted(); Directory.CreateDirectory(subFolderItem.LocalPath); // Create database entry for this folder. // TODO - Yannick - Add metadata database.AddFolder(subFolderItem, remoteSubFolder.Id, remoteSubFolder.LastModificationDate); Logger.Info("Added folder to database: " + subFolderItem.LocalPath); // Recursive copy of the whole folder. RecursiveFolderCopy(remoteSubFolder, subFolderItem.LocalPath); activityListener.ActivityStopped(); } } } } } catch (Exception e) { activityListener.ActivityStopped(); ProcessRecoverableException("Could not crawl sync remote folder: " + remoteSubFolder.Path, e); } }
/// <summary> /// Download a single folder from the CMIS server for sync. /// </summary> /// <returns>true if successful</returns> private bool SyncDownloadFolder(IFolder remoteSubFolder, string localFolder) { var syncItem = SyncItemFactory.CreateFromRemotePath(remoteSubFolder.Path, repoinfo); string localName = PathRepresentationConverter.RemoteToLocal(remoteSubFolder.Name); // If the target folder has been removed/renamed, then relaunch sync. if (!Directory.Exists(localFolder)) { Logger.Warn("The target folder has been removed/renamed: " + localFolder); return false; } if (Directory.Exists(syncItem.LocalPath)) { return true; } if (database.ContainsFolder(syncItem)) { // If there was previously a folder with this name, it means that // the user has deleted it voluntarily, so delete it from server too. // Delete the folder from the remote server. Logger.Debug(String.Format("CMIS::DeleteTree({0})", remoteSubFolder.Path)); try { remoteSubFolder.DeleteTree(true, null, true); // Delete the folder from database. database.RemoveFolder(syncItem); } catch (Exception) { Logger.Info("Remote Folder could not be deleted: " + remoteSubFolder.Path); // Just go on and try it the next time } } else { // The folder has been recently created on server, so download it. // If there was previously a file with this name, delete it. // TODO warn if local changes in the file. if (File.Exists(syncItem.LocalPath)) { string conflictFilename = Utils.CreateConflictFilename(syncItem.LocalPath, repoinfo.User); Logger.Warn("Local file \"" + syncItem.LocalPath + "\" has been renamed to \"" + conflictFilename + "\""); File.Move(syncItem.LocalPath, conflictFilename); } // Skip if invalid folder name. See https://github.com/aegif/CmisSync/issues/196 if (Utils.IsInvalidFolderName(localName)) { Logger.Info("Skipping download of folder with illegal name: " + localName); } else if (repoinfo.isPathIgnored(syncItem.RemoteRelativePath)) { Logger.Info("Skipping dowload of ignored folder: " + syncItem.RemoteRelativePath); } else { // Create local folder.remoteDocument.Name Logger.Info("Creating local directory: " + syncItem.LocalPath); Directory.CreateDirectory(syncItem.LocalPath); // Should the local folder be made read-only? // Check ther permissions of the current user to the remote folder. bool readOnly = ! remoteSubFolder.AllowableActions.Actions.Contains(PermissionMappingKeys.CanAddToFolderObject); if (readOnly) { new DirectoryInfo(syncItem.LocalPath).Attributes = FileAttributes.ReadOnly; } // Create database entry for this folder. // TODO - Yannick - Add metadata database.AddFolder(syncItem, remoteSubFolder.Id, remoteSubFolder.LastModificationDate); } } return true; }
/// <summary> /// Delete the folder from the remote server. /// </summary> public void DeleteRemoteFolder(IFolder folder, SyncItem syncItem, string upperFolderPath) { try { Logger.Debug("Removing remote folder tree: " + folder.Path); IList<string> failedIDs = folder.DeleteTree(true, null, true); if (failedIDs == null || failedIDs.Count != 0) { Logger.Error("Failed to completely delete remote folder " + folder.Path); // TODO Should we retry? Maybe at least once, as a manual recursion instead of a DeleteTree. } // Delete the folder from database. database.RemoveFolder(syncItem); } catch (CmisPermissionDeniedException e) { // TODO: Add resource string message = String.Format("フォルダ {0} に対して削除やリネームする権限がないため、サーバからこのフォルダを復元します(フォルダに含まれるファイル数が多い場合、復元に時間がかかります)。", syncItem.LocalPath); Utils.NotifyUser(message); // We don't have the permission to delete this folder. Warn and recreate it. /* Utils.NotifyUser("You don't have the necessary permissions to delete folder " + folder.Path + "\nIf you feel you should be able to delete it, please contact your server administrator"); */ database.RemoveFolder(syncItem); DownloadDirectory(folder, syncItem.RemotePath, syncItem.LocalPath); } }
/// <summary> /// Download a single folder from the CMIS server for sync. /// </summary> private bool SyncDownloadFolder(IFolder remoteSubFolder, string localFolder) { string name = remoteSubFolder.Name; string remotePathname = remoteSubFolder.Path; string localSubFolder = Path.Combine(localFolder, name); if (!Directory.Exists(localFolder)) { // The target folder has been removed/renamed => relaunch sync Logger.Warn("The target folder has been removed/renamed: " + localFolder); return false; } if (Directory.Exists(localSubFolder)) { return true; } if (database.ContainsFolder(localSubFolder)) { // If there was previously a folder with this name, it means that // the user has deleted it voluntarily, so delete it from server too. // Delete the folder from the remote server. Logger.Debug(String.Format("CMIS::DeleteTree({0})", remoteSubFolder.Path)); try { remoteSubFolder.DeleteTree(true, null, true); // Delete the folder from database. database.RemoveFolder(localSubFolder); } catch (Exception) { Logger.Info("Remote Folder could not be deleted: " + remoteSubFolder.Path); // Just go on and try it the next time } } else { // The folder has been recently created on server, so download it. // If there was previously a file with this name, delete it. // TODO warn if local changes in the file. if (File.Exists(localSubFolder)) { Logger.Warn("Local file \"" + localSubFolder + "\" has been renamed to \"" + localSubFolder + ".conflict\""); File.Move(localSubFolder, localSubFolder + ".conflict"); } // Skip if invalid folder name. See https://github.com/nicolas-raoul/CmisSync/issues/196 if (Utils.IsInvalidFolderName(name)) { Logger.Info("Skipping download of folder with illegal name: " + name); } else if (repoinfo.isPathIgnored(remotePathname)) { Logger.Info("Skipping dowload of ignored folder: " + remotePathname); } else { // Create local folder.remoteDocument.Name Logger.Info("Creating local directory: " + localSubFolder); Directory.CreateDirectory(localSubFolder); // Create database entry for this folder. // TODO - Yannick - Add metadata database.AddFolder(localSubFolder, remoteSubFolder.Id, remoteSubFolder.LastModificationDate); } } return true; }
/// <summary> /// Crawl remote content, syncing down if needed. /// Meanwhile, cache remoteFiles and remoteFolders, they are output parameters that are used in CrawlLocalFiles/CrawlLocalFolders /// </summary> private void CrawlRemote(IFolder remoteFolder, string localFolder, IList remoteFiles, IList remoteFolders) { foreach (ICmisObject cmisObject in remoteFolder.GetChildren()) { while (repo.Status == SyncStatus.Suspend) { Logger.Info("Sync of " + repoinfo.Name + " is suspended, will retry in " + repoinfo.PollInterval + "ms"); System.Threading.Thread.Sleep((int)repoinfo.PollInterval); // TODO Should not sleep, but skip instead. } #region Cmis Folder if (cmisObject is DotCMIS.Client.Impl.Folder) { // It is a CMIS folder. IFolder remoteSubFolder = (IFolder)cmisObject; if (Utils.WorthSyncing(remoteSubFolder.Name) && !repoinfo.isPathIgnored(remoteSubFolder.Path)) { //Logger.Debug("CrawlRemote dir: " + localFolder + Path.DirectorySeparatorChar.ToString() + remoteSubFolder.Name); remoteFolders.Add(remoteSubFolder.Name); string localSubFolder = localFolder + Path.DirectorySeparatorChar.ToString() + remoteSubFolder.Name; // Check whether local folder exists. if (Directory.Exists(localSubFolder)) { // Recurse into folder. CrawlSync(remoteSubFolder, localSubFolder); } else { // If there was previously a file with this name, delete it. // TODO warn if local changes in the file. if (File.Exists(localSubFolder)) { File.Delete(localSubFolder); } if (database.ContainsFolder(localSubFolder)) { // If there was previously a folder with this name, it means that // the user has deleted it voluntarily, so delete it from server too. // Delete the folder from the remote server. remoteSubFolder.DeleteTree(true, null, true); // Delete the folder from database. database.RemoveFolder(localSubFolder); } else { // The folder has been recently created on server, so download it. // Skip if invalid folder name. See https://github.com/nicolas-raoul/CmisSync/issues/196 if (Utils.IsInvalidFileName(remoteSubFolder.Name)) { Logger.Info("Skipping download of folder with illegal name: " + remoteSubFolder.Name); } else if (repoinfo.isPathIgnored(remoteSubFolder.Path)) { Logger.Info("Skipping dowload of ignored folder: " + remoteSubFolder.Name); } else { // Create local folder.remoteDocument.Name Directory.CreateDirectory(localSubFolder); // Create database entry for this folder. // TODO - Yannick - Add metadata database.AddFolder(localSubFolder, remoteFolder.LastModificationDate); // Recursive copy of the whole folder. RecursiveFolderCopy(remoteSubFolder, localSubFolder); } } } } } #endregion #region Cmis Document else { // It is a CMIS document. IDocument remoteDocument = (IDocument)cmisObject; if (Utils.WorthSyncing(remoteDocument.Name)) { // We use the filename of the document's content stream. // This can be different from the name of the document. // For instance in FileNet it is not usual to have a document where // document.Name is "foo" and document.ContentStreamFileName is "foo.jpg". string remoteDocumentFileName = remoteDocument.ContentStreamFileName; //Logger.Debug("CrawlRemote doc: " + localFolder + Path.DirectorySeparatorChar.ToString() + remoteDocumentFileName); // Check if file extension is allowed remoteFiles.Add(remoteDocumentFileName); // If this file does not have a filename, ignore it. // It sometimes happen on IBM P8 CMIS server, not sure why. if (remoteDocumentFileName == null) { Logger.Warn("Skipping download of '" + remoteDocument.Name + "' with null content stream in " + localFolder); continue; } string filePath = localFolder + Path.DirectorySeparatorChar.ToString() + remoteDocumentFileName; if (File.Exists(filePath)) { // Check modification date stored in database and download if remote modification date if different. DateTime?serverSideModificationDate = ((DateTime)remoteDocument.LastModificationDate).ToUniversalTime(); DateTime?lastDatabaseUpdate = database.GetServerSideModificationDate(filePath); if (lastDatabaseUpdate == null) { Logger.Info("Downloading file absent from database: " + filePath); DownloadFile(remoteDocument, localFolder); } else { // If the file has been modified since last time we downloaded it, then download again. if (serverSideModificationDate > lastDatabaseUpdate) { if (database.LocalFileHasChanged(filePath)) { Logger.Info("Conflict with file: " + remoteDocumentFileName + ", backing up locally modified version and downloading server version"); // Rename locally modified file. String ext = Path.GetExtension(filePath); String filename = Path.GetFileNameWithoutExtension(filePath); String path = Path.GetDirectoryName(filePath); String NewFileName = Utils.SuffixIfExists(filename + "_" + repoinfo.User + "-version"); String newFilePath = Path.Combine(path, NewFileName); File.Move(filePath, newFilePath); // Download server version DownloadFile(remoteDocument, localFolder); repo.OnConflictResolved(); // TODO move to OS-dependant layer //System.Windows.Forms.MessageBox.Show("Someone modified a file at the same time as you: " + filePath // + "\n\nYour version has been saved with a '_your-version' suffix, please merge your important changes from it and then delete it."); // TODO show CMIS property lastModifiedBy } else { Logger.Info("Downloading modified file: " + remoteDocumentFileName); DownloadFile(remoteDocument, localFolder); } } } } else { if (database.ContainsFile(filePath)) { // File has been recently removed locally, so remove it from server too. Logger.Info("Removing locally deleted file on server: " + filePath); remoteDocument.DeleteAllVersions(); // Remove it from database. database.RemoveFile(filePath); } else { // New remote file, download it. Logger.Info("New remote file: " + filePath); DownloadFile(remoteDocument, localFolder); } } } } #endregion } }
public void CheckinTest( string canonical_name, string localPath, string remoteFolderPath, string url, string user, string password, string repositoryId, string binding) { string subFolderName = "subFolder"; string fileName = "testFile.bin"; string subFolderPath = remoteFolderPath.TrimEnd('/') + "/" + subFolderName; string filePath = subFolderPath + "/" + fileName; ISession session = DotCMISSessionTests.CreateSession(user, password, url, repositoryId, binding); if (!session.ArePrivateWorkingCopySupported()) { Assert.Ignore("PWCs are not supported"); } try { IFolder dir = session.GetObjectByPath(remoteFolderPath.TrimEnd('/') + "/" + subFolderName) as IFolder; if (dir != null) { dir.DeleteTree(true, null, true); } } catch (CmisObjectNotFoundException) { } IFolder folder = (IFolder)session.GetObjectByPath(remoteFolderPath); IFolder subFolder = folder.CreateFolder(subFolderName); string content = "testContent"; IDocument doc = subFolder.CreateDocument(fileName, "testContent", checkedOut: true); IObjectId checkoutId = doc.CheckOut(); IDocument docCheckout = session.GetObject(checkoutId) as IDocument; Assert.AreEqual(doc.ContentStreamLength, docCheckout.ContentStreamLength); ContentStream contentStream = new ContentStream(); contentStream.FileName = fileName; contentStream.MimeType = MimeType.GetMIMEType(fileName); contentStream.Length = content.Length; for (int i = 0; i < 10; ++i) { using (var memstream = new MemoryStream(Encoding.UTF8.GetBytes(content))) { contentStream.Stream = memstream; docCheckout.AppendContentStream(contentStream, i == 9); } Assert.That(docCheckout.ContentStreamLength, Is.EqualTo(content.Length * (i + 2))); } IObjectId checkinId = docCheckout.CheckIn(true, null, null, "checkin"); IDocument docCheckin = session.GetObject(checkinId) as IDocument; docCheckin.Refresh(); // refresh is required, or DotCMIS will re-use the cached properties if checinId is the same as doc.Id Assert.That(docCheckin.ContentStreamLength, Is.EqualTo(content.Length * (9 + 2))); }
/// <summary> /// Crawl remote subfolder, syncing down if needed. /// Meanwhile, cache all contained remote folders, they are output parameters that are used in CrawlLocalFiles/CrawlLocalFolders /// </summary> private void CrawlRemoteFolder(IFolder remoteSubFolder, string localFolder, IList<string> remoteFolders) { CheckPendingCancelation(); try { if (SyncUtils.IsWorthSyncing(localFolder, remoteSubFolder.Name, SyncFolderInfo)) { // Logger.Debug("CrawlRemote localFolder:\"" + localFolder + "\" remoteSubFolder.Path:\"" + remoteSubFolder.Path + "\" remoteSubFolder.Name:\"" + remoteSubFolder.Name + "\""); remoteFolders.Add(remoteSubFolder.Name); SyncItem subFolderItem = getSyncItemFromRemotePath(remoteSubFolder.Path); // Check whether local folder exists. if (Directory.Exists(subFolderItem.LocalPath)) { // Recurse into folder. CrawlSync(remoteSubFolder, subFolderItem.LocalPath); } else { // If there was previously a file with this name, delete it. // TODO warn if local changes in the file. if (File.Exists(subFolderItem.LocalPath)) { File.Delete(subFolderItem.LocalPath); } if (database.ContainsFolder(subFolderItem)) { // If there was previously a folder with this name, it means that // the user has deleted it voluntarily, so delete it from server too. // Delete the folder from the remote server. try { Logger.Debug("Removing remote folder tree: " + remoteSubFolder.Path); IList<string> failedIDs = remoteSubFolder.DeleteTree(true, null, true); if (failedIDs == null || failedIDs.Count != 0) { Logger.Error("Failed to completely delete remote folder " + remoteSubFolder.Path); // TODO Should we retry? Maybe at least once, as a manual recursion instead of a DeleteTree. } } catch (CmisPermissionDeniedException e) { HandleException(new DeleteRemoteFolderException(remoteSubFolder.Path, e)); //restore the folder //TODO: check permissions before deleting the folder DownloadFolder(remoteSubFolder, localFolder); return; } // Delete the folder from database. database.RemoveFolder(subFolderItem); } else { if (SyncUtils.IsInvalidFileName(remoteSubFolder.Name)) { Logger.Warn("Skipping remote folder with name invalid on local filesystem: " + remoteSubFolder.Name); } else { // The folder has been recently created on server, so download it. Directory.CreateDirectory(subFolderItem.LocalPath); // Create database entry for this folder. // TODO - Yannick - Add metadata database.AddFolder(subFolderItem, remoteSubFolder.Id, remoteSubFolder.LastModificationDate); Logger.Info("Added folder to database: " + subFolderItem.LocalPath); // Recursive copy of the whole folder. RecursiveFolderCopy(remoteSubFolder, subFolderItem.LocalPath); } } } } } catch (Exception e) { HandleException(new DownloadFolderException(remoteSubFolder.Path, e)); } }