/// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentException"></exception> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <exception cref="InvalidOperationException"></exception> public void WriteBytes(byte[] array, int startingPosition, int length) { MethodArgumentValidator.ThrowIfNull(array, "array"); MethodArgumentValidator.ThrowIfNegative(startingPosition, "startingPosition"); MethodArgumentValidator.ThrowIfNegative(length, "length"); if ((startingPosition + length) > array.Length) { throw new ArgumentException("В массиве, начиная с позиции {0}, не найдется следующего числа байт для записи: {1}".FormatWith(startingPosition, length)); } if (this.IsAtEndOfBlock) { throw new InvalidOperationException("Запись за пределами границ блока не разрешена"); } int positionAfterWriting = this.Position + length; if (positionAfterWriting > this.SizeInBytes) { throw new ArgumentException("Запись невозможна: попытка записи за пределами массива"); } _disk.WriteBytesToBlock(BlockIndex, array, startingPosition, _position, length); if ((positionAfterWriting > this.OccupiedSpaceInBytes) && (this.OccupiedSpaceInBytes < this.SizeInBytes)) { this.OccupiedSpaceInBytes += (positionAfterWriting - this.OccupiedSpaceInBytes); } this.Position = positionAfterWriting; }
/// <summary> /// /// </summary> /// <param name="fileSystem"></param> /// <param name="exportingFolderPath"></param> /// <param name="virtualDestinationFolder"></param> /// <param name="taskToken"></param> /// <returns></returns> /// <exception cref="InsufficientSpaceException"></exception> /// <exception cref="CannotGetImportedFolderStructureException"></exception> /// <exception cref="FolderNotFoundException"></exception> internal static ReadOnlyCollection <FileSystemTaskResult> ImportFolderFromRealFileSystem( this VirtualFileSystem fileSystem, string exportingFolderPath, string virtualDestinationFolder, IFileSystemCancellableTaskToken taskToken) { if (fileSystem == null) { throw new ArgumentNullException("fileSystem"); } MethodArgumentValidator.ThrowIfStringIsNullOrEmpty(exportingFolderPath, "exportingFolderPath"); MethodArgumentValidator.ThrowIfStringIsNullOrEmpty(virtualDestinationFolder, "virtualDestinationFolder"); FolderAddressable folderAddressable = CreateFileSystemObjectStructureFromFolder(exportingFolderPath); int totalNumberOfFilesToTraverse = folderAddressable.GetTotalFileCount(); // Note: можно уменьшить связность классов, передав сюда через интерфейс фабрику, которая уж знает, как сделать нужного Visitor-а. ImportingAddressableObjectVisitor visitor = new ImportingAddressableObjectVisitor(fileSystem, exportingFolderPath, virtualDestinationFolder, new RealFileContentsBufferFactory(), taskToken, totalNumberOfFilesToTraverse); if (!fileSystem.FolderExists(virtualDestinationFolder)) { throw new FolderNotFoundException("Не удалось найти папку \"{0}\", в которую следует произвести копирование/импорт.".FormatWith(virtualDestinationFolder)); } folderAddressable.Accept(visitor); var results = visitor.GetResult(); return(results); }
/// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentOutOfRangeException"></exception> public DiskBlock(IVirtualDisk disk, int index, int occupiedSpaceInBytes, int position) { if (disk == null) { throw new ArgumentNullException("disk"); } MethodArgumentValidator.ThrowIfNegative(index, "index"); MethodArgumentValidator.ThrowIfNegative(occupiedSpaceInBytes, "occupiedSpaceInBytes"); MethodArgumentValidator.ThrowIfNegative(position, "position"); if (index >= disk.NumberOfBlocks) { throw new ArgumentOutOfRangeException("index"); } if (occupiedSpaceInBytes > disk.BlockSizeInBytes) { throw new ArgumentOutOfRangeException("occupiedSpaceInBytes"); } if (position > disk.BlockSizeInBytes) { throw new ArgumentOutOfRangeException("position"); } _disk = disk; _blockIndex = index; this.OccupiedSpaceInBytes = occupiedSpaceInBytes; this.SizeInBytes = _disk.BlockSizeInBytes; _position = position; }
/// <summary> /// Устанавливает указатель текущего положения в потоке в новое место. /// Примечание: за границу потока установить указатель нельзя (допускается лишь устанавливать ее за последним записанным/считанным байтом). /// </summary> /// <param name="newPosition">Новая позиция указателя текущего положения.</param> /// <exception cref="InvalidOperationException"></exception> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <exception cref="ObjectDisposedException"></exception> public override void SetPosition(int newPosition) { lock (_stateChangeCriticalSection) { this.ThrowIfDisposed(); MethodArgumentValidator.ThrowIfNegative(newPosition, "newPosition"); if (newPosition > this.Length) { throw new ArgumentOutOfRangeException("newPosition", "Невозможно установить позицию за пределами потока данных."); } if (newPosition == this.Length) { this.MoveToEnd(); return; } int blockIndex = newPosition / _blockSize; _diskBlockEnumerator.SetPosition(blockIndex); _diskBlockEnumerator.Current.Position = newPosition % _blockSize; } }
/// <summary> /// /// </summary> /// <param name="newSize"></param> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <exception cref="NoFreeBlocksException"></exception> /// <exception cref="ArgumentException"></exception> /// <exception cref="InconsistentDataDetectedException"></exception> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="MaximumFileSizeReachedException"></exception> public override void SetSize(int newSize) { MethodArgumentValidator.ThrowIfNegative(newSize, "newSize"); if (newSize == this.CurrentSize) { return; } if (newSize > this.MaximumSize) { throw new MaximumFileSizeReachedException( "Не удалось установить размер структуры в {0} байт. Максимальный размер - {1} байт.".FormatWith( newSize, this.MaximumSize)); } if (newSize > this.CurrentSize) { this.MakeLonger(newSize - this.CurrentSize); } else { this.MakeShorter(newSize); } }
/// <summary> /// Устанавливает длину потока (беря себе или освобождая соответствующий объем дискового пространства). /// </summary> /// <param name="newLength">Новая длина потока</param> /// <exception cref="InsufficientSpaceException"></exception> /// <exception cref="ObjectDisposedException"></exception> public override void SetLength(int newLength) { lock (_stateChangeCriticalSection) { this.ThrowIfDisposed(); MethodArgumentValidator.ThrowIfNegative(newLength, "newLength"); if (newLength < _streamStructureBuilder.CurrentSize) { this.Shrink(newLength); return; } if (newLength == this.Length) { return; } int position = this.Position; this.MoveToEnd(); int numberOfZeroesToAdd = this.Length == 0 ? newLength : newLength - (_streamStructureBuilder.CurrentSize - 1); WriteZeroes(numberOfZeroesToAdd); this.SetPosition(position); } }
/// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <exception cref="ArgumentException"></exception> internal DataStream( IDataStreamStructureBuilder streamStructureBuilder, int blockSize, IFileSystemLockReleaseManager lockingManager, Guid idOfLockBeingHeld) { try { if (streamStructureBuilder == null) { throw new ArgumentNullException("streamStructureBuilder"); } if (lockingManager == null) { throw new ArgumentNullException("lockingManager"); } MethodArgumentValidator.ThrowIfIsDefault(idOfLockBeingHeld, "idOfLockBeingHeld"); MethodArgumentValidator.ThrowIfNegative(blockSize, "blockSize"); _streamStructureBuilder = streamStructureBuilder; _blockSize = blockSize; _lockingManager = lockingManager; _idOfLockBeingHeld = idOfLockBeingHeld; _diskBlockEnumerator = streamStructureBuilder.CreateEnumerator(); } catch (Exception) { GC.SuppressFinalize(this); throw; } }
/// <summary> /// Создает Iterator для перебора файлов в папке, имена которых удовлетворяют заданной маске (<paramref name="patternNamesOfFilesMustMatch"/>). /// Работает рекурсивно - то есть перебирает и файлы во всех подпапках указанной папки. /// Note: генерирует исключение (<see cref="InvalidOperationException"/>), если папка, по которой производится обход, меняется во время обхода (итераторы не thread-safe, я бы их лучше не показывал, но это явно зафиксированное требования). /// </summary> /// <param name="folderToEnumerateFilesIn">Папка, в которой следует искать файлы.</param> /// <param name="patternNamesOfFilesMustMatch">Маска для поиска файлов. Звездочка означает любую последовательность символов. Знак вопроса - один любой символ.</param> /// <returns>Iterator для перебора файлов в папке, имена которых удовлетворяют заданной маске (<paramref name="patternNamesOfFilesMustMatch"/>)</returns> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="FolderNotFoundException"></exception> /// <exception cref="ObjectDisposedException"></exception> public IEnumerator <FileInfo> EnumerateFilesUnderFolder(string folderToEnumerateFilesIn, string patternNamesOfFilesMustMatch) { MethodArgumentValidator.ThrowIfStringIsNullOrEmpty(folderToEnumerateFilesIn, "folderToEnumerateFilesIn"); MethodArgumentValidator.ThrowIfStringIsNullOrEmpty(patternNamesOfFilesMustMatch, "patternNamesOfFilesMustMatch"); Monitor.Enter(_operationExecutionCriticalSection); try { ThrowIfDisposed(); var nodeResolvingResult = _nodeResolver.ResolveFolderNodeByPath(folderToEnumerateFilesIn); var folder = new FolderInfo(nodeResolvingResult.ResolvedNode, folderToEnumerateFilesIn); var enumerator = new FolderContentsEnumerator(folder, patternNamesOfFilesMustMatch, _folderEnumeratorRegistry, this); _folderEnumeratorRegistry.RegisterEnumerator(enumerator); return(enumerator); } catch (InvalidPathException) { throw new FolderNotFoundException( "Не удалось найти папку по указанному пути (\"{0}\")".FormatWith(folderToEnumerateFilesIn)); } finally { Monitor.Exit(_operationExecutionCriticalSection); } }
/// <summary> /// Открывает указанный файл для записи и чтения. /// </summary> /// <param name="fullPathForFile">Путь, указывающий открываемый файл.</param> /// <returns>Поток данных файла, допускающий чтение и запись данных</returns> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="FileNotFoundException"></exception> /// <exception cref="FileLockedException"></exception> /// <exception cref="ObjectDisposedException"></exception> public DataStreamReadableWritable OpenFileForWriting(string fullPathForFile) { MethodArgumentValidator.ThrowIfStringIsNullOrEmpty(fullPathForFile, "fullPathForFile"); try { NodeWithSurroundingsResolvingResult <FileNode> nodeResolvingResult; DataStreamStructureBuilder dataStreamStructureBuilder = GetDataStreamStructureBuilderResolvingTheFile(fullPathForFile, out nodeResolvingResult); Guid lockId = _lockingManager.AcquireLock(nodeResolvingResult, LockKind.Write); var stream = new DataStream(dataStreamStructureBuilder, AddressingSystemParameters.Default.BlockSize, _lockingManager, lockId); var nodeUpdatingStream = new DataStreamNodeUpdating(stream, nodeResolvingResult.ResolvedNode, _fileSystemNodeStorage); return(nodeUpdatingStream); } catch (InvalidPathException) { throw new FileNotFoundException("Файл не найден по указанному пути (\"{0}\")".FormatWith(fullPathForFile)); } catch (CannotAcquireLockException) { throw new FileLockedException( "Не удалось открыть файл \"{0}\" с блокировкой на запись: он уже заблокирован на чтение или запись." .FormatWith(fullPathForFile)); } }
/// <summary> /// /// </summary> /// <param name="freeSpaceBitmap"></param> /// <param name="blockIndexOffset"></param> /// <param name="freeSpaceMapLength"></param> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <exception cref="ArgumentException"></exception> public FreeBlockManagerBitArrayBased(BitArray freeSpaceBitmap, int blockIndexOffset, int freeSpaceMapLength) { MethodArgumentValidator.ThrowIfNull(freeSpaceBitmap, "freeSpaceBitmap"); MethodArgumentValidator.ThrowIfNegative(blockIndexOffset, "blockIndexOffset"); if (freeSpaceBitmap.Length != freeSpaceMapLength) { throw new ArgumentException("В Bitmap для разметки свободного места должно быть следующее число бит: {0}".FormatWith(freeSpaceMapLength)); } _freeSpaceBitmap = freeSpaceBitmap; _blockIndexOffset = blockIndexOffset; _freeSpaceMapLength = freeSpaceMapLength; int freeBlocksCount = 0; for (int i = 0; i < freeSpaceBitmap.Length; i++) { if (!freeSpaceBitmap[i]) { freeBlocksCount++; } } _freeBlockCount = freeBlocksCount; }
/// <summary> /// /// </summary> /// <param name="blockIndex"></param> /// <param name="dataStreamToAddReferenceIn"></param> /// <param name="nodeOwningTheStream"></param> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentOutOfRangeException"></exception> /// <exception cref="InsufficientSpaceException"></exception> /// <exception cref="MaximumFileSizeReachedException"></exception> public void AddBlockReference(int blockIndex, DataStreamDefinition dataStreamToAddReferenceIn, Node nodeOwningTheStream) { if (dataStreamToAddReferenceIn == null) { throw new ArgumentNullException("dataStreamToAddReferenceIn"); } if (nodeOwningTheStream == null) { throw new ArgumentNullException("nodeOwningTheStream"); } MethodArgumentValidator.ThrowIfNegative(blockIndex, "blockIndex"); var streamStructureBuilder = new DataStreamStructureBuilder(dataStreamToAddReferenceIn, _virtualDisk, _freeBlockManager, _fileSystemNodeStorage, nodeOwningTheStream, AddressingSystemParameters.Default); // Note: никаких настоящих блокировок не использует. var parentFolderFileReferencesStream = new DataStream(streamStructureBuilder, AddressingSystemParameters.Default.BlockSize, new NullFileSystemObjectLockingManager(), Guid.NewGuid()); var nodeUpdatingStream = new DataStreamNodeUpdating(parentFolderFileReferencesStream, nodeOwningTheStream, _fileSystemNodeStorage); using (nodeUpdatingStream) { var stream = new MemoryStream(); var writer = new BinaryWriter(stream); writer.Write(blockIndex); nodeUpdatingStream.MoveToEnd(); nodeUpdatingStream.Write(stream.ToArray(), 0, (int)stream.Length); } }
public DataStreamDefinition(int contentsBlockReference, int streamLengthInBytes) { MethodArgumentValidator.ThrowIfNegative(contentsBlockReference, "contentsBlockReference"); MethodArgumentValidator.ThrowIfNegative(streamLengthInBytes, "streamLengthInBytes"); _contentsBlockIndex = contentsBlockReference; _streamLengthInBytes = streamLengthInBytes; }
public AddressingSystemBlockSizes(int doubleIndirectBlockSize, int lastSingleIndirectBlockSize) { MethodArgumentValidator.ThrowIfNegative(doubleIndirectBlockSize, "doubleIndirectBlockSize"); MethodArgumentValidator.ThrowIfNegative(lastSingleIndirectBlockSize, "lastSingleIndirectBlockSize"); DoubleIndirectBlockSize = doubleIndirectBlockSize; LastSingleIndirectBlockSize = lastSingleIndirectBlockSize; }
/// <summary> /// Удаляет пустую папку, расположенную по указанному пути. Непустые папки в этой версии удалить вызовом одного метода /// нельзя. /// </summary> /// <param name="folderPath">Путь, указывающий, какую папку надо удалить.</param> /// <exception cref="FolderNotFoundException"></exception> /// <exception cref="FolderNotEmptyException"></exception> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="ObjectDisposedException"></exception> public void DeleteFolder(string folderPath) { MethodArgumentValidator.ThrowIfStringIsNullOrEmpty(folderPath, "folderPath"); if (_pathBuilder.PointsToRoot(folderPath)) { throw new InvalidPathException("Не получилось удалить папку: нельзя удалить корень файловой системы."); } try { string folderName; var parentFolderResolvingResult = _nodeResolver.ResolveParentFolderNodeByPath(folderPath, out folderName); FolderNode folderToRemoveDirectoryFrom = parentFolderResolvingResult.ResolvedNode; var allFolders = _nodeResolver.GetAllFoldersFrom(folderToRemoveDirectoryFrom); FolderNode folderToRemove = allFolders.FirstOrDefault(folderNode => _namesComparer.Equals(folderNode.Name, folderName)); if (folderToRemove == null) { throw new FolderNotFoundException("Не найдена папка для удаления (\"0\")".FormatWith(folderPath)); } if ((folderToRemove.FileReferencesStreamDefinition.StreamLengthInBytes > 0) || (folderToRemove.FolderReferencesStreamDefinition.StreamLengthInBytes > 0)) { throw new FolderNotEmptyException("Не удалось удалить папку: она не пуста"); // Note: блокировки не проверяю. В пустой папке блокировать нечего. } var idsOfFolderUnderGivenOne = _nodeResolver.GetIdsOfAllFoldersUnderGivenOne(folderPath); // TODO: посмотреть на исключения этого метода. _blockReferenceListsEditor.TakeOutABlockFromBlockReferenceList(folderToRemoveDirectoryFrom, folderToRemove.DiskBlockIndex, folderToRemoveDirectoryFrom.FolderReferencesStreamDefinition); _freeBlockManager.MarkBlocksAsFree(new[] { folderToRemove.FileReferencesStreamDefinition.ContentsBlockIndex, folderToRemove.FolderReferencesStreamDefinition.ContentsBlockIndex, folderToRemove.DiskBlockIndex }); _folderEnumeratorRegistry.InvalidateEnumeratorsFor(parentFolderResolvingResult.FoldersPassedWhileResolving); _folderEnumeratorRegistry.InvalidateEnumeratorsForFolder(parentFolderResolvingResult.ResolvedNode.Id); _folderEnumeratorRegistry.InvalidateEnumeratorsForFolder(folderToRemove.Id); _folderEnumeratorRegistry.InvalidateEnumeratorsFor(idsOfFolderUnderGivenOne); } catch (CannotResolvePathException) { throw new FolderNotFoundException("Не удалось найти папку по указанному пути (\"{0}\")".FormatWith(folderPath)); } catch (InvalidPathException) { throw new FolderNotFoundException("Не удалось найти папку по указанному пути (\"{0}\")".FormatWith(folderPath)); } }
/// <summary> /// Устанавливает в качестве текущего блок заданного номера. /// </summary> /// <param name="newPosition"></param> /// <exception cref="ArgumentOutOfRangeException"></exception> public void SetPosition(int newPosition) { if (newPosition == EnumeratorAddressable <IDiskBlock> .IndexOfPositionBeforeFirstElement) { this.Reset(); return; } MethodArgumentValidator.ThrowIfNegative(newPosition, "newPosition"); if (newPosition >= _numberOfBlocks) { throw new ArgumentOutOfRangeException("newPosition", "Невозможно установить позицию за границей массива"); } #region совсем топорная версия // if (newPosition < _position) // { // this.Reset(); // } // // while (_position != newPosition) // { // this.MoveNext(); // } // //return; #endregion var compositeIndex = new CompositeIndex(newPosition, new[] { _addressingSystemParameters.IndirectBlockReferencesCountInDoubleIndirectBlock, _addressingSystemParameters.DataBlockReferencesCountInSingleIndirectBlock }); var sizes = _blockSizesCalculator.GetSizesOfAddressingBlocksSufficientToStoreItems(newPosition); _doubleIndirectListEnumerator.SetPosition(compositeIndex.CompositeValue[0]); bool isLastDoubleIndirectionBlock = _doubleIndirectListEnumerator.IsAtLastElement; int numberOfSingleIndirectBlockReferences = isLastDoubleIndirectionBlock ? _addressingSystemSizesOfLastBlocks.LastSingleIndirectBlockSize : _addressingSystemParameters.DataBlockReferencesCountInSingleIndirectBlock; this.InitializeSingleIndirectionBlock( _doubleIndirectListEnumerator.Current, numberOfSingleIndirectBlockReferences, compositeIndex.CompositeValue[1]); this.InitializeCurrentBlockBrowser(); _position = newPosition; }
/// <summary> /// /// </summary> /// <exception cref="LockNotFoundException"></exception> /// <exception cref="ArgumentNullException"></exception> public void ReleaseLock(Guid associatedLockId) { MethodArgumentValidator.ThrowIfIsDefault <Guid>(associatedLockId, "associatedLockId"); bool removedSuccessfully = _idsOfAssociatedFileLocks.Remove(associatedLockId); if (!removedSuccessfully) { throw new LockNotFoundException("Блокировка с идентификатором {0} не найдена.".FormatWith(associatedLockId)); } }
/// <summary> /// Возвращает сведения о всех подпапках в указанной директории (<paramref name="folderToGetSubfoldersOf"/>). Работает без рекурсии. /// </summary> /// <param name="folderToGetSubfoldersOf">Папка, поддиректории которой надо вернуть.</param> /// <returns>Сведения о всех папках в указанной директории (<paramref name="folderToGetSubfoldersOf"/>)</returns> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="FolderNotFoundException"></exception> /// <exception cref="ObjectDisposedException"></exception> public ReadOnlyCollection <FolderInfo> GetAllFoldersFrom(string folderToGetSubfoldersOf) { MethodArgumentValidator.ThrowIfStringIsNullOrEmpty(folderToGetSubfoldersOf, "folderToGetSubfoldersOf"); lock (_operationExecutionCriticalSection) { ThrowIfDisposed(); return(_nodeResolver.GetAllFoldersFrom(folderToGetSubfoldersOf)); } }
public FolderNode(string name, Guid id, int diskBlockIndex, int parentFolderBlockReference, DataStreamDefinition fileReferencesStreamDefinition, DataStreamDefinition folderReferencesStreamDefinition, DateTime creationTime, Guid version) : base(name, id, diskBlockIndex, version, creationTime) { MethodArgumentValidator.ThrowIfNull(fileReferencesStreamDefinition, "fileReferencesStream"); MethodArgumentValidator.ThrowIfNull(folderReferencesStreamDefinition, "folderReferencesStream"); MethodArgumentValidator.ThrowIfNegative(parentFolderBlockReference, "parentFolderBlockReference"); MethodArgumentValidator.ThrowIfNegative(diskBlockIndex, "diskBlockIndex"); MethodArgumentValidator.ThrowIfIsDefault(id, "id"); _fileReferencesStreamDefinition = fileReferencesStreamDefinition; _folderReferencesStreamDefinition = folderReferencesStreamDefinition; _parentFolderBlockReference = parentFolderBlockReference; }
public FileNode(string name, Guid id, int diskBlockIndex, DataStreamDefinition fileContentsStreamDefinition, DateTime lastModificationTimeUtc, DateTime creationTimeUtc, Guid version) : base(name, id, diskBlockIndex, version, creationTimeUtc) { if (fileContentsStreamDefinition == null) { throw new ArgumentNullException("fileContentsStreamDefinition"); } MethodArgumentValidator.ThrowIfIsDefault <DateTime>(lastModificationTimeUtc, "lastModificationTimeUtc"); MethodArgumentValidator.ThrowIfDateIsNonUtc(lastModificationTimeUtc, "lastModificationTimeUtc"); _fileContentsStreamDefinition = fileContentsStreamDefinition; _lastModificationTimeUtc = lastModificationTimeUtc; }
public static bool ContainsLetters(this IEnumerable <char> characters) { MethodArgumentValidator.ThrowIfNull(characters, "characters"); foreach (char character in characters) { if (Char.IsLetter(character)) { return(true); } } return(false); }
/// <summary> /// Переименовывает указанный файл. /// </summary> /// <param name="fullPathForFile">Путь, указывающий файл для переименования.</param> /// <param name="newFileName">Новое имя файла (без пути).</param> /// <exception cref="FileAlreadyExistsException"></exception> /// <exception cref="InvalidPathException"></exception> /// <exception cref="FileNotFoundException"></exception> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="ObjectDisposedException"></exception> /// <exception cref="InvalidNameException"></exception> /// <exception cref="FileLockedException"></exception> public void RenameFile(string fullPathForFile, string newFileName) { MethodArgumentValidator.ThrowIfStringIsNullOrEmpty(fullPathForFile, "fullPathForFile"); MethodArgumentValidator.ThrowIfStringIsNullOrEmpty(newFileName, "newFileName"); if (_pathBuilder.PointsToRoot(fullPathForFile)) { throw new InvalidPathException("Файл не был переименован: имя файла, который следует переименовать, не может указывать на корень файловой системы"); } _nameValidator.Validate(newFileName); try { string fileName; var parentFolderResolvingResult = _nodeResolver.ResolveParentFolderNodeByPath(fullPathForFile, out fileName); string lastPartOfFullPath = _pathBuilder.GetFileOrFolderName(fullPathForFile); if (_namesComparer.Equals(newFileName, lastPartOfFullPath)) { return; } ReadOnlyCollection <FileNode> files; FileNode fileNode = this.ResolveFileNodeThrowingUserFriendlyErrors(fullPathForFile, parentFolderResolvingResult, fileName, "переименовать", out files); if (files.Any(node => _namesComparer.Equals(newFileName, node.Name))) { throw new FileAlreadyExistsException("Не удалось переименовать файл: файл с именем \"{0}\" уже существует в папке, где вы производите переименование".FormatWith(newFileName)); } fileNode.Name = newFileName; _fileSystemNodeStorage.WriteNode(fileNode); _folderEnumeratorRegistry.InvalidateEnumeratorsFor(parentFolderResolvingResult.FoldersPassedWhileResolving); _folderEnumeratorRegistry.InvalidateEnumeratorsForFolder(parentFolderResolvingResult.ResolvedNode.Id); } catch (CannotResolvePathException) { throw new FileNotFoundException("Не удалось найти файл {0}".FormatWith(fullPathForFile)); } catch (InvalidPathException) { throw new FileNotFoundException("Не удалось найти файл {0}".FormatWith(fullPathForFile)); } }
internal VirtualFileSystemInfo(Version version, int blockSizeInBytes, int firstNonReservedDiskBlockIndex, int freeSpaceBitmapStartingBlock) { if (version == null) { throw new ArgumentNullException("version"); } MethodArgumentValidator.ThrowIfNegative(blockSizeInBytes, "blockSizeInBytes"); MethodArgumentValidator.ThrowIfNegative(firstNonReservedDiskBlockIndex, "firstNonReservedDiskBlockIndex"); MethodArgumentValidator.ThrowIfNegative(freeSpaceBitmapStartingBlock, "freeSpaceBitmapStartingBlock"); Version = version; BlockSizeInBytes = blockSizeInBytes; FirstNonReservedDiskBlockIndex = firstNonReservedDiskBlockIndex; FreeSpaceBitmapStartingBlock = freeSpaceBitmapStartingBlock; }
/// <summary> /// Копирует указанный файл. /// </summary> /// <param name="fullPathForFileToBeCopied">Полный путь (от корня), указывающий файл, который следует скопировать.</param> /// <param name="newPathThatWillPointToTheCopyOfFile">Полный путь (от корня), указывающий, где будет находиться и как называться копия файла.</param> /// <param name="taskToken"></param> /// <returns>Описание копии файла.</returns> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="FileNotFoundException"></exception> /// <exception cref="FileLockedException"></exception> /// <exception cref="ObjectDisposedException"></exception> /// <exception cref="InvalidPathException"></exception> /// <exception cref="FolderNotFoundException"></exception> /// <exception cref="FileAlreadyExistsException"></exception> /// <exception cref="InsufficientSpaceException"></exception> /// <exception cref="MaximumFileCountReachedException"></exception> /// <exception cref="TaskCancelledException"></exception> internal FileInfo CopyFile(string fullPathForFileToBeCopied, string newPathThatWillPointToTheCopyOfFile, IFileSystemCancellableTaskToken taskToken) { if (taskToken == null) { throw new ArgumentNullException("taskToken"); } MethodArgumentValidator.ThrowIfStringIsNullOrEmpty(fullPathForFileToBeCopied, "fullPathForFileToBeCopied"); MethodArgumentValidator.ThrowIfStringIsNullOrEmpty(newPathThatWillPointToTheCopyOfFile, "newPathThatWillPointToTheCopyOfFile"); if (_namesComparer.Equals(fullPathForFileToBeCopied, newPathThatWillPointToTheCopyOfFile)) { return (new FileInfo(_nodeResolver.ResolveFileNodeByPath(newPathThatWillPointToTheCopyOfFile).ResolvedNode, newPathThatWillPointToTheCopyOfFile)); } lock (_operationExecutionCriticalSection) { ThrowIfDisposed(); // так себе проверка на этот раз. } // Note: не смотрю, хватит ли там места. Хотя отрицательный ответ на такой вопрос мог бы стать поводом, чтобы ничего не копировать. try { CopyFileContents(taskToken, fullPathForFileToBeCopied, newPathThatWillPointToTheCopyOfFile); return (new FileInfo(_nodeResolver.ResolveFileNodeByPath(newPathThatWillPointToTheCopyOfFile).ResolvedNode, newPathThatWillPointToTheCopyOfFile)); } catch (Exception) { try { this.DeleteFile(newPathThatWillPointToTheCopyOfFile); } catch (InvalidPathException) { } catch (ObjectDisposedException) { throw new ObjectDisposedException("Работа с файловой системой была вами завершена принудительным вызовом метода Dispose() - до того, как был докопирован файл. Рекомендуется удалить следующий файл при очередном запуске системы (простите - в текущей версии ничего более удобного не сделано): \"{0}\"".FormatWith(newPathThatWillPointToTheCopyOfFile)); } catch (FileNotFoundException) { } throw; } }
/// <summary> /// Делает из абсолютного пути к папке <paramref name="fullPathToTurnIntoRelative"/>, ее путь относительно папки <paramref name="fullPathForFolderToGetRelativePathAgainst"/>. /// </summary> /// <param name="fullPathForFolderToGetRelativePathAgainst"></param> /// <param name="fullPathToTurnIntoRelative"></param> /// <returns></returns> /// <exception cref="ArgumentException"></exception> /// <exception cref="ArgumentNullException"></exception> internal string GetRelativePath(string fullPathForFolderToGetRelativePathAgainst, string fullPathToTurnIntoRelative) { MethodArgumentValidator.ThrowIfStringIsNullOrEmpty("fullPathForFolderToGetRelativePathAgainst", fullPathForFolderToGetRelativePathAgainst); MethodArgumentValidator.ThrowIfStringIsNullOrEmpty("fullPathToTurnIntoRelative", fullPathToTurnIntoRelative); // Note: ordinal ignore case - выносить надо отсюда. Такие вещи надо настраивать в каком-то одном месте. if (!fullPathToTurnIntoRelative.StartsWith(fullPathForFolderToGetRelativePathAgainst, StringComparison.OrdinalIgnoreCase)) { throw new ArgumentException("Чтобы получить путь одной папки относительно другой, необходимо, чтобы та папка, относительно которой считается путь, была родительской папкой (прямо или косвенно) для той, которой считается путь."); } return (fullPathToTurnIntoRelative .Substring(fullPathForFolderToGetRelativePathAgainst.Length, fullPathToTurnIntoRelative.Length - fullPathForFolderToGetRelativePathAgainst.Length) .TrimStart(new[] { _directorySeparator })); }
/// <summary> /// /// </summary> /// <param name="path"></param> /// <returns></returns> /// <exception cref="ArgumentException"></exception> internal string GetFileOrFolderName(string path) { MethodArgumentValidator.ThrowIfStringIsNullOrEmpty(path, "fullPath"); if (_nameComparer.Equals(_rootPath, path)) { return(path); } if (path.IndexOf(_directorySeparator) < 0) { return(path); } return(path.Remove(0, path.LastIndexOf(_directorySeparator) + 1)); }
/// <summary> /// /// </summary> /// <param name="name"></param> /// <param name="id"></param> /// <param name="diskBlockIndex"></param> /// <param name="version"></param> /// <param name="creationTimeUtc"></param> /// <exception cref="InvalidNameException"></exception> protected Node(string name, Guid id, int diskBlockIndex, Guid version, DateTime creationTimeUtc) { MethodArgumentValidator.ThrowIfIsDefault <Guid>(version, "version"); MethodArgumentValidator.ThrowIfIsDefault <Guid>(id, "id"); MethodArgumentValidator.ThrowIfIsDefault <DateTime>(creationTimeUtc, "creationTimeUtc"); MethodArgumentValidator.ThrowIfDateIsNonUtc(creationTimeUtc, "creationTimeUtc"); this.InitializeValidator(); _nameValidator.Validate(name); _creationTimeUtc = creationTimeUtc; _diskBlockIndex = diskBlockIndex; _id = id; _version = version; _name = name; }
/// <summary> /// Создает новый файл по указанному пути. /// Примечание: в текущей версии не создает недостающие папки. /// </summary> /// <param name="fullPathToFile">Полный путь (включая имя файла), указывающий, где будет находиться новый файл.</param> /// <returns>Сведения о только что созданном файле.</returns> /// <exception cref="InvalidPathException">Если указанный путь невалиден.</exception> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="FolderNotFoundException">Если путь (<paramref name="fullPathToFile"/>), за исключением последней части (имени нового файла), указывает на несуществующую папку.</exception> /// <exception cref="FileAlreadyExistsException"></exception> /// <exception cref="InsufficientSpaceException"></exception> /// <exception cref="MaximumFileCountReachedException"></exception> /// <exception cref="ObjectDisposedException"></exception> public FileInfo CreateFile(string fullPathToFile) { MethodArgumentValidator.ThrowIfStringIsNullOrEmpty(fullPathToFile, "fullPathToFile"); if (_pathBuilder.PointsToRoot(fullPathToFile)) { throw new InvalidPathException("Не удалось создать файл: в качестве пути к файлу нельзя указать корень файловой системы"); } _pathValidator.Validate(fullPathToFile); try { string fileName; var nodeResolvingResult = _nodeResolver.ResolveParentFolderNodeByPath(fullPathToFile, out fileName); FolderNode parentFolder = nodeResolvingResult.ResolvedNode; var newFileInfo = new FileInfo(this.CreateFile(parentFolder, fileName), fullPathToFile); _folderEnumeratorRegistry.InvalidateEnumeratorsFor(nodeResolvingResult.FoldersPassedWhileResolving); return(newFileInfo); } catch (InsufficientSpaceException) { throw new InsufficientSpaceException("Недостаточно свободного места на диске для создания файла."); } catch (MaximumFileSizeReachedException) { throw new MaximumFileCountReachedException("Не удалось добавить файл: папка, в которую вы добавляете файл, не может вместить их больше, чем уже вмещает."); } catch (NoFreeBlocksException) { throw new InsufficientSpaceException("Недостаточно свободного места на диске для создания файла."); } catch (InvalidPathException) { throw new FolderNotFoundException("Не получилось создать файл по указанному пути (\"{0}\"). Не найдена папка, в которой следует создать файл. (В текущей версии недостающие папки не создаются автоматически)".FormatWith(fullPathToFile)); } catch (CannotResolvePathException) { throw new FolderNotFoundException("Не получилось создать файл по указанному пути (\"{0}\"). Не найдена папка, в которой следует создать файл. (В текущей версии недостающие папки не создаются автоматически)".FormatWith(fullPathToFile)); } }
public NodeResolver( IVirtualDisk virtualDisk, FileSystemNodeStorage fileSystemNodeStorage, IEqualityComparer <string> namesComparer, int rootBlockIndex, string rootFolderPath, char directorySeparatorChar, IPathValidator pathValidator, PathBuilder pathBuilder) { if (virtualDisk == null) { throw new ArgumentNullException("virtualDisk"); } if (fileSystemNodeStorage == null) { throw new ArgumentNullException("fileSystemNodeStorage"); } if (namesComparer == null) { throw new ArgumentNullException("namesComparer"); } if (pathBuilder == null) { throw new ArgumentNullException("pathBuilder"); } if (String.IsNullOrEmpty(rootFolderPath)) { throw new ArgumentNullException("rootFolderPath"); } MethodArgumentValidator.ThrowIfNegative(rootBlockIndex, "rootBlockIndex"); if (rootBlockIndex >= virtualDisk.NumberOfBlocks) { throw new ArgumentOutOfRangeException("rootBlockIndex"); } _virtualDisk = virtualDisk; _pathBuilder = pathBuilder; _fileSystemNodeStorage = fileSystemNodeStorage; _namesComparer = namesComparer; _rootBlockIndex = rootBlockIndex; _rootFolderPath = rootFolderPath; _directorySeparatorChar = directorySeparatorChar; _pathValidator = pathValidator; }
/// <summary> /// /// </summary> /// <param name="path"></param> /// <returns></returns> /// <exception cref="FolderNotFoundException"></exception> /// <exception cref="ArgumentNullException"></exception> public ReadOnlyCollection <FileInfo> GetAllFilesFrom(string path) { MethodArgumentValidator.ThrowIfStringIsNullOrEmpty(path, "path"); try { var nodeResolvingResult = this.ResolveFolderNodeByPath(path); FolderNode parentFolder = nodeResolvingResult.ResolvedNode; return(this.GetAllFilesFrom(parentFolder).Select(file => new FileInfo(file, _pathBuilder.CombinePaths(path, file.Name))).ToList().AsReadOnly()); } catch (InvalidPathException exception) { throw new FolderNotFoundException("Не удалось получить файлы, содержащиеся в папке \"{0}\". {1}".FormatWith(path, exception.Message)); } }
/// <summary> /// Удаляет указанный файл. /// </summary> /// <param name="filePath">Путь, указывающий удаляемый файл.</param> /// <exception cref="FileNotFoundException"></exception> /// <exception cref="FileLockedException"></exception> /// <exception cref="InvalidPathException"></exception> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="ObjectDisposedException"></exception> public void DeleteFile(string filePath) { MethodArgumentValidator.ThrowIfStringIsNullOrEmpty(filePath, "filePath"); if (_pathBuilder.PointsToRoot(filePath)) { throw new InvalidPathException("Не получилось удалить файл: нельзя удалить корень файловой системы."); } try { string fileName; var parentFolderResolvingResult = _nodeResolver.ResolveParentFolderNodeByPath(filePath, out fileName); ReadOnlyCollection <FileNode> files; FolderNode folderToRemoveFileFrom = parentFolderResolvingResult.ResolvedNode; FileNode fileToRemove = ResolveFileNodeThrowingUserFriendlyErrors(filePath, parentFolderResolvingResult, fileName, "удалить", out files); // очистка всех данных. using (var dataStream = this.OpenFileForWriting(filePath)) { dataStream.Truncate(); } // TODO: поглядеть на исключения этого метода. _blockReferenceListsEditor.TakeOutABlockFromBlockReferenceList(folderToRemoveFileFrom, fileToRemove.DiskBlockIndex, folderToRemoveFileFrom.FileReferencesStreamDefinition); _freeBlockManager.MarkBlockAsFree(fileToRemove.DiskBlockIndex); _freeBlockManager.MarkBlockAsFree(fileToRemove.FileContentsStreamDefinition.ContentsBlockIndex); _folderEnumeratorRegistry.InvalidateEnumeratorsFor(parentFolderResolvingResult.FoldersPassedWhileResolving); _folderEnumeratorRegistry.InvalidateEnumeratorsForFolder(parentFolderResolvingResult.ResolvedNode.Id); } catch (CannotResolvePathException) { throw new FileNotFoundException("Не удалось найти файл {0}".FormatWith(filePath)); } catch (InvalidPathException) { throw new FileNotFoundException("Не удалось найти файл {0}".FormatWith(filePath)); } }