/*++

Copyright (c) 1990-2001 Microsoft Corporation

Module Name:

    rfatsa.hxx

Abstract:

Author:

    Mark Shavlik (marks) 27-Mar-90
    Norbert Kusters (norbertk) 15-Jan-91
    Matthew Bradburn (mattbr) 01-Oct-93

--*/

#ifndef REAL_FAT_SA_DEFN
#define REAL_FAT_SA_DEFN

#include "hmem.hxx"
#include "message.hxx"
#include "fatsa.hxx"
#include "bpb.hxx"

#if defined ( _AUTOCHECK_ )
#define UFAT_EXPORT
#elif defined ( _UFAT_MEMBER_ )
#define UFAT_EXPORT    __declspec(dllexport)
#else
#define UFAT_EXPORT    __declspec(dllimport)
#endif

//
//    Forward references
//

DECLARE_CLASS( ARRAY );
DECLARE_CLASS( BITVECTOR );
DECLARE_CLASS( EA_HEADER );
DECLARE_CLASS( FAT );
DECLARE_CLASS( FAT_SA );
DECLARE_CLASS( FAT_DIRENT );
DECLARE_CLASS( FATDIR );
DECLARE_CLASS( GENERIC_STRING );
DECLARE_CLASS( INTSTACK );
DECLARE_CLASS( NUMBER_SET );
DECLARE_CLASS( LOG_IO_DP_DRIVE );
DECLARE_CLASS( MESSAGE );
DECLARE_CLASS( ROOTDIR );
DECLARE_CLASS( SORTED_LIST );
DECLARE_CLASS( TIMEINFO );
DECLARE_CLASS( WSTRING );
DEFINE_POINTER_TYPES( PFATDIR );

//
// Sony Memory Stick thresholds
//
#define SMS_VOLSIZE_SMALL   (70*1024*1024) // Maximum volume size to be formatted as FAT12

// Internal data types
// Possible return status after validating a given cluster size
typedef enum _VALIDATION_STATUS
{
VALID,
TOO_SMALL,
TOO_BIG
} VALIDATION_STATUS;


class REAL_FAT_SA : public FAT_SA {

    public:

        UFAT_EXPORT
        DECLARE_CONSTRUCTOR(REAL_FAT_SA);

        VIRTUAL
        UFAT_EXPORT
        ~REAL_FAT_SA(
            );

        NONVIRTUAL
        UFAT_EXPORT
        BOOLEAN
        Initialize(
            IN OUT  PLOG_IO_DP_DRIVE    Drive,
            IN OUT  PMESSAGE            Message,
            IN      BOOLEAN             Formatted DEFAULT TRUE
            );

        NONVIRTUAL
        UFAT_EXPORT
        BOOLEAN
        InitFATChkDirty(
            IN OUT  PLOG_IO_DP_DRIVE    Drive,
            IN OUT  PMESSAGE            Message
            );

        NONVIRTUAL
        BOOLEAN
        Create(
            IN      PCNUMBER_SET    BadSectors,
            IN OUT  PMESSAGE        Message,
            IN      PCWSTRING       Label                DEFAULT NULL,
            IN      ULONG           Flags                DEFAULT FORMAT_BACKWARD_COMPATIBLE,
            IN      ULONG           ClusterSize          DEFAULT 0,
            IN      ULONG           VirtualSize          DEFAULT 0
            );

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

        NONVIRTUAL
        UFAT_EXPORT
        BOOLEAN
        Read(
            IN OUT  PMESSAGE    Message
            );

        NONVIRTUAL
        BOOLEAN
        Write(
            IN OUT  PMESSAGE    Message
            );

        NONVIRTUAL
        VOID
        QueryGeometry(
            OUT PUSHORT SectorSize,
            OUT PUSHORT SectorsPerTrack,
            OUT PUSHORT Heads,
            OUT PULONG  HiddenSectors
            );

        NONVIRTUAL
        USHORT
        QuerySectorsPerCluster(
            ) CONST;

        NONVIRTUAL
        ULONG
        QuerySectorsPerFat(
            ) CONST;

        NONVIRTUAL
        USHORT
        QueryReservedSectors(
            ) CONST;

        NONVIRTUAL
        USHORT
        QueryFats(
            ) CONST;

        NONVIRTUAL
        ULONG
        QueryRootEntries(
            ) CONST;

        NONVIRTUAL
        PARTITION_SYSTEM_ID
        QuerySystemId(
            ) CONST;

        NONVIRTUAL
        LBN
        QueryStartDataLbn(
            ) CONST;

        NONVIRTUAL
        ULONG
        QueryClusterCount(
            ) CONST;

        NONVIRTUAL
        UFAT_EXPORT
        SECTORCOUNT
        QueryFreeSectors(
            ) CONST;

        NONVIRTUAL
        FATTYPE
        QueryFatType(
            ) CONST;

        NONVIRTUAL
        BYTE
        QueryVolumeFlags(
            ) CONST;

        NONVIRTUAL
        VOID
        SetVolumeFlags(
            BYTE Flags,
            BOOLEAN ResetFlags
            );

        NONVIRTUAL
        BOOLEAN
        RecoverChain(
            IN OUT  PULONG      StartingCluster,
            OUT     PBOOLEAN    ChangesMade,
            IN      ULONG       EndingCluster   DEFAULT 0,
            IN      BOOLEAN     Replace         DEFAULT FALSE,
            IN      PBITVECTOR  FatBitMap       DEFAULT NULL
            );

        STATIC
        USHORT
        ComputeSecClus(
            IN  SECTORCOUNT Sectors,
            IN  FATTYPE     FatType,
#if defined(FE_SB) && defined(_X86_)
            IN  MEDIA_TYPE  MediaType,
            IN  ULONG       SectorSize = 512
#else
            IN  MEDIA_TYPE  MediaType
#endif
            );

        NONVIRTUAL
        BOOLEAN
        IsFileContiguous(
            IN      ULONG       StartingCluster
            ) CONST;

        NONVIRTUAL
        BOOLEAN
        IsCompressed(
            ) CONST;

        NONVIRTUAL
        BOOLEAN
        IsVolumeDataAligned(
            ) CONST;

        NONVIRTUAL
        BOOLEAN
        ReadSectorZero(
            );

        NONVIRTUAL
        PBIOS_PARAMETER_BLOCK
        GetBpb(
            );

        NONVIRTUAL
        SECTORCOUNT
        QueryVirtualSectors(
            ) CONST;

        NONVIRTUAL
        VOID
        PrintFormatReport (
            IN OUT PMESSAGE                             Message,
            IN     PFILE_FS_SIZE_INFORMATION            FsSizeInfo,
            IN     PFILE_FS_VOLUME_INFORMATION          FsVolInfo
            );

    private:

        HMEM                _mem;           // memory for SECRUN

        // _fat inherited from FAT_SA
        // _fattype inherited from FAT_SA
        // _dir inherited from FAT_SA

        HMEM                _mem2;          // memory for SECRUN2
        SECRUN              _secrun2;       // secrun to hold one sector FAT sector
        LBN                 _StartDataLbn;  // LBN of files, or data area
        ULONG               _ClusterCount;  // number of clusters in Super Area
                                            // It actually means the number of
                                            // fat entries.

        PARTITION_SYSTEM_ID _sysid;         // system id
        ULONG               _sec_per_boot;  // sectors for boot code.
        EXTENDED_BIOS_PARAMETER_BLOCK
                            _sector_zero;
        PUCHAR              _sector_sig;    // sector signature

        BOOLEAN             _data_aligned;  // TRUE if data clusters are aligned to
                                            // FAT_FIRST_DATA_CLUSTER_ALIGNMENT boundary

        ULONG               _AdditionalReservedSectors; // padding to be added for data alignment

        NONVIRTUAL
        VOID
        Construct(
            );

        NONVIRTUAL
        VOID
        Destroy(
            );

        NONVIRTUAL
        VALIDATION_STATUS
        ValidateClusterSize(
            IN  ULONG      ClusterSize,
            IN  ULONG      Sectors,
            IN  ULONG      SectorSize,
            IN  ULONG      Fats,
            IN OUT FATTYPE *FatType,
            OUT PULONG     FatSize,
            OUT PULONG     ClusterCount
            );

        NONVIRTUAL
        ULONG
        ComputeDefaultClusterSize(
            IN  ULONG      Sectors,
            IN  ULONG      SectorSize,
            IN  ULONG      ReservedSectors,
            IN  ULONG      Fats,
            IN  MEDIA_TYPE MediaType,
            IN  FATTYPE    FatType,
            OUT PULONG     FatSize,
            OUT PULONG     ClusterCount
            );

        NONVIRTUAL
        ULONG
        DetermineClusterCountAndFatType (
            IN OUT  PULONG      StartingDataLbn,
            IN OUT  FATTYPE     *Fattype
            );

        NONVIRTUAL
        BOOLEAN
        InitializeRootDirectory (
            IN  PMESSAGE Message
            );

        NONVIRTUAL
        BOOLEAN
        SetBpb(
            IN  ULONG      ClusterSize,
            IN  ULONG      Flags,
            IN  PMESSAGE   Message
            );

        NONVIRTUAL
        BOOLEAN
        SetBpb(
            );

        NONVIRTUAL
        BOOLEAN
        DupFats(
            );

        NONVIRTUAL
        LBN
        ComputeStartDataLbn(
            ) CONST;

        NONVIRTUAL
        ULONG
        ComputeRootEntries(
            ) CONST;

        NONVIRTUAL
        BOOLEAN
        ValidateDirent(
            IN OUT  PFAT_DIRENT Dirent,
            IN      PCWSTRING   FilePath,
            IN      FIX_LEVEL   FixLevel,
            IN      BOOLEAN     RecoverAlloc,
            IN OUT  PMESSAGE    Message,
            IN OUT  PBOOLEAN    NeedErrorsMessage,
            IN OUT  PBITVECTOR  FatBitMap,
            OUT     PBOOLEAN    CrossLinkDetected,
            OUT     PULONG      CrossLinkPreviousCluster
            );

        NONVIRTUAL
        BOOLEAN
        CopyClusters(
            IN      ULONG       SourceChain,
            OUT     PULONG      DestChain,
            IN OUT  PBITVECTOR  FatBitMap,
            IN      FIX_LEVEL   FixLevel,
            IN OUT  PMESSAGE    Message
            );

        NONVIRTUAL
        BOOLEAN
        InitRelocationList(
            IN OUT  PINTSTACK       RelocationStack,
            IN OUT  PULONG          RelocatedChain,
            IN OUT  PSORTED_LIST    ClustersToRelocate,
            OUT     PBOOLEAN        Relocated
            );

        NONVIRTUAL
        BOOLEAN
        RelocateFirstCluster(
            IN OUT  PFAT_DIRENT     Dirent
            );

        NONVIRTUAL
        ULONG
        RelocateOneCluster(
            IN  ULONG    Cluster,
            IN  ULONG    Previous
            );

        NONVIRTUAL
        BOOLEAN
        DoDirectoryCensusAndRelocation(
            IN OUT  PFATDIR         Directory,
            IN OUT  PCENSUS_REPORT  CensusReport,
            IN OUT  PSORTED_LIST    ClustersToRelocate,
            IN OUT  PULONG          RelocatedChain,
            OUT     PBOOLEAN        Relocated
            );

        NONVIRTUAL
        BOOLEAN
        DoVolumeCensusAndRelocation(
            IN OUT  PCENSUS_REPORT  CensusReport,
            IN OUT  PSORTED_LIST    ClustersToRelocate,
            IN OUT  PULONG          RelocatedChain,
            OUT     PBOOLEAN        Relocated
            );

        NONVIRTUAL
        ULONG
        SecPerBoot(
            );

        NONVIRTUAL
        VOLID
        QueryVolId(
            ) CONST;

        NONVIRTUAL
        VOLID
        SetVolId(
            IN VOLID VolId
            );

        NONVIRTUAL
        UCHAR
        QueryMediaByte(
            ) CONST;

        VIRTUAL
        VOID
        SetMediaByte(
            UCHAR   MediaByte
            );

        NONVIRTUAL
        BOOLEAN
        VerifyBootSector(
            );

        NONVIRTUAL
        BOOLEAN
        CreateBootSector(
            IN  ULONG    ClusterSize,
            IN  ULONG    Flags,
            IN  PMESSAGE Message
            );

        BOOLEAN
        REAL_FAT_SA::SetBootCode(
            );

        NONVIRTUAL
        BOOLEAN
        SetPhysicalDriveType(
            IN  PHYSTYPE    PhysType
            );

        NONVIRTUAL
        BOOLEAN
        SetOemData(
            );

        NONVIRTUAL
        BOOLEAN
        SetSignature(
            );

        NONVIRTUAL
        BOOLEAN
        SetBootSignature(
            IN  UCHAR   Signature DEFAULT sigBOOTSTRAP
            );

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

        BOOLEAN
        DosSaSetBpb(
            );

        BOOLEAN
        RecoverOrphans(
            IN OUT  PBITVECTOR     FatBitMap,
            IN      FIX_LEVEL      FixLevel,
            IN OUT  PMESSAGE       Message,
            IN OUT  PBOOLEAN       NeedErrorsMessage,
            IN OUT  PFATCHK_REPORT Report,
               OUT  PBOOLEAN       Changes
            );

        NONVIRTUAL
        ULONG
        QuerySectorFromCluster(
            IN      ULONG       Cluster,
            OUT     PUCHAR      NumSectors        DEFAULT NULL
            );

        NONVIRTUAL
        BOOLEAN
        IsClusterCompressed(
            IN      ULONG       Cluster
            ) CONST;

        NONVIRTUAL
        VOID
        SetClusterCompressed(
            IN      ULONG       Cluster,
            IN      BOOLEAN     fCompressed
            );

        NONVIRTUAL
        UCHAR
        QuerySectorsRequiredForPlainData(
            IN      ULONG       Cluster
            );

        NONVIRTUAL
        BOOLEAN
        VerifyFatExtensions(
            IN      FIX_LEVEL   FixLevel,
            IN      PMESSAGE    Message,
            IN      PBOOLEAN    pfNeedMsg
            );

        NONVIRTUAL
        VOID
        SetFat32RootDirStartingCluster(
            IN      ULONG       RootCluster
            );

        NONVIRTUAL
        ULONG
        QueryFat32RootDirStartingCluster(
            );

        NONVIRTUAL
        BOOLEAN
        CheckSectorHeapAllocation(
            IN      FIX_LEVEL   FixLevel,
            IN      PMESSAGE    Message,
            IN      PBOOLEAN    pfNeedMsg
            );

        NONVIRTUAL
        BOOLEAN
        FreeClusterData(
            ULONG Cluster
            );

        NONVIRTUAL
        BOOLEAN
        AllocateClusterData(
            ULONG Cluster,
            UCHAR NumSectors,
            BOOLEAN bCompressed,
            UCHAR PlainSize
            );

        //
        // The following routines are defined for the new lightweight
        // format.
        //
        NONVIRTUAL
        BOOLEAN
        DiskIsUsable (
            IN PCNUMBER_SET     BadSectors,
            IN PMESSAGE         Message
            );

        NONVIRTUAL
        BOOLEAN
        WriteNewFats (
            IN      PCNUMBER_SET    BadSectors,
            IN OUT  PULONG          BadClusters,
            IN      PMESSAGE        Message
            );

        NONVIRTUAL
        BOOLEAN
        WriteNewRootDirAndVolumeLabel (
            IN  PCWSTRING       Label,
            IN  PMESSAGE        Message
            );

        NONVIRTUAL
        BOOLEAN
        WriteNewBootArea (
            IN  PMESSAGE    Message
            );

        NONVIRTUAL
        VOID
        PrintFormatReport (
            IN  ULONG       BadClusters,
            IN  PMESSAGE    Message
            );

};

INLINE
USHORT
REAL_FAT_SA::QuerySectorsPerCluster(
    ) CONST
/*++

Routine Description:

    This routine computes the number of sectors per cluster for
    the volume.

Arguments:

    None.

Return Value:

    The number of sectors per cluster for the volume.

--*/
{
    return _sector_zero.Bpb.SectorsPerCluster ?
           _sector_zero.Bpb.SectorsPerCluster : 256;
}


INLINE
ULONG
REAL_FAT_SA::QuerySectorsPerFat(
    ) CONST
/*++

Routine Description:

    This routine computes the number of sectors per FAT for the volume.

Arguments:

    None.

Return Value:

    The number of sectors per FAT for the volume.

--*/
{
    if ( 0 == _sector_zero.Bpb.SectorsPerFat ) {
        return _sector_zero.Bpb.BigSectorsPerFat;
    } else {
        return _sector_zero.Bpb.SectorsPerFat;
    }
}


INLINE
USHORT
REAL_FAT_SA::QueryReservedSectors(
    ) CONST
/*++

Routine Description:

    This routine computes the volume's number of Reserved Sectors,
    i.e. the number of sectors before the first FAT.

Arguments:

    None.

Return Value:

    The number of Reserved Sectors.

--*/
{
    return _sector_zero.Bpb.ReservedSectors;
}

INLINE
USHORT
REAL_FAT_SA::QueryFats(
    ) CONST
/*++

Routine Description:

    This routine computes the number of FATs on the volume.

Arguments:

    None.

Return Value:

    The number of FATs on the volume.

--*/
{
    return _sector_zero.Bpb.Fats;
}

INLINE
ULONG
REAL_FAT_SA::QueryRootEntries(
    ) CONST
/*++

Routine Description:

    This routine returns the number of entries in the root
    directory.

Arguments:

    None.

Return Value:

    The number of root directory entries.

--*/
{
    return _sector_zero.Bpb.RootEntries;
}


INLINE
PARTITION_SYSTEM_ID
REAL_FAT_SA::QuerySystemId(
    ) CONST
/*++

Routine Description:

    This routine computes the system ID for the volume.

Arguments:

    None.

Return Value:

    The system ID for the volume.

--*/
{
    return _sysid;
}


INLINE
LBN
REAL_FAT_SA::QueryStartDataLbn(
    ) CONST
/*++

Routine Description:

    This routine computes the LBN of the first logical cluster of the
    volume.

Arguments:

    None.

Return Value:

    The LBN of the first logical cluster of the volume.

--*/
{
    return _StartDataLbn;
}


INLINE
ULONG
REAL_FAT_SA::QueryClusterCount(
    ) CONST
/*++

Routine Description:

    This routine computes the total number of clusters for the volume.
    That is to say that the largest addressable cluster on the disk
    is cluster number 'QueryClusterCount() - 1'.  Note that the
    smallest addressable cluster on the disk is 2.

Arguments:

    None.

Return Value:

    The total number of clusters for the volume.

--*/
{
    return _ClusterCount;
}

INLINE BOOLEAN
REAL_FAT_SA::IsCompressed(
    ) CONST
/*++

Routine Description:

    This routine tells whether this volume is doublespaced or not.
    Since the class is REAL_FAT_SA, we know it's not.

Arguments:

Return Value:

    TRUE  -   Compressed.
    FALSE -   Not compressed.

--*/
{
    return FALSE;
}

INLINE BOOLEAN
REAL_FAT_SA::IsVolumeDataAligned(
    ) CONST
/*++

Routine Description:

    This routine tells whether the data clusters of this volume is
    aligned to FAT_FIRST_DATA_CLUSTER_ALIGNMENT boundary.

Arguments:

Return Value:

    TRUE  -   Aligned.
    FALSE -   Not aligned.

--*/
{
    return _data_aligned;
}

INLINE BOOLEAN
REAL_FAT_SA::ReadSectorZero(
    )
/*++

Routine Description:

    This routine used to be DOS_SUPERAREA::Read().

Arguments:

Return Value:

    TRUE  -   Success.
    FALSE -   Failure.

--*/
{
    BOOLEAN b;
    PEXTENDED_BIOS_PARAMETER_BLOCK Pbios;

    b = SECRUN::Read();
    if (!b)
        return FALSE;

    Pbios = (PEXTENDED_BIOS_PARAMETER_BLOCK)SECRUN::GetBuf();

    UnpackExtendedBios(&_sector_zero, Pbios);

    return TRUE;
}

INLINE
PBIOS_PARAMETER_BLOCK
REAL_FAT_SA::GetBpb(
    )
{
    return &(_sector_zero.Bpb);
}



INLINE
UCHAR
REAL_FAT_SA::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.Bpb.Media;
}

INLINE
VOID
REAL_FAT_SA::SetMediaByte(
    UCHAR   MediaByte
    )
/*++

Routine Description:

    This routine sets the media byte in the super area's data.

Arguments:

    MediaByte   --  Supplies the new media byte.

Return Value:

    None.

--*/
{
       _sector_zero.Bpb.Media = MediaByte;
}

INLINE
SECTORCOUNT
REAL_FAT_SA::QueryVirtualSectors(
    ) 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.Bpb.Sectors ? _sector_zero.Bpb.Sectors :
           _sector_zero.Bpb.LargeSectors;
}

INLINE
VOLID
REAL_FAT_SA::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
VOLID
REAL_FAT_SA::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
BOOLEAN
REAL_FAT_SA::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
VOID
REAL_FAT_SA::QueryGeometry(
    OUT PUSHORT SectorSize,
    OUT PUSHORT SectorsPerTrack,
    OUT PUSHORT Heads,
    OUT PULONG  HiddenSectors
    )
/*++

Routine Description:

    This method returns the geometry information stored in
    the Bios Parameter Block.

Arguments:

    SectorSize      --  Receives the recorded sector size.
    SectorsPerTrack --  Receives the recorded sectors per track.
    Heads           --  Receives the recorded number of heads.
    HiddenSectors   --  Receives the recorded number of hidden sectors.

Return Value:

    None.

--*/
{
    *SectorSize = _sector_zero.Bpb.BytesPerSector;
    *SectorsPerTrack = _sector_zero.Bpb.SectorsPerTrack;
    *Heads = _sector_zero.Bpb.Heads;
    *HiddenSectors = _sector_zero.Bpb.HiddenSectors;
}

INLINE
BOOLEAN
AllocateClusterData(
    ULONG Cluster,
    UCHAR NumSectors,
    BOOLEAN bCompressed,
    UCHAR PlainSize
    )
{
    DebugAbort("Didn't expect REAL_FAT_SA::AllocateClusterData() to be called");
    return FALSE;
}

//
// Defines for the volume flags in the BPB current head field.
//
#define FAT_BPB_RESERVED_DIRTY        0x01
#define FAT_BPB_RESERVED_TEST_SURFACE 0x02

//
// Defines for the volume flags in FAT[1].
//
#define CLUS1CLNSHUTDWNFAT16         0x00008000
#define CLUS1NOHRDERRFAT16           0x00004000

#define CLUS1CLNSHUTDWNFAT32         0x08000000
#define CLUS1NOHRDERRFAT32           0x04000000


#endif // REAL_FAT_SA_DEFN
