public override int Overwrite(object fileNode, object fileDesc, uint fileAttributes, bool replaceFileAttributes, ulong allocationSize, out FileInfo fileInfo) { if (fileNode is FileNode node && fileDesc is FileMetadata metadata) { Logger.LogTrace($"{nameof ( Overwrite )} \"{metadata . Name}\"."); metadata.Size = 0; if (replaceFileAttributes) { metadata.Attributes = fileAttributes; } else { metadata.Attributes |= fileAttributes; } FlushMetadata( ); fileInfo = metadata.FileInfo; return(STATUS_SUCCESS); } throw GetIoExceptionWithNtStatus(STATUS_INVALID_HANDLE); }
public override int Flush(object fileNode, object fileDesc, out FileInfo fileInfo) { Logger.LogTrace($"{nameof ( Flush )} {( fileDesc as FileMetadata ) ? . Name}"); if (fileNode is FileNode node) { OnetimeTask flushTask = new OnetimeTask(node.Flush, default); TaskDispatcher.Dispatch(flushTask); } FlushMetadata( ); if (fileDesc is FileMetadata metadata) { fileInfo = metadata.FileInfo; } else { throw GetIoExceptionWithNtStatus(STATUS_INVALID_HANDLE); } return(STATUS_SUCCESS); }
public override bool ReadDirectoryEntry(object fileNode, object fileDesc, string pattern, string marker, ref object context, out string fileName, out FileInfo fileInfo) { if (fileDesc is FileMetadata metadata) { if (!(context is EnumerateDirectoryContext currentContext)) { Logger.LogTrace( $"{nameof ( ReadDirectoryEntry )} of \"{metadata . Name}\"."); if (null != pattern) { pattern = pattern.Replace('<', '*'). Replace('>', '?'). Replace('"', '.'); } else { pattern = "*"; } Regex fileNamePatternRegex = FindFilesPatternToRegex.Convert(pattern); string pathPrefix; if (metadata.Name.EndsWith("\\")) { pathPrefix = metadata.Name; } else { pathPrefix = $"{metadata . Name}\\"; } string escapedPathPrefix = Regex.Escape(pathPrefix); Regex pathPrefixRegex = new Regex( @$ "^{escapedPathPrefix}([^\\]+)$", RegexOptions.Compiled); IEnumerable <FileMetadata> fileInFolder; lock ( DataContext ) { fileInFolder = DataContext. FileMetadata. Where((fileMetadata) => !fileMetadata.IsDeleted). Where( fileMetadata => fileMetadata. Name.StartsWith(pathPrefix)). OrderBy(fileMetadata => fileMetadata.Name). AsEnumerable( ); } List <(string FileName, FileMetadata FileMetadata)> availableFiles = fileInFolder.Select( fileMetadata => { Match pathPrefixMatch = pathPrefixRegex.Match( fileMetadata. Name); if (pathPrefixMatch.Success) { string matchedFileName = pathPrefixMatch. Groups [1]. Value; Match fileNameMatch = fileNamePatternRegex.Match( matchedFileName); if (fileNameMatch.Success) { return(FileName: matchedFileName, FileMetadata: fileMetadata); } } return(default);
public override int Write(object fileNode, object fileDesc, IntPtr buffer, ulong offset, uint length, bool writeToEndOfFile, bool constrainedIo, out uint bytesTransferred, out FileInfo fileInfo) { if (fileNode is FileNode node && fileDesc is FileMetadata metadata) { Logger.LogTrace( $"Request {nameof ( Write )} to \"{metadata . Name}\", start from {offset} with length {length}({( ( long ) length ) . BytesCountToHumanString ( )})."); if (writeToEndOfFile) { offset = ( ulong )metadata.Size; } if (!constrainedIo) { ResizeFile( node, Math.Max(metadata.Size, ( long )offset + length)); length = ( uint )Math.Min(metadata.Size - ( long )offset, length); } int startBlockSequence = ( int )(offset / ( ulong )BlockSize); int endBlockSequence = ( int )((offset + length + ( ulong )BlockSize - 1) / ( ulong )BlockSize); int currentByteSequence = 0; int currentBlockSequence = startBlockSequence; CachedBlock currentBlock = node.GetBlock(currentBlockSequence); #region firstBlock int firstByteStartFrom = ( int )(offset % ( ulong )BlockSize); int currentBlockCopyByteCount = ( int )Math.Min( BlockSize - firstByteStartFrom, length - currentByteSequence); currentBlock.IsModified = true; Marshal.Copy( buffer + currentByteSequence, currentBlock.Content, firstByteStartFrom, currentBlockCopyByteCount); currentByteSequence += currentBlockCopyByteCount; currentBlockSequence++; #endregion firstByteStartFrom = 0; for ( ; currentBlockSequence < endBlockSequence; currentBlockSequence++) { currentBlock = node.GetBlock(currentBlockSequence); currentBlockCopyByteCount = ( int )Math.Min( BlockSize - firstByteStartFrom, length - currentByteSequence); currentBlock.IsModified = true; Marshal.Copy( buffer + currentByteSequence, currentBlock.Content, firstByteStartFrom, currentBlockCopyByteCount); currentByteSequence += currentBlockCopyByteCount; } bytesTransferred = ( uint )currentByteSequence; fileInfo = metadata.FileInfo; Logger.LogDebug( $"Written to \"{metadata . Name}\", start from {offset} with length {bytesTransferred}({( ( long ) bytesTransferred ) . BytesCountToHumanString ( )})."); return(STATUS_SUCCESS); } throw GetIoExceptionWithNtStatus(STATUS_INVALID_HANDLE); }
public override int Create(string fileName, uint createOptions, uint grantedAccess, uint fileAttributes, byte [] securityDescriptor, ulong allocationSize, out object fileNode, out object fileDesc, out FileInfo fileInfo, out string normalizedName) { string normalizedFileName = fileName.Normalize(NormalizationForm.FormD).TrimEnd('\\'); List <string> directoryDependency = normalizedFileName. Split( '\\', StringSplitOptions.RemoveEmptyEntries). SkipLast(1). ToList( ); StringBuilder currentDirectory = new StringBuilder("\\"); foreach (string path in directoryDependency) { currentDirectory.Append(path); string currentDirectoryFileName = currentDirectory.ToString( ); FileMetadata directoryMetadata; lock ( DataContext ) { directoryMetadata = DataContext.FileMetadata.SingleOrDefault( fileMetadata => fileMetadata. Name == currentDirectoryFileName); } if (directoryMetadata is null) { CreateDirectory(currentDirectoryFileName); } currentDirectory.Append('\\'); } FileMetadata metadata; lock ( DataContext ) { metadata = DataContext.FileMetadata.SingleOrDefault( (fileMetadata) => fileMetadata.Name == normalizedFileName); } if (metadata != null) { if ((createOptions & FILE_DIRECTORY_FILE) != 0) { //Directory fileNode = null; } else { //File if (FileNodes.TryGetValue(metadata.Guid, out FileNode node)) { node.ReferenceCount++; node.ClosedTime = null; fileNode = node; } else { node = new FileNode(metadata); lock ( DataContext ) { node.Blocks = DataContext.BlockMetadata. Where( block => block.File == metadata.Guid). OrderBy( block => block.BlockSequence). ToList( ); } lock ( FileNodes ) { FileNodes.Add(metadata.Guid, node); } fileNode = node; } } } else { if ((createOptions & FILE_DIRECTORY_FILE) != 0) { //Directory metadata = CreateDirectory( normalizedFileName, fileAttributes, securityDescriptor); fileNode = null; } else { //File int allocatedBlockCount = ( int )((( long )allocationSize + BlockSize - 1) / BlockSize); metadata = CreateFile( normalizedFileName, allocatedBlockCount, fileAttributes, securityDescriptor); List <BlockMetadata> blocks = new List <BlockMetadata> (allocatedBlockCount); for (int sequenceNumber = 0; sequenceNumber < allocatedBlockCount; sequenceNumber++) { blocks.Add(CreateBlock(metadata.Guid, sequenceNumber)); } FileNode node = new FileNode(metadata) { Blocks = blocks }; FileNodes.Add(metadata.Guid, node); fileNode = node; FlushMetadata( ); } } fileDesc = metadata; fileInfo = metadata.FileInfo; normalizedName = normalizedFileName; return(STATUS_SUCCESS); }