/*++ 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 #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; }