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.
468 lines
9.6 KiB
468 lines
9.6 KiB
//----------------------------------------------------------------------------
|
|
//
|
|
// CAB file manipulation for dump files and dump CABs.
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 2001-2002.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "pch.hpp"
|
|
#pragma hdrstop
|
|
|
|
#ifndef _WIN32_WCE
|
|
|
|
#include <io.h>
|
|
#include <fcntl.h>
|
|
#include <sys\stat.h>
|
|
#include <share.h>
|
|
#include <errno.h>
|
|
|
|
#include <fci.h>
|
|
#include <fdi.h>
|
|
|
|
#include "cmnutil.hpp"
|
|
|
|
#define CAB_HR(Code) MAKE_HRESULT(SEVERITY_ERROR, 0xfd1, ((Code) & 0xffff))
|
|
|
|
HFCI g_AddCab;
|
|
ERF g_AddCabErr;
|
|
ULONG g_CabTmpSequence;
|
|
|
|
FNALLOC(CabAlloc)
|
|
{
|
|
return malloc(cb);
|
|
}
|
|
|
|
FNFREE(CabFree)
|
|
{
|
|
free(pv);
|
|
}
|
|
|
|
PSTR
|
|
CabPathTail(PSTR Path)
|
|
{
|
|
PSTR Tail = strrchr(Path, '\\');
|
|
if (Tail == NULL)
|
|
{
|
|
Tail = strrchr(Path, '/');
|
|
if (Tail == NULL)
|
|
{
|
|
Tail = strrchr(Path, ':');
|
|
}
|
|
}
|
|
return Tail ? Tail + 1 : Path;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Expanding dump files from CAB files.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
struct FDI_CB_STATE
|
|
{
|
|
PSTR DmpFile;
|
|
ULONG DmpFileLen;
|
|
PSTR DstDir;
|
|
ULONG FileFlags;
|
|
INT_PTR DmpFh;
|
|
PCSTR MatchFile;
|
|
};
|
|
|
|
FNOPEN(FdiOpen)
|
|
{
|
|
return _open(pszFile, oflag, pmode);
|
|
}
|
|
|
|
FNREAD(FdiRead)
|
|
{
|
|
return _read((int)hf, pv, cb);
|
|
}
|
|
|
|
FNWRITE(FdiWrite)
|
|
{
|
|
return _write((int)hf, pv, cb);
|
|
}
|
|
|
|
FNCLOSE(FdiClose)
|
|
{
|
|
return _close((int)hf);
|
|
}
|
|
|
|
FNSEEK(FdiSeek)
|
|
{
|
|
return _lseek((int)hf, dist, seektype);
|
|
}
|
|
|
|
INT_PTR
|
|
FdiCommonNotify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin, BOOL bMatchExt)
|
|
{
|
|
FDI_CB_STATE* CbState = (FDI_CB_STATE*)pfdin->pv;
|
|
PSTR Scan;
|
|
|
|
switch(fdint)
|
|
{
|
|
case fdintCOPY_FILE:
|
|
if (CbState->DmpFh >= 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Match the file extension if needed
|
|
Scan = strrchr(pfdin->psz1, '.');
|
|
if (Scan == NULL ||
|
|
(bMatchExt && (_stricmp(Scan, CbState->MatchFile) != 0)) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Match the file name if if needed
|
|
Scan = CabPathTail(pfdin->psz1);
|
|
if (!bMatchExt && (_stricmp(Scan, CbState->MatchFile) != 0))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Add in the process ID to the filename to
|
|
// make it possible to expand the same CAB from
|
|
// multiple processes at once.
|
|
if (*CbState->DstDir)
|
|
{
|
|
if (_snprintf(CbState->DmpFile, CbState->DmpFileLen,
|
|
"%s\\%08x%x_%s",
|
|
CbState->DstDir, GetCurrentProcessId(),
|
|
g_CabTmpSequence++, Scan) < 0)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (_snprintf(CbState->DmpFile, CbState->DmpFileLen,
|
|
"%08x%x_%s",
|
|
GetCurrentProcessId(), g_CabTmpSequence++,
|
|
Scan) < 0)
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
CbState->DmpFh = FdiOpen(CbState->DmpFile,
|
|
_O_BINARY | _O_WRONLY | CbState->FileFlags,
|
|
_S_IREAD | _S_IWRITE);
|
|
return CbState->DmpFh;
|
|
|
|
case fdintCLOSE_FILE_INFO:
|
|
// Leave the file open.
|
|
return TRUE;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
FNFDINOTIFY(FdiNotifyFileExt)
|
|
{
|
|
return FdiCommonNotify(fdint, pfdin, 1);
|
|
}
|
|
|
|
FNFDINOTIFY(FdiNotifyFileName)
|
|
{
|
|
return FdiCommonNotify(fdint, pfdin, 0);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
ExpandDumpCab(PCSTR CabFile, ULONG FileFlags, PCSTR FileToOpen,
|
|
PSTR DmpFile, ULONG DmpFileLen, INT_PTR* DmpFh)
|
|
{
|
|
FDI_CB_STATE CbState;
|
|
HFDI Context;
|
|
ERF Err;
|
|
BOOL Status;
|
|
PSTR Env;
|
|
|
|
Env = getenv("TMP");
|
|
if (Env == NULL)
|
|
{
|
|
Env = getenv("TEMP");
|
|
if (Env == NULL)
|
|
{
|
|
Env = "";
|
|
}
|
|
}
|
|
|
|
CbState.DmpFile = DmpFile;
|
|
CbState.DmpFileLen = DmpFileLen;
|
|
CbState.DstDir = Env;
|
|
CbState.FileFlags = FileFlags;
|
|
CbState.DmpFh = -1;
|
|
CbState.MatchFile = FileToOpen;
|
|
|
|
Context = FDICreate(CabAlloc, CabFree,
|
|
FdiOpen, FdiRead, FdiWrite, FdiClose, FdiSeek,
|
|
cpuUNKNOWN, &Err);
|
|
if (Context == NULL)
|
|
{
|
|
return CAB_HR(Err.erfOper);
|
|
}
|
|
|
|
if (FileToOpen == NULL)
|
|
{
|
|
// try to open .mdmp or .dmp extension files
|
|
CbState.MatchFile = ".mdmp";
|
|
Status = FDICopy(Context, "", (PSTR)CabFile, 0,
|
|
FdiNotifyFileExt, NULL, &CbState);
|
|
|
|
if (!Status || (CbState.DmpFh < 0))
|
|
{
|
|
CbState.MatchFile = ".dmp";
|
|
Status = FDICopy(Context, "", (PSTR)CabFile, 0,
|
|
FdiNotifyFileExt, NULL, &CbState);
|
|
}
|
|
} else
|
|
{
|
|
Status = FDICopy(Context, "", (PSTR)CabFile, 0,
|
|
FdiNotifyFileName, NULL, &CbState);
|
|
}
|
|
|
|
if (!Status)
|
|
{
|
|
return CAB_HR(Err.erfOper);
|
|
}
|
|
|
|
*DmpFh = CbState.DmpFh;
|
|
return (CbState.DmpFh >= 0) ? S_OK : E_NOINTERFACE;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Placing files into a CAB.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
// We don't really care about specific error codes.
|
|
#define CrtErr() EBADF
|
|
|
|
FNFCIFILEPLACED(FciFilePlaced)
|
|
{
|
|
// Not watching for anything.
|
|
return 0;
|
|
}
|
|
|
|
FNFCIGETTEMPFILE(FciGetTempFile)
|
|
{
|
|
CHAR TempPath[MAX_PATH];
|
|
DWORD Len;
|
|
|
|
Len = GetTempPathA(sizeof(TempPath), TempPath);
|
|
if (Len == 0 || Len >= sizeof(TempPath))
|
|
{
|
|
TempPath[0] = '.';
|
|
TempPath[1] = '\0';
|
|
}
|
|
|
|
if (GetTempFileNameA(TempPath, "dbg", 0, pszTempName))
|
|
{
|
|
DeleteFileA(pszTempName);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
FNFCIGETNEXTCABINET(FciGetNextCabinet)
|
|
{
|
|
// No multi-cabinet activity expected, just fail.
|
|
return FALSE;
|
|
}
|
|
|
|
FNFCISTATUS(FciStatus)
|
|
{
|
|
// No status tracking.
|
|
return TRUE;
|
|
}
|
|
|
|
FNFCIGETOPENINFO(FciGetOpenInfo)
|
|
{
|
|
WIN32_FIND_DATAA FindData;
|
|
HANDLE FindHandle;
|
|
FILETIME Local;
|
|
|
|
FindHandle = FindFirstFileA(pszName, &FindData);
|
|
if (FindHandle == INVALID_HANDLE_VALUE)
|
|
{
|
|
return -1;
|
|
}
|
|
FindClose(FindHandle);
|
|
|
|
FileTimeToLocalFileTime(&FindData.ftLastWriteTime, &Local);
|
|
FileTimeToDosDateTime(&Local, pdate, ptime);
|
|
*pattribs = (WORD)(FindData.dwFileAttributes &
|
|
(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN |
|
|
FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE));
|
|
|
|
return _open(pszName, _O_RDONLY | _O_BINARY);
|
|
}
|
|
|
|
FNFCIOPEN(FciOpen)
|
|
{
|
|
int Result;
|
|
|
|
Result = _open(pszFile, oflag, pmode);
|
|
if (Result == -1)
|
|
{
|
|
*err = CrtErr();
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
FNFCIREAD(FciRead)
|
|
{
|
|
UINT Result;
|
|
|
|
Result = (UINT)_read((int)hf, memory, cb);
|
|
if (Result != cb)
|
|
{
|
|
*err = CrtErr();
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
FNFCIWRITE(FciWrite)
|
|
{
|
|
UINT Result;
|
|
|
|
Result = (UINT)_write((int)hf, memory, cb);
|
|
if (Result != cb)
|
|
{
|
|
*err = CrtErr();
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
FNFCICLOSE(FciClose)
|
|
{
|
|
int Result;
|
|
|
|
Result = _close((int)hf);
|
|
if (Result == -1)
|
|
{
|
|
*err = CrtErr();
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
FNFCISEEK(FciSeek)
|
|
{
|
|
long Result;
|
|
|
|
Result = _lseek((int)hf, dist, seektype);
|
|
if (Result == -1)
|
|
{
|
|
*err = CrtErr();
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
FNFCIDELETE(FciDelete)
|
|
{
|
|
int Result;
|
|
|
|
Result = _unlink(pszFile);
|
|
if (Result == -1)
|
|
{
|
|
*err = CrtErr();
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
HRESULT
|
|
CreateDumpCab(PCSTR FileName)
|
|
{
|
|
CCAB Cab;
|
|
PSTR Tail;
|
|
|
|
if (g_AddCab)
|
|
{
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
ZeroMemory(&Cab, sizeof(Cab));
|
|
|
|
//
|
|
// Split filename into path and tail components
|
|
// for szCabPath and szCab.
|
|
//
|
|
|
|
if (!CopyString(Cab.szCabPath, FileName, DIMA(Cab.szCabPath)))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
Tail = CabPathTail(Cab.szCabPath);
|
|
if (Tail > Cab.szCabPath)
|
|
{
|
|
if (!CopyString(Cab.szCab, Tail, DIMA(Cab.szCab)))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
*Tail = 0;
|
|
}
|
|
else
|
|
{
|
|
if (!CopyString(Cab.szCab, FileName, DIMA(Cab.szCab)))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
Cab.szCabPath[0] = 0;
|
|
}
|
|
|
|
g_AddCab = FCICreate(&g_AddCabErr, FciFilePlaced, CabAlloc, CabFree,
|
|
FciOpen, FciRead, FciWrite, FciClose,
|
|
FciSeek, FciDelete, FciGetTempFile,
|
|
&Cab, NULL);
|
|
if (!g_AddCab)
|
|
{
|
|
return CAB_HR(g_AddCabErr.erfOper);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
AddToDumpCab(PCSTR FileName)
|
|
{
|
|
if (!g_AddCab)
|
|
{
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
if (!FCIAddFile(g_AddCab, (PSTR)FileName, CabPathTail((PSTR)FileName),
|
|
FALSE, FciGetNextCabinet, FciStatus,
|
|
FciGetOpenInfo, tcompTYPE_LZX | tcompLZX_WINDOW_HI))
|
|
{
|
|
return CAB_HR(g_AddCabErr.erfOper);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void
|
|
CloseDumpCab(void)
|
|
{
|
|
if (!g_AddCab)
|
|
{
|
|
return;
|
|
}
|
|
|
|
FCIFlushCabinet(g_AddCab, FALSE, FciGetNextCabinet, FciStatus);
|
|
FCIDestroy(g_AddCab);
|
|
g_AddCab = NULL;
|
|
}
|
|
|
|
#endif // #ifndef _WIN32_WCE
|