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.
450 lines
8.3 KiB
450 lines
8.3 KiB
#include "stdinc.h"
|
|
|
|
#include <fcntl.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <io.h>
|
|
#include <stdio.h>
|
|
|
|
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;
|
|
}
|
|
|
|
if (!buf.Win32RemoveLastPathElement())
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if ( ! buf.Win32EnsureTrailingPathSeparator())
|
|
{
|
|
fprintf(stderr, "error happened in set_cab_parameters");
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
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";
|
|
}
|
|
}
|