/*************************************************************************** ** ** File: dmnd2.c ** Purpose: CallBack functions to be passed to the Diamond ** FDI (File Decompression Interface) module. ** Notes: ** ****************************************************************************/ #define DMND2_C #include #include /* malloc */ #include /* malloc, _halloc */ #include /* _tempnam */ #include #include /* _open, _read, _write, _write, _lseek, _mktemp */ #include /* _S_IWRITE, _S_IREAD */ #include "stdtypes.h" #include "setup.h" #include 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); }