/// <summary> /// Creates or updates file in the remote storage. /// </summary> /// <param name="remoteStoragePath">Path of the file to be created or updated in the remote storage.</param> /// <param name="newInfo">New information about the file, such as modification date, attributes, custom data, etc.</param> /// <param name="mode">Specifies if a new file should be created or existing file should be updated.</param> /// <param name="newContentStream">New file content or null if the file content is not modified.</param> /// <param name="eTagOld">The ETag to be sent to the remote storage as part of the update request to make sure the content is not overwritten.</param> /// <param name="lockInfo">Information about the lock. Null if the item is not locked.</param> /// <returns>The new ETag returned from the remote storage.</returns> protected async Task <string> CreateOrUpdateFileAsync( string remoteStoragePath, IFileMetadata newInfo, FileMode mode, Stream newContentStream = null, string eTagOld = null, ServerLockInfo lockInfo = null) { FileInfo remoteStorageItem = new FileInfo(remoteStoragePath); try { Program.VirtualDrive.RemoteStorageMonitor.Enabled = false; // Disable RemoteStorageMonitor to avoid circular calls. // If another thread is trying to sync the same file, this call will fail in other threads. // In your implementation you must lock your remote storage file, or block it for reading and writing by other means. await using (FileStream remoteStorageStream = remoteStorageItem.Open(mode, FileAccess.Write, FileShare.None)) { string userFileSystemPath = Mapping.ReverseMapPath(remoteStoragePath); if (mode == FileMode.Open) { // Verify that the item in the remote storage is not modified since it was downloaded to the user file system. // In your real-life application you will send the ETag to the server as part of the update request. FileSystemItemMetadataExt itemInfo = Mapping.GetUserFileSysteItemMetadata(remoteStorageItem); if (!(await VirtualDrive.GetETagManager(userFileSystemPath).ETagEqualsAsync(itemInfo))) { throw new ConflictException(Modified.Server, "Item is modified in the remote storage, ETags not equal."); } } // Update ETag/LastWriteTime in user file system, so the synchronyzation or remote storage monitor would not start the new update. // This is only required to avoid circular updates because of the simplicity of this sample. // In your real-life application you will receive a new ETag from the server in the update response // and return it from this method. string eTagNew = newInfo.LastWriteTime.ToUniversalTime().ToString("o"); await VirtualDrive.GetETagManager(userFileSystemPath).SetETagAsync(eTagNew); // Update remote storage file content. if (newContentStream != null) { await newContentStream.CopyToAsync(remoteStorageStream); remoteStorageStream.SetLength(newContentStream.Length); } // Update remote storage file basic info. WindowsFileSystemItem.SetFileInformation( remoteStorageStream.SafeFileHandle, newInfo.Attributes, newInfo.CreationTime, newInfo.LastWriteTime, newInfo.LastAccessTime, newInfo.LastWriteTime); return(eTagNew); } } finally { Program.VirtualDrive.RemoteStorageMonitor.Enabled = true; } }
private async Task CreateOrUpdateFileAsync(string userFileSystemPath, bool create) { try { Program.RemoteStorageMonitorInstance.Enabled = false; // Disable RemoteStorageMonitor to avoid circular calls. FileInfo userFileSystemFile = new FileInfo(userFileSystemPath); FileInfo remoteStorageFile = new FileInfo(remoteStoragePath); FileMode fileMode = create ? FileMode.CreateNew : FileMode.Open; await using (FileStream userFileSystemStream = userFileSystemFile.Open(FileMode.Open, FileAccess.Read, FileShare.Read)) { // If another thread is trying to sync the same file, this call will fail in other threads. // In your implemntation you must lock your remote storage file, or block it for reading and writing by other means. await using (FileStream remoteStorageStream = remoteStorageFile.Open(fileMode, FileAccess.Write, FileShare.None)) { userFileSystemFile.Refresh(); // Ensures LastWriteTimeUtc is in sync with file content after Open() was called. // Update ETag/LastWriteTime in user file system, so the synchronyzation or remote storage monitor would not start the new update. byte[] customData = BitConverter.GetBytes(userFileSystemFile.LastWriteTime.ToBinary()); PlaceholderItem.SetCustomData(userFileSystemStream.SafeFileHandle, customData); // Update remote storage file content. await userFileSystemStream.CopyToAsync(remoteStorageStream); remoteStorageStream.SetLength(userFileSystemStream.Length); // Update remote storage file basic info. WindowsFileSystemItem.SetFileInformation(remoteStorageStream.SafeFileHandle, userFileSystemFile.Attributes & (FileAttributes) ~FileAttributesExt.Pinned, // Remove Pinned flag. userFileSystemFile.CreationTimeUtc, userFileSystemFile.LastWriteTimeUtc, userFileSystemFile.LastAccessTimeUtc, userFileSystemFile.LastWriteTimeUtc); // If you are using ETags, here you will also send to the remote storage a new file ETag. PlaceholderItem.SetInSync(userFileSystemStream.SafeFileHandle, true); } } } finally { Program.RemoteStorageMonitorInstance.Enabled = true; } }