https://git.reactos.org/?p=reactos.git;a=commitdiff;h=e0048b1362c812705d326…
commit e0048b1362c812705d326bf902b3712a258b4611
Author: Trevor Thompson <tmt256(a)email.vccs.edu>
AuthorDate: Fri Jun 9 03:14:30 2017 +0000
[NTFS] - Add the most basic support for file creation. Expand diagnostic output,
especially in NtfsDumpIndexRootAttribute(). Replace an ExFreePool() with
ExFreePoolWithTag().
AddFileName() - Add a parameter to receive the Mft index of the parent directory. Fix
so the name of the file will be stored in the attribute, not the name of the directory.
NtfsCreateFile() - Open a file that was successfully created, instead of assuming
failure.
NtfsCreateFileRecord() - Add the filename attribute of the created file to the parent
directory's index.
+NtfsAddFilenameToDirectory() - Adds a $FILE_NAME attribute to a given directory
index. Presently, a file can be created in an empty directory only.
AddNewMftEntry() - Add a parameter to receive the mft index where the new entry was
stored.
svn path=/branches/GSoC_2016/NTFS/; revision=74970
---
drivers/filesystems/ntfs/attrib.c | 94 ++++++++++++--
drivers/filesystems/ntfs/create.c | 44 +++++--
drivers/filesystems/ntfs/dirctl.c | 250 ++++++++++++++++++++++++++++++++++++++
drivers/filesystems/ntfs/mft.c | 8 +-
drivers/filesystems/ntfs/ntfs.h | 18 ++-
5 files changed, 388 insertions(+), 26 deletions(-)
diff --git a/drivers/filesystems/ntfs/attrib.c b/drivers/filesystems/ntfs/attrib.c
index bb678e3ef8..eeed58104e 100644
--- a/drivers/filesystems/ntfs/attrib.c
+++ b/drivers/filesystems/ntfs/attrib.c
@@ -112,6 +112,9 @@ AddData(PFILE_RECORD_HEADER FileRecord,
* Pointer to the FILE_OBJECT which represents the new name.
* This parameter is used to determine the filename and parent directory.
*
+* @param ParentMftIndex
+* Pointer to a ULONGLONG which will receive the index of the parent directory.
+*
* @return
* STATUS_SUCCESS on success. STATUS_NOT_IMPLEMENTED if target address isn't at the
end
* of the given file record.
@@ -128,16 +131,18 @@ NTSTATUS
AddFileName(PFILE_RECORD_HEADER FileRecord,
PNTFS_ATTR_RECORD AttributeAddress,
PDEVICE_EXTENSION DeviceExt,
- PFILE_OBJECT FileObject)
+ PFILE_OBJECT FileObject,
+ PULONGLONG ParentMftIndex)
{
ULONG ResidentHeaderLength = FIELD_OFFSET(NTFS_ATTR_RECORD, Resident.Reserved) +
sizeof(UCHAR);
PFILENAME_ATTRIBUTE FileNameAttribute;
LARGE_INTEGER SystemTime;
ULONG FileRecordEnd = AttributeAddress->Length;
ULONGLONG CurrentMFTIndex = NTFS_FILE_ROOT;
- UNICODE_STRING Current, Remaining;
+ UNICODE_STRING Current, Remaining, FilenameNoPath;
NTSTATUS Status = STATUS_SUCCESS;
ULONG FirstEntry = 0;
+ WCHAR Buffer[MAX_PATH];
if (AttributeAddress->Type != AttributeEnd)
{
@@ -162,20 +167,29 @@ AddFileName(PFILE_RECORD_HEADER FileRecord,
// we need to extract the filename from the path
DPRINT1("Pathname: %wZ\n", &FileObject->FileName);
+ RtlZeroMemory(&FilenameNoPath, sizeof(UNICODE_STRING));
+ FilenameNoPath.Buffer = Buffer;
+ FilenameNoPath.MaximumLength = MAX_PATH;
+
FsRtlDissectName(FileObject->FileName, &Current, &Remaining);
while (Current.Length != 0)
{
DPRINT1("Current: %wZ\n", &Current);
+ if(Remaining.Length != 0)
+ RtlCopyUnicodeString(&FilenameNoPath, &Remaining);
+
Status = NtfsFindMftRecord(DeviceExt, CurrentMFTIndex, &Current,
&FirstEntry, FALSE, &CurrentMFTIndex);
if (!NT_SUCCESS(Status))
- {
break;
- }
- if (Remaining.Length == 0)
+ if (Remaining.Length == 0 )
+ {
+ if(Current.Length != 0)
+ RtlCopyUnicodeString(&FilenameNoPath, &Current);
break;
+ }
FsRtlDissectName(Current, &Current, &Remaining);
}
@@ -184,6 +198,9 @@ AddFileName(PFILE_RECORD_HEADER FileRecord,
// set reference to parent directory
FileNameAttribute->DirectoryFileReferenceNumber = CurrentMFTIndex;
+ *ParentMftIndex = CurrentMFTIndex;
+
+ DPRINT1("SequenceNumber: 0x%02x\n", FileRecord->SequenceNumber);
// The highest 2 bytes should be the sequence number, unless the parent happens to be
root
if (CurrentMFTIndex == NTFS_FILE_ROOT)
@@ -191,19 +208,19 @@ AddFileName(PFILE_RECORD_HEADER FileRecord,
else
FileNameAttribute->DirectoryFileReferenceNumber |=
(ULONGLONG)FileRecord->SequenceNumber << 48;
- DPRINT1("FileNameAttribute->DirectoryFileReferenceNumber: 0x%I64x\n",
FileNameAttribute->DirectoryFileReferenceNumber);
+ DPRINT1("FileNameAttribute->DirectoryFileReferenceNumber: 0x%016I64x\n",
FileNameAttribute->DirectoryFileReferenceNumber);
- FileNameAttribute->NameLength = Current.Length / 2;
+ FileNameAttribute->NameLength = FilenameNoPath.Length / 2;
// TODO: Get proper nametype, add DOS links as needed
FileNameAttribute->NameType = NTFS_FILE_NAME_WIN32_AND_DOS;
- RtlCopyMemory(FileNameAttribute->Name, Current.Buffer, Current.Length);
+ RtlCopyMemory(FileNameAttribute->Name, FilenameNoPath.Buffer,
FilenameNoPath.Length);
FileRecord->LinkCount++;
AttributeAddress->Length = ResidentHeaderLength +
- FIELD_OFFSET(FILENAME_ATTRIBUTE, Name) + Current.Length;
+ FIELD_OFFSET(FILENAME_ATTRIBUTE, Name) + FilenameNoPath.Length;
AttributeAddress->Length = ALIGN_UP_BY(AttributeAddress->Length, 8);
- AttributeAddress->Resident.ValueLength = FIELD_OFFSET(FILENAME_ATTRIBUTE, Name) +
Current.Length;
+ AttributeAddress->Resident.ValueLength = FIELD_OFFSET(FILENAME_ATTRIBUTE, Name) +
FilenameNoPath.Length;
AttributeAddress->Resident.ValueOffset = ResidentHeaderLength;
AttributeAddress->Resident.Flags = 1; // indexed
@@ -1054,6 +1071,7 @@ NtfsDumpFileNameAttribute(PNTFS_ATTR_RECORD Attribute)
DbgPrint(" (%x) '%.*S' ", FileNameAttr->NameType,
FileNameAttr->NameLength, FileNameAttr->Name);
DbgPrint(" '%x' \n", FileNameAttr->FileAttributes);
DbgPrint(" AllocatedSize: %I64u\nDataSize: %I64u\n",
FileNameAttr->AllocatedSize, FileNameAttr->DataSize);
+ DbgPrint(" File reference: 0x%016I64x\n",
FileNameAttr->DirectoryFileReferenceNumber);
}
@@ -1110,23 +1128,73 @@ VOID
NtfsDumpIndexRootAttribute(PNTFS_ATTR_RECORD Attribute)
{
PINDEX_ROOT_ATTRIBUTE IndexRootAttr;
+ ULONG currentOffset;
+ ULONG currentNode;
IndexRootAttr = (PINDEX_ROOT_ATTRIBUTE)((ULONG_PTR)Attribute +
Attribute->Resident.ValueOffset);
if (IndexRootAttr->AttributeType == AttributeFileName)
ASSERT(IndexRootAttr->CollationRule == COLLATION_FILE_NAME);
- DbgPrint(" $INDEX_ROOT (%uB, %u) ", IndexRootAttr->SizeOfEntry,
IndexRootAttr->ClustersPerIndexRecord);
+ DbgPrint(" $INDEX_ROOT (%u bytes per index record, %u clusters) ",
IndexRootAttr->SizeOfEntry, IndexRootAttr->ClustersPerIndexRecord);
if (IndexRootAttr->Header.Flags == INDEX_ROOT_SMALL)
{
- DbgPrint(" (small) ");
+ DbgPrint(" (small)\n");
}
else
{
ASSERT(IndexRootAttr->Header.Flags == INDEX_ROOT_LARGE);
- DbgPrint(" (large) ");
+ DbgPrint(" (large)\n");
}
+
+ DbgPrint(" Offset to first index: 0x%lx\n Total size of index entries:
0x%lx\n Allocated size of node: 0x%lx\n",
+ IndexRootAttr->Header.FirstEntryOffset,
+ IndexRootAttr->Header.TotalSizeOfEntries,
+ IndexRootAttr->Header.AllocatedSize);
+ currentOffset = IndexRootAttr->Header.FirstEntryOffset;
+ currentNode = 0;
+ // print details of every node in the index
+ while (currentOffset < IndexRootAttr->Header.TotalSizeOfEntries)
+ {
+ PINDEX_ENTRY_ATTRIBUTE currentIndexExtry =
(PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)IndexRootAttr + 0x10 + currentOffset);
+ DbgPrint(" Index Node Entry %u", currentNode++);
+ if (currentIndexExtry->Flags & NTFS_INDEX_ENTRY_NODE)
+ DbgPrint(" (Branch)");
+ else
+ DbgPrint(" (Leaf)");
+ if((currentIndexExtry->Flags & NTFS_INDEX_ENTRY_END))
+ {
+ DbgPrint(" (Dummy Key)");
+ }
+ DbgPrint("\n File Reference: 0x%016I64x\n",
currentIndexExtry->Data.Directory.IndexedFile);
+ DbgPrint(" Index Entry Length: 0x%x\n",
currentIndexExtry->Length);
+ DbgPrint(" Index Key Length: 0x%x\n",
currentIndexExtry->KeyLength);
+
+ // if this isn't the final (dummy) node, print info about the key (Filename
attribute)
+ if (!(currentIndexExtry->Flags & NTFS_INDEX_ENTRY_END))
+ {
+ UNICODE_STRING Name;
+ DbgPrint(" Parent File Reference: 0x%016I64x\n",
currentIndexExtry->FileName.DirectoryFileReferenceNumber);
+ DbgPrint(" $FILENAME indexed: ");
+ Name.Length = currentIndexExtry->FileName.NameLength * sizeof(WCHAR);
+ Name.MaximumLength = Name.Length;
+ Name.Buffer = currentIndexExtry->FileName.Name;
+ DbgPrint("'%wZ'\n", &Name);
+ }
+
+ // if this node has a sub-node beneath it
+ if (currentIndexExtry->Flags & NTFS_INDEX_ENTRY_NODE)
+ {
+ // Print the VCN of the sub-node
+ PULONGLONG SubNodeVCN = (PULONGLONG)((ULONG_PTR)currentIndexExtry +
currentIndexExtry->Length - 8);
+ DbgPrint(" VCN of sub-node: 0x%llx\n", *SubNodeVCN);
+ }
+
+ currentOffset += currentIndexExtry->Length;
+ ASSERT(currentIndexExtry->Length);
+ }
+
}
diff --git a/drivers/filesystems/ntfs/create.c b/drivers/filesystems/ntfs/create.c
index 6513827c62..ef39b44373 100644
--- a/drivers/filesystems/ntfs/create.c
+++ b/drivers/filesystems/ntfs/create.c
@@ -523,7 +523,7 @@ NtfsCreateFile(PDEVICE_OBJECT DeviceObject,
DoneOverwriting:
if (fileRecord)
- ExFreePool(fileRecord);
+ ExFreePoolWithTag(fileRecord, TAG_NTFS);
if (dataContext)
ReleaseAttributeContext(dataContext);
@@ -562,13 +562,14 @@ NtfsCreateFile(PDEVICE_OBJECT DeviceObject,
// Create the file record on disk
Status = NtfsCreateFileRecord(DeviceExt, FileObject);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ERROR: Couldn't create file record!\n");
+ return Status;
+ }
- // Update the parent directory index
- // Still TODO
-
- // Call NtfsOpenFile()
-
- return STATUS_CANNOT_MAKE;
+ // Now we should be able to open the file
+ return NtfsCreateFile(DeviceObject, Irp);
}
}
@@ -624,7 +625,8 @@ NtfsCreate(PNTFS_IRP_CONTEXT IrpContext)
* @name NtfsCreateFileRecord()
* @implemented
*
-* Creates a file record and saves it to the MFT.
+* Creates a file record and saves it to the MFT. Adds the filename attribute of the
+* created file to the parent directory's index.
*
* @param DeviceExt
* Points to the target disk's DEVICE_EXTENSION
@@ -643,6 +645,9 @@ NtfsCreateFileRecord(PDEVICE_EXTENSION DeviceExt,
NTSTATUS Status = STATUS_SUCCESS;
PFILE_RECORD_HEADER FileRecord;
PNTFS_ATTR_RECORD NextAttribute;
+ PFILENAME_ATTRIBUTE FilenameAttribute;
+ ULONGLONG ParentMftIndex;
+ ULONGLONG FileMftIndex;
// allocate memory for file record
FileRecord = ExAllocatePoolWithTag(NonPagedPool,
@@ -686,7 +691,10 @@ NtfsCreateFileRecord(PDEVICE_EXTENSION DeviceExt,
NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)NextAttribute +
(ULONG_PTR)NextAttribute->Length);
// Add the $FILE_NAME attribute
- AddFileName(FileRecord, NextAttribute, DeviceExt, FileObject);
+ AddFileName(FileRecord, NextAttribute, DeviceExt, FileObject, &ParentMftIndex);
+
+ // save a pointer to the filename attribute
+ FilenameAttribute = (PFILENAME_ATTRIBUTE)((ULONG_PTR)NextAttribute +
NextAttribute->Resident.ValueOffset);
// advance NextAttribute pointer to the next attribute
NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)NextAttribute +
(ULONG_PTR)NextAttribute->Length);
@@ -698,7 +706,23 @@ NtfsCreateFileRecord(PDEVICE_EXTENSION DeviceExt,
NtfsDumpFileRecord(DeviceExt, FileRecord);
// Now that we've built the file record in memory, we need to store it in the
MFT.
- Status = AddNewMftEntry(FileRecord, DeviceExt);
+ Status = AddNewMftEntry(FileRecord, DeviceExt, &FileMftIndex);
+ if (NT_SUCCESS(Status))
+ {
+ // The highest 2 bytes should be the sequence number, unless the parent happens
to be root
+ if (FileMftIndex == NTFS_FILE_ROOT)
+ FileMftIndex = FileMftIndex + ((ULONGLONG)NTFS_FILE_ROOT << 48);
+ else
+ FileMftIndex = FileMftIndex + ((ULONGLONG)FileRecord->SequenceNumber
<< 48);
+
+ DPRINT1("New File Reference: 0x%016I64x\n", FileMftIndex);
+
+ // Add the filename attribute to the filename-index of the parent directory
+ Status = NtfsAddFilenameToDirectory(DeviceExt,
+ ParentMftIndex,
+ FileMftIndex,
+ FilenameAttribute);
+ }
ExFreePoolWithTag(FileRecord, TAG_NTFS);
diff --git a/drivers/filesystems/ntfs/dirctl.c b/drivers/filesystems/ntfs/dirctl.c
index aaa6dfcb87..91f0bc5db7 100644
--- a/drivers/filesystems/ntfs/dirctl.c
+++ b/drivers/filesystems/ntfs/dirctl.c
@@ -34,6 +34,256 @@
/* 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.
+*
+* @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 an empty 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)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PFILE_RECORD_HEADER ParentFileRecord;
+ PNTFS_ATTR_CONTEXT DirectoryContext;
+ PINDEX_ROOT_ATTRIBUTE I30IndexRoot;
+ ULONG IndexRootOffset;
+ ULONGLONG I30IndexRootLength;
+ PINDEX_ENTRY_ATTRIBUTE IndexNodeEntry;
+ ULONG LengthWritten;
+ PNTFS_ATTR_RECORD DestinationAttribute;
+ PINDEX_ROOT_ATTRIBUTE NewIndexRoot;
+ ULONG AttributeLength;
+ PNTFS_ATTR_RECORD NextAttribute;
+
+ // 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,
+ &DirectoryContext,
+ &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;
+ }
+
+ I30IndexRootLength = AttributeDataLength(&DirectoryContext->Record);
+
+ // Allocate memory for the index root data
+ I30IndexRoot = (PINDEX_ROOT_ATTRIBUTE)ExAllocatePoolWithTag(NonPagedPool,
I30IndexRootLength, TAG_NTFS);
+ if (!I30IndexRoot)
+ {
+ DPRINT1("ERROR: Couldn't allocate memory for index root
attribute!\n");
+ ReleaseAttributeContext(DirectoryContext);
+ ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+ }
+
+ // Read the Index Root
+ Status = ReadAttribute(DeviceExt, DirectoryContext, 0, (PCHAR)I30IndexRoot,
I30IndexRootLength);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ERROR: Couln't read index root attribute for Mft index
#%I64u\n", DirectoryMftIndex);
+ ReleaseAttributeContext(DirectoryContext);
+ ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
+ ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+ return Status;
+ }
+
+ // Make sure it's empty (temporarily)
+ IndexNodeEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)I30IndexRoot +
I30IndexRoot->Header.FirstEntryOffset + 0x10);
+ if (IndexNodeEntry->Data.Directory.IndexedFile != 0 || IndexNodeEntry->Flags !=
2)
+ {
+ DPRINT1("FIXME: File-creation is only supported in empty directories right
now! Be patient! :)\n");
+ ReleaseAttributeContext(DirectoryContext);
+ ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
+ ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ // Now we need to setup a new index root attribute to replace the old one
+ NewIndexRoot = ExAllocatePoolWithTag(NonPagedPool,
DeviceExt->NtfsInfo.BytesPerIndexRecord, TAG_NTFS);
+ if (!NewIndexRoot)
+ {
+ DPRINT1("ERROR: Unable to allocate memory for new index root
attribute!\n");
+ ReleaseAttributeContext(DirectoryContext);
+ ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
+ ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // Setup the new index record
+ RtlZeroMemory(NewIndexRoot, DeviceExt->NtfsInfo.BytesPerIndexRecord); //
shouldn't be necessary but aids in debugging
+
+ NewIndexRoot->AttributeType = AttributeFileName;
+ NewIndexRoot->CollationRule = COLLATION_FILE_NAME;
+ NewIndexRoot->SizeOfEntry = DeviceExt->NtfsInfo.BytesPerIndexRecord;
+ // If Bytes per index record is less than cluster size, clusters per index record
becomes sectors per index
+ if(NewIndexRoot->SizeOfEntry < DeviceExt->NtfsInfo.BytesPerCluster)
+ NewIndexRoot->ClustersPerIndexRecord = NewIndexRoot->SizeOfEntry /
DeviceExt->NtfsInfo.BytesPerSector;
+ else
+ NewIndexRoot->ClustersPerIndexRecord = NewIndexRoot->SizeOfEntry /
DeviceExt->NtfsInfo.BytesPerCluster;
+
+ // Setup the Index node header
+ NewIndexRoot->Header.FirstEntryOffset = 0x10;
+ NewIndexRoot->Header.Flags = INDEX_ROOT_SMALL;
+ // still need to calculate sizes
+
+ // The first index node entry will be for the filename we're adding
+ IndexNodeEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)NewIndexRoot +
NewIndexRoot->Header.FirstEntryOffset + 0x10);
+ IndexNodeEntry->Data.Directory.IndexedFile = FileReferenceNumber;
+ IndexNodeEntry->Flags = INDEX_ROOT_SMALL;
+ IndexNodeEntry->KeyLength = FIELD_OFFSET(FILENAME_ATTRIBUTE, Name) + (2 *
FilenameAttribute->NameLength);
+ IndexNodeEntry->Length = ALIGN_UP_BY(IndexNodeEntry->KeyLength, 8) +
FIELD_OFFSET(INDEX_ENTRY_ATTRIBUTE, FileName);
+
+ // Now we can calculate the Node length (temp logic)
+ NewIndexRoot->Header.TotalSizeOfEntries = NewIndexRoot->Header.FirstEntryOffset
+ IndexNodeEntry->Length + 0x10;
+ NewIndexRoot->Header.AllocatedSize = NewIndexRoot->Header.TotalSizeOfEntries;
+
+ DPRINT1("New Index Node Entry Stream Length: %u\nNew Inde Node Entry Length:
%u\n",
+ IndexNodeEntry->KeyLength,
+ IndexNodeEntry->Length);
+
+ // copy over the attribute proper
+ RtlCopyMemory(&IndexNodeEntry->FileName, FilenameAttribute,
IndexNodeEntry->KeyLength);
+
+ // Now setup the dummy key
+ IndexNodeEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)IndexNodeEntry +
IndexNodeEntry->Length);
+
+ IndexNodeEntry->Data.Directory.IndexedFile = 0;
+ IndexNodeEntry->Length = 0x10;
+ IndexNodeEntry->KeyLength = 0;
+ IndexNodeEntry->Flags = NTFS_INDEX_ENTRY_END;
+
+ // This is when we'd normally setup the length (already done above)
+
+ // Write back the new index root attribute to the parent directory file record
+
+ // First, we need to make sure the attribute is large enough.
+ // 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);
+
+ 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(DirectoryContext);
+ 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(DirectoryContext,
+ ParentFileRecord,
+ IndexRootOffset,
+ AttributeLength);
+
+ 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);
+ ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
+ return Status;
+ }
+
+ // Update the parent directory with the new index root
+ Status = WriteAttribute(DeviceExt,
+ DirectoryContext,
+ 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(DirectoryContext);
+ 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(DirectoryContext);
+ ExFreePoolWithTag(I30IndexRoot, TAG_NTFS);
+ ExFreePoolWithTag(ParentFileRecord, TAG_NTFS);
+
+ return Status;
+}
ULONGLONG
NtfsGetFileSize(PDEVICE_EXTENSION DeviceExt,
diff --git a/drivers/filesystems/ntfs/mft.c b/drivers/filesystems/ntfs/mft.c
index 19ae0d15c1..5b9b291e4e 100644
--- a/drivers/filesystems/ntfs/mft.c
+++ b/drivers/filesystems/ntfs/mft.c
@@ -1361,6 +1361,9 @@ FixupUpdateSequenceArray(PDEVICE_EXTENSION Vcb,
* @param DeviceExt
* Pointer to the DEVICE_EXTENSION of the target drive.
*
+* @param DestinationIndex
+* Pointer to a ULONGLONG which will receive the MFT index where the file record was
stored.
+*
* @return
* STATUS_SUCCESS on success.
* STATUS_OBJECT_NAME_NOT_FOUND if we can't find the MFT's $Bitmap or if we
weren't able
@@ -1371,7 +1374,8 @@ FixupUpdateSequenceArray(PDEVICE_EXTENSION Vcb,
*/
NTSTATUS
AddNewMftEntry(PFILE_RECORD_HEADER FileRecord,
- PDEVICE_EXTENSION DeviceExt)
+ PDEVICE_EXTENSION DeviceExt,
+ PULONGLONG DestinationIndex)
{
NTSTATUS Status = STATUS_SUCCESS;
ULONGLONG MftIndex;
@@ -1454,6 +1458,8 @@ AddNewMftEntry(PFILE_RECORD_HEADER FileRecord,
return Status;
}
+ *DestinationIndex = MftIndex;
+
ExFreePoolWithTag(BitmapData, TAG_NTFS);
ReleaseAttributeContext(BitmapContext);
diff --git a/drivers/filesystems/ntfs/ntfs.h b/drivers/filesystems/ntfs/ntfs.h
index 2177f1db0e..a3265db9da 100644
--- a/drivers/filesystems/ntfs/ntfs.h
+++ b/drivers/filesystems/ntfs/ntfs.h
@@ -534,7 +534,8 @@ NTSTATUS
AddFileName(PFILE_RECORD_HEADER FileRecord,
PNTFS_ATTR_RECORD AttributeAddress,
PDEVICE_EXTENSION DeviceExt,
- PFILE_OBJECT FileObject);
+ PFILE_OBJECT FileObject,
+ PULONGLONG ParentMftIndex);
NTSTATUS
AddStandardInformation(PFILE_RECORD_HEADER FileRecord,
@@ -675,6 +676,12 @@ NtfsDeviceControl(PNTFS_IRP_CONTEXT IrpContext);
/* dirctl.c */
+NTSTATUS
+NtfsAddFilenameToDirectory(PDEVICE_EXTENSION DeviceExt,
+ ULONGLONG DirectoryMftIndex,
+ ULONGLONG FileMftIndex,
+ PFILENAME_ATTRIBUTE FilenameAttribute);
+
ULONGLONG
NtfsGetFileSize(PDEVICE_EXTENSION DeviceExt,
PFILE_RECORD_HEADER FileRecord,
@@ -816,7 +823,8 @@ NtfsFileSystemControl(PNTFS_IRP_CONTEXT IrpContext);
/* mft.c */
NTSTATUS
AddNewMftEntry(PFILE_RECORD_HEADER FileRecord,
- PDEVICE_EXTENSION DeviceExt);
+ PDEVICE_EXTENSION DeviceExt,
+ PULONGLONG DestinationIndex);
PNTFS_ATTR_CONTEXT
PrepareAttributeContext(PNTFS_ATTR_RECORD AttrRecord);
@@ -842,6 +850,12 @@ WriteAttribute(PDEVICE_EXTENSION Vcb,
ULONGLONG
AttributeDataLength(PNTFS_ATTR_RECORD AttrRecord);
+VOID
+InternalSetResidentAttributeLength(PNTFS_ATTR_CONTEXT AttrContext,
+ PFILE_RECORD_HEADER FileRecord,
+ ULONG AttrOffset,
+ ULONG DataSize);
+
NTSTATUS
SetAttributeDataLength(PFILE_OBJECT FileObject,
PNTFS_FCB Fcb,