/*++

Copyright (c) 1991 Microsoft Corporation

Module Name:

    dossa.hxx

Abstract:

    This class models the root of an HPFS or FAT file system.

Author:

    Mark Shavlik (marks) 27-Mar-90
    Norbert Kusters (norbertk) 25-July-91

Notes:

	The super sector contains data that is common to both FAT and HPFS
	file system.  This data is stored at LBN 0 on such volumes.  This
	data maps a number of things  defined by the data structures below.

--*/

#if !defined(DOSSA_DEFN)

#define DOSSA_DEFN


#include "supera.hxx"

//
//	Forward references
//

DECLARE_CLASS( DOS_SUPERAREA );
DECLARE_CLASS( WSTRING );



#define sigBOOTSTRAP (UCHAR)0x29	// boot strap signature

// if any of these values change make sure alignment is not problem,
// see the alignment tables below for more information.
#define cOEM 	     8			// 8 bytes of OEM data 
#define cLABEL	     11			// number of bytes in the label
#define cSYSID	     8			// number of bytes in  SYS ID

enum PHYSTYPE {	// ptype
	PHYS_REMOVABLE,		// physical drive is removable
	PHYS_FIXED = 0x80	// physical drive is fixed
};

// The structures below are the aligned version of the above structures.
// Conversions between the two  types is done by the Pack and UnPack methods.
// Any access to sector 0 data must be done via  these aligned types.

//
//  Define the Packed and Unpacked BIOS Parameter Block
//

// Unaligned Sector 0
typedef struct UNALIGNED_SECTOR_ZERO {
    UCHAR   IntelNearJumpCommand[1];    // Intel Jump command
    UCHAR   BootStrapJumpOffset[2];     // offset of boot strap code
    UCHAR   OemData[cOEM];		     	// OEM data
    UCHAR   BytesPerSector[2];          // BPB
    UCHAR   SectorsPerCluster[1];       //
    UCHAR   ReservedSectors[2];         //
    UCHAR   Fats[1];                    //
    UCHAR   RootEntries[2];             //
    UCHAR   Sectors[2];                 //
    UCHAR   Media[1];                   //
    UCHAR   SectorsPerFat[2];           //
    UCHAR   SectorsPerTrack[2];         //
    UCHAR   Heads[2];                   //
    UCHAR   HiddenSectors[4];           //
    UCHAR   LargeSectors[4];            //
	UCHAR   PhysicalDrive[1]; 		    // 0 = removable, 80h = fixed
	UCHAR   CurrentHead[1];			    // not used by fs utils
	UCHAR   Signature[1]; 			    // boot signature
	UCHAR   SerialNumber[4];     	    // serial number
	UCHAR   Label[cLABEL]; 			    // volume label, aligned padded
    UCHAR   SystemIdText[cSYSID];       // system ID, FAT for example
    UCHAR   StartBootCode;              // First byte of boot code
} *PUNALIGNED_SECTOR_ZERO;		 	

// Aligned Sector 0
typedef struct ALIGNED_SECTOR_ZERO {
    UCHAR	IntelNearJumpCommand;	// Intel Jump command
    USHORT  BootStrapJumpOffset; 	// offset of boot strap code
	UCHAR 	OemData[cOEM];			// OEM data
	USHORT 	BytesPerSector;
    UCHAR   SectorsPerCluster;
	USHORT 	ReservedSectors;
	UCHAR 	Fats;
	USHORT 	RootEntries;
	USHORT 	SectorCount_16bits; 	// 16 bit count
	UCHAR 	MediaByte;
	USHORT 	SectorsPerFat;
	USHORT 	SectorsPerTrack;
	USHORT 	Heads;
	ULONG 	HiddenSectors;
	ULONG 	SectorCount_32bits; 	// 32 bit count
	UCHAR 	PhysicalDrive; 		    // 0 = removable, 80h = fixed
	UCHAR 	CurrentHead;			// not used by fs utils
	UCHAR 	Signature;				// boot signature	
	ULONG 	SerialNumber;     	    // serial number
	UCHAR  	Label[cLABEL]; 		    // volume label, aligned padded
	UCHAR 	SystemIdText[cSYSID];	// system ID
} *PALIGNED_SECTOR_ZERO;

//
//  The following types and macros are used to help unpack the packed and
//  misaligned fields found in the Bios parameter block
//
#if !defined( _UCHAR_DEFINED_ )

#define _UCHAR_DEFINED_

// This code is taken directly from the NT HPFS code 

typedef union _UCHAR1 {
    UCHAR  Uchar[1];
    UCHAR  ForceAlignment;
} UCHAR1, *PUCHAR1;

typedef union _UCHAR2 {
    UCHAR  Uchar[2];
    USHORT ForceAlignment;
} UCHAR2, *PUCHAR2;

typedef union _UCHAR4 {
    UCHAR  Uchar[4];
    ULONG  ForceAlignment;
} UCHAR4, *PUCHAR4;

//
//  This macro copies an unaligned src byte to an aligned dst byte
//

#define CopyUchar1(Dst,Src) {                                \
    ((PUCHAR1)(Dst))->Uchar[0] = ((PUCHAR1)(Src))->Uchar[0]; \
    }

//
//  This macro copies an unaligned src word to an aligned dst word
//

#define CopyUchar2(Dst,Src) {                                \
    ((PUCHAR2)(Dst))->Uchar[0] = ((PUCHAR2)(Src))->Uchar[0]; \
    ((PUCHAR2)(Dst))->Uchar[1] = ((PUCHAR2)(Src))->Uchar[1]; \
    }

//
//  This macro copies an unaligned src longword to an aligned dsr longword
//

#define CopyUchar4(Dst,Src) {                                \
    ((PUCHAR4)(Dst))->Uchar[0] = ((PUCHAR4)(Src))->Uchar[0]; \
    ((PUCHAR4)(Dst))->Uchar[1] = ((PUCHAR4)(Src))->Uchar[1]; \
    ((PUCHAR4)(Dst))->Uchar[2] = ((PUCHAR4)(Src))->Uchar[2]; \
    ((PUCHAR4)(Dst))->Uchar[3] = ((PUCHAR4)(Src))->Uchar[3]; \
    }

#endif // _UCHAR_DEFINED_

//
//  This macro Uncopies an unaligned src byte to an aligned dst byte
//

#define UnCopyUchar1(Dst,Src) {                              \
    ((PUCHAR1)(Src))->Uchar[0] = ((PUCHAR1)(Dst))->Uchar[0]; \
    }

//
//  This macro Uncopies an unaligned src word to an aligned dst word
//

#define UnCopyUchar2(Dst,Src) {                              \
    ((PUCHAR2)(Src))->Uchar[0] = ((PUCHAR2)(Dst))->Uchar[0]; \
    ((PUCHAR2)(Src))->Uchar[1] = ((PUCHAR2)(Dst))->Uchar[1]; \
    }

//
//  This macro Uncopies an unaligned src longword to an aligned dst longword
//

#define UnCopyUchar4(Dst,Src) {                              \
    ((PUCHAR4)(Src))->Uchar[0] = ((PUCHAR4)(Dst))->Uchar[0]; \
    ((PUCHAR4)(Src))->Uchar[1] = ((PUCHAR4)(Dst))->Uchar[1]; \
    ((PUCHAR4)(Src))->Uchar[2] = ((PUCHAR4)(Dst))->Uchar[2]; \
    ((PUCHAR4)(Src))->Uchar[3] = ((PUCHAR4)(Dst))->Uchar[3]; \
    }

// the text for the oem data field
#define OEMTEXT       "MSDOS5.0"
#define OEMTEXTLENGTH 8


class DOS_SUPERAREA : public SUPERAREA {

    public:

	    VIRTUAL
        ~DOS_SUPERAREA(
            );

        VIRTUAL
        BOOLEAN
        Read(
            );

        VIRTUAL
        BOOLEAN
        Write(
            );

        VIRTUAL
        PVOID
        GetBuf(
            );

        VIRTUAL
        BOOLEAN
        Create(
            IN      PCNUMBER_SET    BadSectors,
            IN OUT  PMESSAGE        Message,
            IN      PCWSTRING       Label       DEFAULT NULL,
            IN      ULONG           ClusterSize DEFAULT 0
            ) PURE;

        VIRTUAL
        BOOLEAN
        VerifyAndFix(
            IN      FIX_LEVEL   FixLevel,
            IN OUT  PMESSAGE    Message,
            IN      BOOLEAN     Verbose         DEFAULT FALSE,
            IN      BOOLEAN     OnlyIfDirty     DEFAULT FALSE,
            IN      BOOLEAN     RecoverFree     DEFAULT FALSE,
            IN      BOOLEAN     RecoverAlloc    DEFAULT FALSE
            ) PURE;

        VIRTUAL
        BOOLEAN
        RecoverFile(
            IN      PCWSTRING    FullPathFileName,
            IN OUT  PMESSAGE            Message
            ) PURE;

        NONVIRTUAL
        PALIGNED_SECTOR_ZERO
        GetSectorZero(
            );

 	    NONVIRTUAL
	    BOOLEAN
	    IsFormatted(
	        ) CONST;

 	    VIRTUAL
        PARTITION_SYSTEM_ID
	    QuerySystemId(
	        ) CONST PURE;

        NONVIRTUAL
        SECTORCOUNT
        QuerySectors(
            ) CONST;

        VIRTUAL
	    SECTORCOUNT
        QueryFreeSectors(
            ) CONST PURE;

        NONVIRTUAL
	    VOLID
        SetVolId(
            IN  VOLID   VolId
            );

        NONVIRTUAL
        VOLID
        QueryVolId(
            ) CONST;

        NONVIRTUAL
        VOLID
        CreateVolId(
            );

        NONVIRTUAL
        UCHAR
        QueryMediaByte(
            ) CONST;

        VIRTUAL
        BOOLEAN
        QueryLabel(
            OUT PWSTRING    Label
            ) CONST;

        VIRTUAL
        BOOLEAN
        SetLabel(
            IN  PCWSTRING    NewLabel
            );

        STATIC
        BOOLEAN
        IsValidString(
            IN  PCWSTRING    String
            );

    protected:

		DECLARE_CONSTRUCTOR( DOS_SUPERAREA );

        NONVIRTUAL
        BOOLEAN
        Initialize(
            IN OUT  PMEM                Mem,
            IN OUT  PLOG_IO_DP_DRIVE    Drive,
            IN      SECTORCOUNT         NumberOfSectors,
            IN OUT  PMESSAGE            Message
            );

        NONVIRTUAL
        BOOLEAN
        CreateBootSector(
            );

        NONVIRTUAL
        BOOLEAN
        VerifyBootSector(
            );

        VIRTUAL
	    BOOLEAN
        SetBpb(
            );

        NONVIRTUAL
	    BOOLEAN
	    PackSectorZero(
	        );

	    NONVIRTUAL
	    BOOLEAN
	    UnPackSectorZero(
	        );
	
	    ALIGNED_SECTOR_ZERO	_sector_zero;

    private:

	    PUCHAR              _sector_sig;    // sector signature

		NONVIRTUAL
		VOID
		Construct(
			);

        NONVIRTUAL
        VOID
        Destroy(
            );

        NONVIRTUAL
	    ULONG
        QuerySecMeg(
            IN  ULONG   MegaBytes
            ) CONST;

        NONVIRTUAL
	    BOOLEAN
        SetOemData(
            );

        NONVIRTUAL
	    BOOLEAN
        SetBootCode(
            );

        NONVIRTUAL
	    BOOLEAN
        SetBootSignature(
            IN  UCHAR   Signature DEFAULT sigBOOTSTRAP
            );

        NONVIRTUAL
	    BOOLEAN
        SetSignature(
            );

        NONVIRTUAL
	    BOOLEAN
        SetPhysicalDriveType(
            IN  PHYSTYPE    PhysType
            );

};


INLINE
BOOLEAN
DOS_SUPERAREA::Read(
    )
/*++

Routine Description:

    This routine calls SECRUN's read routine and then unpacks the
    sectorzero data into a local structure.

Arguments:

    None.

Return Value:

    FALSE   - Failure.
    TRUE    - Success.

--*/
{
    return SECRUN::Read() && UnPackSectorZero();
}


INLINE
BOOLEAN
DOS_SUPERAREA::Write(
    )
/*++

Routine Description:

    This routine packs the sector zero structure in the SECRUN and then
    calls SECRUN's write routine.

Arguments:

    None.

Return Value:

    FALSE   - Failure.
    TRUE    - Success.

--*/
{
    return PackSectorZero() && SECRUN::Write();
}


INLINE
PVOID
DOS_SUPERAREA::GetBuf(
    )
/*++

Routine Description:

    This routine returns a pointer to the beginning of the read/write
    buffer.

Arguments:

    None.

Return Value:

    A pointer to a read/write buffer.

--*/
{
    return PackSectorZero() ? SECRUN::GetBuf() : NULL;
}


INLINE
PALIGNED_SECTOR_ZERO
DOS_SUPERAREA::GetSectorZero(
    )
/*++

Routine Description:

    This routine returns a pointer to the unpacked version of sector zero.
    The values modified here will take effect on disk after a write.

Arguments:

    None.

Return Value:

    A pointer to an unpacked sector zero.

--*/
{
    return &_sector_zero;
}


INLINE
SECTORCOUNT
DOS_SUPERAREA::QuerySectors(
    ) CONST
/*++

Routine Description:

    This routine computes the number of sectors on the volume according
    to the file system.

Arguments:

    None.

Return Value:

    The number of sectors on the volume according to the file system.

--*/
{
    return _sector_zero.SectorCount_16bits ? _sector_zero.SectorCount_16bits :
           _sector_zero.SectorCount_32bits;
}


INLINE
VOLID
DOS_SUPERAREA::SetVolId(
    IN  VOLID   VolId
    )
/*++

Routine Description:

    This routine puts the volume ID into the super area's data.

Arguments:

    VolId   - The new volume ID.

Return Value:

    The volume ID that was put.

--*/
{
   	return _sector_zero.SerialNumber = VolId;
}


INLINE
VOLID
DOS_SUPERAREA::CreateVolId(
    )
/*++

Routine Description:

    This routine puts a new volume identifier in the super area.

Arguments:

    None.

Return Value:

    The volume id that was created.

--*/
{
    return SetVolId(ComputeVolId());
}


INLINE
ULONG
DOS_SUPERAREA::QuerySecMeg(
    IN  ULONG   MegaBytes
    ) CONST
/*++

Routine Description:

    This routine computes the number of sectors contained in 'MegaBytes'
    megabytes.

Arguments:

    MegaBytes   - Supplies the number of megabytes.

Return Value:

    The number of sectors contained in 'MegaBytes' megabytes.

--*/
{
	return ( (MegaBytes<<20) / _drive->QuerySectorSize());
}


INLINE
BOOLEAN
DOS_SUPERAREA::SetOemData(
    )
/*++

Routine Description:

    This routine sets the OEM data in the super area.

Arguments:

    None.

Return Value:

    FALSE   - Failure.
    TRUE    - Success.

--*/
{
 	memcpy( (void*)_sector_zero.OemData, (void*)OEMTEXT, OEMTEXTLENGTH);
	return TRUE;
}


INLINE
BOOLEAN
DOS_SUPERAREA::SetBootSignature(
    IN  UCHAR   Signature
    )
/*++

Routine Description:

    This routine sets the boot signature in the super area.

Arguments:

    Signature   - Supplies the character to set the signature to.

Return Value:

    FALSE   - Failure.
    TRUE    - Success.

--*/
{
 	_sector_zero.Signature = Signature;
	return TRUE;
}


INLINE
VOLID
DOS_SUPERAREA::QueryVolId(
    ) CONST
/*++

Routine Description:

    This routine fetches the volume ID from the super area's data.
    This routine will return 0 if volume serial numbers are not
    supported by the partition.

Arguments:

    None.

Return Value:

    The volume ID residing in the super area.

--*/
{
   	return (_sector_zero.Signature == 0x28 || _sector_zero.Signature == 0x29) ?
           _sector_zero.SerialNumber : 0;
}


INLINE
UCHAR
DOS_SUPERAREA::QueryMediaByte(
    ) CONST
/*++

Routine Description:

    This routine fetches the media byte from the super area's data.

Arguments:

    None.

Return Value:

    The media byte residing in the super area.

--*/
{
   	return _sector_zero.MediaByte;
}


#endif // DOSSA_DEFN