/*++ Copyright (c) 1991-1999, Microsoft Corporation All rights reserved. Module Name: diamond.c Abstract: Implement File Decompression Interface -FDI- for Cabinet files. Revision History: 04-20-1999 SamerA Created. --*/ #include "muisetup.h" #include #include #include #include #define STRSAFE_LIB #include // // Module Global Variables // // // Cabinet DLL handle HINSTANCE hCabinetDll; HFDI ghfdi; // diamond FDI context // // DLL Function pointers // typedef HFDI (DIAMONDAPI *PFNFDICREATE)( PFNALLOC pfnalloc, PFNFREE pfnfree, PFNOPEN pfnopen, PFNREAD pfnread, PFNWRITE pfnwrite, PFNCLOSE pfnclose, PFNSEEK pfnseek, int cpuType, PERF perf); typedef BOOL (DIAMONDAPI *PFNFDIISCABINET)( HFDI hfdi, INT_PTR hf, PFDICABINETINFO pfdici); typedef BOOL (DIAMONDAPI *PFNFDICOPY)( HFDI hfdi, char *pszCabinet, char *pszCabPath, int flags, PFNFDINOTIFY pfnfdin, PFNFDIDECRYPT pfnfdid, void *pvUser); typedef BOOL (DIAMONDAPI *PFNFDIDESTROY)( HFDI hfdi); PFNFDICREATE pfnFDICreate; PFNFDICOPY pfnFDICopy; PFNFDIISCABINET pfnFDIIsCabinet; PFNFDIDESTROY pfnFDIDestroy; //-------------------------------------------------------------------------// // FDI EXTERNAL ROUTINES // //-------------------------------------------------------------------------// //////////////////////////////////////////////////////////////////////////// // // FDICreate // // Tries to create an FDI context. Will load cabinet.dll and hook necessary // function pointers. // // 04-20-99 SamerA Created. //////////////////////////////////////////////////////////////////////////// HFDI DIAMONDAPI FDICreate( PFNALLOC pfnalloc, PFNFREE pfnfree, PFNOPEN pfnopen, PFNREAD pfnread, PFNWRITE pfnwrite, PFNCLOSE pfnclose, PFNSEEK pfnseek, int cpuType, PERF perf) { HFDI hfdi; // // Load cabinet DLL // hCabinetDll = LoadLibrary(TEXT("CABINET.DLL")); if (hCabinetDll == NULL) { return NULL; } // // Hook function pointers // pfnFDICreate = (PFNFDICREATE) GetProcAddress(hCabinetDll, "FDICreate"); pfnFDICopy = (PFNFDICOPY) GetProcAddress(hCabinetDll, "FDICopy"); pfnFDIIsCabinet = (PFNFDIISCABINET) GetProcAddress(hCabinetDll, "FDIIsCabinet"); pfnFDIDestroy = (PFNFDIDESTROY) GetProcAddress(hCabinetDll, "FDIDestroy"); if ((pfnFDICreate == NULL) || (pfnFDICopy == NULL) || (pfnFDIIsCabinet == NULL) || (pfnFDIDestroy == NULL)) { FreeLibrary( hCabinetDll ); return NULL; } // // Try to create an FDI context // hfdi = pfnFDICreate( pfnalloc, pfnfree, pfnopen, pfnread, pfnwrite, pfnclose, pfnseek, cpuType, perf); if (hfdi == NULL) { FreeLibrary(hCabinetDll); } return hfdi; } //////////////////////////////////////////////////////////////////////////// // // FDIIsCabinet // // Determines if file is a cabinet, returns info if it is // // 04-20-99 SamerA Created. //////////////////////////////////////////////////////////////////////////// BOOL DIAMONDAPI FDIIsCabinet( HFDI hfdi, INT_PTR hf, PFDICABINETINFO pfdici) { if (pfnFDIIsCabinet == NULL) { return FALSE; } return (pfnFDIIsCabinet(hfdi,hf,pfdici)); } //////////////////////////////////////////////////////////////////////////// // // FDICopy // // Extracts files from a cabinet // // 04-20-99 SamerA Created. //////////////////////////////////////////////////////////////////////////// BOOL DIAMONDAPI FDICopy( HFDI hfdi, char *pszCabinet, char *pszCabPath, int flags, PFNFDINOTIFY pfnfdin, PFNFDIDECRYPT pfnfdid, void *pvUser) { if (pfnFDICopy == NULL) { return FALSE; } return (pfnFDICopy(hfdi,pszCabinet,pszCabPath,flags,pfnfdin,pfnfdid,pvUser)); } //////////////////////////////////////////////////////////////////////////// // // FDIDestroy // // Destroy an FDI context. Should be called when you're done with the HFDI. // // 04-20-99 SamerA Created. //////////////////////////////////////////////////////////////////////////// BOOL DIAMONDAPI FDIDestroy( HFDI hfdi) { BOOL bRet; if (pfnFDIDestroy == NULL) { return FALSE; } bRet = pfnFDIDestroy( hfdi ); if (bRet == TRUE) { FreeLibrary(hCabinetDll); } return bRet; } //-------------------------------------------------------------------------// // FDI SUPPORT ROUTINES // //-------------------------------------------------------------------------// PVOID DIAMONDAPI DiamondMemAlloc( IN ULONG NumberOfBytes ) { return ((PVOID)LocalAlloc(LMEM_FIXED, NumberOfBytes)); } VOID DIAMONDAPI DiamondMemFree( IN PVOID Block ) { if (Block) { LocalFree( (HLOCAL)Block ); } } INT_PTR DIAMONDAPI DiamondFileOpen( IN PSTR FileName, IN int oflag, IN int pmode ) { 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) { return -1; } return ((INT_PTR) h); } UINT DIAMONDAPI DiamondFileRead( IN INT_PTR Handle, OUT PVOID pv, IN UINT ByteCount ) { UINT rc; rc = _lread((HFILE)Handle, pv, ByteCount); if (rc == HFILE_ERROR) { rc = (UINT)(-1); } return rc; } UINT DIAMONDAPI DiamondFileWrite( IN INT_PTR Handle, IN PVOID pv, IN UINT ByteCount ) { UINT rc; rc = _lwrite((HFILE)Handle, (LPCSTR)pv, ByteCount); return rc; } int DIAMONDAPI DiamondFileClose( IN INT_PTR Handle ) { _lclose( (HFILE)Handle ); return 0; } LONG DIAMONDAPI DiamondFileSeek( IN INT_PTR Handle, IN long Distance, IN int SeekType ) { LONG rc; rc = _llseek((HFILE)Handle, Distance, SeekType); if (rc == HFILE_ERROR) { rc = -1L; } return rc; } INT_PTR DIAMONDAPI DiamondNotifyFunction( IN FDINOTIFICATIONTYPE Operation, IN PFDINOTIFICATION Parameters ) { HRESULT hresult; switch (Operation) { case fdintCABINET_INFO: // general information about the cabinet return 0; break; case fdintPARTIAL_FILE: // first file in cabinet is continuation return 0; break; case fdintCOPY_FILE: // file to be copied { HFILE handle; char destination[256]; PDIAMOND_PACKET pDiamond = (PDIAMOND_PACKET) Parameters->pv; // // Check to see if we just want the original file name // if (pDiamond->flags & DIAMOND_GET_DEST_FILE_NAME) { //*STRSAFE* strcpy( pDiamond->szDestFilePath, Parameters->psz1 ); hresult = StringCchCopyA(pDiamond->szDestFilePath , ARRAYSIZE(pDiamond->szDestFilePath), Parameters->psz1 ); if (!SUCCEEDED(hresult)) { return -1; } return 0; } //*STRSAFE* sprintf( destination, "%s%s", pDiamond->szDestFilePath, Parameters->psz1 ); hresult = StringCchPrintfA(destination , ARRAYSIZE(destination), "%s%s", pDiamond->szDestFilePath, Parameters->psz1 ); if (!SUCCEEDED(hresult)) { return -1; } handle = _lcreat(destination, 0); if (handle == HFILE_ERROR) { return -1; } return handle; } break; case fdintCLOSE_FILE_INFO: // close the file, set relevant info { HANDLE handle; DWORD attrs; char destination[256]; PDIAMOND_PACKET pDiamond = (PDIAMOND_PACKET) Parameters->pv; if (pDiamond->flags & DIAMOND_GET_DEST_FILE_NAME) { return 0; } //*STRSAFE* sprintf( destination, "%s%s", pDiamond->szDestFilePath, Parameters->psz1); hresult = StringCchPrintfA(destination , ARRAYSIZE(destination), "%s%s", pDiamond->szDestFilePath, Parameters->psz1); if (!SUCCEEDED(hresult)) { return -1; } _lclose( (HFILE)Parameters->hf ); // // Set date/time // // Need Win32 type handle for to set date/time // handle = CreateFileA( destination, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if (handle != INVALID_HANDLE_VALUE) { FILETIME datetime; if (TRUE == DosDateTimeToFileTime( Parameters->date, Parameters->time, &datetime)) { FILETIME local_filetime; if (TRUE == LocalFileTimeToFileTime( &datetime, &local_filetime)) { SetFileTime( handle, &local_filetime, NULL, &local_filetime ); } } CloseHandle(handle); } // // Mask out attribute bits other than readonly, // hidden, system, and archive, since the other // attribute bits are reserved for use by // the cabinet format. // attrs = Parameters->attribs; attrs &= (_A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH); SetFileAttributesA( destination, attrs ); return TRUE; } break; case fdintNEXT_CABINET: // file continued to next cabinet return 0; break; } return 0; } //-------------------------------------------------------------------------// // MUISETUP-SUPPORT ROUTINES // //-------------------------------------------------------------------------// //////////////////////////////////////////////////////////////////////////// // // Muisetup_InitDiamond // // Initialize diamond DLL. // // 04-23-99 SamerA Created. //////////////////////////////////////////////////////////////////////////// HFDI Muisetup_InitDiamond() { ERF erf; if (!ghfdi) { ghfdi = FDICreate( DiamondMemAlloc, DiamondMemFree, DiamondFileOpen, DiamondFileRead, DiamondFileWrite, DiamondFileClose, DiamondFileSeek, cpuUNKNOWN, &erf ); } return ghfdi; } //////////////////////////////////////////////////////////////////////////// // // Muisetup_FreeDiamond // // Free diamond dll. Should be called at application shutdown. // // 04-23-99 SamerA Created. //////////////////////////////////////////////////////////////////////////// BOOL Muisetup_FreeDiamond() { BOOL bRet = TRUE; if (ghfdi) { bRet = FDIDestroy(ghfdi); } return bRet; } //////////////////////////////////////////////////////////////////////////// // // Muisetup_DiamondReset // // Should be called at the start of processing a file to copy. // // 04-23-99 SamerA Created. //////////////////////////////////////////////////////////////////////////// void Muisetup_DiamondReset( PDIAMOND_PACKET pDiamond) { pDiamond->flags = DIAMOND_NONE; return; } //////////////////////////////////////////////////////////////////////////// // // Muisetup_IsDiamondFile // // Determines if a file is a diamond file, and if so, returns its original // name. // // 04-23-99 SamerA Created. //////////////////////////////////////////////////////////////////////////// BOOL Muisetup_IsDiamondFile( PWSTR pwszFileName, PWSTR pwszOriginalName, INT nSize, PDIAMOND_PACKET pDiamond) { INT_PTR hf; BOOL bRet; int nCount; char *p; FDICABINETINFO fdici; HFDI hfdi = ghfdi; HRESULT hresult; if (!hfdi) { #if SAMER_DBG OutputDebugStringA("Muisetup_IsDiamondFile : No HFDI context\n"); #endif return FALSE; } // // Init the diamond packet // pDiamond->flags = DIAMOND_NONE; if ((nCount = WideCharToMultiByte( CP_ACP, 0, pwszFileName, -1, pDiamond->szSrcFilePath, sizeof( pDiamond->szSrcFilePath ), NULL, NULL )) == 0) { #if SAMER_DBG OutputDebugStringA("Muisetup_IsDiamondFile : WideCharToMultiByte failed\n"); #endif return FALSE; } pDiamond->szSrcFilePath[ nCount ] = '\0'; hf = DiamondFileOpen( pDiamond->szSrcFilePath, _O_BINARY | _O_RDONLY | _O_SEQUENTIAL, 0 ); if (hf == -1) { #if SAMER_DBG OutputDebugStringA("Muisetup_IsDiamondFile : file_open failed\n"); #endif return FALSE; } bRet = FDIIsCabinet( hfdi, hf, &fdici ); DiamondFileClose( hf ); // // If succeeded, then let's setup everything else // to get the correct original file name // if (bRet) { pDiamond->flags |= DIAMOND_GET_DEST_FILE_NAME; p = strrchr(pDiamond->szSrcFilePath, '\\'); if (p == NULL) { //*STRSAFE* strcpy(pDiamond->szSrcFileName, pDiamond->szSrcFilePath); hresult = StringCchCopyA(pDiamond->szSrcFileName , ARRAYSIZE(pDiamond->szSrcFileName), pDiamond->szSrcFilePath); if (!SUCCEEDED(hresult)) { return FALSE; } //*STRSAFE* strcpy(pDiamond->szSrcFilePath, ""); hresult = StringCchCopyA(pDiamond->szSrcFilePath , ARRAYSIZE(pDiamond->szSrcFilePath), ""); if (!SUCCEEDED(hresult)) { return FALSE; } } else { //*STRSAFE* strcpy(pDiamond->szSrcFileName, p+1); hresult = StringCchCopyA(pDiamond->szSrcFileName , ARRAYSIZE(pDiamond->szSrcFileName), p+1); if (!SUCCEEDED(hresult)) { return FALSE; } p[ 1 ] = '\0'; } //*STRSAFE* strcpy( pDiamond->szDestFilePath, "c:\\samer\\" ); hresult = StringCchCopyA(pDiamond->szDestFilePath , ARRAYSIZE(pDiamond->szDestFilePath), "c:\\samer\\" ); if (!SUCCEEDED(hresult)) { return FALSE; } if (Muisetup_CopyDiamondFile( pDiamond, NULL)) { // // Convert the original file name back to Unicode // nCount = MultiByteToWideChar( CP_ACP, 0, pDiamond->szDestFilePath, -1, pwszOriginalName, nSize ); if (!nCount) { return FALSE; } pwszOriginalName[ nCount ] = UNICODE_NULL; pDiamond->flags = DIAMOND_FILE; #if SAMER_DBG { BYTE byBuf[200]; //*STRSAFE* wsprintfA(byBuf, "SrcFile = %s%s, OriginalFileName=%s\n", pDiamond->szSrcFilePath, pDiamond->szSrcFileName,pDiamond->szDestFilePath); hresult = StringCchPrintfA(byBuf , ARRAYSIZE(byBuf), "SrcFile = %s%s, OriginalFileName=%s\n", pDiamond->szSrcFilePath, pDiamond->szSrcFileName,pDiamond->szDestFilePath); if (!SUCCEEDED(hresult)) { return FALSE; } OutputDebugStringA(byBuf); } #endif } pDiamond->flags &= ~DIAMOND_GET_DEST_FILE_NAME; } return bRet; } //////////////////////////////////////////////////////////////////////////// // // Muisetup_CopyDiamondFile // // Copies and expands a diamond file. // // 04-23-99 SamerA Created. //////////////////////////////////////////////////////////////////////////// BOOL Muisetup_CopyDiamondFile( PDIAMOND_PACKET pDiamond, PWSTR pwszCopyTo) { char szDestPath[ MAX_PATH + 1]; char *p; int nCount; BOOL bRet; HFDI hfdi = ghfdi; HRESULT hresult; // // Validate that this is a diamond file // if ((!hfdi) || (pDiamond->flags == DIAMOND_NONE)) { return FALSE; } // // Validate flags // if (!(pDiamond->flags & (DIAMOND_FILE | DIAMOND_GET_DEST_FILE_NAME))) { return FALSE; } #if SAMER_DBG { BYTE byBuf[100]; //*STRSAFE* wsprintfA(byBuf, "DiamondCopy called for %s, flags = %lx\n", pDiamond->szSrcFileName, pDiamond->flags); hresult = StringCchPrintfA(byBuf , ARRAYSIZE(byBuf), "DiamondCopy called for %s, flags = %lx\n", pDiamond->szSrcFileName, pDiamond->flags); if (!SUCCEEDED(hresult)) { return FALSE; } OutputDebugStringA(byBuf); } #endif if (!(pDiamond->flags & DIAMOND_GET_DEST_FILE_NAME)) { if ((nCount = WideCharToMultiByte( CP_ACP, 0, pwszCopyTo, -1, szDestPath, sizeof( szDestPath ), NULL, NULL )) == 0) { return FALSE; } p = strrchr(szDestPath, '\\'); if (p) { p[1] = '\0'; } else { szDestPath[ nCount ] = '\\'; szDestPath[ nCount + 1 ] = '\0'; } //*STRSAFE* strcpy( pDiamond->szDestFilePath, szDestPath ); hresult = StringCchCopyA(pDiamond->szDestFilePath , ARRAYSIZE(pDiamond->szDestFilePath), szDestPath ); if (!SUCCEEDED(hresult)) { return FALSE; } } bRet = FDICopy( hfdi, pDiamond->szSrcFileName, pDiamond->szSrcFilePath, 0, DiamondNotifyFunction, NULL, pDiamond); #if SAMER_DBG { BYTE byBuf[200]; //*STRSAFE* wsprintfA(byBuf, "SrcFile = %s%s, DestPath=%s, Status=%lx\n", pDiamond->szSrcFilePath,pDiamond->szSrcFileName,pDiamond->szDestFilePath, bRet); hresult = StringCchPrintfA(byBuf , ARRAYSIZE(byBuf), "SrcFile = %s%s, DestPath=%s, Status=%lx\n", pDiamond->szSrcFilePath,pDiamond->szSrcFileName,pDiamond->szDestFilePath, bRet); if (!SUCCEEDED(hresult)) { return FALSE; } OutputDebugStringA(byBuf); } #endif return bRet; }