windows-nt/Source/XPSP1/NT/base/fs/utils/untfs/src/mftref.cxx
2020-09-26 16:20:57 +08:00

450 lines
11 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
mftref.cxx
Abstract:
This module contains the member function definitions for
the NTFS_REFLECTED_MASTER_FILE_TABLE class. This class
models the backup copy of the Master File Table.
Author:
Bill McJohn (billmc) 13-June-91
Environment:
ULIB, User Mode
--*/
#include <pch.cxx>
#define _NTAPI_ULIB_
#define _UNTFS_MEMBER_
#include "ulib.hxx"
#include "error.hxx"
#include "untfs.hxx"
#include "drive.hxx"
#include "attrib.hxx"
#include "ntfsbit.hxx"
#include "mftref.hxx"
#include "ifssys.hxx"
#include "numset.hxx"
#include "message.hxx"
#include "rtmsg.h"
DEFINE_EXPORTED_CONSTRUCTOR( NTFS_REFLECTED_MASTER_FILE_TABLE,
NTFS_FILE_RECORD_SEGMENT, UNTFS_EXPORT );
UNTFS_EXPORT
NTFS_REFLECTED_MASTER_FILE_TABLE::~NTFS_REFLECTED_MASTER_FILE_TABLE(
)
{
Destroy();
}
VOID
NTFS_REFLECTED_MASTER_FILE_TABLE::Construct(
)
/*++
Routine Description:
Worker function for the construtor.
Arguments:
None.
Return Value:
None.
--*/
{
}
VOID
NTFS_REFLECTED_MASTER_FILE_TABLE::Destroy(
)
/*++
Routine Description:
Clean up an NTFS_MASTER_FILE_TABLE object in preparation for
destruction or reinitialization.
Arguments:
None.
Return Value:
None.
--*/
{
}
BOOLEAN
NTFS_REFLECTED_MASTER_FILE_TABLE::Initialize(
IN OUT PNTFS_MASTER_FILE_TABLE Mft
)
/*++
Routine Description:
This method initializes a Master File Table Reflection object.
The only special knowledge that it adds to the File Record Segment
initialization is the location within the Master File Table of the
Master File Table Reflection.
Arguments:
Mft -- Supplies the volume MasterFile Table.
Return Value:
TRUE upon successful completion
Notes:
This class is reinitializable.
--*/
{
return( NTFS_FILE_RECORD_SEGMENT::Initialize( MASTER_FILE_TABLE2_NUMBER,
Mft ) );
}
BOOLEAN
NTFS_REFLECTED_MASTER_FILE_TABLE::Create(
IN PCSTANDARD_INFORMATION StandardInformation,
IN OUT PNTFS_BITMAP VolumeBitmap
)
/*++
Routine Description:
This method formats a Master File Table Reflection File Record
Segment in memory (without writing it to disk).
Arguments:
StandardInformation -- supplies the standard information for the
file record segment.
VolumeBitmap -- supplies the bitmap for the volume on
which this object resides.
Return Value:
TRUE upon successful completion.
--*/
{
NTFS_ATTRIBUTE DataAttribute;
NTFS_EXTENT_LIST Extents;
LCN FirstLcn;
BIG_INT Size;
ULONG ReflectedMftClusters;
ULONG cluster_size;
// Set this object up as a File Record Segment.
if( !NTFS_FILE_RECORD_SEGMENT::Create( StandardInformation ) ) {
return FALSE;
}
// The Master File Table Reflection has a data attribute whose value
// consists of REFLECTED_MFT_SEGMENTS file record segments. Create
// merely allocates space for these clusters, it does not write them.
cluster_size = QueryClusterFactor() * GetDrive()->QuerySectorSize();
ReflectedMftClusters = (REFLECTED_MFT_SEGMENTS * QuerySize() + (cluster_size-1))
/ cluster_size;
Size = ReflectedMftClusters * cluster_size;
if( !VolumeBitmap->AllocateClusters( (QueryVolumeSectors()/2)/
QueryClusterFactor(),
ReflectedMftClusters,
&FirstLcn ) ||
!Extents.Initialize( 0, 0 ) ||
!Extents.AddExtent( 0,
FirstLcn,
ReflectedMftClusters ) ||
!DataAttribute.Initialize( GetDrive(),
QueryClusterFactor(),
&Extents,
Size,
Size,
$DATA ) ||
!DataAttribute.InsertIntoFile( this, VolumeBitmap ) ) {
return FALSE;
}
return TRUE;
}
NONVIRTUAL
BOOLEAN
NTFS_REFLECTED_MASTER_FILE_TABLE::VerifyAndFix(
IN PNTFS_ATTRIBUTE MftData,
IN OUT PNTFS_BITMAP VolumeBitmap,
IN OUT PNUMBER_SET BadClusters,
IN OUT PNTFS_INDEX_TREE RootIndex,
OUT PBOOLEAN Changes,
IN FIX_LEVEL FixLevel,
IN OUT PMESSAGE Message
)
/*++
Routine Description:
This routine ensures that this FRS's $DATA attribute is the
appropriate length (from 1 to 3 clusters). It also compares
the data in these clusters with the first clusters of the
$MftData attribute and prints a message if they are different.
This routine does not actually write out the contents of these
clusters because this is done by MFT_FILE::Flush()
Arguments:
MftData - Supplies the MFT $DATA attribute.
VolumeBitmap - Supplies the volume bitmap.
BadClusters - Supplies the list of bad clusters.
RootIndex - Supplies the root index.
Changes - Returns whether or not changes were made.
FixLevel - Supplies the CHKDSK fix level.
Message - Supplies an outlet for messages.
Return Value:
FALSE - Failure.
TRUE - Success.
--*/
{
HMEM mft_hmem, ref_hmem;
SECRUN mft_secrun, ref_secrun;
LCN mft_lcn, ref_lcn;
BIG_INT run_length;
ULONG num_clusters;
ULONG num_sectors;
ULONG num_bytes, bytes_written;
BOOLEAN need_write;
NTFS_ATTRIBUTE data_attribute;
NTFS_EXTENT_LIST extents;
BOOLEAN error;
*Changes = FALSE;
// First read in the original stuff.
num_sectors = (REFLECTED_MFT_SEGMENTS*QuerySize())/GetDrive()->QuerySectorSize();
num_bytes = num_sectors * GetDrive()->QuerySectorSize();
if (!MftData->QueryLcnFromVcn(0, &mft_lcn) ||
!mft_hmem.Initialize() ||
!mft_secrun.Initialize(&mft_hmem, GetDrive(),
mft_lcn*QueryClusterFactor(),
num_sectors) ||
!mft_secrun.Read()) {
Message->DisplayMsg(MSG_CHK_NO_MEMORY);
return FALSE;
}
need_write = FALSE;
// Query the $DATA attribute from this FRS.
if (!QueryAttribute(&data_attribute, &error, $DATA) ||
data_attribute.IsResident()) {
if (error) {
Message->DisplayMsg(MSG_CHK_NO_MEMORY);
return FALSE;
}
Message->LogMsg(MSG_CHKLOG_NTFS_MISSING_OR_RESIDENT_DATA_ATTR_IN_MFT_MIRROR);
Message->DisplayMsg(MSG_CHK_NTFS_CORRECTING_MFT_MIRROR);
need_write = TRUE;
if (!extents.Initialize(0, 0) ||
!data_attribute.Initialize(GetDrive(), QueryClusterFactor(),
&extents, 0, 0, $DATA)) {
Message->DisplayMsg(MSG_CHK_NTFS_CANT_FIX_MFT_MIRROR);
return FALSE;
}
}
// Make sure that the $DATA attribute is the right size.
error = FALSE;
if (need_write) {
error = TRUE;
} else if (!data_attribute.QueryLcnFromVcn(0, &ref_lcn, &run_length)) {
Message->LogMsg(MSG_CHKLOG_NTFS_UNABLE_TO_QUERY_LCN_FROM_VCN_FOR_MFT_MIRROR);
error = TRUE;
} else if (ref_lcn == LCN_NOT_PRESENT) {
Message->LogMsg(MSG_CHKLOG_NTFS_LCN_NOT_PRESENT_FOR_VCN_ZERO_OF_MFT_MIRROR);
error = TRUE;
} else if (run_length*QueryClusterFactor() < num_sectors) {
Message->LogMsg(MSG_CHKLOG_NTFS_DISCONTIGUOUS_MFT_MIRROR);
error = TRUE;
} else if (data_attribute.QueryValueLength() < num_bytes) {
Message->LogMsg(MSG_CHKLOG_NTFS_MFT_MIRROR_HAS_INVALID_VALUE_LENGTH,
"%I64x%x",
data_attribute.QueryValueLength().GetLargeInteger(),
num_bytes);
error = TRUE;
} else if (data_attribute.QueryValidDataLength() < num_bytes) {
Message->LogMsg(MSG_CHKLOG_NTFS_MFT_MIRROR_HAS_INVALID_DATA_LENGTH,
"%I64x%x",
data_attribute.QueryValidDataLength().GetLargeInteger(),
num_bytes);
error = TRUE;
} else if (!ref_hmem.Initialize()) {
error = TRUE;
} else if (!ref_secrun.Initialize(&ref_hmem, GetDrive(),
ref_lcn*QueryClusterFactor(),
num_sectors)) {
error = TRUE;
} else if (!ref_secrun.Read()) {
Message->LogMsg(MSG_CHKLOG_NTFS_UNABLE_TO_READ_MFT_MIRROR,
"%I64x%x",
ref_lcn.GetLargeInteger(),
num_sectors);
error = TRUE;
}
if (error) {
if (!need_write) {
Message->DisplayMsg(MSG_CHK_NTFS_CORRECTING_MFT_MIRROR);
}
need_write = TRUE;
if (data_attribute.QueryLcnFromVcn(0, &ref_lcn, &run_length) &&
ref_lcn != LCN_NOT_PRESENT &&
!BadClusters->Add(ref_lcn, run_length)) {
Message->DisplayMsg(MSG_CHK_NO_MEMORY);
return FALSE;
}
num_clusters = (num_sectors+QueryClusterFactor()-1)/QueryClusterFactor();
// the write below is just to change the valid data length and valid length
// to the correct value. The content we write is not of importance.
if (!data_attribute.Hotfix(0, num_clusters, VolumeBitmap,
BadClusters, TRUE) ||
!data_attribute.Write(NULL,
num_bytes,
0,
&bytes_written,
NULL)) {
Message->DisplayMsg(MSG_CHK_NTFS_CANT_FIX_MFT_MIRROR);
return FALSE;
}
} else if (memcmp(mft_hmem.GetBuf(), ref_hmem.GetBuf(),
REFLECTED_MFT_SEGMENTS*QuerySize())) {
Message->LogMsg(MSG_CHKLOG_NTFS_MFT_MIRROR_DIFFERENT_FROM_MFT);
if (!need_write) {
Message->DisplayMsg(MSG_CHK_NTFS_CORRECTING_MFT_MIRROR);
}
need_write = TRUE; // set the change status
}
if ((data_attribute.IsStorageModified() &&
!data_attribute.InsertIntoFile(this, VolumeBitmap)) ||
(need_write && FixLevel != CheckOnly &&
!Flush(VolumeBitmap, RootIndex))) {
Message->DisplayMsg(MSG_CHK_NTFS_CANT_FIX_MFT_MIRROR);
return FALSE;
}
*Changes = need_write;
return TRUE;
}
LCN
NTFS_REFLECTED_MASTER_FILE_TABLE::QueryFirstLcn(
)
/*++
Routine Description:
Arguments:
None.
Return Value:
The LCN of the first cluster of the Master File Table
Reflection's $DATA attribute.
--*/
{
NTFS_ATTRIBUTE DataAttribute;
LCN Result = 0;
BOOLEAN Error;
if( !QueryAttribute( &DataAttribute, &Error, $DATA ) ||
!DataAttribute.QueryLcnFromVcn( 0, &Result ) ) {
Result = 0;
}
return Result;
}