762 lines
17 KiB
C
762 lines
17 KiB
C
#include <windows.h>
|
|
#include <lzexpand.h>
|
|
#include <fcntl.h>
|
|
|
|
/************************************************************************\
|
|
*
|
|
* NOTE!!!!
|
|
*
|
|
* While the 'Diamond' interfaced functions defined in this file are
|
|
* multi thread safe, EACH THREAD MUST ONLY HAVE ONE DIAMOND FILE
|
|
* OPEN AT A TIME! (ie. You can not nest InitDiamond()/TermDiamond()
|
|
* pairs in one thread of execution.)
|
|
*
|
|
\************************************************************************/
|
|
|
|
//
|
|
// diamond headers
|
|
//
|
|
#include <diamondd.h>
|
|
#include "mydiam.h"
|
|
|
|
HINSTANCE hCabinet;
|
|
DWORD cCabinetLoad;
|
|
typedef HFDI (DIAMONDAPI * tFDICreate) (PFNALLOC pfnalloc,
|
|
PFNFREE pfnfree,
|
|
PFNOPEN pfnopen,
|
|
PFNREAD pfnread,
|
|
PFNWRITE pfnwrite,
|
|
PFNCLOSE pfnclose,
|
|
PFNSEEK pfnseek,
|
|
int cpuType,
|
|
PERF perf);
|
|
|
|
typedef BOOL (DIAMONDAPI * tFDIIsCabinet)(HFDI hfdi,
|
|
INT_PTR hf,
|
|
PFDICABINETINFO pfdici);
|
|
|
|
typedef BOOL (DIAMONDAPI * tFDICopy)(HFDI hfdi,
|
|
char FAR *pszCabinet,
|
|
char FAR *pszCabPath,
|
|
int flags,
|
|
PFNFDINOTIFY pfnfdin,
|
|
PFNFDIDECRYPT pfnfdid,
|
|
void FAR *pvUser);
|
|
|
|
typedef BOOL (DIAMONDAPI * tFDIDestroy)(HFDI hfdi);
|
|
|
|
tFDICreate pFDICreate;
|
|
tFDIIsCabinet pFDIIsCabinet;
|
|
tFDICopy pFDICopy;
|
|
tFDIDestroy pFDIDestroy;
|
|
|
|
// this function is the same as CharNextA, available locally
|
|
extern LPSTR WINAPI VerCharNextA(LPCSTR lpCurrentChar);
|
|
|
|
INT CopyDateTimeStamp(INT_PTR doshFrom, INT_PTR doshTo)
|
|
{
|
|
FILETIME lpCreationTime, lpLastAccessTime, lpLastWriteTime;
|
|
|
|
if (!GetFileTime((HANDLE) doshFrom, &lpCreationTime, &lpLastAccessTime,
|
|
&lpLastWriteTime)) {
|
|
return ((INT)LZERROR_BADINHANDLE);
|
|
}
|
|
if (!SetFileTime((HANDLE) doshTo, &lpCreationTime, &lpLastAccessTime,
|
|
&lpLastWriteTime)) {
|
|
return ((INT)LZERROR_BADINHANDLE);
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
INT_PTR
|
|
DIAMONDAPI
|
|
SpdFdiOpen(
|
|
IN PSTR FileName,
|
|
IN int oflag,
|
|
IN int pmode
|
|
);
|
|
|
|
int
|
|
DIAMONDAPI
|
|
SpdFdiClose(
|
|
IN INT_PTR Handle
|
|
);
|
|
|
|
typedef struct _DIAMOND_INFO {
|
|
|
|
//
|
|
// A read handle to the source file.
|
|
//
|
|
INT_PTR SourceFileHandle;
|
|
|
|
//
|
|
// File names.
|
|
//
|
|
PSTR SourceFileName;
|
|
PSTR TargetFileName;
|
|
|
|
//
|
|
// Flag indicating whether to rename the target file.
|
|
//
|
|
BOOL RenameTargetFile;
|
|
|
|
//
|
|
// Pointer to LZ information structure.
|
|
// We'll fill in some of the fields to fool expand.
|
|
//
|
|
PLZINFO pLZI;
|
|
|
|
} DIAMOND_INFO, *PDIAMOND_INFO;
|
|
|
|
|
|
PSTR
|
|
StringRevChar(
|
|
IN PSTR String,
|
|
IN CHAR Char
|
|
)
|
|
{
|
|
//
|
|
// Although not the most efficient possible algoeithm in each case,
|
|
// this algorithm is correct for unicode, sbcs, or dbcs.
|
|
//
|
|
PCHAR Occurrence,Next;
|
|
|
|
//
|
|
// Check each character in the string and remember
|
|
// the most recently encountered occurrence of the desired char.
|
|
//
|
|
for (Occurrence=NULL,Next=VerCharNextA(String); *String; ) {
|
|
|
|
if (!memcmp(String,&Char,(int)((PUCHAR)Next-(PUCHAR)String))) {
|
|
Occurrence = String;
|
|
}
|
|
|
|
String = Next;
|
|
Next = VerCharNextA(Next);
|
|
}
|
|
|
|
//
|
|
// Return address of final occurrence of the character
|
|
// (will be NULL if not found at all).
|
|
//
|
|
return (Occurrence);
|
|
}
|
|
|
|
|
|
INT_PTR
|
|
DIAMONDAPI
|
|
DiamondNotifyFunction(
|
|
IN FDINOTIFICATIONTYPE Operation,
|
|
IN PFDINOTIFICATION Parameters
|
|
)
|
|
{
|
|
switch (Operation) {
|
|
|
|
case fdintCABINET_INFO:
|
|
case fdintNEXT_CABINET:
|
|
case fdintPARTIAL_FILE:
|
|
case fdintENUMERATE:
|
|
|
|
//
|
|
// Cabinet management functions which we don't use.
|
|
// Return success.
|
|
//
|
|
return (0);
|
|
|
|
case fdintCOPY_FILE:
|
|
|
|
//
|
|
// Diamond is asking us whether we want to copy the file.
|
|
//
|
|
{
|
|
PDIAMOND_INFO Info = (PDIAMOND_INFO)Parameters->pv;
|
|
HFILE h;
|
|
|
|
//
|
|
// If we need to rename the target file, do that here.
|
|
// The name stored in the cabinet file will be used as
|
|
// the uncompressed name.
|
|
//
|
|
if (Info->RenameTargetFile) {
|
|
|
|
PSTR p,q;
|
|
|
|
//
|
|
// Find the start of the filename part of the target.
|
|
//
|
|
if (p = StringRevChar(Info->TargetFileName,'\\')) {
|
|
p++;
|
|
} else {
|
|
p = Info->TargetFileName;
|
|
}
|
|
|
|
//
|
|
// Find the start of the filename part of the name in the cabinet.
|
|
//
|
|
if (q = StringRevChar(Parameters->psz1,'\\')) {
|
|
q++;
|
|
} else {
|
|
q = Parameters->psz1;
|
|
}
|
|
|
|
//
|
|
// Copy the filename part of the name in the cabinet over
|
|
// the filename part of the name in the target spec.
|
|
//
|
|
lstrcpyA(p,q);
|
|
}
|
|
|
|
{
|
|
// Check they're not the same file
|
|
|
|
CHAR Source[MAX_PATH];
|
|
CHAR Target[MAX_PATH];
|
|
PSTR FileName;
|
|
DWORD PathLenSource;
|
|
DWORD PathLenTarget;
|
|
|
|
PathLenSource = GetFullPathNameA(Info->SourceFileName,
|
|
MAX_PATH,
|
|
Source,
|
|
&FileName);
|
|
PathLenTarget = GetFullPathNameA(Info->TargetFileName,
|
|
MAX_PATH,
|
|
Target,
|
|
&FileName);
|
|
|
|
if (PathLenSource == 0 || PathLenSource >= MAX_PATH ||
|
|
PathLenTarget == 0 || PathLenTarget >= MAX_PATH ||
|
|
lstrcmpiA(Source, Target) == 0) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Remember the uncompressed size and open the file.
|
|
// Returns -1 if an error occurs opening the file.
|
|
//
|
|
Info->pLZI->cblOutSize = Parameters->cb;
|
|
h = _lcreat(Info->TargetFileName,0);
|
|
if (h == HFILE_ERROR) {
|
|
DiamondLastIoError = LZERROR_BADOUTHANDLE;
|
|
return (-1);
|
|
}
|
|
return (h);
|
|
}
|
|
|
|
case fdintCLOSE_FILE_INFO:
|
|
|
|
//
|
|
// Diamond is done with the target file and wants us to close it.
|
|
// (ie, this is the counterpart to fdint_COPY_FILE).
|
|
//
|
|
{
|
|
PDIAMOND_INFO Info = (PDIAMOND_INFO)Parameters->pv;
|
|
|
|
CopyDateTimeStamp(Info->SourceFileHandle,Parameters->hf);
|
|
_lclose((HFILE)Parameters->hf);
|
|
}
|
|
return (TRUE);
|
|
|
|
default:
|
|
|
|
//
|
|
// invalid operation
|
|
//
|
|
return(-1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
PVOID
|
|
DIAMONDAPI
|
|
SpdFdiAlloc(
|
|
IN ULONG NumberOfBytes
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback used by FDICopy to allocate memory.
|
|
|
|
Arguments:
|
|
|
|
NumberOfBytes - supplies desired size of block.
|
|
|
|
Return Value:
|
|
|
|
Returns pointer to a block of memory or NULL
|
|
if memory cannot be allocated.
|
|
|
|
--*/
|
|
|
|
{
|
|
return ((PVOID)LocalAlloc(LMEM_FIXED,NumberOfBytes));
|
|
}
|
|
|
|
|
|
VOID
|
|
DIAMONDAPI
|
|
SpdFdiFree(
|
|
IN PVOID Block
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback used by FDICopy to free a memory block.
|
|
The block must have been allocated with SpdFdiAlloc().
|
|
|
|
Arguments:
|
|
|
|
Block - supplies pointer to block of memory to be freed.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
LocalFree((HLOCAL)Block);
|
|
}
|
|
|
|
|
|
INT_PTR
|
|
DIAMONDAPI
|
|
SpdFdiOpen(
|
|
IN PSTR FileName,
|
|
IN int oflag,
|
|
IN int pmode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback used by FDICopy to open files.
|
|
|
|
Arguments:
|
|
|
|
FileName - supplies name of file to be opened.
|
|
|
|
oflag - supplies flags for open.
|
|
|
|
pmode - supplies additional flags for open.
|
|
|
|
Return Value:
|
|
|
|
Handle to open file or -1 if error occurs.
|
|
|
|
--*/
|
|
|
|
{
|
|
HFILE h;
|
|
int OpenMode;
|
|
|
|
if (oflag & _O_WRONLY) {
|
|
OpenMode = OF_WRITE;
|
|
} else {
|
|
if (oflag & _O_RDWR) {
|
|
OpenMode = OF_READWRITE;
|
|
} else {
|
|
OpenMode = OF_READ;
|
|
}
|
|
}
|
|
|
|
h = _lopen(FileName,OpenMode | OF_SHARE_DENY_WRITE);
|
|
|
|
if (h == HFILE_ERROR) {
|
|
DiamondLastIoError = LZERROR_BADINHANDLE;
|
|
return (-1);
|
|
}
|
|
|
|
return ((INT_PTR)h);
|
|
}
|
|
|
|
|
|
UINT
|
|
DIAMONDAPI
|
|
SpdFdiRead(
|
|
IN INT_PTR Handle,
|
|
OUT PVOID pv,
|
|
IN UINT ByteCount
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback used by FDICopy to read from a file.
|
|
|
|
Arguments:
|
|
|
|
Handle - supplies handle to open file to be read from.
|
|
|
|
pv - supplies pointer to buffer to receive bytes we read.
|
|
|
|
ByteCount - supplies number of bytes to read.
|
|
|
|
Return Value:
|
|
|
|
Number of bytes read (ByteCount) or -1 if an error occurs.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT rc;
|
|
|
|
rc = _lread((HFILE)Handle,pv,ByteCount);
|
|
|
|
if (rc == HFILE_ERROR) {
|
|
rc = (UINT)(-1);
|
|
DiamondLastIoError = LZERROR_READ;
|
|
}
|
|
|
|
return (rc);
|
|
}
|
|
|
|
|
|
UINT
|
|
DIAMONDAPI
|
|
SpdFdiWrite(
|
|
IN INT_PTR Handle,
|
|
IN PVOID pv,
|
|
IN UINT ByteCount
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback used by FDICopy to write to a file.
|
|
|
|
Arguments:
|
|
|
|
Handle - supplies handle to open file to be written to.
|
|
|
|
pv - supplies pointer to buffer containing bytes to write.
|
|
|
|
ByteCount - supplies number of bytes to write.
|
|
|
|
Return Value:
|
|
|
|
Number of bytes written (ByteCount) or -1 if an error occurs.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT rc;
|
|
|
|
rc = _lwrite((HFILE)Handle,pv,ByteCount);
|
|
|
|
if (rc == HFILE_ERROR) {
|
|
|
|
DiamondLastIoError = (GetLastError() == ERROR_DISK_FULL) ? LZERROR_WRITE : LZERROR_BADOUTHANDLE;
|
|
|
|
} else {
|
|
|
|
if (rc != ByteCount) {
|
|
//
|
|
// let caller interpret return value but record last error just in case
|
|
//
|
|
DiamondLastIoError = LZERROR_WRITE;
|
|
}
|
|
}
|
|
|
|
return (rc);
|
|
}
|
|
|
|
|
|
int
|
|
DIAMONDAPI
|
|
SpdFdiClose(
|
|
IN INT_PTR Handle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback used by FDICopy to close files.
|
|
|
|
Arguments:
|
|
|
|
Handle - handle of file to close.
|
|
|
|
Return Value:
|
|
|
|
0 (success).
|
|
|
|
--*/
|
|
|
|
{
|
|
_lclose((HFILE)Handle);
|
|
return (0);
|
|
}
|
|
|
|
|
|
LONG
|
|
DIAMONDAPI
|
|
SpdFdiSeek(
|
|
IN INT_PTR Handle,
|
|
IN long Distance,
|
|
IN int SeekType
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback used by FDICopy to seek files.
|
|
|
|
Arguments:
|
|
|
|
Handle - handle of file to close.
|
|
|
|
Distance - supplies distance to seek. Interpretation of this
|
|
parameter depends on the value of SeekType.
|
|
|
|
SeekType - supplies a value indicating how Distance is to be
|
|
interpreted; one of SEEK_SET, SEEK_CUR, SEEK_END.
|
|
|
|
Return Value:
|
|
|
|
New file offset or -1 if an error occurs.
|
|
|
|
--*/
|
|
|
|
{
|
|
LONG rc;
|
|
|
|
rc = _llseek((HFILE)Handle,Distance,SeekType);
|
|
|
|
if (rc == HFILE_ERROR) {
|
|
DiamondLastIoError = LZERROR_BADINHANDLE;
|
|
rc = -1L;
|
|
}
|
|
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// this function is linked in from ntdll
|
|
//
|
|
extern int sprintf(LPSTR, LPCSTR, ...);
|
|
|
|
INT
|
|
ExpandDiamondFile(
|
|
IN PSTR SourceFileName, // Note ASCII
|
|
IN PTSTR TargetFileNameT,
|
|
IN BOOL RenameTarget,
|
|
OUT PLZINFO pLZI
|
|
)
|
|
{
|
|
BOOL b;
|
|
INT rc;
|
|
INT_PTR h;
|
|
DIAMOND_INFO DiamondInfo;
|
|
CHAR TargetFileName[MAX_PATH];
|
|
|
|
sprintf(TargetFileName, "%ls", TargetFileNameT);
|
|
|
|
if (!FdiContext) {
|
|
return (LZERROR_BADVALUE);
|
|
}
|
|
|
|
DiamondLastIoError = TRUE;
|
|
|
|
//
|
|
// Get a handle to the source to use to
|
|
// copy the date and time stamp.
|
|
//
|
|
h = SpdFdiOpen(SourceFileName,_O_RDONLY,0);
|
|
if (h == -1) {
|
|
return (LZERROR_BADINHANDLE);
|
|
}
|
|
|
|
pLZI->cblInSize = GetFileSize((HANDLE)h,NULL);
|
|
if (pLZI->cblInSize == -1) {
|
|
SpdFdiClose(h);
|
|
return (LZERROR_BADINHANDLE);
|
|
}
|
|
|
|
DiamondInfo.SourceFileHandle = h;
|
|
DiamondInfo.SourceFileName = SourceFileName;
|
|
DiamondInfo.TargetFileName = TargetFileName;
|
|
DiamondInfo.RenameTargetFile = RenameTarget;
|
|
DiamondInfo.pLZI = pLZI;
|
|
|
|
b = pFDICopy(
|
|
FdiContext,
|
|
SourceFileName, // pass the whole path as the name
|
|
"", // don't bother with the path part
|
|
0, // flags
|
|
DiamondNotifyFunction,
|
|
NULL, // no decryption
|
|
&DiamondInfo
|
|
);
|
|
|
|
if (b) {
|
|
|
|
rc = TRUE;
|
|
|
|
} else {
|
|
|
|
switch (FdiError.erfOper) {
|
|
|
|
case FDIERROR_CORRUPT_CABINET:
|
|
case FDIERROR_UNKNOWN_CABINET_VERSION:
|
|
case FDIERROR_BAD_COMPR_TYPE:
|
|
rc = LZERROR_READ; // causes SID_FORMAT_ERROR message
|
|
break;
|
|
|
|
case FDIERROR_ALLOC_FAIL:
|
|
rc = LZERROR_GLOBALLOC;
|
|
break;
|
|
|
|
case FDIERROR_TARGET_FILE:
|
|
case FDIERROR_USER_ABORT:
|
|
rc = DiamondLastIoError;
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// The rest of the errors are not handled specially.
|
|
//
|
|
rc = LZERROR_BADVALUE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Remove the partial target file.
|
|
//
|
|
DeleteFileA(TargetFileName);
|
|
}
|
|
|
|
SpdFdiClose(h);
|
|
|
|
return (rc);
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsDiamondFile(
|
|
IN PSTR FileName
|
|
)
|
|
{
|
|
FDICABINETINFO CabinetInfo;
|
|
BOOL b;
|
|
INT_PTR h;
|
|
|
|
if (!FdiContext) {
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// Open the file such that the handle is valid for use
|
|
// in the diamond context (ie, seek, read routines above).
|
|
//
|
|
h = SpdFdiOpen(FileName,_O_RDONLY,0);
|
|
if (h == -1) {
|
|
return (FALSE);
|
|
}
|
|
|
|
b = pFDIIsCabinet(FdiContext,h,&CabinetInfo);
|
|
|
|
SpdFdiClose(h);
|
|
|
|
return (b);
|
|
}
|
|
|
|
|
|
DWORD
|
|
InitDiamond(
|
|
VOID
|
|
)
|
|
{
|
|
PDIAMOND_CONTEXT pdcx;
|
|
|
|
if (!GotDmdTlsSlot())
|
|
return VIF_OUTOFMEMORY;
|
|
|
|
if (GotDmdContext())
|
|
return VIF_OUTOFMEMORY;
|
|
|
|
pdcx = LocalAlloc(LPTR, sizeof(DIAMOND_CONTEXT));
|
|
|
|
if (pdcx == NULL || !TlsSetValue(itlsDiamondContext, pdcx)) {
|
|
/*
|
|
* For some unknown reason, we can't associate
|
|
* our thread storage with the slot, so free
|
|
* it and say we never got one.
|
|
*/
|
|
|
|
if (pdcx) {
|
|
LocalFree(pdcx);
|
|
}
|
|
return VIF_OUTOFMEMORY;
|
|
}
|
|
|
|
if (!cCabinetLoad) {
|
|
hCabinet = LoadLibraryW(L"CABINET.DLL");
|
|
if (!hCabinet) {
|
|
return (VIF_CANNOTLOADCABINET);
|
|
}
|
|
pFDICreate = (tFDICreate) GetProcAddress(hCabinet, "FDICreate");
|
|
pFDIDestroy = (tFDIDestroy) GetProcAddress(hCabinet, "FDIDestroy");
|
|
pFDIIsCabinet = (tFDIIsCabinet) GetProcAddress(hCabinet, "FDIIsCabinet");
|
|
pFDICopy = (tFDICopy) GetProcAddress(hCabinet, "FDICopy");
|
|
|
|
if (!(pFDICreate && pFDIDestroy && pFDIIsCabinet && pFDICopy)) {
|
|
FreeLibrary(hCabinet);
|
|
return (VIF_CANNOTLOADCABINET);
|
|
}
|
|
|
|
if (InterlockedExchangeAdd(&cCabinetLoad, 1) != 0) {
|
|
// Multiple threads are attempting to LoadLib
|
|
// Free one here.
|
|
FreeLibrary(hCabinet);
|
|
}
|
|
}
|
|
|
|
SetFdiContext( pFDICreate(
|
|
SpdFdiAlloc,
|
|
SpdFdiFree,
|
|
SpdFdiOpen,
|
|
SpdFdiRead,
|
|
SpdFdiWrite,
|
|
SpdFdiClose,
|
|
SpdFdiSeek,
|
|
cpuUNKNOWN,
|
|
&FdiError
|
|
));
|
|
|
|
return ((FdiContext == NULL) ? VIF_CANNOTLOADCABINET : 0);
|
|
}
|
|
|
|
|
|
VOID
|
|
TermDiamond(
|
|
VOID
|
|
)
|
|
{
|
|
if (!GotDmdTlsSlot() || !GotDmdContext())
|
|
return;
|
|
|
|
if (FdiContext) {
|
|
pFDIDestroy(FdiContext);
|
|
SetFdiContext( NULL );
|
|
}
|
|
|
|
LocalFree( TlsGetValue(itlsDiamondContext) );
|
|
TlsSetValue(itlsDiamondContext, NULL);
|
|
}
|
|
|
|
|
|
|