Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

764 lines
22 KiB

/*** buildfol.c - Diamond Folder Builder
*
* Author:
* Chuck Strouss
*
* History:
* 01-Dec-1993 chuckst Initial version
* 01-Dec-1993 chuckst Now requires only two output files
* 03-Dec-1993 chuckst Implemented FCC blocks
* 09-Jan-1994 chuckst Renamed from FCI.C, FCI.C will be the
* higher level calls.
* 15-Mar-1994 bens Add tempfile index enumeration; RESERVE work
* 01-Jun-1994 bens Add Quantum support
*/
#include <memory.h>
#include <string.h>
#include <fcntl.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <io.h>
#include <stdio.h>
#include <errno.h>
#include "types.h"
#include "asrt.h"
#include "fci_int.h"
#include "cabinet.h"
#include "erf.h"
#include "..\mszip\mci.h"
#include "..\quantum\qci.h"
#include "buildcab.h"
#include "checksum.h"
//*** Internal function prototypes
BOOL WriteCFDATABlock (PFOL pfol,
PFNFCISTATUS pfnProgress,
void *pv);
BOOL MCIResetCompressionGlobal(PFOL pfol);
BOOL MCICreateCompressionGlobal(PFOL pfol);
BOOL MCIDestroyCompressionGlobal(PFOL pfol);
BOOL MCICompressGlobal(PFOL pfol, USHORT *pcbData);
/*** FolderInit - Initialize for folder creation
*
*/
HFOL FolderInit(PERF perf, // error type return structure
PFNALLOC pfnalloc, // memory allocation function
PFNFREE pfnfree, // memory free function
PFNFCIGETTEMPFILE pfntemp, // generate temp file name
UINT cbCFDataPlusReserve
)
{
PFOL pfol;
pfol = (PFOL)pfnalloc(sizeof (FOL));
if (pfol == NULL) {
ErfSetCodes(perf,FCIERR_ALLOC_FAIL,0);
return NULL;
}
SetAssertSignature(pfol,sigFOL);
AssertFOL(pfol); // Make sure we've really set sig
pfol->perf = perf; // Save away error pointer
pfol->pfnfree = pfnfree; // Save free function in our context
pfol->pfnalloc = pfnalloc; // Save alloc function in our context
pfol->pchCompr = NULL; // Simplify error cleanup
pfol->pchUncompr = NULL; // Simplify error cleanup
pfol->typeCompress = tcompBAD; // No compressor initialized yet
pfol->cbCFDataPlusReserve = cbCFDataPlusReserve;
if (!CrTempFiles(pfol->tf,NUM_FOLDER_TF,pfntemp,pfol->perf)) {
FolderDestroy(pfol); // clean up
return NULL;
}
pfol->uoffNext = 0; // keep track of uncompressed size.
pfol->cbBuffered = 0; // Nothing currently in our buffer
return HFOLfromPFOL(pfol);
} /* FolderInit() */
/*** AddFileToFolder -- add a source file into the current folder
*
* Entry:
* parameters noted below
*
* Exit success:
* Returns TRUE
*
* Exit failure:
* Returns FALSE
* error structure indicates error type
* files closed, context deleted
*/
int AddFileToFolder(
HFOL hfol, // compression context
char *pszSourceFile, // filename to get new data from
char *pszFileName, // name to store into CAB file
BOOL fExecute, // Set Execute on extract
PFNFCISTATUS pfnProgress, // Progress callback
PFNFCIGETOPENINFO pfnOpenInfo, // Open file, get info callback
TCOMP typeCompress, // compression setting
void *pv) // context pointer for callbacks
{
PFOL pfol;
int hfInput;
int cbRead;
CFFILE cff;
pfol = PFOLfromHFOL(hfol);
AssertFOL (pfol); // verify structure signature
cff.uoffFolderStart = pfol->uoffNext; // save file start
cff.iFolder = 0; // folder numbers filled in at
if (-1 == (hfInput = pfnOpenInfo(pszSourceFile,
&cff.date,
&cff.time,
&cff.attribs,
pv))) {
ErfSetCodes(pfol->perf,FCIERR_OPEN_SRC,errno); // set error
return FALSE; // fatal error
}
// Overloading this flag -- if it's actually used we're in trouble
Assert( !(cff.attribs & RUNATTRIB) );
if (fExecute) {
cff.attribs |= RUNATTRIB;
}
while ((cbRead = _read(hfInput,
&(pfol->pchUncompr[pfol->cbBuffered]),
pfol->cbSrcBuffer-pfol->cbBuffered)) !=0 ) {
if (cbRead == -1) { // Read error
ErfSetCodes(pfol->perf,FCIERR_READ_SRC,errno);
goto error;
}
pfol->uoffNext += (unsigned)cbRead;
pfol->cbBuffered += (unsigned)cbRead;
//** If we filled up the buffer, compress it and write it
if (pfol->cbBuffered == pfol->cbSrcBuffer) {
// Compress, write, give progress reports
if (!WriteCFDATABlock(pfol,pfnProgress,pv)) {
goto error; // error already filled in
}
}
}
//** Done reading this file
_close(hfInput);
//** Write out the CFFILE structure to the temp file
cff.cbFile = pfol->uoffNext - cff.uoffFolderStart;
if (!WriteCount(&pfol->tf[iftfCFFOLDER],
&cff,
sizeof(cff),
pfol->perf)
|| !WritePszTmp(&pfol->tf[iftfCFFOLDER],
pszFileName,
pfol->perf)) {
goto error;
}
//** Success
return TRUE;
error:
if (hfInput != -1) {
_close(hfInput);
}
return FALSE;
}
/*** FolderFlush - Flush buffers, reset MCI compressor
*
* Entry:
* hfol -- handle to folder context
* pfnProgress -- Progress callbacks go here
* pv -- original caller's callback context
*
* Exit-success:
* returns TRUE
*
* Exit-failure:
* returns FALSE
* error structure in pfol filled in
*/
BOOL FolderFlush (HFOL hfol,PFNFCISTATUS pfnProgress,void *pv)
{
PFOL pfol;
BOOL rc;
pfol = PFOLfromHFOL (hfol);
AssertFOL (pfol);
//** flush the last buffer, if any
rc = WriteCFDATABlock(pfol,pfnProgress,pv);
if (!MCIResetCompressionGlobal(pfol)) { // reset the compressor
return FALSE; // error already filled in
}
pfol->uoffNext = 0; // keep track of uncompressed size.
return rc; // error already filled in
}
/*** FolderDestroy - Deletes temp files and destroy a folder context
*
* Entry:
* hfol -- folder context
*
* Exit-Success:
* returns TRUE
*
* Exit-Failure:
* returns FALSE, error struct filled in
*/
BOOL FolderDestroy (HFOL hfol)
{
PFOL pfol;
BOOL fOK;
pfol = PFOLfromHFOL (hfol);
AssertFOL (pfol);
SetCompressionType(tcompBAD,pfol); // clear out compressor
fOK = NukeTempFiles(pfol->tf,NUM_FOLDER_TF,pfol->perf);
ClearAssertSignature(pfol);
(*pfol->pfnfree)(pfol);
return fOK;
}
/*** SetCompressionType -- initializes a new compressor
*
* Entry:
* typeCompress - New compression type (tcompBAD to term w/ no new)
* pfol - Folder context structure
*
* Exit-Success:
* returns TRUE;
*
* Exit-Failure:
* returns FALSE, error structure filled in
*/
BOOL SetCompressionType(TCOMP typeCompress,PFOL pfol)
{
//BUGBUG 15-Mar-1994 bens What if new type is same as old type?
if (!MCIDestroyCompressionGlobal(pfol)) {
return FALSE; // error already filled in
}
pfol->typeCompress = typeCompress; // update current compression type
if (!MCICreateCompressionGlobal(pfol)) {
return FALSE; // error already filled in
}
return TRUE;
}
/*** WriteCFDATABlock - write out a CFDATA block to current .CFD file
*
* Entry:
* pfol - pointer to folder structure
* pfnProgress - issue Progress callbacks to this function
* pv - context to pass to Progress callbacks
*
* Exit-Success:
* Returns TRUE
*
* Exit-Failure:
* Returns FALSE; error structure filled in
*/
BOOL WriteCFDATABlock (PFOL pfol, PFNFCISTATUS pfnProgress, void *pv)
{
CFDATA *pcfdata=NULL;
AssertFOL (pfol);
if (pfol->cbBuffered == 0) {
return TRUE; // done if nothing to write
}
if (!(pcfdata = (*pfol->pfnalloc)(pfol->cbCFDataPlusReserve))) {
ErfSetCodes(pfol->perf,FCIERR_ALLOC_FAIL,0);
return FALSE;
}
//** Zero reserved area (and rest of CFDATA structure, too)
memset(pcfdata,0,pfol->cbCFDataPlusReserve);
if (!MCICompressGlobal(pfol,&(pcfdata->cbData))) {
goto error; // error struct already filled in
}
// Generate the CFDATA structure that will be prepended to the actual
// data on the disk. Notice that we will not fill in the checksum until
// later, when this record is copied to the cabinet. This works better
// because there are times when a CFDATA block ends up being split
// between two cabinets.
pcfdata->cbUncomp = pfol->cbBuffered;
if (!WriteCount(&pfol->tf[iftfCFDATA],
pcfdata,
pfol->cbCFDataPlusReserve,
pfol->perf)
|| !WriteCount(&pfol->tf[iftfCFDATA],
pfol->pchCompr,
pcfdata->cbData,
pfol->perf)) {
goto error; // Error already filled in
}
if (-1 == pfnProgress(statusFile, // type of Progress callback
pcfdata->cbData, // Compressed size
pfol->cbBuffered, // Uncompressed size
pv)) { // context pointer
ErfSetCodes(pfol->perf,FCIERR_USER_ABORT,0);
goto error;
}
pfol->cbBuffered = 0; // Folder is empty
(*pfol->pfnfree)(pcfdata); // Free resources
return TRUE;
error:
//** Clean up and exit
if (pcfdata) {
(*pfol->pfnfree)(pcfdata);
}
return FALSE;
}
// The following routines are use for manipulating temporary files
/*** CrTempFiles -- creates temporary files and opens them for writing
*
* Entry:
* ptf -- pointer to an array of temp file structures
* ctf -- count of temp files to init
* pfntemp -- callback for generating a temp filename
* perf -- error code structure
*
* Exit-success:
* return value is TRUE
* ptf->szName has name of open file
* ptf->hf has file handle
* ptf->cb length field init'd to 0
*
* Exit-failure:
* return code FALSE, error structure filled in
*
*/
BOOL CrTempFiles(TF *ptf,
int ctf,
PFNFCIGETTEMPFILE pfntemp,
PERF perf)
{
int tfIndex;
int iRetry;
for (tfIndex=0; tfIndex<ctf; tfIndex++) {
ptf[tfIndex].hf = -1; // init all temp file handles to -1
ptf[tfIndex].cb = 0; // length == empty
}
for (tfIndex=0; tfIndex< ctf;tfIndex++)
{
iRetry = 11; // Try 10 times to create a temp file
while ((ptf[tfIndex].hf == -1) && iRetry--) {
if (pfntemp(ptf[tfIndex].szName,sizeof(ptf[tfIndex].szName))) {
//** Create file, must not already exists
ptf[tfIndex].hf = _open(ptf[tfIndex].szName,
_O_CREAT | _O_EXCL | _O_BINARY | _O_RDWR,
_S_IREAD | _S_IWRITE );
}
}
//** Were we able to create the temp file?
if (ptf[tfIndex].hf == -1) {
ErfSetCodes(perf,FCIERR_TEMP_FILE,errno);
goto error;
}
}
//** Success
return TRUE;
error:
//** Close and destroy any files we created
for (tfIndex=0; tfIndex<ctf; tfIndex++) {
if (ptf[tfIndex].hf != -1) {
_close(ptf[tfIndex].hf);
_unlink(ptf[tfIndex].szName);
}
}
return FALSE;
}
/*** NukeTempFiles -- close and delete open temp files
*
* Entry:
* ptf -- points to an open temp file structure array
* ctf -- number of files to nuke
* perf -- error structure
*
* Exit-success:
* return TRUE
* temp files closed and deleted
*
* Exit-failure:
* return FALSE, error structure filled in
*/
BOOL NukeTempFiles(TF *ptf,int ctf,PERF perf)
{
BOOL fOK=TRUE;
int tfIndex;
//** Close and delete temp files; we record an error occurence, but
// continue going because we want to close and delete as many as
// possible.
for (tfIndex=0; tfIndex<ctf; tfIndex++)
{
if (_close(ptf[tfIndex].hf)) {
ErfSetCodes(perf,FCIERR_TEMP_FILE,errno);
fOK = FALSE;
}
ptf[tfIndex].hf = -1; // file no longer open
if (-1 == _unlink(ptf[tfIndex].szName)) {
ErfSetCodes(perf,FCIERR_TEMP_FILE,errno);
fOK = FALSE;
}
}
return fOK;
}
/*** WriteCount -- Write into temp file, count bytes
*
* Entry:
* ptf - pointer to temp file structure
* pv - buffer pointer
* cb - count to write
* perf - error structure
*
* Exit-Success:
* Returns TRUE if the write occurred properly
*
* Exit-Failure:
* Returns FALSE, error struct fille din
*/
int WriteCount(TF *ptf,
const void *pv,
unsigned int cb,
PERF perf)
{
ptf->cb += cb; // keep track of how much we've written
if (cb != (unsigned)_write(ptf->hf,pv,cb))
{
ErfSetCodes(perf,FCIERR_TEMP_FILE,0);
return FALSE;
}
return TRUE;
}
/*** WritePszTmp -- writes a psz string to temp file
*
* Entry:
* ptf - pointer to temp file structure
* psz - string to write
* perf - error structure
*
* Exit-Success:
* returns TRUE
*
* Exit-Failure:
* returns FALSE, error struct filled in (TEMP file error)
*/
BOOL WritePszTmp(TF *ptf,char *psz,PERF perf)
{
return WriteCount(ptf,psz,1+strlen(psz),perf);
}
/*** MCIDestroyCompressionGlobal -- Destroy the currently selected compressor
*
* Entry:
* pfol - Pointer to folder context
*
* Exit-Success:
* returns TRUE
*
* Exit-Failure:
* returns FALSE, error structure filled in
*/
BOOL MCIDestroyCompressionGlobal(PFOL pfol)
{
BOOL fOK=TRUE;
switch(CompressionTypeFromTCOMP(pfol->typeCompress)) {
case tcompBAD: // no existing compression
break; // nothing to do
case tcompTYPE_NONE:
break; //no action needed for null compressor
case tcompTYPE_MSZIP:
if (MCI_ERROR_NO_ERROR != MCIDestroyCompression(pfol->mch)) {
ErfSetCodes(pfol->perf,FCIERR_MCI_FAIL,0);
fOK = FALSE;
}
break;
#ifndef BIT16
case tcompTYPE_QUANTUM:
if (MCI_ERROR_NO_ERROR != QCIDestroyCompression(pfol->mch)) {
ErfSetCodes(pfol->perf,FCIERR_MCI_FAIL,0);
fOK = FALSE;
}
break;
#endif
default:
ErfSetCodes(pfol->perf,FCIERR_BAD_COMPR_TYPE,0);
}
//** Now free the buffers
if (pfol->pchCompr) {
(*pfol->pfnfree)(pfol->pchCompr);
pfol->pchCompr = NULL; // Simplify error cleanup
}
if (pfol->pchUncompr) {
(*pfol->pfnfree)(pfol->pchUncompr);
pfol->pchUncompr = NULL; // Simplify error cleanup
}
return fOK;
}
/*** MCICreateCompressionGlobal -- Create the currently selected compressor
*
* Entry:
* pfol - Pointer to folder context
*
* Exit-Success:
* Returns TRUE
*
* Exit-Failure:
* Returns FALSE, error structure filled in
*/
BOOL MCICreateCompressionGlobal(PFOL pfol)
{
#ifndef BIT16
QUANTUMCONFIGURATION qcfg;
#endif
pfol->cbSrcBuffer = CB_MAX_CHUNK;
pfol->pchCompr = NULL; // Simplify error cleanup
pfol->pchUncompr = NULL; // Simplify error cleanup
switch(CompressionTypeFromTCOMP(pfol->typeCompress)) {
case tcompBAD: // no new compressor
return TRUE; // all done if no compressor enabled
case tcompTYPE_NONE:
pfol->cbDstBuffer = pfol->cbSrcBuffer;
break;
case tcompTYPE_MSZIP:
if (MCI_ERROR_NO_ERROR != MCICreateCompression(&pfol->cbSrcBuffer,
pfol->pfnalloc,
pfol->pfnfree,
&pfol->cbDstBuffer,
&pfol->mch)) {
ErfSetCodes(pfol->perf,FCIERR_MCI_FAIL,0);
return FALSE;
}
break;
#ifndef BIT16
case tcompTYPE_QUANTUM:
qcfg.CompressionLevel = CompressionLevelFromTCOMP(pfol->typeCompress);
qcfg.WindowBits = CompressionMemoryFromTCOMP(pfol->typeCompress);
//BUGBUG 01-Jun-1994 bens What is 3rd member of QCICreate structure
qcfg.HackHack = -1; // Why?
if (MCI_ERROR_NO_ERROR != QCICreateCompression(&pfol->cbSrcBuffer,
&qcfg,
pfol->pfnalloc,
pfol->pfnfree,
&pfol->cbDstBuffer,
&pfol->mch)) {
ErfSetCodes(pfol->perf,FCIERR_MCI_FAIL,0);
return FALSE;
}
break;
#endif
default:
ErfSetCodes(pfol->perf,FCIERR_BAD_COMPR_TYPE,0);
return FALSE;
}
//** Now allocate whatever buffers the selected compressor requested
if (NULL == (pfol->pchCompr=(char *)pfol->pfnalloc(pfol->cbDstBuffer))) {
ErfSetCodes(pfol->perf,FCIERR_ALLOC_FAIL,0);
goto error;
}
if (NULL == (pfol->pchUncompr=(char *)pfol->pfnalloc(pfol->cbSrcBuffer))) {
ErfSetCodes(pfol->perf,FCIERR_ALLOC_FAIL,0);
goto error;
}
return TRUE;
error:
MCIDestroyCompressionGlobal(pfol); // Clean up
return FALSE; // Failure
}
/*** MCIResetCompressionGlobal -- reset the currently selected compressor
*
* Entry:
* pfol -- pointer to folder context
*
* Exit-success:
* returns TRUE
*
* Exit-failure:
* returns FALSE, error structure filled in
*/
BOOL MCIResetCompressionGlobal(PFOL pfol)
{
switch(CompressionTypeFromTCOMP(pfol->typeCompress)) {
case tcompBAD:
case tcompTYPE_NONE:
break; // no action for null compressor or none installed
case tcompTYPE_MSZIP:
if (MCI_ERROR_NO_ERROR != MCIResetCompression(pfol->mch)) {
ErfSetCodes(pfol->perf,FCIERR_MCI_FAIL,0);
return FALSE;
}
break;
#ifndef BIT16
case tcompTYPE_QUANTUM:
if (MCI_ERROR_NO_ERROR != QCIResetCompression(pfol->mch)) {
ErfSetCodes(pfol->perf,FCIERR_MCI_FAIL,0);
return FALSE;
}
break;
#endif
default:
ErfSetCodes(pfol->perf,FCIERR_BAD_COMPR_TYPE,0);
return FALSE;
}
return TRUE;
}
/*** MCICompressGlobal -- Compress with the currently selected compressor
*
* Entry:
* pfol - Pointer to folder context
* cbData - Location to return the compressed size
*
* Exit-Success:
* Returns TRUE
*
* Exit-Failure:
* Returns FALSE, error filled in
*/
BOOL MCICompressGlobal(PFOL pfol,USHORT *pcbData)
{
UINT cbData;
switch(CompressionTypeFromTCOMP(pfol->typeCompress)) {
case tcompTYPE_NONE:
memcpy(pfol->pchCompr,pfol->pchUncompr,*pcbData=pfol->cbBuffered);
break;
case tcompTYPE_MSZIP:
if (MCI_ERROR_NO_ERROR != MCICompress(pfol->mch,
pfol->pchUncompr,
pfol->cbBuffered,
pfol->pchCompr,
pfol->cbDstBuffer,
&cbData)) {
ErfSetCodes(pfol->perf,FCIERR_MCI_FAIL,0);
return FALSE;
}
//** Step down
*pcbData = (USHORT)cbData;
break;
#ifndef BIT16
case tcompTYPE_QUANTUM:
if (MCI_ERROR_NO_ERROR != QCICompress(pfol->mch,
pfol->pchUncompr,
pfol->cbBuffered,
pfol->pchCompr,
pfol->cbDstBuffer,
&cbData)) {
ErfSetCodes(pfol->perf,FCIERR_MCI_FAIL,0);
return FALSE;
}
//** Step down
*pcbData = (USHORT)cbData;
break;
#endif
default:
ErfSetCodes(pfol->perf,FCIERR_BAD_COMPR_TYPE,0);
return FALSE; // Fatal error -- no valid compressor initialized
}
#ifndef REMOVE_CHICAGO_M6_HACK
//BUGBUG 18-May-1994 bens Hack for Chicago M6
// AndyHi & Co. are very risk averse, and so do not want to pick up a
// version of FDI.LIB newer than 302. Unfortunately, 302 has a bug
// in both FCI.LIB and FDI.LIB that cause diamond.exe to Assert() when
// an incompressible block is generated, and cause extract.exe (fdi.lib,
// really) to detect corrupted compressed data when an incompressible
// block is encountered.
//
// So, FCI has a temporary option to detect and fail when incompressible
// data is encountered, and DIAMOND.EXE has a switch to turn on this
// checking! Once Chicago M6 is released, we can destroy all this code!
//
//** Check for incompressible data and fail if told to do so;
if ((pfol->fFailOnIncompressible) && // Fail if incompressible
(cbData > pfol->cbSrcBuffer)) { // Output bigger than source buffer
ErfSetCodes(pfol->perf,FCIERR_M6_HACK_INCOMPRESSIBLE,0);
return FALSE; // Fatal error -- no valid compressor initialized
}
#endif
return TRUE;
}