///<inheritdoc> public async Task UnlockAsync() { if (MsOfficeHelper.IsMsOfficeLocked(UserFileSystemPath)) // Required for PowerPoint. It does not block the for writing. { throw new ClientLockFailedException("The file is blocked for writing."); } ExternalDataManager customDataManager = Engine.CustomDataManager(UserFileSystemPath, Logger); LockManager lockManager = customDataManager.LockManager; // Set pending icon, so the user has a feedback as unlock operation may take some time. await customDataManager.SetLockPendingIconAsync(true); // Read lock-token from lock-info file. string lockToken = (await lockManager.GetLockInfoAsync()).LockToken; // Unlock the item in the remote storage. try { await Program.DavClient.UnlockAsync(new Uri(RemoteStoragePath), lockToken); } catch (ITHit.WebDAV.Client.Exceptions.ConflictException) { // The item is already unlocked. } // Delete lock-mode and lock-token info. lockManager.DeleteLock(); // Remove lock icon and lock info in custom columns. await customDataManager.SetLockInfoAsync(null); Logger.LogMessage("Unlocked in the remote storage succesefully", UserFileSystemPath); }
/// <inheritdoc/> public async Task WriteAsync(IFileMetadata fileMetadata, Stream content = null) { if (MsOfficeHelper.IsMsOfficeLocked(UserFileSystemPath)) // Required for PowerPoint. It does not block the for writing. { throw new ClientLockFailedException("The file is blocked for writing."); } Logger.LogMessage($"{nameof(IFile)}.{nameof(WriteAsync)}()", UserFileSystemPath); ExternalDataManager customDataManager = Engine.CustomDataManager(UserFileSystemPath); // Send the ETag to the server as part of the update to ensure the file in the remote storge is not modified since last read. string oldEtag = await customDataManager.ETagManager.GetETagAsync(); // Send the lock-token to the server as part of the update. string lockToken = (await customDataManager.LockManager.GetLockInfoAsync())?.LockToken; if (content != null) { long contentLength = content != null ? content.Length : 0; IWebRequestAsync request = await Program.DavClient.GetFileWriteRequestAsync( new Uri(RemoteStoragePath), null, contentLength, 0, -1, lockToken, oldEtag); // Update remote storage file content. using (Stream davContentStream = await request.GetRequestStreamAsync()) { if (content != null) { await content.CopyToAsync(davContentStream); } // Get the new ETag returned by the server (if any). IWebResponseAsync response = await request.GetResponseAsync(); string eTagNew = response.Headers["ETag"]; response.Close(); // Store ETag unlil the next update. // This will also mark the item as not new, which is required for correct MS Office saving opertions. await customDataManager.ETagManager.SetETagAsync(eTagNew); // Update ETag in custom column displayed in file manager. await customDataManager.SetCustomColumnsAsync(new[] { new FileSystemItemPropertyData((int)CustomColumnIds.ETag, eTagNew) }); } } }
/// <inheritdoc/> public override async Task <bool> FilterAsync(string userFileSystemPath, string userFileSystemNewPath = null) { // IsMsOfficeLocked() check is required for MS Office PowerPoint. // PowerPoint does not block the file for reading when the file is opened for editing. // As a result the file will be sent to the remote storage during each file save operation. if (userFileSystemNewPath == null) { // Executed during create, update, delete, open, close. return(MsOfficeHelper.AvoidMsOfficeSync(userFileSystemPath)); } else { // Executed during rename/move operation. return (MsOfficeHelper.IsRecycleBin(userFileSystemNewPath) || // When a hydrated file is deleted, it is moved to a Recycle Bin. MsOfficeHelper.AvoidMsOfficeSync(userFileSystemNewPath)); } }
/// <summary> /// Called when a file or folder is renamed in the user file system. /// </summary> private async void RenamedAsync(object sender, RenamedEventArgs e) { // If the item and was previusly filtered by EngineWindows.FilterAsync(), // for example temp MS Office file was renamed SGE4274H->file.xlsx, // we need to convert the file to a pleaceholder and upload it to the remote storage. // We must also LogMessage("Renamed", e.OldFullPath, e.FullPath); string userFileSystemOldPath = e.OldFullPath; string userFileSystemNewPath = e.FullPath; try { if (System.IO.File.Exists(userFileSystemNewPath) && !MsOfficeHelper.AvoidMsOfficeSync(userFileSystemNewPath)) { if (!PlaceholderItem.IsPlaceholder(userFileSystemNewPath)) { if (engine.CustomDataManager(userFileSystemNewPath).IsNew) { await engine.ClientNotifications(userFileSystemNewPath, this).CreateAsync(); } else { LogMessage("Converting to placeholder", userFileSystemNewPath); PlaceholderItem.ConvertToPlaceholder(userFileSystemNewPath, null, null, false); await engine.ClientNotifications(userFileSystemNewPath, this).UpdateAsync(); await engine.CustomDataManager(userFileSystemNewPath).RefreshCustomColumnsAsync(); } } } } catch (Exception ex) { LogError($"{e.ChangeType} failed", userFileSystemOldPath, userFileSystemNewPath, ex); } }