Exemplo n.º 1
0
            /// <summary>
            /// Apply: Added files.
            /// </summary>
            public bool ApplyAddedFiles(ref List <string> addedFiles)
            {
                bool success = true;

                foreach (string addedFile in addedFiles)
                {
                    string   destinationFolderPath = Path.GetDirectoryName(addedFile);
                    SyncItem folderItem            = SyncItemFactory.CreateFromLocalPath(destinationFolderPath, true, repoInfo, database);
                    SyncItem fileItem = SyncItemFactory.CreateFromLocalPath(addedFile, false, repoInfo, database);
                    try
                    {
                        IFolder destinationFolder = (IFolder)session.GetObjectByPath(folderItem.RemotePath);

                        // Fill documents list, needed by the crawl method.
                        IList <string> remoteFiles = new List <string>();

                        if (CmisUtils.DocumentExists(session, fileItem.RemotePath))
                        {
                            remoteFiles.Add(fileItem.RemoteLeafname);
                        }

                        // Crawl this particular file.
                        CheckLocalFile(fileItem.LocalPath, destinationFolder, remoteFiles);
                    }
                    catch (Exception e)
                    {
                        Logger.Error("Error applying local file addition to the server: " + addedFile, e);
                        success = false;
                    }
                }
                return(success);
            }
            /// <summary>
            /// Apply: Added folders.
            /// </summary>
            public bool ApplyAddedFolders(ref List <string> addedFolders)
            {
                bool success = true;

                foreach (string addedFolder in addedFolders)
                {
                    string   destinationFolderPath = Path.GetDirectoryName(addedFolder);
                    SyncItem destinationFolderItem = SyncItemFactory.CreateFromLocalPath(destinationFolderPath, true, repoInfo, database);
                    SyncItem addedFolderItem       = SyncItemFactory.CreateFromLocalPath(addedFolder, true, repoInfo, database);
                    try
                    {
                        IFolder destinationFolder = (IFolder)session.GetObjectByPath(destinationFolderItem.RemotePath, true);

                        IList <string> remoteFolders = new List <string>();

                        if (CmisUtils.FolderExists(session, addedFolderItem.RemotePath))
                        {
                            remoteFolders.Add(addedFolderItem.RemoteLeafname);
                        }

                        // TODO more efficient: first create said folder, then call CrawlSync in it.
                        CrawlSync(destinationFolder, destinationFolderItem.RemotePath, destinationFolderItem.LocalPath);
                    }
                    catch (Exception e)
                    {
                        Logger.Error("Error applying local folder addition to the server: " + addedFolder, e);
                        success = false;
                    }
                }
                return(success);
            }
Exemplo n.º 3
0
            /// <summary>
            /// Watchers the sync delete.
            /// </summary>
            /// <param name="remoteFolder">Remote folder.</param>
            /// <param name="localFolder">Local folder.</param>
            /// <param name="pathname">Pathname.</param>
            private void WatcherSyncDelete(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('\\', '/'); // FIXME
                    if (database.ContainsFile(SyncItemFactory.CreateFromLocalPath(pathname, repoinfo)))
                    {
                        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(SyncItemFactory.CreateFromLocalPath(pathname, repoinfo));
                    }
                    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(SyncItemFactory.CreateFromLocalPath(pathname, repoinfo));
                    }
                    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);
                }
            }
Exemplo n.º 4
0
            /// <summary>
            /// Takes the loaded and given descendants as children of the given remoteFolder and checks agains the localFolder
            /// </summary>
            /// <param name="remoteFolder">Folder which contains to given children</param>
            /// <param name="children">All children of the given remote folder</param>
            /// <param name="localFolder">The local folder, with which the remoteFolder should be synchronized</param>
            /// <returns></returns>
            private void CrawlDescendants(IFolder remoteFolder, IList <ITree <IFileableCmisObject> > children, string localFolder)
            {
                // Lists of files/folders, to delete those that have been removed on the server.
                IList <string> remoteFiles      = new List <string>();
                IList <string> remoteSubfolders = new List <string>();

                if (children != null)
                {
                    foreach (ITree <IFileableCmisObject> node in children)
                    {
                        #region Cmis Folder
                        if (node.Item is Folder)
                        {
                            // It is a CMIS folder.
                            IFolder remoteSubFolder = (IFolder)node.Item;
                            remoteSubfolders.Add(remoteSubFolder.Name);
                            if (!Utils.IsInvalidFolderName(remoteSubFolder.Name) && !repoinfo.isPathIgnored(remoteSubFolder.Path))
                            {
                                var syncItem = database.GetFolderSyncItemFromRemotePath(remoteSubFolder.Path);
                                if (null == syncItem)
                                {
                                    syncItem = SyncItemFactory.CreateFromRemotePath(remoteSubFolder.Path, repoinfo);
                                }

                                //Check whether local folder exists.
                                if (Directory.Exists(syncItem.LocalPath))
                                {
                                    CrawlDescendants(remoteSubFolder, node.Children, syncItem.LocalPath);
                                }
                                else
                                {
                                    DownloadFolder(remoteSubFolder, localFolder);
                                    if (Directory.Exists(syncItem.LocalPath))
                                    {
                                        RecursiveFolderCopy(remoteSubFolder, syncItem.LocalPath);
                                    }
                                }
                            }
                        }
                        #endregion

                        #region Cmis Document
                        else if (node.Item is Document)
                        {
                            // It is a CMIS document.
                            string    remoteFolderPath   = remoteFolder.Path;
                            string    remoteDocumentName = ((IDocument)node.Item).Name;
                            IDocument remoteDocument     = (IDocument)node.Item;
                            SyncDownloadFile(remoteDocument, localFolder, remoteFiles);
                        }
                        #endregion
                    }
                }
                CrawlLocalFiles(localFolder, remoteFolder, remoteFiles);
                CrawlLocalFolders(localFolder, remoteFolder, remoteSubfolders);
            }
Exemplo n.º 5
0
            /// <summary>
            /// Synchronize changes made to a particular CMIS object.
            /// </summary>
            private bool CrawlCmisObject(ICmisObject cmisObject)
            {
                bool success = true;

                if (cmisObject is DotCMIS.Client.Impl.Folder)
                {
                    var remoteSubFolder = cmisObject as IFolder;

                    // Look for the local equivalent.
                    var localFolderItem = database.GetFolderSyncItemFromRemotePath(remoteSubFolder.Path);
                    while (true)
                    {
                        // If other local folders have the same id, they are obsolete and must be deteled.
                        var foldersToDelete = database.GetAllFoldersWithCmisId(cmisObject.Id).Where(p => p.RemotePath != remoteSubFolder.Path);
                        foreach (var folderToDelete in foldersToDelete)
                        {
                            success &= RemoveFolderLocally(folderToDelete.LocalPath);
                        }
                        ;

                        if (localFolderItem != null || remoteSubFolder.IsRootFolder)
                        {
                            break;
                        }

                        // Go up one level before performing the same thing.
                        remoteSubFolder = remoteSubFolder.Parents[0]; //TODO: Fix Parents[0] for multi-parent repositories
                        localFolderItem = database.GetFolderSyncItemFromRemotePath(remoteSubFolder.Path);
                    }
                    ;

                    success &= CrawlSync(remoteSubFolder, remoteSubFolder.Path, localFolderItem.LocalPath);
                }
                else if (cmisObject is DotCMIS.Client.Impl.Document)
                {
                    var remoteDocument = cmisObject as IDocument;

                    // Apply the change on all paths via which it is applicable.
                    foreach (IFolder remoteIFolder in remoteDocument.Parents)
                    {
                        if (PathIsApplicable(remoteIFolder.Path))
                        {
                            Logger.Debug("Document change is applicable:" + remoteIFolder);

                            var localFolderItem = database.GetFolderSyncItemFromRemotePath(remoteIFolder.Path);
                            var localFolder     = localFolderItem.LocalPath;

                            var remoteDocumentPath = CmisUtils.PathCombine(remoteIFolder.Path, repoInfo.CmisProfile.localFilename(remoteDocument));
                            var documentItem       = SyncItemFactory.CreateFromRemoteDocument(remoteDocumentPath, remoteDocument, repoInfo, database);

                            success &= CrawlRemoteDocument(remoteDocument, documentItem.RemotePath, localFolder, null);
                        }
                    }
                }
                return(success);
            }
Exemplo n.º 6
0
        /// <summary>
        /// Gets the syncitem from id.
        /// </summary>
        /// <returns>syncitem.</returns>
        /// <param name="id">Identifier.</param>
        public SyncItem GetSyncItem(string id)
        {
            Dictionary <string, object> parameters = new Dictionary <string, object>();

            parameters.Add("id", id);
            var    result       = ExecuteSQL("SELECT path, localPath FROM files WHERE id=@id", parameters);
            string remotePath   = (string)result["path"];
            object localPathObj = result["localPath"];
            string localPath    = (localPathObj is DBNull) ? remotePath : (string)localPathObj;

            return(SyncItemFactory.CreateFromPaths(pathPrefix, localPath, remotePathPrefix, remotePath));
        }
Exemplo n.º 7
0
            /// <summary>
            /// Apply a remote change for Deleted.
            /// </summary>
            private bool ApplyRemoteChangeDelete(IChangeEvent change)
            {
                try
                {
                    ICmisObject remoteObject = session.GetObject(change.ObjectId);
                    if (null != remoteObject)
                    {
                        //  should be moveObject
                        Logger.Info("Ignore moveObject for id " + change.ObjectId);
                        return(true);
                    }
                }
                catch (CmisObjectNotFoundException)
                {
                }
                catch (Exception e)
                {
                    Logger.Warn("Exception when GetObject for " + change.ObjectId + " : ", e);
                }
                string savedDocumentPath = database.GetRemoteFilePath(change.ObjectId); // FIXME use SyncItem to differentiate between local path and remote path

                if (null != savedDocumentPath)
                {
                    Logger.Info("Remove local document: " + savedDocumentPath);
                    if (File.Exists(savedDocumentPath))
                    {
                        File.Delete(savedDocumentPath);
                    }

                    database.RemoveFile(SyncItemFactory.CreateFromRemotePath(savedDocumentPath, repoinfo));
                    Logger.Info("Removed local document: " + savedDocumentPath);
                    return(true);
                }

                string savedFolderPath = database.GetFolderPath(change.ObjectId);

                if (null != savedFolderPath)
                {
                    Logger.Info("Remove local folder: " + savedFolderPath);
                    if (Directory.Exists(savedFolderPath))
                    {
                        Directory.Delete(savedFolderPath, true);
                        database.RemoveFolder(SyncItemFactory.CreateFromRemotePath(savedFolderPath, repoinfo));
                    }
                    Logger.Info("Removed local folder: " + savedFolderPath);
                    return(true);
                }

                return(true);
            }
Exemplo n.º 8
0
        /// <summary>
        /// Gets the syncitem from local path.
        /// </summary>
        /// <returns>syncitem. If the item is not included in the database, return null.</returns>
        /// <param name="localPath">Local path.</param>
        public SyncItem GetSyncItemFromLocalPath(string localPath)
        {
            string normalizedLocalPath             = RemoveLocalPrefix(localPath);
            Dictionary <string, object> parameters = new Dictionary <string, object>();

            parameters.Add("localPath", normalizedLocalPath);
            string path = (string)ExecuteSQLFunction("SELECT path FROM files WHERE localPath=@localPath", parameters);

            if (string.IsNullOrEmpty(path))
            {
                return(null);
            }

            return(SyncItemFactory.CreateFromPaths(pathPrefix, normalizedLocalPath, remotePathPrefix, path));
        }
Exemplo n.º 9
0
        /// <summary>
        /// Gets the syncitem from remote path.
        /// </summary>
        /// <returns>syncitem. If the item is not included in the database, return null.</returns>
        /// <param name="remotePath">Remote path.</param>
        public SyncItem GetFolderSyncItemFromRemotePath(string remotePath)
        {
            string normalizedRemotePath            = RemoveRemotePrefix(remotePath);
            Dictionary <string, object> parameters = new Dictionary <string, object>();

            parameters.Add("path", normalizedRemotePath);
            string localPath = (string)ExecuteSQLFunction("SELECT localPath FROM folders WHERE path=@path", parameters);

            if (string.IsNullOrEmpty(localPath))
            {
                return(null);
            }

            return(SyncItemFactory.CreateFromPaths(pathPrefix, localPath, remotePathPrefix, normalizedRemotePath));
        }
Exemplo n.º 10
0
            /// <summary>
            /// Crawl local folder in a given directory (not recursive).
            /// </summary>
            private void CrawlLocalFolder(string localSubFolder, IFolder remoteFolder, IList <string> remoteFolders)
            {
                SleepWhileSuspended();
                try
                {
                    if (Utils.IsSymlink(new DirectoryInfo(localSubFolder)))
                    {
                        Logger.Info("Skipping symbolic link folder: " + localSubFolder);
                        return;
                    }

                    string folderName     = Path.GetFileName(localSubFolder);
                    var    syncFolderItem = database.GetFolderSyncItemFromLocalPath(localSubFolder);
                    if (null == syncFolderItem)
                    {
                        syncFolderItem = SyncItemFactory.CreateFromLocalPath(localSubFolder, repoInfo);
                    }

                    if (Utils.WorthSyncing(Path.GetDirectoryName(localSubFolder), folderName, repoInfo))
                    {
                        if (!remoteFolders.Contains(syncFolderItem.RemoteFileName))
                        {
                            // This local folder is not on the CMIS server now, so
                            // check whether it used to exist on server or not.
                            if (database.ContainsFolder(syncFolderItem))
                            {
                                activityListener.ActivityStarted();
                                RemoveFolderLocally(localSubFolder);
                                activityListener.ActivityStopped();
                            }
                            else
                            {
                                if (BIDIRECTIONAL)
                                {
                                    // New local folder, upload recursively.
                                    activityListener.ActivityStarted();
                                    UploadFolderRecursively(remoteFolder, localSubFolder);
                                    activityListener.ActivityStopped();
                                }
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    ProcessRecoverableException("Could not crawl sync local folder: " + localSubFolder, e);
                }
            }
Exemplo n.º 11
0
            /// <summary>
            /// Apply: Deleted files.
            /// </summary>
            public bool ApplyDeletedFiles(ref List <string> deletedFiles)
            {
                bool success = true;

                foreach (string deletedFile in deletedFiles)
                {
                    SyncItem deletedItem = SyncItemFactory.CreateFromLocalPath(deletedFile, false, repoInfo, database);
                    try
                    {
                        IDocument deletedDocument = (IDocument)session.GetObjectByPath(deletedItem.RemotePath);

                        // Needed by the normal crawl, but actually not used in our particular case here.
                        IList <string> remoteFiles = new List <string>();
                        try
                        {
                            CrawlRemoteDocument(deletedDocument, deletedItem.RemotePath, deletedItem.LocalPath, remoteFiles);
                        }
                        catch (CmisPermissionDeniedException e)
                        {
                            Logger.Info("This user cannot delete file : " + deletedFile, e);
                            DownloadFile(deletedDocument, deletedItem.RemotePath, deletedItem.LocalPath);
                        }
                    }
                    catch (Exception e)
                    {
                        if (e is ArgumentNullException || e is CmisObjectNotFoundException)
                        {
                            // Typical error when the document does not exist anymore on the server
                            // TODO Make DotCMIS generate a more precise exception.
                            Logger.Info("The document has probably been deleted on the server already: " + deletedFile, e);

                            // Delete local database entry.
                            database.RemoveFile(deletedItem);

                            // Note: This is not a failure per-se, so we don't need to modify the "success" variable.
                        }
                        else
                        {
                            // Could be a network error.
                            Logger.Error("Error applying local file deletion to the server: " + deletedFile, e);
                            success = false;
                        }
                    }
                }
                return(success);
            }
Exemplo n.º 12
0
            /// <summary>
            /// Apply: Modified files.
            /// </summary>
            public bool ApplyModifiedFiles(ref List <string> modifiedFiles)
            {
                bool success = true;

                foreach (string modifiedFile in modifiedFiles)
                {
                    SyncItem modifiedItem = SyncItemFactory.CreateFromLocalPath(modifiedFile, true, repoInfo, database);
                    try
                    {
                        IDocument modifiedDocument = (IDocument)session.GetObjectByPath(modifiedItem.RemotePath);
                        UpdateFile(modifiedItem.LocalPath, modifiedDocument);
                    }
                    catch (Exception e)
                    {
                        Logger.Error("Error applying local file modification to the server: " + modifiedFile, e);
                        success = false;
                    }
                }
                return(success);
            }
            /// <summary>
            /// Check whether a change is relevant for the current synchronized folder.
            /// </summary>

            /*private bool ChangeIsApplicable(IChangeEvent change)
             * {
             *  ICmisObject cmisObject = null;
             *  IFolder remoteFolder = null;
             *  IDocument remoteDocument = null;
             *  IList<string> remotePaths = null;
             *  var changeIdForDebug = change.Properties.ContainsKey("cmis:name") ?
             *      change.Properties["cmis:name"][0] : change.Properties["cmis:objectId"][0]; // TODO is it different from change.ObjectId ?
             *
             *  // Get the remote changed object.
             *  try
             *  {
             *      cmisObject = session.GetObject(change.ObjectId);
             *  }
             *  catch (CmisObjectNotFoundException)
             *  {
             *      Logger.Info("Changed object has already been deleted on the server. Syncing just in case: " + changeIdForDebug);
             *      // Unfortunately, in this case we can not know whether the object was relevant or not.
             *      return true;
             *  }
             *  catch (CmisRuntimeException e)
             *  {
             *      if (e.Message.Equals("Unauthorized"))
             *      {
             *          Logger.Info("We can not read the object id, so it is not an object we can sync anyway: " + changeIdForDebug);
             *          return false;
             *      }
             *      else
             *      {
             *          Logger.Info("A CMIS exception occured when querying the change. Syncing just in case: " + changeIdForDebug + " :", e);
             *          return true;
             *      }
             *
             *  }
             *  catch (CmisPermissionDeniedException e)
             *  {
             *      Logger.Info("Permission denied object  : " + changeIdForDebug + " :", e);
             *      return false;
             *  }
             *  catch (Exception e)
             *  {
             *      Logger.Warn("An exception occurred, syncing just in case: " + changeIdForDebug + " :", e);
             *      return true;
             *  }
             *
             *  // Check whether change is about a document or folder.
             *  remoteDocument = cmisObject as IDocument;
             *  remoteFolder = cmisObject as IFolder;
             *  if (remoteDocument == null && remoteFolder == null)
             *  {
             *      Logger.Info("Ignore change as it is not about a document nor folder: " + changeIdForDebug);
             *      return false;
             *  }
             *
             *  // Check whether it is a document worth syncing.
             *  if (remoteDocument != null)
             *  {
             *      if (!Utils.IsFileWorthSyncing(repoInfo.CmisProfile.localFilename(remoteDocument), repoInfo))
             *      {
             *          Logger.Info("Ignore change as it is about a document unworth syncing: " + changeIdForDebug);
             *          return false;
             *      }
             *      if (remoteDocument.Paths.Count == 0)
             *      {
             *          Logger.Info("Ignore the unfiled object: " + changeIdForDebug);
             *          return false;
             *      }
             *
             *      // We will check the remote document's path(s) at the end of this method.
             *      remotePaths = remoteDocument.Paths;
             *  }
             *
             *  // Check whether it is a folder worth syncing.
             *  if (remoteFolder != null)
             *  {
             *      remotePaths = new List<string>();
             *      remotePaths.Add(remoteFolder.Path);
             *  }
             *
             *  // Check the object's path(s)
             *  foreach (string remotePath in remotePaths)
             *  {
             *      if (PathIsApplicable(remotePath))
             *      {
             *          Logger.Debug("Change is applicable. Sync:" + changeIdForDebug);
             *          return true;
             *      }
             *  }
             *
             *  // No path was relevant, so ignore the change.
             *  return false;
             * }*/


            /// <summary>
            /// Apply CMIS ChangeLog changes.
            /// </summary>
            private bool CrawlChangeLogSyncAndUpdateChangeLogToken(IList <IChangeEvent> changeLogs, IFolder remoteFolder, string remotePath, string localFolder)
            {
                SleepWhileSuspended();
                bool success = true;
                var  sw      = new System.Diagnostics.Stopwatch();

                activityListener.ActivityStarted();
                try
                {
                    sw.Start();
                    Logger.InfoFormat("Change log sync start : {0} logs", changeLogs.Count());

                    // TODO: Compact changelogs

                    foreach (var change in changeLogs)
                    {
                        var id = change.ObjectId;
                        try
                        {
                            Logger.InfoFormat("Change log : Type={0}, Name={1}, Id={2}", change.ChangeType, change.Properties["cmis:name"].First(), id);
                        }
                        catch
                        {
                            Logger.InfoFormat("Change log : Type={0}, Id={1} ", change.ChangeType, id);
                        }

                        try
                        {
                            // Get the object with that identifier. Note that it might not exist anymore, so errors are expected, no need to log their details.
                            var cmisObject = session.GetObject(id, false);
                            if (change.ChangeType == ChangeType.Updated)
                            {
                                // Updates are tricky, as they can be move/rename operations in which we don't get complete information about
                                // both the source and destination.
                                // So, just sync everything.

                                success &= CrawlSyncAndUpdateChangeLogToken(remoteFolder, remoteFolderPath, localFolder);;
                                break; // We synced everything, so no need to process the rest of the changes.
                            }
                            else
                            {
                                // The change only applies to the object itself, so only crawl that object.
                                success &= CrawlCmisObject(cmisObject);
                            }
                        }
                        catch (CmisObjectNotFoundException ex)
                        {
                            if (change.ChangeType == ChangeType.Deleted)
                            {
                                var local = database.GetSyncItem(id);
                                if (local != null)
                                {
                                    var destFolderPath = Path.GetDirectoryName(local.LocalPath);
                                    var destFolderItem = SyncItemFactory.CreateFromLocalPath(destFolderPath, true, repoInfo, database);

                                    try
                                    {
                                        var destCmisFolder = session.GetObjectByPath(destFolderItem.RemotePath, true) as IFolder;

                                        if (local.IsFolder)
                                        {
                                            success &= CrawlSync(destCmisFolder, destFolderItem.RemotePath, destFolderItem.LocalPath);
                                        }
                                        else
                                        {
                                            success &= CheckLocalFile(local.LocalPath, destCmisFolder, null);
                                        }
                                    }
                                    catch (Exception e)
                                    {
                                        if (e is ArgumentNullException || e is CmisObjectNotFoundException)
                                        {
                                            // GetObjectByPath failure
                                            Logger.InfoFormat("Remote parent object not found, ignore. {0}", destFolderItem.RemotePath);
                                        }
                                        else
                                        {
                                            // Something really bad and unexpected happened.
                                            // Give up the ChangeLog strategy, and just crawl everything, this is better than failing.
                                            success &= CrawlSyncAndUpdateChangeLogToken(remoteFolder, remoteFolderPath, localFolder);;
                                            break; // We synced everything, so no need to process the rest of the changes.
                                        }
                                    }
                                }
                                else
                                {
                                    Logger.InfoFormat("Remote deleted object not in local database, ignore. {0}", id);
                                }
                            }
                            else
                            {
                                Logger.InfoFormat("Remote object not found but delete event, ignore. {0}", id);
                            }
                        }
                        catch (Exception ex)
                        {
                            Logger.Debug(ex);
                        }
                    }

                    sw.Stop();
                    Logger.InfoFormat("Change log sync end : {1} min / {0} logs", changeLogs.Count(), sw.Elapsed);
                }
                finally
                {
                    activityListener.ActivityStopped();
                }
                return(success);
            }
Exemplo n.º 14
0
            /// <summary>
            /// Crawl local file in a given directory (not recursive).
            /// </summary>
            private void CrawlLocalFile(string filePath, IFolder remoteFolder, IList <string> remoteFiles)
            {
                SleepWhileSuspended();

                try
                {
                    if (Utils.IsSymlink(new FileInfo(filePath)))
                    {
                        Logger.Info("Skipping symbolic linked file: " + filePath);
                        return;
                    }

                    var item = database.GetSyncItemFromLocalPath(filePath);
                    if (null == item)
                    {
                        item = SyncItemFactory.CreateFromLocalPath(filePath, repoInfo);
                    }

                    // string fileName = Path.GetFileName(filePath);
                    string fileName = item.RemoteFileName;

                    if (Utils.WorthSyncing(Path.GetDirectoryName(filePath), fileName, repoInfo))
                    {
                        if (!(remoteFiles.Contains(fileName) ||
                              // Workaround for Documentum which sometimes put a ".zip" extension to document names.
                              (CmisUtils.IsDocumentum(session) && remoteFiles.Contains(fileName + ".zip"))))
                        {
                            // This local file is not on the CMIS server now, so
                            // check whether it used invalidFolderNameRegex to exist on server or not.
                            if (database.ContainsFile(SyncItemFactory.CreateFromLocalPath(filePath, repoInfo)))
                            {
                                if (database.LocalFileHasChanged(filePath))
                                {
                                    // If file has changed locally, move to 'your_version' and warn about conflict
                                    if (BIDIRECTIONAL)
                                    {
                                        // Local file was updated, sync up.
                                        Logger.Info("Uploading locally edited remotely removed file from the repository: " + filePath);
                                        activityListener.ActivityStarted();
                                        UploadFile(filePath, remoteFolder);
                                        activityListener.ActivityStopped();
                                    }
                                    else
                                    {
                                        Logger.Info("Conflict with file: " + filePath + ", backing up locally modified version.");
                                        activityListener.ActivityStarted();
                                        // Rename locally modified file.
                                        String newFilePath = Utils.CreateConflictFilename(filePath, repoInfo.User);

                                        // The file might be ReadOnly, so make it writable first, otherwise the move will fail.
                                        File.SetAttributes(filePath, FileAttributes.Normal); // TODO use Utils.DeleteEvenIfReadOnly

                                        File.Move(filePath, newFilePath);

                                        // Delete file from database.
                                        database.RemoveFile(item);

                                        repo.OnConflictResolved();
                                        activityListener.ActivityStopped();
                                    }
                                }
                                else
                                {
                                    // File has been deleted on server, so delete it locally.
                                    Logger.Info("Removing remotely deleted file: " + filePath);
                                    activityListener.ActivityStarted();

                                    // The file might be ReadOnly, so make it writable first, otherwise removal will fail.
                                    File.SetAttributes(filePath, FileAttributes.Normal); // TODO use Utils.DeleteEvenIfReadOnly

                                    // Delete from the local filesystem.
                                    File.Delete(filePath);

                                    // Delete file from database.
                                    database.RemoveFile(item);

                                    activityListener.ActivityStopped();
                                }
                            }
                            else
                            {
                                if (BIDIRECTIONAL)
                                {
                                    // New file, sync up.
                                    Logger.Info("Uploading file absent on repository: " + filePath);
                                    activityListener.ActivityStarted();
                                    UploadFile(filePath, remoteFolder);
                                    activityListener.ActivityStopped();
                                }
                            }
                        }
                        else
                        {
                            // The file exists both on server and locally.
                            if (database.LocalFileHasChanged(filePath))
                            {
                                if (BIDIRECTIONAL)
                                {
                                    // Upload new version of file content.
                                    Logger.Info("Uploading file update on repository: " + filePath);
                                    activityListener.ActivityStarted();
                                    UpdateFile(filePath, remoteFolder);
                                    activityListener.ActivityStopped();
                                }
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    ProcessRecoverableException("Could not crawl sync local file: " + filePath, e);
                }
            }
Exemplo n.º 15
0
            /// <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);
                }
            }
Exemplo n.º 16
0
            /// <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);
                }
            }
Exemplo n.º 17
0
            /// <summary>
            /// Crawl remote document, syncing down if needed.
            /// Meanwhile, cache remoteFiles, they are output parameters that are used in CrawlLocalFiles/CrawlLocalFolders
            /// </summary>
            private void CrawlRemoteDocument(IDocument remoteDocument, string remotePath, string localFolder, IList <string> remoteFiles)
            {
                SleepWhileSuspended();

                if (Utils.WorthSyncing(localFolder, remoteDocument.Name, repoInfo))
                {
                    // 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 unusual to have a document where
                    // document.Name is "foo" and document.ContentStreamFileName is "foo.jpg".
                    string remoteDocumentFileName = remoteDocument.ContentStreamFileName;
                    //Logger.Debug("CrawlRemote doc: " + localFolder + CmisUtils.CMIS_FILE_SEPARATOR + 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);
                        return;
                    }

                    remoteFiles.Add(remoteDocumentFileName);

                    var paths      = remoteDocument.Paths;
                    var pathsCount = paths.Count;
                    var syncItem   = database.GetSyncItemFromRemotePath(remotePath);
                    if (null == syncItem)
                    {
                        syncItem = SyncItemFactory.CreateFromRemotePath(remotePath, repoInfo);
                    }

                    if (syncItem.ExistsLocal())
                    {
                        // Check modification date stored in database and download if remote modification date if different.
                        DateTime?serverSideModificationDate = ((DateTime)remoteDocument.LastModificationDate).ToUniversalTime();
                        DateTime?lastDatabaseUpdate         = database.GetServerSideModificationDate(syncItem);

                        if (lastDatabaseUpdate == null)
                        {
                            Logger.Info("Downloading file absent from database: " + syncItem.LocalPath);
                            activityListener.ActivityStarted();
                            DownloadFile(remoteDocument, remotePath, localFolder);
                            activityListener.ActivityStopped();
                        }
                        else
                        {
                            // If the file has been modified since last time we downloaded it, then download again.
                            if (serverSideModificationDate > lastDatabaseUpdate)
                            {
                                activityListener.ActivityStarted();

                                if (database.LocalFileHasChanged(syncItem.LocalPath))
                                {
                                    Logger.Info("Conflict with file: " + remoteDocumentFileName + ", backing up locally modified version and downloading server version");
                                    Logger.Info("- serverSideModificationDate: " + serverSideModificationDate);
                                    Logger.Info("- lastDatabaseUpdate: " + lastDatabaseUpdate);
                                    Logger.Info("- Checksum in database: " + database.GetChecksum(syncItem.LocalPath));
                                    Logger.Info("- Checksum of local file: " + Database.Database.Checksum(syncItem.LocalPath));

                                    // Rename locally modified file.
                                    String newFilePath = Utils.CreateConflictFilename(syncItem.LocalPath, repoInfo.User);
                                    File.Move(syncItem.LocalPath, newFilePath);

                                    // Download server version
                                    DownloadFile(remoteDocument, remotePath, localFolder);
                                    Logger.Info("- Checksum of remote file: " + Database.Database.Checksum(syncItem.LocalPath));
                                    repo.OnConflictResolved();

                                    // Notify the user.
                                    string lastModifiedBy = CmisUtils.GetProperty(remoteDocument, "cmis:lastModifiedBy");
                                    string message        = String.Format(
                                        // Properties_Resources.ResourceManager.GetString("ModifiedSame", CultureInfo.CurrentCulture),
                                        "User {0} modified file \"{1}\" at the same time as you.",
                                        lastModifiedBy, syncItem.LocalPath)
                                                            + "\n\n"
                                                            // + Properties_Resources.ResourceManager.GetString("YourVersion", CultureInfo.CurrentCulture);
                                                            + "Your version has been saved as \"" + newFilePath + "\", please merge your important changes from it and then delete it.";
                                    Logger.Info(message);
                                    Utils.NotifyUser(message);
                                }
                                else
                                {
                                    Logger.Info("Downloading modified file: " + remoteDocumentFileName);
                                    DownloadFile(remoteDocument, remotePath, localFolder);
                                }

                                activityListener.ActivityStopped();
                            }
                        }
                    }
                    else
                    {
                        // The remote file exists locally.

                        if (database.ContainsFile(syncItem))
                        {
                            // The file used to be present locally (as revealed by the database), but does not exist anymore locally.
                            // So, it must have been deleted locally by the user.
                            // Thus, CmisSync must remove the file from the server too.

                            string message0 = "CmisSync Warning: You have deleted file " + syncItem.LocalPath + "\nCmisSync will now delete it from the server. If you actually did not delete this file, please report a bug at [email protected]";
                            Logger.Info(message0);
                            //Utils.NotifyUser(message0);

                            if ((bool)remoteDocument.IsVersionSeriesCheckedOut)
                            {
                                string message = String.Format("File {0} is checked out on the server by another user: {1}", syncItem.LocalPath, remoteDocument.CheckinComment);
                                Logger.Info(message);
                                Utils.NotifyUser(message);
                            }
                            else
                            {
                                // File has been recently removed locally, so remove it from server too.

                                activityListener.ActivityStarted();
                                Logger.Info("Removing locally deleted file on server: " + syncItem.RemotePath);
                                remoteDocument.DeleteAllVersions();
                                // Remove it from database.
                                database.RemoveFile(syncItem);
                                activityListener.ActivityStopped();
                            }
                        }
                        else
                        {
                            // New remote file, download it.

                            Logger.Info("New remote file: " + syncItem.RemotePath);
                            activityListener.ActivityStarted();
                            DownloadFile(remoteDocument, remotePath, localFolder);
                            activityListener.ActivityStopped();
                        }
                    }
                }
            }
Exemplo n.º 18
0
            /// <summary>
            /// An event was received from the filesystem watcher, analyze the change and apply it.
            /// <returns>Whether the move has now been synchronized, so that no further action is needed</returns>
            /// </summary>
            private bool WatchSyncMove(string remoteFolder, string localFolder, string oldPathname, string newPathname)
            {
                bool success = true;

                SleepWhileSuspended();

                // Old item.
                string   oldDirectory            = Path.GetDirectoryName(oldPathname);
                string   oldFilename             = Path.GetFileName(oldPathname);
                string   oldLocalName            = oldPathname.Substring(localFolder.Length + 1);
                SyncItem oldItem                 = database.GetSyncItemFromLocalPath(oldPathname);
                string   oldRemoteName           = oldItem.RemotePath;
                string   oldRemoteBaseName       = CmisUtils.GetUpperFolderOfCmisPath(oldRemoteName);
                bool     oldPathnameWorthSyncing = Utils.WorthSyncing(oldDirectory, oldFilename, repoInfo);

                // New item.
                bool     isFolder                = Utils.IsFolder(newPathname);
                string   newDirectory            = Path.GetDirectoryName(newPathname); // TODO do this only if isFolder is true, modify rest of the logic accordingly.
                string   newFilename             = Path.GetFileName(newPathname);
                string   newLocalName            = newPathname.Substring(localFolder.Length + 1);
                SyncItem newItem                 = SyncItemFactory.CreateFromLocalPath(newPathname, isFolder, repoInfo, database);
                string   newRemoteName           = newItem.RemotePath;
                string   newRemoteBaseName       = CmisUtils.GetUpperFolderOfCmisPath(newRemoteName);
                bool     newPathnameWorthSyncing = Utils.WorthSyncing(newDirectory, newFilename, repoInfo);

                // Operations.
                bool rename = oldDirectory.Equals(newDirectory) && !oldFilename.Equals(newFilename);
                bool move   = !oldDirectory.Equals(newDirectory) && oldFilename.Equals(newFilename);

                if ((rename && move) || (!rename && !move))
                {
                    Logger.ErrorFormat("Not a valid rename/move: {0} -> {1}", oldPathname, newPathname);
                    return(true); // It is not our problem that watcher data is not valid.
                }
                try
                {
                    if (oldPathnameWorthSyncing && newPathnameWorthSyncing)
                    {
                        if (database.ContainsLocalFile(oldPathname))
                        {
                            if (database.ContainsLocalFile(newPathname))
                            {
                                //database already contains path so revert back to delete/update
                                success &= WatcherSyncDelete(remoteFolder, localFolder, oldPathname);
                                success &= WatcherSyncUpdate(remoteFolder, localFolder, newPathname);
                            }
                            else
                            {
                                if (rename)
                                {
                                    //rename file...
                                    IDocument remoteDocument = (IDocument)session.GetObjectByPath(oldRemoteName);
                                    success &= RenameFile(oldDirectory, newFilename, remoteDocument);
                                }
                                else //move
                                {
                                    //move file...
                                    IDocument remoteDocument  = (IDocument)session.GetObjectByPath(oldRemoteName);
                                    IFolder   oldRemoteFolder = (IFolder)session.GetObjectByPath(oldRemoteBaseName);
                                    IFolder   newRemoteFolder = (IFolder)session.GetObjectByPath(newRemoteBaseName);
                                    success &= MoveFile(oldDirectory, newDirectory, oldRemoteFolder, newRemoteFolder, remoteDocument);
                                }
                            }
                        }
                        else if (database.ContainsFolder(oldPathname))
                        {
                            if (database.ContainsFolder(newPathname))
                            {
                                //database already contains path so revert back to delete/update
                                success &= WatcherSyncDelete(remoteFolder, localFolder, oldPathname);
                                success &= WatcherSyncUpdate(remoteFolder, localFolder, newPathname);
                            }
                            else
                            {
                                if (rename)
                                {
                                    //rename folder...
                                    IFolder remoteFolderObject = (IFolder)session.GetObjectByPath(oldRemoteName);
                                    success &= RenameFolder(oldDirectory, newFilename, remoteFolderObject);
                                }
                                else //move
                                {
                                    //move folder...
                                    IFolder remoteFolderObject = (IFolder)session.GetObjectByPath(oldRemoteName);
                                    IFolder oldRemoteFolder    = (IFolder)session.GetObjectByPath(oldRemoteBaseName);
                                    IFolder newRemoteFolder    = (IFolder)session.GetObjectByPath(newRemoteBaseName);
                                    success &= MoveFolder(oldDirectory, newDirectory, oldRemoteFolder, newRemoteFolder, remoteFolderObject);
                                }
                            }
                        }
                        else
                        {
                            //File/Folder has not been synced before so simply update
                            success &= WatcherSyncUpdate(remoteFolder, localFolder, newPathname);
                        }
                    }
                    else if (oldPathnameWorthSyncing && !newPathnameWorthSyncing)
                    {
                        //New path not worth syncing
                        success &= WatcherSyncDelete(remoteFolder, localFolder, oldPathname);
                    }
                    else if (!oldPathnameWorthSyncing && newPathnameWorthSyncing)
                    {
                        //Old path not worth syncing
                        success &= WatcherSyncUpdate(remoteFolder, localFolder, newPathname);
                    }
                    else
                    {
                        //Neither old or new path worth syncing
                    }
                }
                catch (Exception e)
                {
                    success = false;
                    ProcessRecoverableException("Could process watcher sync move: " + oldPathname + " -> " + newPathname, e);
                }
                return(success);
            }
Exemplo n.º 19
0
            /// <summary>
            /// Sync update.
            /// </summary>
            /// <param name="remoteFolder">Remote folder.</param>
            /// <param name="localFolder">Local folder.</param>
            /// <param name="localPath">Pathname.</param>
            /// <returns>Whether the update has now been synchronized, so that no further action is needed</returns>
            private bool WatcherSyncUpdate(string remoteFolder, string localFolder, string localPath)
            {
                SleepWhileSuspended();
                string localFilename = Path.GetFileName(localPath);

                if (!Utils.WorthSyncing(Path.GetDirectoryName(localPath), localFilename, repoInfo))
                {
                    return(true);
                }
                try
                {
                    string localName = localPath.Substring(localFolder.Length + 1);
                    bool   isFolder  = Utils.IsFolder(localPath);

                    SyncItem item = SyncItemFactory.CreateFromLocalPath(localPath, isFolder, repoInfo, database);

                    // Get the remote directory, needed by the update method.
                    string  remoteName = item.RemotePath;
                    IFolder remoteBase = null;
                    if (File.Exists(localPath) || Directory.Exists(localPath))
                    {
                        string remoteBaseName = CmisUtils.GetUpperFolderOfCmisPath(item.RemotePath);
                        remoteBase = (IFolder)session.GetObjectByPath(remoteBaseName);
                        if (null == remoteBase)
                        {
                            Logger.WarnFormat("The remote base folder {0} for local {1} does not exist, ignore for the update action", remoteBaseName, localPath);
                            return(true); // Ignore is not a failure.
                        }
                    }
                    else
                    {
                        Logger.InfoFormat("The file/folder {0} is deleted, ignore for the update action", localPath);
                        return(true);
                    }

                    // Update the item.
                    if (File.Exists(localPath))
                    {
                        // The item is a file.
                        bool success = false;
                        if (database.ContainsLocalFile(localPath))
                        {
                            if (database.LocalFileHasChanged(localPath))
                            {
                                success = UpdateFile(localPath, remoteBase);
                                Logger.InfoFormat("Update {0}: {1}", localPath, success);
                            }
                            else
                            {
                                success = true;
                                Logger.InfoFormat("File {0} remains unchanged, ignore for the update action", localPath);
                            }
                        }
                        else
                        {
                            success = UploadFile(localPath, remoteBase);
                            Logger.InfoFormat("Upload {0}: {1}", localPath, success);
                        }
                        if (success)
                        {
                            return(true);
                        }
                        else
                        {
                            Logger.WarnFormat("Failure to update: {0}", localPath);
                            return(false);
                        }
                    }
                    if (Directory.Exists(localPath))
                    {
                        // The item is a folder.
                        bool success = true;
                        if (database.ContainsFolder(localPath))
                        {
                            Logger.InfoFormat("Folder exists in Database {0}, ignore for the update action", localPath);
                        }
                        else
                        {
                            Logger.InfoFormat("Create locally created folder on server: {0}", localPath);
                            success &= UploadFolderRecursively(remoteBase, localPath);
                        }
                        return(success);
                    }
                    Logger.InfoFormat("The file/folder {0} is deleted, ignore for the update action", localPath);
                }
                catch (Exception e)
                {
                    ProcessRecoverableException("Could process watcher sync update: " + localPath, e);
                    return(false);
                }
                return(true);
            }
            /// <summary>
            /// Apply: Deleted folders.
            /// </summary>
            public bool ApplyDeletedFolders(ref List <string> deletedFolders)
            {
                bool success = true;

                foreach (string deletedFolder in deletedFolders)
                {
                    SyncItem deletedItem = SyncItemFactory.CreateFromLocalPath(deletedFolder, true, repoInfo, database);
                    try
                    {
                        var deletedIFolder = session.GetObjectByPath(deletedItem.RemotePath, true) as IFolder;

                        // Check whether the remote folder has changes we haven't gotten yet (conflict)
                        var changed = HasFolderChanged(deletedIFolder);

                        // Delete the remote folder if unchanged, otherwise let full sync handle the conflict.
                        var remotePath    = deletedItem.RemotePath;
                        var localPath     = deletedItem.LocalPath;
                        var remoteFolders = new List <string>();

                        if (changed)
                        {
                            // TODO: Internationalization
                            string message = String.Format("Restoring folder {0} because its sub-items have been modified on the server. You can delete it again.", localPath);
                            Utils.NotifyUser(message);

                            // TODO: Handle folder conflict
                            // Delete local database entry.
                            database.RemoveFolder(SyncItemFactory.CreateFromLocalPath(deletedFolder, true, repoInfo, database));

                            DownloadDirectory(deletedIFolder, remotePath, localPath);

                            return(false);
                        }
                        else
                        {
                            DeleteRemoteFolder(deletedIFolder, deletedItem, Utils.UpperFolderLocal(deletedItem.LocalPath));
                        }
                    }
                    catch (Exception e)
                    {
                        if (e is ArgumentNullException || e is CmisObjectNotFoundException)
                        {
                            // Typical error when the document does not exist anymore on the server
                            // TODO Make DotCMIS generate a more precise exception.

                            Logger.Error("The folder has probably been deleted on the server already: " + deletedFolder, e);

                            // Delete local database entry.
                            database.RemoveFolder(SyncItemFactory.CreateFromLocalPath(deletedFolder, true, repoInfo, database));

                            // Note: This is not a failure per-se, so we don't need to modify the "success" variable.
                        }
                        else
                        {
                            Logger.Error("Error applying local folder deletion to the server: " + deletedFolder, e);
                            success = false;
                        }
                    }
                }
                return(success);
            }
Exemplo n.º 21
0
            /// <summary>
            /// Watchers the sync delete.
            /// </summary>
            /// <param name="remoteFolder">Remote folder.</param>
            /// <param name="localFolder">Local folder.</param>
            /// <param name="pathname">Pathname.</param>
            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(SyncItemFactory.CreateFromLocalPath(pathname, repoinfo))) // FIXME remote or local?
                    {
                        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(SyncItemFactory.CreateFromLocalPath(pathname, repoinfo));
                    }
                    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(SyncItemFactory.CreateFromLocalPath(pathname, repoinfo));
                    }
                    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;
            }
Exemplo n.º 22
0
            /// <summary>
            /// Apply a remote change for Created or Updated.
            /// </summary>
            private bool ApplyRemoteChangeUpdate(IChangeEvent change)
            {
                ICmisObject cmisObject     = null;
                IFolder     remoteFolder   = null;
                IDocument   remoteDocument = null;
                string      remotePath     = null;
                ICmisObject remoteObject   = null;
                IFolder     remoteParent   = null;

                try
                {
                    cmisObject = session.GetObject(change.ObjectId);
                }
                catch (CmisObjectNotFoundException)
                {
                    Logger.Info("Ignore the missed object for " + change.ObjectId);
                    return(true);
                }
                catch (Exception e)
                {
                    Logger.Warn("Exception when GetObject for " + change.ObjectId + " :", e);
                    return(false);
                }

                remoteDocument = cmisObject as IDocument;
                remoteFolder   = cmisObject as IFolder;
                if (remoteDocument == null && remoteFolder == null)
                {
                    Logger.Info("Change in no sync object: " + change.ObjectId);
                    return(true);
                }
                if (remoteDocument != null)
                {
                    if (!Utils.IsFileWorthSyncing(remoteDocument.Name, repoinfo))
                    {
                        Logger.Info("Change in remote unworth syncing file: " + remoteDocument.Paths);
                        return(true);
                    }
                    if (remoteDocument.Paths.Count == 0)
                    {
                        Logger.Info("Ignore the unfiled object: " + remoteDocument.Name);
                        return(true);
                    }
                    // TODO: Support Multiple Paths
                    remotePath   = remoteDocument.Paths[0];
                    remoteParent = remoteDocument.Parents[0];
                }
                if (remoteFolder != null)
                {
                    remotePath   = remoteFolder.Path;
                    remoteParent = remoteFolder.FolderParent;
                    foreach (string name in remotePath.Split('/'))
                    {
                        if (!String.IsNullOrEmpty(name) && Utils.IsInvalidFolderName(name))
                        {
                            Logger.Info(String.Format("Change in illegal syncing path name {0}: {1}", name, remotePath));
                            return(true);
                        }
                    }
                }

                if (!remotePath.StartsWith(this.remoteFolderPath))
                {
                    Logger.Info("Change in unrelated path: " + remotePath);
                    return(true);    // The change is not under the folder we care about.
                }

                if (this.repoinfo.isPathIgnored(remotePath))
                {
                    Logger.Info("Change in ignored path: " + remotePath);
                    return(true);
                }

                string relativePath = remotePath.Substring(remoteFolderPath.Length);

                if (relativePath.Length <= 0)
                {
                    Logger.Info("Ignore change in root path: " + remotePath);
                    return(true);
                }
                if (relativePath[0] == '/')
                {
                    relativePath = relativePath.Substring(1);
                }

                try
                {
                    remoteObject = session.GetObjectByPath(remotePath);
                }
                catch (CmisObjectNotFoundException)
                {
                    Logger.Info(String.Format("Ignore remote path {0} deleted from id {1}", remotePath, cmisObject.Id));
                    return(true);
                }
                catch (Exception e)
                {
                    Logger.Warn("Exception when GetObject for " + remotePath + " : ", e);
                    return(false);
                }

                if (remoteObject.Id != cmisObject.Id)
                {
                    Logger.Info(String.Format("Ignore remote path {0} changed from id {1} to id {2}", remotePath, cmisObject.Id, remoteObject.Id));
                    return(true);
                }

                string localPath = Path.Combine(repoinfo.TargetDirectory, relativePath).Replace('/', Path.DirectorySeparatorChar);

                if (!DownloadFolder(remoteParent, Path.GetDirectoryName(localPath)))
                {
                    Logger.Warn("Failed to download the parent folder for " + localPath);
                    return(false);
                }

                if (null != remoteDocument)
                {
                    Logger.Info(String.Format("New remote file ({0}) found.", remotePath));
                    //  check moveObject
                    string savedDocumentPath = database.GetRemoteFilePath(change.ObjectId);
                    if ((null != savedDocumentPath) && (savedDocumentPath != localPath))
                    {
                        if (File.Exists(localPath))
                        {
                            File.Delete(savedDocumentPath);
                            database.RemoveFile(SyncItemFactory.CreateFromRemotePath(savedDocumentPath, repoinfo));
                        }
                        else
                        {
                            if (File.Exists(savedDocumentPath))
                            {
                                if (!Directory.Exists(Path.GetDirectoryName(localPath)))
                                {
                                    Logger.Warn("Creating local directory: " + localPath);
                                    Directory.CreateDirectory(Path.GetDirectoryName(localPath));
                                }
                                File.Move(savedDocumentPath, localPath);
                            }
                            database.MoveFile(SyncItemFactory.CreateFromRemotePath(savedDocumentPath, repoinfo), SyncItemFactory.CreateFromLocalPath(savedDocumentPath, repoinfo));
                        }
                    }

                    return(SyncDownloadFile(remoteDocument, Path.GetDirectoryName(localPath)));
                }

                if (null != remoteFolder)
                {
                    Logger.Info(String.Format("New remote folder ({0}) found.", remotePath));
                    //  check moveObject
                    string savedFolderPath = database.GetFolderPath(change.ObjectId);
                    if ((null != savedFolderPath) && (savedFolderPath != localPath))
                    {
// TODO                        MoveFolderLocally(savedFolderPath, localPath);
                        CrawlSync(remoteFolder, localPath);
                    }
                    else
                    {
                        SyncDownloadFolder(remoteFolder, Path.GetDirectoryName(localPath));
                        CrawlSync(remoteFolder, localPath);
                    }
                }

                return(true);
            }
Exemplo n.º 23
0
            /// <summary>
            /// Sync move file.
            /// </summary>
            private void WatchSyncMove(string remoteFolder, string localFolder, string oldPathname, string newPathname)
            {
                SleepWhileSuspended();
                string oldDirectory            = Path.GetDirectoryName(oldPathname);
                string oldFilename             = Path.GetFileName(oldPathname);
                string oldLocalName            = oldPathname.Substring(localFolder.Length + 1);
                string oldRemoteName           = Path.Combine(remoteFolder, oldLocalName).Replace('\\', '/'); // FIXME
                string oldRemoteBaseName       = Path.GetDirectoryName(oldRemoteName).Replace('\\', '/');
                bool   oldPathnameWorthSyncing = Utils.WorthSyncing(oldDirectory, oldFilename, repoinfo);
                string newDirectory            = Path.GetDirectoryName(newPathname);
                string newFilename             = Path.GetFileName(newPathname);
                string newLocalName            = newPathname.Substring(localFolder.Length + 1);
                string newRemoteName           = Path.Combine(remoteFolder, newLocalName).Replace('\\', '/');
                string newRemoteBaseName       = Path.GetDirectoryName(newRemoteName).Replace('\\', '/');
                bool   newPathnameWorthSyncing = Utils.WorthSyncing(newDirectory, newFilename, repoinfo);
                bool   rename = oldDirectory.Equals(newDirectory) && !oldFilename.Equals(newFilename);
                bool   move   = !oldDirectory.Equals(newDirectory) && oldFilename.Equals(newFilename);

                if ((rename && move) || (!rename && !move))
                {
                    Logger.ErrorFormat("Not a valid rename/move: {0} -> {1}", oldPathname, newPathname);
                    return;
                }
                try
                {
                    if (oldPathnameWorthSyncing && newPathnameWorthSyncing)
                    {
                        if (database.ContainsFile(SyncItemFactory.CreateFromLocalPath(oldPathname, repoinfo)))
                        {
                            if (database.ContainsFile(SyncItemFactory.CreateFromLocalPath(newPathname, repoinfo)))
                            {
                                //database already contains path so revert back to delete/update
                                WatcherSyncDelete(remoteFolder, localFolder, oldPathname);
                                WatcherSyncUpdate(remoteFolder, localFolder, newPathname);
                            }
                            else
                            {
                                if (rename)
                                {
                                    //rename file...
                                    IDocument remoteDocument = (IDocument)session.GetObjectByPath(oldRemoteName);
                                    RenameFile(oldDirectory, newFilename, remoteDocument);
                                }
                                else //move
                                {
                                    //move file...
                                    IDocument remoteDocument  = (IDocument)session.GetObjectByPath(oldRemoteName);
                                    IFolder   oldRemoteFolder = (IFolder)session.GetObjectByPath(oldRemoteBaseName);
                                    IFolder   newRemoteFolder = (IFolder)session.GetObjectByPath(newRemoteBaseName);
                                    MoveFile(oldDirectory, newDirectory, oldRemoteFolder, newRemoteFolder, remoteDocument);
                                }
                            }
                        }
                        else if (database.ContainsFolder(oldPathname))
                        {
                            if (database.ContainsFolder(newPathname))
                            {
                                //database already contains path so revert back to delete/update
                                WatcherSyncDelete(remoteFolder, localFolder, oldPathname);
                                WatcherSyncUpdate(remoteFolder, localFolder, newPathname);
                            }
                            else
                            {
                                if (rename)
                                {
                                    //rename folder...
                                    IFolder remoteFolderObject = (IFolder)session.GetObjectByPath(oldRemoteName);
                                    RenameFolder(oldDirectory, newFilename, remoteFolderObject);
                                }
                                else //move
                                {
                                    //move folder...
                                    IFolder remoteFolderObject = (IFolder)session.GetObjectByPath(oldRemoteName);
                                    IFolder oldRemoteFolder    = (IFolder)session.GetObjectByPath(oldRemoteBaseName);
                                    IFolder newRemoteFolder    = (IFolder)session.GetObjectByPath(newRemoteBaseName);
                                    MoveFolder(oldDirectory, newDirectory, oldRemoteFolder, newRemoteFolder, remoteFolderObject);
                                }
                            }
                        }
                        else
                        {
                            //File/Folder has not been synced before so simply update
                            WatcherSyncUpdate(remoteFolder, localFolder, newPathname);
                        }
                    }
                    else if (oldPathnameWorthSyncing && !newPathnameWorthSyncing)
                    {
                        //New path not worth syncing
                        WatcherSyncDelete(remoteFolder, localFolder, oldPathname);
                    }
                    else if (!oldPathnameWorthSyncing && newPathnameWorthSyncing)
                    {
                        //Old path not worth syncing
                        WatcherSyncUpdate(remoteFolder, localFolder, newPathname);
                    }
                    else
                    {
                        //Neither old or new path worth syncing
                    }
                }
                catch (Exception e)
                {
                    ProcessRecoverableException("Could process watcher sync move: " + oldPathname + " -> " + newPathname, e);
                }
            }
Exemplo n.º 24
0
            /// <summary>
            /// Check whether a change is relevant for the current synchronized folder.
            /// </summary>

            /*private bool ChangeIsApplicable(IChangeEvent change)
             * {
             *  ICmisObject cmisObject = null;
             *  IFolder remoteFolder = null;
             *  IDocument remoteDocument = null;
             *  IList<string> remotePaths = null;
             *  var changeIdForDebug = change.Properties.ContainsKey("cmis:name") ?
             *      change.Properties["cmis:name"][0] : change.Properties["cmis:objectId"][0]; // TODO is it different from change.ObjectId ?
             *
             *  // Get the remote changed object.
             *  try
             *  {
             *      cmisObject = session.GetObject(change.ObjectId);
             *  }
             *  catch (CmisObjectNotFoundException)
             *  {
             *      Logger.Info("Changed object has already been deleted on the server. Syncing just in case: " + changeIdForDebug);
             *      // Unfortunately, in this case we can not know whether the object was relevant or not.
             *      return true;
             *  }
             *  catch (CmisRuntimeException e)
             *  {
             *      if (e.Message.Equals("Unauthorized"))
             *      {
             *          Logger.Info("We can not read the object id, so it is not an object we can sync anyway: " + changeIdForDebug);
             *          return false;
             *      }
             *      else
             *      {
             *          Logger.Info("A CMIS exception occured when querying the change. Syncing just in case: " + changeIdForDebug + " :", e);
             *          return true;
             *      }
             *
             *  }
             *  catch (CmisPermissionDeniedException e)
             *  {
             *      Logger.Info("Permission denied object  : " + changeIdForDebug + " :", e);
             *      return false;
             *  }
             *  catch (Exception e)
             *  {
             *      Logger.Warn("An exception occurred, syncing just in case: " + changeIdForDebug + " :", e);
             *      return true;
             *  }
             *
             *  // Check whether change is about a document or folder.
             *  remoteDocument = cmisObject as IDocument;
             *  remoteFolder = cmisObject as IFolder;
             *  if (remoteDocument == null && remoteFolder == null)
             *  {
             *      Logger.Info("Ignore change as it is not about a document nor folder: " + changeIdForDebug);
             *      return false;
             *  }
             *
             *  // Check whether it is a document worth syncing.
             *  if (remoteDocument != null)
             *  {
             *      if (!Utils.IsFileWorthSyncing(repoInfo.CmisProfile.localFilename(remoteDocument), repoInfo))
             *      {
             *          Logger.Info("Ignore change as it is about a document unworth syncing: " + changeIdForDebug);
             *          return false;
             *      }
             *      if (remoteDocument.Paths.Count == 0)
             *      {
             *          Logger.Info("Ignore the unfiled object: " + changeIdForDebug);
             *          return false;
             *      }
             *
             *      // We will check the remote document's path(s) at the end of this method.
             *      remotePaths = remoteDocument.Paths;
             *  }
             *
             *  // Check whether it is a folder worth syncing.
             *  if (remoteFolder != null)
             *  {
             *      remotePaths = new List<string>();
             *      remotePaths.Add(remoteFolder.Path);
             *  }
             *
             *  // Check the object's path(s)
             *  foreach (string remotePath in remotePaths)
             *  {
             *      if (PathIsApplicable(remotePath))
             *      {
             *          Logger.Debug("Change is applicable. Sync:" + changeIdForDebug);
             *          return true;
             *      }
             *  }
             *
             *  // No path was relevant, so ignore the change.
             *  return false;
             * }*/


            /// <summary>
            /// Apply CMIS ChangeLog changes.
            /// </summary>
            private void CrawlChangeLogSyncAndUpdateChangeLogToken(IList <IChangeEvent> changeLogs, IFolder remoteFolder, string remotePath, string localFolder)
            {
                SleepWhileSuspended();

                var sw = new System.Diagnostics.Stopwatch();

                activityListener.ActivityStarted();
                try
                {
                    sw.Start();
                    Logger.InfoFormat("Change log sync start : {0} logs", changeLogs.Count());

                    // TODO: Compact changelogs

                    foreach (var change in changeLogs)
                    {
                        var id = change.ObjectId;
                        try
                        {
                            Logger.InfoFormat("Change log : Type={0}, Name={1}, Id={2}", change.ChangeType, change.Properties["cmis:name"].First(), id);
                        }
                        catch
                        {
                            Logger.InfoFormat("Change log : Type={0}, Id={1} ", change.ChangeType, id);
                        }

                        try
                        {
                            var cmisObject = session.GetObject(id);
                            CrawlCmisObject(cmisObject);
                        }
                        catch (CmisObjectNotFoundException ex)
                        {
                            if (change.ChangeType == ChangeType.Deleted)
                            {
                                var local = database.GetSyncItem(id);
                                if (local != null)
                                {
                                    var destFolderPath = Path.GetDirectoryName(local.LocalPath);
                                    var destFolderItem = SyncItemFactory.CreateFromLocalPath(destFolderPath, true, repoInfo, database);

                                    try
                                    {
                                        var destCmisFolder = session.GetObjectByPath(destFolderItem.RemotePath) as IFolder;

                                        if (local.IsFolder)
                                        {
                                            CrawlSync(destCmisFolder, destFolderItem.RemotePath, destFolderItem.LocalPath);
                                        }
                                        else
                                        {
                                            CheckLocalFile(local.LocalPath, destCmisFolder, new List <string>());
                                        }
                                    }
                                    catch (Exception e)
                                    {
                                        if (e is ArgumentNullException || e is CmisObjectNotFoundException)
                                        {
                                            // GetObjectByPath failure
                                            Logger.InfoFormat("Remote parent object not found, ignore. {0}", destFolderItem.RemotePath);
                                        }
                                        else
                                        {
                                            throw;
                                        }
                                    }
                                }
                                else
                                {
                                    Logger.InfoFormat("Remote deleted object not in local database, ignore. {0}", id);
                                }
                            }
                            else
                            {
                                Logger.InfoFormat("Remote object not found but delete event, ignore. {0}", id);
                            }
                        }
                        catch (Exception ex)
                        {
                            Logger.Debug(ex);
                        }
                    }

                    sw.Stop();
                    Logger.InfoFormat("Change log sync end : {1} min / {0} logs", changeLogs.Count(), sw.Elapsed);
                }
                finally
                {
                    activityListener.ActivityStopped();
                }
            }
Exemplo n.º 25
0
            private bool CrawlSyncQuery(IFolder remoteFolder, string remoteFolderPath, string localFolder)
            {
                bool success = true;

                try
                {
                    //IList<string> remoteFolders = new List<string>();

                    //IList<string> localFolders = database.getfoldersId();

                    IList <string> qFolders = queryAddedAndModifiedFolders(remoteFolder);


                    // Folders
                    foreach (string fId in qFolders)
                    {
                        try
                        {
                            IFolder folder = session.GetObject(fId) as IFolder;

                            SyncItem newFolderItem = SyncItemFactory.CreateFromRemoteFolder(folder.Path, repoInfo, database);

                            // Check if the folder already exists
                            IList <SyncItem> localfolders = database.GetAllFoldersWithCmisId(fId);
                            if (localfolders != null)
                            {
                                foreach (SyncItem oldFolderItem in localfolders)
                                {
                                    // if directory did not exists -> Move
                                    if (!Directory.Exists(newFolderItem.LocalPath))
                                    {
                                        //Directory.CreateDirectory(newFolderItem.LocalPath);
                                        //Directory.Delete(newFolderItem.LocalPath);
                                        Directory.Move(oldFolderItem.LocalPath, newFolderItem.LocalPath);
                                        database.MoveFolder(oldFolderItem, newFolderItem);
                                        //var test = database.getMetadataInfo();
                                    }

                                    /*
                                     * else
                                     * {
                                     *  // Directory already exists, move content of the old folder and update database
                                     *
                                     *
                                     *  // Files
                                     *  foreach (string filePath in Directory.GetFiles(oldFolderItem.LocalPath))
                                     *  {
                                     *      string fileName = Path.GetFileName(filePath);
                                     *      string newFilePath = Path.Combine(newFolderItem.LocalPath, fileName);
                                     *
                                     *      File.Move(filePath, newFilePath);
                                     *      SyncItem oldFileItem = database.GetSyncItemFromLocalPath(filePath);
                                     *      if (oldFileItem == null)
                                     *          oldFileItem = SyncItemFactory.CreateFromLocalPath(filePath, false, repoInfo, database);
                                     *
                                     *      SyncItem newFileItem = SyncItemFactory.CreateFromLocalPath(newFilePath, false, repoInfo, database);
                                     *
                                     *      if (Utils.IsMetadataFile(newFilePath))
                                     *      {
                                     *          database.MoveMetadataFile(oldFileItem, newFileItem, newFileItem.LocalPath + ".metadata");
                                     *      }
                                     *      else
                                     *      {
                                     *          database.MoveFile(oldFileItem, newFileItem);
                                     *      }
                                     *  }
                                     */
                                }
                            }
                            Directory.CreateDirectory(newFolderItem.LocalPath);
                        }
                        catch (CmisBaseException e)
                        {
                            ProcessRecoverableException("Could not access remote folder : ", e);
                            success = false;
                        }
                    }

                    IList <string> qDocs = queryAddedAndModifiedFiles(remoteFolder);

                    IList <string> remoteFiles = new List <string>();
                    // Files
                    foreach (string docId in qDocs)
                    {
                        try
                        {
                            IDocument doc = session.GetObject(docId) as IDocument;

                            SyncItem syncItem = SyncItemFactory.CreateFromRemoteDocument(doc.Paths[0], doc, repoInfo, database);

                            // Check if the file already exists
                            string id       = docId.Remove(docId.IndexOf(';'));
                            string filePath = database.GetFilePath(id);
                            if (filePath != null)
                            {
                                // File already exists, delete
                                File.Delete(filePath);
                                SyncItem si = database.GetSyncItemFromLocalPath(filePath);
                                database.RemoveFile(si);

                                // Delete Metadata
                                if (database.ContainsLocalMetadata(filePath + ".metadata"))
                                {
                                    File.Delete(filePath + ".metadata");
                                    database.RemoveMetadataFile(si);
                                }
                            }
                            CrawlRemoteDocument(doc, syncItem.RemotePath, syncItem.LocalPath, remoteFiles);
                        }
                        catch (CmisBaseException e)
                        {
                            ProcessRecoverableException("Could not access remote document : ", e);
                            success = false;
                        }
                    }
                    database.setLastSyncDate(DateTimeOffset.Now.ToString("O"));
                }
                catch (CmisBaseException e)
                {
                    ProcessRecoverableException("Could not access remote objects: ", e);
                    success = false;
                }
                catch (Exception e)
                {
                    Logger.Error("Error in CrawlSyncQuery", e);
                    success = false;
                }
                return(success);
            }
Exemplo n.º 26
0
            /// <summary>
            /// Check a particular local folder (not recursive).
            /// See whether it has been deleted locally or not.
            /// </summary>
            private void CheckLocalFolder(string localSubFolder, IFolder remoteRoot, IList <string> remoteFolders)
            {
                SleepWhileSuspended();
                try
                {
                    if (Utils.IsSymlink(new DirectoryInfo(localSubFolder)))
                    {
                        Logger.Info("Skipping symbolic link folder: " + localSubFolder);
                        return;
                    }

                    string folderName = Path.GetFileName(localSubFolder);

                    if (Utils.WorthSyncing(Path.GetDirectoryName(localSubFolder), folderName, repoInfo))
                    {
                        var syncFolderItem = database.GetFolderSyncItemFromLocalPath(localSubFolder);
                        if (null == syncFolderItem)
                        {
                            // The local item is not in database. It has not been uploaded yet.
                            syncFolderItem = SyncItemFactory.CreateFromLocalPath(localSubFolder, true, repoInfo, database);
                        }

                        if (remoteFolders.Contains(syncFolderItem.RemoteLeafname))
                        {
                            // The same folder exists locally and remotely.
                            // Are they synchronized, or were they just created (or moved) at the same time?
                            if (database.ContainsFolder(syncFolderItem))
                            {
                                // Check modification dates of local folder and remote folder.
                                // TODO
                            }
                            else
                            {
                                // The folder just appeared both on the local and remote sides.
                                // Rename local folder then download remote folder.

                                IFolder remoteFolder = (IFolder)session.GetObjectByPath(syncFolderItem.RemotePath);

                                var path    = syncFolderItem.LocalPath;
                                var newPath = Utils.CreateConflictFoldername(path, repoInfo.User);

                                Directory.Move(path, newPath);

                                // Delete file from database.
                                database.RemoveFile(syncFolderItem);

                                repo.OnConflictResolved();

                                // Download folder from server.
                                DownloadDirectory(remoteFolder, syncFolderItem.RemotePath, path);
                            }
                        }
                        else
                        {
                            // This local folder is not on the CMIS server now, so
                            // check whether it used to exist on server or not.
                            if (database.ContainsFolder(syncFolderItem))
                            {
                                activityListener.ActivityStarted();
                                RemoveFolderLocally(localSubFolder);
                                activityListener.ActivityStopped();
                            }
                            else
                            {
                                // New local folder, upload recursively.
                                activityListener.ActivityStarted();
                                UploadFolderRecursively(remoteRoot, localSubFolder);
                                activityListener.ActivityStopped();
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    ProcessRecoverableException("Could not crawl sync local folder: " + localSubFolder, e);
                }
            }
Exemplo n.º 27
0
            /// <summary>
            /// Check remote document, syncing down if needed.
            /// Meanwhile, cache remoteFiles, they are output parameters that are used in CrawlLocalFiles/CrawlLocalFolders
            /// </summary>
            private void CrawlRemoteDocument(IDocument remoteDocument, string remotePath, string localFolder, IList <string> remoteFiles)
            {
                SleepWhileSuspended();

                if (Utils.WorthSyncing(localFolder, repoInfo.CmisProfile.localFilename(remoteDocument), repoInfo))
                {
                    // 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 unusual to have a document where
                    // document.Name is "foo" and document.ContentStreamFileName is "foo.jpg".
                    string remoteDocumentFileName = repoInfo.CmisProfile.localFilename(remoteDocument);
                    //Logger.Debug("CrawlRemote doc: " + localFolder + CmisUtils.CMIS_FILE_SEPARATOR + 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 '" + repoInfo.CmisProfile.localFilename(remoteDocument) + "' with null content stream in " + localFolder);
                        return;
                    }

                    if (remoteFiles != null)
                    {
                        remoteFiles.Add(remoteDocumentFileName);
                    }

                    var paths      = remoteDocument.Paths;
                    var pathsCount = paths.Count;
                    var syncItem   = database.GetSyncItemFromRemotePath(remotePath);
                    if (null == syncItem)
                    {
                        syncItem = SyncItemFactory.CreateFromRemoteDocument(remotePath, repoInfo.CmisProfile.localFilename(remoteDocument), repoInfo, database);
                    }

                    // Get HashCodes from the server
                    string hashDoc      = remoteDocument.GetPropertyValue("sy:hashDoc") as string;
                    string hashMetadata = remoteDocument.GetPropertyValue("sy:hashDoc") as string;

                    if (syncItem.FileExistsLocal())
                    {
                        // Check modification date stored in database and download if remote modification date if different.
                        DateTime?serverSideModificationDate = ((DateTime)remoteDocument.LastModificationDate).ToUniversalTime();
                        DateTime?lastDatabaseUpdate         = database.GetServerSideModificationDate(syncItem);

                        if (lastDatabaseUpdate == null)
                        {
                            Logger.Info("Downloading file absent from database: " + syncItem.LocalPath);
                            activityListener.ActivityStarted();
                            DownloadFile(remoteDocument, remotePath, localFolder);
                            activityListener.ActivityStopped();
                        }
                        else
                        {
                            // If the file has been modified since last time we downloaded it, then download again.
                            if (serverSideModificationDate > lastDatabaseUpdate)
                            {
                                activityListener.ActivityStarted();

                                if (database.LocalFileHasChanged(syncItem.LocalPath))
                                {
                                    Logger.Info("Conflict with file: " + remoteDocumentFileName + ", backing up locally modified version and downloading server version");
                                    Logger.Info("- serverSideModificationDate: " + serverSideModificationDate);
                                    Logger.Info("- lastDatabaseUpdate: " + lastDatabaseUpdate);
                                    Logger.Info("- Checksum in database: " + database.GetFileChecksum(syncItem.LocalPath));
                                    Logger.Info("- Checksum of local file: " + Database.Database.Checksum(syncItem.LocalPath));

                                    // Rename locally modified file.
                                    String newFilePath = Utils.CreateConflictFilename(syncItem.LocalPath, repoInfo.User);
                                    File.Move(syncItem.LocalPath, newFilePath);

                                    // Download server version
                                    DownloadFile(remoteDocument, remotePath, localFolder);
                                    Logger.Info("- Checksum of remote file: " + Database.Database.Checksum(syncItem.LocalPath));
                                    repo.OnConflictResolved();

                                    // Notify the user.
                                    string lastModifiedBy = CmisUtils.GetProperty(remoteDocument, "cmis:lastModifiedBy");
                                    string message        = String.Format(
                                        // Properties_Resources.ResourceManager.GetString("ModifiedSame", CultureInfo.CurrentCulture),
                                        "User {0} modified file \"{1}\" at the same time as you.",
                                        lastModifiedBy, syncItem.LocalPath)
                                                            + "\n\n"
                                                            // + Properties_Resources.ResourceManager.GetString("YourVersion", CultureInfo.CurrentCulture);
                                                            + "Your version has been saved as \"" + newFilePath + "\", please merge your important changes from it and then delete it.";
                                    Logger.Info(message);
                                    Utils.NotifyUser(message);
                                }
                                else
                                {
                                    if (database.GetFileChecksum(syncItem.LocalPath) != hashDoc || hashDoc == null)
                                    {
                                        Logger.Info("Downloading modified file: " + remoteDocumentFileName);
                                        DownloadFile(remoteDocument, remotePath, localFolder);
                                    }
                                    else
                                    {
                                        // Only the metadatas have changed
                                        Logger.Info("Updating modified remote metadata: " + remoteDocumentFileName);
                                        CreateMetadataFile(syncItem);
                                        database.SetFileServerSideModificationDate(syncItem, serverSideModificationDate);
                                    }
                                }

                                activityListener.ActivityStopped();
                            }
                        }
                    }
                    else
                    {
                        // The remote file does not exist on the local filesystem.

                        // Maybe the whole synchronized folder has disappeared?
                        // While rare for normal filesystems, that happens rather often with mounted folders (for instance encrypted folders)
                        // In such a case, we should abort this synchronization rather than delete the remote file.
                        if (!Directory.Exists(repoInfo.TargetDirectory))
                        {
                            throw new Exception("Local target directory has disappeared: " + repoInfo.TargetDirectory + " , aborting synchronization");
                        }

                        if (database.ContainsLocalFile(syncItem.LocalRelativePath))
                        {
                            // The file used to be present locally (as revealed by the database), but does not exist anymore locally.
                            // So, it must have been deleted locally by the user.
                            // Thus, CmisSync must remove the file from the server too.

                            DeleteRemoteDocument(remoteDocument, syncItem);
                        }
                        else
                        {
                            // Maybe the file has been renamed
                            // Check if a file in the local folder with the remote document id exists
                            string id       = Utils.RemoveVersion(remoteDocument.Id);
                            string filePath = database.GetFilePath(id);
                            if (filePath != null)
                            {
                                // File has been moved
                                SyncItem oldSynctItem = database.GetSyncItem(id);
                                string   metadataFile = filePath + ".metadata";

                                if (database.GetFileChecksum(syncItem.LocalPath) != hashDoc || hashDoc == null)
                                {
                                    // New content, so delete the old and download the new
                                    File.Delete(filePath);
                                    database.RemoveFile(oldSynctItem);
                                    if (metadataFile != null)
                                    {
                                        File.Delete(metadataFile);
                                        database.RemoveMetadataFile(oldSynctItem);
                                    }
                                    // New remote file, download it.
                                    Logger.Info("New remote file: " + syncItem.RemotePath);
                                    activityListener.ActivityStarted();
                                    DownloadFile(remoteDocument, remotePath, localFolder);
                                    activityListener.ActivityStopped();
                                }
                                else
                                {
                                    // File content has not change, just move it locally
                                    File.Move(filePath, syncItem.LocalPath);
                                    database.MoveFile(oldSynctItem, syncItem);

                                    // Update Metadatas
                                    File.Delete(metadataFile);
                                    database.RemoveMetadataFile(oldSynctItem);
                                    CreateMetadataFile(syncItem);
                                }
                            }
                        }
                        // New remote file, download it.
                        Logger.Info("New remote file: " + syncItem.RemotePath);
                        activityListener.ActivityStarted();
                        DownloadFile(remoteDocument, remotePath, localFolder);
                        activityListener.ActivityStopped();
                    }
                }
            }
Exemplo n.º 28
0
            /// <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.Info("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.CreateFromRemoteFolder(remoteSubFolder.Path, repoInfo, database);
                        }

                        // Check whether local folder exists.
                        if (Directory.Exists(subFolderItem.LocalPath))
                        {
                            try
                            {
                                activityListener.ActivityStarted();
                                // Recurse into folder.
                                CrawlSync(remoteSubFolder, remotePath, subFolderItem.LocalPath);
                            }
                            finally
                            {
                                activityListener.ActivityStopped();
                            }
                        }
                        else
                        {
                            // Maybe the whole synchronized folder has disappeared?
                            // While rare for normal filesystems, that happens rather often with mounted folders (for instance encrypted folders)
                            // In such a case, we should abort this synchronization rather than delete the remote subfolder.
                            if (!Directory.Exists(repoInfo.TargetDirectory))
                            {
                                throw new Exception("Local folder has disappeared: " + repoInfo.TargetDirectory + " , aborting synchronization");
                            }

                            // If there was previously a file with this name, delete it.
                            // TODO warn if local changes in the file.
                            if (File.Exists(subFolderItem.LocalPath))
                            {
                                try
                                {
                                    activityListener.ActivityStarted();
                                    Utils.DeleteEvenIfReadOnly(subFolderItem.LocalPath);
                                }
                                finally
                                {
                                    activityListener.ActivityStopped();
                                }
                            }

                            if (database.ContainsFolder(subFolderItem))
                            {
                                try
                                {
                                    activityListener.ActivityStarted();

                                    // If there was previously a folder with this name, it means that
                                    // the user has deleted it voluntarily, so delete it from server too.

                                    DeleteRemoteFolder(remoteSubFolder, subFolderItem, remotePath);
                                }
                                finally
                                {
                                    activityListener.ActivityStopped();
                                }
                            }
                            else
                            {
                                try
                                {
                                    // Maybe the folder has been renamed
                                    // Check the id
                                    List <SyncItem> oldSyncItems = database.GetAllFoldersWithCmisId(remoteSubFolder.Id);
                                    if (oldSyncItems != null)
                                    {
                                        foreach (SyncItem item in oldSyncItems)
                                        {
                                            RemoveFolderLocally(item.LocalPath);
                                        }
                                    }

                                    // 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);
                                }
                                finally
                                {
                                    activityListener.ActivityStopped();
                                }
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    activityListener.ActivityStopped();
                    ProcessRecoverableException("Could not crawl sync remote folder: " + remoteSubFolder.Path, e);
                }
            }
Exemplo n.º 29
0
            /// <summary>
            /// Sync update.
            /// </summary>
            /// <param name="remoteFolder">Remote folder.</param>
            /// <param name="localFolder">Local folder.</param>
            /// <param name="pathname">Pathname.</param>
            private bool WatcherSyncUpdate(string remoteFolder, string localFolder, string pathname)
            {
                SleepWhileSuspended();
                string filename = Path.GetFileName(pathname);

                if (!Utils.WorthSyncing(Path.GetDirectoryName(pathname), filename, repoInfo))
                {
                    return(true);
                }
                try
                {
                    string  name       = pathname.Substring(localFolder.Length + 1);
                    string  remoteName = Path.Combine(remoteFolder, name).Replace('\\', '/');
                    IFolder remoteBase = null;
                    if (File.Exists(pathname) || Directory.Exists(pathname))
                    {
                        string remoteBaseName = Path.GetDirectoryName(remoteName).Replace('\\', '/');
                        remoteBase = (IFolder)session.GetObjectByPath(remoteBaseName);
                        if (null == remoteBase)
                        {
                            Logger.WarnFormat("The remote base folder {0} for local {1} does not exist, ignore for the update action", remoteBaseName, pathname);
                            return(true); // Ignore is not a failure.
                        }
                    }
                    else
                    {
                        Logger.InfoFormat("The file/folder {0} is deleted, ignore for the update action", pathname);
                        return(true);
                    }
                    if (File.Exists(pathname))
                    {
                        bool success = false;
                        if (database.ContainsFile(SyncItemFactory.CreateFromLocalPath(pathname, repoInfo)))
                        {
                            if (database.LocalFileHasChanged(pathname))
                            {
                                success = UpdateFile(pathname, remoteBase);
                                Logger.InfoFormat("Update {0}: {1}", pathname, success);
                            }
                            else
                            {
                                success = true;
                                Logger.InfoFormat("File {0} remains unchanged, ignore for the update action", pathname);
                            }
                        }
                        else
                        {
                            success = UploadFile(pathname, remoteBase);
                            Logger.InfoFormat("Upload {0}: {1}", pathname, success);
                        }
                        if (success)
                        {
                            return(true);
                        }
                        else
                        {
                            Logger.WarnFormat("Failure to update: {0}", pathname);
                            return(false);
                        }
                    }
                    if (Directory.Exists(pathname))
                    {
                        bool success = true;
                        if (database.ContainsFolder(pathname))
                        {
                            Logger.InfoFormat("Folder exists in Database {0}, ignore for the update action", pathname);
                        }
                        else
                        {
                            Logger.InfoFormat("Create locally created folder on server: {0}", pathname);
                            success &= UploadFolderRecursively(remoteBase, pathname);
                        }
                        return(success);
                    }
                    Logger.InfoFormat("The file/folder {0} is deleted, ignore for the update action", pathname);
                }
                catch (Exception e)
                {
                    ProcessRecoverableException("Could process watcher sync update: " + pathname, e);
                    return(false);
                }
                return(true);
            }
Exemplo n.º 30
0
            /// <summary>
            /// Check a local file in a given directory (not recursive).
            /// </summary>
            /// <param name="localFilenameTranslationOfExistingRemoteDocuments">Remove the file if it is not in this list of remote files (translated to local filenames). Ignored if null</param>
            private bool CheckLocalFile(string localFilePath, IFolder remoteFolder, IList <string> localFilenameTranslationOfExistingRemoteDocuments)
            {
                SleepWhileSuspended();
                bool success = true;

                try
                {
                    if (Utils.IsSymlink(new FileInfo(localFilePath)))
                    {
                        Logger.Info("Skipping symbolic linked file: " + localFilePath);
                        return(true);
                    }

                    var item = database.GetSyncItemFromLocalPath(localFilePath);
                    if (null == item)
                    {
                        // The file has been recently created locally (not synced from server).
                        item = SyncItemFactory.CreateFromLocalPath(localFilePath, false, repoInfo, database);
                    }

                    string fileName = item.LocalLeafname;

                    if (Utils.WorthSyncing(Path.GetDirectoryName(localFilePath), fileName, repoInfo))
                    {
                        if (localFilenameTranslationOfExistingRemoteDocuments == null ||
                            !localFilenameTranslationOfExistingRemoteDocuments.Contains(fileName))
                        {
                            // This local file is not on the CMIS server now, so
                            // check whether it used to exist on server or not.
                            if (database.ContainsLocalFile(localFilePath))
                            {
                                if (database.LocalFileHasChanged(localFilePath))
                                {
                                    // If file has changed locally, move to 'your_version' and warn about conflict
                                    Logger.Info("Conflict with file: " + localFilePath + ", backing up locally modified version.");
                                    activityListener.ActivityStarted();
                                    // Rename locally modified file.
                                    String newFilePath = Utils.CreateConflictFilename(localFilePath, repoInfo.User);

                                    // The file might be ReadOnly, so make it writable first, otherwise the move will fail.
                                    File.SetAttributes(localFilePath, FileAttributes.Normal); // TODO use Utils.DeleteEvenIfReadOnly

                                    File.Move(localFilePath, newFilePath);

                                    // Delete file from database.
                                    database.RemoveFile(item);

                                    repo.OnConflictResolved();
                                    activityListener.ActivityStopped();
                                }
                                else
                                {
                                    // File has been deleted on server, so delete it locally.
                                    Logger.Info("Removing remotely deleted file: " + localFilePath);
                                    activityListener.ActivityStarted();

                                    // Delete from the local filesystem.
                                    Utils.DeleteEvenIfReadOnly(localFilePath);

                                    // Delete file from database.
                                    database.RemoveFile(item);

                                    activityListener.ActivityStopped();
                                }
                            }
                            else
                            {
                                // New file, sync up.
                                Logger.Info("Uploading file absent on repository: " + localFilePath);
                                activityListener.ActivityStarted();
                                success &= UploadFile(localFilePath, remoteFolder);
                                activityListener.ActivityStopped();
                            }
                        }
                        else
                        {
                            // The file exists both on server and locally.
                            if (database.LocalFileHasChanged(localFilePath))
                            {
                                // Upload new version of file content.
                                Logger.Info("Uploading file update on repository: " + localFilePath);
                                activityListener.ActivityStarted();
                                success &= UpdateFile(localFilePath, remoteFolder);
                                activityListener.ActivityStopped();
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    ProcessRecoverableException("Could not crawl sync local file: " + localFilePath, e);
                    success = false;
                }
                return(success);
            }