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

315 lines
9.0 KiB
C++

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
cvteas.cxx
Abstract:
This module contains the routines to support conversion of HPFS
Extended Attributes.
Author:
Bill McJohn (billmc) 27-Dec-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 "hpfsea.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
ConvertEasToNtfs(
IN OUT PLOG_IO_DP_DRIVE Drive,
IN OUT PNTFS_BITMAP VolumeBitmap,
IN OUT PNTFS_MFT_FILE Mft,
IN OUT PFNODE Fnode,
IN OUT PNTFS_FILE_RECORD_SEGMENT TargetFrs,
IN ULONG DirentEaSize,
IN ULONG CodepageId,
IN OUT PBOOLEAN IsCorrupt,
IN OUT PVOID NameBuffer,
IN ULONG NameBufferLength,
IN OUT PVOID EaBuffer,
IN ULONG EaBufferLength
)
/*++
Routine Description:
This function converts the Extended Attributes associated with an FNode
into attributes associated with an NTFS File Record Segment.
Arguments:
Drive -- Supplies the drive being converted.
VolumeBitmap -- Supplies the NTFS bitmap for the volume.
Mft -- Supplies the NTFS Master File Table for the volume.
Fnode -- Supplies the FNode being converted.
TargetFrs -- Supplies the NTFS File Record Segment that will
receive the converted attributes.
DirentEaSize -- Supplies the size of the Extended Attributes
associated with this FNode, according to the
parent directory entry.
CodepageId -- Supplies the Code Page associated with the parent
directory entry. (Note that this is a real code
page ID, rather than a volume index).
IsCorrupt -- Receives TRUE if the Extended Attribute structures
are found to be corrupt.
NameBuffer -- Supplies a scratch buffer for name conversion.
NameBufferLength -- Supplies the length in bytes of NameBuffer.
EaBuffer -- Supplies a scratch buffer for EA conversion.
EaBufferLength -- Supplies the length in bytes of EaBuffer.
Return Value:
TRUE upon successful completion.
--*/
{
EA_INFORMATION EaInformation;
NTFS_ATTRIBUTE EaDataAttribute, EaInformationAttribute;
NTFS_EXTENT_LIST ExtentList;
HPFS_EA CurrentEa;
DSTRING AttributeName;
PBYTE UnpackedListBuffer;
ULONG BytesWritten;
ULONG PackedListLength, UnpackedListLength, NeedEaCount;
ULONG CurrentOffset, TargetOffset, CurrentLength;
PBYTE CurrentEaData;
USHORT AttributeFlags;
ULONG Threshold = 1;
// Get the list of extended attributes from the FNode. Since
// Convert assumes that there are no hotfixes on the volume,
// pass in NULL for the hotfix parameter.
if( !Fnode->QueryPackedEaList( EaBuffer,
EaBufferLength,
&PackedListLength,
IsCorrupt,
NULL ) ) {
DebugPrint( "Cannot query packed EA list from FNode.\n" );
return FALSE;
}
// If the packed list length is zero, then there's
// no work to do.
if( PackedListLength == 0 ) {
return TRUE;
}
// Determine the unpacked size of this EA list by traversing the
// EA list.
CurrentOffset = 0;
UnpackedListLength = 0;
NeedEaCount = 0;
while( CurrentOffset < PackedListLength ) {
CurrentEaData = (PBYTE)EaBuffer + CurrentOffset;
// Initialize the HPFS_EA object with the current Extended
// Attribute. For the purpose at hand, the ParentLbn is
// unneccessary, so I pass in zero.
if( !CurrentEa.Initialize( Drive, (PEA_DATA)CurrentEaData, 0 ) ) {
return FALSE;
}
// Is it a need-ea EA?
if( CurrentEa.IsNeedEa() ) {
NeedEaCount += 1;
}
// The unpacked length is increased by a ULONG (for next offset)
// plus the length of this EA, plus enough padding to keep it
// DWORD aligned.
UnpackedListLength += sizeof(ULONG) + CurrentEa.QueryLength();
UnpackedListLength = DwordAlign( UnpackedListLength );
// Move on to the next extended attribute.
CurrentOffset += CurrentEa.QueryLength();
}
// Allocate a buffer to hold the unpacked list length, now that I
// know how big it is.
if( (UnpackedListBuffer = (PBYTE)MALLOC( UnpackedListLength )) == NULL ) {
return FALSE;
}
memset( UnpackedListBuffer, 0, UnpackedListLength );
// Traverse the list again, copying the EAs into the packed buffer.
TargetOffset = 0;
CurrentOffset = 0;
while( CurrentOffset < PackedListLength ) {
CurrentEaData = (PBYTE)EaBuffer + CurrentOffset;
// Initialize an EA with the current EA data.
if( !CurrentEa.Initialize( Drive, (PEA_DATA)CurrentEaData, 0 ) ) {
FREE( UnpackedListBuffer );
return FALSE;
}
// The length of this EA (plus the size of the offset, which
// is a ulong) goes at TargetOffset; the value of the EA goes
// after this ULONG.
CurrentLength = DwordAlign( CurrentEa.QueryLength() + sizeof( ULONG ) );
memcpy( UnpackedListBuffer + TargetOffset,
&CurrentLength,
sizeof(ULONG) );
memcpy( UnpackedListBuffer + TargetOffset + sizeof(ULONG),
CurrentEaData,
CurrentEa.QueryLength() );
TargetOffset += CurrentLength;
// Move on to the next extended attribute.
CurrentOffset += CurrentEa.QueryLength();
}
// Create the EA Information Attribute--fill in the fields of
// the EA information structure and put it into a resident attribute
// of type $EA_INFORMATION.
EaInformation.PackedEaSize = (USHORT)PackedListLength;
EaInformation.NeedEaCount = (USHORT)NeedEaCount;
EaInformation.UnpackedEaSize = UnpackedListLength;
if( !EaInformationAttribute.Initialize( Drive,
Mft->QueryClusterFactor(),
&EaInformation,
sizeof( EA_INFORMATION ),
$EA_INFORMATION,
NULL,
0 ) ) {
FREE( UnpackedListBuffer );
return FALSE;
}
// Set up the Ea Data attribute.
if( UnpackedListLength < Threshold ) {
// Make the $EA_DATA attribute resident
if( !EaDataAttribute.Initialize( Drive,
Mft->QueryClusterFactor(),
UnpackedListBuffer,
UnpackedListLength,
$EA_DATA,
NULL,
0 ) ) {
DebugPrint( "Cannot initialize resident attribute for EA.\n" );
FREE( UnpackedListBuffer );
return FALSE;
}
} else {
// Make the $EA_DATA attribute non-resident
if( !ExtentList.Initialize( 0, 0 ) ||
!EaDataAttribute.Initialize( Drive,
Mft->QueryClusterFactor(),
&ExtentList,
0,
0,
$EA_DATA,
NULL,
0 ) ||
!EaDataAttribute.Write( UnpackedListBuffer,
0,
UnpackedListLength,
&BytesWritten,
VolumeBitmap ) ||
BytesWritten != UnpackedListLength ) {
DebugPrint( "Cannot initialize a non-resident attribute for EA.\n" );
FREE( UnpackedListBuffer );
return FALSE;
}
}
FREE( UnpackedListBuffer );
if( !EaDataAttribute.InsertIntoFile( TargetFrs, VolumeBitmap ) ||
!EaInformationAttribute.InsertIntoFile( TargetFrs, VolumeBitmap ) ) {
return FALSE;
}
return TRUE;
}