Files
mars-flaim/flaim/src/ftkmisc.cpp

785 lines
17 KiB
C++

//-------------------------------------------------------------------------
// Desc: Miscellaneous toolkit functions.
// Tabs: 3
//
// Copyright (c) 2000-2003,2005-2006 Novell, Inc. All Rights Reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of version 2 of the GNU General Public
// License as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, contact Novell, Inc.
//
// To contact Novell about this file by physical or electronic mail,
// you may find current contact information at www.novell.com
//
// $Id: ftkmisc.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $
//-------------------------------------------------------------------------
#include "flaimsys.h"
FLMUINT gv_uiSerialInitCount = 0;
f_randomGenerator gv_uiSerialRandom;
F_MUTEX gv_hSerialMutex = F_MUTEX_NULL;
#if defined( FLM_NLM)
#pragma pack(push,1)
extern "C"
{
LONG gv_lMyModuleHandle = 0;
LONG gv_lFlmTimerTag = 0;
LONG gv_lAllocRTag = 0;
static f_randomGenerator gv_flmRandGenerator;
static SEMAPHORE gv_lFlmRandSemaphore = F_SEM_NULL;
static LONG gv_lFlmStartTicks = 0;
static FLMATOMIC gv_NetWareStartupCount = 0;
}
#pragma pack(pop)
void f_sleep(
FLMUINT uiMilliseconds)
{
if( ! uiMilliseconds )
{
kYieldThread();
}
else
{
kDelayThread( uiMilliseconds);
}
}
#endif
#if defined( FLM_UNIX)
#ifdef FLM_AIX
#ifndef nsleep
extern "C"
{
extern int nsleep( struct timestruc_t *, struct timestruc_t *);
}
#endif
#endif
/****************************************************************************
Desc: This routine causes the calling process to delay the given number
of milliseconds. Due to the nature of the call, the actual sleep
time is almost guaranteed to be different from requested sleep time.
In: milliseconds - the number of milliseconds to delay
****************************************************************************/
void f_sleep(
FLMUINT uiMilliseconds)
{
#ifdef FLM_AIX
struct timestruc_t timeout;
struct timestruc_t remain;
#else
struct timespec timeout;
#endif
timeout.tv_sec = (uiMilliseconds / 1000);
timeout.tv_nsec = (uiMilliseconds % 1000) * 1000000;
#ifdef FLM_AIX
nsleep(&timeout, &remain);
#else
nanosleep(&timeout, 0);
#endif
}
#endif
#ifdef FLM_UNIX
/***************************************************************************
Desc: Map POSIX errno to Flaim IO errors.
***************************************************************************/
RCODE MapErrnoToFlaimErr(
int err,
RCODE defaultRc)
{
/* Switch on passed in error code value */
switch (err)
{
case 0:
return( FERR_OK);
case ENOENT:
return( RC_SET( FERR_IO_PATH_NOT_FOUND));
case EACCES:
case EEXIST:
return( RC_SET( FERR_IO_ACCESS_DENIED));
case EINVAL:
flmAssert( 0);
return( RC_SET( FERR_INVALID_PARM));
case EIO:
return( RC_SET( FERR_IO_DISK_FULL));
case ENOTDIR:
return( RC_SET( FERR_IO_MODIFY_ERR));
#ifdef EBADFD
case EBADFD:
return( RC_SET( FERR_IO_BAD_FILE_HANDLE));
#endif
case EOF:
return( RC_SET( FERR_IO_END_OF_FILE));
case EMFILE:
return( RC_SET( FERR_IO_NO_MORE_FILES));
default:
return( RC_SET( defaultRc));
}
}
#endif
/****************************************************************************
Desc: This routine initializes the serial number generator. If the O/S
does not provide support for GUID generation or if the GUID
routines fail for some reason, a pseudo-GUID will be generated.
Notes: This routine should only be called once by the process.
****************************************************************************/
RCODE f_initSerialNumberGenerator( void)
{
FLMUINT uiTime;
RCODE rc = FERR_OK;
if (++gv_uiSerialInitCount > 1)
{
goto Exit;
}
if( RC_BAD( rc = f_mutexCreate( &gv_hSerialMutex)))
{
goto Exit;
}
f_timeGetSeconds( &uiTime );
#if defined( FLM_WIN)
f_randomSetSeed( &gv_uiSerialRandom,
(FLMUINT32)(uiTime ^ (FLMUINT)_getpid()));
#elif defined( FLM_NLM)
f_randomSetSeed( &gv_uiSerialRandom,
(FLMUINT32)(uiTime ^ (FLMUINT)GetRunningProcess()));
#elif defined( FLM_UNIX)
f_randomSetSeed( &gv_uiSerialRandom,
(FLMUINT32)(uiTime ^ (FLMUINT)getpid()));
#else
f_randomSetSeed( &gv_uiSerialRandom, (FLMUINT32)uiTime);
#endif
Exit:
return( rc);
}
/****************************************************************************
Desc: This routine will use the operating system calls to generate a
"globally unique" identifier. Typically, this is based on the
MAC address of an ethernet card installed in the machine. If the
machine does not have an ethernet card, or if the OS does not
support generating GUIDs, this routine will generate a pseudo-GUID
using a random number generator. A serial number is 16-bytes.
****************************************************************************/
RCODE f_createSerialNumber(
FLMBYTE * pszSerialNum)
{
RCODE rc = FERR_OK;
#if defined( FLM_WIN)
UUID uuidVal;
RPC_STATUS err = UuidCreate( &uuidVal);
if (err == RPC_S_OK || err == RPC_S_UUID_LOCAL_ONLY)
{
UD2FBA( (FLMUINT32)uuidVal.Data1, &pszSerialNum[ 0]);
UW2FBA( (FLMUINT16)uuidVal.Data2, &pszSerialNum[ 4]);
UW2FBA( (FLMUINT16)uuidVal.Data3, &pszSerialNum[ 6]);
f_memcpy( &pszSerialNum[ 8], (FLMBYTE *)uuidVal.Data4, 8);
goto Exit;
}
#elif defined( FLM_NLM)
NWGUID guidVal;
int err = SGUIDCreate( &guidVal);
if( !err || err == 1) // NOTE: 1 == SGUID_WARN_RANDOM_NODE
{
UD2FBA( guidVal.time_low, &pszSerialNum[ 0]);
UW2FBA( guidVal.time_mid, &pszSerialNum[ 4]);
UW2FBA( guidVal.time_hi_and_version, &pszSerialNum[ 6]);
pszSerialNum[ 8] = guidVal.clk_seq_hi_res;
pszSerialNum[ 9] = guidVal.clk_seq_low;
f_memcpy( &pszSerialNum[ 10], (FLMBYTE *)guidVal.node, 6);
goto Exit;
}
#endif
/*
Generate a pseudo GUID value
*/
flmAssert( gv_hSerialMutex != F_MUTEX_NULL);
f_mutexLock( gv_hSerialMutex);
UD2FBA( (FLMUINT32)f_randomLong(
&gv_uiSerialRandom), &pszSerialNum[ 0]);
UD2FBA( (FLMUINT32)f_randomLong(
&gv_uiSerialRandom), &pszSerialNum[ 4]);
UD2FBA( (FLMUINT32)f_randomLong(
&gv_uiSerialRandom), &pszSerialNum[ 8]);
UD2FBA( (FLMUINT32)f_randomLong(
&gv_uiSerialRandom), &pszSerialNum[ 12]);
f_mutexUnlock( gv_hSerialMutex);
#if defined( FLM_WIN) || defined( FLM_NLM)
Exit:
#endif
return( rc);
}
/****************************************************************************
Notes: This routine should only be called once by the process.
****************************************************************************/
void f_freeSerialNumberGenerator( void)
{
if( (--gv_uiSerialInitCount) > 0)
{
return;
}
if( gv_hSerialMutex != F_MUTEX_NULL)
{
f_mutexDestroy( &gv_hSerialMutex);
}
}
/****************************************************************************
Desc: Generates a table of remainders for each 8-bit byte. The resulting
table is used by flmUpdateCRC to calculate a CRC value. The table
must be freed via a call to f_freeCRCTable.
*****************************************************************************/
RCODE f_initCRCTable(
FLMUINT32 ** ppui32CRCTbl)
{
FLMUINT32 * pTable;
FLMUINT32 ui32Val;
FLMUINT32 ui32Loop;
FLMUINT32 ui32SubLoop;
RCODE rc = FERR_OK;
// Use the standard degree-32 polynomial used by
// Ethernet, PKZIP, etc. for computing the CRC of
// a data stream. This is the little-endian
// representation of the polynomial. The big-endian
// representation is 0x04C11DB7.
#define CRC_POLYNOMIAL ((FLMUINT32)0xEDB88320)
*ppui32CRCTbl = NULL;
if( RC_BAD( rc = f_alloc( 256 * sizeof( FLMUINT32), &pTable)))
{
goto Exit;
}
for( ui32Loop = 0; ui32Loop < 256; ui32Loop++)
{
ui32Val = ui32Loop;
for( ui32SubLoop = 0; ui32SubLoop < 8; ui32SubLoop++)
{
if( ui32Val & 0x00000001)
{
ui32Val = CRC_POLYNOMIAL ^ (ui32Val >> 1);
}
else
{
ui32Val >>= 1;
}
}
pTable[ ui32Loop] = ui32Val;
}
*ppui32CRCTbl = pTable;
pTable = NULL;
Exit:
if( pTable)
{
f_free( &pTable);
}
return( rc);
}
/****************************************************************************
Desc: Computes the CRC of the passed-in data buffer. Multiple calls can
be made to this routine to build a CRC over multiple data buffers.
On the first call, *pui32CRC must be initialized to something
(0, etc.). For generating CRCs that are compatible with PKZIP,
*pui32CRC should be initialized to 0xFFFFFFFF and the ones complement
of the resulting CRC should be computed.
*****************************************************************************/
void f_updateCRC(
FLMUINT32 * pui32CRCTbl,
FLMBYTE * pucBlk,
FLMUINT uiBlkSize,
FLMUINT32 * pui32CRC)
{
FLMUINT32 ui32CRC = *pui32CRC;
FLMUINT uiLoop;
for( uiLoop = 0; uiLoop < uiBlkSize; uiLoop++)
{
ui32CRC = (ui32CRC >> 8) ^ pui32CRCTbl[
((FLMBYTE)(ui32CRC & 0x000000FF)) ^ pucBlk[ uiLoop]];
}
*pui32CRC = ui32CRC;
}
/****************************************************************************
Desc:
****************************************************************************/
FLMUINT f_breakpoint(
FLMUINT uiBreakFlag)
{
if( uiBreakFlag)
{
#ifdef FLM_NLM
EnterDebugger();
#else
flmAssert( 0);
#endif
}
return( 0);
}
/****************************************************************************
Desc: Function that must be called within a NLM's startup routine.
****************************************************************************/
#ifdef FLM_NLM
RCODE f_netwareStartup( void)
{
RCODE rc = FERR_OK;
if( flmAtomicInc( &gv_NetWareStartupCount) != 1)
{
goto Exit;
}
gv_lMyModuleHandle = CFindLoadModuleHandle( (void *)f_netwareShutdown);
// Allocate the needed resource tags
if( (gv_lAllocRTag = AllocateResourceTag(
gv_lMyModuleHandle,
(BYTE *)"NOVDB Memory", AllocSignature)) == NULL)
{
rc = RC_SET( FERR_MEM);
goto Exit;
}
if( (gv_lFlmTimerTag = AllocateResourceTag(
gv_lMyModuleHandle,
(BYTE *)"NOVDB Timer", TimerSignature)) == NULL)
{
rc = RC_SET( FERR_MEM);
goto Exit;
}
gv_lFlmStartTicks = GetCurrentTime();
// Random Generator initialization
if( (gv_lFlmRandSemaphore = kSemaphoreAlloc(
(BYTE *)"NOVDB", 1)) == F_SEM_NULL)
{
rc = RC_SET( FERR_MEM);
goto Exit;
}
f_randomSetSeed( &gv_flmRandGenerator, 1);
Exit:
if( RC_BAD( rc))
{
f_netwareShutdown();
}
return( rc);
}
#endif
/****************************************************************************
Desc: Closes (Frees) any resources used by FLAIM's clib patches layer.
****************************************************************************/
#ifdef FLM_NLM
void f_netwareShutdown( void)
{
// Call exit function.
if( flmAtomicDec( &gv_NetWareStartupCount) != 0)
{
goto Exit;
}
if( gv_lAllocRTag)
{
ReturnResourceTag( gv_lAllocRTag, 1);
gv_lAllocRTag = 0;
}
if( gv_lFlmTimerTag)
{
ReturnResourceTag( gv_lFlmTimerTag, 1);
gv_lFlmTimerTag = 0;
}
if( gv_lFlmRandSemaphore)
{
kSemaphoreFree( gv_lFlmRandSemaphore);
gv_lFlmRandSemaphore = 0;
}
gv_lFlmStartTicks = 0;
gv_lMyModuleHandle = 0;
Exit:
return;
}
#endif
/****************************************************************************
Desc:
****************************************************************************/
#ifdef FLM_NLM
FLMUINT f_getNLMHandle( void)
{
return( (FLMUINT)gv_lMyModuleHandle);
}
#endif
/****************************************************************************
Desc: This routine is required to work around known bugs or inefficiencies
in various incarnations of clib.
****************************************************************************/
#undef f_memset
void * f_memset(
void * pvMem,
FLMBYTE ucByte,
FLMUINT uiSize)
{
#ifndef FLM_NLM
return( memset( pvMem, ucByte, uiSize));
#else
char * cp = (char *)pvMem;
unsigned dwordLength;
unsigned long dwordVal;
dwordVal = ((unsigned long)ucByte << 24) |
((unsigned long)ucByte << 16) |
((unsigned long)ucByte << 8) |
(unsigned long)ucByte;
while( uiSize && ((long)cp & 3L))
{
*cp++ = (char)ucByte;
uiSize--;
}
dwordLength = uiSize >> 2;
if( dwordLength != 0)
{
CSetD( dwordVal, (void *)cp, dwordLength);
cp += (dwordLength << 2);
uiSize -= (dwordLength << 2);
}
while( uiSize)
{
*cp++ = (char)ucByte;
uiSize--;
}
return( pvMem);
#endif
}
/****************************************************************************
Desc: This routine is required to work around known bugs or inefficiencies
in various incarnations of clib.
****************************************************************************/
#undef f_memmove
void * f_memmove(
void * pvDest,
const void * pvSrc,
FLMUINT uiSize)
{
#ifndef FLM_NLM
return( memmove( pvDest, pvSrc, uiSize));
#else
#define CMOVB_THRESHOLD 16
char *s = (char *)pvSrc;
char *d = (char *)pvDest;
unsigned uDiff;
if( (char *)(s + uiSize) < d || (char *)(d + uiSize) < s)
{
// The source and destination do not overlap.
CMoveFast( (void *)s, d, (LONG)uiSize);
}
else if( s < d)
{
// Source preceeds the destination, with overlap.
uDiff = (unsigned)(d - s);
d += uiSize;
s += uiSize;
if( uDiff >= CMOVB_THRESHOLD)
{
for( ;;)
{
if( uiSize < uDiff)
{
break;
}
// Copy the tail
s -= uDiff;
d -= uDiff;
uiSize -= uDiff;
CMoveFast( (void *)s, d, (LONG)uDiff);
}
}
// Copy remaining bytes.
while( uiSize--)
{
*--d = *--s;
}
}
else if( s > d)
{
// Source follows the destination, with overlap.
uDiff = (unsigned)(s - d);
if( uDiff >= CMOVB_THRESHOLD)
{
for( ;;)
{
if( uiSize < uDiff)
{
break;
}
// Copy the head
CMoveFast( (void *)s, d, (LONG)uDiff);
uiSize -= uDiff;
d += uDiff;
s += uDiff;
}
}
// Copy the remaining bytes
while( uiSize--)
{
*d++ = *s++;
}
}
// Else, the regions overlap completely (s == d). Do nothing.
return( pvDest);
#endif
}
/****************************************************************************
Desc: Performs a comparison of m1 to m2, for a maximum
length of size bytes.
****************************************************************************/
#undef f_memcmp
FLMINT f_memcmp(
const void * pvMem1,
const void * pvMem2,
FLMUINT uiSize)
{
unsigned char * s1;
unsigned char * s2;
for (s1 = (unsigned char *)pvMem1, s2 = (unsigned char *)pvMem2;
uiSize > 0; uiSize--, s1++, s2++)
{
if (*s1 == *s2)
{
continue;
}
else if( *s1 > *s2)
{
return( 1);
}
else
{
return( -1);
}
}
return( 0);
}
/****************************************************************************
Desc: This routine is required to work around known bugs or inefficiencies
in various incarnations of clib.
****************************************************************************/
#undef f_stricmp
FLMINT f_stricmp(
const char * pszStr1,
const char * pszStr2)
{
while( f_toupper( *pszStr1) == f_toupper( *pszStr2) && *pszStr1)
{
pszStr1++;
pszStr2++;
}
return( (FLMINT)( f_toupper( *pszStr1) - f_toupper( *pszStr2)));
}
/****************************************************************************
Desc: Performs a signed comparison of s1 to s2, for a maximum
length of n bytes, starting with the first character in
each string and continuing with subsequent characters until
the corresponding characters differ, or until n characters
have been examined.
****************************************************************************/
#undef f_strnicmp
FLMINT f_strnicmp(
const char * pszStr1,
const char * pszStr2,
FLMINT iLen)
{
if( !pszStr1 || !pszStr2)
{
return( (pszStr1 == pszStr2)
? 0
: (pszStr1 ? 1 : -1));
}
while( iLen-- && *pszStr1 && *pszStr2 &&
(f_toupper( *pszStr1) == f_toupper( *pszStr2)))
{
pszStr1++;
pszStr2++;
}
return( (iLen == -1)
? 0
: (f_toupper( *pszStr1) - f_toupper( *pszStr2)));
}
/****************************************************************************
Desc:
****************************************************************************/
#undef f_strupr
char * f_strupr(
char * pszStr)
{
while( *pszStr)
{
*pszStr = f_toupper( *pszStr);
pszStr++;
}
return( pszStr);
}
/****************************************************************************
Desc:
****************************************************************************/
#undef f_strstr
char * f_strstr(
const char * pszStr1,
const char * pszStr2)
{
FLMUINT i;
FLMUINT j;
FLMUINT k;
if ( !pszStr1 || !pszStr2)
{
return( NULL);
}
for( i = 0; pszStr1[i] != '\0'; i++)
{
for( j=i, k=0; pszStr2[k] != '\0' &&
pszStr1[j] == pszStr2[k]; j++, k++)
{
;
}
if ( k > 0 && pszStr2[k] == '\0')
{
return( (char *)&pszStr1[i]);
}
}
return( NULL);
}
/****************************************************************************
Desc:
****************************************************************************/
#undef f_strchr
char * f_strchr(
const char * pszStr,
char c)
{
if( !pszStr)
{
return( NULL);
}
while (*pszStr && *pszStr != (FLMBYTE)c)
{
pszStr++;
}
return( (char *)((*pszStr == c)
? pszStr
: NULL));
}