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.
701 lines
14 KiB
701 lines
14 KiB
#include <windows.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <io.h>
|
|
#include <dos.h>
|
|
|
|
#include <time.h>
|
|
#include <tchar.h>
|
|
|
|
#include <cab.h> //Cab file headers
|
|
// #include <main.h> //Main program header file
|
|
|
|
////////////////////////////
|
|
//Cabbing Context Variables
|
|
////////////////////////////
|
|
ERF erf;
|
|
client_state cs;
|
|
|
|
//Global Definations for some static setting
|
|
// Set these to override the defaults
|
|
char g_szCabFileLocation[_MAX_PATH] = {""}; //This is the fully qualified path, must have a \ at the end
|
|
char g_szCabFileName[_MAX_PATH] = {""}; //this is the file name for the cab.. Suggest that it has a .cab for telling its a cab
|
|
extern void Log(char *szString);
|
|
extern void Log2(char *szString, char *szString2);
|
|
|
|
|
|
|
|
|
|
/*
|
|
///////////////////////////////
|
|
// Cabbing API Helper Functions
|
|
/////////////////////./////////
|
|
*/
|
|
|
|
|
|
/*
|
|
* Memory allocation function
|
|
*/
|
|
FNFCIALLOC(mem_alloc)
|
|
{
|
|
return malloc(cb);
|
|
}
|
|
|
|
|
|
/*
|
|
* Memory free function
|
|
*/
|
|
FNFCIFREE(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(hf, memory, cb);
|
|
|
|
if (result != cb)
|
|
*err = errno;
|
|
|
|
return result;
|
|
}
|
|
|
|
FNFCIWRITE(fci_write)
|
|
{
|
|
unsigned int result;
|
|
|
|
result = (unsigned int) _write(hf, memory, cb);
|
|
|
|
if (result != cb)
|
|
*err = errno;
|
|
|
|
return result;
|
|
}
|
|
|
|
FNFCICLOSE(fci_close)
|
|
{
|
|
int result;
|
|
|
|
result = _close(hf);
|
|
|
|
if (result != 0)
|
|
*err = errno;
|
|
|
|
return result;
|
|
}
|
|
|
|
FNFCISEEK(fci_seek)
|
|
{
|
|
long result;
|
|
|
|
result = _lseek(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)
|
|
{
|
|
if (fContinuation)
|
|
Log(" (Above file is a later segment of a continued file)\n");
|
|
|
|
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
|
|
}
|
|
//** if 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
|
|
*/
|
|
//printf(
|
|
// "Compressing: %9ld -> %9ld \r",
|
|
// cs->total_uncompressed_size,
|
|
// cs->total_compressed_size
|
|
//);
|
|
|
|
fflush(stdout);
|
|
}
|
|
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);
|
|
|
|
//printf("Copying folder to cabinet: %d%% \r", percentage);
|
|
fflush(stdout);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
FNFCIGETNEXTCABINET(get_next_cabinet)
|
|
{
|
|
char lpBuffer[_MAX_PATH];
|
|
|
|
/*
|
|
* Cabinet counter has been incremented already by FCI
|
|
* Store next cabinet name
|
|
*/
|
|
strGenerateCabFileName(lpBuffer, MAX_COMPUTERNAME_LENGTH +1); //BUGBUG I am just glueing this together, should check for error
|
|
strcpy(pccab->szCab, lpBuffer);
|
|
|
|
/*
|
|
* 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;
|
|
DWORD attrs;
|
|
int 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, //BUGBUG ARG What should this be???
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING, //OPEN_EXISTING
|
|
FILE_ATTRIBUTE_NORMAL, //FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN
|
|
NULL
|
|
);
|
|
|
|
if (INVALID_HANDLE_VALUE == handle)
|
|
{
|
|
printf("DEBUG: Invalid Handle for CreateFile\n");
|
|
printf("DEBUG: %ld\n", GetLastError());
|
|
return -1;
|
|
}
|
|
|
|
if (GetFileInformationByHandle(handle, &finfo) == FALSE)
|
|
{
|
|
printf("DEBUG: GetFileInformation Failed\n");
|
|
CloseHandle(handle);
|
|
return -1;
|
|
}
|
|
|
|
FileTimeToLocalFileTime(
|
|
&finfo.ftLastWriteTime,
|
|
&filetime
|
|
);
|
|
|
|
FileTimeToDosDateTime(
|
|
&filetime,
|
|
pdate,
|
|
ptime
|
|
);
|
|
|
|
attrs = GetFileAttributes((const LPCTSTR)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 = (int) (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)
|
|
{
|
|
const char *szCabStorePath="";
|
|
char lpBuffer[_MAX_PATH];
|
|
|
|
|
|
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 = 1;
|
|
|
|
/*
|
|
* If you want to use disk names, use this to
|
|
* count disks
|
|
*/
|
|
cab_parms->iDisk = 0;
|
|
|
|
/*
|
|
* Choose your own number
|
|
*/
|
|
cab_parms->setID = 12345;
|
|
|
|
/*
|
|
* 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, "MyDisk");
|
|
|
|
/* where to store the created CAB files */
|
|
if( NULL != *g_szCabFileLocation)
|
|
{
|
|
//make sure that we have a \\ on the end of the path to the cab.
|
|
if( '\\' != g_szCabFileLocation[strlen(g_szCabFileLocation)] )
|
|
strcat(g_szCabFileLocation, "\\");
|
|
strcpy(cab_parms->szCabPath, g_szCabFileLocation);
|
|
}
|
|
else
|
|
{
|
|
szCabStorePath = getenv("TEMP");
|
|
strcpy(cab_parms->szCabPath, szCabStorePath);
|
|
strcat(cab_parms->szCabPath, "\\");
|
|
}
|
|
|
|
//**
|
|
//check if last char in path is "\"
|
|
// len = strlen(g_szCurrDir);
|
|
// if ('\' != g_szCurrDir[len-1])
|
|
// strcat(cab_parms->szCabPath, "\\"); //Not the root: Append "\"at end of path
|
|
|
|
/* store name of first CAB file */
|
|
strGenerateCabFileName(lpBuffer, _MAX_PATH); //BUGBUG I am just glueing this together, should check for error
|
|
|
|
strcpy(cab_parms->szCab, lpBuffer);
|
|
|
|
sprintf(lpBuffer, "Cab location = %s%s\n", cab_parms->szCabPath, cab_parms->szCab);
|
|
Log(lpBuffer);
|
|
|
|
}
|
|
|
|
/*
|
|
************************************************************************
|
|
*
|
|
* Function: create_cab()
|
|
*
|
|
* Initializes the Context to create a CAB File.
|
|
* Returns hcfi if successful (context to a Cab file).
|
|
*
|
|
************************************************************************
|
|
*/
|
|
|
|
HFCI create_cab()
|
|
{
|
|
// Initialize our internal state
|
|
HFCI hfci;
|
|
CCAB cab_parameters;
|
|
|
|
cs.total_compressed_size = 0;
|
|
cs.total_uncompressed_size = 0;
|
|
|
|
set_cab_parameters(&cab_parameters);
|
|
|
|
hfci = FCICreate(
|
|
&erf,
|
|
file_placed,
|
|
mem_alloc,
|
|
mem_free,
|
|
fci_open,
|
|
fci_read,
|
|
fci_write,
|
|
fci_close,
|
|
fci_seek,
|
|
fci_delete,
|
|
get_temp_file,
|
|
&cab_parameters,
|
|
&cs
|
|
);
|
|
|
|
if (hfci == NULL)
|
|
{
|
|
Log2("FCICreate() failed: ",return_fci_error_string((FCIERROR)erf.erfOper));
|
|
printf("FCICreate() failed: code %d [%s]\n",
|
|
erf.erfOper, return_fci_error_string((FCIERROR)erf.erfOper)
|
|
);
|
|
|
|
return hfci;
|
|
}
|
|
else
|
|
return hfci;
|
|
}
|
|
|
|
/*
|
|
********************************************************************************
|
|
*
|
|
* Function: flush_cab
|
|
*
|
|
* Forces the Cabinet under construction to be completed and written to disk.
|
|
* Returns TRUE if successful
|
|
*
|
|
********************************************************************************
|
|
*/
|
|
|
|
BOOL flush_cab(HFCI hfci)
|
|
|
|
{
|
|
|
|
// This will automatically flush the folder first
|
|
|
|
if (FALSE == FCIFlushCabinet(
|
|
hfci,
|
|
FALSE,
|
|
get_next_cabinet,
|
|
progress))
|
|
{
|
|
|
|
Log2("FCIFlushCabinet() failed: ",return_fci_error_string((FCIERROR)erf.erfOper));
|
|
printf("FCIFlushCabinet() failed: code %d [%s]\n",
|
|
erf.erfOper, return_fci_error_string((FCIERROR)erf.erfOper)
|
|
);
|
|
|
|
(void) FCIDestroy(hfci);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (FCIDestroy(hfci) != TRUE)
|
|
{
|
|
Log2("FCIDestroy() failed: ",return_fci_error_string((FCIERROR)erf.erfOper));
|
|
printf("FCIDestroy() failed: code %d [%s]\n",
|
|
erf.erfOper, return_fci_error_string((FCIERROR)erf.erfOper)
|
|
);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
**************************************************************************************
|
|
*
|
|
* Function: test_fci
|
|
*
|
|
* Adds Files to HFCI Context, Cabs them and flushes the folder (generates Cab file).
|
|
* Returns TRUE if successfull
|
|
*
|
|
***************************************************************************************
|
|
*/
|
|
|
|
bool test_fci(HFCI hfci, int num_files, char *file_list[], char *currdir)
|
|
{
|
|
int i;
|
|
|
|
// Add files in the Array passed in file_list[]
|
|
|
|
for (i = 0; (i < num_files)&&(strlen(file_list[i])); i++)
|
|
{
|
|
char stripped_name[256];
|
|
char *szAux;//added ="";
|
|
|
|
Log("--------------------------------------------------");
|
|
Log2("Processing File = ",file_list[i]);
|
|
|
|
szAux = (char *) malloc(strlen(file_list[i])+strlen(currdir)+1);
|
|
|
|
if (NULL!= szAux)
|
|
{
|
|
|
|
if (NULL == currdir) // if currdir is empty, then just pass element[i] in argv[]
|
|
strcpy(szAux,file_list[i]);
|
|
else {
|
|
strcpy(szAux,currdir); // else append filename to currdir
|
|
strcat(szAux,file_list[i]);
|
|
}
|
|
|
|
if( -1 != (_access(szAux, 0 )) )
|
|
{
|
|
// Don't store the path name in the cabinet file!
|
|
strip_path(szAux, stripped_name);
|
|
|
|
if (FALSE == FCIAddFile(
|
|
hfci, //This was hfci
|
|
szAux, /* file to add */
|
|
stripped_name, /* file name in cabinet file */
|
|
FALSE, /* file is not executable */
|
|
get_next_cabinet,
|
|
progress,
|
|
get_open_info,
|
|
COMPRESSION_TYPE))
|
|
{
|
|
|
|
Log2("FCIAddFile() failed: ",return_fci_error_string((FCIERROR)erf.erfOper));
|
|
printf("FCIAddFile() failed: code %d [%s]\n",
|
|
erf.erfOper, return_fci_error_string((FCIERROR)erf.erfOper)
|
|
);
|
|
|
|
// I need to continue if file can't be added....
|
|
|
|
// (void) FCIDestroy(hfci);
|
|
// return false;
|
|
}
|
|
else
|
|
Log("File Was Added!");
|
|
}
|
|
else
|
|
Log("File does not exist! Continuing... ");
|
|
|
|
free (szAux);
|
|
}
|
|
else
|
|
Log("Could not allocate enough memory to Cab\n");
|
|
|
|
} // End for
|
|
|
|
// Done Adding Files
|
|
Log("--------------------------------------------------");
|
|
|
|
//By here then everything is successful.. If not then you need to uncomment the previous failure return.
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
/*
|
|
********************************************************************************
|
|
*
|
|
* Function: strip_path
|
|
*
|
|
* Returns the file name of a full path.
|
|
*
|
|
********************************************************************************
|
|
*/
|
|
|
|
void strip_path(char *filename, char *stripped_name)
|
|
{
|
|
char *p;
|
|
|
|
p = strrchr(filename, '\\');
|
|
//printf ("Path + Filename= %s\n",filename);
|
|
|
|
if (p == NULL)
|
|
strcpy(stripped_name, filename);
|
|
else
|
|
strcpy(stripped_name, p+1);
|
|
}
|
|
|
|
char *return_fci_error_string(FCIERROR 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";
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
**************************************************************
|
|
*
|
|
* Function: Generate Cab File name
|
|
*
|
|
* Output: Global String containing a filename
|
|
* szCabFileName = ComputerName + ddmmyy + hhmmss
|
|
*
|
|
**************************************************************
|
|
*/
|
|
|
|
DWORD strGenerateCabFileName(char *lpBuffer, DWORD dSize)
|
|
{
|
|
time_t ltime;
|
|
struct tm *now;
|
|
char tmpbuf[128];
|
|
|
|
//Check to see if we have an override for the cabname, if so use it.
|
|
if( NULL != *g_szCabFileName)
|
|
{
|
|
strcpy(lpBuffer, g_szCabFileName);
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Copy Computer Name to CabFileName
|
|
//
|
|
strcpy(lpBuffer, getenv("COMPUTERNAME"));
|
|
//GetComputerName((LPTSTR) lpBuffer, &dSize);
|
|
|
|
//
|
|
// Append Undescore character to CabFileName
|
|
//
|
|
strcat(lpBuffer, "_");
|
|
|
|
//
|
|
// Get System Time and Date
|
|
//
|
|
time( <ime );
|
|
now = localtime( <ime );
|
|
|
|
//
|
|
// Convert time/date to mmddyyhhmmss format (24hr)
|
|
//
|
|
if (strftime( tmpbuf, 128,"%m%d%y_%H%M%S", now))
|
|
// Append Timestamp to CabFileName
|
|
strcat(lpBuffer, tmpbuf);
|
|
else {
|
|
Log ("Could not convert system time to mmddyy_hhmmss format\n");
|
|
return -1;
|
|
}
|
|
|
|
//Now append on the extension and now we are set.
|
|
strcat(lpBuffer, ".cab");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|