home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Hack-Phreak Scene Programs
/
cleanhpvac.zip
/
cleanhpvac
/
HPACK78S.ZIP
/
os2.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-02
|
41KB
|
1,511 lines
/****************************************************************************
* *
* HPACK Multi-System Archiver *
* =========================== *
* *
* OS/2-Specific Routines *
* OS2.C Updated 04/08/92 *
* *
* This program is protected by copyright and as such any use or copying of *
* this code for your own purposes directly or indirectly is highly uncool *
* and if you do so there will be....trubble. *
* And remember: We know where your kids go to school. *
* *
* Copyright 1991 - 1992 Conrad Bullock and John Burnell *
* All rights reserved *
* *
****************************************************************************/
/* This file contains a the code for both the 16 and 32-bit versions of
OS/2. There is a fair amount of dual-use code, as well as some version-
specific routines, toggled by defining OS2_32 */
#define INCL_BASE
#if defined( __TSC__ )
#define BYTE OS2_BYTE
#include <os2pm.h>
#undef BYTE
#undef COMMENT
#elif defined( OS2_32 )
#define INCL_BASE
#define INCL_NOPMAPI
#define BYTE OS2_BYTE
#include <os2.h>
#undef BYTE
#else
#include <os2.h>
#endif /* __TSC__ */
#undef LONG
#ifdef __TSC__
#include <alloc.h>
#endif /* __TSC__ */
#include <ctype.h>
#ifdef __TSC__
#include <dir.h>
#endif /* __TSC__ */
#ifndef OS2_32
#include <io.h>
#endif /* OS2_32 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "defs.h"
#include "arcdir.h"
#include "frontend.h"
#include "system.h"
#include "wildcard.h"
#include "hpacklib.h"
#include "crc/crc16.h"
#include "io/fastio.h"
#ifndef OS2_32
/* Prototypes for memory-management functions */
void far *farmalloc( unsigned long num );
void far *farrealloc( void far *block, unsigned long num );
void farfree( void far *block );
#endif /* OS2_32 */
/* Whether this file is being added from an HPFS drive or not */
BOOLEAN isHPFS = FALSE;
BOOLEAN destIsHPFS = FALSE;
/* The drive the archive is on */
BYTE archiveDrive;
/* Get an input char, no echo */
int hgetch( void )
{
#ifdef OS2_32
return _read_kbd( 0, 1, 1 );
#else
return( getch() );
#endif /* OS2_32 */
}
/****************************************************************************
* *
* HPACKLIB Functions *
* *
****************************************************************************/
/* Memory management functions. The OS2_32 ones could be aliased in
hpacklib.h since under OS/2 2.0 we don't have the memory limitations of
the 16-bit versions of OS/2, but to be consistent we implement them as
wrappers for the std. library calls as in the 16-bit version */
#ifdef OS2_32
void *hmalloc( const unsigned long size )
{
return( malloc( size ) );
}
void *hrealloc( void *buffer, const unsigned long size )
{
return( realloc( buffer, size ) );
}
void hfree( void *buffer )
{
free( buffer );
}
#else
void *hmalloc( const unsigned long size )
{
if( size > 0xFFFF )
/* Farm alloc? Out of pasture space - don't have a cow man */
return( farmalloc( size ) );
else
return( malloc( ( int ) size ) );
}
void *hrealloc( void *buffer, const unsigned long size )
{
if( size > 0xFFFF )
return( farrealloc( buffer, size ) );
else
return( realloc( buffer, ( int ) size ) );
}
void hfree( void *buffer )
{
free( buffer );
}
#endif /* OS2_32 */
/****************************************************************************
* *
* HPACKIO Functions *
* *
****************************************************************************/
/* Functions to open and create files in binary mode */
int hopen( const char *fileName, const int mode )
{
HFILE hFile;
#ifdef OS2_32
ULONG action;
#else
USHORT action;
#endif /* OS2_32 */
return( ( DosOpen( ( PSZ ) fileName, &hFile, &action, 0, \
FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS, mode, 0 ) == NO_ERROR ) ? \
hFile : IO_ERROR );
}
int hcreat( const char *fileName, const int attr )
{
HFILE hFile;
#ifdef OS2_32
ULONG action;
#else
USHORT action;
#endif /* OS2_32 */
return( ( DosOpen( ( PSZ ) fileName, &hFile, &action, 0, FILE_NORMAL, \
OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS, \
attr, 0 ) == NO_ERROR ) ? hFile : IO_ERROR );
}
/* Close a file */
int hclose( const FD theFD )
{
return( ( DosClose( theFD ) == NO_ERROR ) ? OK : IO_ERROR );
}
/* Create a directory */
int hmkdir( const char *dirName, const int attr )
{
#ifdef OS2_32
return( ( DosCreateDir( ( PSZ ) dirName, 0 ) == NO_ERROR ) ? OK : IO_ERROR );
#else
return( ( mkdir( dirName ) == NO_ERROR ) ? OK : IO_ERROR );
#endif
}
/* Seek to a specified position in a file, and return the current position
in a file */
long hlseek( const FD theFD, const long position, const int whence )
{
LONG where;
#ifdef OS2_32
return( ( DosSetFilePtr( theFD, position, whence, &where ) == NO_ERROR ) ? \
where : IO_ERROR );
#else
return( ( DosChgFilePtr( theFD, position, whence, &where ) == NO_ERROR ) ? \
where : IO_ERROR );
#endif
}
long htell( const FD theFD )
{
ULONG where;
#ifdef OS2_32
if( DosSetFilePtr( theFD, 0L, FILE_CURRENT, &where ) != NO_ERROR )
#else
if( DosChgFilePtr( theFD, 0L, FILE_CURRENT, &where ) != NO_ERROR )
#endif
return( IO_ERROR );
return( where );
}
/* Read/write a specified amount of data from/to a file */
int hread( const FD inFD, void *buffer, const unsigned int bufSize )
{
#ifdef OS2_32
ULONG bytesRead;
#else
USHORT bytesRead;
#endif /* OS2_32 */
return( ( DosRead( inFD, buffer, bufSize, &bytesRead ) == NO_ERROR ) ? \
( int ) bytesRead : IO_ERROR );
}
int hwrite( const FD outFD, void *buffer, const unsigned int bufSize )
{
#ifdef OS2_32
USHORT bytesWritten;
#else
ULONG bytesWritten;
#endif /* OS2_32 */
int bytesToWrite = bufSize;
FSALLOCATE fsAllocate;
ULONG SpaceAvail;
USHORT Result;
if( DosWrite( outFD, buffer, bytesToWrite, &bytesWritten ) != NO_ERROR )
return( IO_ERROR );
/* Fix the behaviour of DosWrite() by retrying the write with less data
if it fails (the DOS/OS2 write() is a boolean all-or-nothing affair
rather than doing the Right Thing as writing as much as it can) */
if( ( int ) bytesWritten != bytesToWrite )
{
#ifdef OS2_32
if( DosQueryFSInfo( archiveDrive, FSIL_ALLOC, &fsAllocate, \
sizeof( fsAllocate ) ) != NO_ERROR )
#else
if( DosQFSInfo( archiveDrive, FSIL_ALLOC, &fsAllocate, \
sizeof( fsAllocate ) ) != NO_ERROR )
#endif
return( IO_ERROR );
/* Calculate the disk space available and retry the write with that
amount */
SpaceAvail = fsAllocate.cUnitAvail * fsAllocate.cSectorUnit * fsAllocate.cbSector;
return( ( DosWrite( outFD, buffer, SpaceAvail, &bytesWritten ) == NO_ERROR) ? \
bytesWritten : IO_ERROR );
}
else
return( bytesWritten );
}
/* Change a file's attributes */
int hchmod( const char *fileName, const WORD attr )
{
#ifdef OS2_32
FILESTATUS3 fileInfo;
if( DosQueryPathInfo( ( PSZ ) fileName, FIL_STANDARD, &fileInfo, \
sizeof( fileInfo ) ) != NO_ERROR )
return( IO_ERROR );
fileInfo.attrFile = attr;
return( ( DosSetPathInfo( ( PSZ ) fileName, FIL_STANDARD, &fileInfo, \
sizeof( fileInfo ), 0 ) == NO_ERROR ) ? \
OK : IO_ERROR );
#else
return( DosSetFileMode( ( PSZ ) fileName, attr, 0L ) );
#endif /* OS2_32 */
}
/* Delete a file */
int hunlink( const char *fileName )
{
#ifdef OS2_32
return( ( DosDelete( ( PSZ ) fileName ) == NO_ERROR ) ? OK : IO_ERROR );
#else
return( ( DosDelete( ( PSZ ) fileName, 0L ) == NO_ERROR ) ? OK : IO_ERROR );
#endif
}
/* Rename a file */
int hrename( const char *srcName, const char *destName )
{
#ifdef OS2_32
return( ( DosMove( ( PSZ ) srcName, ( PSZ ) destName ) == NO_ERROR ) ? OK : IO_ERROR );
#else
return( ( DosMove( ( PSZ ) srcName, ( PSZ ) destName, 0L ) == NO_ERROR ) ? OK : IO_ERROR );
#endif /* OS2_32 */
}
int htruncate ( const FD theFile )
{
ULONG FilePos;
#ifdef OS2_32
DosSetFilePtr( ( HFILE ) theFile, 0L, FILE_CURRENT, &FilePos );
return( ( DosSetFileSize( ( HFILE ) theFile, FilePos ) == NO_ERROR ) ? OK : IO_ERROR );
#else
DosChgFilePtr( ( HFILE ) theFile, 0L, FILE_CURRENT, &FilePos );
return( ( DosNewSize( ( HFILE ) theFile, FilePos ) == NO_ERROR ) ? OK : IO_ERROR );
#endif
}
/****************************************************************************
* *
* SYSTEM Functions *
* *
*****************************************************************************
/* Which of the three file dates to set */
typedef enum { LASTWRITE, LASTACCESS, CREATION } TIMES;
/* Local function to set one of the timestamps of a file (or directory) */
static void setOneOfFileTimes( const char *fileName, const LONG Time,
const TIMES TimeToSet )
{
FILESTATUS info;
FDATE date;
FTIME time;
struct tm *tmtime;
tmtime = localtime( ( time_t * ) &Time );
time.twosecs = tmtime->tm_sec / 2;
time.minutes = tmtime->tm_min;
time.hours = tmtime->tm_hour ;
date.day = tmtime->tm_mday;
date.month = tmtime->tm_mon + 1;
date.year = tmtime->tm_year - 80;
/* Get information for file */
#ifdef OS2_32
DosQueryPathInfo( ( PSZ ) fileName, FIL_STANDARD, &info, sizeof( info ) );
#else
DosQPathInfo( ( PSZ ) fileName, FIL_STANDARD, ( PBYTE ) &info, \
sizeof( info ), 0L );
#endif /* OS2_32 */
switch( TimeToSet )
{
case LASTWRITE:
info.fdateLastWrite = date;
info.ftimeLastWrite = time;
break;
case LASTACCESS:
info.fdateLastAccess = date;
info.ftimeLastAccess = time;
break;
case CREATION:
info.fdateCreation = date;
info.ftimeCreation = time;
break;
}
/* The default is not to change the data */
#ifdef OS2_32
DosSetPathInfo( ( PSZ ) fileName, FIL_STANDARD, &info, \
sizeof( info ), 0 );
#else
DosSetPathInfo( ( PSZ ) fileName, FIL_STANDARD,( PBYTE) &info, \
sizeof( info ), 0, 0L );
#endif /* OS2_32 */
}
/* Set a files (or directories) timestamp */
void setFileTime( const char *fileName, const LONG fileTime )
{
setOneOfFileTimes( fileName, fileTime, LASTWRITE );
}
/* Set various other file timestamps */
void setAccessTime( const char *fileName, const LONG accessTime )
{
setOneOfFileTimes( fileName, accessTime, LASTACCESS );
}
void setCreationTime( const char *fileName, const LONG creationTime )
{
setOneOfFileTimes( fileName, creationTime, CREATION );
}
int getCountry( void )
{
COUNTRYCODE CountCode;
COUNTRYINFO CountInfo;
#ifdef OS2_32
ULONG retLen;
#else
USHORT retLen;
#endif /* OS2_32 */
USHORT result;
/* Clear country and codepage */
CountCode.country = 0;
CountCode.codepage = 0;
/* Try and get country info, defaulting to US if we can't find anything */
#ifdef OS2_32
return( ( DosQueryCtryInfo( sizeof( CountInfo ), &CountCode, &CountInfo, \
&retLen ) != NO_ERROR ) ? \
0 : CountInfo.fsDateFmt );
#else
return( ( DosGetCtryInfo( ( USHORT ) sizeof( CountInfo ), &CountCode, \
&CountInfo, &retLen ) != NO_ERROR ) ? \
0 : CountInfo.fsDateFmt );
#endif /* OS2_32 */
}
/* Find the first/next file in a directory. When we do the findFirst() we
enquire about any EA's attached to the file/directory for later
processing */
time_t TimetoLong( FDATE FDate, FTIME FTime )
{
struct tm timeBuf;
timeBuf.tm_sec = FTime.twosecs * 2;
timeBuf.tm_min = FTime.minutes;
timeBuf.tm_hour = FTime.hours;
timeBuf.tm_mday = FDate.day;
if( FDate.month > 0 )
/* Month range is from 1-12 */
timeBuf.tm_mon = FDate.month - 1;
else
/* Clear date if no access or creation time */
timeBuf.tm_mon = 0;
timeBuf.tm_year = FDate.year + 80; /* Years since 1980 */
timeBuf.tm_isdst = -1; /* Daylight saving indeterminate */
timeBuf.tm_wday = 0;
timeBuf.tm_yday = 0;
return( mktime( &timeBuf ) );
}
BOOLEAN findFirst( const char *filePath, const ATTR fileAttr, FILEINFO *fileInfo )
{
#ifdef OS2_32
FILEFINDBUF4 FindBuffer;
ULONG FindCount = 1;
#else
FILEFINDBUF2 FindBuffer;
USHORT FindCount = 1;
#endif /* OS2_32 */
HDIR FindHandle = HDIR_CREATE; /* OS allocates new file handle */
#ifdef OS2_32
if( DosFindFirst( ( PSZ ) filePath, &FindHandle, fileAttr, \
&FindBuffer, sizeof( FindBuffer ), &FindCount, \
FIL_QUERYEASIZE ) != NO_ERROR )
#else
if( DosFindFirst2( ( PSZ ) filePath, &FindHandle, fileAttr, \
&FindBuffer, sizeof( FindBuffer ), &FindCount, \
FIL_QUERYEASIZE, 0L ) )
#endif /* OS2_32 */
return( FALSE );
fileInfo->hdir = FindHandle;
strncpy( fileInfo->fName, FindBuffer.achName, FindBuffer.cchName );
fileInfo->fName[ FindBuffer.cchName ] = '\0';
fileInfo->fSize = FindBuffer.cbFile;
fileInfo->fAttr = FindBuffer.attrFile;
fileInfo->eaSize = FindBuffer.cbList;
fileInfo->fTime = TimetoLong( FindBuffer.fdateLastWrite, \
FindBuffer.ftimeLastWrite );
fileInfo->cTime = TimetoLong( FindBuffer.fdateCreation, \
FindBuffer.ftimeCreation );
fileInfo->aTime = TimetoLong( FindBuffer.fdateLastAccess, \
FindBuffer.ftimeLastAccess );
return TRUE;
}
BOOLEAN findNext( FILEINFO *fileInfo )
{
#ifdef OS2_32
FILEFINDBUF4 FindBuffer;
ULONG FileCount = 1;
#else
FILEFINDBUF2 FindBuffer;
USHORT FileCount = 1;
#endif /* OS2_32 */
if( DosFindNext( fileInfo->hdir, ( PFILEFINDBUF ) &FindBuffer,
sizeof( FindBuffer ), &FileCount ) != NO_ERROR )
return( FALSE );
strncpy( fileInfo->fName, FindBuffer.achName, FindBuffer.cchName );
fileInfo->fName[ FindBuffer.cchName ] = '\0';
fileInfo->fSize = FindBuffer.cbFile;
fileInfo->fAttr = FindBuffer.attrFile;
fileInfo->eaSize = FindBuffer.cbList;
fileInfo->fTime = TimetoLong( FindBuffer.fdateLastWrite, \
FindBuffer.ftimeLastWrite );
fileInfo->cTime = TimetoLong( FindBuffer.fdateCreation, \
FindBuffer.ftimeCreation );
fileInfo->aTime = TimetoLong( FindBuffer.fdateLastAccess, \
FindBuffer.ftimeLastAccess );
return TRUE;
}
void findEnd( FILEINFO *fileInfo )
{
DosFindClose( ( HDIR ) fileInfo->hdir );
}
/* Check whether two pathnames refer to the same file */
BOOLEAN isSameFile( const char *pathName1, const char *pathName2 )
{
char InfoBuf1[ MAX_PATH ], InfoBuf2[ MAX_PATH ];
USHORT cbInfoBuf = MAX_PATH;
/* Get the qualified filenames for the two paths */
#ifdef OS2_32
DosQueryPathInfo( ( PSZ ) pathName1, FIL_QUERYFULLNAME, \
&InfoBuf1, MAX_PATH );
DosQueryPathInfo( ( PSZ ) pathName2, FIL_QUERYFULLNAME, \
&InfoBuf2, MAX_PATH );
#else
DosQPathInfo( ( PSZ ) pathName1, FIL_QUERYFULLNAME, \
( PBYTE ) &InfoBuf1, cbInfoBuf, 0 );
DosQPathInfo( ( PSZ ) pathName2, FIL_QUERYFULLNAME, \
( PBYTE ) &InfoBuf2, cbInfoBuf, 0 );
#endif /* OS2_32 */
return( matchString( InfoBuf1, InfoBuf2, NO_WILDCARDS ) );
}
void getScreenSize( void )
{
#ifdef OS2_32
/* Unfortunately the GNU GCC/2 port cannot generated thunked calls to the
old 16-bit DLL's. If this code is recompiled with ICC or maybe BCC
then the 16-bit code can be used */
screenWidth = 80;
screenHeight = 25;
#else
VIOMODEINFO ModeInfo;
ModeInfo.cb = sizeof( ModeInfo );
VioGetMode( &ModeInfo, 0 );
screenWidth = ModeInfo.col;
screenHeight = ModeInfo.row;
#endif /* OS2_32 */
}
/****************************************************************************
* *
* Extended-Attribute Handling Functions *
* *
****************************************************************************/
#include "error.h"
#include "tags.h"
/* The EA's used by HPACK archives */
BYTE EA_HPACK_ARCH_TYPE[] = "Hpack Archive";
BYTE EA_HPACK_ICON[] = { 0x00, 0x00, 0x00, 0x00 }; /* Not yet defined */
BYTE EA_HPACK_ASSOCTBL[] = { 0x00, 0x00, 0x00, 0x00 }; /* Not yet defined */
/* Names for various EA types */
#define OS2_MISC LONG_TAG( TAG_OS2_MISC_EA )
#define ICON_NAME ".ICON"
#define LONGNAME_NAME ".LONGNAME"
#ifndef OS2_32
/* Variables and data structures used for handling EA's, these are
defined in the 32 BIT API, so these will be included in os2.h */
typedef struct _FEA2 /* fea2 */
{
#ifdef __32BIT__ /* This redundant for now, but keep it here
just in case */
ULONG oNextEntryOffset; /* New field */
#endif
BYTE fEA;
BYTE cbName;
USHORT cbValue;
CHAR szName[1]; /* New field */
} FEA2;
typedef FEA2 *PFEA2;
typedef struct _FEA2LIST /* fea2l */
{
ULONG cbList;
FEA2 list[ 1 ];
} FEA2LIST;
typedef FEA2LIST *PFEA2LIST;
typedef struct _GEA2 /* gea2 */
{
#ifdef OS2_32
/* New field - redundant for now, but keep it here just in case */
ULONG oNextEntryOffset;
#endif /* OS2_32 */
BYTE cbName;
CHAR szName[ 1 ]; /* New field */
} GEA2;
typedef GEA2 *PGEA2;
typedef struct _GEA2LIST /* gea2l */
{
ULONG cbList;
GEA2 list[ 1 ];
} GEA2LIST;
typedef GEA2LIST *PGEA2LIST;
typedef struct _EAOP2 /* eaop2 */
{
PGEA2LIST fpGEA2List; /* GEA set */
PFEA2LIST fpFEA2List; /* FEA set */
ULONG oError; /* Offset of FEA error */
} EAOP2;
typedef EAOP2 *PEAOP2;
typedef PVOID *PPVOID;
#define DSPI_WRTTHRU 0x10 /* Write through */
#endif /* OS2_32 */
/* The HoldFEA is used to hold individual EAs. The member names correspond
directly to those of the FEA structure. Note however, that both szName
and aValue are pointers to the values. An additional field, next, is
used to link the HoldFEA's together to form a linked list. */
struct _HoldFEA
{
#ifdef OS2_32
ULONG oNextEntryOffset; /* Not used in 16 bit code */
#endif /* OS2_32 */
BYTE fEA; /* Flag byte */
BYTE cbName;
USHORT cbValue;
CHAR *szName;
BYTE *aValue;
struct _HoldFEA *next;
};
typedef struct _HoldFEA HOLDFEA;
#define MAX_GEA 500L /* Max size for a GEA List */
#define REF_ASCIIZ 1 /* Reference type for DosEnumAttribute */
#define GET_INFO_LEVEL1 1 /* Get info from SFT */
#define GET_INFO_LEVEL2 2 /* Get size of FEAlist */
#define GET_INFO_LEVEL3 3 /* Get FEAlist given the GEAlist */
#define GET_INFO_LEVEL4 4 /* Get whole FEAlist */
#define GET_INFO_LEVEL5 5 /* Get FSDname */
#define SET_INFO_LEVEL1 1 /* Set info in SFT */
#define SET_INFO_LEVEL2 2 /* Set FEAlist */
typedef enum { STORE_WHOLE_EA, STORE_EA_VALUE } TAG_TYPE;
/* Free_FEAList (pFEA)
Frees the memory used by the linked list of HOLDFEA's pointed to by pFEA */
VOID Free_FEAList( HOLDFEA *pFEA )
{
HOLDFEA *next; /* Holds the next field since we free the structure
before reading the current next field */
/* Step through the list freeing all the fields */
while( pFEA )
{
/* Free the fields of the struct */
next = pFEA->next;
if( pFEA->szName != NULL )
/* Free if non-NULL name */
hfree(pFEA->szName);
if( pFEA->aValue != NULL )
/* Free if non-NULL value */
hfree(pFEA->aValue);
/* Free the pFEA struct itself and move on to the next field */
hfree(pFEA);
pFEA = next;
}
}
/* Read the EA type, this is stored at the start of the EA value */
ULONG getEAType( const CHAR *Value )
{
USHORT Type = *( USHORT * ) Value;
return( Type );
}
/* Return the EA length, stored in pFEA, this done so that it is calculated
in only one place */
ULONG getEALength( const HOLDFEA *pFEA )
{
return( sizeof( FEA2 )
- sizeof( CHAR ) /* Don't include the first element of aValue */
+ pFEA->cbName + 1 /* Length of ASCIIZ name */
+ pFEA->cbValue ); /* The value length */
}
/* Set the first two words of the EA value, this is usually the
EA type and EA size in pFEA, from the values Type and Size */
void setEATypeSize( const HOLDFEA *pFEA, const USHORT Type, const USHORT Size )
{
USHORT *valPtr = ( USHORT * ) pFEA->aValue;
valPtr[ 0 ] = Type;
valPtr[ 1 ] = Size;
}
/* Read the first two words of the EA value, this is usually the
EA type and EA size in pFEA, into the Type and Size */
void getEATypeSize( const HOLDFEA *pFEA, USHORT *Type, USHORT *Size )
{
USHORT *valPtr = ( USHORT * ) pFEA->aValue;
*Type = valPtr[ 0 ];
*Size = valPtr[ 1 ];
}
/* Get the address of the EA value in pFEA, ie skip over the Type and Size */
VOID* getEADataVal (const HOLDFEA *pFEA)
{
/* Skip over the type and size */
return pFEA->aValue + 2 * sizeof ( USHORT );
}
/* QueryEAs (szFileName)
find all EAs that file szFileName has
return these in the linked list of HOLDFEAs
if no EAs exist or the linked list cannot be created then
return NULL
This function is modelled after code from IBM's Toolkit */
HOLDFEA *QueryEAs( const CHAR *szFileName )
{
HOLDFEA *pHoldFEA; /* The start of the linked list */
CHAR *pAllocc = NULL; /* Temp buffer used with DosEnumAttribute */
CHAR *pBigAlloc = NULL; /* Temp buffer to hold each EA as it is read in */
USHORT cbBigAlloc = 0;
ULONG ulEntryNum = 1; /* Count of current EA to read (1-relative) */
ULONG ulEnumCnt; /* Number of EAs for Enum to return, always 1 */
HOLDFEA *pLastIn = 0; /* Points to last EA added, so new EA can link */
HOLDFEA *pNewFEA = NULL; /* Struct to build the new EA in */
FEA2 *pFEA; /* Used to read from Enum's return buffer */
GEA2LIST *pGEAList; /* Ptr used to set up buffer for DosQueryPathInfo() */
EAOP2 eaopGet; /* Used to call DosQueryPathInfo() */
pAllocc = hmalloc( MAX_GEA ); /* Allocate room for a GEA list */
pFEA = ( FEA2 * ) pAllocc;
pHoldFEA = NULL; /* Initialize the linked list */
/* Loop through all the EA's adding them to the list */
while( TRUE )
{
ulEnumCnt = 1; /* No of EAs to retrieve */
if( DosEnumAttribute( REF_ASCIIZ, /* Read into EA name into */
szFileName, /* pAlloc Buffer */
ulEntryNum, pAllocc, MAX_GEA, &ulEnumCnt,
#ifndef OS2_32 /* 16 bit API has an extra parameter */
( LONG ) GET_INFO_LEVEL1, 0 ) )
#else
( LONG ) GET_INFO_LEVEL1 ) )
#endif /* OS2_32 */
break; /* An error */
/* Exit if all the EA's have been read */
if( ulEnumCnt != 1 )
break;
/* Move on to next EA */
ulEntryNum++;
/* Try and allocate the HoldFEA structure */
if( ( pNewFEA = hmalloc( sizeof( HOLDFEA ) ) ) == NULL )
{
hfree( pAllocc );
Free_FEAList( pHoldFEA );
return( NULL );
}
/* Fill in the HoldFEA structure */
pNewFEA->cbName = pFEA->cbName;
pNewFEA->cbValue= pFEA->cbValue;
pNewFEA->fEA = pFEA->fEA;
pNewFEA->next = '\0';
/* Allocate the two arrays */
if( ( pNewFEA->szName = hmalloc( pFEA->cbName + 1 ) ) == NULL || \
( pNewFEA->aValue = hmalloc( pFEA->cbValue ) ) == NULL )
{
/* Out of memory, clean up and exit */
if( pNewFEA->szName )
hfree( pNewFEA->szName );
if( pNewFEA->aValue )
hfree( pNewFEA->aValue );
hfree( pAllocc );
hfree( pNewFEA );
Free_FEAList( pHoldFEA );
return( NULL );
}
/* Copy EA name across */
strcpy( pNewFEA->szName, pFEA->szName );
cbBigAlloc = sizeof( FEA2LIST ) + pNewFEA->cbName + 1 + pNewFEA->cbValue;
/* +1 is for '\0' */
if( ( pBigAlloc = hmalloc( cbBigAlloc ) ) == NULL )
{
hfree( pNewFEA->szName );
hfree( pNewFEA->aValue );
hfree( pAllocc );
hfree( pNewFEA );
Free_FEAList( pHoldFEA );
return( NULL );
}
/* Set up GEAlist structure */
pGEAList = ( GEA2LIST * ) pAllocc;
pGEAList->cbList = sizeof( GEA2LIST ) + pNewFEA->cbName; /* + 1 for NULL */
#ifdef OS2_32
pGEAList->list[ 0 ].oNextEntryOffset = 0L;
#endif /* OS2_32 */
pGEAList->list[ 0 ].cbName = pNewFEA->cbName;
strcpy( pGEAList->list[ 0 ].szName, pNewFEA->szName );
eaopGet.fpGEA2List = ( GEA2LIST FAR * ) pAllocc;
eaopGet.fpFEA2List = ( FEA2LIST FAR * ) pBigAlloc;
eaopGet.fpFEA2List->cbList = cbBigAlloc;
/* Get the complete EA info and copy the EA value */
#ifndef OS2_32 /* The 16 bit API has an extra parameter */
DosQPathInfo( szFileName, FIL_QUERYEASFROMLIST, ( PVOID ) &eaopGet, \
sizeof( EAOP2 ), 0 );
#else
DosQueryPathInfo( szFileName, FIL_QUERYEASFROMLIST, ( PVOID ) &eaopGet, \
sizeof( EAOP2 ) );
#endif /* OS2_32 */
memcpy( pNewFEA->aValue, \
pBigAlloc + sizeof( FEA2LIST ) + pNewFEA->cbName, \
pNewFEA->cbValue );
/* Release the temp. Enum buffer */
hfree( pBigAlloc );
/* Add to the list */
if( pHoldFEA == NULL )
pHoldFEA = pNewFEA;
else
pLastIn->next = pNewFEA;
pLastIn = pNewFEA;
}
/* Free up the GEA buffer for DosEnum() */
hfree( pAllocc );
return pHoldFEA;
}
/* WriteEAs(szFileName, pHoldFEA)
Write the EAs contained in the linked list pointed to by pHoldFEA
to the file szFileName.
Returns TRUE if the write was successful, FALSE otherwise */
BOOLEAN WriteEAs( const char *szFileName, HOLDFEA *pHoldFEA )
{
HOLDFEA *pHFEA = pHoldFEA;
EAOP2 eaopWrite;
CHAR *aPtr = NULL;
USHORT usMemNeeded, usRet;
eaopWrite.fpGEA2List = NULL;
while( pHFEA ) /* Go through each HoldFEA */
{
#ifndef OS2_32 /* The 16 bit API doesn't use the name */
usMemNeeded = sizeof( FEA2LIST ) - \
sizeof( eaopWrite.fpFEA2List->list[0].szName ) + \
pHFEA->cbName + 1 + pHFEA->cbValue;
#else
usMemNeeded = sizeof( FEA2LIST ) + pHFEA->cbName + 1 + pHFEA->cbValue;
#endif
if( ( aPtr = hmalloc( usMemNeeded ) ) == NULL )
return FALSE;
/* Fill in eaop structure */
eaopWrite.fpFEA2List = ( FEA2LIST FAR * ) aPtr;
eaopWrite.fpFEA2List->cbList = usMemNeeded;
#ifdef OS2_32
eaopWrite.fpFEA2List->list[ 0 ].oNextEntryOffset = pHFEA->oNextEntryOffset;
#endif /* OS2_32 */
eaopWrite.fpFEA2List->list[ 0 ].fEA = pHFEA->fEA;
eaopWrite.fpFEA2List->list[ 0 ].cbName = pHFEA->cbName;
eaopWrite.fpFEA2List->list[ 0 ].cbValue = pHFEA->cbValue;
strcpy( eaopWrite.fpFEA2List->list[ 0 ].szName, pHFEA->szName );
memcpy( eaopWrite.fpFEA2List->list[ 0 ].szName + pHFEA->cbName + 1, \
pHFEA->aValue, pHFEA->cbValue );
/* Write out the EA */
usRet = DosSetPathInfo( szFileName, FIL_QUERYEASIZE,
( PVOID ) &eaopWrite, sizeof( EAOP2 ),
#ifndef OS2_32 /* The 16 bit API has an extra parameter */
DSPI_WRTTHRU, 0 );
#else
DSPI_WRTTHRU );
#endif
/* Free up the FEALIST struct */
hfree( aPtr );
/* If the write failed, leave now */
if( usRet )
return FALSE;
pHFEA = pHFEA->next;
}
return( TRUE );
}
/* Copy EA's from a file to an archive in HPACK tagged form.
Either the whole EA will be stored (flag, name len, data len, name, ...)
or just the EA value (the rest can be reconstructed from the HPACK tag.
The current EA tags are ICON, LONGNAME (both just store the value)
and MISC (store the whole EA).
MISC is a superset of the other EA types, and all EA's can in fact be
stored as a MISC tag, however this is less efficient and portable */
LONG storeEAinfo( const BOOLEAN isFile, const char *pathName, const LONG eaSize1, const FD outFD )
{
HOLDFEA *pHoldFEA; /* Global EA linked-list pointer */
HOLDFEA *pFEA;
WORD eaLength = ERROR;
WORD tagLength;
WORD i, dataLength = 0;
TAG_TYPE tagType = STORE_WHOLE_EA;
WORD theTag;
USHORT eaType, Size;
BOOLEAN isDir = !isFile;
BYTE *dataPtr;
/* Check whether there are any EA's to store */
if( !( pHoldFEA = QueryEAs( pathName ) ) )
return (0);
/* Loop through each EA found, using a temporary pointer */
pFEA = pHoldFEA;
while( pFEA != NULL )
{
/* Determine EA type and write appropriate tag info */
switch( getEAType ( pFEA->aValue ) )
{
case EAT_ASCII:
/* Length-preceded ASCII. Check whether the EA can be
recovered from the tag type */
if( !strncmp( pFEA->szName, ".LONGNAME", pFEA->cbName ) && \
( pFEA->fEA == 0 ) )
{
tagType = STORE_EA_VALUE;
theTag = TAG_LONGNAME;
}
else
tagType = STORE_WHOLE_EA;
break;
case EAT_ICON:
/* Length-preceded icon. Check whether the EA can be
recovered from the tag type */
if( !strncmp( pFEA->szName, ".ICON", pFEA->cbName ) && \
( pFEA->fEA == 0 ) )
{
tagType = STORE_EA_VALUE;
theTag = TAG_OS2_ICON;
}
else
tagType = STORE_WHOLE_EA;
break;
default:
tagType = STORE_WHOLE_EA;
break;
}
/* Store type of EA as a tag */
switch( tagType )
{
case STORE_EA_VALUE:
/* Just store the EA value, the other fields
are implicit in the tag */
eaLength = pFEA->cbValue;
eaLength -= 2 * sizeof( USHORT ); /* EA_VALUE.type & .eaSize are not stored */
tagLength = eaLength + sizeof( WORD ); /* For CRC check */
/* Write the tag as either a normal file or a directory tag */
if( isDir )
{
dataLength += addDirData( theTag, TAGFORMAT_STORED, tagLength, LEN_NONE );
checksumDirBegin( RESET_CHECKSUM );
}
else
{
dataLength += writeTag( theTag, TAGFORMAT_STORED, tagLength, LEN_NONE );
checksumBegin( RESET_CHECKSUM );
}
dataLength += tagLength ;
break;
case STORE_WHOLE_EA:
/* Store the whole EA */
#ifndef OS2_32
eaLength = getEALength( pFEA ) - sizeof( CHAR );
/* Don't store the null in the Name */
#else
eaLength = getEALength( pFEA ) - sizeof( pFEA->oNextEntryOffset ) - sizeof( CHAR );
/* Don't store the offset or the null in the Name */
#endif /* OS2_32 */
tagLength = eaLength + sizeof( WORD ); /* For CRC check */
/* Write the tag as either a normal file or a directory tag */
if( isDir )
{
dataLength += addDirData( TAG_OS2_MISC_EA, TAGFORMAT_STORED, tagLength, LEN_NONE );
checksumDirBegin( RESET_CHECKSUM );
}
else
{
dataLength += writeTag( TAG_OS2_MISC_EA, TAGFORMAT_STORED, tagLength, LEN_NONE );
checksumBegin( RESET_CHECKSUM );
}
/* Write the flag, name, etc */
getEATypeSize( pFEA, &eaType, &Size );
if( isDir )
{
fputDirByte( pFEA->fEA );
/* fputDirByte( pFEA->cbName ); */
fputDirWord( pFEA->cbValue );
for( i = 0; i < pFEA->cbName; i++ )
fputDirByte( pFEA->szName[ i ] );
fputDirByte( '\0' );
fputDirWord( eaType );
fputDirWord( Size );
}
else
{
fputByte( pFEA->fEA );
/* fputByte( pFEA->cbName ); */
fputWord( pFEA->cbValue );
for( i = 0; i < pFEA->cbName; i++ )
fputByte( pFEA->szName[ i ] );
fputByte( '\0' );
fputWord( eaType );
fputWord( Size );
}
dataLength += tagLength;
/* Adjust eaLength for the data already written */
eaLength = pFEA->cbValue - 2 * sizeof( USHORT );
/* Don't include type & size */
break;
}
dataPtr = getEADataVal( pFEA ); /* Where data starts */
/* Copy EA data to outFD */
/* Try and compress the buffer before we write it - not implemented yet */
if( isDir )
while( eaLength-- )
fputDirByte( *dataPtr++ );
else
while( eaLength-- )
fputByte( *dataPtr++ );
/* Write CRC for data */
if( isDir )
{
checksumDirEnd();
fputDirWord( crc16 );
}
else
{
checksumEnd();
fputWord( crc16 );
}
/* Go to next EA */
pFEA = pFEA->next;
}
Free_FEAList( pFEA );
return( dataLength );
}
/* Set an EA from tagged EA info, see above for EA tag structure */
void setEAinfo( const char *filePath, const TAGINFO *tagInfo, const FD srcFD )
{
HOLDFEA *pFEA;
char *dataPtr;
WORD eaType, eaSize;
int i, eaLen = ( int ) tagInfo->dataLength - sizeof( WORD );
/* Subtract CRC check, Need this since length is const */
/* Initialize HOLDFEA to receive EA's */
if( ( pFEA = hmalloc( sizeof( HOLDFEA ) ) ) == NULL )
{
/* Skip over the tag before returning */
skipSeek( tagInfo->dataLength );
return;
}
pFEA->next = NULL;
/* Read the header size and the EA flag, don't include checksum */
checksumSetInput( tagInfo->dataLength - sizeof( WORD ), RESET_CHECKSUM );
/* eaName might have to be constructed locally, eg if all icons are called
"ICON" there is little need to store this information, we can examine the
tag type and set the name depending on this info. Otherwise we read the
name (0..255 chars, Pascal string) from srcFD into the EA buffer */
switch( tagInfo->tagID )
{
case TAG_OS2_ICON:
/* Construct EA */
pFEA->cbName = sizeof( ICON_NAME ) - 1;
if( ( pFEA->szName = hmalloc( pFEA->cbName ) ) == NULL )
{
/* Skip data before returning */
skipSeek( tagInfo->dataLength );
hfree( pFEA );
return;
}
strcpy( pFEA->szName, ICON_NAME );
pFEA->fEA = 0;
pFEA->cbValue = eaLen + 2 * sizeof( USHORT ); /* Add type and length */
eaType = EAT_ICON;
eaSize = eaLen;
eaLen = getEALength( pFEA );
break;
case TAG_LONGNAME:
/* Construct EA */
pFEA->cbName = sizeof( LONGNAME_NAME ) - 1;
if( ( pFEA->szName = hmalloc( pFEA->cbName ) ) == NULL )
{
/* Skip data before returning */
skipSeek( tagInfo->dataLength );
hfree( pFEA );
return;
}
strcpy( pFEA->szName, LONGNAME_NAME );
pFEA->fEA = 0;
pFEA->cbValue = eaLen + 2 * sizeof( USHORT ); /* Add type and length */
eaType = EAT_ASCII;
eaSize = eaLen;
eaLen = getEALength( pFEA );
break;
case TAG_OS2_MISC_EA:
/* Read flags, name etc from source file */
pFEA->fEA = fgetByte();
/* i = pFEA->cbName = fgetByte();
if( ( pFEA->szName = hmalloc( pFEA->cbName + 1 ) ) == NULL )
*/
/* Allocate enough room for the name (can't be bigger that the tag) */
if( ( pFEA->szName = hmalloc( tagInfo->dataLength - sizeof( WORD ) - sizeof( BYTE ) ) ) == NULL )
{
/* Again skip data */
skipSeek( tagInfo->dataLength - sizeof( BYTE ) - sizeof( BYTE ) );
hfree( pFEA );
return;
}
pFEA->cbValue = fgetWord();
dataPtr = pFEA->szName;
/* while( i-- )
*dataPtr++ = fgetByte();
pFEA->szName[ pFEA->cbName ] = '\0';
*/
i = 0;
while( ( dataPtr[ i++ ] = fgetByte() ) );
pFEA->cbName = i - 1;
/* Read the type and size */
eaType = fgetWord();
eaSize = fgetWord(); /* Probably the size, but not for multi valued */
eaLen = getEALength( pFEA );
}
if( ( pFEA->aValue = hmalloc( pFEA->cbValue ) ) == NULL )
{
/* Skip data */
skipSeek( tagInfo->dataLength - \
( pFEA->cbValue - 2 * sizeof( USHORT ) ) + \
sizeof( WORD ) );
hfree( pFEA->szName );
hfree( pFEA );
return;
}
setEATypeSize( pFEA, eaType, eaSize );
/* Construct data portion of EA */
i = pFEA->cbValue - 2 * sizeof( USHORT ); /* Don't include the type or size */
dataPtr = getEADataVal( pFEA );
/* We may need to decompress this. Currently compression isn't supported.
When it is, the uncompressed size is given by tagInfo->uncoprLen */
while( i-- )
*dataPtr++ = fgetByte();
/* Make sure data was non-corrupted */
if( fgetWord() == crc16 )
/* Ignore errors on Writing for the moment */
WriteEAs( filePath, pFEA );
Free_FEAList( pFEA );
}
/* Copy all EA's from one file to another */
void copyExtraInfo( const char *srcFilePath, const char *destFilePath )
{
HOLDFEA *pFEA;
pFEA = QueryEAs( srcFilePath );
WriteEAs( destFilePath, pFEA );
Free_FEAList (pFEA);
}
/* Set any necessary extra information associated with a file */
static void setEA( const char *filePath, const WORD type, const char *name, \
const BYTE *value, const WORD length )
{
HOLDFEA *pFEA;
BYTE *dataPtr;
/* Initialize HOLDFEA to receive EA's */
if( ( pFEA = hmalloc( sizeof( HOLDFEA ) ) ) == NULL )
return;
pFEA->next = NULL;
#ifdef OS2_32
pFEA->oNextEntryOffset = 0L;
#endif /* OS2_32 */
pFEA->fEA = 0;
pFEA->cbName = strlen ( name );
pFEA->cbValue = length + 2 * sizeof( WORD ); /* Include type and size */
if( ( pFEA->szName = hmalloc( pFEA->cbName ) ) == NULL )
{
hfree( pFEA );
return;
}
strcpy( pFEA->szName, name);
if( ( pFEA->aValue = hmalloc( pFEA->cbValue ) ) == NULL )
{
hfree( pFEA->szName );
hfree( pFEA );
return;
}
setEATypeSize( pFEA, type, length );
dataPtr = getEADataVal( pFEA );
memcpy( dataPtr, value, length );
WriteEAs( filePath, pFEA );
Free_FEAList( pFEA );
}
void setExtraInfo( const char *filePath )
{
/* Attach the type, icon, and file creator information to the archive */
setEA( filePath, EAT_ASCII, ".TYPE", EA_HPACK_ARCH_TYPE, \
sizeof( EA_HPACK_ARCH_TYPE ) - 1 );
/* putEA( theFD, ".ICON", EA_HPACK_ICON, \ */
/* sizeof( EA_HPACK_ICON ), EAT_ICON ); */
/* putEA( theFD, ".ASSOCTBL", EA_HPACK_ASSOCTBL, \ */
/* sizeof( EA_HPACK_ASSOCTBL ), EAT_???? ); */
}
/* Add a longname EA to a file or directory if it's been truncated on
extraction */
void addLongName( const char *filePath, const char *longName )
{
FD theFD;
if( ( theFD = hopen( filePath, O_RDONLY | S_DENYRDWR ) ) == ERROR )
/* This should never happen since we've just created the file/dir */
return;
/* Save the non-truncated name as an EA */
setEA( filePath, EAT_ASCII, ".LONGNAME", ( BYTE * ) longName, strlen( longName ) );
hclose( theFD );
}
#ifndef OS2_32
/* Determine the filesystem type. The structure for the filesystem info
seems to be:
USHORT iType; \* Item type *\
USHORT cbName; \* Length of item name, sans NULL *\
UCHAR szName[]; \* ASCIIZ item name *\
NULL
USHORT cbFSDName; \* Length of FSD name, sans NULL *\
UCHAR szFSDName[ 1 ]; \* ASCIIZ FSD name *\
NULL
USHORT cbFSAData; \* Length of FSD Attach data returned *\
UCHAR rgFSAData[ 60 ]; \* FSD Attach data from FSD *\
NULL */
typedef struct {
USHORT cbName; /* Length of name, sans NULL */
UCHAR szName[ 1 ]; /* ASCIIZ name */
} FSNAME;
typedef struct { /* Data structure for QFSAttach */
USHORT iType; /* Item type */
FSNAME Name; /* Item name */
UCHAR rgFSAData[ 59 ]; /* Place to store data */
} FSQINFO;
typedef FSQINFO FAR *PFSQINFO;
BOOLEAN queryFilesystemType( char *path )
{
USHORT nDrive;
ULONG lMap;
FSQINFO bData;
BYTE bName[ 3 ];
FSNAME *pFSName;
USHORT cbData;
/* Get drive */
if( ( strlen( path ) > 0 ) && path[ 1 ] == ':' )
bName[ 0 ] = path[ 0 ];
else
{
DosQCurDisk( &nDrive, &lMap );
bName[ 0 ] = ( char ) ( nDrive + '@' );
}
bName[ 1 ] = ':';
bName[ 2 ] = 0;
cbData = sizeof( bData );
DosQFSAttach( ( PSZ ) bName, 0U, 1U, ( PBYTE ) &bData, &cbData, 0L );
pFSName = &bData.Name;
( char * ) pFSName += pFSName->cbName + sizeof( pFSName->cbName ) + 1;
return( strcmp ( ( char * ) &( pFSName->szName[ 0 ] ), "FAT" ) != 0 );
}
#else
/* Determine the file system type. This uses a strange function that
populates a variables sised buffer that YOU have to declare, not knowing
how big to actually make it! Plus to access the ASCIIZ strings you need
to play games with the offsets to find the real potition of the data you
are after */
#define FSQBUFFERSIZE 64
BOOLEAN queryFilesystemType( char *path )
{
ULONG nDrive;
ULONG lMap;
char buffer[ FSQBUFFERSIZE ];
FSQBUFFER2 *bData = ( FSQBUFFER2 * ) buffer;
char bName[ 3 ];
ULONG bDataLen;
if( ( strlen( path ) > 0 ) && path[ 1 ] == ':' )
bName[ 0 ] = path[ 0 ];
else
{
DosQueryCurrentDisk( &nDrive, &lMap );
bName[ 0 ] = ( char ) ( nDrive + 'A' - 1 );
}
bName[ 1 ] = ':';
bName[ 2 ] = 0;
bDataLen = FSQBUFFERSIZE;
DosQueryFSAttach( bName, 0, FSAIL_QUERYNAME, bData, &bDataLen );
return( strcmp( bData->szFSDName + bData->cbName, "FAT" ) != 0 );
}
#if defined( __gcc ) && !defined( __EMX__ )
/* NLS support for string case conversion */
static unsigned char cLCtbl[ 256 ], cUCtbl[ 256 ];
static BOOLEAN bNLSinit = FALSE;
static void InitNLS( void )
{
int i, uppercaseChar;
COUNTRYCODE countryCode;
/* Flag the fact that the xlate tables are initialized */
bNLSInit = TRUE;
/* Set up default tables */
for( i = 0; i < 256; i++ )
cUCtbl[ i ] = cLCtbl[ i ] = ( unsigned char ) i;
/* Set up map table */
countryCode.country = countryCode.codepage = 0;
DosMapCase( sizeof( cUCtbl ), &countryCode, ( PCHAR ) cUCtbl );
for( i = 0; i < 256; i++ )
if( ( uppercaseChar = cUCtbl[ i ] ) != i && \
cLCtbl[ uppercaseChar ] == ( unsigned char ) uppercaseChar )
cLCtbl[ uppercaseChar ] = ( unsigned char ) i;
for( i = 'A'; i <= 'Z'; i++ )
cLCtbl[ i ] = ( unsigned char ) ( i - 'A' + 'a' );
}
void strlwr( char *string )
{
char *strPtr = string;
if( !bNLSinit )
InitNLS();
while( *strPtr )
*strPtr = cLowerCase[ ( int ) *strPtr ];
}
int strnicmp( char *src, char *dest, int length )
{
char srcLower[ length ]; /* Note cool GNUC variable length array! */
char destLower[ length ]; /* Note cool GNUC variable length array! */
strlwr( strcpy( srcLower, src ) );
strlwr( strcpy( destLower, dest ) );
return( strncmp( srcLower, destLower, length ) );
}
#endif /* __gcc && !__EMX__ */
#endif /* OS2_32 */