NT4/private/utils/cuhpfs/cvtfnode.cxx
2020-09-30 17:12:29 +02:00

267 lines
7.3 KiB
C++

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
cvtfnode.cxx
Abstract:
This module contains the routines to support conversion of an HPFS
FNode into an NTFS file.
Author:
Bill McJohn (billmc) 18-Nov-1991
Environment:
ULIB, User Mode
--*/
#include <pch.cxx>
#define _NTAPI_ULIB_
#include "ulib.hxx"
#include "hmem.hxx"
#include "ifssys.hxx"
#include "drive.hxx"
#include "secrun.hxx"
#include "uhpfs.hxx"
#include "bitmap.hxx"
#include "dirblk.hxx"
#include "error.hxx"
#include "fnode.hxx"
#include "message.hxx"
#include "store.hxx"
#include "cpinfo.hxx"
#include "untfs.hxx"
#include "attrib.hxx"
#include "extents.hxx"
#include "frs.hxx"
#include "mft.hxx"
#include "ntfsbit.hxx"
#include "indxtree.hxx"
#include "mftfile.hxx"
#include "cuhpfs.hxx"
BOOLEAN
ConvertFileFnodeToNtfs(
IN OUT PLOG_IO_DP_DRIVE Drive,
IN OUT PNTFS_BITMAP VolumeBitmap,
IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap,
IN OUT PNTFS_MFT_FILE Mft,
IN OUT PFNODE Fnode,
IN OUT PNTFS_FILE_RECORD_SEGMENT TargetFrs,
IN ULONG FileSize,
IN OUT PBOOLEAN IsCorrupt,
IN PCWSTRING FullPath
)
/*++
Routine Description:
This method creates a $DATA attribute which corresponds to the
storage allocation of the given FNode and inserts that attribute
into the target File Record Segment.
Arguments:
Drive -- Supplies the drive being converted.
VolumeBitmap -- Supplies the NTFS bitmap for the volume.
HpfsOnlyBitmap -- Supplies the bitmap of HPFS-only structures.
Mft -- Supplies the Master File Table.
Fnode -- Supplies the FNode being converted.
TargetFrs -- Supplies the FRS which will accept the new DATA
attribute.
FileSize -- Supplies the size of the file (from directory entry).
IsCorrupt -- Receives TRUE if the volume is found to be corrupt.
(Note that it may already be TRUE
FullPath -- Supplies the path for this file.
Return Value:
TRUE upon successful completion.
Notes:
If the file's data stream is sufficiently small, it will be
incorporated into the File Record Segment as a resident attribute.
If this happens, this method will mark the file's allocated sectors
in the HpfsOnlyBitmap.
This method does not write the new File Record Segment--that is the
client's responsibility.
--*/
{
NTFS_ATTRIBUTE DataAttribute;
NTFS_EXTENT_LIST Extents;
SECRUN Secrun;
HMEM SecrunBuffer;
ULONG NumberOfExtents, NumberOfSectors, i;
PALLEAF AllocationLeaves;
BOOLEAN result;
// Extract the allocation information from the FNode. First,
// determine the number of extents associated with the FNode
// (using QueryExtents with 0 for max. number and NULL for
// output buffer).
if( !Fnode->QueryExtents( 0, NULL, &NumberOfExtents ) ) {
return FALSE;
}
// Allocate a buffer based on the number of extents it will hold.
if( (AllocationLeaves =
(PALLEAF)MALLOC( NumberOfExtents * sizeof( ALLEAF ) )) ==
NULL ) {
return FALSE;
}
// Now go back to the FNode and get the actual list of
// allocation leaves.
if( !Fnode->QueryExtents( NumberOfExtents,
AllocationLeaves,
&NumberOfExtents ) ) {
FREE( AllocationLeaves );
return FALSE;
}
// Compute the allocated size of the file.
NumberOfSectors = 0;
for( i = 0; i < NumberOfExtents; i++ ) {
NumberOfSectors += AllocationLeaves[i].csecRun;
}
// Decide whether the $DATA attribute should be resident or
// non-resident. The data attribute can be resident if it
// has at most one extent, fits in the base file record segment,
// and has a valid length equal to the file length.
//
if( FileSize == 0 ) {
// This is an empty file, so it may as well be resident.
// I pass a length of zero to NTFS_ATTRIBUTE::Initialize
// to indicate that it's an empty attribute.
if( !DataAttribute.Initialize( Drive,
Mft->QueryClusterFactor(),
NULL,
0,
$DATA ) ) {
FREE( AllocationLeaves );
return FALSE;
}
} else if( NumberOfExtents == 1 &&
FileSize == Fnode->QueryValidLength() &&
FileSize + SIZE_OF_RESIDENT_HEADER <
TargetFrs->QueryFreeSpace() ) {
// This is a non-empty small file which only has one
// extent, so it might fit into the FRS. Start with
// it resident; if it doesn't fit, it'll get converted
// to nonresident later.
//
if( !SecrunBuffer.Initialize() ||
!Secrun.Initialize( &SecrunBuffer,
Drive,
AllocationLeaves[0].lbnPhys,
AllocationLeaves[0].csecRun ) ||
!Secrun.Read() ||
!DataAttribute.Initialize( Drive,
Mft->QueryClusterFactor(),
Secrun.GetBuf(),
FileSize,
$DATA ) ) {
FREE( AllocationLeaves );
return FALSE;
}
// The sectors associated with the file are now HPFS-only
// structures.
HpfsOnlyBitmap->SetAllocated(AllocationLeaves[0].lbnPhys,
AllocationLeaves[0].csecRun );
} else {
// Keep it nonresident. Initialize an extent list and
// put the extents from the FNode into that extent list.
if( !Extents.Initialize( 0, 0 ) ) {
FREE( AllocationLeaves );
return FALSE;
}
for( i = 0; i < NumberOfExtents; i++ ) {
if( !Extents.AddExtent( AllocationLeaves[i].lbnLog,
AllocationLeaves[i].lbnPhys,
AllocationLeaves[i].csecRun ) ) {
FREE( AllocationLeaves );
return FALSE;
}
}
// Initialize a data attribute with this extent list.
if( !DataAttribute.Initialize( Drive,
Mft->QueryClusterFactor(),
&Extents,
FileSize,
Fnode->QueryValidLength(),
$DATA,
NULL ) ) {
FREE( AllocationLeaves );
return FALSE;
}
}
// Jam this data attribute into the File Record Segment.
result = DataAttribute.InsertIntoFile( TargetFrs, VolumeBitmap );
if( !result && DataAttribute.IsResident() ) {
// Couldn't insert a resident attribute--make it nonresident
// and try again.
//
result = DataAttribute.MakeNonresident( VolumeBitmap ) &&
DataAttribute.InsertIntoFile( TargetFrs, VolumeBitmap );
}
FREE( AllocationLeaves );
return result;
}