/// <summary> /// Creates a new file or folder placeholder in user file system. /// </summary> /// <param name="userFileSystemParentPath">User file system folder path in which the new item will be created.</param> /// <param name="remoteStorageItem">Remote storage item info. The new placeholder will be populated with data from this item.</param> public static async Task CreateAsync(string userFileSystemParentPath, FileSystemInfo remoteStorageItem) { IFileSystemItemBasicInfo userFileSystemNewItemInfo = Mapping.GetUserFileSysteItemInfo(remoteStorageItem); try { new PlaceholderFolder(userFileSystemParentPath).CreatePlaceholders(new[] { userFileSystemNewItemInfo }); } catch (Win32Exception ex) { // "Cannot create a file when that file already exists." if (ex.NativeErrorCode == 183) { // Process conflict. // Rethrow the exception preserving stack trace of the original exception. System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(ex).Throw(); throw ex; // This is for the compiler to know that the code never reaches here. } } }
/// <summary> /// Creates or updates the item in the remote storage. /// </summary> /// <param name="mode"> /// Indicates if the file should created or updated. /// Supported modes are <see cref="FileMode.CreateNew"/> and <see cref="FileMode.Open"/> /// </param> /// <param name="lockInfo">Information about the lock. Pass null if the item is not locked.</param> private async Task CreateOrUpdateAsync(FileMode mode, ServerLockInfo lockInfo = null) { if ((mode != FileMode.CreateNew) && (mode != FileMode.Open)) { throw new ArgumentOutOfRangeException("mode", $"Must be {FileMode.CreateNew} or {FileMode.Open}"); } FileSystemInfo userFileSystemItem = FsPath.GetFileSystemItem(userFileSystemPath); using (WindowsFileSystemItem userFileSystemWinItem = WindowsFileSystemItem.OpenReadAttributes(userFileSystemPath, FileMode.Open, FileShare.Read)) //await using (FileStream userFileSystemStream = userFileSystemFile.Open(FileMode.Open, FileAccess.Read, FileShare.Read)) { // Create the new file/folder in the remote storage only if the file/folder in the user file system was not moved. // If the file is moved in user file system, move must first be syched to remote storage. if ((mode == FileMode.CreateNew) && PlaceholderItem.GetItem(userFileSystemPath).IsMoved()) { string originalPath = PlaceholderItem.GetItem(userFileSystemPath).GetOriginalPath(); throw new ConflictException(Modified.Client, $"The item was moved. Original path: {originalPath}"); } // Ensures LastWriteTimeUtc is in sync with file content after Open() was called. userFileSystemItem.Refresh(); IFileSystemItemBasicInfo info = GetBasicInfo(userFileSystemItem); // Update remote storage file. FileStream userFileSystemStream = null; try { string eTag = null; if (FsPath.IsFile(userFileSystemPath)) { // File is marked as not in-sync when updated OR moved. // Opening a file for reading triggers hydration, make sure to open only if content is modified. if (PlaceholderFile.GetFileDataSizeInfo(userFileSystemWinItem.SafeHandle).ModifiedDataSize > 0) { //userFileSystemStream = new FileStream(userFileSystemWinItem.SafeHandle, FileAccess.Read); userFileSystemStream = ((FileInfo)userFileSystemItem).Open(FileMode.Open, FileAccess.Read, FileShare.Read); } if (mode == FileMode.CreateNew) { string userFileSystemParentPath = Path.GetDirectoryName(userFileSystemPath); IUserFolder userFolder = await virtualDrive.GetItemAsync <IUserFolder>(userFileSystemParentPath); eTag = await userFolder.CreateFileAsync((IFileBasicInfo)info, userFileSystemStream); } else { IUserFile userFile = await virtualDrive.GetItemAsync <IUserFile>(userFileSystemPath); eTag = await userFile.UpdateAsync((IFileBasicInfo)info, userFileSystemStream, lockInfo); } } else { if (mode == FileMode.CreateNew) { string userFileSystemParentPath = Path.GetDirectoryName(userFileSystemPath); IUserFolder userFolder = await virtualDrive.GetItemAsync <IUserFolder>(userFileSystemParentPath); eTag = await userFolder.CreateFolderAsync((IFolderBasicInfo)info); } else { IUserFolder userFolder = await virtualDrive.GetItemAsync <IUserFolder>(userFileSystemPath); eTag = await userFolder.UpdateAsync((IFolderBasicInfo)info, lockInfo); } } await ETag.SetETagAsync(userFileSystemPath, eTag); if (mode == FileMode.CreateNew) { PlaceholderItem.GetItem(userFileSystemPath).SetOriginalPath(userFileSystemPath); } } finally { if (userFileSystemStream != null) { userFileSystemStream.Close(); } } PlaceholderItem.SetInSync(userFileSystemWinItem.SafeHandle, true); } }