BytesRead = ReadAttribute(Vcb, IndexAllocationContext, 0, (PCHAR)Buffer, BufferSize);
- ASSERT(BytesRead = BufferSize);
+ ASSERT(BytesRead == BufferSize);
CurrentNode = Buffer;
* @returns
* STATUS_SUCCESS in case of success.
* STATUS_NOT_IMPLEMENTED if there's no $I30 bitmap attribute in the file record.
-*
+*
* @remarks
* AllocateIndexNode() doesn't write any data to the index record it creates. Called by UpdateIndexNode().
* Don't call PrintAllVCNs() or NtfsDumpFileRecord() after calling AllocateIndexNode() before UpdateIndexNode() finishes.
// Windows seems to allocate the bitmap in 8-byte chunks to keep any bytes from being wasted on padding
BytesNeeded = ALIGN_UP(BytesNeeded, ATTR_RECORD_ALIGNMENT);
- // Allocate memory for the bitmap, including some padding; RtlInitializeBitmap() wants a pointer
+ // Allocate memory for the bitmap, including some padding; RtlInitializeBitmap() wants a pointer
// that's ULONG-aligned, and it wants the size of the memory allocated for it to be a ULONG-multiple.
BitmapMem = ExAllocatePoolWithTag(NonPagedPool, BytesNeeded + sizeof(ULONG), TAG_NTFS);
if (!BitmapMem)
// Set the bit for the new index record
RtlSetBits(&Bitmap, NextNodeNumber, 1);
-
+
// Write the new bitmap attribute
Status = WriteAttribute(DeviceExt,
BitmapCtx,
}
RtlZeroMemory(NewIndexEntry, EntrySize);
-
+
if (HasChildNode)
{
NewIndexEntry->Flags = NTFS_INDEX_ENTRY_NODE | NTFS_INDEX_ENTRY_END;
{
// Truncate KeyName2 to be the same length as KeyName1
Key2Name.Length = Key1Name.Length;
-
+
// Compare the names of the same length
Comparison = RtlCompareUnicodeString(&Key1Name, &Key2Name, !CaseSensitive);
/**
* @name CountBTreeKeys
* @implemented
-*
+*
* Counts the number of linked B-Tree keys, starting with FirstKey.
*
* @param FirstKey
* Pointer to a B_TREE_KEY that will be the first key to be counted.
-*
+*
* @return
* The number of keys in a linked-list, including FirstKey and the final dummy key.
*/
{
ULONG Count = 0;
PB_TREE_KEY Current = FirstKey;
-
+
while (Current != NULL)
{
Count++;
* @returns
* STATUS_SUCCESS on success.
* STATUS_INSUFFICIENT_RESOURCES if an allocation fails.
-*
+*
* @remarks
* Allocates memory for the entire tree. Caller is responsible for destroying the tree with DestroyBTree().
*/
PB_TREE_KEY CurrentKey = Node->FirstKey;
ULONG i;
for (i = 0; i < Node->KeyCount; i++)
- {
+ {
ASSERT(CurrentKey->IndexEntry->Length != 0);
// Add the length of the current node
* STATUS_SUCCESS on success.
* STATUS_INSUFFICIENT_RESOURCES if an allocation fails.
* STATUS_NOT_IMPLEMENTED if the new index can't fit within MaxIndexSize.
-*
+*
* @remarks
* If the function succeeds, it's the caller's responsibility to free IndexRoot with ExFreePoolWithTag().
*/
// Setup each Node Entry
CurrentKey = Tree->RootNode->FirstKey;
- CurrentNodeEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)NewIndexRoot
+ CurrentNodeEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)NewIndexRoot
+ FIELD_OFFSET(INDEX_ROOT_ATTRIBUTE, Header)
+ NewIndexRoot->Header.FirstEntryOffset);
for (i = 0; i < Tree->RootNode->KeyCount; i++)
// Windows seems to alternate between using 0x28 and 0x40 for the first entry offset of each index buffer.
// Interestingly, neither Windows nor chkdsk seem to mind if we just use 0x28 for every index record.
- IndexBuffer->Header.FirstEntryOffset = 0x28;
+ IndexBuffer->Header.FirstEntryOffset = 0x28;
IndexBuffer->Header.AllocatedSize = BufferSize - FIELD_OFFSET(INDEX_BUFFER, Header);
// Start summing the total size of this node's entries
return Status;
}
- // Advance end marker
+ // Advance end marker
EndMarker = (PNTFS_ATTR_RECORD)((ULONG_PTR)EndMarker + EndMarker->Length);
// Add index bitmap to the very end of the file record
DPRINT1("ERROR: Failed to update child node!\n");
return Status;
}
-
+
// Is the Index Entry large enough to store the VCN?
if (!BooleanFlagOn(CurrentKey->IndexEntry->Flags, NTFS_INDEX_ENTRY_NODE))
{
CaseSensitive,
MaxIndexRootSize,
IndexRecordSize,
- &NewLeftKey,
+ &NewLeftKey,
&NewChild);
if (!NT_SUCCESS(Status))
{
// Calculate maximum size of index entries without any headers
AllocatedNodeSize = IndexRecordSize - FIELD_OFFSET(INDEX_BUFFER, Header);
- // TODO: Replace magic with math
+ // TODO: Replace magic with math
MaxNodeSizeWithoutHeader = AllocatedNodeSize - 0x28;
-
+
// Has the node grown larger than its allocated size?
if (NodeSize > MaxNodeSizeWithoutHeader)
{
* @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.
}
// TODO: check for appropriate access
-
+
ExAcquireResourceExclusiveLite(&(Fcb->MainResource), TRUE);
fileRecord = ExAllocateFromNPagedLookasideList(&Fcb->Vcb->FileRecLookasideList);
else
{
Status = STATUS_NO_MEMORY;
- }
-
+ }
+
DoneOverwriting:
if (fileRecord)
ExFreeToNPagedLookasideList(&Fcb->Vcb->FileRecLookasideList, fileRecord);
{
NtfsCloseFile(DeviceExt, FileObject);
return Status;
- }
+ }
if (RequestedDisposition == FILE_SUPERSEDE)
{
}
// Calculate maximum size of index root
- MaxIndexRootSize = DeviceExt->NtfsInfo.BytesPerFileRecord
+ MaxIndexRootSize = DeviceExt->NtfsInfo.BytesPerFileRecord
- ((ULONG_PTR)NextAttribute - (ULONG_PTR)FileRecord)
- sizeof(ULONG) * 2;
*
* @param DeviceExt
* Pointer to the DEVICE_EXTENSION of the target volume the file record will be stored on.
-*
+*
* @return
* A pointer to the newly-created FILE_RECORD_HEADER if the function succeeds, NULL otherwise.
*/
* @param CanWait
* Boolean indicating if the function is allowed to wait for exclusive access to the master file table.
* This will only be relevant if the MFT doesn't have any free file records and needs to be enlarged.
-*
+*
* @return
-* STATUS_SUCCESS on success.
+* STATUS_SUCCESS on success.
* STATUS_INSUFFICIENT_RESOURCES if unable to allocate memory for the file record.
-* STATUS_CANT_WAIT if CanWait was FALSE and the function needed to resize the MFT but
+* STATUS_CANT_WAIT if CanWait was FALSE and the function needed to resize the MFT but
* couldn't get immediate, exclusive access to it.
*/
NTSTATUS
BOOLEAN
NtfsFCBIsCompressed(PNTFS_FCB Fcb)
{
- return ((Fcb->Entry.FileAttributes & NTFS_FILE_TYPE_COMPRESSED) == NTFS_FILE_TYPE_COMPRESSED);
+ return ((Fcb->Entry.FileAttributes & NTFS_FILE_TYPE_COMPRESSED) == NTFS_FILE_TYPE_COMPRESSED);
}
BOOLEAN
NTSTATUS
NtfsReadFCBAttribute(PNTFS_VCB Vcb,
PNTFS_FCB pFCB,
- ULONG Type,
+ ULONG Type,
PCWSTR Name,
ULONG NameLength,
PVOID * Data)
* STATUS_INSUFFICIENT_RESOURCES if an allocation failed,
* STATUS_ACCESS_DENIED if target file is a volume or if paging is involved.
*
-* @remarks As this function sets the size of a file at the file-level
-* (and not at the attribute level) it's not recommended to use this
+* @remarks As this function sets the size of a file at the file-level
+* (and not at the attribute level) it's not recommended to use this
* function alongside functions that operate on the data attribute directly.
*
*/
*
* @remarks Called by NtfsDispatch() in response to an IRP_MJ_SET_INFORMATION request.
* Only the FileEndOfFileInformation InformationClass is fully implemented. FileAllocationInformation
-* is a hack and not a true implementation, but it's enough to make SetEndOfFile() work.
+* is a hack and not a true implementation, but it's enough to make SetEndOfFile() work.
* All other information classes are TODO.
*
*/
{
PFILE_END_OF_FILE_INFORMATION EndOfFileInfo;
- /* TODO: Allocation size is not actually the same as file end for NTFS,
+ /* TODO: Allocation size is not actually the same as file end for NTFS,
however, few applications are likely to make the distinction. */
- case FileAllocationInformation:
+ case FileAllocationInformation:
DPRINT1("FIXME: Using hacky method of setting FileAllocationInformation.\n");
case FileEndOfFileInformation:
EndOfFileInfo = (PFILE_END_OF_FILE_INFORMATION)SystemBuffer;
BooleanFlagOn(Stack->Flags, SL_CASE_SENSITIVE),
&EndOfFileInfo->EndOfFile);
break;
-
+
// TODO: all other information classes
default:
* PURPOSE: NTFS filesystem driver
* PROGRAMMER: Eric Kohl
* Valentin Verkhovsky
- * Pierre Schweitzer
+ * Pierre Schweitzer
*/
/* INCLUDES *****************************************************************/
/* Check cluster size */
ClusterSize = BootSector->BPB.BytesPerSector * BootSector->BPB.SectorsPerCluster;
- if (ClusterSize != 512 && ClusterSize != 1024 &&
+ if (ClusterSize != 512 && ClusterSize != 1024 &&
ClusterSize != 2048 && ClusterSize != 4096 &&
ClusterSize != 8192 && ClusterSize != 16384 &&
ClusterSize != 32768 && ClusterSize != 65536)
* @implemented
*
* Writes a file to the disk. It presently borrows a lot of code from NtfsReadFile() and
-* VFatWriteFileData(). It needs some more work before it will be complete; it won't handle
+* VFatWriteFileData(). It needs some more work before it will be complete; it won't handle
* page files, asnyc io, cached writes, etc.
*
* @param DeviceExt
return FreeClusters;
}
-/**
-* NtfsAllocateClusters
+/**
+* NtfsAllocateClusters
* Allocates a run of clusters. The run allocated might be smaller than DesiredClusters.
*/
NTSTATUS
NtfsAllocateClusters(PDEVICE_EXTENSION DeviceExt,
ULONG FirstDesiredCluster,
- ULONG DesiredClusters,
- PULONG FirstAssignedCluster,
+ ULONG DesiredClusters,
+ PULONG FirstAssignedCluster,
PULONG AssignedClusters)
{
NTSTATUS Status;
ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, BitmapRecord);
return STATUS_DISK_FULL;
}
-
+
// TODO: Observe MFT reservation zone
// Can we get one contiguous run?
{
// we can't get one contiguous run
*AssignedClusters = RtlFindNextForwardRunClear(&Bitmap, FirstDesiredCluster, FirstAssignedCluster);
-
+
if (*AssignedClusters == 0)
{
// we couldn't find any runs starting at DesiredFirstCluster
*AssignedClusters = RtlFindLongestRunClear(&Bitmap, FirstAssignedCluster);
}
-
+
}
-
+
Status = WriteAttribute(DeviceExt, DataContext, 0, BitmapData, (ULONG)BitmapDataSize, &LengthWritten, BitmapRecord);
-
+
ReleaseAttributeContext(DataContext);
ExFreePoolWithTag(BitmapData, TAG_NTFS);