Пример #1
0
        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));
        }
Пример #2
0
        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;
            }
        }
Пример #3
0
        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);
        }
Пример #4
0
        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
                       ));
        }
Пример #5
0
        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);
        }
Пример #6
0
        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);
        }
Пример #7
0
        public override async Task <IOFileAttributes> GetAttributesAsync(CancellationToken cancellationToken = default)
        {
            var folder = await FsHelper.GetFolderAsync(_fullPath, cancellationToken).ConfigureAwait(false);

            return(folder.Attributes.ToIOFileAttributes());
        }
Пример #8
0
        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));
        }
Пример #9
0
        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);
                }
            }
        }