https://git.reactos.org/?p=reactos.git;a=commitdiff;h=935fcd1b353a65d3af01e…
commit 935fcd1b353a65d3af01e3f9061d3784f759cdbc
Author: Trevor Thompson <tmt256(a)email.vccs.edu>
AuthorDate: Tue Jul 18 19:59:36 2017 +0000
[NTFS] - Fix some more issues, including remaining issues marked as
"unresolved" from CR-123:
-Add define for indexed flag for resident attributes, RA_INDEXED.
-CreateBTreeFromIndex() - Don't try to read index entries beyond attribute
length.
-Move NtfsAddFileNameToDirectory() from dirctl.c to mft.c (no changes to function).
-SetResidentAttributeDataLength() - Don't try to free AttribData if it hasn't
been allocated. Cast IndexRecord to PUCHAR for WriteAttribute(), and cast BitmapData to
PCHAR for ReadAttribute() (make gcc happy).
-Replace magic number 16 with a define, NTFS_FILE_FIRST_USER_FILE.
svn path=/branches/GSoC_2016/NTFS/; revision=75371
---
drivers/filesystems/ntfs/attrib.c | 2 +-
drivers/filesystems/ntfs/btree.c | 30 +++--
drivers/filesystems/ntfs/create.c | 4 +-
drivers/filesystems/ntfs/dirctl.c | 245 ------------------------------------
drivers/filesystems/ntfs/mft.c | 256 +++++++++++++++++++++++++++++++++++++-
drivers/filesystems/ntfs/ntfs.h | 18 +--
6 files changed, 284 insertions(+), 271 deletions(-)
diff --git a/drivers/filesystems/ntfs/attrib.c b/drivers/filesystems/ntfs/attrib.c
index bd070c97ad..a6bc9a8aca 100644
--- a/drivers/filesystems/ntfs/attrib.c
+++ b/drivers/filesystems/ntfs/attrib.c
@@ -245,7 +245,7 @@ AddFileName(PFILE_RECORD_HEADER FileRecord,
AttributeAddress->Resident.ValueLength = FIELD_OFFSET(FILENAME_ATTRIBUTE, Name) +
FilenameNoPath.Length;
AttributeAddress->Resident.ValueOffset = ResidentHeaderLength;
- AttributeAddress->Resident.Flags = 1; // indexed
+ AttributeAddress->Resident.Flags = RA_INDEXED;
// move the attribute-end and file-record-end markers to the end of the file record
AttributeAddress = (PNTFS_ATTR_RECORD)((ULONG_PTR)AttributeAddress +
AttributeAddress->Length);
diff --git a/drivers/filesystems/ntfs/btree.c b/drivers/filesystems/ntfs/btree.c
index 179107272b..a7eacb3173 100644
--- a/drivers/filesystems/ntfs/btree.c
+++ b/drivers/filesystems/ntfs/btree.c
@@ -138,6 +138,7 @@ CreateBTreeFromIndex(PNTFS_ATTR_CONTEXT IndexRootContext,
PB_TREE Tree = ExAllocatePoolWithTag(NonPagedPool, sizeof(B_TREE), TAG_NTFS);
PB_TREE_FILENAME_NODE RootNode = ExAllocatePoolWithTag(NonPagedPool,
sizeof(B_TREE_FILENAME_NODE), TAG_NTFS);
PB_TREE_KEY CurrentKey = ExAllocatePoolWithTag(NonPagedPool, sizeof(B_TREE_KEY),
TAG_NTFS);
+ ULONG CurrentOffset = IndexRoot->Header.FirstEntryOffset;
DPRINT1("CreateBTreeFromIndex(%p, %p, %p)\n", IndexRootContext, IndexRoot,
NewTree);
@@ -161,11 +162,21 @@ CreateBTreeFromIndex(PNTFS_ATTR_CONTEXT IndexRootContext,
RootNode->FirstKey = CurrentKey;
Tree->RootNode = RootNode;
- // Create a key for each entry in the node
+ // Make sure we won't try reading past the attribute-end
+ if (FIELD_OFFSET(INDEX_ROOT_ATTRIBUTE, Header) +
IndexRoot->Header.TotalSizeOfEntries >
IndexRootContext->Record.Resident.ValueLength)
+ {
+ DPRINT1("Filesystem corruption detected!\n");
+ DestroyBTree(Tree);
+ return STATUS_FILE_CORRUPT_ERROR;
+ }
+
+ // Start at the first node entry
CurrentNodeEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)IndexRoot
+ FIELD_OFFSET(INDEX_ROOT_ATTRIBUTE,
Header)
+
IndexRoot->Header.FirstEntryOffset);
- while (TRUE)
+
+ // Create a key for each entry in the node
+ while (CurrentOffset < IndexRoot->Header.TotalSizeOfEntries)
{
// Allocate memory for the current entry
CurrentKey->IndexEntry = ExAllocatePoolWithTag(NonPagedPool,
CurrentNodeEntry->Length, TAG_NTFS);
@@ -207,6 +218,7 @@ CreateBTreeFromIndex(PNTFS_ATTR_CONTEXT IndexRootContext,
}
// Advance to the next entry
+ CurrentOffset += CurrentNodeEntry->Length;
CurrentNodeEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)CurrentNodeEntry +
CurrentNodeEntry->Length);
CurrentKey = NextKey;
}
@@ -336,7 +348,7 @@ CreateIndexRootFromBTree(PDEVICE_EXTENSION DeviceExt,
// Add Length of Current Entry to Total Size of Entries
NewIndexRoot->Header.TotalSizeOfEntries += CurrentNodeEntry->Length;
- // Go to the next node
+ // Go to the next node entry
CurrentNodeEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)CurrentNodeEntry +
CurrentNodeEntry->Length);
CurrentKey = CurrentKey->NextKey;
@@ -533,16 +545,12 @@ NtfsInsertKey(ULONGLONG FileReference,
{
// Should the New Key go before the current key?
LONG Comparison = CompareTreeKeys(NewKey, CurrentKey, CaseSensitive);
- if (Comparison == 0)
- {
- DPRINT1("DRIVER ERROR: Asked to insert key into tree that already has
it!\n");
- ExFreePoolWithTag(NewKey, TAG_NTFS);
- ExFreePoolWithTag(NewEntry, TAG_NTFS);
- return STATUS_INVALID_PARAMETER;
- }
+
+ ASSERT(Comparison != 0);
+
+ // Is NewKey < CurrentKey?
if (Comparison < 0)
{
- // NewKey is < CurrentKey
// Insert New Key before Current Key
NewKey->NextKey = CurrentKey;
diff --git a/drivers/filesystems/ntfs/create.c b/drivers/filesystems/ntfs/create.c
index 30cc921095..f5ca1027fc 100644
--- a/drivers/filesystems/ntfs/create.c
+++ b/drivers/filesystems/ntfs/create.c
@@ -185,7 +185,7 @@ NtfsOpenFileById(PDEVICE_EXTENSION DeviceExt,
DPRINT1("NtfsOpenFileById(%p, %p, %I64x, %p)\n", DeviceExt, FileObject,
MftId, FoundFCB);
- ASSERT(MftId < 0x10);
+ ASSERT(MftId < NTFS_FILE_FIRST_USER_FILE);
if (MftId > 0xb) /* No entries are used yet beyond this */
{
return STATUS_OBJECT_NAME_NOT_FOUND;
@@ -375,7 +375,7 @@ NtfsCreateFile(PDEVICE_OBJECT DeviceObject,
return STATUS_INVALID_PARAMETER;
MFTId = (*(PULONGLONG)FileObject->FileName.Buffer) & NTFS_MFT_MASK;
- if (MFTId < 0x10)
+ if (MFTId < NTFS_FILE_FIRST_USER_FILE)
{
Status = NtfsOpenFileById(DeviceExt, FileObject, MFTId, &Fcb);
}
diff --git a/drivers/filesystems/ntfs/dirctl.c b/drivers/filesystems/ntfs/dirctl.c
index c41688ea2b..98294b4791 100644
--- a/drivers/filesystems/ntfs/dirctl.c
+++ b/drivers/filesystems/ntfs/dirctl.c
@@ -34,251 +34,6 @@
/* FUNCTIONS ****************************************************************/
-/**
-* @name NtfsAddFilenameToDirectory
-* @implemented
-*
-* Adds a $FILE_NAME attribute to a given directory index.
-*
-* @param DeviceExt
-* Points to the target disk's DEVICE_EXTENSION.
-*
-* @param DirectoryMftIndex
-* Mft index of the parent directory which will receive the file.
-*
-* @param FileReferenceNumber
-* File reference of the file to be added to the directory. This is a combination of the
-* Mft index and sequence number.
-*
-* @param FilenameAttribute
-* Pointer to the FILENAME_ATTRIBUTE of the file being added to the directory.
-*
-* @param CaseSensitive
-* Boolean indicating if the function should operate in case-sensitive mode. This will be
TRUE
-* if an application created the file with the FILE_FLAG_POSIX_SEMANTICS flag.
-*
-* @return
-* STATUS_SUCCESS on success.
-* STATUS_INSUFFICIENT_RESOURCES if an allocation fails.
-* STATUS_NOT_IMPLEMENTED if target address isn't at the end of the given file
record.
-*
-* @remarks
-* WIP - Can only support a few files in a directory.
-* One FILENAME_ATTRIBUTE is added to the directory's index for each link to that
file. So, each
-* file which contains one FILENAME_ATTRIBUTE for a long name and another for the 8.3
name, will
-* get both attributes added to its parent directory.
-*/
-NTSTATUS
-NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt,
- ULONGLONG DirectoryMftIndex,
- ULONGLONG FileReferenceNumber,
- PFILENAME_ATTRIBUTE FilenameAttribute,
- BOOLEAN CaseSensitive)
-{
- NTSTATUS Status = STATUS_SUCCESS;
- PFILE_RECORD_HEADER ParentFileRecord;
- PNTFS_ATTR_CONTEXT IndexRootContext;
- PINDEX_ROOT_ATTRIBUTE I30IndexRoot;
- ULONG IndexRootOffset;
- ULONGLONG I30IndexRootLength;
- ULONG LengthWritten;
- PNTFS_ATTR_RECORD DestinationAttribute;
- PINDEX_ROOT_ATTRIBUTE NewIndexRoot;
- ULONG AttributeLength;
- PNTFS_ATTR_RECORD NextAttribute;
- PB_TREE NewTree;
- ULONG BtreeIndexLength;
- ULONG MaxIndexSize;
-
- // Allocate memory for the parent directory
- ParentFileRecord = ExAllocatePoolWithTag(NonPagedPool,
- DeviceExt->NtfsInfo.BytesPerFileRecord,
- TAG_NTFS);
- if (!ParentFileRecord)
- {
- DPRINT1("ERROR: Couldn't allocate memory for file record!\n");
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- // Open the parent directory
- Status = ReadFileRecord(DeviceExt, DirectoryMftIndex, ParentFileRecord);
- if (!NT_SUCCESS(Status))
- {
- ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
- DPRINT1("ERROR: Couldn't read parent directory with index
%I64u\n",
- DirectoryMftIndex);
- return Status;
- }
-
- DPRINT1("Dumping old parent file record:\n");
- NtfsDumpFileRecord(DeviceExt, ParentFileRecord);
-
- // Find the index root attribute for the directory
- Status = FindAttribute(DeviceExt,
- ParentFileRecord,
- AttributeIndexRoot,
- L"$I30",
- 4,
- &IndexRootContext,
- &IndexRootOffset);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("ERROR: Couldn't find $I30 $INDEX_ROOT attribute for parent
directory with MFT #: %I64u!\n",
- DirectoryMftIndex);
- ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
- return Status;
- }
-
- // Find the maximum index size given what the file record can hold
- MaxIndexSize = DeviceExt->NtfsInfo.BytesPerFileRecord
- - IndexRootOffset
- - IndexRootContext->Record.Resident.ValueOffset
- - FIELD_OFFSET(INDEX_ROOT_ATTRIBUTE, Header)
- - (sizeof(ULONG) * 2);
-
- // Allocate memory for the index root data
- I30IndexRootLength = AttributeDataLength(&IndexRootContext->Record);
- I30IndexRoot = ExAllocatePoolWithTag(NonPagedPool, I30IndexRootLength, TAG_NTFS);
- if (!I30IndexRoot)
- {
- DPRINT1("ERROR: Couldn't allocate memory for index root
attribute!\n");
- ReleaseAttributeContext(IndexRootContext);
- ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- // Read the Index Root
- Status = ReadAttribute(DeviceExt, IndexRootContext, 0, (PCHAR)I30IndexRoot,
I30IndexRootLength);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("ERROR: Couln't read index root attribute for Mft index
#%I64u\n", DirectoryMftIndex);
- ReleaseAttributeContext(IndexRootContext);
- ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
- ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
- return Status;
- }
-
- // Convert the index to a B*Tree
- Status = CreateBTreeFromIndex(IndexRootContext, I30IndexRoot, &NewTree);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("ERROR: Failed to create B-Tree from Index!\n");
- ReleaseAttributeContext(IndexRootContext);
- ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
- ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
- return Status;
- }
-
- DumpBTree(NewTree);
-
- // Insert the key for the file we're adding
- Status = NtfsInsertKey(FileReferenceNumber, FilenameAttribute, NewTree->RootNode,
CaseSensitive);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("ERROR: Failed to insert key into B-Tree!\n");
- DestroyBTree(NewTree);
- ReleaseAttributeContext(IndexRootContext);
- ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
- ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
- return Status;
- }
-
- DumpBTree(NewTree);
-
- // Convert B*Tree back to Index Root
- Status = CreateIndexRootFromBTree(DeviceExt, NewTree, MaxIndexSize,
&NewIndexRoot, &BtreeIndexLength);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("ERROR: Failed to create Index root from B-Tree!\n");
- DestroyBTree(NewTree);
- ReleaseAttributeContext(IndexRootContext);
- ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
- ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
- return Status;
- }
-
- // We're done with the B-Tree now
- DestroyBTree(NewTree);
-
- // Write back the new index root attribute to the parent directory file record
-
- // First, we need to resize the attribute.
- // CreateIndexRootFromBTree() should have verified that the index root fits within
MaxIndexSize.
- // We can't set the size as we normally would, because if we extend past the file
record,
- // 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)
- {
- 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);
-
- Status = UpdateFileRecord(DeviceExt, DirectoryMftIndex, ParentFileRecord);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("ERROR: Failed to update file record of directory with index:
%llx\n", DirectoryMftIndex);
- ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
- ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
- ReleaseAttributeContext(IndexRootContext);
- ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
- return Status;
- }
-
- // Write the new index root to disk
- Status = WriteAttribute(DeviceExt,
- IndexRootContext,
- 0,
- (PUCHAR)NewIndexRoot,
- AttributeLength,
- &LengthWritten);
- if (!NT_SUCCESS(Status) )
- {
- DPRINT1("ERROR: Unable to write new index root attribute to parent
directory!\n");
- ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
- ReleaseAttributeContext(IndexRootContext);
- ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
- ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
- return Status;
- }
-
- // re-read the parent file record, so we can dump it
- Status = ReadFileRecord(DeviceExt, DirectoryMftIndex, ParentFileRecord);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("ERROR: Couldn't read parent directory after messing with
it!\n");
- }
- else
- {
- DPRINT1("Dumping new parent file record:\n");
- NtfsDumpFileRecord(DeviceExt, ParentFileRecord);
- }
-
- // Cleanup
- ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
- ReleaseAttributeContext(IndexRootContext);
- ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
- ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
-
- return Status;
-}
-
ULONGLONG
NtfsGetFileSize(PDEVICE_EXTENSION DeviceExt,
PFILE_RECORD_HEADER FileRecord,
diff --git a/drivers/filesystems/ntfs/mft.c b/drivers/filesystems/ntfs/mft.c
index ed531df173..72953c0086 100644
--- a/drivers/filesystems/ntfs/mft.c
+++ b/drivers/filesystems/ntfs/mft.c
@@ -750,7 +750,8 @@ SetResidentAttributeDataLength(PDEVICE_EXTENSION Vcb,
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
DPRINT1("Unable to create LargeMcb!\n");
- ExFreePoolWithTag(AttribData, TAG_NTFS);
+ if (AttribDataSize.QuadPart > 0)
+ ExFreePoolWithTag(AttribData, TAG_NTFS);
_SEH2_YIELD(return _SEH2_GetExceptionCode());
} _SEH2_END;
@@ -1452,7 +1453,7 @@ UpdateFileNameRecord(PDEVICE_EXTENSION Vcb,
{
// we need to write the index root attribute back to disk
ULONG LengthWritten;
- Status = WriteAttribute(Vcb, IndexRootCtx, 0, IndexRecord,
AttributeDataLength(&IndexRootCtx->Record), &LengthWritten);
+ Status = WriteAttribute(Vcb, IndexRootCtx, 0, (PUCHAR)IndexRecord,
AttributeDataLength(&IndexRootCtx->Record), &LengthWritten);
if (!NT_SUCCESS(Status))
{
DPRINT1("ERROR: Couldn't update Index Root!\n");
@@ -1514,7 +1515,7 @@ UpdateIndexEntryFileNameSize(PDEVICE_EXTENSION Vcb,
while (IndexEntry < LastEntry &&
!(IndexEntry->Flags & NTFS_INDEX_ENTRY_END))
{
- if ((IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK) > 0x10
&&
+ if ((IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK) >
NTFS_FILE_FIRST_USER_FILE &&
*CurrentEntry >= *StartEntry &&
IndexEntry->FileName.NameType != NTFS_FILE_NAME_DOS &&
CompareFileName(FileName, IndexEntry, DirSearch, CaseSensitive))
@@ -1755,7 +1756,7 @@ AddNewMftEntry(PFILE_RECORD_HEADER FileRecord,
}
// read $Bitmap attribute
- AttrBytesRead = ReadAttribute(DeviceExt, BitmapContext, 0, BitmapData,
BitmapDataSize);
+ AttrBytesRead = ReadAttribute(DeviceExt, BitmapContext, 0, (PCHAR)BitmapData,
BitmapDataSize);
if (AttrBytesRead == 0)
{
@@ -1843,6 +1844,251 @@ AddNewMftEntry(PFILE_RECORD_HEADER FileRecord,
return Status;
}
+/**
+* @name NtfsAddFilenameToDirectory
+* @implemented
+*
+* Adds a $FILE_NAME attribute to a given directory index.
+*
+* @param DeviceExt
+* Points to the target disk's DEVICE_EXTENSION.
+*
+* @param DirectoryMftIndex
+* Mft index of the parent directory which will receive the file.
+*
+* @param FileReferenceNumber
+* File reference of the file to be added to the directory. This is a combination of the
+* Mft index and sequence number.
+*
+* @param FilenameAttribute
+* Pointer to the FILENAME_ATTRIBUTE of the file being added to the directory.
+*
+* @param CaseSensitive
+* Boolean indicating if the function should operate in case-sensitive mode. This will be
TRUE
+* if an application created the file with the FILE_FLAG_POSIX_SEMANTICS flag.
+*
+* @return
+* STATUS_SUCCESS on success.
+* STATUS_INSUFFICIENT_RESOURCES if an allocation fails.
+* STATUS_NOT_IMPLEMENTED if target address isn't at the end of the given file
record.
+*
+* @remarks
+* WIP - Can only support a few files in a directory.
+* One FILENAME_ATTRIBUTE is added to the directory's index for each link to that
file. So, each
+* file which contains one FILENAME_ATTRIBUTE for a long name and another for the 8.3
name, will
+* get both attributes added to its parent directory.
+*/
+NTSTATUS
+NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt,
+ ULONGLONG DirectoryMftIndex,
+ ULONGLONG FileReferenceNumber,
+ PFILENAME_ATTRIBUTE FilenameAttribute,
+ BOOLEAN CaseSensitive)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PFILE_RECORD_HEADER ParentFileRecord;
+ PNTFS_ATTR_CONTEXT IndexRootContext;
+ PINDEX_ROOT_ATTRIBUTE I30IndexRoot;
+ ULONG IndexRootOffset;
+ ULONGLONG I30IndexRootLength;
+ ULONG LengthWritten;
+ PNTFS_ATTR_RECORD DestinationAttribute;
+ PINDEX_ROOT_ATTRIBUTE NewIndexRoot;
+ ULONG AttributeLength;
+ PNTFS_ATTR_RECORD NextAttribute;
+ PB_TREE NewTree;
+ ULONG BtreeIndexLength;
+ ULONG MaxIndexSize;
+
+ // Allocate memory for the parent directory
+ ParentFileRecord = ExAllocatePoolWithTag(NonPagedPool,
+ DeviceExt->NtfsInfo.BytesPerFileRecord,
+ TAG_NTFS);
+ if (!ParentFileRecord)
+ {
+ DPRINT1("ERROR: Couldn't allocate memory for file record!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // Open the parent directory
+ Status = ReadFileRecord(DeviceExt, DirectoryMftIndex, ParentFileRecord);
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+ DPRINT1("ERROR: Couldn't read parent directory with index
%I64u\n",
+ DirectoryMftIndex);
+ return Status;
+ }
+
+ DPRINT1("Dumping old parent file record:\n");
+ NtfsDumpFileRecord(DeviceExt, ParentFileRecord);
+
+ // Find the index root attribute for the directory
+ Status = FindAttribute(DeviceExt,
+ ParentFileRecord,
+ AttributeIndexRoot,
+ L"$I30",
+ 4,
+ &IndexRootContext,
+ &IndexRootOffset);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ERROR: Couldn't find $I30 $INDEX_ROOT attribute for parent
directory with MFT #: %I64u!\n",
+ DirectoryMftIndex);
+ ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+ return Status;
+ }
+
+ // Find the maximum index size given what the file record can hold
+ MaxIndexSize = DeviceExt->NtfsInfo.BytesPerFileRecord
+ - IndexRootOffset
+ - IndexRootContext->Record.Resident.ValueOffset
+ - FIELD_OFFSET(INDEX_ROOT_ATTRIBUTE, Header)
+ - (sizeof(ULONG) * 2);
+
+ // Allocate memory for the index root data
+ I30IndexRootLength = AttributeDataLength(&IndexRootContext->Record);
+ I30IndexRoot = ExAllocatePoolWithTag(NonPagedPool, I30IndexRootLength, TAG_NTFS);
+ if (!I30IndexRoot)
+ {
+ DPRINT1("ERROR: Couldn't allocate memory for index root
attribute!\n");
+ ReleaseAttributeContext(IndexRootContext);
+ ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // Read the Index Root
+ Status = ReadAttribute(DeviceExt, IndexRootContext, 0, (PCHAR)I30IndexRoot,
I30IndexRootLength);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ERROR: Couln't read index root attribute for Mft index
#%I64u\n", DirectoryMftIndex);
+ ReleaseAttributeContext(IndexRootContext);
+ ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
+ ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+ return Status;
+ }
+
+ // Convert the index to a B*Tree
+ Status = CreateBTreeFromIndex(IndexRootContext, I30IndexRoot, &NewTree);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ERROR: Failed to create B-Tree from Index!\n");
+ ReleaseAttributeContext(IndexRootContext);
+ ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
+ ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+ return Status;
+ }
+
+ DumpBTree(NewTree);
+
+ // Insert the key for the file we're adding
+ Status = NtfsInsertKey(FileReferenceNumber, FilenameAttribute, NewTree->RootNode,
CaseSensitive);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ERROR: Failed to insert key into B-Tree!\n");
+ DestroyBTree(NewTree);
+ ReleaseAttributeContext(IndexRootContext);
+ ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
+ ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+ return Status;
+ }
+
+ DumpBTree(NewTree);
+
+ // Convert B*Tree back to Index Root
+ Status = CreateIndexRootFromBTree(DeviceExt, NewTree, MaxIndexSize,
&NewIndexRoot, &BtreeIndexLength);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ERROR: Failed to create Index root from B-Tree!\n");
+ DestroyBTree(NewTree);
+ ReleaseAttributeContext(IndexRootContext);
+ ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
+ ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+ return Status;
+ }
+
+ // We're done with the B-Tree now
+ DestroyBTree(NewTree);
+
+ // Write back the new index root attribute to the parent directory file record
+
+ // First, we need to resize the attribute.
+ // CreateIndexRootFromBTree() should have verified that the index root fits within
MaxIndexSize.
+ // We can't set the size as we normally would, because if we extend past the file
record,
+ // 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)
+ {
+ 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);
+
+ Status = UpdateFileRecord(DeviceExt, DirectoryMftIndex, ParentFileRecord);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ERROR: Failed to update file record of directory with index:
%llx\n", DirectoryMftIndex);
+ ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+ ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
+ ReleaseAttributeContext(IndexRootContext);
+ ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
+ return Status;
+ }
+
+ // Write the new index root to disk
+ Status = WriteAttribute(DeviceExt,
+ IndexRootContext,
+ 0,
+ (PUCHAR)NewIndexRoot,
+ AttributeLength,
+ &LengthWritten);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ERROR: Unable to write new index root attribute to parent
directory!\n");
+ ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
+ ReleaseAttributeContext(IndexRootContext);
+ ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
+ ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+ return Status;
+ }
+
+ // re-read the parent file record, so we can dump it
+ Status = ReadFileRecord(DeviceExt, DirectoryMftIndex, ParentFileRecord);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ERROR: Couldn't read parent directory after messing with
it!\n");
+ }
+ else
+ {
+ DPRINT1("Dumping new parent file record:\n");
+ NtfsDumpFileRecord(DeviceExt, ParentFileRecord);
+ }
+
+ // Cleanup
+ ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
+ ReleaseAttributeContext(IndexRootContext);
+ ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
+ ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+
+ return Status;
+}
+
NTSTATUS
AddFixupArray(PDEVICE_EXTENSION Vcb,
PNTFS_RECORD_HEADER Record)
@@ -1995,7 +2241,7 @@ BrowseIndexEntries(PDEVICE_EXTENSION Vcb,
while (IndexEntry < LastEntry &&
!(IndexEntry->Flags & NTFS_INDEX_ENTRY_END))
{
- if ((IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK) >= 0x10
&&
+ if ((IndexEntry->Data.Directory.IndexedFile & NTFS_MFT_MASK) >=
NTFS_FILE_FIRST_USER_FILE &&
*CurrentEntry >= *StartEntry &&
IndexEntry->FileName.NameType != NTFS_FILE_NAME_DOS &&
CompareFileName(FileName, IndexEntry, DirSearch, CaseSensitive))
diff --git a/drivers/filesystems/ntfs/ntfs.h b/drivers/filesystems/ntfs/ntfs.h
index ddb876daf9..9cbc4d5485 100644
--- a/drivers/filesystems/ntfs/ntfs.h
+++ b/drivers/filesystems/ntfs/ntfs.h
@@ -193,6 +193,7 @@ typedef enum
#define NTFS_FILE_QUOTA 9
#define NTFS_FILE_UPCASE 10
#define NTFS_FILE_EXTEND 11
+#define NTFS_FILE_FIRST_USER_FILE 16
#define NTFS_MFT_MASK 0x0000FFFFFFFFFFFFULL
@@ -223,6 +224,9 @@ typedef enum
#define NTFS_FILE_TYPE_COMPRESSED 0x800
#define NTFS_FILE_TYPE_DIRECTORY 0x10000000
+/* Indexed Flag in Resident attributes - still somewhat speculative */
+#define RA_INDEXED 0x01
+
typedef struct
{
ULONG Type; /* Magic number 'FILE' */
@@ -740,13 +744,6 @@ NtfsDeviceControl(PNTFS_IRP_CONTEXT IrpContext);
/* dirctl.c */
-NTSTATUS
-NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt,
- ULONGLONG DirectoryMftIndex,
- ULONGLONG FileReferenceNumber,
- PFILENAME_ATTRIBUTE FilenameAttribute,
- BOOLEAN CaseSensitive);
-
ULONGLONG
NtfsGetFileSize(PDEVICE_EXTENSION DeviceExt,
PFILE_RECORD_HEADER FileRecord,
@@ -888,6 +885,13 @@ NtfsFileSystemControl(PNTFS_IRP_CONTEXT IrpContext);
/* mft.c */
+NTSTATUS
+NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt,
+ ULONGLONG DirectoryMftIndex,
+ ULONGLONG FileReferenceNumber,
+ PFILENAME_ATTRIBUTE FilenameAttribute,
+ BOOLEAN CaseSensitive);
+
NTSTATUS
AddNewMftEntry(PFILE_RECORD_HEADER FileRecord,
PDEVICE_EXTENSION DeviceExt,