Author: tthompson
Date: Mon Aug 28 03:11:38 2017
New Revision: 75694
URL: http://svn.reactos.org/svn/reactos?rev=75694&view=rev
Log:
[NTFS] - Fix increasing the mft size, to keep chkdsk happy.
IncreaseMftSize() - Add some fixes. Write blank records to newly-allocated mft entries, and update $MFTMirr when finished; these changes are needed for chkdsk. Increase size by 64 records instead of 8.
+UpdateMftMirror() - Backs up the first ~4 master file table entries to the $MFTMirr file.
Modified:
branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/mft.c
branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/ntfs.h
Modified: branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/mft.c
URL: http://svn.reactos.org/svn/reactos/branches/GSoC_2016/NTFS/drivers/filesyst…
==============================================================================
--- branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/mft.c [iso-8859-1] (original)
+++ branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/mft.c [iso-8859-1] Mon Aug 28 03:11:38 2017
@@ -30,6 +30,7 @@
/* INCLUDES *****************************************************************/
#include "ntfs.h"
+#include <ntintsafe.h>
#define NDEBUG
#include <debug.h>
@@ -228,7 +229,7 @@
* STATUS_CANT_WAIT if CanWait was FALSE and the function could not get immediate, exclusive access to the MFT.
*
* @remarks
-* Increases the size of the Master File Table by 8 records. Bitmap entries for the new records are cleared,
+* Increases the size of the Master File Table by 64 records. Bitmap entries for the new records are cleared,
* and the bitmap is also enlarged if needed. Mimicking Windows' behavior when enlarging the mft is still TODO.
* This function will wait for exlusive access to the volume fcb.
*/
@@ -239,13 +240,17 @@
LARGE_INTEGER BitmapSize;
LARGE_INTEGER DataSize;
LONGLONG BitmapSizeDifference;
- ULONG DataSizeDifference = Vcb->NtfsInfo.BytesPerFileRecord * 8;
+ ULONG NewRecords = ATTR_RECORD_ALIGNMENT * 8; // Allocate one new record for every bit of every byte we'll be adding to the bitmap
+ ULONG DataSizeDifference = Vcb->NtfsInfo.BytesPerFileRecord * NewRecords;
ULONG BitmapOffset;
PUCHAR BitmapBuffer;
ULONGLONG BitmapBytes;
ULONGLONG NewBitmapSize;
+ ULONGLONG FirstNewMftIndex;
ULONG BytesRead;
ULONG LengthWritten;
+ PFILE_RECORD_HEADER BlankFileRecord;
+ ULONG i;
NTSTATUS Status;
DPRINT1("IncreaseMftSize(%p, %s)\n", Vcb, CanWait ? "TRUE" : "FALSE");
@@ -256,11 +261,23 @@
return STATUS_CANT_WAIT;
}
+ // Create a blank file record that will be used later
+ BlankFileRecord = NtfsCreateEmptyFileRecord(Vcb);
+ if (!BlankFileRecord)
+ {
+ DPRINT1("Error: Unable to create empty file record!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // Clear the flags (file record is not in use)
+ BlankFileRecord->Flags = 0;
+
// Find the bitmap attribute of master file table
- Status = FindAttribute(Vcb, Vcb->MasterFileTable, AttributeBitmap, L"", 0, &BitmapContext, &BitmapOffset);
+ Status = FindAttribute(Vcb, Vcb->MasterFileTable, AttributeBitmap, L"", 0, &BitmapContext, NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("ERROR: Couldn't find $BITMAP attribute of Mft!\n");
+ ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
ExReleaseResourceLite(&(Vcb->DirResource));
return Status;
}
@@ -271,9 +288,17 @@
// Calculate the new mft size
DataSize.QuadPart = AttributeDataLength(Vcb->MFTContext->pRecord) + DataSizeDifference;
+ // Find the index of the first Mft entry that will be created
+ FirstNewMftIndex = AttributeDataLength(Vcb->MFTContext->pRecord) / Vcb->NtfsInfo.BytesPerFileRecord;
+
// Determine how many bytes will make up the bitmap
BitmapBytes = DataSize.QuadPart / Vcb->NtfsInfo.BytesPerFileRecord / 8;
-
+ if ((DataSize.QuadPart / Vcb->NtfsInfo.BytesPerFileRecord) % 8 != 0)
+ BitmapBytes++;
+
+ // Windows will always keep the number of bytes in a bitmap as a multiple of 8, so no bytes are wasted on slack
+ BitmapBytes = ALIGN_UP_BY(BitmapBytes, ATTR_RECORD_ALIGNMENT);
+
// Determine how much we need to adjust the bitmap size (it's possible we don't)
BitmapSizeDifference = BitmapBytes - BitmapSize.QuadPart;
NewBitmapSize = max(BitmapSize.QuadPart + BitmapSizeDifference, BitmapSize.QuadPart);
@@ -283,6 +308,7 @@
if (!BitmapBuffer)
{
DPRINT1("ERROR: Unable to allocate memory for bitmap attribute!\n");
+ ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
ExReleaseResourceLite(&(Vcb->DirResource));
ReleaseAttributeContext(BitmapContext);
return STATUS_INSUFFICIENT_RESOURCES;
@@ -300,6 +326,7 @@
if (BytesRead != BitmapSize.LowPart)
{
DPRINT1("ERROR: Bytes read != Bitmap size!\n");
+ ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
ExReleaseResourceLite(&(Vcb->DirResource));
ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
ReleaseAttributeContext(BitmapContext);
@@ -311,17 +338,29 @@
if (!NT_SUCCESS(Status))
{
DPRINT1("ERROR: Failed to set size of $MFT data attribute!\n");
+ ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
ExReleaseResourceLite(&(Vcb->DirResource));
ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
ReleaseAttributeContext(BitmapContext);
return Status;
}
+
+ // We'll need to find the bitmap again, because its offset will have changed after resizing the data attribute
+ ReleaseAttributeContext(BitmapContext);
+ Status = FindAttribute(Vcb, Vcb->MasterFileTable, AttributeBitmap, L"", 0, &BitmapContext, &BitmapOffset);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ERROR: Couldn't find $BITMAP attribute of Mft!\n");
+ ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
+ ExReleaseResourceLite(&(Vcb->DirResource));
+ return Status;
+ }
// If the bitmap grew
if (BitmapSizeDifference > 0)
{
// Set the new bitmap size
- BitmapSize.QuadPart += BitmapSizeDifference;
+ BitmapSize.QuadPart = NewBitmapSize;
if (BitmapContext->pRecord->IsNonResident)
Status = SetNonResidentAttributeDataLength(Vcb, BitmapContext, BitmapOffset, Vcb->MasterFileTable, &BitmapSize);
else
@@ -330,6 +369,7 @@
if (!NT_SUCCESS(Status))
{
DPRINT1("ERROR: Failed to set size of bitmap attribute!\n");
+ ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
ExReleaseResourceLite(&(Vcb->DirResource));
ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
ReleaseAttributeContext(BitmapContext);
@@ -337,13 +377,14 @@
}
}
- //NtfsDumpFileAttributes(Vcb, FileRecord);
+ NtfsDumpFileAttributes(Vcb, Vcb->MasterFileTable);
// Update the file record with the new attribute sizes
Status = UpdateFileRecord(Vcb, Vcb->VolumeFcb->MFTIndex, Vcb->MasterFileTable);
if (!NT_SUCCESS(Status))
{
DPRINT1("ERROR: Failed to update $MFT file record!\n");
+ ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
ExReleaseResourceLite(&(Vcb->DirResource));
ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
ReleaseAttributeContext(BitmapContext);
@@ -351,9 +392,10 @@
}
// Write out the new bitmap
- Status = WriteAttribute(Vcb, BitmapContext, BitmapOffset, BitmapBuffer, BitmapSize.LowPart, &LengthWritten, Vcb->MasterFileTable);
- if (!NT_SUCCESS(Status))
- {
+ Status = WriteAttribute(Vcb, BitmapContext, 0, BitmapBuffer, NewBitmapSize, &LengthWritten, Vcb->MasterFileTable);
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
ExReleaseResourceLite(&(Vcb->DirResource));
ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
ReleaseAttributeContext(BitmapContext);
@@ -361,12 +403,31 @@
return Status;
}
+ // Create blank records for the new file record entries.
+ for (i = 0; i < NewRecords; i++)
+ {
+ Status = UpdateFileRecord(Vcb, FirstNewMftIndex + i, BlankFileRecord);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ERROR: Failed to write blank file record!\n");
+ ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
+ ExReleaseResourceLite(&(Vcb->DirResource));
+ ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
+ ReleaseAttributeContext(BitmapContext);
+ return Status;
+ }
+ }
+
+ // Update the mft mirror
+ Status = UpdateMftMirror(Vcb);
+
// Cleanup
+ ExFreePoolWithTag(BlankFileRecord, TAG_NTFS);
ExReleaseResourceLite(&(Vcb->DirResource));
ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
ReleaseAttributeContext(BitmapContext);
- return STATUS_SUCCESS;
+ return Status;
}
/**
@@ -2384,6 +2445,129 @@
}
}
+/**
+* @name UpdateMftMirror
+* @implemented
+*
+* Backs-up the first ~4 master file table entries to the $MFTMirr file.
+*
+* @param Vcb
+* Pointer to an NTFS_VCB for the volume whose Mft mirror is being updated.
+*
+* @returninja livecd
+
+* STATUS_SUCCESS on success.
+* STATUS_INSUFFICIENT_RESOURCES if an allocation failed.
+* STATUS_UNSUCCESSFUL if we couldn't read the master file table.
+*
+* @remarks
+* NTFS maintains up-to-date copies of the first several mft entries in the $MFTMirr file. Usually, the first 4 file
+* records from the mft are stored. The exact number of entries is determined by the size of $MFTMirr's $DATA.
+* If $MFTMirr is not up-to-date, chkdsk will reject every change it can find prior to when $MFTMirr was last updated.
+* Therefore, it's recommended to call this function if the volume changes considerably. For instance, IncreaseMftSize()
+* relies on this function to keep chkdsk from deleting the mft entries it creates. Note that under most instances, creating
+* or deleting a file will not affect the first ~four mft entries, and so will not require updating the mft mirror.
+*/
+NTSTATUS
+UpdateMftMirror(PNTFS_VCB Vcb)
+{
+ PFILE_RECORD_HEADER MirrorFileRecord;
+ PNTFS_ATTR_CONTEXT MirrDataContext;
+ PNTFS_ATTR_CONTEXT MftDataContext;
+ PCHAR DataBuffer;
+ ULONGLONG DataLength;
+ NTSTATUS Status;
+ ULONG BytesRead;
+ ULONG LengthWritten;
+
+ // Allocate memory for the Mft mirror file record
+ MirrorFileRecord = ExAllocatePoolWithTag(NonPagedPool, Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
+ if (!MirrorFileRecord)
+ {
+ DPRINT1("Error: Failed to allocate memory for $MFTMirr!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // Read the Mft Mirror file record
+ Status = ReadFileRecord(Vcb, NTFS_FILE_MFTMIRR, MirrorFileRecord);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ERROR: Failed to read $MFTMirr!\n");
+ ExFreePoolWithTag(MirrorFileRecord, TAG_NTFS);
+ return Status;
+ }
+
+ // Find the $DATA attribute of $MFTMirr
+ Status = FindAttribute(Vcb, MirrorFileRecord, AttributeData, L"", 0, &MirrDataContext, NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ERROR: Couldn't find $DATA attribute!\n");
+ ExFreePoolWithTag(MirrorFileRecord, TAG_NTFS);
+ return Status;
+ }
+
+ // Find the $DATA attribute of $MFT
+ Status = FindAttribute(Vcb, Vcb->MasterFileTable, AttributeData, L"", 0, &MftDataContext, NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ERROR: Couldn't find $DATA attribute!\n");
+ ReleaseAttributeContext(MirrDataContext);
+ ExFreePoolWithTag(MirrorFileRecord, TAG_NTFS);
+ return Status;
+ }
+
+ // Get the size of the mirror's $DATA attribute
+ DataLength = AttributeDataLength(MirrDataContext->pRecord);
+
+ ASSERT(DataLength % Vcb->NtfsInfo.BytesPerFileRecord == 0);
+
+ // Create buffer for the mirror's $DATA attribute
+ DataBuffer = ExAllocatePoolWithTag(NonPagedPool, DataLength, TAG_NTFS);
+ if (!DataBuffer)
+ {
+ DPRINT1("Error: Couldn't allocate memory for $DATA buffer!\n");
+ ReleaseAttributeContext(MftDataContext);
+ ReleaseAttributeContext(MirrDataContext);
+ ExFreePoolWithTag(MirrorFileRecord, TAG_NTFS);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ ASSERT(DataLength < ULONG_MAX);
+
+ // Back up the first several entries of the Mft's $DATA Attribute
+ BytesRead = ReadAttribute(Vcb, MftDataContext, 0, DataBuffer, (ULONG)DataLength);
+ if (BytesRead != (ULONG)DataLength)
+ {
+ DPRINT1("Error: Failed to read $DATA for $MFTMirr!\n");
+ ReleaseAttributeContext(MftDataContext);
+ ReleaseAttributeContext(MirrDataContext);
+ ExFreePoolWithTag(DataBuffer, TAG_NTFS);
+ ExFreePoolWithTag(MirrorFileRecord, TAG_NTFS);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ // Write the mirror's $DATA attribute
+ Status = WriteAttribute(Vcb,
+ MirrDataContext,
+ 0,
+ (PUCHAR)DataBuffer,
+ DataLength,
+ &LengthWritten,
+ MirrorFileRecord);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ERROR: Failed to write $DATA attribute of $MFTMirr!\n");
+ }
+
+ // Cleanup
+ ReleaseAttributeContext(MftDataContext);
+ ReleaseAttributeContext(MirrDataContext);
+ ExFreePoolWithTag(DataBuffer, TAG_NTFS);
+ ExFreePoolWithTag(MirrorFileRecord, TAG_NTFS);
+
+ return Status;
+}
+
#if 0
static
VOID
Modified: branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/ntfs.h
URL: http://svn.reactos.org/svn/reactos/branches/GSoC_2016/NTFS/drivers/filesyst…
==============================================================================
--- branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/ntfs.h [iso-8859-1] (original)
+++ branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/ntfs.h [iso-8859-1] Mon Aug 28 03:11:38 2017
@@ -1048,6 +1048,9 @@
BOOLEAN CaseSensitive);
NTSTATUS
+UpdateMftMirror(PNTFS_VCB Vcb);
+
+NTSTATUS
ReadFileRecord(PDEVICE_EXTENSION Vcb,
ULONGLONG index,
PFILE_RECORD_HEADER file);
Author: tthompson
Date: Sun Aug 27 14:37:17 2017
New Revision: 75692
URL: http://svn.reactos.org/svn/reactos?rev=75692&view=rev
Log:
[NTFS] - Add support for directory creation. Add some helper functions, some comments, and some fixes.
+AddIndexRoot() - Creates an $INDEX_ROOT attribute and adds it to a file record.
AddNewMftEntry() - Make sure the buffer used by RtlInitializeBitmap() is ULONG-aligned, and a ULONG-multiple in size, per MSDN.
AllocateIndexNode() - Calculate BytesNeeded correctly. Read $BITMAP attribute before increasing its length, in anticipation of a future commit that will check for a free bit before assigning a new index record to the end of the allocation. Use appropriate Set*AttributeDataLength() function, as $BITMAP can be resident or non-resident.
B_TREE_FILENAME_NODE - Give two members more accurate names: change "ExistsOnDisk" member to "HasValidVCN" and rename "NodeNumber" member "VCN."
+CreateEmptyBTree() - Creates a B-Tree to represent an empty directory (for AddIndexRoot).
+NtfsCreateEmptyFileRecord() - Creates an empty file record in memory, with no attributes.
CreateIndexRootFromBTree() - Fix TotalSizeOfEntries calculation.
+NtfsCreateDirectory() - Creates a file record for an empty directory and adds it to the mft.
Modified:
branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/attrib.c
branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/btree.c
branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/create.c
branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/mft.c
branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/ntfs.h
Modified: branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/attrib.c
URL: http://svn.reactos.org/svn/reactos/branches/GSoC_2016/NTFS/drivers/filesyst…
==============================================================================
--- branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/attrib.c [iso-8859-1] (original)
+++ branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/attrib.c [iso-8859-1] Sun Aug 27 14:37:17 2017
@@ -167,7 +167,11 @@
FileNameAttribute->LastWriteTime = SystemTime.QuadPart;
FileNameAttribute->LastAccessTime = SystemTime.QuadPart;
- FileNameAttribute->FileAttributes = NTFS_FILE_TYPE_ARCHIVE;
+ // Is this a directory?
+ if(FileRecord->Flags & FRH_DIRECTORY)
+ FileNameAttribute->FileAttributes = NTFS_FILE_TYPE_DIRECTORY;
+ else
+ FileNameAttribute->FileAttributes = NTFS_FILE_TYPE_ARCHIVE;
// we need to extract the filename from the path
DPRINT1("Pathname: %wZ\n", &FileObject->FileName);
@@ -252,6 +256,112 @@
SetFileRecordEnd(FileRecord, AttributeAddress, FileRecordEnd);
return Status;
+}
+
+/**
+* @name AddIndexRoot
+* @implemented
+*
+* Adds an $INDEX_ROOT attribute to a given FileRecord.
+*
+* @param Vcb
+* Pointer to an NTFS_VCB for the destination volume.
+*
+* @param FileRecord
+* Pointer to a complete file record to add the attribute to. Caller is responsible for
+* ensuring FileRecord is large enough to contain $INDEX_ROOT.
+*
+* @param AttributeAddress
+* Pointer to the region of memory that will receive the $INDEX_ROOT attribute.
+* This address must reside within FileRecord. Must be aligned to an 8-byte boundary (relative to FileRecord).
+*
+* @param NewIndexRoot
+* Pointer to an INDEX_ROOT_ATTRIBUTE containing the index root that will be copied to the new attribute.
+*
+* @param RootLength
+* The length of NewIndexRoot, in bytes.
+*
+* @param Name
+* Pointer to a string of 16-bit Unicode characters naming the attribute. Most often, this will be L"$I30".
+*
+* @param NameLength
+* The number of wide-characters in the name. L"$I30" Would use 4 here.
+*
+* @return
+* STATUS_SUCCESS on success. STATUS_NOT_IMPLEMENTED if target address isn't at the end
+* of the given file record.
+*
+* @remarks
+* This function is intended to assist in creating new folders.
+* Only adding the attribute to the end of the file record is supported; AttributeAddress must
+* be of type AttributeEnd.
+* It's the caller's responsibility to ensure the given file record has enough memory allocated
+* for the attribute, and this memory must have been zeroed.
+*/
+NTSTATUS
+AddIndexRoot(PNTFS_VCB Vcb,
+ PFILE_RECORD_HEADER FileRecord,
+ PNTFS_ATTR_RECORD AttributeAddress,
+ PINDEX_ROOT_ATTRIBUTE NewIndexRoot,
+ ULONG RootLength,
+ PCWSTR Name,
+ USHORT NameLength)
+{
+ ULONG AttributeLength;
+ // Calculate the header length
+ ULONG ResidentHeaderLength = FIELD_OFFSET(NTFS_ATTR_RECORD, Resident.Reserved) + sizeof(UCHAR);
+ // Back up the file record's final ULONG (even though it doesn't matter)
+ ULONG FileRecordEnd = AttributeAddress->Length;
+ ULONG NameOffset;
+ ULONG ValueOffset;
+ ULONG BytesAvailable;
+
+ if (AttributeAddress->Type != AttributeEnd)
+ {
+ DPRINT1("FIXME: Can only add $DATA attribute to the end of a file record.\n");
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ NameOffset = ResidentHeaderLength;
+
+ // Calculate ValueOffset, which will be aligned to a 4-byte boundary
+ ValueOffset = ALIGN_UP_BY(NameOffset + (sizeof(WCHAR) * NameLength), VALUE_OFFSET_ALIGNMENT);
+
+ // Calculate length of attribute
+ AttributeLength = ValueOffset + RootLength;
+ AttributeLength = ALIGN_UP_BY(AttributeLength, ATTR_RECORD_ALIGNMENT);
+
+ // Make sure the file record is large enough for the new attribute
+ BytesAvailable = Vcb->NtfsInfo.BytesPerFileRecord - FileRecord->BytesInUse;
+ if (BytesAvailable < AttributeLength)
+ {
+ DPRINT1("FIXME: Not enough room in file record for index allocation attribute!\n");
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ // Set Attribute fields
+ RtlZeroMemory(AttributeAddress, AttributeLength);
+
+ AttributeAddress->Type = AttributeIndexRoot;
+ AttributeAddress->Length = AttributeLength;
+ AttributeAddress->NameLength = NameLength;
+ AttributeAddress->NameOffset = NameOffset;
+ AttributeAddress->Instance = FileRecord->NextAttributeNumber++;
+
+ AttributeAddress->Resident.ValueLength = RootLength;
+ AttributeAddress->Resident.ValueOffset = ValueOffset;
+
+ // Set the name
+ RtlCopyMemory((PCHAR)((ULONG_PTR)AttributeAddress + NameOffset), Name, NameLength * sizeof(WCHAR));
+
+ // Copy the index root attribute
+ RtlCopyMemory((PCHAR)((ULONG_PTR)AttributeAddress + ValueOffset), NewIndexRoot, RootLength);
+
+ // 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);
+ SetFileRecordEnd(FileRecord, AttributeAddress, FileRecordEnd);
+
+ return STATUS_SUCCESS;
}
/**
Modified: branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/btree.c
URL: http://svn.reactos.org/svn/reactos/branches/GSoC_2016/NTFS/drivers/filesyst…
==============================================================================
--- branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/btree.c [iso-8859-1] (original)
+++ branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/btree.c [iso-8859-1] Sun Aug 27 14:37:17 2017
@@ -111,6 +111,7 @@
* @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.
+* Possible TODO: Create an empty node and write it to the allocated index node, so the index allocation is always valid.
*/
NTSTATUS
AllocateIndexNode(PDEVICE_EXTENSION DeviceExt,
@@ -167,11 +168,30 @@
// See how many bytes we need to store the amount of bits we'll have
BytesNeeded = NextNodeNumber / 8;
- if (NextNodeNumber % 8 != 0)
- BytesNeeded++;
+ BytesNeeded++;
// Windows seems to allocate the bitmap in 8-byte chunks to keep any bytes from being wasted on padding
- ALIGN_UP(BytesNeeded, ATTR_RECORD_ALIGNMENT);
+ BytesNeeded = ALIGN_UP(BytesNeeded, ATTR_RECORD_ALIGNMENT);
+
+ // 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)
+ {
+ DPRINT1("Error: failed to allocate bitmap!");
+ ReleaseAttributeContext(BitmapCtx);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ // RtlInitializeBitmap() wants a pointer that's ULONG-aligned.
+ BitmapPtr = (PULONG)ALIGN_UP_BY((ULONG_PTR)BitmapMem, sizeof(ULONG));
+
+ RtlZeroMemory(BitmapPtr, BytesNeeded);
+
+ // Read the existing bitmap data
+ Status = ReadAttribute(DeviceExt, BitmapCtx, 0, (PCHAR)BitmapPtr, BitmapLength);
+
+ // Initialize bitmap
+ RtlInitializeBitMap(&Bitmap, BitmapPtr, NextNodeNumber);
// Do we need to enlarge the bitmap?
if (BytesNeeded > BitmapLength)
@@ -179,11 +199,22 @@
// TODO: handle synchronization issues that could occur from changing the directory's file record
// Change bitmap size
DataSize.QuadPart = BytesNeeded;
- Status = SetResidentAttributeDataLength(DeviceExt,
- BitmapCtx,
- BitmapOffset,
- FileRecord,
- &DataSize);
+ if (BitmapCtx->pRecord->IsNonResident)
+ {
+ Status = SetNonResidentAttributeDataLength(DeviceExt,
+ BitmapCtx,
+ BitmapOffset,
+ FileRecord,
+ &DataSize);
+ }
+ else
+ {
+ Status = SetResidentAttributeDataLength(DeviceExt,
+ BitmapCtx,
+ BitmapOffset,
+ FileRecord,
+ &DataSize);
+ }
if (!NT_SUCCESS(Status))
{
DPRINT1("ERROR: Failed to set length of bitmap attribute!\n");
@@ -214,18 +245,6 @@
ReleaseAttributeContext(BitmapCtx);
return Status;
}
-
- // Allocate memory for the bitmap. RtlInitializeBitmap() wants a pointer that's ULONG-aligned
- BitmapMem = ExAllocatePoolWithTag(NonPagedPool, BytesNeeded + sizeof(ULONG) - 1, TAG_NTFS);
- BitmapPtr = (PULONG)ALIGN_UP_BY((ULONG_PTR)BitmapMem, sizeof(ULONG));
-
- RtlZeroMemory(BitmapPtr, BytesNeeded);
-
- // Read the existing bitmap data
- Status = ReadAttribute(DeviceExt, BitmapCtx, 0, (PCHAR)BitmapPtr, BitmapLength);
-
- // Initialize bitmap
- RtlInitializeBitMap(&Bitmap, BitmapPtr, BytesNeeded);
// Set the bit for the new index record
RtlSetBits(&Bitmap, NextNodeNumber, 1);
@@ -246,6 +265,8 @@
// Calculate VCN of new node number
*NewVCN = NextNodeNumber * (IndexBufferSize / DeviceExt->NtfsInfo.BytesPerCluster);
+ DPRINT("New VCN: %I64u\n", *NewVCN);
+
ExFreePoolWithTag(BitmapMem, TAG_NTFS);
ReleaseAttributeContext(BitmapCtx);
@@ -309,6 +330,63 @@
NewDummyKey->IndexEntry = NewIndexEntry;
return NewDummyKey;
+}
+
+/**
+* @name CreateEmptyBTree
+* @implemented
+*
+* Creates an empty B-Tree, which will contain a single root node which will contain a single dummy key.
+*
+* @param NewTree
+* Pointer to a PB_TREE that will receive the pointer of the newly-created B-Tree.
+*
+* @return
+* STATUS_SUCCESS on success. STATUS_INSUFFICIENT_RESOURCES if an allocation fails.
+*/
+NTSTATUS
+CreateEmptyBTree(PB_TREE *NewTree)
+{
+ 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 DummyKey;
+
+ DPRINT1("CreateEmptyBTree(%p) called\n", NewTree);
+
+ if (!Tree || !RootNode)
+ {
+ DPRINT1("Couldn't allocate enough memory for B-Tree!\n");
+ if (Tree)
+ ExFreePoolWithTag(Tree, TAG_NTFS);
+ if (RootNode)
+ ExFreePoolWithTag(RootNode, TAG_NTFS);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // Create the dummy key
+ DummyKey = CreateDummyKey(FALSE);
+ if (!DummyKey)
+ {
+ DPRINT1("ERROR: Failed to create dummy key!\n");
+ ExFreePoolWithTag(Tree, TAG_NTFS);
+ ExFreePoolWithTag(RootNode, TAG_NTFS);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(Tree, sizeof(B_TREE));
+ RtlZeroMemory(RootNode, sizeof(B_TREE_FILENAME_NODE));
+
+ // Setup the Tree
+ RootNode->FirstKey = DummyKey;
+ RootNode->KeyCount = 1;
+ RootNode->DiskNeedsUpdating = TRUE;
+ Tree->RootNode = RootNode;
+
+ *NewTree = Tree;
+
+ // Memory will be freed when DestroyBTree() is called
+
+ return STATUS_SUCCESS;
}
/**
@@ -402,7 +480,7 @@
ULONG CurrentEntryOffset = 0;
PINDEX_BUFFER NodeBuffer;
ULONG IndexBufferSize = Vcb->NtfsInfo.BytesPerIndexRecord;
- PULONGLONG NodeNumber;
+ PULONGLONG VCN;
PB_TREE_KEY CurrentKey;
NTSTATUS Status;
ULONGLONG IndexNodeOffset;
@@ -415,10 +493,9 @@
}
// Get the node number from the end of the node entry
- NodeNumber = (PULONGLONG)((ULONG_PTR)NodeEntry + NodeEntry->Length - sizeof(ULONGLONG));
+ VCN = (PULONGLONG)((ULONG_PTR)NodeEntry + NodeEntry->Length - sizeof(ULONGLONG));
// Create the new tree node
- DPRINT1("About to allocate %ld for NewNode\n", sizeof(B_TREE_FILENAME_NODE));
NewNode = ExAllocatePoolWithTag(NonPagedPool, sizeof(B_TREE_FILENAME_NODE), TAG_NTFS);
if (!NewNode)
{
@@ -449,7 +526,7 @@
}
// Calculate offset into index allocation
- IndexNodeOffset = GetAllocationOffsetFromVCN(Vcb, IndexBufferSize, *NodeNumber);
+ IndexNodeOffset = GetAllocationOffsetFromVCN(Vcb, IndexBufferSize, *VCN);
// TODO: Confirm index bitmap has this node marked as in-use
@@ -462,7 +539,7 @@
ASSERT(BytesRead == IndexBufferSize);
NT_ASSERT(NodeBuffer->Ntfs.Type == NRH_INDX_TYPE);
- NT_ASSERT(NodeBuffer->VCN == *NodeNumber);
+ NT_ASSERT(NodeBuffer->VCN == *VCN);
// Apply the fixup array to the node buffer
Status = FixupUpdateSequenceArray(Vcb, &NodeBuffer->Ntfs);
@@ -516,8 +593,6 @@
// See if the current key has a sub-node
if (CurrentKey->IndexEntry->Flags & NTFS_INDEX_ENTRY_NODE)
{
- DPRINT1("TODO: Only a node with a single-level is supported right now!\n");
- // Needs debugging:
CurrentKey->LesserChild = CreateBTreeNodeFromIndexNode(Vcb,
IndexRoot,
IndexAllocationAttributeCtx,
@@ -535,8 +610,6 @@
// See if the current key has a sub-node
if (CurrentKey->IndexEntry->Flags & NTFS_INDEX_ENTRY_NODE)
{
- DPRINT1("TODO: Only a node with a single-level is supported right now!\n");
- // Needs debugging:
CurrentKey->LesserChild = CreateBTreeNodeFromIndexNode(Vcb,
IndexRoot,
IndexAllocationAttributeCtx,
@@ -551,8 +624,8 @@
CurrentNodeEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)CurrentNodeEntry + CurrentNodeEntry->Length);
}
- NewNode->NodeNumber = *NodeNumber;
- NewNode->ExistsOnDisk = TRUE;
+ NewNode->VCN = *VCN;
+ NewNode->HasValidVCN = TRUE;
ExFreePoolWithTag(NodeBuffer, TAG_NTFS);
@@ -622,8 +695,6 @@
NULL);
if (!NT_SUCCESS(Status))
IndexAllocationContext = NULL;
- else
- PrintAllVCNs(Vcb, IndexAllocationContext, IndexRoot->SizeOfEntry);
// Setup the Tree
RootNode->FirstKey = CurrentKey;
@@ -871,7 +942,7 @@
NewIndexRoot->Header.Flags = INDEX_ROOT_LARGE;
// Add Length of Current Entry to Total Size of Entries
- NewIndexRoot->Header.TotalSizeOfEntries += CurrentNodeEntry->Length;
+ NewIndexRoot->Header.TotalSizeOfEntries += CurrentKey->IndexEntry->Length;
// Go to the next node entry
CurrentNodeEntry = (PINDEX_ENTRY_ATTRIBUTE)((ULONG_PTR)CurrentNodeEntry + CurrentNodeEntry->Length);
@@ -905,10 +976,12 @@
IndexBuffer->Ntfs.UsaCount = 9;
// TODO: Check bitmap for VCN
- ASSERT(Node->ExistsOnDisk);
- IndexBuffer->VCN = Node->NodeNumber;
-
- IndexBuffer->Header.FirstEntryOffset = 0x28;
+ ASSERT(Node->HasValidVCN);
+ IndexBuffer->VCN = Node->VCN;
+
+ // 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.AllocatedSize = BufferSize - FIELD_OFFSET(INDEX_BUFFER, Header);
// Start summing the total size of this node's entries
@@ -934,9 +1007,9 @@
// Copy the index entry
RtlCopyMemory(CurrentNodeEntry, CurrentKey->IndexEntry, CurrentKey->IndexEntry->Length);
- DPRINT1("Index Node Entry Stream Length: %u\nIndex Node Entry Length: %u\n",
- CurrentNodeEntry->KeyLength,
- CurrentNodeEntry->Length);
+ DPRINT("Index Node Entry Stream Length: %u\nIndex Node Entry Length: %u\n",
+ CurrentNodeEntry->KeyLength,
+ CurrentNodeEntry->Length);
// Add Length of Current Entry to Total Size of Entries
IndexBuffer->Header.TotalSizeOfEntries += CurrentNodeEntry->Length;
@@ -1019,14 +1092,6 @@
{
DPRINT1("FIXME: Need to add index allocation\n");
return STATUS_NOT_IMPLEMENTED;
- }
-
- Status = UpdateIndexNode(DeviceExt, FileRecord, CurrentKey->LesserChild, IndexBufferSize, IndexAllocationContext, IndexAllocationOffset, BitmapContext);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("ERROR: Failed to update index node!\n");
- ReleaseAttributeContext(IndexAllocationContext);
- return Status;
}
// Is the Index Entry large enough to store the VCN?
@@ -1056,9 +1121,17 @@
CurrentKey->IndexEntry->Flags |= NTFS_INDEX_ENTRY_NODE;
}
+ // Update the sub-node
+ Status = UpdateIndexNode(DeviceExt, FileRecord, CurrentKey->LesserChild, IndexBufferSize, IndexAllocationContext, IndexAllocationOffset, BitmapContext);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ERROR: Failed to update index node!\n");
+ ReleaseAttributeContext(IndexAllocationContext);
+ return Status;
+ }
+
// Update the VCN stored in the index entry of CurrentKey
- SetIndexEntryVCN(CurrentKey->IndexEntry, CurrentKey->LesserChild->NodeNumber);
-
+ SetIndexEntryVCN(CurrentKey->IndexEntry, CurrentKey->LesserChild->VCN);
}
CurrentKey = CurrentKey->NextKey;
}
@@ -1096,7 +1169,7 @@
IndexAllocationContext,
IndexAllocationOffset,
BitmapContext,
- Node->NodeNumber);
+ Node->VCN);
// Do we need to write this node to disk?
if (Node->DiskNeedsUpdating)
@@ -1106,7 +1179,7 @@
PINDEX_BUFFER IndexBuffer;
// Does the node need to be assigned a VCN?
- if (!Node->ExistsOnDisk)
+ if (!Node->HasValidVCN)
{
// Allocate the node
Status = AllocateIndexNode(DeviceExt,
@@ -1114,14 +1187,14 @@
IndexBufferSize,
IndexAllocationContext,
IndexAllocationOffset,
- &Node->NodeNumber);
+ &Node->VCN);
if (!NT_SUCCESS(Status))
{
DPRINT1("ERROR: Failed to allocate index record in index allocation!\n");
return Status;
}
- Node->ExistsOnDisk = TRUE;
+ Node->HasValidVCN = TRUE;
}
// Allocate memory for an index buffer
@@ -1142,7 +1215,7 @@
}
// Get Offset of index buffer in index allocation
- NodeOffset = GetAllocationOffsetFromVCN(DeviceExt, IndexBufferSize, Node->NodeNumber);
+ NodeOffset = GetAllocationOffsetFromVCN(DeviceExt, IndexBufferSize, Node->VCN);
// Write the buffer to the index allocation
Status = WriteAttribute(DeviceExt, IndexAllocationContext, NodeOffset, (const PUCHAR)IndexBuffer, IndexBufferSize, &LengthWritten, FileRecord);
@@ -1274,7 +1347,7 @@
}
VOID
-DumpBTreeKey(PB_TREE_KEY Key, ULONG Number, ULONG Depth)
+DumpBTreeKey(PB_TREE Tree, PB_TREE_KEY Key, ULONG Number, ULONG Depth)
{
ULONG i;
for (i = 0; i < Depth; i++)
@@ -1298,7 +1371,7 @@
if (Key->IndexEntry->Flags & NTFS_INDEX_ENTRY_NODE)
{
if (Key->LesserChild)
- DumpBTreeNode(Key->LesserChild, Number, Depth + 1);
+ DumpBTreeNode(Tree, Key->LesserChild, Number, Depth + 1);
else
{
// This will be an assert once nodes with arbitrary depth are debugged
@@ -1308,18 +1381,28 @@
}
VOID
-DumpBTreeNode(PB_TREE_FILENAME_NODE Node, ULONG Number, ULONG Depth)
+DumpBTreeNode(PB_TREE Tree,
+ PB_TREE_FILENAME_NODE Node,
+ ULONG Number,
+ ULONG Depth)
{
PB_TREE_KEY CurrentKey;
ULONG i;
for (i = 0; i < Depth; i++)
DbgPrint(" ");
- DbgPrint("Node #%d, Depth %d, has %d key%s\n", Number, Depth, Node->KeyCount, Node->KeyCount == 1 ? "" : "s");
+ DbgPrint("Node #%d, Depth %d, has %d key%s", Number, Depth, Node->KeyCount, Node->KeyCount == 1 ? "" : "s");
+
+ if (Node->HasValidVCN)
+ DbgPrint(" VCN: %I64u\n", Node->VCN);
+ else if (Tree->RootNode == Node)
+ DbgPrint(" Index Root");
+ else
+ DbgPrint(" NOT ASSIGNED VCN YET\n");
CurrentKey = Node->FirstKey;
- for (i = 1; i <= Node->KeyCount; i++)
- {
- DumpBTreeKey(CurrentKey, i, Depth);
+ for (i = 0; i < Node->KeyCount; i++)
+ {
+ DumpBTreeKey(Tree, CurrentKey, i, Depth);
CurrentKey = CurrentKey->NextKey;
}
}
@@ -1340,7 +1423,7 @@
DumpBTree(PB_TREE Tree)
{
DbgPrint("B_TREE @ %p\n", Tree);
- DumpBTreeNode(Tree->RootNode, 0, 0);
+ DumpBTreeNode(Tree, Tree->RootNode, 0, 0);
}
// Calculates start of Index Buffer relative to the index allocation, given the node's VCN
@@ -1525,7 +1608,6 @@
NewIndexRoot->FirstKey = DummyKey;
NewIndexRoot->KeyCount = 1;
NewIndexRoot->DiskNeedsUpdating = TRUE;
- NewIndexRoot->ExistsOnDisk = TRUE;
// Make the new node the Tree's root node
Tree->RootNode = NewIndexRoot;
Modified: branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/create.c
URL: http://svn.reactos.org/svn/reactos/branches/GSoC_2016/NTFS/drivers/filesyst…
==============================================================================
--- branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/create.c [iso-8859-1] (original)
+++ branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/create.c [iso-8859-1] Sun Aug 27 14:37:17 2017
@@ -569,25 +569,31 @@
return STATUS_ACCESS_DENIED;
}
- // We can't create directories yet
+ // Was the user trying to create a directory?
if (RequestedOptions & FILE_DIRECTORY_FILE)
{
- DPRINT1("FIXME: Folder creation is still TODO!\n");
- return STATUS_NOT_IMPLEMENTED;
+ // Create the directory on disk
+ Status = NtfsCreateDirectory(DeviceExt,
+ FileObject,
+ BooleanFlagOn(Stack->Flags, SL_CASE_SENSITIVE),
+ BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT));
}
-
- // Create the file record on disk
- Status = NtfsCreateFileRecord(DeviceExt,
- FileObject,
- BooleanFlagOn(Stack->Flags, SL_CASE_SENSITIVE),
- BooleanFlagOn(IrpContext->Flags,IRPCONTEXT_CANWAIT));
+ else
+ {
+ // Create the file record on disk
+ Status = NtfsCreateFileRecord(DeviceExt,
+ FileObject,
+ BooleanFlagOn(Stack->Flags, SL_CASE_SENSITIVE),
+ BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT));
+ }
+
if (!NT_SUCCESS(Status))
{
DPRINT1("ERROR: Couldn't create file record!\n");
return Status;
}
- // Before we open the file we just created, we need to change the disposition (upper 8 bits of ULONG)
+ // Before we open the file/directory we just created, we need to change the disposition (upper 8 bits of ULONG)
// from create to open, since we already created the file
Stack->Parameters.Create.Options = (ULONG)FILE_OPEN << 24 | RequestedOptions;
@@ -649,6 +655,215 @@
return Status;
}
+
+/**
+* @name NtfsCreateDirectory()
+* @implemented
+*
+* Creates a file record for a new directory and saves it to the MFT. Adds the filename attribute of the
+* created directory to the parent directory's index.
+*
+* @param DeviceExt
+* Points to the target disk's DEVICE_EXTENSION
+*
+* @param FileObject
+* Pointer to a FILE_OBJECT describing the directory to be created
+*
+* @param CaseSensitive
+* Boolean indicating if the function should operate in case-sensitive mode. This will be TRUE
+* if an application created the folder with the FILE_FLAG_POSIX_SEMANTICS flag.
+*
+* @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_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
+* couldn't get immediate, exclusive access to it.
+*/
+NTSTATUS
+NtfsCreateDirectory(PDEVICE_EXTENSION DeviceExt,
+ PFILE_OBJECT FileObject,
+ BOOLEAN CaseSensitive,
+ BOOLEAN CanWait)
+{
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ PFILE_RECORD_HEADER FileRecord;
+ PNTFS_ATTR_RECORD NextAttribute;
+ PFILENAME_ATTRIBUTE FilenameAttribute;
+ ULONGLONG ParentMftIndex;
+ ULONGLONG FileMftIndex;
+ PB_TREE Tree;
+ PINDEX_ROOT_ATTRIBUTE NewIndexRoot;
+ ULONG RootLength;
+
+ DPRINT1("NtfsCreateFileRecord(%p, %p, %s, %s)\n",
+ DeviceExt,
+ FileObject,
+ CaseSensitive ? "TRUE" : "FALSE",
+ CanWait ? "TRUE" : "FALSE");
+
+ // Start with an empty file record
+ FileRecord = NtfsCreateEmptyFileRecord(DeviceExt);
+ if (!FileRecord)
+ {
+ DPRINT1("ERROR: Unable to allocate memory for file record!\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // Set the directory flag
+ FileRecord->Flags |= FRH_DIRECTORY;
+
+ // find where the first attribute will be added
+ NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
+
+ // add first attribute, $STANDARD_INFORMATION
+ AddStandardInformation(FileRecord, NextAttribute);
+
+ // advance NextAttribute pointer to the next attribute
+ NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)NextAttribute + (ULONG_PTR)NextAttribute->Length);
+
+ // Add the $FILE_NAME attribute
+ AddFileName(FileRecord, NextAttribute, DeviceExt, FileObject, CaseSensitive, &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);
+
+ // Create an empty b-tree to represent our new index
+ Status = CreateEmptyBTree(&Tree);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ERROR: Failed to create empty B-Tree!\n");
+ ExFreePoolWithTag(FileRecord, TAG_NTFS);
+ return Status;
+ }
+
+ // Calculate maximum size of index root
+ ULONG MaxIndexRootSize = DeviceExt->NtfsInfo.BytesPerFileRecord
+ - ((ULONG_PTR)NextAttribute - (ULONG_PTR)FileRecord)
+ - sizeof(ULONG) * 2;
+
+ // Create a new index record from the tree
+ Status = CreateIndexRootFromBTree(DeviceExt,
+ Tree,
+ MaxIndexRootSize,
+ &NewIndexRoot,
+ &RootLength);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ERROR: Unable to create empty index root!\n");
+ DestroyBTree(Tree);
+ ExFreePoolWithTag(FileRecord, TAG_NTFS);
+ return Status;
+ }
+
+ // We're done with the B-Tree
+ DestroyBTree(Tree);
+
+ // add the $INDEX_ROOT attribute
+ Status = AddIndexRoot(DeviceExt, FileRecord, NextAttribute, NewIndexRoot, RootLength, L"$I30", 4);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("ERROR: Failed to add index root to new file record!\n");
+ ExFreePoolWithTag(FileRecord, TAG_NTFS);
+ return Status;
+ }
+
+
+#ifndef NDEBUG
+ NtfsDumpFileRecord(DeviceExt, FileRecord);
+#endif
+
+ // Now that we've built the file record in memory, we need to store it in the MFT.
+ Status = AddNewMftEntry(FileRecord, DeviceExt, &FileMftIndex, CanWait);
+ 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,
+ CaseSensitive);
+ }
+
+ ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
+ ExFreePoolWithTag(FileRecord, TAG_NTFS);
+
+ return Status;
+}
+
+/**
+* @name NtfsCreateEmptyFileRecord
+* @implemented
+*
+* Creates a new, empty file record, with no attributes.
+*
+* @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.
+*/
+PFILE_RECORD_HEADER
+NtfsCreateEmptyFileRecord(PDEVICE_EXTENSION DeviceExt)
+{
+ PFILE_RECORD_HEADER FileRecord;
+ PNTFS_ATTR_RECORD NextAttribute;
+
+ DPRINT1("NtfsCreateEmptyFileRecord(%p)\n", DeviceExt);
+
+ // allocate memory for file record
+ FileRecord = ExAllocatePoolWithTag(NonPagedPool,
+ DeviceExt->NtfsInfo.BytesPerFileRecord,
+ TAG_NTFS);
+ if (!FileRecord)
+ {
+ DPRINT1("ERROR: Unable to allocate memory for file record!\n");
+ return NULL;
+ }
+
+ RtlZeroMemory(FileRecord, DeviceExt->NtfsInfo.BytesPerFileRecord);
+
+ FileRecord->Ntfs.Type = NRH_FILE_TYPE;
+
+ // calculate USA offset and count
+ FileRecord->Ntfs.UsaOffset = FIELD_OFFSET(FILE_RECORD_HEADER, MFTRecordNumber) + sizeof(ULONG);
+
+ // size of USA (in ULONG's) will be 1 (for USA number) + 1 for every sector the file record uses
+ FileRecord->BytesAllocated = DeviceExt->NtfsInfo.BytesPerFileRecord;
+ FileRecord->Ntfs.UsaCount = (FileRecord->BytesAllocated / DeviceExt->NtfsInfo.BytesPerSector) + 1;
+
+ // setup other file record fields
+ FileRecord->SequenceNumber = 1;
+ FileRecord->AttributeOffset = FileRecord->Ntfs.UsaOffset + (2 * FileRecord->Ntfs.UsaCount);
+ FileRecord->AttributeOffset = ALIGN_UP_BY(FileRecord->AttributeOffset, ATTR_RECORD_ALIGNMENT);
+ FileRecord->Flags = FRH_IN_USE;
+ FileRecord->BytesInUse = FileRecord->AttributeOffset + sizeof(ULONG) * 2;
+
+ // find where the first attribute will be added
+ NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
+
+ // mark the (temporary) end of the file-record
+ NextAttribute->Type = AttributeEnd;
+ NextAttribute->Length = FILE_RECORD_END;
+
+ return FileRecord;
+}
+
/**
* @name NtfsCreateFileRecord()
@@ -693,43 +908,19 @@
CanWait ? "TRUE" : "FALSE");
// allocate memory for file record
- FileRecord = ExAllocatePoolWithTag(NonPagedPool,
- DeviceExt->NtfsInfo.BytesPerFileRecord,
- TAG_NTFS);
+ FileRecord = NtfsCreateEmptyFileRecord(DeviceExt);
if (!FileRecord)
{
DPRINT1("ERROR: Unable to allocate memory for file record!\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
- RtlZeroMemory(FileRecord, DeviceExt->NtfsInfo.BytesPerFileRecord);
-
- FileRecord->Ntfs.Type = NRH_FILE_TYPE;
-
- // calculate USA offset and count
- FileRecord->Ntfs.UsaOffset = FIELD_OFFSET(FILE_RECORD_HEADER, MFTRecordNumber) + sizeof(ULONG);
-
- // size of USA (in ULONG's) will be 1 (for USA number) + 1 for every sector the file record uses
- FileRecord->BytesAllocated = DeviceExt->NtfsInfo.BytesPerFileRecord;
- FileRecord->Ntfs.UsaCount = (FileRecord->BytesAllocated / DeviceExt->NtfsInfo.BytesPerSector) + 1;
-
- // setup other file record fields
- FileRecord->SequenceNumber = 1;
- FileRecord->AttributeOffset = FileRecord->Ntfs.UsaOffset + (2 * FileRecord->Ntfs.UsaCount);
- FileRecord->AttributeOffset = ALIGN_UP_BY(FileRecord->AttributeOffset, ATTR_RECORD_ALIGNMENT);
- FileRecord->Flags = FRH_IN_USE;
- FileRecord->BytesInUse = FileRecord->AttributeOffset + sizeof(ULONG) * 2;
-
// find where the first attribute will be added
NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
- // mark the (temporary) end of the file-record
- NextAttribute->Type = AttributeEnd;
- NextAttribute->Length = FILE_RECORD_END;
-
// add first attribute, $STANDARD_INFORMATION
AddStandardInformation(FileRecord, NextAttribute);
-
+
// advance NextAttribute pointer to the next attribute
NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)NextAttribute + (ULONG_PTR)NextAttribute->Length);
@@ -745,8 +936,10 @@
// add the $DATA attribute
AddData(FileRecord, NextAttribute);
+#ifndef NDEBUG
// dump file record in memory (for debugging)
NtfsDumpFileRecord(DeviceExt, FileRecord);
+#endif
// Now that we've built the file record in memory, we need to store it in the MFT.
Status = AddNewMftEntry(FileRecord, DeviceExt, &FileMftIndex, CanWait);
Modified: branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/mft.c
URL: http://svn.reactos.org/svn/reactos/branches/GSoC_2016/NTFS/drivers/filesyst…
==============================================================================
--- branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/mft.c [iso-8859-1] (original)
+++ branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/mft.c [iso-8859-1] Sun Aug 27 14:37:17 2017
@@ -1893,6 +1893,7 @@
ULONGLONG BitmapDataSize;
ULONGLONG AttrBytesRead;
PUCHAR BitmapData;
+ PUCHAR BitmapBuffer;
ULONG LengthWritten;
PNTFS_ATTR_CONTEXT BitmapContext;
LARGE_INTEGER BitmapBits;
@@ -1901,6 +1902,8 @@
DPRINT1("AddNewMftEntry(%p, %p, %p, %s)\n", FileRecord, DeviceExt, DestinationIndex, CanWait ? "TRUE" : "FALSE");
// First, we have to read the mft's $Bitmap attribute
+
+ // Find the attribute
Status = FindAttribute(DeviceExt, DeviceExt->MasterFileTable, AttributeBitmap, L"", 0, &BitmapContext, NULL);
if (!NT_SUCCESS(Status))
{
@@ -1908,22 +1911,28 @@
return Status;
}
- // allocate a buffer for the $Bitmap attribute
+ // Get size of bitmap
BitmapDataSize = AttributeDataLength(BitmapContext->pRecord);
- BitmapData = ExAllocatePoolWithTag(NonPagedPool, BitmapDataSize, TAG_NTFS);
- if (!BitmapData)
+
+ // RtlInitializeBitmap wants a ULONG-aligned pointer, and wants the memory passed to it to be a ULONG-multiple
+ // Allocate a buffer for the $Bitmap attribute plus enough to ensure we can get a ULONG-aligned pointer
+ BitmapBuffer = ExAllocatePoolWithTag(NonPagedPool, BitmapDataSize + sizeof(ULONG), TAG_NTFS);
+ if (!BitmapBuffer)
{
ReleaseAttributeContext(BitmapContext);
return STATUS_INSUFFICIENT_RESOURCES;
}
+ // Get a ULONG-aligned pointer for the bitmap itself
+ BitmapData = (PUCHAR)ALIGN_UP_BY((ULONG_PTR)BitmapBuffer, sizeof(ULONG));
+
// read $Bitmap attribute
AttrBytesRead = ReadAttribute(DeviceExt, BitmapContext, 0, (PCHAR)BitmapData, BitmapDataSize);
- if (AttrBytesRead == 0)
+ if (AttrBytesRead != BitmapDataSize)
{
DPRINT1("ERROR: Unable to read $Bitmap attribute of master file table!\n");
- ExFreePoolWithTag(BitmapData, TAG_NTFS);
+ ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
ReleaseAttributeContext(BitmapContext);
return STATUS_OBJECT_NAME_NOT_FOUND;
}
@@ -1939,7 +1948,8 @@
if (BitmapBits.HighPart != 0)
{
DPRINT1("\tFIXME: bitmap sizes beyond 32bits are not yet supported! (Your NTFS volume is too large)\n");
- ExFreePoolWithTag(BitmapData, TAG_NTFS);
+ NtfsGlobalData->EnableWriteSupport = FALSE;
+ ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
ReleaseAttributeContext(BitmapContext);
return STATUS_NOT_IMPLEMENTED;
}
@@ -1953,7 +1963,7 @@
{
DPRINT1("Couldn't find free space in MFT for file record, increasing MFT size.\n");
- ExFreePoolWithTag(BitmapData, TAG_NTFS);
+ ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
ReleaseAttributeContext(BitmapContext);
// Couldn't find a free record in the MFT, add some blank records and try again
@@ -1982,7 +1992,7 @@
if (!NT_SUCCESS(Status))
{
DPRINT1("ERROR encountered when writing $Bitmap attribute!\n");
- ExFreePoolWithTag(BitmapData, TAG_NTFS);
+ ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
ReleaseAttributeContext(BitmapContext);
return Status;
}
@@ -1993,14 +2003,14 @@
if (!NT_SUCCESS(Status))
{
DPRINT1("ERROR: Unable to write file record!\n");
- ExFreePoolWithTag(BitmapData, TAG_NTFS);
+ ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
ReleaseAttributeContext(BitmapContext);
return Status;
}
*DestinationIndex = MftIndex;
- ExFreePoolWithTag(BitmapData, TAG_NTFS);
+ ExFreePoolWithTag(BitmapBuffer, TAG_NTFS);
ReleaseAttributeContext(BitmapContext);
return Status;
@@ -2255,7 +2265,7 @@
AttributeLength,
&LengthWritten,
ParentFileRecord);
- if (!NT_SUCCESS(Status))
+ if (!NT_SUCCESS(Status) || LengthWritten != AttributeLength)
{
DPRINT1("ERROR: Unable to write new index root attribute to parent directory!\n");
ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
Modified: branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/ntfs.h
URL: http://svn.reactos.org/svn/reactos/branches/GSoC_2016/NTFS/drivers/filesyst…
==============================================================================
--- branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/ntfs.h [iso-8859-1] (original)
+++ branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/ntfs.h [iso-8859-1] Sun Aug 27 14:37:17 2017
@@ -304,6 +304,12 @@
// relative to the beginning of the file record.
#define ATTR_RECORD_ALIGNMENT 8
+// Data runs are aligned to a 4-byte boundary, relative to the start of the attribute record
+#define DATA_RUN_ALIGNMENT 4
+
+// Value offset is aligned to a 4-byte boundary, relative to the start of the attribute record
+#define VALUE_OFFSET_ALIGNMENT 4
+
typedef struct
{
ULONGLONG CreationTime;
@@ -423,9 +429,9 @@
typedef struct _B_TREE_FILENAME_NODE
{
ULONG KeyCount;
- BOOLEAN ExistsOnDisk;
+ BOOLEAN HasValidVCN;
BOOLEAN DiskNeedsUpdating;
- ULONGLONG NodeNumber;
+ ULONGLONG VCN;
PB_TREE_KEY FirstKey;
} B_TREE_FILENAME_NODE, *PB_TREE_FILENAME_NODE;
@@ -571,6 +577,15 @@
ULONG RunLength);
NTSTATUS
+AddIndexRoot(PNTFS_VCB Vcb,
+ PFILE_RECORD_HEADER FileRecord,
+ PNTFS_ATTR_RECORD AttributeAddress,
+ PINDEX_ROOT_ATTRIBUTE NewIndexRoot,
+ ULONG RootLength,
+ PCWSTR Name,
+ USHORT NameLength);
+
+NTSTATUS
AddFileName(PFILE_RECORD_HEADER FileRecord,
PNTFS_ATTR_RECORD AttributeAddress,
PDEVICE_EXTENSION DeviceExt,
@@ -718,9 +733,19 @@
DumpBTree(PB_TREE Tree);
VOID
-DumpBTreeNode(PB_TREE_FILENAME_NODE Node,
+DumpBTreeKey(PB_TREE Tree,
+ PB_TREE_KEY Key,
+ ULONG Number,
+ ULONG Depth);
+
+VOID
+DumpBTreeNode(PB_TREE Tree,
+ PB_TREE_FILENAME_NODE Node,
ULONG Number,
ULONG Depth);
+
+NTSTATUS
+CreateEmptyBTree(PB_TREE *NewTree);
ULONGLONG
GetAllocationOffsetFromVCN(PDEVICE_EXTENSION DeviceExt,
@@ -770,6 +795,15 @@
NTSTATUS
NtfsCreate(PNTFS_IRP_CONTEXT IrpContext);
+
+NTSTATUS
+NtfsCreateDirectory(PDEVICE_EXTENSION DeviceExt,
+ PFILE_OBJECT FileObject,
+ BOOLEAN CaseSensitive,
+ BOOLEAN CanWait);
+
+PFILE_RECORD_HEADER
+NtfsCreateEmptyFileRecord(PDEVICE_EXTENSION DeviceExt);
NTSTATUS
NtfsCreateFileRecord(PDEVICE_EXTENSION DeviceExt,
Author: ssawant
Date: Sun Aug 27 11:45:46 2017
New Revision: 75690
URL: http://svn.reactos.org/svn/reactos?rev=75690&view=rev
Log:
[STOBJECT]
-Documented the required functions and modules.
-Minor cleanup.
Modified:
branches/GSoC_2017/shellext/reactos/dll/shellext/stobject/csystray.cpp
branches/GSoC_2017/shellext/reactos/dll/shellext/stobject/hotplug.cpp
branches/GSoC_2017/shellext/reactos/dll/shellext/stobject/power.cpp
branches/GSoC_2017/shellext/reactos/dll/shellext/stobject/stobject.cpp
Modified: branches/GSoC_2017/shellext/reactos/dll/shellext/stobject/csystray.cpp
URL: http://svn.reactos.org/svn/reactos/branches/GSoC_2017/shellext/reactos/dll/…
==============================================================================
--- branches/GSoC_2017/shellext/reactos/dll/shellext/stobject/csystray.cpp [iso-8859-1] (original)
+++ branches/GSoC_2017/shellext/reactos/dll/shellext/stobject/csystray.cpp [iso-8859-1] Sun Aug 27 11:45:46 2017
@@ -98,6 +98,26 @@
return S_FALSE;
}
+/*++
+* @name NotifyIcon
+*
+* Basically a Shell_NotifyIcon wrapper.
+* Based on the parameters provided, it changes the current state of the notification icon.
+*
+* @param code
+* Determines whether to add, delete or modify the notification icon (represented by uId).
+* @param uId
+* Represents the particular notification icon.
+* @param hIcon
+* A handle to an icon for the notification object.
+* @param szTip
+* A string for the tooltip of the notification.
+* @param dwstate
+* Determines whether to show or hide the notification icon.
+*
+* @return The error code.
+*
+*--*/
HRESULT CSysTray::NotifyIcon(INT code, UINT uId, HICON hIcon, LPCWSTR szTip, DWORD dwstate)
{
NOTIFYICONDATA nim = { 0 };
Modified: branches/GSoC_2017/shellext/reactos/dll/shellext/stobject/hotplug.cpp
URL: http://svn.reactos.org/svn/reactos/branches/GSoC_2017/shellext/reactos/dll/…
==============================================================================
--- branches/GSoC_2017/shellext/reactos/dll/shellext/stobject/hotplug.cpp [iso-8859-1] (original)
+++ branches/GSoC_2017/shellext/reactos/dll/shellext/stobject/hotplug.cpp [iso-8859-1] Sun Aug 27 11:45:46 2017
@@ -28,8 +28,17 @@
static BOOL g_IsRunning = FALSE;
static BOOL g_IsRemoving = FALSE;
-// Enumerate the connected removable devices
-// TODO: Require proper enumeration and filters.
+/*++
+* @name EnumHotpluggedDevices
+*
+* Enumerates the connected safely removable devices.
+*
+* @param devList
+* List of device instances, representing the currently attached devices.
+*
+* @return The error code.
+*
+*--*/
HRESULT EnumHotpluggedDevices(CSimpleArray<DEVINST> &devList)
{
devList.RemoveAll(); // Clear current devList
@@ -39,6 +48,7 @@
SP_DEVINFO_DATA did = { 0 };
did.cbSize = sizeof(did);
+ // Enumerate all the attached devices.
for (int idev = 0; SetupDiEnumDeviceInfo(hdev, idev, &did); idev++)
{
DWORD dwCapabilities = 0, dwSize = sizeof(dwCapabilities);
@@ -54,6 +64,7 @@
if (cr != CR_SUCCESS)
continue;
+ // Filter and make list of only the appropriate safely removable devices.
if ( (dwCapabilities & CM_DEVCAP_REMOVABLE) &&
!(dwCapabilities & CM_DEVCAP_DOCKDEVICE) &&
!(dwCapabilities & CM_DEVCAP_SURPRISEREMOVALOK) &&
@@ -73,7 +84,23 @@
return S_OK;
}
-// Pops a balloon notification
+/*++
+* @name NotifyBalloon
+*
+* Pops the balloon notification of the given notification icon.
+*
+* @param pSysTray
+* Provides interface for acquiring CSysTray information as required.
+* @param szTitle
+* Title for the balloon notification.
+* @param szInfo
+* Main content for the balloon notification.
+* @param uId
+* Represents the particular notification icon.
+*
+* @return The error code.
+*
+*--*/
HRESULT NotifyBalloon(CSysTray* pSysTray, LPCWSTR szTitle = NULL, LPCWSTR szInfo = NULL, UINT uId = ID_ICON_HOTPLUG)
{
NOTIFYICONDATA nim = { 0 };
@@ -175,12 +202,13 @@
swprintf(strInfo, L"Problem Ejecting %wS", g_strMenuSel);
MessageBox(0, L"The device cannot be stopped right now! Try stopping it again later!", strInfo, MB_OKCANCEL | MB_ICONEXCLAMATION);
}
- else //TODO
+ else
{
//MessageBox(0, L"Device ejected successfully!! You can safely remove the device now!", L"Safely Remove Hardware", MB_OKCANCEL | MB_ICONINFORMATION);
g_IsRemoving = TRUE;
- g_devList.RemoveAt(id); // thing is.. even after removing id at this point, the devnode_change occurs after some seconds of sucessful removal
- // and since pendrive is still plugged in it gets enumerated, if problem number is not filtered.
+ g_devList.RemoveAt(id); /* thing is.. even after removing id at this point, the devnode_change occurs after some seconds of sucessful removal
+ and since pendrive is still plugged in it gets enumerated, if problem number is not filtered.
+ */
}
}
Modified: branches/GSoC_2017/shellext/reactos/dll/shellext/stobject/power.cpp
URL: http://svn.reactos.org/svn/reactos/branches/GSoC_2017/shellext/reactos/dll/…
==============================================================================
--- branches/GSoC_2017/shellext/reactos/dll/shellext/stobject/power.cpp [iso-8859-1] (original)
+++ branches/GSoC_2017/shellext/reactos/dll/shellext/stobject/power.cpp [iso-8859-1] Sun Aug 27 11:45:46 2017
@@ -25,8 +25,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(stobject);
-int br_icons[5] = { IDI_BATTCAP0, IDI_BATTCAP1, IDI_BATTCAP2, IDI_BATTCAP3, IDI_BATTCAP4 };
-int bc_icons[5] = { IDI_BATTCHA0, IDI_BATTCHA1, IDI_BATTCHA2, IDI_BATTCHA3, IDI_BATTCHA4 };
+int br_icons[5] = { IDI_BATTCAP0, IDI_BATTCAP1, IDI_BATTCAP2, IDI_BATTCAP3, IDI_BATTCAP4 }; // battery mode icons.
+int bc_icons[5] = { IDI_BATTCHA0, IDI_BATTCHA1, IDI_BATTCHA2, IDI_BATTCHA3, IDI_BATTCHA4 }; // charging mode icons.
typedef struct _PWRSCHEMECONTEXT
{
@@ -40,16 +40,25 @@
static HICON g_hIconBattery = NULL;
static BOOL g_IsRunning = FALSE;
-/*** This function enumerates the available battery devices and provides the remaining capacity
-@param cap: if no error occurs, then this will contatin average remaining capacity
-@param dwResult: helps in making battery type checks
-{
-Returned value includes GBS_HASBATTERY if the system has a non-UPS battery, and GBS_ONBATTERY if the system is running on a battery.
-dwResult & GBS_ONBATTERY means we have not yet found AC power.
-dwResult & GBS_HASBATTERY means we have found a non-UPS battery.
-}
-@return : error checking
-*/
+/*++
+* @name GetBatteryState
+*
+* Enumerates the available battery devices and provides the remaining capacity.
+*
+* @param cap
+* If no error occurs, then this will contain average remaining capacity.
+* @param dwResult
+* Helps in making battery type checks.
+* {
+* Returned value includes GBS_HASBATTERY if the system has a non-UPS battery,
+* and GBS_ONBATTERY if the system is running on a battery.
+* dwResult & GBS_ONBATTERY means we have not yet found AC power.
+* dwResult & GBS_HASBATTERY means we have found a non-UPS battery.
+* }
+*
+* @return The error code.
+*
+*--*/
static HRESULT GetBatteryState(float& cap, DWORD& dwResult)
{
cap = 0;
@@ -148,11 +157,19 @@
return S_OK;
}
-/*** This function quantizes the mentioned quantity to nearest level
-@param p: should be a quantity in percentage
-@param lvl: quantization level, default is 10
-@return : nearest quantized level
-*/
+/*++
+* @name Quantize
+*
+* This function quantizes the mentioned quantity to nearest level.
+*
+* @param p
+* Should be a quantity in percentage.
+* @param lvl
+* Quantization level (this excludes base level 0, which will always be present), default is 10.
+*
+* @return Nearest quantized level, can be directly used as array index based on context.
+*
+*--*/
static UINT Quantize(float p, UINT lvl = 10)
{
int i = 0;
@@ -163,13 +180,29 @@
return i;
else
return i - 1;
-}
-
-/*** This function returns the respective icon as per the current battery capacity.
- It also does the work of setting global parameters of battery capacity and tooltips.
-@param hinst: instance handle
-@return : icon handle
+/*
+ @remarks This function uses centred/symmetric logic for quantization.
+ For the case of lvl = 4, You will get following integer levels if given (p) value falls in between the range partitions:
+ 0 <= p < 12.5 : returns 0; (corresponding to 0% centre)
+ 12.5 <= p < 37.5 : returns 1; (corresponding to 25% centre)
+ 37.5 <= p < 62.5 : returns 2; (corresponding to 50% centre)
+ 62.5 <= p < 87.5 : returns 3; (corresponding to 75% centre)
+ 87.5 <= p <= 100 : returns 4; (corresponding to 100% centre)
*/
+}
+
+/*++
+* @name DynamicLoadIcon
+*
+* Returns the respective icon as per the current battery capacity.
+* It also does the work of setting global parameters of battery capacity and tooltips.
+*
+* @param hinst
+* A handle to a instance of the module.
+*
+* @return The handle to respective battery icon.
+*
+*--*/
static HICON DynamicLoadIcon(HINSTANCE hinst)
{
HICON hBatIcon;
Modified: branches/GSoC_2017/shellext/reactos/dll/shellext/stobject/stobject.cpp
URL: http://svn.reactos.org/svn/reactos/branches/GSoC_2017/shellext/reactos/dll/…
==============================================================================
--- branches/GSoC_2017/shellext/reactos/dll/shellext/stobject/stobject.cpp [iso-8859-1] (original)
+++ branches/GSoC_2017/shellext/reactos/dll/shellext/stobject/stobject.cpp [iso-8859-1] Sun Aug 27 11:45:46 2017
@@ -4,7 +4,7 @@
* FILE: dll/shellext/stobject/stobject.cpp
* PURPOSE: COM registration services for STobject.dll
* PROGRAMMERS: Robert Naumann
- David Quintana <gigaherz(a)gmail.com>
+ David Quintana <gigaherz(a)gmail.com>
*/
#include "precomp.h"
Author: gadamopoulos
Date: Sun Aug 27 10:55:30 2017
New Revision: 75688
URL: http://svn.reactos.org/svn/reactos?rev=75688&view=rev
Log:
[UXTHEME] -Ignore the alpha channel so that TrasnparentBlt will be used when a bitmap has an alpha channel but no pixel has alpha transparency. CORE-13464
Modified:
trunk/reactos/dll/win32/uxtheme/msstyles.c
Modified: trunk/reactos/dll/win32/uxtheme/msstyles.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/uxtheme/msstyles…
==============================================================================
--- trunk/reactos/dll/win32/uxtheme/msstyles.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/uxtheme/msstyles.c [iso-8859-1] Sun Aug 27 10:55:30 2017
@@ -875,7 +875,6 @@
/* nothing to do */
return TRUE;
- *hasAlpha = TRUE;
p = dib.dsBm.bmBits;
n = dib.dsBmih.biHeight * dib.dsBmih.biWidth;
/* AlphaBlend() wants premultiplied alpha, so do that now */
@@ -886,6 +885,9 @@
p[1] = (p[1] * a) >> 8;
p[2] = (p[2] * a) >> 8;
p += 4;
+
+ if (a != 256)
+ *hasAlpha = TRUE;
}
return TRUE;
Author: gadamopoulos
Date: Sun Aug 27 09:35:03 2017
New Revision: 75687
URL: http://svn.reactos.org/svn/reactos?rev=75687&view=rev
Log:
[BROWSEUI] -CExplorerBand: Calling ILGetDisplayNameEx with a full pidl was a bit hacky after all because it doesn't work always in win10. Just get the name manually as no helper is good enough.
Modified:
trunk/reactos/dll/win32/browseui/explorerband.cpp
Modified: trunk/reactos/dll/win32/browseui/explorerband.cpp
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/browseui/explore…
==============================================================================
--- trunk/reactos/dll/win32/browseui/explorerband.cpp [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/browseui/explorerband.cpp [iso-8859-1] Sun Aug 27 09:35:03 2017
@@ -574,11 +574,14 @@
/* Get the name of the node */
WCHAR wszDisplayName[MAX_PATH];
- if (!ILGetDisplayNameEx(psfParent, pElt, wszDisplayName, ILGDN_INFOLDER))
- {
- ERR("Failed to get node name\n");
+ STRRET strret;
+ hr = psfParent->GetDisplayNameOf(pEltRelative, SHGDN_INFOLDER, &strret);
+ if (FAILED_UNEXPECTEDLY(hr))
return NULL;
- }
+
+ hr = StrRetToBufW(&strret, pEltRelative, wszDisplayName, MAX_PATH);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return NULL;
/* Get the icon of the node */
INT iIcon = SHMapPIDLToSystemImageListIndex(psfParent, pEltRelative, NULL);