* PROJECT: ReactOS kernel
* FILE: drivers/filesystem/ntfs/attrib.c
* PURPOSE: NTFS filesystem driver
- * PROGRAMMER: Eric Kohl
- * Updated by Valentin Verkhovsky 2003/09/12
+ * PROGRAMMERS: Eric Kohl
+ * Valentin Verkhovsky
+ * Hervé Poussineau (hpoussin@reactos.org)
*/
/* INCLUDES *****************************************************************/
/* FUNCTIONS ****************************************************************/
-static
-ULONG
-RunLength(PUCHAR run)
+PUCHAR
+DecodeRun(PUCHAR DataRun,
+ LONGLONG *DataRunOffset,
+ ULONGLONG *DataRunLength)
{
- return(*run & 0x0f) + ((*run >> 4) & 0x0f) + 1;
-}
-
-
-static
-LONGLONG
-RunLCN(PUCHAR run)
-{
- UCHAR n1 = *run & 0x0f;
- UCHAR n2 = (*run >> 4) & 0x0f;
- LONGLONG lcn = (n2 == 0) ? 0 : (CHAR)(run[n1 + n2]);
- LONG i = 0;
-
- for (i = n1 +n2 - 1; i > n1; i--)
- lcn = (lcn << 8) + run[i];
- return lcn;
-}
+ UCHAR DataRunOffsetSize;
+ UCHAR DataRunLengthSize;
+ CHAR i;
+
+ DataRunOffsetSize = (*DataRun >> 4) & 0xF;
+ DataRunLengthSize = *DataRun & 0xF;
+ *DataRunOffset = 0;
+ *DataRunLength = 0;
+ DataRun++;
+ for (i = 0; i < DataRunLengthSize; i++)
+ {
+ *DataRunLength += ((ULONG64)*DataRun) << (i * 8);
+ DataRun++;
+ }
+ /* NTFS 3+ sparse files */
+ if (DataRunOffsetSize == 0)
+ {
+ *DataRunOffset = -1;
+ }
+ else
+ {
+ for (i = 0; i < DataRunOffsetSize - 1; i++)
+ {
+ *DataRunOffset += ((ULONG64)*DataRun) << (i * 8);
+ DataRun++;
+ }
+ /* The last byte contains sign so we must process it different way. */
+ *DataRunOffset = ((LONG64)(CHAR)(*(DataRun++)) << (i * 8)) + *DataRunOffset;
+ }
-static
-ULONGLONG
-RunCount(PUCHAR run)
-{
- UCHAR n = *run & 0xf;
- ULONGLONG count = 0;
- ULONG i = 0;
+ DPRINT("DataRunOffsetSize: %x\n", DataRunOffsetSize);
+ DPRINT("DataRunLengthSize: %x\n", DataRunLengthSize);
+ DPRINT("DataRunOffset: %x\n", *DataRunOffset);
+ DPRINT("DataRunLength: %x\n", *DataRunLength);
- for (i = n; i > 0; i--)
- count = (count << 8) + run[i];
- return count;
+ return DataRun;
}
-
BOOLEAN
-FindRun(PNONRESIDENT_ATTRIBUTE NresAttr,
+FindRun(PNTFS_ATTR_RECORD NresAttr,
ULONGLONG vcn,
PULONGLONG lcn,
PULONGLONG count)
{
- PUCHAR run;
- ULONGLONG base = NresAttr->StartVcn;
-
- if (vcn < NresAttr->StartVcn || vcn > NresAttr->LastVcn)
+ if (vcn < NresAttr->NonResident.LowestVCN || vcn > NresAttr->NonResident.HighestVCN)
return FALSE;
- *lcn = 0;
-
- for (run = (PUCHAR)((ULONG_PTR)NresAttr + NresAttr->RunArrayOffset);
- *run != 0; run += RunLength(run))
- {
- *lcn += RunLCN(run);
- *count = RunCount(run);
+ DecodeRun((PUCHAR)((ULONG_PTR)NresAttr + NresAttr->NonResident.MappingPairsOffset), (PLONGLONG)lcn, count);
- if (base <= vcn && vcn < base + *count)
- {
- *lcn = (RunLCN(run) == 0) ? 0 : *lcn + vcn - base;
- *count -= (ULONG)(vcn - base);
-
- return TRUE;
- }
- else
- {
- base += *count;
- }
- }
-
- return FALSE;
+ return TRUE;
}
static
VOID
-NtfsDumpFileNameAttribute(PATTRIBUTE Attribute)
+NtfsDumpFileNameAttribute(PNTFS_ATTR_RECORD Attribute)
{
- PRESIDENT_ATTRIBUTE ResAttr;
PFILENAME_ATTRIBUTE FileNameAttr;
DbgPrint(" $FILE_NAME ");
- ResAttr = (PRESIDENT_ATTRIBUTE)Attribute;
-// DbgPrint(" Length %lu Offset %hu ", ResAttr->ValueLength, ResAttr->ValueOffset);
+// DbgPrint(" Length %lu Offset %hu ", Attribute->Resident.ValueLength, Attribute->Resident.ValueOffset);
- FileNameAttr = (PFILENAME_ATTRIBUTE)((ULONG_PTR)ResAttr + ResAttr->ValueOffset);
+ FileNameAttr = (PFILENAME_ATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
DbgPrint(" '%.*S' ", FileNameAttr->NameLength, FileNameAttr->Name);
}
static
VOID
-NtfsDumpVolumeNameAttribute(PATTRIBUTE Attribute)
+NtfsDumpVolumeNameAttribute(PNTFS_ATTR_RECORD Attribute)
{
- PRESIDENT_ATTRIBUTE ResAttr;
PWCHAR VolumeName;
DbgPrint(" $VOLUME_NAME ");
- ResAttr = (PRESIDENT_ATTRIBUTE)Attribute;
-// DbgPrint(" Length %lu Offset %hu ", ResAttr->ValueLength, ResAttr->ValueOffset);
+// DbgPrint(" Length %lu Offset %hu ", Attribute->Resident.ValueLength, Attribute->Resident.ValueOffset);
- VolumeName = (PWCHAR)((ULONG_PTR)ResAttr + ResAttr->ValueOffset);
- DbgPrint(" '%.*S' ", ResAttr->ValueLength / sizeof(WCHAR), VolumeName);
+ VolumeName = (PWCHAR)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
+ DbgPrint(" '%.*S' ", Attribute->Resident.ValueLength / sizeof(WCHAR), VolumeName);
}
static
VOID
-NtfsDumpVolumeInformationAttribute(PATTRIBUTE Attribute)
+NtfsDumpVolumeInformationAttribute(PNTFS_ATTR_RECORD Attribute)
{
- PRESIDENT_ATTRIBUTE ResAttr;
PVOLINFO_ATTRIBUTE VolInfoAttr;
DbgPrint(" $VOLUME_INFORMATION ");
- ResAttr = (PRESIDENT_ATTRIBUTE)Attribute;
-// DbgPrint(" Length %lu Offset %hu ", ResAttr->ValueLength, ResAttr->ValueOffset);
+// DbgPrint(" Length %lu Offset %hu ", Attribute->Resident.ValueLength, Attribute->Resident.ValueOffset);
- VolInfoAttr = (PVOLINFO_ATTRIBUTE)((ULONG_PTR)ResAttr + ResAttr->ValueOffset);
+ VolInfoAttr = (PVOLINFO_ATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
DbgPrint(" NTFS Version %u.%u Flags 0x%04hx ",
VolInfoAttr->MajorVersion,
VolInfoAttr->MinorVersion,
static
VOID
-NtfsDumpIndexRootAttribute(PATTRIBUTE Attribute)
+NtfsDumpIndexRootAttribute(PNTFS_ATTR_RECORD Attribute)
{
- PRESIDENT_ATTRIBUTE ResAttr;
PINDEX_ROOT_ATTRIBUTE IndexRootAttr;
- ResAttr = (PRESIDENT_ATTRIBUTE)Attribute;
- IndexRootAttr = (PINDEX_ROOT_ATTRIBUTE)((ULONG_PTR)ResAttr + ResAttr->ValueOffset);
+ 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);
+
+ if (IndexRootAttr->Header.Flags == INDEX_ROOT_SMALL)
+ {
+ DbgPrint(" (small) ");
+ }
+ else
+ {
+ ASSERT(IndexRootAttr->Header.Flags == INDEX_ROOT_LARGE);
+ DbgPrint(" (large) ");
+ }
}
static
VOID
-NtfsDumpAttribute (PATTRIBUTE Attribute)
+NtfsDumpAttribute(PNTFS_ATTR_RECORD Attribute)
{
- PNONRESIDENT_ATTRIBUTE NresAttr;
UNICODE_STRING Name;
ULONGLONG lcn = 0;
ULONGLONG runcount = 0;
- switch (Attribute->AttributeType)
+ switch (Attribute->Type)
{
case AttributeFileName:
NtfsDumpFileNameAttribute(Attribute);
default:
DbgPrint(" Attribute %lx ",
- Attribute->AttributeType);
+ Attribute->Type);
break;
}
}
DbgPrint("(%s)\n",
- Attribute->Nonresident ? "non-resident" : "resident");
+ Attribute->IsNonResident ? "non-resident" : "resident");
- if (Attribute->Nonresident)
+ if (Attribute->IsNonResident)
{
- NresAttr = (PNONRESIDENT_ATTRIBUTE)Attribute;
-
- FindRun(NresAttr,0,&lcn, &runcount);
+ FindRun(Attribute,0,&lcn, &runcount);
DbgPrint(" AllocatedSize %I64u DataSize %I64u\n",
- NresAttr->AllocatedSize, NresAttr->DataSize);
+ Attribute->NonResident.AllocatedSize, Attribute->NonResident.DataSize);
DbgPrint(" logical clusters: %I64u - %I64u\n",
lcn, lcn + runcount - 1);
}
VOID
NtfsDumpFileAttributes(PFILE_RECORD_HEADER FileRecord)
{
- PATTRIBUTE Attribute;
+ PNTFS_ATTR_RECORD Attribute;
- Attribute = (PATTRIBUTE)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
- while (Attribute < (PATTRIBUTE)((ULONG_PTR)FileRecord + FileRecord->BytesInUse) &&
- Attribute->AttributeType != (ATTRIBUTE_TYPE)-1)
+ Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
+ while (Attribute < (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse) &&
+ Attribute->Type != AttributeEnd)
{
NtfsDumpAttribute(Attribute);
- Attribute = (PATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Length);
+ Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length);
+ }
+}
+
+PFILENAME_ATTRIBUTE
+GetFileNameFromRecord(PFILE_RECORD_HEADER FileRecord, UCHAR NameType)
+{
+ PNTFS_ATTR_RECORD Attribute;
+ PFILENAME_ATTRIBUTE Name;
+
+ Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
+ while (Attribute < (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse) &&
+ Attribute->Type != AttributeEnd)
+ {
+ if (Attribute->Type == AttributeFileName)
+ {
+ Name = (PFILENAME_ATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
+ if (Name->NameType == NameType ||
+ (Name->NameType == NTFS_FILE_NAME_WIN32_AND_DOS && NameType == NTFS_FILE_NAME_WIN32) ||
+ (Name->NameType == NTFS_FILE_NAME_WIN32_AND_DOS && NameType == NTFS_FILE_NAME_DOS))
+ {
+ return Name;
+ }
+ }
+
+ Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length);
}
+
+ return NULL;
+}
+
+PFILENAME_ATTRIBUTE
+GetBestFileNameFromRecord(PFILE_RECORD_HEADER FileRecord)
+{
+ PFILENAME_ATTRIBUTE FileName;
+
+ FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_POSIX);
+ if (FileName == NULL)
+ {
+ FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_WIN32);
+ if (FileName == NULL)
+ {
+ FileName = GetFileNameFromRecord(FileRecord, NTFS_FILE_NAME_DOS);
+ }
+ }
+
+ return FileName;
}
/* EOF */