446 lines
10 KiB
C++
446 lines
10 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1996.
|
|
//
|
|
// File: difat.cxx
|
|
//
|
|
// Contents: Double Indirected Fat Code
|
|
//
|
|
// Classes: None.
|
|
//
|
|
// Functions:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "msfhead.cxx"
|
|
|
|
|
|
#include "h/difat.hxx"
|
|
#include "mread.hxx"
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CDIFat::CDIFat, public
|
|
//
|
|
// Synopsis: CDIFat constructor
|
|
//
|
|
// Arguments: [cbSector] -- size of a sector
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
CDIFat::CDIFat(USHORT cbSector)
|
|
: _pmsParent(NULL),
|
|
_fv( SIDDIF,
|
|
(FSOFFSET) (cbSector / sizeof(SECT)),
|
|
(FSOFFSET) ((cbSector / sizeof(SECT)) - 1) )
|
|
{
|
|
msfDebugOut((DEB_TRACE,"In CDIFat constructor\n"));
|
|
_cfsTable = 0;
|
|
msfDebugOut((DEB_TRACE,"Out CDIFat constructor\n"));
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CDIFat::Empty, public
|
|
//
|
|
// Synopsis: Empty all the control structures of this instance
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: void.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CDIFat::Empty(void)
|
|
{
|
|
_fv.Empty();
|
|
_pmsParent = NULL;
|
|
_cfsTable = 0;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CIDFat::Flush, private
|
|
//
|
|
// Synopsis: Flush a sector to disk
|
|
//
|
|
// Arguments: none
|
|
//
|
|
// Returns: S_OK if call completed OK.
|
|
//
|
|
// Algorithm: Write sector up to parent mstream.
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
SCODE CDIFat::Flush(void)
|
|
{
|
|
return _fv.Flush();
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CDIFat::GetFatSect, public
|
|
//
|
|
// Synopsis: Given an offset into the Fat chain, return the sector
|
|
// value for that FatSect.
|
|
//
|
|
// Arguments: [oSect] -- offset in Fat chain
|
|
// [psect] -- pointer to returned sector
|
|
//
|
|
// Modifies: [*psect]
|
|
//
|
|
// Returns: Sector value of FatSect.
|
|
//
|
|
// Algorithm: If sector is stored in the header, retrieve it from
|
|
// there.
|
|
// If not, retrieve it from the FatVector.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
SCODE CDIFat::GetFatSect(const FSINDEX oSect, SECT *psect)
|
|
{
|
|
SCODE sc = S_OK;
|
|
SECT sectReturn;
|
|
|
|
msfDebugOut((DEB_TRACE,"In CDIFat::GetFatSect(%lu)\n",oSect));
|
|
if (oSect < CSECTFAT)
|
|
{
|
|
msfDebugOut((DEB_ITRACE,"Getting sect from header\n"));
|
|
sectReturn = _pmsParent->GetHeader()->GetFatSect(oSect);
|
|
}
|
|
else
|
|
{
|
|
FSINDEX ipfs;
|
|
FSOFFSET isect;
|
|
|
|
SectToPair(oSect,&ipfs,&isect);
|
|
|
|
msfAssert(ipfs < _cfsTable);
|
|
|
|
CFatSect *pfs;
|
|
msfChk(_fv.GetTable(ipfs, FB_NONE, &pfs));
|
|
sectReturn = pfs->GetSect(isect);
|
|
_fv.ReleaseTable(ipfs);
|
|
}
|
|
|
|
msfDebugOut((DEB_TRACE,"Out CDIFat::GetFatSect(%lu)=>%lu\n",oSect,sectReturn));
|
|
*psect = sectReturn;
|
|
|
|
Err:
|
|
return sc;
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CDIFat::SetFatSect, public
|
|
//
|
|
// Synopsis: Given an offset into the Fat chain, set the sector
|
|
// value.
|
|
//
|
|
// Arguments: [oSect] -- Offset into fat chain
|
|
// [sect] -- New sector value for that offset.
|
|
//
|
|
// Returns: S_OK if call completed OK.
|
|
//
|
|
// Algorithm: If the sector is stored in the header, set it and
|
|
// flush the header.
|
|
// Otherwise, if the sector will not fit in the current
|
|
// CFatVector, resize it.
|
|
// Set the sector in the FatVector and flush it.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
SCODE CDIFat::SetFatSect(const FSINDEX oSect, const SECT sect)
|
|
{
|
|
msfDebugOut((DEB_TRACE,"In CDIFat::SetFatSect(%lu,%lu)\n",oSect,sect));
|
|
SCODE sc = S_OK;
|
|
|
|
if (oSect < CSECTFAT)
|
|
{
|
|
msfDebugOut((DEB_ITRACE,"Setting sect in header: %lu, %lu\n",oSect,sect));
|
|
_pmsParent->GetHeader()->SetFatSect(oSect, sect);
|
|
}
|
|
else
|
|
{
|
|
FSINDEX ipfs;
|
|
FSOFFSET isect;
|
|
|
|
SectToPair(oSect,&ipfs,&isect);
|
|
if (ipfs >= _cfsTable)
|
|
{
|
|
msfChk(Resize(_cfsTable + 1));
|
|
}
|
|
|
|
CFatSect *pfs;
|
|
msfChk(_fv.GetTable(ipfs, FB_DIRTY, &pfs));
|
|
|
|
pfs->SetSect(isect, sect);
|
|
_fv.ReleaseTable(ipfs);
|
|
|
|
msfDebugOut((DEB_TRACE,"In CDIFat::SetFatSect(%lu,%lu)\n",oSect,sect));
|
|
}
|
|
|
|
Err:
|
|
return sc;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CDIFat::GetSect, public
|
|
//
|
|
// Synopsis: Given an offset into the DIFat chain, return the
|
|
// sector value
|
|
//
|
|
// Arguments: [oSect] -- Offset into DIFat chain.
|
|
// [psect] -- pointer to returned sector
|
|
//
|
|
// Modifies: [*psect]
|
|
//
|
|
// Returns: Sector value for given offset.
|
|
//
|
|
// Algorithm: Retrieve the information from the NextFat fields of
|
|
// the CFatVector
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
SCODE CDIFat::GetSect(const FSINDEX oSect, SECT *psect)
|
|
{
|
|
SCODE sc = S_OK;
|
|
|
|
SECT sectReturn;
|
|
|
|
msfDebugOut((DEB_TRACE,"In CDIFat::GetSect(%lu)\n",oSect));
|
|
msfAssert(oSect < _cfsTable);
|
|
|
|
if (oSect == 0)
|
|
{
|
|
sectReturn = _pmsParent->GetHeader()->GetDifStart();
|
|
}
|
|
else
|
|
{
|
|
CFatSect *pfs;
|
|
msfChk(_fv.GetTable(oSect - 1, FB_NONE, &pfs));
|
|
|
|
sectReturn = pfs->GetNextFat(_fv.GetSectTable());
|
|
_fv.ReleaseTable(oSect - 1);
|
|
}
|
|
|
|
msfDebugOut((DEB_TRACE,"Out CDIFat::GetSect(%lu)=>%lu\n",oSect,sectReturn));
|
|
*psect = sectReturn;
|
|
|
|
Err:
|
|
return sc;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CDIFat::Init, public
|
|
//
|
|
// Synopsis: Init function for previously stored DIFat.
|
|
//
|
|
// Arguments: [pmsParent] -- pointer to stream parent
|
|
// [cFatSect] -- Length of DIFat in sectors
|
|
//
|
|
// Returns: S_OK if call completed properly.
|
|
//
|
|
// Algorithm: Initialize all the variables
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
SCODE CDIFat::Init(CMStream * pmsParent, const FSINDEX cFatSect)
|
|
{
|
|
msfDebugOut((DEB_TRACE,"In CDIFat::Init(%lu)\n",cFatSect));
|
|
SCODE sc;
|
|
|
|
_pmsParent = pmsParent;
|
|
|
|
msfChk(_fv.Init(_pmsParent, cFatSect));
|
|
|
|
_cfsTable = cFatSect;
|
|
|
|
msfDebugOut((DEB_TRACE,"Out CDIFat::Init(%lu)\n",cFatSect));
|
|
|
|
Err:
|
|
return sc;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CDIFat::InitConvert, public
|
|
//
|
|
// Synopsis: Init function for conversion
|
|
//
|
|
// Arguments: [pmsParent] -- pointer to stream parent
|
|
// [sectMax] -- Last used sector in existing file
|
|
//
|
|
// Returns: S_OK if call completed OK.
|
|
//
|
|
// Algorithm: See below
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
SCODE CDIFat::InitConvert(CMStream *pmsParent, SECT sectMax)
|
|
{
|
|
msfDebugOut((DEB_TRACE,"In CDIFat::InitConvert(%lu)\n",sectMax));
|
|
SCODE sc;
|
|
|
|
_pmsParent = pmsParent;
|
|
|
|
USHORT cbSector = _pmsParent->GetSectorSize();
|
|
FSOFFSET csectPer = (FSOFFSET) (cbSector / sizeof(SECT));
|
|
|
|
FSINDEX csectFat = 0;
|
|
FSINDEX csectFatLast;
|
|
|
|
FSINDEX csectDif = 0;
|
|
FSINDEX csectDifLast;
|
|
do
|
|
{
|
|
//Number of fat sectors needed to represent:
|
|
// Number of Data Sectors (sectMax) +
|
|
// Number of Fat Sectors (csectFat) +
|
|
// Number of DIF sectors (csectDif) +
|
|
// Number of Directory Sectors (1)
|
|
|
|
//We must use a loop here, since the fat must be large
|
|
// enough to represent itself and the DIFat. See
|
|
// CFat::InitConvert for a more lengthy discussion of
|
|
// this method.
|
|
|
|
csectFatLast = csectFat;
|
|
|
|
csectFat = (sectMax + csectFatLast + csectDif + 1 + csectPer - 1) /
|
|
csectPer;
|
|
|
|
csectDifLast = csectDif;
|
|
|
|
if (csectFat < CSECTFAT)
|
|
{
|
|
csectDif = 0;
|
|
}
|
|
else
|
|
{
|
|
FSOFFSET ciSect;
|
|
|
|
SectToPair(csectFat, &csectDif, &ciSect);
|
|
csectDif++;
|
|
}
|
|
}
|
|
while ((csectDif != csectDifLast) || (csectFat != csectFatLast));
|
|
|
|
|
|
_cfsTable = csectDif;
|
|
|
|
msfChk(_fv.Init(_pmsParent, _cfsTable));
|
|
|
|
_pmsParent->GetHeader()->SetDifLength(_cfsTable);
|
|
|
|
if (_cfsTable > 0)
|
|
{
|
|
_pmsParent->GetHeader()->SetDifStart(sectMax);
|
|
|
|
FSINDEX i;
|
|
for (i = 0; i < _cfsTable; i++)
|
|
{
|
|
CFatSect *pfs;
|
|
|
|
msfChk(_fv.GetTable(i, FB_NEW, &pfs));
|
|
_fv.SetSect(i, sectMax);
|
|
|
|
sectMax++;
|
|
pfs->SetNextFat(_fv.GetSectTable(),sectMax);
|
|
_fv.ReleaseTable(i);
|
|
}
|
|
}
|
|
|
|
msfDebugOut((DEB_TRACE,"Out CDIFat::InitConvert()\n"));
|
|
|
|
Err:
|
|
return sc;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CDIFat::Resize, private
|
|
//
|
|
// Synopsis: Resize an existing DIFat.
|
|
//
|
|
// Arguments: [fsiSize] -- New size for object
|
|
//
|
|
// Returns: S_OK if success
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
SCODE CDIFat::Resize(FSINDEX fsiSize)
|
|
{
|
|
msfDebugOut((DEB_TRACE,"In CDIFat::Resize(%lu)\n",fsiSize));
|
|
msfAssert(fsiSize == _cfsTable + 1);
|
|
|
|
SCODE sc;
|
|
|
|
msfChk(_fv.Resize(fsiSize));
|
|
ULONG ipfs;
|
|
ipfs = fsiSize - 1;
|
|
|
|
CFatSect *pfs;
|
|
msfChk(_fv.GetTable(ipfs, FB_NEW, &pfs));
|
|
|
|
FSINDEX csect;
|
|
csect = _cfsTable;
|
|
_cfsTable = fsiSize;
|
|
|
|
SECT sectNew;
|
|
|
|
msfChk(_pmsParent->GetFat()->GetFree(1, §New));
|
|
msfChk(_pmsParent->GetFat()->SetNext(sectNew, DIFSECT));
|
|
|
|
_fv.SetSect(ipfs, sectNew);
|
|
_fv.ReleaseTable(ipfs);
|
|
|
|
if (csect == 0)
|
|
{
|
|
_pmsParent->GetHeader()->SetDifStart(sectNew);
|
|
}
|
|
else
|
|
{
|
|
CFatSect *pfs;
|
|
msfChk(_fv.GetTable(csect - 1, FB_DIRTY, &pfs));
|
|
|
|
pfs->SetNextFat(_fv.GetSectTable(),sectNew);
|
|
_fv.ReleaseTable(csect - 1);
|
|
}
|
|
|
|
_pmsParent->GetHeader()->SetDifLength(_cfsTable);
|
|
|
|
msfDebugOut((DEB_TRACE,"Out CDIFat::Resize(%lu)\n",fsiSize));
|
|
|
|
Err:
|
|
return sc;
|
|
}
|
|
|
|
|
|
|
|
|