315 lines
9.0 KiB
C++
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;
|
|
}
|