2002-07-15 15:37:33 +00:00
|
|
|
/*
|
|
|
|
* ReactOS kernel
|
2003-01-17 18:51:13 +00:00
|
|
|
* Copyright (C) 2002,2003 ReactOS Team
|
2002-07-15 15:37:33 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
2008-03-08 21:45:51 +00:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
2002-07-15 15:37:33 +00:00
|
|
|
*
|
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS kernel
|
2008-02-10 11:20:29 +00:00
|
|
|
* FILE: drivers/filesystem/ntfs/attrib.c
|
2002-07-15 15:37:33 +00:00
|
|
|
* PURPOSE: NTFS filesystem driver
|
2014-11-02 22:56:38 +00:00
|
|
|
* PROGRAMMERS: Eric Kohl
|
|
|
|
* Valentin Verkhovsky
|
|
|
|
* Hervé Poussineau (hpoussin@reactos.org)
|
2002-07-15 15:37:33 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
|
2005-07-20 02:52:52 +00:00
|
|
|
#include "ntfs.h"
|
2003-08-07 11:47:33 +00:00
|
|
|
|
2003-11-12 15:30:21 +00:00
|
|
|
#define NDEBUG
|
2002-07-15 15:37:33 +00:00
|
|
|
#include <debug.h>
|
|
|
|
|
|
|
|
/* FUNCTIONS ****************************************************************/
|
|
|
|
|
2014-09-26 13:57:29 +00:00
|
|
|
PUCHAR
|
|
|
|
DecodeRun(PUCHAR DataRun,
|
|
|
|
LONGLONG *DataRunOffset,
|
|
|
|
ULONGLONG *DataRunLength)
|
2003-09-15 16:01:16 +00:00
|
|
|
{
|
2014-09-26 13:57:29 +00:00
|
|
|
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++;
|
|
|
|
}
|
2003-09-15 16:01:16 +00:00
|
|
|
|
2014-09-26 13:57:29 +00:00
|
|
|
/* 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;
|
|
|
|
}
|
2003-09-15 16:01:16 +00:00
|
|
|
|
2014-09-26 13:57:29 +00:00
|
|
|
DPRINT("DataRunOffsetSize: %x\n", DataRunOffsetSize);
|
|
|
|
DPRINT("DataRunLengthSize: %x\n", DataRunLengthSize);
|
|
|
|
DPRINT("DataRunOffset: %x\n", *DataRunOffset);
|
|
|
|
DPRINT("DataRunLength: %x\n", *DataRunLength);
|
2003-09-15 16:01:16 +00:00
|
|
|
|
2014-09-26 13:57:29 +00:00
|
|
|
return DataRun;
|
2003-09-15 16:01:16 +00:00
|
|
|
}
|
|
|
|
|
2003-11-12 15:30:21 +00:00
|
|
|
BOOLEAN
|
2014-09-26 13:57:29 +00:00
|
|
|
FindRun(PNTFS_ATTR_RECORD NresAttr,
|
2013-06-16 12:15:06 +00:00
|
|
|
ULONGLONG vcn,
|
|
|
|
PULONGLONG lcn,
|
|
|
|
PULONGLONG count)
|
2003-11-12 15:30:21 +00:00
|
|
|
{
|
2014-09-26 13:57:29 +00:00
|
|
|
if (vcn < NresAttr->NonResident.LowestVCN || vcn > NresAttr->NonResident.HighestVCN)
|
2013-06-16 12:15:06 +00:00
|
|
|
return FALSE;
|
2003-11-12 15:30:21 +00:00
|
|
|
|
2014-09-26 13:57:29 +00:00
|
|
|
DecodeRun((PUCHAR)((ULONG_PTR)NresAttr + NresAttr->NonResident.MappingPairsOffset), (PLONGLONG)lcn, count);
|
2013-06-16 12:15:06 +00:00
|
|
|
|
2014-09-26 13:57:29 +00:00
|
|
|
return TRUE;
|
2003-11-12 15:30:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
static
|
|
|
|
VOID
|
2014-09-26 13:57:29 +00:00
|
|
|
NtfsDumpFileNameAttribute(PNTFS_ATTR_RECORD Attribute)
|
2003-01-17 18:51:13 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
PFILENAME_ATTRIBUTE FileNameAttr;
|
2003-01-17 18:51:13 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
DbgPrint(" $FILE_NAME ");
|
2003-01-17 18:51:13 +00:00
|
|
|
|
2014-09-26 13:57:29 +00:00
|
|
|
// DbgPrint(" Length %lu Offset %hu ", Attribute->Resident.ValueLength, Attribute->Resident.ValueOffset);
|
2003-01-17 18:51:13 +00:00
|
|
|
|
2014-09-26 13:57:29 +00:00
|
|
|
FileNameAttr = (PFILENAME_ATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
|
2014-12-08 18:44:29 +00:00
|
|
|
DbgPrint(" (%x) '%.*S' ", FileNameAttr->NameType, FileNameAttr->NameLength, FileNameAttr->Name);
|
|
|
|
DbgPrint(" '%x' ", FileNameAttr->FileAttributes);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static
|
|
|
|
VOID
|
|
|
|
NtfsDumpStandardInformationAttribute(PNTFS_ATTR_RECORD Attribute)
|
|
|
|
{
|
|
|
|
PSTANDARD_INFORMATION StandardInfoAttr;
|
|
|
|
|
|
|
|
DbgPrint(" $STANDARD_INFORMATION ");
|
|
|
|
|
|
|
|
// DbgPrint(" Length %lu Offset %hu ", Attribute->Resident.ValueLength, Attribute->Resident.ValueOffset);
|
|
|
|
|
|
|
|
StandardInfoAttr = (PSTANDARD_INFORMATION)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
|
|
|
|
DbgPrint(" '%x' ", StandardInfoAttr->FileAttribute);
|
2003-01-17 18:51:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
static
|
|
|
|
VOID
|
2014-09-26 13:57:29 +00:00
|
|
|
NtfsDumpVolumeNameAttribute(PNTFS_ATTR_RECORD Attribute)
|
2003-01-17 18:51:13 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
PWCHAR VolumeName;
|
2003-01-17 18:51:13 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
DbgPrint(" $VOLUME_NAME ");
|
2003-01-17 18:51:13 +00:00
|
|
|
|
2014-09-26 13:57:29 +00:00
|
|
|
// DbgPrint(" Length %lu Offset %hu ", Attribute->Resident.ValueLength, Attribute->Resident.ValueOffset);
|
2003-01-17 18:51:13 +00:00
|
|
|
|
2014-09-26 13:57:29 +00:00
|
|
|
VolumeName = (PWCHAR)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
|
|
|
|
DbgPrint(" '%.*S' ", Attribute->Resident.ValueLength / sizeof(WCHAR), VolumeName);
|
2003-01-17 18:51:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
static
|
|
|
|
VOID
|
2014-09-26 13:57:29 +00:00
|
|
|
NtfsDumpVolumeInformationAttribute(PNTFS_ATTR_RECORD Attribute)
|
2003-01-17 18:51:13 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
PVOLINFO_ATTRIBUTE VolInfoAttr;
|
2003-01-17 18:51:13 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
DbgPrint(" $VOLUME_INFORMATION ");
|
2003-01-17 18:51:13 +00:00
|
|
|
|
2014-09-26 13:57:29 +00:00
|
|
|
// DbgPrint(" Length %lu Offset %hu ", Attribute->Resident.ValueLength, Attribute->Resident.ValueOffset);
|
2003-01-17 18:51:13 +00:00
|
|
|
|
2014-09-26 13:57:29 +00:00
|
|
|
VolInfoAttr = (PVOLINFO_ATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
|
2013-06-16 12:15:06 +00:00
|
|
|
DbgPrint(" NTFS Version %u.%u Flags 0x%04hx ",
|
|
|
|
VolInfoAttr->MajorVersion,
|
|
|
|
VolInfoAttr->MinorVersion,
|
|
|
|
VolInfoAttr->Flags);
|
2003-01-17 18:51:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-22 19:59:45 +00:00
|
|
|
static
|
|
|
|
VOID
|
2014-09-26 13:57:29 +00:00
|
|
|
NtfsDumpIndexRootAttribute(PNTFS_ATTR_RECORD Attribute)
|
2014-09-22 19:59:45 +00:00
|
|
|
{
|
|
|
|
PINDEX_ROOT_ATTRIBUTE IndexRootAttr;
|
|
|
|
|
2014-09-26 13:57:29 +00:00
|
|
|
IndexRootAttr = (PINDEX_ROOT_ATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Resident.ValueOffset);
|
2014-09-22 19:59:45 +00:00
|
|
|
|
|
|
|
if (IndexRootAttr->AttributeType == AttributeFileName)
|
|
|
|
ASSERT(IndexRootAttr->CollationRule == COLLATION_FILE_NAME);
|
|
|
|
|
|
|
|
DbgPrint(" $INDEX_ROOT (%uB, %u) ", IndexRootAttr->SizeOfEntry, IndexRootAttr->ClustersPerIndexRecord);
|
2014-09-22 20:26:21 +00:00
|
|
|
|
|
|
|
if (IndexRootAttr->Header.Flags == INDEX_ROOT_SMALL)
|
|
|
|
{
|
|
|
|
DbgPrint(" (small) ");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ASSERT(IndexRootAttr->Header.Flags == INDEX_ROOT_LARGE);
|
|
|
|
DbgPrint(" (large) ");
|
|
|
|
}
|
2014-09-22 19:59:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
static
|
|
|
|
VOID
|
2014-09-26 13:57:29 +00:00
|
|
|
NtfsDumpAttribute(PNTFS_ATTR_RECORD Attribute)
|
2002-07-15 15:37:33 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
UNICODE_STRING Name;
|
2003-11-12 15:30:21 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
ULONGLONG lcn = 0;
|
|
|
|
ULONGLONG runcount = 0;
|
2002-07-15 15:37:33 +00:00
|
|
|
|
2014-09-26 13:57:29 +00:00
|
|
|
switch (Attribute->Type)
|
2002-07-15 15:37:33 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
case AttributeFileName:
|
|
|
|
NtfsDumpFileNameAttribute(Attribute);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AttributeStandardInformation:
|
2014-12-08 18:44:29 +00:00
|
|
|
NtfsDumpStandardInformationAttribute(Attribute);
|
2013-06-16 12:15:06 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case AttributeAttributeList:
|
|
|
|
DbgPrint(" $ATTRIBUTE_LIST ");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AttributeObjectId:
|
|
|
|
DbgPrint(" $OBJECT_ID ");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AttributeSecurityDescriptor:
|
|
|
|
DbgPrint(" $SECURITY_DESCRIPTOR ");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AttributeVolumeName:
|
|
|
|
NtfsDumpVolumeNameAttribute(Attribute);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AttributeVolumeInformation:
|
|
|
|
NtfsDumpVolumeInformationAttribute(Attribute);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AttributeData:
|
|
|
|
DbgPrint(" $DATA ");
|
|
|
|
//DataBuf = ExAllocatePool(NonPagedPool,AttributeLengthAllocated(Attribute));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AttributeIndexRoot:
|
2014-09-22 19:59:45 +00:00
|
|
|
NtfsDumpIndexRootAttribute(Attribute);
|
2013-06-16 12:15:06 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case AttributeIndexAllocation:
|
|
|
|
DbgPrint(" $INDEX_ALLOCATION ");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AttributeBitmap:
|
|
|
|
DbgPrint(" $BITMAP ");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AttributeReparsePoint:
|
|
|
|
DbgPrint(" $REPARSE_POINT ");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AttributeEAInformation:
|
|
|
|
DbgPrint(" $EA_INFORMATION ");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AttributeEA:
|
|
|
|
DbgPrint(" $EA ");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AttributePropertySet:
|
|
|
|
DbgPrint(" $PROPERTY_SET ");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AttributeLoggedUtilityStream:
|
|
|
|
DbgPrint(" $LOGGED_UTILITY_STREAM ");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
DbgPrint(" Attribute %lx ",
|
2014-09-26 13:57:29 +00:00
|
|
|
Attribute->Type);
|
2013-06-16 12:15:06 +00:00
|
|
|
break;
|
2002-07-15 15:37:33 +00:00
|
|
|
}
|
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
if (Attribute->NameLength != 0)
|
2002-07-15 15:37:33 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
Name.Length = Attribute->NameLength * sizeof(WCHAR);
|
|
|
|
Name.MaximumLength = Name.Length;
|
|
|
|
Name.Buffer = (PWCHAR)((ULONG_PTR)Attribute + Attribute->NameOffset);
|
2002-07-15 15:37:33 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
DbgPrint("'%wZ' ", &Name);
|
2002-07-15 15:37:33 +00:00
|
|
|
}
|
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
DbgPrint("(%s)\n",
|
2014-09-26 13:57:29 +00:00
|
|
|
Attribute->IsNonResident ? "non-resident" : "resident");
|
2002-07-15 15:37:33 +00:00
|
|
|
|
2014-09-26 13:57:29 +00:00
|
|
|
if (Attribute->IsNonResident)
|
2002-07-15 15:37:33 +00:00
|
|
|
{
|
2014-09-26 13:57:29 +00:00
|
|
|
FindRun(Attribute,0,&lcn, &runcount);
|
2002-07-15 15:37:33 +00:00
|
|
|
|
2013-06-16 12:15:06 +00:00
|
|
|
DbgPrint(" AllocatedSize %I64u DataSize %I64u\n",
|
2014-09-26 13:57:29 +00:00
|
|
|
Attribute->NonResident.AllocatedSize, Attribute->NonResident.DataSize);
|
2013-06-16 12:15:06 +00:00
|
|
|
DbgPrint(" logical clusters: %I64u - %I64u\n",
|
|
|
|
lcn, lcn + runcount - 1);
|
2003-11-12 15:30:21 +00:00
|
|
|
}
|
|
|
|
}
|
2003-09-15 16:01:16 +00:00
|
|
|
|
|
|
|
|
2003-11-12 15:30:21 +00:00
|
|
|
VOID
|
2013-06-16 12:15:06 +00:00
|
|
|
NtfsDumpFileAttributes(PFILE_RECORD_HEADER FileRecord)
|
2003-11-12 15:30:21 +00:00
|
|
|
{
|
2014-09-26 13:57:29 +00:00
|
|
|
PNTFS_ATTR_RECORD Attribute;
|
2003-09-15 16:01:16 +00:00
|
|
|
|
2014-09-26 13:57:29 +00:00
|
|
|
Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
|
|
|
|
while (Attribute < (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->BytesInUse) &&
|
2014-10-08 19:12:48 +00:00
|
|
|
Attribute->Type != AttributeEnd)
|
2003-11-12 15:30:21 +00:00
|
|
|
{
|
2013-06-16 12:15:06 +00:00
|
|
|
NtfsDumpAttribute(Attribute);
|
2002-07-15 15:37:33 +00:00
|
|
|
|
2014-09-26 13:57:29 +00:00
|
|
|
Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length);
|
2003-11-12 15:30:21 +00:00
|
|
|
}
|
2002-07-15 15:37:33 +00:00
|
|
|
}
|
|
|
|
|
2014-10-08 19:12:48 +00:00
|
|
|
PFILENAME_ATTRIBUTE
|
2014-10-26 19:10:17 +00:00
|
|
|
GetFileNameFromRecord(PFILE_RECORD_HEADER FileRecord, UCHAR NameType)
|
2014-10-08 19:12:48 +00:00
|
|
|
{
|
|
|
|
PNTFS_ATTR_RECORD Attribute;
|
2014-10-26 19:10:17 +00:00
|
|
|
PFILENAME_ATTRIBUTE Name;
|
2014-10-08 19:12:48 +00:00
|
|
|
|
|
|
|
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)
|
2014-10-26 19:10:17 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2014-10-08 19:12:48 +00:00
|
|
|
|
|
|
|
Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-11-23 14:07:08 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2002-07-15 15:37:33 +00:00
|
|
|
/* EOF */
|