/* * ReactOS kernel * Copyright (C) 2002 ReactOS Team * * 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 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: drivers/filesystem/ntfs/mft.c * PURPOSE: NTFS filesystem driver * PROGRAMMER: Eric Kohl * Updated by Valentin Verkhovsky 2003/09/12 */ /* INCLUDES *****************************************************************/ #include "ntfs.h" #define NDEBUG #include /* GLOBALS *****************************************************************/ /* FUNCTIONS ****************************************************************/ NTSTATUS NtfsOpenMft (PDEVICE_EXTENSION Vcb) { // PVOID Bitmap; PFILE_RECORD_HEADER MftRecord; PFILE_RECORD_HEADER FileRecord; // PATTRIBUTE Attribute; // PATTRIBUTE AttrData; // PRESIDENT_ATTRIBUTE ResAttr; NTSTATUS Status; ULONG BytesPerFileRecord; ULONG n; ULONG i; DPRINT1("NtfsOpenMft() called\n"); BytesPerFileRecord = Vcb->NtfsInfo.BytesPerFileRecord; MftRecord = ExAllocatePoolWithTag(NonPagedPool, BytesPerFileRecord, TAG_NTFS); if (MftRecord == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } Status = NtfsReadSectors(Vcb->StorageDevice, Vcb->NtfsInfo.MftStart.u.LowPart * Vcb->NtfsInfo.SectorsPerCluster, BytesPerFileRecord / Vcb->NtfsInfo.BytesPerSector, Vcb->NtfsInfo.BytesPerSector, (PVOID)MftRecord, FALSE); if (!NT_SUCCESS(Status)) { ExFreePool(MftRecord); return Status; } FixupUpdateSequenceArray(MftRecord); // Attribute = FindAttribute(MftRecord, AttributeBitmap, 0); /* Get number of file records*/ n = AttributeDataLength (FindAttribute (MftRecord, AttributeData, 0)) / BytesPerFileRecord; FileRecord = ExAllocatePoolWithTag(NonPagedPool, BytesPerFileRecord, TAG_NTFS); if (FileRecord == NULL) { ExFreePool(MftRecord); return(STATUS_INSUFFICIENT_RESOURCES); } /* Enumerate MFT Records */ DPRINT("Enumerate MFT records\n"); for ( i=0; i < n; i++) { ReadFileRecord(Vcb, i, FileRecord, MftRecord); if (FileRecord->Ntfs.Type == NRH_FILE_TYPE && (FileRecord->Flags & FRH_IN_USE)) { DPRINT("\nFile %lu\n\n", i); /* Enumerate attributtes */ NtfsDumpFileAttributes (FileRecord); DbgPrint("\n\n"); } } ExFreePool(FileRecord); ExFreePool(MftRecord); return Status; } PATTRIBUTE FindAttribute (PFILE_RECORD_HEADER FileRecord, ATTRIBUTE_TYPE Type, PWSTR name) { PATTRIBUTE Attribute; Attribute = (PATTRIBUTE)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset); while (Attribute < (PATTRIBUTE)((ULONG_PTR)FileRecord + FileRecord->BytesInUse) && Attribute->AttributeType != (ATTRIBUTE_TYPE)-1) { if (Attribute->AttributeType == Type) { return Attribute; } Attribute = (PATTRIBUTE)((ULONG_PTR)Attribute + Attribute->Length); } return NULL; } ULONG AttributeAllocatedLength (PATTRIBUTE Attribute) { if (Attribute->Nonresident) { return ((PNONRESIDENT_ATTRIBUTE)Attribute)->AllocatedSize; } return ((PRESIDENT_ATTRIBUTE)Attribute)->ValueLength; } ULONG AttributeDataLength (PATTRIBUTE Attribute) { if (Attribute->Nonresident) { return ((PNONRESIDENT_ATTRIBUTE)Attribute)->DataSize; } return ((PRESIDENT_ATTRIBUTE)Attribute)->ValueLength; } VOID ReadAttribute (PATTRIBUTE attr, PVOID buffer, PDEVICE_EXTENSION Vcb, PDEVICE_OBJECT DeviceObject) { PNONRESIDENT_ATTRIBUTE NresAttr = (PNONRESIDENT_ATTRIBUTE)attr; if (attr->Nonresident == FALSE) { memcpy (buffer, (PVOID)((ULONG_PTR)attr + ((PRESIDENT_ATTRIBUTE)attr)->ValueOffset), ((PRESIDENT_ATTRIBUTE)attr)->ValueLength); } ReadExternalAttribute(Vcb, NresAttr, 0, (ULONG)(NresAttr->LastVcn) + 1, buffer); } NTSTATUS ReadFileRecord (PDEVICE_EXTENSION Vcb, ULONG index, PFILE_RECORD_HEADER file, PFILE_RECORD_HEADER Mft) { PVOID p; ULONG BytesPerFileRecord = Vcb->NtfsInfo.BytesPerFileRecord; ULONG clusters = max(BytesPerFileRecord / Vcb->NtfsInfo.BytesPerCluster, 1); ULONGLONG vcn = index * BytesPerFileRecord / Vcb->NtfsInfo.BytesPerCluster; LONG m = (Vcb->NtfsInfo.BytesPerCluster / BytesPerFileRecord) - 1; ULONG n = m > 0 ? (index & m) : 0; p = ExAllocatePoolWithTag(NonPagedPool, clusters * Vcb->NtfsInfo.BytesPerCluster, TAG_NTFS); ReadVCN (Vcb, Mft, AttributeData, vcn, clusters, p); memcpy(file, (PVOID)((ULONG_PTR)p + n * BytesPerFileRecord), BytesPerFileRecord); ExFreePool(p); FixupUpdateSequenceArray(file); return STATUS_SUCCESS; } VOID ReadExternalAttribute (PDEVICE_EXTENSION Vcb, PNONRESIDENT_ATTRIBUTE NresAttr, ULONGLONG vcn, ULONG count, PVOID buffer) { ULONGLONG lcn; ULONGLONG runcount; ULONG readcount; ULONG left; ULONG n; PUCHAR bytes = (PUCHAR)buffer; for (left = count; left>0; left -=readcount) { FindRun(NresAttr, vcn, &lcn, &runcount); // readcount = (ULONG)(__min(runcount, left)); readcount = (ULONG)min (runcount, left); n = readcount * Vcb->NtfsInfo.BytesPerCluster; if (lcn == 0) memset(bytes, 0, n); else ReadLCN(Vcb, lcn, readcount, bytes); vcn += readcount; bytes += n; } } VOID ReadVCN (PDEVICE_EXTENSION Vcb, PFILE_RECORD_HEADER file, ATTRIBUTE_TYPE type, ULONGLONG vcn, ULONG count, PVOID buffer) { PNONRESIDENT_ATTRIBUTE NresAttr; PATTRIBUTE attr; attr = FindAttribute(file, type, 0); NresAttr = (PNONRESIDENT_ATTRIBUTE) attr; if (NresAttr == 0 || (vcn < NresAttr->StartVcn ||vcn > NresAttr->LastVcn)) { // PATTRIBUTE attrList = FindAttribute(file,AttributeAttributeList,0); DbgPrint("Exeption \n"); // KeDebugCheck(0); } ReadExternalAttribute(Vcb, NresAttr, vcn, count, buffer); } #if 0 BOOL bitset(PUCHAR bitmap, ULONG i) { return (bitmap[i>>3] & (1 << (i & 7))) !=0; } #endif VOID FixupUpdateSequenceArray(PFILE_RECORD_HEADER file) { PUSHORT usa = (PUSHORT)((ULONG_PTR)file + file->Ntfs.UsaOffset); PUSHORT sector = (PUSHORT)file; ULONG i; for( i =1; i < file->Ntfs.UsaCount; i++) { sector[255] = usa[i]; sector += 256; } } NTSTATUS ReadLCN (PDEVICE_EXTENSION Vcb, ULONGLONG lcn, ULONG count, PVOID buffer) { LARGE_INTEGER DiskSector; DiskSector.QuadPart = lcn; return NtfsReadSectors (Vcb->StorageDevice, DiskSector.u.LowPart * Vcb->NtfsInfo.SectorsPerCluster, count * Vcb->NtfsInfo.SectorsPerCluster, Vcb->NtfsInfo.BytesPerSector, buffer, FALSE); } /* EOF */