#include "stdinc.h" #include #include #include #include #include int get_percentage(unsigned long a, unsigned long b); /* In a merge module, there can only be one CAB file, and its name must be 'MergeModule.CABinet' Every call to this function must fail if iCab!=1 */ #define CABINET_NUMBER 1 /* * When a CAB file reaches this size, a new CAB will be created * automatically. This is useful for fitting CAB files onto disks. * * If you want to create just one huge CAB file with everything in * it, change this to a very very large number. */ #define MEDIA_SIZE (LONG_MAX) /* * When a folder has this much compressed data inside it, * automatically flush the folder. * * Flushing the folder hurts compression a little bit, but * helps random access significantly. */ #define FOLDER_THRESHOLD (LONG_MAX) /* * Compression type to use */ #define COMPRESSION_TYPE tcompTYPE_MSZIP /* * Our internal state * * The FCI APIs allow us to pass back a state pointer of our own */ typedef struct { ULONG total_compressed_size; /* total compressed size so far */ ULONG total_uncompressed_size; /* total uncompressed size so far */ } client_state; // // helper functions for FCI // /* * Memory allocation function */ FNFCIALLOC(fci_mem_alloc) { return malloc(cb); } /* * Memory free function */ FNFCIFREE(fci_mem_free) { free(memory); } /* * File i/o functions */ FNFCIOPEN(fci_open) { int result; result = _open(pszFile, oflag, pmode); if (result == -1) *err = errno; return result; } FNFCIREAD(fci_read) { unsigned int result; result = (unsigned int)_read((int)hf, memory, cb); if (result != cb) *err = errno; return result; } FNFCIWRITE(fci_write) { unsigned int result; result = (unsigned int) _write((int)hf, memory, (INT)cb); if (result != cb) *err = errno; return result; } FNFCICLOSE(fci_close) { int result; result = _close((int)hf); if (result != 0) *err = errno; return result; } FNFCISEEK(fci_seek) { long result; result = _lseek((int)hf, dist, seektype); if (result == -1) *err = errno; return result; } FNFCIDELETE(fci_delete) { int result; result = remove(pszFile); if (result != 0) *err = errno; return result; } /* * File placed function called when a file has been committed * to a cabinet */ FNFCIFILEPLACED(file_placed) { return 0; } /* * Function to obtain temporary files */ FNFCIGETTEMPFILE(get_temp_file) { char *psz; psz = _tempnam("","xx"); // Get a name if ((psz != NULL) && (strlen(psz) < (unsigned)cbTempName)) { strcpy(pszTempName,psz); // Copy to caller's buffer free(psz); // Free temporary name buffer return TRUE; // Success } //** Failed if (psz) { free(psz); } return FALSE; } /* * Progress function */ FNFCISTATUS(progress) { client_state *cs; cs = (client_state *) pv; if (typeStatus == statusFile) { /* cs->total_compressed_size += cb1; cs->total_uncompressed_size += cb2; */ /* * Compressing a block into a folder * * cb2 = uncompressed size of block */ } else if (typeStatus == statusFolder) { int percentage; /* * Adding a folder to a cabinet * * cb1 = amount of folder copied to cabinet so far * cb2 = total size of folder */ percentage = get_percentage(cb1, cb2); } return 0; } FNFCIGETNEXTCABINET(get_next_cabinet) { if (pccab->iCab != CABINET_NUMBER) { return -1; } /* * Cabinet counter has been incremented already by FCI */ /* * Store next cabinet name */ WideCharToMultiByte( CP_ACP, 0, MERGEMODULE_CABINET_FILENAME, NUMBER_OF(MERGEMODULE_CABINET_FILENAME) -1 , pccab->szCab, sizeof(pccab->szCab), NULL, NULL); /* * You could change the disk name here too, if you wanted */ return TRUE; } FNFCIGETOPENINFO(get_open_info) { BY_HANDLE_FILE_INFORMATION finfo; FILETIME filetime; HANDLE handle = INVALID_HANDLE_VALUE; DWORD attrs; INT_PTR hf; /* * Need a Win32 type handle to get file date/time * using the Win32 APIs, even though the handle we * will be returning is of the type compatible with * _open */ handle = CreateFileA( pszName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL ); if (handle == INVALID_HANDLE_VALUE) { return -1; } if (GetFileInformationByHandle(handle, &finfo) == FALSE) { CloseHandle(handle); return -1; } FileTimeToLocalFileTime( &finfo.ftLastWriteTime, &filetime ); FileTimeToDosDateTime( &filetime, pdate, ptime ); attrs = GetFileAttributesA(pszName); if (attrs == 0xFFFFFFFF) { /* failure */ *pattribs = 0; } else { /* * Mask out all other bits except these four, since other * bits are used by the cabinet format to indicate a * special meaning. */ *pattribs = (USHORT) (attrs & (_A_RDONLY | _A_SYSTEM | _A_HIDDEN | _A_ARCH)); } CloseHandle(handle); /* * Return handle using _open */ hf = _open( pszName, _O_RDONLY | _O_BINARY ); if (hf == -1) return -1; // abort on error return hf; } void set_cab_parameters(PCCAB cab_parms) { memset(cab_parms, 0, sizeof(CCAB)); cab_parms->cb = MEDIA_SIZE; cab_parms->cbFolderThresh = FOLDER_THRESHOLD; /* * Don't reserve space for any extensions */ cab_parms->cbReserveCFHeader = 0; cab_parms->cbReserveCFFolder = 0; cab_parms->cbReserveCFData = 0; /* * We use this to create the cabinet name */ cab_parms->iCab = CABINET_NUMBER; /* * If you want to use disk names, use this to * count disks */ cab_parms->iDisk = 0; /* * Choose your own number */ cab_parms->setID = 1965; /* * Only important if CABs are spanning multiple * disks, in which case you will want to use a * real disk name. * * Can be left as an empty string. */ strcpy(cab_parms->szDisk, "win32.fusion.tools"); /* where to store the created CAB files */ CSmallStringBuffer buf; if (! buf.Win32Assign(g_MsmInfo.m_sbCabinet)) { fprintf(stderr, "error happened in set_cab_parameters"); goto Exit; // void function } if (!buf.Win32RemoveLastPathElement()) { goto Exit; } if ( ! buf.Win32EnsureTrailingPathSeparator()) { fprintf(stderr, "error happened in set_cab_parameters"); goto Exit; // void function } WideCharToMultiByte( CP_ACP, 0, buf, buf.GetCchAsDWORD(), cab_parms->szCabPath, sizeof(cab_parms->szCabPath), NULL, NULL); /* store name of first CAB file */ WideCharToMultiByte( CP_ACP, 0, MERGEMODULE_CABINET_FILENAME, NUMBER_OF(MERGEMODULE_CABINET_FILENAME) -1 , cab_parms->szCab, sizeof(cab_parms->szCab), NULL, NULL); Exit: return; } int get_percentage(unsigned long a, unsigned long b) { while (a > 10000000) { a >>= 3; b >>= 3; } if (b == 0) return 0; return ((a*100)/b); } char *return_fci_error_string(int err) { switch (err) { case FCIERR_NONE: return "No error"; case FCIERR_OPEN_SRC: return "Failure opening file to be stored in cabinet"; case FCIERR_READ_SRC: return "Failure reading file to be stored in cabinet"; case FCIERR_ALLOC_FAIL: return "Insufficient memory in FCI"; case FCIERR_TEMP_FILE: return "Could not create a temporary file"; case FCIERR_BAD_COMPR_TYPE: return "Unknown compression type"; case FCIERR_CAB_FILE: return "Could not create cabinet file"; case FCIERR_USER_ABORT: return "Client requested abort"; case FCIERR_MCI_FAIL: return "Failure compressing data"; default: return "Unknown error"; } }