#include "stdafx.h" #include "Cabinet.h" #include "../../solo/solo.h" #include #include #include #include #include #pragma comment(lib, "cabinet.lib") FNFCIFILEPLACED(FilePlaced) { UNREFERENCED_PARAMETER(pszFile); UNREFERENCED_PARAMETER(pccab); UNREFERENCED_PARAMETER(pv); UNREFERENCED_PARAMETER(cbFile); if(!fContinuation) { DBG_TEXT("Placed file \"%s\" in cabinet \"%s\"", pszFile, pccab->szCab); } return 0; } FNFCIALLOC(CabAlloc) { return WinLib::Alloc(cb); } FNFCIFREE(CabFree) { WinLib::Free(memory); } FNFCIOPEN(CabFileOpen) { UNREFERENCED_PARAMETER(pv); HANDLE hFile = NULL; DWORD dwDesiredAccess = 0; DWORD dwCreationDisposition = 0; DWORD attributes = FILE_FLAG_SEQUENTIAL_SCAN | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED; UNREFERENCED_PARAMETER(pv); UNREFERENCED_PARAMETER(pmode); if ( oflag & _O_RDWR ) { dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; } else if ( oflag & _O_WRONLY ) { dwDesiredAccess = GENERIC_WRITE; } else { dwDesiredAccess = GENERIC_READ; } if ( oflag & _O_CREAT ) { dwCreationDisposition = CREATE_ALWAYS; attributes |= FILE_ATTRIBUTE_TEMPORARY; } else { dwCreationDisposition = OPEN_EXISTING; } DBG_TEXT("Creating cab file \"%s\"", pszFile); hFile = CreateFileA( pszFile, dwDesiredAccess, FILE_SHARE_READ, NULL, dwCreationDisposition, attributes, NULL ); if(hFile == INVALID_HANDLE_VALUE) { DBG_TEXT("Failed with error %lu", GetLastError()); *err = GetLastError(); } else { NTFSCompressFile(hFile); } return (INT_PTR)hFile; } FNFCIREAD(CabFileRead) { UNREFERENCED_PARAMETER(pv); DWORD dwBytesRead = 0; UNREFERENCED_PARAMETER(pv); if(ReadFile((HANDLE)hf, memory, cb, &dwBytesRead, NULL) == FALSE) { dwBytesRead = (DWORD)-1; *err = GetLastError(); } return dwBytesRead; } FNFCIWRITE(CabFileWrite) { UNREFERENCED_PARAMETER(pv); DWORD dwBytesWritten = 0; UNREFERENCED_PARAMETER(pv); if(WriteFile((HANDLE)hf, memory, cb, &dwBytesWritten, NULL) == FALSE ) { dwBytesWritten = (DWORD)-1; *err = GetLastError(); } return dwBytesWritten; } FNFCICLOSE(CabFileClose) { INT iResult = 0; UNREFERENCED_PARAMETER(pv); if(CloseHandle((HANDLE)hf) == FALSE) { *err = GetLastError(); iResult = -1; } return iResult; } FNFCISEEK(CabFileSeek) { DWORD iResult = 0; UNREFERENCED_PARAMETER(pv); iResult = SetFilePointer((HANDLE)hf, dist, NULL, seektype); if(iResult == INVALID_SET_FILE_POINTER) { *err = GetLastError(); } return static_cast(iResult); } FNFCIDELETE(CabFileDelete) { INT iResult = 0; UNREFERENCED_PARAMETER(pv); DBG_TEXT("Deleting file \"%s\"", pszFile); if(DeleteFileA(pszFile) == FALSE) { *err = GetLastError(); DBG_TEXT("Failed to delete CAB file \"%s\" because of error %lu", pszFile, GetLastError()); iResult = -1; } return iResult; } FNFCIGETTEMPFILE(CabGetTempFileName) { UNREFERENCED_PARAMETER(pv); WinLib::ScopedArray tempFile; WinLib::GetTemporaryFileName(tempFile, NULL); size_t nameLen = WinLib::StrLen(*tempFile) + 1; strncpy(pszTempName, *tempFile, std::min(cbTempName, nameLen)); pszTempName[cbTempName - 1] = 0; DBG_TEXT("Generated temp cab filename \"%s\"", pszTempName); return TRUE; } FNFCIGETNEXTCABINET(CabNextCab) { int written; UNREFERENCED_PARAMETER(pv); UNREFERENCED_PARAMETER(cbPrevCab); written = _snprintf( pccab->szCab, ARRAYSIZE(pccab->szCab), "%s%d.cab", static_cast(pv), pccab->iCab ); DBG_TEXT("Next cab will be at \"%s\\%s\"", pccab->szCabPath, pccab->szCab); return written > 0; } FNFCISTATUS(CabStatus) { UNREFERENCED_PARAMETER(pv); UNREFERENCED_PARAMETER(typeStatus); UNREFERENCED_PARAMETER(cb1); UNREFERENCED_PARAMETER(cb2); return 0; } FNFCIGETOPENINFO(CabGetOpenInfo) { UNREFERENCED_PARAMETER(pv); HANDLE hFile; FILETIME fileTime; BY_HANDLE_FILE_INFORMATION fileInfo; hFile = (HANDLE)CabFileOpen(pszName, _O_RDONLY, 0, err, pv); if(hFile != INVALID_HANDLE_VALUE) { if( GetFileInformationByHandle(hFile, &fileInfo) && FileTimeToLocalFileTime(&fileInfo.ftCreationTime, &fileTime) && FileTimeToDosDateTime(&fileTime, pdate, ptime) ) { *pattribs = static_cast(fileInfo.dwFileAttributes); } else { CabFileClose((INT_PTR)hFile, err, pv); hFile = (HANDLE)-1; } } return (INT_PTR)hFile; } HANDLE CreateCab( LPCWSTR cabFileName, LPCWSTR dumpFileName, LPCWSTR xmlData, const std::vector& userFiles ) { BOOL cabCreated = FALSE; LPCWSTR cabName = wcsrchr(cabFileName, L'\\'); if(!cabName) cabName = wcsrchr(cabFileName, L'/'); assert(cabName); if(!cabName) cabName = cabFileName; ++cabName; // skip over the found slash // cab api is narrow only std::string narrowXmlFile = WinLib::ConvertToString(xmlData); std::string narrowCabName = WinLib::ConvertToString(cabName); std::string narrowCabPath = WinLib::ConvertToString(cabFileName, cabName - cabFileName); std::string narrowDump = WinLib::ConvertToString(dumpFileName); ERF erf = {0}; CCAB cab = {0}; cab.cbFolderThresh = 0x20000000; cab.iCab = cab.setID = 1; narrowCabName.copy(cab.szCab, std::min(ARRAYSIZE(cab.szCab), narrowCabName.size())); narrowCabPath.copy(cab.szCabPath, std::min(ARRAYSIZE(cab.szCabPath), narrowCabPath.size())); HFCI fci = FCICreate( &erf, &FilePlaced, &CabAlloc, &CabFree, &CabFileOpen, &CabFileRead, &CabFileWrite, &CabFileClose, &CabFileSeek, &CabFileDelete, &CabGetTempFileName, &cab, const_cast(narrowCabName.c_str()) ); if(fci) { // add the files to the cab if(FCIAddFile( fci, const_cast(narrowDump.c_str()), "minidmp.dmp", FALSE, &CabNextCab, &CabStatus, &CabGetOpenInfo, TCOMPfromTypeLevelMemory( tcompTYPE_LZX, 4, 21 ) ) && FCIAddFile( fci, const_cast(narrowXmlFile.c_str()), "dumpinfo.xml", FALSE, &CabNextCab, &CabStatus, &CabGetOpenInfo, TCOMPfromTypeLevelMemory( tcompTYPE_LZX, 4, 21 ) ) ) { // yay, we got our files in the cab, now add any user specific additional files for(std::vector::const_iterator iter = userFiles.begin(), end = userFiles.end(); iter != end; ++iter ) { LPCSTR filePath = iter->c_str(); FCIAddFile( fci, const_cast(filePath), PathFindFileNameA(filePath), FALSE, &CabNextCab, &CabStatus, &CabGetOpenInfo, TCOMPfromTypeLevelMemory( tcompTYPE_LZX, 4, 21 ) ); } cabCreated = TRUE; FCIFlushCabinet(fci, FALSE, &CabNextCab, &CabStatus); } FCIDestroy(fci); } } void NTFSCompressFile(HANDLE hFile) { USHORT fsComp = COMPRESSION_FORMAT_DEFAULT; DWORD bytes = 0; DeviceIoControl(hFile, FSCTL_SET_COMPRESSION, &fsComp, sizeof(fsComp), NULL, 0, &bytes, NULL); }