1199 lines
33 KiB
C++
1199 lines
33 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1996.
|
|
//
|
|
// File: layout.cxx
|
|
//
|
|
// Contents: Code for the relayout tool
|
|
//
|
|
// Classes:
|
|
//
|
|
// Functions:
|
|
//
|
|
// History: 12-Feb-96 PhilipLa Created
|
|
// 21-Feb-96 SusiA Put funtions on ILayoutStorage
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "layouthd.cxx"
|
|
#pragma hdrstop
|
|
|
|
#include <dirfunc.hxx>
|
|
#include "laylkb.hxx"
|
|
#include "laywrap.hxx"
|
|
|
|
#include <stddef.h>
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CLayoutRootStorage::LayoutScript
|
|
//
|
|
// Synopsis: Construct an unprocessed script from an app provided script
|
|
//
|
|
// Arguments: [pStorageLayout] -- Pointer to storage layout array
|
|
// [nEntries] -- Number of entries in the array
|
|
// [grfInterleavedFlag] -- Specifies disposition of control
|
|
// structures
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 21-Feb-96 SusiA Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CLayoutRootStorage::LayoutScript( StorageLayout *pStorageLayout,
|
|
DWORD nEntries,
|
|
DWORD glfInterleavedFlag)
|
|
{
|
|
|
|
SCODE sc;
|
|
|
|
if ((LONG)nEntries < 0)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if ((LONG)nEntries == 0)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
if ((glfInterleavedFlag != STG_LAYOUT_INTERLEAVED) &&
|
|
(glfInterleavedFlag != STG_LAYOUT_SEQUENTIAL ) )
|
|
{
|
|
return STG_E_INVALIDFLAG;
|
|
}
|
|
|
|
if (IsBadWritePtr( pStorageLayout, nEntries * sizeof(StorageLayout)))
|
|
{
|
|
return STG_E_INVALIDPOINTER;
|
|
}
|
|
|
|
if (FAILED(sc = BeginMonitor()))
|
|
{
|
|
return sc;
|
|
}
|
|
|
|
if (FAILED(sc = ProcessLayout(pStorageLayout,
|
|
nEntries,
|
|
glfInterleavedFlag)))
|
|
{
|
|
// ignore errors from EndMonitor
|
|
EndMonitor();
|
|
return sc;
|
|
}
|
|
|
|
if (FAILED(sc = EndMonitor()))
|
|
{
|
|
return sc;
|
|
}
|
|
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CLayoutRootStorage::BeginMonitor
|
|
//
|
|
// Synopsis: Begin monitoring the ILockBytes operations for recording a
|
|
// script.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 21-Feb-96 SusiA Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CLayoutRootStorage::BeginMonitor(void)
|
|
{
|
|
SCODE sc = S_OK;
|
|
sc = _pllkb->StartLogging();
|
|
return ResultFromScode(sc);
|
|
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CLayoutRootStorage::EndMonitor
|
|
//
|
|
// Synopsis: Stop monitoring ILockBytes operations for script recording.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 21-Feb-96 SusiA Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CLayoutRootStorage::EndMonitor(void)
|
|
{
|
|
SCODE sc = S_OK;
|
|
sc = _pllkb->StopLogging();
|
|
return ResultFromScode(sc);
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CLayoutRootStorage::ReLayoutDocfile
|
|
//
|
|
// Synopsis: Relayout the docfile into the new name specified.
|
|
//
|
|
// Arguments: [pwcsNewName] -- Name of destination file
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 13-Feb-96 PhilipLa Created
|
|
// 21-Feb-96 SusiA Made a method on ILayoutStorage
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CLayoutRootStorage::ReLayoutDocfile(OLECHAR *pwcsNewDfName)
|
|
{
|
|
SCODE sc;
|
|
|
|
#if (!defined(UNICODE) && (!defined(_MAC)))
|
|
|
|
WCHAR awcScriptName[MAX_PATH + 1];
|
|
|
|
|
|
UINT uCodePage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
|
|
|
|
if (!MultiByteToWideChar(
|
|
uCodePage,
|
|
0,
|
|
_pllkb->GetScriptName(),
|
|
-1,
|
|
awcScriptName,
|
|
MAX_PATH + 1
|
|
))
|
|
{
|
|
return STG_E_INVALIDNAME;
|
|
}
|
|
sc = StgLayoutDocfile(_pllkb->GetHandle(),
|
|
pwcsNewDfName,
|
|
awcScriptName);
|
|
#else
|
|
|
|
|
|
sc = StgLayoutDocfile(_pllkb->GetHandle(),
|
|
pwcsNewDfName,
|
|
_pllkb->GetScriptName());
|
|
#endif //UNICODE
|
|
|
|
if (FAILED(sc))
|
|
{
|
|
//Delete new file
|
|
#ifdef UNICODE
|
|
DeleteFileW(pwcsNewDfName);
|
|
#elif defined( _MAC)
|
|
DeleteFile(pwcsNewDfName);
|
|
#else
|
|
|
|
TCHAR atcPath[MAX_PATH + 1];
|
|
|
|
UINT uCodePage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
|
|
|
|
//Note: Intentionally ignore an error if it happens here. We
|
|
// want to return the error from StgLayoutDocfile, not from
|
|
// the cleanup path.
|
|
WideCharToMultiByte(
|
|
uCodePage,
|
|
0,
|
|
pwcsNewDfName,
|
|
-1,
|
|
atcPath,
|
|
_MAX_PATH + 1,
|
|
NULL,
|
|
NULL);
|
|
DeleteFileA(atcPath);
|
|
|
|
#endif // UNICODE
|
|
}
|
|
else
|
|
{
|
|
//Delete Script File
|
|
DeleteFile(_pllkb->GetScriptName());
|
|
//Note: Intentionally ignore an error if it happens here. We
|
|
// want to return the error from StgLayoutDocfile, not from
|
|
// the cleanup path.
|
|
_pllkb->ClearScriptName();
|
|
|
|
}
|
|
return sc;
|
|
}
|
|
|
|
#if DBG == 1
|
|
STDMETHODIMP CLayoutRootStorage::GetScript(TCHAR **ptcsScriptFileName)
|
|
{
|
|
|
|
*ptcsScriptFileName = _pllkb->GetScriptName();
|
|
return S_OK;
|
|
}
|
|
#endif
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CLayoutRootStorage::ReLayoutDocfileOnILockBytes
|
|
//
|
|
// Synopsis: Relayout the docfile into a generic ILockBytes implementation.
|
|
//
|
|
// Arguments: [pILockBytes] -- destination relayout ILockBytes
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 09-Jun-96 SusiA Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP CLayoutRootStorage::ReLayoutDocfileOnILockBytes(ILockBytes *pILockBytes)
|
|
{
|
|
return STG_E_UNIMPLEMENTEDFUNCTION;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: StgLayoutDocfile
|
|
//
|
|
// Synopsis: Given an old file and an unprocessed script, relayout the
|
|
// docfile into the new name specified.
|
|
//
|
|
// Arguments: [hOld] -- Handle of source file
|
|
// [pwcsNewDfName] -- Name of destination file
|
|
// [pwcsScriptName] -- Name of unprocessed script file
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 13-Feb-96 PhilipLa Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE StgLayoutDocfile(HANDLE hOld,
|
|
OLECHAR const *pwcsNewDfName,
|
|
OLECHAR const *pwcsScriptName)
|
|
{
|
|
SCODE sc = S_OK;
|
|
CMappedFile mfOld, mfNew, mfScript;
|
|
MAPFILE *pvOld, *pvNew, *pvScript;
|
|
ULONG ulScriptSize;
|
|
ULONG csectScript, csectProcessed, csectFile;
|
|
ULONG cbSectorSize;
|
|
ULONG i;
|
|
|
|
SECT *psProcessedScript = NULL;
|
|
|
|
if (pwcsNewDfName == NULL)
|
|
return STG_E_INVALIDNAME;
|
|
|
|
#ifdef _MAC
|
|
layChkTo(EH_End, mfOld.InitFromHandle(hOld,
|
|
GENERIC_READ,
|
|
FALSE,
|
|
NULL));
|
|
#else
|
|
layChkTo(EH_End, mfOld.InitFromHandle(hOld,
|
|
GENERIC_READ,
|
|
TRUE,
|
|
NULL));
|
|
#endif
|
|
layChkTo(EH_End, mfNew.Init(pwcsNewDfName,
|
|
mfOld.GetSize(),
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
CREATE_ALWAYS,
|
|
NULL));
|
|
|
|
|
|
if ((pwcsScriptName !=NULL) &&
|
|
(pwcsScriptName[0] != TEXT('\0')) )
|
|
{
|
|
sc = mfScript.Init(pwcsScriptName,
|
|
0,
|
|
GENERIC_READ,
|
|
OPEN_EXISTING,
|
|
NULL);
|
|
layChkTo(EH_End, sc);
|
|
|
|
if (sc == STG_S_FILEEMPTY)
|
|
{
|
|
pvScript = NULL;
|
|
}
|
|
else
|
|
{
|
|
pvScript = &mfScript;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pvScript = NULL;
|
|
}
|
|
|
|
pvOld = &mfOld;
|
|
pvNew = &mfNew;
|
|
|
|
|
|
//From this point on, we may get an exception while we're poking around
|
|
// in one of the memory maps. We need to handle this case and be able
|
|
// to properly return an error and clean up if it happens.
|
|
|
|
#ifndef _MAC
|
|
__try
|
|
{
|
|
#endif
|
|
//Figure out how many sectors are in the file
|
|
cbSectorSize = 1 << pvOld->GetUSHORT(
|
|
(ULONG) offsetof(CMSFHeaderData,_uSectorShift));
|
|
pvOld->SetSectorSize(cbSectorSize);
|
|
pvNew->SetSectorSize(cbSectorSize);
|
|
|
|
const ULONG cbHeader = cbSectorSize;
|
|
csectFile = (mfOld.GetSize() + cbSectorSize - 1 -
|
|
cbHeader) / cbSectorSize;
|
|
|
|
SECT sectRangeLocks = (OLOCKREGIONEND - cbHeader + cbSectorSize - 1)
|
|
/ cbSectorSize;
|
|
|
|
if (pvScript)
|
|
{
|
|
ulScriptSize = mfScript.GetSize();
|
|
}
|
|
else
|
|
{
|
|
ulScriptSize = 0;
|
|
}
|
|
|
|
csectProcessed = max(ulScriptSize / sizeof(SECT), csectFile);
|
|
layMem(psProcessedScript = new SECT[csectProcessed]);
|
|
|
|
for (i = 0; i < csectProcessed; i++)
|
|
{
|
|
psProcessedScript[i] = ENDOFCHAIN;
|
|
}
|
|
|
|
ULONG csectControl;
|
|
layChk(ProcessControl(psProcessedScript,
|
|
pvOld,
|
|
&csectControl));
|
|
|
|
layChk(ProcessScript(psProcessedScript,
|
|
pvScript,
|
|
csectFile,
|
|
ulScriptSize / sizeof(SECT),
|
|
csectControl,
|
|
sectRangeLocks,
|
|
&csectScript));
|
|
|
|
//layAssert(csectScript == csectFile);
|
|
|
|
layChk(CopyData(pvNew,
|
|
pvOld,
|
|
psProcessedScript,
|
|
csectFile,
|
|
cbSectorSize));
|
|
|
|
layChk(RemapHeader(pvNew, psProcessedScript, csectFile));
|
|
layChk(RemapDIF(pvNew, psProcessedScript, csectFile, cbSectorSize));
|
|
layChk(RemapFat(pvNew,
|
|
pvOld,
|
|
psProcessedScript,
|
|
csectFile,
|
|
cbSectorSize));
|
|
layChk(RemapDirectory(pvNew,
|
|
psProcessedScript,
|
|
csectFile,
|
|
cbSectorSize));
|
|
Err:
|
|
delete psProcessedScript;
|
|
|
|
#ifndef _MAC
|
|
}
|
|
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
sc = LAST_STG_SCODE;
|
|
}
|
|
#endif
|
|
|
|
pvOld = NULL;
|
|
pvNew = NULL;
|
|
|
|
|
|
EH_End:
|
|
return sc;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: GetDIFSect
|
|
//
|
|
// Synopsis: Return a pointer to the appropriate sector in the DIF
|
|
//
|
|
// Arguments: [pvBase] -- Pointer to base address of memory mapped file
|
|
// [iDIF] -- Index into DIF desired
|
|
// [cbSectorSize] -- Size in bytes of sector
|
|
//
|
|
// Returns: Pointer to appropriate sector
|
|
//
|
|
// History: 13-Feb-96 PhilipLa Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CFatSect * GetDIFSect(MAPFILE *pvBase,
|
|
ULONG iDIF,
|
|
ULONG cbSectorSize,
|
|
SECT *psect)
|
|
{
|
|
USHORT cSectPerFat = (USHORT)(cbSectorSize / sizeof(SECT));
|
|
SECT sectDif = pvBase->GetULONG(
|
|
(ULONG) offsetof(CMSFHeaderData,_sectDifStart));
|
|
|
|
|
|
for (ULONG i = 0; i < iDIF; i++)
|
|
{
|
|
CFatSect *pdif = pvBase->GetCFatSect((sectDif * cbSectorSize) +
|
|
cbSectorSize);
|
|
|
|
sectDif = pdif->GetSect(cSectPerFat - 1);
|
|
|
|
pvBase->Remove(pdif);
|
|
}
|
|
|
|
if (psect)
|
|
{
|
|
*psect = sectDif;
|
|
}
|
|
return pvBase->GetCFatSect((sectDif * cbSectorSize) +
|
|
cbSectorSize);
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: GetFatSect
|
|
//
|
|
// Synopsis: Return a pointer to the appropriate sector in the fat
|
|
//
|
|
// Arguments: [pvBase] -- Pointer to base address of memory mapped file
|
|
// [iFat] -- Index into fat desired
|
|
// [cbSectorSize] -- Size in bytes of sector
|
|
//
|
|
// Returns: Pointer to appropriate sector
|
|
//
|
|
// History: 13-Feb-96 PhilipLa Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CFatSect *GetFatSect(MAPFILE *pvBase,
|
|
ULONG iFat,
|
|
ULONG cbSectorSize,
|
|
SECT *psect)
|
|
{
|
|
SECT sectFat;
|
|
|
|
if (iFat < CSECTFAT)
|
|
{
|
|
//Fatsect can be found in header
|
|
sectFat = pvBase->GetULONG(
|
|
(ULONG) offsetof(CMSFHeaderData,_sectFat[iFat]));
|
|
}
|
|
else
|
|
{
|
|
ULONG cFatPerDif = (cbSectorSize / sizeof(SECT)) - 1;
|
|
ULONG iDIF = (iFat - CSECTFAT) / cFatPerDif;
|
|
USHORT oDIF = (USHORT)((iFat - CSECTFAT) % cFatPerDif);
|
|
CFatSect *pDif = GetDIFSect(pvBase, iDIF, cbSectorSize, NULL);
|
|
sectFat = pDif->GetSect(oDIF);
|
|
|
|
pvBase->Remove(pDif);
|
|
}
|
|
|
|
CFatSect *pbFat = pvBase->GetCFatSect(
|
|
(sectFat * cbSectorSize) + cbSectorSize);
|
|
|
|
if (psect)
|
|
{
|
|
*psect = sectFat;
|
|
}
|
|
return (CFatSect *)pbFat;
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: GetNext
|
|
//
|
|
// Synopsis: Given a sector, return the next sector in the fat chain
|
|
//
|
|
// Arguments: [pvBase] -- Pointer to base address of memory mapped file
|
|
// [sect] -- Sect desired
|
|
// [cbSectorSize] -- Sector size in bytes
|
|
//
|
|
// Returns: Appropriate SECT value
|
|
//
|
|
// History: 13-Feb-96 PhilipLa Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SECT GetNext(MAPFILE *pvBase,
|
|
SECT sect,
|
|
ULONG cbSectorSize)
|
|
{
|
|
SECT newsect;
|
|
|
|
ULONG csectPerFat = cbSectorSize / sizeof(SECT);
|
|
ULONG iFat = sect / csectPerFat;
|
|
USHORT oFat = (USHORT)(sect % csectPerFat);
|
|
CFatSect *pfs = GetFatSect(pvBase, iFat, cbSectorSize, NULL);
|
|
|
|
newsect = pfs->GetSect(oFat);
|
|
|
|
pvBase->Remove(pfs);
|
|
|
|
return newsect;
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: ProcessControl, private
|
|
//
|
|
// Synopsis: Add control structures to processed script
|
|
//
|
|
// Arguments: [psProcessed] -- Pointer to processed script
|
|
// [pvOld] -- Pointer to old file
|
|
// [pcsectControl] -- Return location for total sectors processed
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 05-Mar-96 PhilipLa Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE ProcessControl(SECT *psProcessed,
|
|
MAPFILE *pvOld,
|
|
ULONG *pcsectControl)
|
|
{
|
|
SECT sectCurrent = 0;
|
|
CMSFHeaderData *phdr = (CMSFHeaderData *)pvOld->GetCMSFHeaderData();
|
|
|
|
ULONG csectDif, csectFat;
|
|
ULONG cbSectorSize;
|
|
|
|
csectDif = phdr->_csectDif;
|
|
csectFat = phdr->_csectFat;
|
|
cbSectorSize = 1 << phdr->_uSectorShift;
|
|
|
|
//We want the structures in the following order:
|
|
//1) Enough fat and DIFat sectors to hold themselves and all of the
|
|
// directory sectors.
|
|
//2) All of the directory sectors
|
|
//3) Everything else - the rest of the difat, the fat, and the minifat.
|
|
|
|
//First find out how big the directory is
|
|
SECT sectDir = phdr->_sectDirStart;
|
|
ULONG csectDir = 0;
|
|
while (sectDir != ENDOFCHAIN)
|
|
{
|
|
sectDir = GetNext(pvOld, sectDir, cbSectorSize);
|
|
csectDir++;
|
|
}
|
|
|
|
//Now compute the number of fat sectors we need to hold the directory
|
|
// plus the fat sectors themselves.
|
|
ULONG csectFatNeeded = 0;
|
|
ULONG csectDifNeeded = 0;
|
|
ULONG csectNeededLast = 0;
|
|
ULONG cfsSect = (cbSectorSize / sizeof(SECT));
|
|
|
|
do
|
|
{
|
|
csectNeededLast = csectFatNeeded;
|
|
csectFatNeeded = (csectFatNeeded + csectDifNeeded + csectDir +
|
|
cfsSect - 1) /
|
|
cfsSect;
|
|
if (csectFatNeeded > CSECTFAT)
|
|
{
|
|
csectDifNeeded = (csectFatNeeded - CSECTFAT + cfsSect - 2) /
|
|
(cfsSect - 1);
|
|
}
|
|
}
|
|
while (csectFatNeeded != csectNeededLast);
|
|
|
|
//Now we know how many DIF, Fat, and Directory sectors we need.
|
|
//Lay those out first.
|
|
|
|
//For those of you keeping score, the docfile will need to have exactly
|
|
// csectFatNeeded + csectDifNeeded sectors downloaded before it can
|
|
// be opened.
|
|
for (ULONG i = 0; i < csectDifNeeded; i++)
|
|
{
|
|
SECT sectDif;
|
|
pvOld->Remove(GetDIFSect(pvOld, i, cbSectorSize, §Dif));
|
|
psProcessed[sectDif] = sectCurrent++;
|
|
}
|
|
|
|
for (i = 0; i < csectFatNeeded; i++)
|
|
{
|
|
SECT sectFat;
|
|
|
|
pvOld->Remove(GetFatSect(pvOld, i, cbSectorSize, §Fat));
|
|
psProcessed[sectFat] = sectCurrent++;
|
|
}
|
|
sectDir = phdr->_sectDirStart;
|
|
for (i = 0; i < csectDir; i++)
|
|
{
|
|
layAssert(sectDir != ENDOFCHAIN);
|
|
psProcessed[sectDir] = sectCurrent++;
|
|
sectDir = GetNext(pvOld, sectDir, cbSectorSize);
|
|
}
|
|
|
|
//Now put down everything else
|
|
for (i = csectDifNeeded; i < csectDif; i++)
|
|
{
|
|
SECT sectDif;
|
|
|
|
GetDIFSect(pvOld, i, cbSectorSize, §Dif);
|
|
pvOld->Remove(GetDIFSect(pvOld, i, cbSectorSize, §Dif));
|
|
psProcessed[sectDif] = sectCurrent++;
|
|
}
|
|
for (i = csectFatNeeded; i < csectFat; i++)
|
|
{
|
|
SECT sectFat;
|
|
pvOld->Remove(GetFatSect(pvOld, i, cbSectorSize, §Fat));
|
|
psProcessed[sectFat] = sectCurrent++;
|
|
}
|
|
//Finally minifat
|
|
SECT sectMiniFat = phdr->_sectMiniFatStart;
|
|
while (sectMiniFat != ENDOFCHAIN)
|
|
{
|
|
psProcessed[sectMiniFat] = sectCurrent++;
|
|
sectMiniFat = GetNext(pvOld, sectMiniFat, cbSectorSize);
|
|
}
|
|
|
|
*pcsectControl = sectCurrent;
|
|
|
|
pvOld->Remove(phdr);
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: ProcessScript
|
|
//
|
|
// Synopsis: Given a list of sectors in order, construct a mapping
|
|
// of old sector->new sector
|
|
//
|
|
// Arguments: [psProcessed] -- Pointer to destination buffer
|
|
// [psOriginal] -- Pointer to source script buffer
|
|
// [csectFile] -- Count of sectors in file
|
|
// [csectOriginal] -- Count of entries in original script
|
|
// [sectRangeLocks] -- sector containing docfile range locks
|
|
// [pcsectProcessed] -- Return location for number of entries
|
|
// in processed script
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 13-Feb-96 PhilipLa Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE ProcessScript(SECT *psProcessed,
|
|
MAPFILE *psOriginal,
|
|
ULONG csectFile,
|
|
ULONG csectOriginal,
|
|
ULONG csectControl,
|
|
SECT sectRangeLocks,
|
|
ULONG *pcsectProcessed)
|
|
{
|
|
SCODE sc = S_OK;
|
|
#if DBG == 1
|
|
ULONG csectProcessed = 0;
|
|
#endif
|
|
ULONG cDuplicates = 0;
|
|
ULONG cUnlisted = 0;
|
|
|
|
for (ULONG i = 0; i < csectOriginal; i++)
|
|
{
|
|
SECT sectOld = (*psOriginal)[i];
|
|
|
|
if (sectOld >= csectFile)
|
|
{
|
|
//Weird. We're past the range of the file.
|
|
return STG_E_UNKNOWN;
|
|
}
|
|
|
|
#if DBG == 1
|
|
if (sectOld + 1> csectProcessed)
|
|
{
|
|
csectProcessed = sectOld + 1;
|
|
}
|
|
#endif
|
|
|
|
if (psProcessed[sectOld] == ENDOFCHAIN)
|
|
{
|
|
psProcessed[sectOld] = i - cDuplicates + csectControl;
|
|
}
|
|
else
|
|
{
|
|
cDuplicates++;
|
|
}
|
|
}
|
|
|
|
|
|
//Fill in holes
|
|
for (i = 0; i < csectFile; i++)
|
|
{
|
|
if (psProcessed[i] == ENDOFCHAIN)
|
|
{
|
|
SECT sectNew = csectOriginal - cDuplicates + csectControl +
|
|
cUnlisted;
|
|
if (sectNew == sectRangeLocks) // skip over range locks
|
|
{
|
|
sectNew++;
|
|
cUnlisted++;
|
|
}
|
|
psProcessed[i] = sectNew;
|
|
cUnlisted++;
|
|
#if DBG == 1
|
|
if (sectNew + 1> csectProcessed)
|
|
{
|
|
csectProcessed = sectNew + 1;
|
|
}
|
|
#endif
|
|
}
|
|
#if DBG == 1
|
|
//If we have control structures at the end of the file that are
|
|
// not in the script anywhere (which may happen particularly often
|
|
// on files produced with simple mode), we want to make sure to
|
|
// update the count on those. For retail builds, we don't really
|
|
// care about the count, so we can skip this.
|
|
else if (psProcessed[i] + 1 > csectProcessed)
|
|
{
|
|
csectProcessed = psProcessed[i] + 1;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if DBG == 1
|
|
for (i = 0; i < csectProcessed; i++)
|
|
{
|
|
layDebugOut((DEB_IERROR, "Script[%lu] = %lx\n", i, psProcessed[i]));
|
|
}
|
|
#endif
|
|
|
|
#if DBG == 1
|
|
*pcsectProcessed = csectProcessed;
|
|
#else
|
|
*pcsectProcessed = csectFile;
|
|
#endif
|
|
|
|
return sc;
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: CopyData
|
|
//
|
|
// Synopsis: Given an old->new mapping, copy data from old mapping to
|
|
// new mapping
|
|
//
|
|
// Arguments: [pvNew] -- Pointer to destination mapped file
|
|
// [pvOld] -- Pointer to source mapped file
|
|
// [psScript] -- Pointer to processed script
|
|
// [csectFile] -- Count of sectors in the file
|
|
// [cbSectorSize] -- Sector size in bytes
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 13-Feb-96 PhilipLa Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE CopyData(MAPFILE *pvNew,
|
|
MAPFILE *pvOld,
|
|
SECT *psScript,
|
|
ULONG csectFile,
|
|
ULONG cbSectorSize)
|
|
{
|
|
SCODE sc = S_OK;
|
|
|
|
#ifdef SUPPORT_FILE_MAPPING
|
|
BYTE *pbSrc, *pbDest;
|
|
|
|
pbSrc = (BYTE *)(pvOld->GetBaseAddress());
|
|
pbDest = (BYTE *)(pvNew->GetBaseAddress());
|
|
#endif
|
|
|
|
for (ULONG i = 0; i < csectFile; i++)
|
|
{
|
|
#ifdef SUPPORT_FILE_MAPPING
|
|
|
|
BYTE *pbSrcStart = (BYTE *)pbSrc + (i * cbSectorSize) +
|
|
cbSectorSize;
|
|
BYTE *pbDestStart = (BYTE *)pbDest + (psScript[i] * cbSectorSize) +
|
|
cbSectorSize;
|
|
|
|
if ((pbSrc != NULL) && pbDest != NULL)
|
|
{
|
|
CopyMemory(pbDestStart, pbSrcStart, cbSectorSize);
|
|
}
|
|
else
|
|
#endif // SUPPORT_FILE_MAPPING
|
|
{
|
|
BYTE *pbBuffer = (BYTE *) CoTaskMemAlloc(cbSectorSize);
|
|
|
|
if (!pbBuffer)
|
|
{
|
|
return STG_E_INSUFFICIENTMEMORY;
|
|
}
|
|
|
|
if (S_OK == (sc = pvOld->ReadFromFile(pbBuffer,
|
|
(i * cbSectorSize) +
|
|
cbSectorSize,
|
|
cbSectorSize )))
|
|
{
|
|
sc = pvNew->WriteToFile(pbBuffer,
|
|
(psScript[i] * cbSectorSize) +
|
|
cbSectorSize,
|
|
cbSectorSize );
|
|
}
|
|
|
|
|
|
CoTaskMemFree(pbBuffer);
|
|
|
|
if (S_OK != sc)
|
|
{
|
|
return sc;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
//Also the header.
|
|
#ifdef SUPPORT_FILE_MAPPING
|
|
|
|
if ((pbSrc != NULL) && (pbDest != NULL))
|
|
{
|
|
CopyMemory(pbDest, pbSrc, sizeof(CMSFHeaderData));
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
|
|
BYTE *pbBuffer = (BYTE *) CoTaskMemAlloc(sizeof(CMSFHeaderData));
|
|
|
|
if (!pbBuffer)
|
|
{
|
|
return STG_E_INSUFFICIENTMEMORY;
|
|
}
|
|
|
|
if (S_OK == (sc = pvOld->ReadFromFile( pbBuffer,
|
|
0,
|
|
sizeof(CMSFHeaderData) )))
|
|
{
|
|
sc = pvNew->WriteToFile( pbBuffer,
|
|
0,
|
|
sizeof(CMSFHeaderData) );
|
|
}
|
|
|
|
|
|
|
|
CoTaskMemFree(pbBuffer);
|
|
|
|
if (S_OK != sc)
|
|
{
|
|
return sc;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: RemapHeader
|
|
//
|
|
// Synopsis: Remap the docfile header using a processed script
|
|
//
|
|
// Arguments: [pvNew] -- Pointer to base of memory mapped file
|
|
// [psScript] -- Pointer to processed script
|
|
// [csectFile] -- Count of sectors in file
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 13-Feb-96 PhilipLa Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE RemapHeader(MAPFILE *pvNew, SECT *psScript, ULONG csectFile)
|
|
{
|
|
|
|
SCODE sc = S_OK;
|
|
|
|
CMSFHeaderData *ph = (CMSFHeaderData *)pvNew->GetCMSFHeaderData();
|
|
|
|
//Directory start will never be EOC
|
|
|
|
ph->_sectDirStart = psScript[ph->_sectDirStart];
|
|
|
|
if (ph->_sectMiniFatStart != ENDOFCHAIN)
|
|
ph->_sectMiniFatStart = psScript[ph->_sectMiniFatStart];
|
|
|
|
if (ph->_sectDifStart != ENDOFCHAIN)
|
|
ph->_sectDifStart = psScript[ph->_sectDifStart];
|
|
|
|
for (ULONG i = 0; i < CSECTFAT; i++)
|
|
{
|
|
if (ph->_sectFat[i] != FREESECT)
|
|
{
|
|
ph->_sectFat[i] = psScript[ph->_sectFat[i]];
|
|
}
|
|
}
|
|
|
|
sc = pvNew->WriteToFile(ph);
|
|
pvNew->Remove(ph);
|
|
|
|
return sc;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: RemapDIF
|
|
//
|
|
// Synopsis: Remap the DIF according to a processed script
|
|
//
|
|
// Arguments: [pvNew] -- Pointer to base of memory mapped file
|
|
// [psScript] -- Pointer to processed script
|
|
// [csectFile] -- Count of sectors in file
|
|
// [cbSectorSize] -- Sector size in bytes
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 13-Feb-96 PhilipLa Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE RemapDIF(MAPFILE *pvNew,
|
|
SECT *psScript,
|
|
ULONG csectFile,
|
|
ULONG cbSectorSize)
|
|
{
|
|
CMSFHeaderData *ph = (CMSFHeaderData *)pvNew->GetCMSFHeaderData();
|
|
|
|
SCODE sc = S_OK;
|
|
|
|
CFatSect *pfs = NULL;
|
|
USHORT csectPerDif = (USHORT)(cbSectorSize / sizeof(SECT));
|
|
SECT sectDif = ph->_sectDifStart;
|
|
|
|
for (ULONG i = 0; i < ph->_csectDif; i++)
|
|
{
|
|
|
|
pfs = pvNew->GetCFatSect((sectDif * cbSectorSize) +
|
|
cbSectorSize );
|
|
|
|
for (USHORT j = 0; j < csectPerDif; j++)
|
|
{
|
|
SECT sectOld = pfs->GetSect(j);
|
|
|
|
if ((sectOld != FREESECT) &&
|
|
(sectOld != ENDOFCHAIN))
|
|
{
|
|
pfs->SetSect(j, psScript[sectOld]);
|
|
}
|
|
}
|
|
|
|
sectDif = pfs->GetNextFat(csectPerDif - 1);
|
|
|
|
sc = pvNew->WriteToFile(pfs);
|
|
pvNew->Remove(pfs);
|
|
|
|
}
|
|
|
|
pvNew->Remove(ph);
|
|
return sc;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: RemapFat
|
|
//
|
|
// Synopsis: Remap the Fat according to a processed script and the original
|
|
// file
|
|
//
|
|
// Arguments: [pvNew] -- Pointer to base of destination memory mapped file
|
|
// [pvOld] -- Pointer to base of source memory mapped file
|
|
// [psScript] -- Pointer to processed script
|
|
// [csectFile] -- Count of sectors in file
|
|
// [cbSectorSize] -- Sector size in bytes
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 13-Feb-96 PhilipLa Created
|
|
//
|
|
// Notes: Since the processed script does not contain information
|
|
// about individual fat chains, we need the old file in order
|
|
// to construct the new fat.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE RemapFat(MAPFILE *pvNew,
|
|
MAPFILE *pvOld,
|
|
SECT *psScript,
|
|
ULONG csectFile,
|
|
ULONG cbSectorSize)
|
|
{
|
|
CFatSect *pfsNew;
|
|
CFatSect *pfsOld;
|
|
|
|
SCODE sc = S_OK;
|
|
|
|
ULONG csectFat = pvNew->GetULONG(
|
|
(ULONG) offsetof(CMSFHeaderData, _csectFat));
|
|
|
|
USHORT csectPerFat = (USHORT)(cbSectorSize / sizeof(SECT));
|
|
|
|
for (ULONG i = 0; i < csectFat; i++)
|
|
{
|
|
pfsNew = GetFatSect(pvNew, i, cbSectorSize, NULL);
|
|
memset(pfsNew, 0xFF, cbSectorSize);
|
|
|
|
sc = pvNew->WriteToFile(pfsNew);
|
|
if (sc != S_OK)
|
|
{
|
|
return sc;
|
|
}
|
|
pvNew->Remove(pfsNew);
|
|
}
|
|
|
|
for (i = 0; i < csectFat; i++)
|
|
{
|
|
pfsOld = GetFatSect(pvOld, i, cbSectorSize, NULL);
|
|
|
|
for (USHORT j = 0; j < csectPerFat; j++)
|
|
{
|
|
if (i * csectPerFat + j >= csectFile)
|
|
{
|
|
//Sector outside of current file size - no remapping
|
|
//is necessary, and sector has already been marked
|
|
//as free above.
|
|
break;
|
|
}
|
|
|
|
SECT sectOld = pfsOld->GetSect(j);
|
|
SECT sectNew = psScript[i * csectPerFat + j];
|
|
ULONG iFatNew = sectNew / csectPerFat;
|
|
USHORT oFatNew = (USHORT)(sectNew % csectPerFat);
|
|
|
|
CFatSect *pfsNew = GetFatSect(pvNew, iFatNew, cbSectorSize, NULL);
|
|
|
|
if (sectOld > MAXREGSECT)
|
|
{
|
|
pfsNew->SetSect(oFatNew, sectOld);
|
|
}
|
|
else
|
|
{
|
|
//Need to map contents.
|
|
SECT sectMap = psScript[sectOld];
|
|
pfsNew->SetSect(oFatNew, sectMap);
|
|
}
|
|
sc = pvNew->WriteToFile(pfsNew);
|
|
pvNew->Remove(pfsNew);
|
|
}
|
|
|
|
pvOld->Remove(pfsOld);
|
|
}
|
|
|
|
return sc;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: RemapDirectory
|
|
//
|
|
// Synopsis: Remap a directory based on a processed script
|
|
//
|
|
// Arguments: [pvNew] -- Pointer to base of memory mapped file
|
|
// [psScript] -- Pointer to processed script
|
|
// [csectFile] -- Count of sectors in file
|
|
// [cbSectorSize] -- Sector size in bytes
|
|
//
|
|
// Returns: Appropriate status code
|
|
//
|
|
// History: 13-Feb-96 PhilipLa Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE RemapDirectory(MAPFILE *pvNew,
|
|
SECT *psScript,
|
|
ULONG csectFile,
|
|
ULONG cbSectorSize)
|
|
{
|
|
CMSFHeaderData *ph = (CMSFHeaderData *)pvNew->GetCMSFHeaderData();
|
|
|
|
SCODE sc = S_OK;
|
|
|
|
USHORT csectPerFat = (USHORT)(cbSectorSize / sizeof(SECT));
|
|
USHORT cEntryPerSect = (USHORT)(cbSectorSize / sizeof(CDirEntry));
|
|
SECT sectDir = ph->_sectDirStart;
|
|
|
|
while (sectDir != ENDOFCHAIN)
|
|
{
|
|
CDirSect *pds = pvNew->GetCDirSect((sectDir * cbSectorSize) +
|
|
cbSectorSize );
|
|
|
|
for (USHORT i = 0; i < cEntryPerSect; i++)
|
|
{
|
|
CDirEntry *pde = pds->GetEntry(i);
|
|
|
|
if (STREAMLIKE(pde->GetFlags()))
|
|
{
|
|
SECT sectOld = (ULONG) pde->GetStart();
|
|
#ifdef LARGE_STREAMS
|
|
ULONGLONG ulSize = pde->GetSize(cbSectorSize > 512);
|
|
#else
|
|
ULONG ulSize = pde->GetSize();
|
|
#endif
|
|
swap ((char *) §Old, sizeof(SECT));
|
|
swap ((char *) &ulSize, sizeof(ulSize));
|
|
|
|
|
|
if ((ulSize >= ph->_ulMiniSectorCutoff) ||
|
|
(pde->GetFlags() == STGTY_ROOT))
|
|
{
|
|
if ((sectOld != ENDOFCHAIN) && (sectOld != FREESECT))
|
|
{
|
|
SECT sectNew = psScript[sectOld];
|
|
swap ((char *) §New, sizeof(SECT));
|
|
pde->SetStart(sectNew);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
sectDir = GetNext(pvNew, sectDir, cbSectorSize);
|
|
|
|
sc = pvNew->WriteToFile(pds);
|
|
pvNew->Remove(pds);
|
|
}
|
|
pvNew->Remove(ph);
|
|
|
|
return sc;
|
|
}
|