windows-nt/Source/XPSP1/NT/base/wow64/setup/boot/dmnd2.c
2020-09-26 16:20:57 +08:00

682 lines
16 KiB
C

/***************************************************************************
**
** File: dmnd2.c
** Purpose: CallBack functions to be passed to the Diamond
** FDI (File Decompression Interface) module.
** Notes:
**
****************************************************************************/
#define DMND2_C
#include <windows.h>
#include <stdlib.h> /* malloc */
#include <malloc.h> /* malloc, _halloc */
#include <stdio.h> /* _tempnam */
#include <fcntl.h>
#include <io.h> /* _open, _read, _write, _write, _lseek, _mktemp */
#include <sys\stat.h> /* _S_IWRITE, _S_IREAD */
#include "stdtypes.h"
#include "setup.h"
#include <fdi.h>
typedef struct _fud /* Fdi User Data block used in FDICopy */
{
char * szDstDir;
char * szSrcs;
char * szDsts;
char * szSrcBuf;
char * szDstBuf;
BOOL * rgfSrcFilesCopied;
int cFilesCopied;
int cSrcFiles;
int cCabNum; /* Current cabinet number (starts at 1) */
HWND hWnd; /* Window handle used to display dialogs */
HFDI hfdi;
ERF erf;
BRC brc;
char rgchSpillFileName[cchFullPathMax];
int hfSpillFile;
} FUD;
typedef FUD * PFUD; /* Ptr to Fdi User Data block */
#define pfudNull ((PFUD)NULL)
#define hfdiNull ((HFDI)NULL)
#define szSpillFilePrefix "sf"
#define szSpillFileTemplate "sfXXXXXX"
/* FDI Callback Routines
*/
FNFDINOTIFY ( FnFdiNotifyCB );
FNALLOC ( FnFdiAllocCB );
FNFREE ( FnFdiFreeCB );
INT_PTR FAR DIAMONDAPI FnFdiOpenCB ( char FAR *szFile, int oflag, int pmode );
UINT FAR DIAMONDAPI FnFdiReadCB ( INT_PTR hf, void FAR *pv, UINT cb );
UINT FAR DIAMONDAPI FnFdiWriteCB ( INT_PTR hf, void FAR *pv, UINT cb );
int FAR DIAMONDAPI FnFdiCloseCB ( INT_PTR hf );
long FAR DIAMONDAPI FnFdiSeekCB ( INT_PTR hf, long dist, int seektype );
/* Private Functions
*/
static int FhHandleCopyFileMsgInNotify ( PFUD pfud, char * szFName );
static BOOL FHandleCloseFileMsgInNotify ( PFUD pfud, INT_PTR hf );
static BOOL FHandleNextCabMsgInNotify ( PFUD pfud, char * szCabFName,
char * szDiskLabel, char * szSrcDir, FDIERROR fdie );
static BOOL FModifyCabinetName(char * szSrcDir, int cCabNum);
static BOOL FEnsureCabinetFileIsPresent(HWND hWnd, char * szSrcDir,
char * szCabinet, int cCabNum);
static int HfOpenSpillFile ( PFDISPILLFILE pfdisf, int oflag, int pmode );
static VOID InitFud (PFUD pfud, char * szDstDir, char * szSrcs,
char * szDsts, char * szSrcBuf, char * szDstBuf,
BOOL * rgfSrcFilesCopied, int cSrcFiles, HWND hWnd );
/* KLUDGE - so pfud->brc can be found in callbacks */
static PFUD pfudG = pfudNull;
#ifndef DEBUG_TEST /* Turn on for create/skip file messages. */
#define DebugMsgSz(sz1, sz2)
#else /* DEBUG */
static VOID DebugMsgSz ( char * szPattern, char * szArgument );
/*
************************************************************************/
static VOID DebugMsgSz ( char * szPattern, char * szArgument )
{
char rgch[128];
wsprintf(rgch, szPattern, szArgument);
DebugMsg(rgch);
}
#endif /* DEBUG */
/*
** Purpose:
** This function is passed as a callback to the FDI library.
** Arguments:
** fdint - type of notification
** pfdin - data for notification
** Returns:
** varies with fdint
**
*************************************************************************/
FNFDINOTIFY ( FnFdiNotifyCB )
{
switch (fdint)
{
default:
DebugMsg("Unexpected message passed to FnFdiNotifyCB().");
((PFUD)(pfdin->pv))->brc = brcGen;
return (0);
case fdintCABINET_INFO:
/* do nothing */
return (0);
case fdintCOPY_FILE:
return (FhHandleCopyFileMsgInNotify(pfdin->pv, pfdin->psz1));
case fdintCLOSE_FILE_INFO:
return (FHandleCloseFileMsgInNotify(pfdin->pv, pfdin->hf) ? TRUE
: -1);
case fdintPARTIAL_FILE:
/* do nothing */
return (0);
case fdintNEXT_CABINET:
return (FHandleNextCabMsgInNotify(pfdin->pv, pfdin->psz1,
pfdin->psz2, pfdin->psz3, pfdin->fdie) ? 0 : -1);
}
}
/*
** returns:
** 0 == skip this file
** -1 == abort FDICopy()
** else a legitimate DOS file handle
*************************************************************************/
static int FhHandleCopyFileMsgInNotify ( PFUD pfud, char * szFName )
{
SZ szSrcs = pfud->szSrcs;
SZ szDsts = pfud->szDsts;
int iFile;
struct _stat stat;
for (iFile = 0; *szSrcs; iFile++)
{
if (*szSrcs == '@' && !lstrcmpi(szSrcs+1, szFName))
{
int hfRet;
lstrcpy(pfud->szDstBuf, pfud->szDstDir);
lstrcat(pfud->szDstBuf, "\\");
lstrcat(pfud->szDstBuf, szDsts);
DebugMsgSz("Creating Dest File: %s", pfud->szDstBuf);
/* If file exists, try to remove it.
*/
if (_stat(pfud->szDstBuf, &stat) != -1)
{
/* NOTE: Ignore error return values here since
* _open should catch any errors anyway.
*/
if (!(stat.st_mode & _S_IWRITE))
_chmod(pfud->szDstBuf, _S_IREAD | _S_IWRITE);
_unlink(pfudG->szDstBuf);
}
hfRet = _open(pfud->szDstBuf,
_O_BINARY | _O_CREAT | _O_RDWR | _O_TRUNC,
_S_IREAD | _S_IWRITE);
if (hfRet == -1)
pfud->brc = brcMemDS;
if (iFile < pfud->cSrcFiles)
(pfud->rgfSrcFilesCopied)[iFile] = TRUE;
// We will have copied one more file
pfud->cFilesCopied++;
return (hfRet);
}
szSrcs += lstrlen(szSrcs) + 1;
szDsts += lstrlen(szDsts) + 1;
}
DebugMsgSz("Skipping a cabinet file: %s", szFName);
return (0);
}
/*
*************************************************************************/
static BOOL FHandleCloseFileMsgInNotify ( PFUD pfud, INT_PTR hf )
{
if (FnFdiCloseCB(hf) != -1)
{
_chmod(pfud->szDstBuf, S_IREAD);
return (TRUE);
}
return (FALSE);
}
/*
*************************************************************************/
static BOOL FHandleNextCabMsgInNotify ( PFUD pfud, char * szCabFName,
char * szDiskLabel, char * szSrcDir, FDIERROR fdie )
{
Unused(szDiskLabel);
/* Check if diamond is calling us again because the cabinet
* we specified was bad.
*/
if (fdie == FDIERROR_WRONG_CABINET)
{
DebugMsg("Cabinet files are out of sequence or corrupted.");
return FALSE;
}
lstrcpy(pfud->szSrcBuf, szSrcDir);
lstrcat(pfud->szSrcBuf, szCabFName);
if (!FEnsureCabinetFileIsPresent(pfud->hWnd, szSrcDir, szCabFName,
pfud->cCabNum+1))
{
pfud->brc = brcFile;
return FALSE;
}
return TRUE;
}
/*
*************************************************************************/
static int CFilesInSrcsInitRgf ( char * szSrcs, BOOL * rgfSrcFilesCopied )
{
int iFile, cFiles;
for (iFile = 0; iFile < 128; iFile++)
rgfSrcFilesCopied[iFile] = TRUE;
cFiles = 0;
while (*szSrcs)
{
if (*szSrcs == '@')
rgfSrcFilesCopied[cFiles] = FALSE;
cFiles++;
szSrcs += lstrlen(szSrcs) + 1;
}
if (cFiles > 128)
{
DebugMsg("More than 128 source files in .LST file "
"- will not check that all exist.");
cFiles = 128;
}
return (cFiles);
}
/*
** Purpose:
** Copies all cabinet files in the specified copy list, ignoring
** any non-cabinet files in the list.
** Arguments:
** szCabinet: cabinet filename (oem).
** szSrcDir: src path with trailing backslash (ANSI).
** szDstDir: dst path with trailing backslash (oem).
** szSrcs: NULL separated list of src filenames (oem).
** szDsts: NULL separated list of dst filenames (oem).
** szSrcBuf: buffer to hold src path for error msgs.
** szDstBuf: buffer to hold dst path for error msgs.
** Returns:
** brcOkay if completed without error, brcXX otherwise.
**
*************************************************************************/
extern BRC BrcHandleCabinetFiles ( HWND hWnd, char * szCabinet,
int cFirstCabinetNum, int cLastCabinetNum, char *szSrcDir,
char * szDstDir, char * szSrcs, char * szDsts,
char * szSrcBuf, char * szDstBuf )
{
FUD fud;
BRC brcRet = brcOkay;
BOOL rgfSrcFilesCopied[128];
int cSrcFiles = CFilesInSrcsInitRgf(szSrcs, rgfSrcFilesCopied);
int cpuType = cpuUNKNOWN;
InitFud(&fud, szDstDir, szSrcs, szDsts, szSrcBuf, szDstBuf,
rgfSrcFilesCopied, cSrcFiles, hWnd);
pfudG = &fud;
#if 0
/* NOTE: Get CPU type ourselves, since FDI's CPU detection may
* not work correctly for 16-bit Windows applications.
*/
cpuType = (GetWinFlags() & WF_CPU286) ? cpu80286 : cpu80386;
#endif
if ((fud.hfdi = FDICreate(FnFdiAllocCB, FnFdiFreeCB, FnFdiOpenCB,
FnFdiReadCB, FnFdiWriteCB, FnFdiCloseCB,
FnFdiSeekCB, cpuType,
&(fud.erf) )) == hfdiNull)
{
return (brcMem);
}
/*
* Process cabinets as long as we have more files to copy.
* i is the current cabinet number (starting at 1).
*/
for (fud.cCabNum=cFirstCabinetNum;
fud.cFilesCopied < fud.cSrcFiles && fud.cCabNum<=cLastCabinetNum;
fud.cCabNum++)
{
/* Modify the cabinet name depending on the current cabinet number */
if (!FModifyCabinetName(szCabinet, fud.cCabNum))
{
brcRet = brcFile;
break;
}
lstrcpy(szSrcBuf, szSrcDir);
lstrcat(szSrcBuf, szCabinet);
if (!FEnsureCabinetFileIsPresent(fud.hWnd, szSrcDir, szCabinet,
fud.cCabNum))
{
brcRet = brcFile;
break;
}
if (!FDICopy(fud.hfdi, szCabinet, szSrcDir, 0, FnFdiNotifyCB, NULL,
&fud))
{
brcRet = (fud.brc == brcOkay) ? brcGen : fud.brc;
break;
}
}
if (brcRet == brcOkay)
{
int iFile;
/* Check if we got all the files we want */
for (iFile = 0; iFile < cSrcFiles; iFile++)
{
if (!(rgfSrcFilesCopied[iFile]))
{
lstrcat(szSrcBuf, " : ");
lstrcat(szSrcBuf, szSrcs + 1);
brcRet = brcFile;
}
szSrcs += lstrlen(szSrcs) + 1;
}
}
FDIDestroy(fud.hfdi);
/* Ensure that the spill file is deleted.
*/
Assert(pfudG != pfudNull);
if (pfudG->hfSpillFile != -1)
FnFdiCloseCB(pfudG->hfSpillFile);
return (brcRet);
}
/*
*************************************************************************/
static VOID InitFud (PFUD pfud, char * szDstDir, char * szSrcs,
char * szDsts, char * szSrcBuf, char * szDstBuf,
BOOL * rgfSrcFilesCopied, int cSrcFiles, HWND hWnd )
{
pfud->erf.fError = fFalse;
pfud->szDstDir = szDstDir;
pfud->szSrcs = szSrcs;
pfud->szDsts = szDsts;
pfud->szSrcBuf = szSrcBuf;
pfud->szDstBuf = szDstBuf;
pfud->rgfSrcFilesCopied = rgfSrcFilesCopied;
pfud->cSrcFiles = cSrcFiles;
pfud->cFilesCopied = 0;
pfud->hWnd = hWnd;
pfud->brc = brcOkay;
*(pfud->rgchSpillFileName) = chEos;
pfud->hfSpillFile = -1;
}
static BOOL FModifyCabinetName(char * szSrcDir, int cCabNum)
{
char *pch = szSrcDir + lstrlen(szSrcDir);
if (cCabNum < 1 || cCabNum > 9)
return FALSE;
/* Leave the name unchabged for the first cabinet */
if (cCabNum == 1)
return TRUE;
/* Look for the dot, starting backward */
for (; *pch != '.'; pch--)
{
/* Error if we can't find a dot before we find a slash */
if (pch<=szSrcDir+1 || *pch == '\\')
return FALSE;
}
/* Point to the character before the dot */
pch--;
/* Replace the last character before the dot by the cabinet number */
*pch = (char)(cCabNum + '0');
return TRUE;
}
static BOOL FEnsureCabinetFileIsPresent(HWND hWnd, char * szSrcDir,
char * szCabinet, int cCabNum)
{
char rgchFileName[cchFullPathMax], rgchCabNum[32];
OFSTRUCT ofs;
HFILE hFile;
BOOL fFirst = TRUE;
Unused(hWnd);
lstrcpy(rgchFileName, szSrcDir);
lstrcat(rgchFileName, szCabinet);
for (;;)
{
hFile = OpenFile(rgchFileName, &ofs, OF_EXIST);
if (hFile != HFILE_ERROR)
break;
_itoa(cCabNum, rgchCabNum, 10);
if (fFirst)
{
if (DispErrBrc(brcInsDisk, FALSE, MB_ICONEXCLAMATION|MB_OKCANCEL,
rgchCabNum, NULL, NULL) != IDOK)
{
return FALSE;
}
fFirst = FALSE;
}
else
{
if (DispErrBrc(brcInsDisk2, FALSE, MB_ICONEXCLAMATION|MB_OKCANCEL,
rgchFileName, rgchCabNum, NULL) != IDOK)
{
return FALSE;
}
}
}
return TRUE;
}
/*
** Purpose:
** Memory allocator for FDI.
** Arguments:
** cb - size of block to allocate
** Returns:
** Non-NULL pointer to block of size at least cb,
** or NULL for failure.
**
*************************************************************************/
FNALLOC ( FnFdiAllocCB )
{
#ifdef _WIN32
void HUGE * pvRet = malloc(cb);
#else
void HUGE * pvRet = _halloc(cb,1);
#endif
if (pvRet == NULL && pfudG->brc == brcOkay)
pfudG->brc = brcMem;
return (pvRet);
}
/*
** Purpose:
** Memory free function for FDI.
** Arguments:
** pv - memory allocated by FnFdiAllocCB to be freed
** Returns:
** None.
**
*************************************************************************/
FNFREE ( FnFdiFreeCB )
{
#ifdef _WIN32
free(pv);
#else
_hfree(pv);
#endif
}
/*
*************************************************************************/
INT_PTR FAR DIAMONDAPI FnFdiOpenCB ( char FAR *szFile, int oflag, int pmode )
{
INT_PTR hfRet;
if (*szFile == '*')
return (HfOpenSpillFile((PFDISPILLFILE)szFile, oflag, pmode));
hfRet = _open(szFile, oflag, pmode);
if (hfRet == -1 && pfudG->brc == brcOkay)
pfudG->brc = brcFile;
return (hfRet);
}
/*
*************************************************************************/
static int HfOpenSpillFile ( PFDISPILLFILE pfdisf, int oflag, int pmode )
{
SZ szTmp;
CHAR rgchSize[20];
BOOL fTryAgain = fTrue;
Assert(pfdisf != (PFDISPILLFILE)NULL);
Assert(*(pfdisf->ach) == '*');
Assert(pfudG != pfudNull);
Assert(pfudG->hfSpillFile == -1); /* Only one at a time */
Assert(*(pfudG->rgchSpillFileName) == chEos);
if ((szTmp = _tempnam("", szSpillFilePrefix)) == szNull)
{
DebugMsg("Unable to get spill file name.");
goto LNoSpillFile;
}
Assert(lstrlen(szTmp) < sizeof(pfudG->rgchSpillFileName));
lstrcpy(pfudG->rgchSpillFileName, szTmp);
free(szTmp);
LOpenSpillFile:
oflag = _O_CREAT | _O_BINARY | _O_RDWR; /* Force open mode */
if ((pfudG->hfSpillFile = _open(pfudG->rgchSpillFileName, oflag, pmode))
== -1)
{
DebugMsg("Unable to open spill file.");
goto LNoSpillFile;
}
if (pfdisf->cbFile > 0)
{
/* Size file by writing one byte at size - 1.
*/
if (FnFdiSeekCB(pfudG->hfSpillFile, pfdisf->cbFile - 1, SEEK_SET) == -1
|| FnFdiWriteCB(pfudG->hfSpillFile, "b", 1) != 1)
{
DebugMsg("Unable to set spill file size.");
goto LNoSpillFile;
}
}
return (pfudG->hfSpillFile);
LNoSpillFile:
if (pfudG->hfSpillFile != -1)
FnFdiCloseCB(pfudG->hfSpillFile);
if (fTryAgain)
{
/* Try again with bootstrap temp dir.
*
* (REVIEW: We could do another search here, checking for size.)
*/
fTryAgain = fFalse;
Assert(lstrlen(pfudG->szDstBuf) + lstrlen(szSpillFileTemplate) <
sizeof(pfudG->rgchSpillFileName));
lstrcpy(pfudG->rgchSpillFileName, pfudG->szDstDir);
lstrcat(pfudG->rgchSpillFileName, szDirSep);
lstrcat(pfudG->rgchSpillFileName, szSpillFileTemplate);
if (_mktemp(pfudG->rgchSpillFileName) != NULL)
goto LOpenSpillFile;
}
_ltoa((pfdisf->cbFile + 1023) / 1024, rgchSize, 10);
DispErrBrc(brcNoSpill, fTrue, MB_OK | MB_ICONSTOP, rgchSize, szNull, szNull);
*(pfudG->rgchSpillFileName) = chEos;
pfudG->brc = brcNoSpill;
return (-1);
}
/*
*************************************************************************/
UINT FAR DIAMONDAPI FnFdiReadCB ( INT_PTR hf, void FAR *pv, UINT cb )
{
UINT cbRet = _read((int)hf, pv, cb);
if (cbRet != cb && pfudG->brc == brcOkay)
pfudG->brc = brcMemDS;
return (cbRet);
}
/*
*************************************************************************/
UINT FAR DIAMONDAPI FnFdiWriteCB ( INT_PTR hf, void FAR *pv, UINT cb )
{
UINT cbRet = _write((int)hf, pv, cb);
FYield();
if (cbRet != cb && pfudG->brc == brcOkay)
pfudG->brc = brcDS;
return (cbRet);
}
/*
*************************************************************************/
int FAR DIAMONDAPI FnFdiCloseCB ( INT_PTR hf )
{
int iRet = _close((int)hf);
if (iRet == -1 && pfudG->brc == brcOkay)
pfudG->brc = brcDS;
/* If we're closing the spill file, delete it.
*/
if (hf == pfudG->hfSpillFile)
{
_unlink(pfudG->rgchSpillFileName); /* Delete spill file */
*(pfudG->rgchSpillFileName) = chEos; /* Empty path */
pfudG->hfSpillFile = -1; /* Mark as closed */
}
return (iRet);
}
/*
*************************************************************************/
long FAR DIAMONDAPI FnFdiSeekCB ( INT_PTR hf, long dist, int seektype )
{
long lRet = _lseek((int)hf, dist, seektype);
if (lRet == -1L && pfudG->brc == brcOkay)
{
DebugMsg("Seek Operation failed in Cabinet");
pfudG->brc = brcGen;
}
return (lRet);
}