public override Task SetAttributesAsync(IOFileAttributes attributes, CancellationToken cancellationToken = default) { // There's no "native" API for setting file/folder attributes. // We can at least try to use System.IO's API - it should at least work in certain locations // like the application data. if (!EnumInfo.IsDefined(attributes)) { throw new ArgumentException(ExceptionStrings.Enum.UndefinedValue(attributes), nameof(attributes)); } return(Task.Run(async() => { try { // Get the folder to ensure that it exists and to throw the appropriate exception. await FsHelper.GetFolderAsync(_fullPath, cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); File.SetAttributes(_fullPath.ToString(), attributes); } catch (FileNotFoundException ex) { // Since we're using a File API, we must manually convert the FileNotFoundException. throw new DirectoryNotFoundException(message: null, ex); } }, cancellationToken)); }
public override async Task <bool> ExistsAsync(CancellationToken cancellationToken = default) { try { await FsHelper.GetFolderAsync(_fullPath, cancellationToken).ConfigureAwait(false); return(true); } catch (DirectoryNotFoundException) { return(false); } catch (IOException) { // IOException might be thrown if a conflicting file exists. // In such cases the specification requires us to return false. try { await FsHelper.GetFileAsync(_fullPath, cancellationToken).ConfigureAwait(false); return(false); } catch { // No conflicting file exists. Rethrow the original IOException. } throw; } }
public override async Task CreateAsync( bool recursive, CreationCollisionOption options, CancellationToken cancellationToken = default ) { if (!EnumInfo.IsDefined(options)) { throw new ArgumentException(ExceptionStrings.Enum.UndefinedValue(options), nameof(options)); } await EnsureNoConflictingFolderExistsAsync(cancellationToken).ConfigureAwait(false); WinStorageFolder parentFolder; if (recursive) { parentFolder = await FsHelper .GetOrCreateFolderAsync(_fullParentPath, cancellationToken) .ConfigureAwait(false); } else { parentFolder = await FsHelper .GetFolderAsync(_fullParentPath, cancellationToken) .ConfigureAwait(false); } await parentFolder .CreateFileAsync(_fullPath.Name, options.ToWinOptions()) .AsTask(cancellationToken) .WithConvertedException() .ConfigureAwait(false); }
public override async Task <StorageFolderProperties> GetPropertiesAsync(CancellationToken cancellationToken = default) { var folder = await FsHelper.GetFolderAsync(_fullPath, cancellationToken).ConfigureAwait(false); var props = await folder.GetBasicPropertiesAsync().AsAwaitable(cancellationToken); var lastModified = props.DateModified == default ? (DateTimeOffset?)null : props.DateModified; return(new StorageFolderProperties( folder.Name, IOPath.GetFileNameWithoutExtension(folder.Name), PhysicalPathHelper.GetExtensionWithoutTrailingExtensionSeparator(folder.Name)?.ToNullIfEmpty(), folder.DateCreated, lastModified )); }
public override async Task CreateAsync( bool recursive, CreationCollisionOption options, CancellationToken cancellationToken = default ) { if (!EnumInfo.IsDefined(options)) { throw new ArgumentException(ExceptionStrings.Enum.UndefinedValue(options), nameof(options)); } // We cannot reasonably create a root directory with the Windows Storage API. // If someone tries to do so, we'll simply deny the call. In most cases, the root // folder will exist anyway. if (_fullParentPath is null) { throw new UnauthorizedAccessException(); } await EnsureNoConflictingFileExistsAsync(cancellationToken).ConfigureAwait(false); WinStorageFolder parentFolder; if (recursive) { parentFolder = await FsHelper .GetOrCreateFolderAsync(_fullParentPath, cancellationToken) .ConfigureAwait(false); } else { parentFolder = await FsHelper .GetFolderAsync(_fullParentPath, cancellationToken) .ConfigureAwait(false); } await parentFolder .CreateFolderAsync(_fullPath.Name, options.ToWinOptions()) .AsTask(cancellationToken) .WithConvertedException() .ConfigureAwait(false); }
public override async Task <StorageFile> MoveAsync( StoragePath destinationPath, NameCollisionOption options, CancellationToken cancellationToken = default ) { _ = destinationPath ?? throw new ArgumentNullException(nameof(destinationPath)); if (!EnumInfo.IsDefined(options)) { throw new ArgumentException(ExceptionStrings.Enum.UndefinedValue(options), nameof(options)); } if (!(destinationPath is PhysicalStoragePath)) { throw new ArgumentException( ExceptionStrings.FsCompatibility.StoragePathTypeNotSupported(), nameof(destinationPath) ); } if (destinationPath.FullPath.Parent is null) { throw new IOException(ExceptionStrings.StorageFile.CannotMoveToRootLocation()); } var fullDestinationPath = destinationPath.FullPath; var destinationFile = FileSystem.GetFile(fullDestinationPath); var file = await FsHelper.GetFileAsync(_fullPath, cancellationToken).ConfigureAwait(false); var destFolder = await FsHelper .GetFolderAsync(fullDestinationPath.Parent, cancellationToken) .ConfigureAwait(false); await file .MoveAsync(destFolder, fullDestinationPath.Name, options.ToWinOptions()) .AsTask(cancellationToken) .WithConvertedException() .ConfigureAwait(false); return(destinationFile); }
public override async Task <IOFileAttributes> GetAttributesAsync(CancellationToken cancellationToken = default) { var folder = await FsHelper.GetFolderAsync(_fullPath, cancellationToken).ConfigureAwait(false); return(folder.Attributes.ToIOFileAttributes()); }
public override async Task <StorageFolder> RenameAsync( string newName, NameCollisionOption options, CancellationToken cancellationToken = default ) { _ = newName ?? throw new ArgumentNullException(nameof(newName)); if (newName.Length == 0) { throw new ArgumentException(ExceptionStrings.String.CannotBeEmpty(), nameof(newName)); } if (newName.Contains(PhysicalPathHelper.InvalidNewNameCharacters)) { throw new ArgumentException( ExceptionStrings.StorageFolder.NewNameContainsInvalidChar(FileSystem.PathInformation), nameof(newName) ); } if (!EnumInfo.IsDefined(options)) { throw new ArgumentException(ExceptionStrings.Enum.UndefinedValue(options), nameof(options)); } var srcFolder = await FsHelper.GetFolderAsync(_fullPath, cancellationToken).ConfigureAwait(false); var fullDestinationPath = _fullParentPath is null ? FileSystem.GetPath(newName).FullPath : _fullParentPath.Join(newName).FullPath; // The Windows Storage API doesn't do a hard replace with the ReplaceExisting option. // For example, if we had this structure: // |_ src // | |_ foo.ext // |_ dst // |_ bar.ext // // and renamed `src` to `dst`, we'd get this result: // |_ dst // |_ foo.ext // |_ bar.ext // // What we (and the spec) want is this: // |_ dst // |_ foo.ext // // We can manually delete the dst folder if it exists to fulfill the specification. // We're *only* doing it if we can be sure that we're not doing an in-place rename though, // i.e. rename `src` to `src`. // Otherwise we'd run into the problem that `src` is deleted and that the rename operation // will fail (DirectoryNotFound). Afterwards the entire folder is gone permanently. // That must be avoided at all cost. if (options == NameCollisionOption.ReplaceExisting && !fullDestinationPath.Name.Equals(_fullPath.Name, FileSystem.PathInformation.DefaultStringComparison)) { try { var dstFolder = await FsHelper.GetFolderAsync(fullDestinationPath, cancellationToken).ConfigureAwait(false); await dstFolder.DeleteAsync(StorageDeleteOption.PermanentDelete).AsAwaitable(cancellationToken); } catch { // If deleting the conflicting folder fails, it's okay, since the whole process // is just there for fulfilling the specification. // The Windows Storage API will still replace conflicting elements. // It's just that certain files may be left over (as described above). // Not fulfilling the spec is the best thing we can do without taking higher risks // of lost data. } } await srcFolder .RenameAsync(newName, options.ToWinOptions()) .AsTask(cancellationToken) .WithConvertedException() .ConfigureAwait(false); return(FileSystem.GetFolder(fullDestinationPath)); }
public override async Task <StorageFolder> CopyAsync( StoragePath destinationPath, NameCollisionOption options, CancellationToken cancellationToken = default ) { _ = destinationPath ?? throw new ArgumentNullException(nameof(destinationPath)); if (!EnumInfo.IsDefined(options)) { throw new ArgumentException(ExceptionStrings.Enum.UndefinedValue(options), nameof(options)); } if (!(destinationPath is PhysicalStoragePath)) { throw new ArgumentException( ExceptionStrings.FsCompatibility.StoragePathTypeNotSupported(), nameof(destinationPath) ); } if (destinationPath.FullPath.Parent is null) { throw new IOException(ExceptionStrings.StorageFolder.CannotMoveToRootLocation()); } if (destinationPath.FullPath == _fullPath) { throw new IOException(ExceptionStrings.StorageFolder.CannotCopyToSameLocation()); } var destinationParentFolder = await FsHelper .GetFolderAsync(destinationPath.FullPath.Parent, cancellationToken) .ConfigureAwait(false); var sourceFolder = await FsHelper.GetFolderAsync(_fullPath, cancellationToken).ConfigureAwait(false); await Impl(sourceFolder, destinationParentFolder, destinationPath.FullPath.Name).ConfigureAwait(false); return(FileSystem.GetFolder(destinationPath.FullPath)); async Task Impl(WinStorageFolder src, WinStorageFolder dstFolderParent, string dstFolderName) { var dstFolder = await dstFolderParent .CreateFolderAsync(dstFolderName, ((CreationCollisionOption)options).ToWinOptions()) .AsTask(cancellationToken) .WithConvertedException() .ConfigureAwait(false); foreach (var file in await src.GetFilesAsync().AsAwaitable(cancellationToken)) { await file .CopyAsync(dstFolder, file.Name) .AsTask(cancellationToken) .WithConvertedException() .ConfigureAwait(false); } foreach (var folder in await src.GetFoldersAsync().AsAwaitable(cancellationToken)) { await Impl(folder, dstFolder, folder.Name).ConfigureAwait(false); } } }