Skip to content

Commit 52c30fd

Browse files
Trevor ThompsonThFabba
Trevor Thompson
authored andcommitted
[NTFS] - Add some helper functions for new features. Add some fixes. Add support for creating an index allocation, splitting a b-tree node, or "demoting" the index root. This allows for file creation without functional limitations.
+AddBitmap() - adds a $BITMAP attribute to a file record. +AddIndexAllocation() - adds an $INDEX_ALLOCATION attribute to a file record. +CountBTreeKeys() - Counts the number of linked B-Tree keys. CreateIndexBufferFromBTreeNode() - Set INDEX_NODE_LARGE if the node has sub-nodes. CreateIndexRootFromBTree() - Simplify the usage and math of MaxIndexSize; make it only account for the cumulative size of the index entries. +DemoteBTreeRoot() - Replaces the contents of an index root with a dummy key, and puts those contents in a new node, which is made a child of the dummy key. This is done when an index root grows too large. +GetIndexEntryVCN() - Retrieves the VCN from an index entry. NtfsAddFilenameToDirectory() - Fix math for MaxIndexRootSize. NtfsInsertKey() - Add support for splitting a B-Tree node. Don't check size of index root (that will be handled later). +SplitBTreeNode() - Called when a B-Tree node grows too large. UpdateIndexAllocation() - Create an $I30 index allocation attribute and bitmap attribute if needed. UpdateIndexNode() - Update children before updating the current node. Store VCN of child nodes in the index entries of their respective keys. svn path=/branches/GSoC_2016/NTFS/; revision=75707
1 parent 5e7c118 commit 52c30fd

File tree

4 files changed

+886
-125
lines changed

4 files changed

+886
-125
lines changed

drivers/filesystems/ntfs/attrib.c

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,100 @@
3636

3737
/* FUNCTIONS ****************************************************************/
3838

39+
/**
40+
* @name AddBitmap
41+
* @implemented
42+
*
43+
* Adds a $BITMAP attribute to a given FileRecord.
44+
*
45+
* @param Vcb
46+
* Pointer to an NTFS_VCB for the destination volume.
47+
*
48+
* @param FileRecord
49+
* Pointer to a complete file record to add the attribute to.
50+
*
51+
* @param AttributeAddress
52+
* Pointer to the region of memory that will receive the $INDEX_ALLOCATION attribute.
53+
* This address must reside within FileRecord. Must be aligned to an 8-byte boundary (relative to FileRecord).
54+
*
55+
* @param Name
56+
* Pointer to a string of 16-bit Unicode characters naming the attribute. Most often L"$I30".
57+
*
58+
* @param NameLength
59+
* The number of wide-characters in the name. L"$I30" Would use 4 here.
60+
*
61+
* @return
62+
* STATUS_SUCCESS on success. STATUS_NOT_IMPLEMENTED if target address isn't at the end
63+
* of the given file record, or if the file record isn't large enough for the attribute.
64+
*
65+
* @remarks
66+
* Only adding the attribute to the end of the file record is supported; AttributeAddress must
67+
* be of type AttributeEnd.
68+
* This could be improved by adding an $ATTRIBUTE_LIST to the file record if there's not enough space.
69+
*
70+
*/
71+
NTSTATUS
72+
AddBitmap(PNTFS_VCB Vcb,
73+
PFILE_RECORD_HEADER FileRecord,
74+
PNTFS_ATTR_RECORD AttributeAddress,
75+
PCWSTR Name,
76+
USHORT NameLength)
77+
{
78+
ULONG AttributeLength;
79+
// Calculate the header length
80+
ULONG ResidentHeaderLength = FIELD_OFFSET(NTFS_ATTR_RECORD, Resident.Reserved) + sizeof(UCHAR);
81+
ULONG FileRecordEnd = AttributeAddress->Length;
82+
ULONG NameOffset;
83+
ULONG ValueOffset;
84+
// We'll start out with 8 bytes of bitmap data
85+
ULONG ValueLength = 8;
86+
ULONG BytesAvailable;
87+
88+
if (AttributeAddress->Type != AttributeEnd)
89+
{
90+
DPRINT1("FIXME: Can only add $BITMAP attribute to the end of a file record.\n");
91+
return STATUS_NOT_IMPLEMENTED;
92+
}
93+
94+
NameOffset = ResidentHeaderLength;
95+
96+
// Calculate ValueOffset, which will be aligned to a 4-byte boundary
97+
ValueOffset = ALIGN_UP_BY(NameOffset + (sizeof(WCHAR) * NameLength), VALUE_OFFSET_ALIGNMENT);
98+
99+
// Calculate length of attribute
100+
AttributeLength = ValueOffset + ValueLength;
101+
AttributeLength = ALIGN_UP_BY(AttributeLength, ATTR_RECORD_ALIGNMENT);
102+
103+
// Make sure the file record is large enough for the new attribute
104+
BytesAvailable = Vcb->NtfsInfo.BytesPerFileRecord - FileRecord->BytesInUse;
105+
if (BytesAvailable < AttributeLength)
106+
{
107+
DPRINT1("FIXME: Not enough room in file record for index allocation attribute!\n");
108+
return STATUS_NOT_IMPLEMENTED;
109+
}
110+
111+
// Set Attribute fields
112+
RtlZeroMemory(AttributeAddress, AttributeLength);
113+
114+
AttributeAddress->Type = AttributeBitmap;
115+
AttributeAddress->Length = AttributeLength;
116+
AttributeAddress->NameLength = NameLength;
117+
AttributeAddress->NameOffset = NameOffset;
118+
AttributeAddress->Instance = FileRecord->NextAttributeNumber++;
119+
120+
AttributeAddress->Resident.ValueLength = ValueLength;
121+
AttributeAddress->Resident.ValueOffset = ValueOffset;
122+
123+
// Set the name
124+
RtlCopyMemory((PCHAR)((ULONG_PTR)AttributeAddress + NameOffset), Name, NameLength * sizeof(WCHAR));
125+
126+
// move the attribute-end and file-record-end markers to the end of the file record
127+
AttributeAddress = (PNTFS_ATTR_RECORD)((ULONG_PTR)AttributeAddress + AttributeAddress->Length);
128+
SetFileRecordEnd(FileRecord, AttributeAddress, FileRecordEnd);
129+
130+
return STATUS_SUCCESS;
131+
}
132+
39133
/**
40134
* @name AddData
41135
* @implemented
@@ -258,6 +352,105 @@ AddFileName(PFILE_RECORD_HEADER FileRecord,
258352
return Status;
259353
}
260354

355+
/**
356+
* @name AddIndexAllocation
357+
* @implemented
358+
*
359+
* Adds an $INDEX_ALLOCATION attribute to a given FileRecord.
360+
*
361+
* @param Vcb
362+
* Pointer to an NTFS_VCB for the destination volume.
363+
*
364+
* @param FileRecord
365+
* Pointer to a complete file record to add the attribute to.
366+
*
367+
* @param AttributeAddress
368+
* Pointer to the region of memory that will receive the $INDEX_ALLOCATION attribute.
369+
* This address must reside within FileRecord. Must be aligned to an 8-byte boundary (relative to FileRecord).
370+
*
371+
* @param Name
372+
* Pointer to a string of 16-bit Unicode characters naming the attribute. Most often, this will be L"$I30".
373+
*
374+
* @param NameLength
375+
* The number of wide-characters in the name. L"$I30" Would use 4 here.
376+
*
377+
* @return
378+
* STATUS_SUCCESS on success. STATUS_NOT_IMPLEMENTED if target address isn't at the end
379+
* of the given file record, or if the file record isn't large enough for the attribute.
380+
*
381+
* @remarks
382+
* Only adding the attribute to the end of the file record is supported; AttributeAddress must
383+
* be of type AttributeEnd.
384+
* This could be improved by adding an $ATTRIBUTE_LIST to the file record if there's not enough space.
385+
*
386+
*/
387+
NTSTATUS
388+
AddIndexAllocation(PNTFS_VCB Vcb,
389+
PFILE_RECORD_HEADER FileRecord,
390+
PNTFS_ATTR_RECORD AttributeAddress,
391+
PCWSTR Name,
392+
USHORT NameLength)
393+
{
394+
ULONG RecordLength;
395+
ULONG FileRecordEnd;
396+
ULONG NameOffset;
397+
ULONG DataRunOffset;
398+
ULONG BytesAvailable;
399+
400+
if (AttributeAddress->Type != AttributeEnd)
401+
{
402+
DPRINT1("FIXME: Can only add $INDEX_ALLOCATION attribute to the end of a file record.\n");
403+
return STATUS_NOT_IMPLEMENTED;
404+
}
405+
406+
// Calculate the name offset
407+
NameOffset = FIELD_OFFSET(NTFS_ATTR_RECORD, NonResident.CompressedSize);
408+
409+
// Calculate the offset to the first data run
410+
DataRunOffset = (sizeof(WCHAR) * NameLength) + NameOffset;
411+
// The data run offset must be aligned to a 4-byte boundary
412+
DataRunOffset = ALIGN_UP_BY(DataRunOffset, DATA_RUN_ALIGNMENT);
413+
414+
// Calculate the length of the new attribute; the empty data run will consist of a single byte
415+
RecordLength = DataRunOffset + 1;
416+
417+
// The size of the attribute itself must be aligned to an 8 - byte boundary
418+
RecordLength = ALIGN_UP_BY(RecordLength, ATTR_RECORD_ALIGNMENT);
419+
420+
// Back up the last 4-bytes of the file record (even though this value doesn't matter)
421+
FileRecordEnd = AttributeAddress->Length;
422+
423+
// Make sure the file record can contain the new attribute
424+
BytesAvailable = Vcb->NtfsInfo.BytesPerFileRecord - FileRecord->BytesInUse;
425+
if (BytesAvailable < RecordLength)
426+
{
427+
DPRINT1("FIXME: Not enough room in file record for index allocation attribute!\n");
428+
return STATUS_NOT_IMPLEMENTED;
429+
}
430+
431+
// Set fields of attribute header
432+
RtlZeroMemory(AttributeAddress, RecordLength);
433+
434+
AttributeAddress->Type = AttributeIndexAllocation;
435+
AttributeAddress->Length = RecordLength;
436+
AttributeAddress->IsNonResident = TRUE;
437+
AttributeAddress->NameLength = NameLength;
438+
AttributeAddress->NameOffset = NameOffset;
439+
AttributeAddress->Instance = FileRecord->NextAttributeNumber++;
440+
441+
AttributeAddress->NonResident.MappingPairsOffset = DataRunOffset;
442+
AttributeAddress->NonResident.HighestVCN = (LONGLONG)-1;
443+
444+
// Set the name
445+
RtlCopyMemory((PCHAR)((ULONG_PTR)AttributeAddress + NameOffset), Name, NameLength * sizeof(WCHAR));
446+
447+
// move the attribute-end and file-record-end markers to the end of the file record
448+
AttributeAddress = (PNTFS_ATTR_RECORD)((ULONG_PTR)AttributeAddress + AttributeAddress->Length);
449+
SetFileRecordEnd(FileRecord, AttributeAddress, FileRecordEnd);
450+
451+
return STATUS_SUCCESS;
452+
}
453+
261454
/**
262455
* @name AddIndexRoot
263456
* @implemented

0 commit comments

Comments
 (0)