From 5579428b4f1361481dae3ea0b901c0a915401148 Mon Sep 17 00:00:00 2001 From: Trevor Thompson Date: Thu, 27 Jul 2017 18:22:24 +0000 Subject: [PATCH] [NTFS] - Add some utility functions and improve some comments. Improve NtfsAddFilenameToDirectory(). +PrintAllVCNs() - Diagnostic function which prints VCN of every node in an index allocation. +GetAllocationOffsetFromVCN() - Calculates location of an index buffer from the node's VCN. +GetInfoClassName() - Gets a string representation of an info class enumeration, to speed up development of unimplemented classes. -NtfsSetInformation() & NtfsQueryInformation() - Use GetInfoClassName to report unhandled information classes. -CompareTreeKeys() - Add a comment and clarify some comments. -NtfsAddFilenameToDirectory() - Don't try to update the size of Index Root on disk if the attribute length hasn't changed. svn path=/branches/GSoC_2016/NTFS/; revision=75424 --- drivers/filesystems/ntfs/btree.c | 46 ++++++++++- drivers/filesystems/ntfs/finfo.c | 128 ++++++++++++++++++++++++++++++- drivers/filesystems/ntfs/mft.c | 38 +++++---- drivers/filesystems/ntfs/ntfs.h | 16 ++++ 4 files changed, 206 insertions(+), 22 deletions(-) diff --git a/drivers/filesystems/ntfs/btree.c b/drivers/filesystems/ntfs/btree.c index a7eacb3173c..38fa9aefee7 100644 --- a/drivers/filesystems/ntfs/btree.c +++ b/drivers/filesystems/ntfs/btree.c @@ -32,6 +32,47 @@ /* FUNCTIONS ****************************************************************/ +// TEMP FUNCTION for diagnostic purposes. +// Prints VCN of every node in an index allocation +VOID +PrintAllVCNs(PDEVICE_EXTENSION Vcb, + PNTFS_ATTR_CONTEXT IndexAllocationContext, + ULONG NodeSize) +{ + ULONGLONG CurrentOffset = 0; + PINDEX_BUFFER CurrentNode, Buffer; + ULONGLONG BufferSize = AttributeDataLength(&IndexAllocationContext->Record); + ULONGLONG i; + int Count = 0; + + Buffer = ExAllocatePoolWithTag(NonPagedPool, BufferSize, TAG_NTFS); + + ULONG BytesRead = ReadAttribute(Vcb, IndexAllocationContext, 0, (PCHAR)Buffer, BufferSize); + + ASSERT(BytesRead = BufferSize); + + CurrentNode = Buffer; + + // loop through all the nodes + for (i = 0; i < BufferSize; i += NodeSize) + { + NTSTATUS Status = FixupUpdateSequenceArray(Vcb, &CurrentNode->Ntfs); + if (!NT_SUCCESS(Status)) + { + DPRINT1("ERROR: Fixing fixup failed!\n"); + continue; + } + + DPRINT1("Node #%d, VCN: %I64u\n", Count, CurrentNode->VCN); + + CurrentNode = (PINDEX_BUFFER)((ULONG_PTR)CurrentNode + NodeSize); + CurrentOffset += NodeSize; + Count++; + } + + ExFreePoolWithTag(Buffer, TAG_NTFS); +} + /** * @name CompareTreeKeys * @implemented @@ -62,6 +103,7 @@ CompareTreeKeys(PB_TREE_KEY Key1, PB_TREE_KEY Key2, BOOLEAN CaseSensitive) UNICODE_STRING Key1Name, Key2Name; LONG Comparison; + // Key1 must not be the final key (AKA the dummy key) ASSERT(!(Key1->IndexEntry->Flags & NTFS_INDEX_ENTRY_END)); // If Key2 is the "dummy key", key 1 will always come first @@ -89,7 +131,7 @@ CompareTreeKeys(PB_TREE_KEY Key1, PB_TREE_KEY Key2, BOOLEAN CaseSensitive) // Compare the names of the same length Comparison = RtlCompareUnicodeString(&Key1Name, &Key2Name, !CaseSensitive); - // If the truncated files are the same length, the shorter one comes first + // If the truncated names are the same length, the shorter one comes first if (Comparison == 0) return -1; } @@ -102,7 +144,7 @@ CompareTreeKeys(PB_TREE_KEY Key1, PB_TREE_KEY Key2, BOOLEAN CaseSensitive) // Compare the names of the same length Comparison = RtlCompareUnicodeString(&Key1Name, &Key2Name, !CaseSensitive); - // If the truncated files are the same length, the shorter one comes first + // If the truncated names are the same length, the shorter one comes first if (Comparison == 0) return 1; } diff --git a/drivers/filesystems/ntfs/finfo.c b/drivers/filesystems/ntfs/finfo.c index 323b85cf45d..aee8aa51e2d 100644 --- a/drivers/filesystems/ntfs/finfo.c +++ b/drivers/filesystems/ntfs/finfo.c @@ -289,6 +289,128 @@ NtfsGetSteamInformation(PNTFS_FCB Fcb, return Status; } +// Convert enum value to friendly name +const PCSTR +GetInfoClassName(FILE_INFORMATION_CLASS infoClass) +{ + const PCSTR fileInfoClassNames[] = { "???????", + "FileDirectoryInformation", + "FileFullDirectoryInformation", + "FileBothDirectoryInformation", + "FileBasicInformation", + "FileStandardInformation", + "FileInternalInformation", + "FileEaInformation", + "FileAccessInformation", + "FileNameInformation", + "FileRenameInformation", + "FileLinkInformation", + "FileNamesInformation", + "FileDispositionInformation", + "FilePositionInformation", + "FileFullEaInformation", + "FileModeInformation", + "FileAlignmentInformation", + "FileAllInformation", + "FileAllocationInformation", + "FileEndOfFileInformation", + "FileAlternateNameInformation", + "FileStreamInformation", + "FilePipeInformation", + "FilePipeLocalInformation", + "FilePipeRemoteInformation", + "FileMailslotQueryInformation", + "FileMailslotSetInformation", + "FileCompressionInformation", + "FileObjectIdInformation", + "FileCompletionInformation", + "FileMoveClusterInformation", + "FileQuotaInformation", + "FileReparsePointInformation", + "FileNetworkOpenInformation", + "FileAttributeTagInformation", + "FileTrackingInformation", + "FileIdBothDirectoryInformation", + "FileIdFullDirectoryInformation", + "FileValidDataLengthInformation", + "FileShortNameInformation", + "FileIoCompletionNotificationInformation", + "FileIoStatusBlockRangeInformation", + "FileIoPriorityHintInformation", + "FileSfioReserveInformation", + "FileSfioVolumeInformation", + "FileHardLinkInformation", + "FileProcessIdsUsingFileInformation", + "FileNormalizedNameInformation", + "FileNetworkPhysicalNameInformation", + "FileIdGlobalTxDirectoryInformation", + "FileIsRemoteDeviceInformation", + "FileAttributeCacheInformation", + "FileNumaNodeInformation", + "FileStandardLinkInformation", + "FileRemoteProtocolInformation", + "FileReplaceCompletionInformation", + "FileMaximumInformation", + "FileDirectoryInformation", + "FileFullDirectoryInformation", + "FileBothDirectoryInformation", + "FileBasicInformation", + "FileStandardInformation", + "FileInternalInformation", + "FileEaInformation", + "FileAccessInformation", + "FileNameInformation", + "FileRenameInformation", + "FileLinkInformation", + "FileNamesInformation", + "FileDispositionInformation", + "FilePositionInformation", + "FileFullEaInformation", + "FileModeInformation", + "FileAlignmentInformation", + "FileAllInformation", + "FileAllocationInformation", + "FileEndOfFileInformation", + "FileAlternateNameInformation", + "FileStreamInformation", + "FilePipeInformation", + "FilePipeLocalInformation", + "FilePipeRemoteInformation", + "FileMailslotQueryInformation", + "FileMailslotSetInformation", + "FileCompressionInformation", + "FileObjectIdInformation", + "FileCompletionInformation", + "FileMoveClusterInformation", + "FileQuotaInformation", + "FileReparsePointInformation", + "FileNetworkOpenInformation", + "FileAttributeTagInformation", + "FileTrackingInformation", + "FileIdBothDirectoryInformation", + "FileIdFullDirectoryInformation", + "FileValidDataLengthInformation", + "FileShortNameInformation", + "FileIoCompletionNotificationInformation", + "FileIoStatusBlockRangeInformation", + "FileIoPriorityHintInformation", + "FileSfioReserveInformation", + "FileSfioVolumeInformation", + "FileHardLinkInformation", + "FileProcessIdsUsingFileInformation", + "FileNormalizedNameInformation", + "FileNetworkPhysicalNameInformation", + "FileIdGlobalTxDirectoryInformation", + "FileIsRemoteDeviceInformation", + "FileAttributeCacheInformation", + "FileNumaNodeInformation", + "FileStandardLinkInformation", + "FileRemoteProtocolInformation", + "FileReplaceCompletionInformation", + "FileMaximumInformation" }; + return fileInfoClassNames[infoClass]; +} + /* * FUNCTION: Retrieve the specified file information */ @@ -376,12 +498,12 @@ NtfsQueryInformation(PNTFS_IRP_CONTEXT IrpContext) case FileAlternateNameInformation: case FileAllInformation: - DPRINT1("Unimplemented information class %u\n", FileInformationClass); + DPRINT1("Unimplemented information class: %s\n", GetInfoClassName(FileInformationClass)); Status = STATUS_NOT_IMPLEMENTED; break; default: - DPRINT1("Unimplemented information class %u\n", FileInformationClass); + DPRINT1("Unimplemented information class: %s\n", GetInfoClassName(FileInformationClass)); Status = STATUS_INVALID_PARAMETER; } @@ -645,7 +767,7 @@ NtfsSetInformation(PNTFS_IRP_CONTEXT IrpContext) // TODO: all other information classes default: - DPRINT1("FIXME: Unimplemented information class %u\n", FileInformationClass); + DPRINT1("FIXME: Unimplemented information class: %s\n", GetInfoClassName(FileInformationClass)); Status = STATUS_NOT_IMPLEMENTED; } diff --git a/drivers/filesystems/ntfs/mft.c b/drivers/filesystems/ntfs/mft.c index 72953c00868..928839edd78 100644 --- a/drivers/filesystems/ntfs/mft.c +++ b/drivers/filesystems/ntfs/mft.c @@ -2018,25 +2018,29 @@ NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt, // we must create an index allocation and index bitmap (TODO). Also TODO: support file records with // $ATTRIBUTE_LIST's. AttributeLength = NewIndexRoot->Header.AllocatedSize + FIELD_OFFSET(INDEX_ROOT_ATTRIBUTE, Header); - DestinationAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)ParentFileRecord + IndexRootOffset); - - // Find the attribute (or attribute-end marker) after the index root - NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)DestinationAttribute + DestinationAttribute->Length); - if (NextAttribute->Type != AttributeEnd) + + if (AttributeLength != IndexRootContext->Record.Resident.ValueLength) { - DPRINT1("FIXME: For now, only resizing index root at the end of a file record is supported!\n"); - ExFreePoolWithTag(NewIndexRoot, TAG_NTFS); - ReleaseAttributeContext(IndexRootContext); - ExFreePoolWithTag(I30IndexRoot, TAG_NTFS); - ExFreePoolWithTag(ParentFileRecord, TAG_NTFS); - return STATUS_NOT_IMPLEMENTED; - } + DestinationAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)ParentFileRecord + IndexRootOffset); - // Update the length of the attribute in the file record of the parent directory - InternalSetResidentAttributeLength(IndexRootContext, - ParentFileRecord, - IndexRootOffset, - AttributeLength); + // Find the attribute (or attribute-end marker) after the index root + NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)DestinationAttribute + DestinationAttribute->Length); + if (NextAttribute->Type != AttributeEnd) + { + DPRINT1("FIXME: For now, only resizing index root at the end of a file record is supported!\n"); + ExFreePoolWithTag(NewIndexRoot, TAG_NTFS); + ReleaseAttributeContext(IndexRootContext); + ExFreePoolWithTag(I30IndexRoot, TAG_NTFS); + ExFreePoolWithTag(ParentFileRecord, TAG_NTFS); + return STATUS_NOT_IMPLEMENTED; + } + + // Update the length of the attribute in the file record of the parent directory + InternalSetResidentAttributeLength(IndexRootContext, + ParentFileRecord, + IndexRootOffset, + AttributeLength); + } NT_ASSERT(ParentFileRecord->BytesInUse <= DeviceExt->NtfsInfo.BytesPerFileRecord); diff --git a/drivers/filesystems/ntfs/ntfs.h b/drivers/filesystems/ntfs/ntfs.h index 9cbc4d54858..39c33210fcf 100644 --- a/drivers/filesystems/ntfs/ntfs.h +++ b/drivers/filesystems/ntfs/ntfs.h @@ -208,6 +208,9 @@ typedef enum #define INDEX_ROOT_SMALL 0x0 #define INDEX_ROOT_LARGE 0x1 +#define INDEX_NODE_SMALL 0x0 +#define INDEX_NODE_LARGE 0x1 + #define NTFS_INDEX_ENTRY_NODE 1 #define NTFS_INDEX_ENTRY_END 2 @@ -700,9 +703,22 @@ CreateIndexRootFromBTree(PDEVICE_EXTENSION DeviceExt, VOID DestroyBTree(PB_TREE Tree); +VOID +DestroyBTreeNode(PB_TREE_FILENAME_NODE Node); + VOID DumpBTree(PB_TREE Tree); +VOID +DumpBTreeNode(PB_TREE_FILENAME_NODE Node, + ULONG Number, + ULONG Depth); + +ULONGLONG +GetAllocationOffsetFromVCN(PDEVICE_EXTENSION DeviceExt, + ULONG IndexBufferSize, + ULONGLONG Vcn); + NTSTATUS NtfsInsertKey(ULONGLONG FileReference, PFILENAME_ATTRIBUTE FileNameAttribute, -- 2.17.1