2901 lines
		
	
	
		
			74 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			2901 lines
		
	
	
		
			74 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/* c4trans.c   (c)Copyright Sequiter Software Inc., 1988-1996.  All rights reserved. */
 | 
						|
 | 
						|
#include "d4all.h"
 | 
						|
 | 
						|
#ifndef UNIX
 | 
						|
   #ifdef __TURBOC__
 | 
						|
      #pragma hdrstop
 | 
						|
   #endif
 | 
						|
#endif
 | 
						|
 | 
						|
/* TRANSACTION FILE FORMAT
 | 
						|
   -----------------------
 | 
						|
 | 
						|
   Every entry in the transaction file has the following format:
 | 
						|
 | 
						|
   [unisgned short int] - transaction entry length (including this length entry)
 | 
						|
   [transaction data]
 | 
						|
   [transaction header]
 | 
						|
 | 
						|
   The transaction file can be read either forwards or backwards in this
 | 
						|
   fashion.  It is usually read backwards when performing rollbacks, but
 | 
						|
   it is useful to read forwards for database history review purposes or
 | 
						|
   in case the transaction file itself is corrupt at some point.
 | 
						|
*/
 | 
						|
 | 
						|
#ifndef S4OFF_TRAN
 | 
						|
#ifndef S4OFF_WRITE
 | 
						|
 | 
						|
static void tran4lowCloseDelayed( TRAN4 *trans )
 | 
						|
{
 | 
						|
   DATA4 *data ;
 | 
						|
 | 
						|
   for ( ;; )
 | 
						|
   {
 | 
						|
      data = (DATA4 *)l4pop( &trans->closedDataFiles ) ;
 | 
						|
      if ( data == 0 )
 | 
						|
         break ;
 | 
						|
      l4add( tran4dataList( data->trans ), data ) ;
 | 
						|
      d4close( data ) ;
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
#ifndef S4CLIENT
 | 
						|
static DATA4 *tran4dataFull( TRAN4 *, const long, const long ) ;
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef E4ANALYZE
 | 
						|
static int code4transVerify( CODE4TRANS *, int ) ;
 | 
						|
#endif  /* E4ANALYZE */
 | 
						|
 | 
						|
#ifndef S4SERVER
 | 
						|
static void code4invalidate( CODE4 * ) ;
 | 
						|
#endif
 | 
						|
#ifndef S4CLIENT
 | 
						|
#ifdef E4ANALYZE
 | 
						|
static int tran4fileVerify( TRAN4FILE *t4, int subs )
 | 
						|
{
 | 
						|
   int rc ;
 | 
						|
 | 
						|
   if ( t4 == 0 )
 | 
						|
      return error4( 0, e4parm_null, E93801 ) ;
 | 
						|
 | 
						|
   if ( t4->c4trans == 0 )
 | 
						|
      return error4( 0, e4parm, E93801 ) ;
 | 
						|
 | 
						|
   if ( subs == 1 )
 | 
						|
      if ( ( rc = code4transVerify( t4->c4trans, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
 | 
						|
   return 0 ;
 | 
						|
}
 | 
						|
#endif  /* E4ANALYZE */
 | 
						|
 | 
						|
static int tran4fileInit( TRAN4FILE *t4, CODE4TRANS *c4trans )
 | 
						|
{
 | 
						|
   t4->c4trans = c4trans ;
 | 
						|
   memset( &t4->file, 0, sizeof( FILE4 ) ) ;
 | 
						|
   t4->file.hand = -1 ;
 | 
						|
   t4->transId = -1 ;
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      return tran4fileVerify( t4, 0 ) ;
 | 
						|
   #else
 | 
						|
      return 0 ;
 | 
						|
   #endif
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION tran4fileAppend( TRAN4FILE *t4, LOG4HEADER *header, void *dta )
 | 
						|
{
 | 
						|
   long filePos ;
 | 
						|
   int rc ;
 | 
						|
   TRAN4ENTRY_LEN len ;
 | 
						|
 | 
						|
   #ifdef E4PARM_LOW
 | 
						|
      if ( header == 0 )
 | 
						|
         return error4( t4->c4trans->c4, e4parm_null, E93801 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( ( rc = tran4fileVerify( t4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
 | 
						|
      if ( t4->file.hand < 0 )
 | 
						|
         return error4( t4->c4trans->c4, e4struct, E93801 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   filePos = file4len( &t4->file ) ;
 | 
						|
   if ( filePos < 0 )
 | 
						|
      return (int)filePos ;
 | 
						|
 | 
						|
   len = tran4entryLen( header ) ;
 | 
						|
   rc = file4write( &t4->file, filePos, &len, sizeof( TRAN4ENTRY_LEN ) ) ;
 | 
						|
   if ( rc < 0 )
 | 
						|
      return rc ;
 | 
						|
   filePos += sizeof( len ) ;
 | 
						|
 | 
						|
   if ( header->dataLen != 0 )
 | 
						|
   {
 | 
						|
      #ifdef E4PARM_LOW
 | 
						|
         if ( dta == 0 )
 | 
						|
            return error4( t4->c4trans->c4, e4parm_null, E93801 ) ;
 | 
						|
      #endif
 | 
						|
      rc = file4write( &t4->file, filePos, dta, (unsigned int)header->dataLen ) ;
 | 
						|
      if ( rc < 0 )
 | 
						|
         return rc ;
 | 
						|
      filePos += header->dataLen ;
 | 
						|
   }
 | 
						|
 | 
						|
   rc = file4write( &t4->file, filePos, header, sizeof( LOG4HEADER ) ) ;
 | 
						|
   if ( rc < 0 )
 | 
						|
      return rc ;
 | 
						|
 | 
						|
   return file4flush( &t4->file ) ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION tran4lowAppend( TRAN4 *t4, void *dta )
 | 
						|
{
 | 
						|
   int rc ;
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( t4->dataPos != 0 )
 | 
						|
   {
 | 
						|
      dta = t4->c4trans->c4->tranData ;
 | 
						|
      t4->dataPos = 0 ;
 | 
						|
   }
 | 
						|
 | 
						|
   t4->pos = -1 ;
 | 
						|
   rc = tran4fileAppend( t4->c4trans->transFile, &t4->header, dta ) ;
 | 
						|
 | 
						|
   memset( &t4->header, 0, sizeof( LOG4HEADER ) ) ;
 | 
						|
   return rc ;
 | 
						|
}
 | 
						|
 | 
						|
static int tran4fileClose( TRAN4FILE *t4 )
 | 
						|
{
 | 
						|
   int rc, saveRc, saveErr ;
 | 
						|
   #ifdef S4SERVER
 | 
						|
      SERVER4CLIENT *client ;
 | 
						|
   #endif
 | 
						|
 | 
						|
/* must close files no matter what */
 | 
						|
/*   #ifdef E4ANALYZE*/
 | 
						|
/*      if ( ( rc = tran4fileVerify( t4, 1 ) ) < 0 )*/
 | 
						|
/*         return rc ;*/
 | 
						|
/*   #endif*/
 | 
						|
 | 
						|
   if ( t4->file.hand < 0 )
 | 
						|
      return 0 ;
 | 
						|
 | 
						|
   saveRc = 0 ;
 | 
						|
 | 
						|
   #ifdef S4SERVER
 | 
						|
      /* ensure there are no active transactions */
 | 
						|
      client = (SERVER4CLIENT *)l4first( &t4->c4trans->c4->server->clients ) ;
 | 
						|
      for ( ;; )
 | 
						|
      {
 | 
						|
         if ( client == 0 )
 | 
						|
            break ;
 | 
						|
         if ( client->trans.currentTranStatus == r4active )
 | 
						|
         {
 | 
						|
            if ( error4code( t4->c4trans->c4 ) == 0 )
 | 
						|
               saveRc = error4( t4->c4trans->c4, e4trans, E93801 ) ;
 | 
						|
            t4->validState = 0 ;
 | 
						|
         }
 | 
						|
      }
 | 
						|
   #endif
 | 
						|
 | 
						|
   saveErr = error4code( t4->c4trans->c4 ) ;
 | 
						|
   error4set( t4->c4trans->c4, 0 ) ;
 | 
						|
 | 
						|
   rc = file4close( &t4->file ) ;
 | 
						|
   if ( rc < 0 && saveRc == 0 )
 | 
						|
      saveRc = rc ;
 | 
						|
 | 
						|
   t4->c4trans->c4->errorCode = saveErr ;
 | 
						|
 | 
						|
   return saveRc ;
 | 
						|
}
 | 
						|
 | 
						|
int tran4fileCreate( TRAN4FILE *t4, const char *name )
 | 
						|
{
 | 
						|
   char buf[258] ;
 | 
						|
   int rc ;
 | 
						|
   LOG4HEADER header ;
 | 
						|
   CODE4 *c4 ;
 | 
						|
   #ifndef S4OFF_MULTI
 | 
						|
      int oldExcl ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( ( rc = tran4fileVerify( t4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   c4 = t4->c4trans->c4 ;
 | 
						|
 | 
						|
   #ifdef E4PARM_LOW
 | 
						|
      if ( name == 0 )
 | 
						|
         return error4( c4, e4parm_null, E93801 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   memcpy( buf, name, strlen( name ) + 1 ) ;
 | 
						|
   u4nameExt( buf, sizeof( buf ), "log", 0 ) ;
 | 
						|
   #ifndef S4OFF_MULTI
 | 
						|
      oldExcl = c4->accessMode ;
 | 
						|
      c4->accessMode = OPEN4DENY_NONE ;
 | 
						|
   #endif
 | 
						|
   rc = file4create( &t4->file, c4, buf, 1 ) ;
 | 
						|
   #ifndef S4OFF_MULTI
 | 
						|
      c4->accessMode = oldExcl ;
 | 
						|
   #endif
 | 
						|
   if ( rc < 0 )
 | 
						|
      return rc ;
 | 
						|
   t4->validState = 1;
 | 
						|
   memset( &header, 0, sizeof( header ) ) ;
 | 
						|
   header.type = TRAN4SHUTDOWN ;
 | 
						|
   header.serverDataId = TRAN4VERSION_NUM ;
 | 
						|
   rc = tran4fileAppend( t4, &header, "\0" ) ;
 | 
						|
   if (rc < 0)
 | 
						|
      return(rc);
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      return tran4fileVerify( t4, 1 ) ;
 | 
						|
   #else
 | 
						|
      return 0 ;
 | 
						|
   #endif
 | 
						|
}
 | 
						|
 | 
						|
#ifndef S4UTILS
 | 
						|
static int tran4fileStatusFile( TRAN4FILE *t4 )
 | 
						|
{
 | 
						|
   CODE4 *c4 ;
 | 
						|
   long filePos ;
 | 
						|
   int rc ;
 | 
						|
   LOG4HEADER header ;
 | 
						|
   TRAN4ENTRY_LEN entryLen;
 | 
						|
   #ifdef S4STAND_ALONE
 | 
						|
      #ifndef S4OFF_MULTI
 | 
						|
         long loop ;
 | 
						|
         int oldNumAttempts ;
 | 
						|
      #endif
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( ( rc = tran4fileVerify( t4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
      if ( t4->file.hand < 0 )
 | 
						|
         return error4( t4->c4trans->c4, e4struct, E93801 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   c4 = t4->c4trans->c4 ;
 | 
						|
 | 
						|
   #ifdef S4STAND_ALONE
 | 
						|
      /* first see if the only user, in which case can verify */
 | 
						|
      #ifndef S4OFF_MULTI
 | 
						|
         oldNumAttempts = c4->lockAttempts ;
 | 
						|
             /* can't do overlay locking due to Novell inconsistencies... */
 | 
						|
             /* reserve a byte so only one attempt to set up at a time */
 | 
						|
         c4->lockAttempts = -1 ;
 | 
						|
         rc = file4lock( &t4->file, TRAN4LOCK_USERS + TRAN4MAX_USERS + 1, 1 ) ;
 | 
						|
         c4->lockAttempts = 1 ;
 | 
						|
         for ( loop = 0 ; loop <= TRAN4MAX_USERS ; loop++ )
 | 
						|
         {
 | 
						|
            rc = file4lock( &t4->file, TRAN4LOCK_USERS+loop, 1 ) ;
 | 
						|
            if ( rc < 0 || rc == r4locked )
 | 
						|
               break ;
 | 
						|
            file4unlock( &t4->file, TRAN4LOCK_USERS+loop, 1 ) ;
 | 
						|
         }
 | 
						|
         c4->lockAttempts = oldNumAttempts ;
 | 
						|
         if ( rc != 0 )
 | 
						|
         {
 | 
						|
            file4unlock( &t4->file, TRAN4LOCK_USERS + TRAN4MAX_USERS + 1, 1 ) ;
 | 
						|
            if ( rc == r4locked )
 | 
						|
               return 0 ;
 | 
						|
            return rc ;
 | 
						|
         }
 | 
						|
      #endif
 | 
						|
   #endif
 | 
						|
 | 
						|
   for( ;; )
 | 
						|
   {
 | 
						|
      filePos = file4len( &t4->file ) - sizeof( LOG4HEADER ) - sizeof(TRAN4ENTRY_LEN);
 | 
						|
      if ( filePos < 0 )
 | 
						|
      {
 | 
						|
         rc = error4( c4, e4trans, E83801 ) ;
 | 
						|
         break ;
 | 
						|
      }
 | 
						|
 | 
						|
      rc = file4readAll( &t4->file, 0L, &entryLen, sizeof( TRAN4ENTRY_LEN ) ) ;
 | 
						|
      if ( rc < 0 )
 | 
						|
         break ;
 | 
						|
 | 
						|
      if (entryLen != sizeof(LOG4HEADER) + sizeof(TRAN4ENTRY_LEN))
 | 
						|
      {
 | 
						|
         rc = error4( c4, e4read, E93801 ) ;
 | 
						|
         break ;
 | 
						|
      }
 | 
						|
 | 
						|
      rc = file4readAll( &t4->file, (long)sizeof(TRAN4ENTRY_LEN), &header, sizeof( LOG4HEADER ) ) ;
 | 
						|
      if ( rc < 0 )
 | 
						|
         break ;
 | 
						|
 | 
						|
      if ( header.type == TRAN4BACKEDUP )
 | 
						|
      {
 | 
						|
         rc = error4( c4, e4trans, E83815 ) ;
 | 
						|
         break ;
 | 
						|
      }
 | 
						|
 | 
						|
      rc = file4readAll( &t4->file, filePos, &entryLen, sizeof( TRAN4ENTRY_LEN ) ) ;
 | 
						|
      if ( rc < 0 )
 | 
						|
         break ;
 | 
						|
 | 
						|
      if (entryLen != sizeof(LOG4HEADER) + sizeof(TRAN4ENTRY_LEN))
 | 
						|
      {
 | 
						|
         rc = error4( c4, e4trans, E83801 ) ;
 | 
						|
         break ;
 | 
						|
      }
 | 
						|
 | 
						|
      rc = file4readAll( &t4->file, filePos + sizeof(TRAN4ENTRY_LEN), &header, sizeof( LOG4HEADER ) ) ;
 | 
						|
      if ( rc < 0 )
 | 
						|
         break ;
 | 
						|
 | 
						|
      break ;
 | 
						|
   }
 | 
						|
 | 
						|
   #ifdef S4STAND_ALONE
 | 
						|
      file4unlock( &t4->file, TRAN4LOCK_USERS + TRAN4MAX_USERS + 1, 1 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( rc < 0 )
 | 
						|
      return rc ;
 | 
						|
 | 
						|
   if ( header.type == TRAN4SHUTDOWN )
 | 
						|
      return 0 ;
 | 
						|
 | 
						|
   return error4( c4, e4trans, E83801 ) ;
 | 
						|
}
 | 
						|
#endif /* S4UTILS */
 | 
						|
 | 
						|
static int tran4fileOpen( TRAN4FILE *t4, char *name )
 | 
						|
{
 | 
						|
   int rc, oldOpenError, oldReadOnly ;
 | 
						|
   char buf[258] ;
 | 
						|
   CODE4 *c4 ;
 | 
						|
   #ifndef S4OFF_MULTI
 | 
						|
      int oldExcl ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifdef E4PARM_LOW
 | 
						|
      if ( name == 0 )
 | 
						|
         return error4( t4->c4trans->c4, e4parm_null, E93801 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   c4 = t4->c4trans->c4 ;
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( ( rc = tran4fileVerify( t4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
      if ( t4->file.hand != -1 )   /* already open */
 | 
						|
         return error4( c4, e4struct, E93801 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   memcpy( buf, name, strlen( name ) + 1 ) ;
 | 
						|
   u4nameExt( buf, sizeof( buf ), "log", 0 ) ;
 | 
						|
 | 
						|
   #ifndef S4OFF_MULTI
 | 
						|
      oldExcl = c4->accessMode ;
 | 
						|
      #ifdef S4UTILS
 | 
						|
         c4->accessMode = OPEN4DENY_RW ;
 | 
						|
      #else
 | 
						|
         c4->accessMode = OPEN4DENY_NONE ;
 | 
						|
      #endif
 | 
						|
   #endif
 | 
						|
   oldReadOnly = c4->readOnly ;
 | 
						|
   c4->readOnly = 0 ;
 | 
						|
   oldOpenError = c4->errOpen ;
 | 
						|
   c4->errOpen = 0 ;
 | 
						|
 | 
						|
   rc = file4open( &t4->file, c4, buf, 1 ) ;
 | 
						|
 | 
						|
   c4->errOpen = oldOpenError ;
 | 
						|
   c4->readOnly = oldReadOnly ;
 | 
						|
   #ifndef S4OFF_MULTI
 | 
						|
      c4->accessMode = oldExcl ;
 | 
						|
   #endif
 | 
						|
   #ifndef S4UTILS
 | 
						|
      if ( rc != r4noOpen && rc >= 0 )
 | 
						|
      {
 | 
						|
         if ( tran4fileStatusFile( t4 ) != 0 )
 | 
						|
         {
 | 
						|
            t4->validState = 0 ;
 | 
						|
            return -1 ;
 | 
						|
         }
 | 
						|
         else
 | 
						|
            t4->validState = 1 ;
 | 
						|
      }
 | 
						|
   #endif /* S4UTILS */
 | 
						|
 | 
						|
   if ( rc != 0 )
 | 
						|
      return rc ;
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      return tran4fileVerify( t4, 1 ) ;
 | 
						|
   #else
 | 
						|
      return 0 ;
 | 
						|
   #endif
 | 
						|
}
 | 
						|
 | 
						|
/* server just increments and checks trans file for last entry */
 | 
						|
/* stand-alone uses the userIdNo as an offset to avoid requiring
 | 
						|
   continual reads to get next id no.  */
 | 
						|
static long tran4fileGetNextTransId( TRAN4FILE *t4, TRAN4 *trans )
 | 
						|
{
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      int rc ;
 | 
						|
 | 
						|
      if ( ( rc = tran4fileVerify( t4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifdef S4SERVER
 | 
						|
      if ( t4->transId > 0 )
 | 
						|
      {
 | 
						|
         if ( t4->transId == LONG_MAX )
 | 
						|
            t4->transId = 0 ;
 | 
						|
         ++t4->transId ;
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
         if ( tran4bottom( trans ) < 0 )  /* no entries */
 | 
						|
            return 0 ;
 | 
						|
 | 
						|
         while ( trans->header.transId == 0 )
 | 
						|
            if ( tran4skip( trans, TRAN4BACKWARDS ) != 0 )
 | 
						|
               break ;
 | 
						|
 | 
						|
         if ( trans->header.transId < 0 )
 | 
						|
            return e4trans ;
 | 
						|
 | 
						|
         if ( trans->header.transId == LONG_MAX )
 | 
						|
            t4->transId = 0 ;
 | 
						|
         else
 | 
						|
            t4->transId = trans->header.transId + 1 ;
 | 
						|
      }
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifdef S4STAND_ALONE
 | 
						|
      if ( t4->transId > 0 )
 | 
						|
      {
 | 
						|
         if ( t4->transId == LONG_MAX )
 | 
						|
            t4->transId = t4->c4trans->trans.userIdNo ;
 | 
						|
         t4->transId += TRAN4MAX_USERS ;
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
         if ( tran4bottom( trans ) < 0 )  /* no entries */
 | 
						|
            return 0 ;
 | 
						|
 | 
						|
         for ( ;; )
 | 
						|
         {
 | 
						|
            if ( trans->header.transId % TRAN4MAX_USERS == trans->userIdNo )
 | 
						|
               break ;
 | 
						|
            if ( tran4skip( trans, TRAN4BACKWARDS ) != 0 )
 | 
						|
               break ;
 | 
						|
         }
 | 
						|
 | 
						|
         if ( trans->header.transId < 0 )
 | 
						|
            return e4trans ;
 | 
						|
 | 
						|
         if ( trans->header.transId == LONG_MAX || ( trans->header.transId % TRAN4MAX_USERS != t4->c4trans->trans.userIdNo ) )
 | 
						|
            t4->transId = t4->c4trans->trans.userIdNo ;
 | 
						|
         else
 | 
						|
            t4->transId = trans->header.transId + TRAN4MAX_USERS ;
 | 
						|
      }
 | 
						|
   #endif
 | 
						|
   return t4->transId ;
 | 
						|
}
 | 
						|
 | 
						|
static long tran4getTransId( TRAN4 *t4 )
 | 
						|
{
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      int rc ;
 | 
						|
 | 
						|
      if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( t4->transId > 0 )
 | 
						|
      return t4->transId ;
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( t4->c4trans->transFile == 0 )
 | 
						|
         return error4( t4->c4trans->c4, e4struct, E93801 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   t4->transId = tran4fileGetNextTransId( t4->c4trans->transFile, t4 ) ;
 | 
						|
   return t4->transId ;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
int S4FUNCTION tran4fileStatus( TRAN4FILE *t4, long transactionId )
 | 
						|
{
 | 
						|
   long filePos ;
 | 
						|
   int rc ;
 | 
						|
   LOG4HEADER header ;
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( ( rc = tran4fileVerify( t4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
      if ( t4->file.hand < 0 )
 | 
						|
         return error4( t4->c4trans->c4, e4struct, E93801 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   rc = -1 ;
 | 
						|
   filePos = file4len( &t4->file ) - sizeof( LOG4HEADER ) ;
 | 
						|
 | 
						|
   for( ; filePos > 0 ; )
 | 
						|
   {
 | 
						|
      rc = file4readAll( &t4->file, filePos, &header, sizeof( LOG4HEADER ) ) ;
 | 
						|
      if ( rc < 0 )
 | 
						|
         return rc ;
 | 
						|
 | 
						|
      if ( header.transId == transactionId )
 | 
						|
         return header.type ;
 | 
						|
 | 
						|
      filePos -= ( header.dataLen + sizeof( LOG4HEADER ) ) ;
 | 
						|
   }
 | 
						|
 | 
						|
   return rc ;
 | 
						|
}
 | 
						|
*/
 | 
						|
 | 
						|
static int tran4fileRead( TRAN4FILE *t4, long pos, LOG4HEADER *header, char **data, unsigned int *dataLen )
 | 
						|
{
 | 
						|
   int rc ;
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( ( rc = tran4fileVerify( t4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
      if ( t4->file.hand < 0 )
 | 
						|
         return error4( t4->c4trans->c4, e4struct, E93801 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   rc = file4readAll( &t4->file, pos, header, sizeof( LOG4HEADER ) ) ;
 | 
						|
   if ( rc < 0 )
 | 
						|
      return rc ;
 | 
						|
   if ( *dataLen < header->dataLen + 1 )
 | 
						|
      if ( u4allocAgain( t4->c4trans->c4, data, dataLen, (unsigned int)header->dataLen + 1 ) != 0 )
 | 
						|
         return e4memory ;
 | 
						|
   if ( header->dataLen > 0L )
 | 
						|
   {
 | 
						|
      rc = file4readAll( &t4->file, pos - header->dataLen, *data, (unsigned int)header->dataLen ) ;
 | 
						|
      if ( rc < 0 )
 | 
						|
         return rc ;
 | 
						|
   }
 | 
						|
   else
 | 
						|
      (*data)[0] = '\0' ;
 | 
						|
   return 0 ;
 | 
						|
}
 | 
						|
 | 
						|
static int tran4read( TRAN4 *t4 )
 | 
						|
{
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      int rc ;
 | 
						|
 | 
						|
      if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
      if ( t4->pos < 0 )
 | 
						|
         return error4( t4->c4trans->c4, e4info, E83802 ) ;
 | 
						|
      if ( t4->c4trans->transFile == 0 )
 | 
						|
         return error4( t4->c4trans->c4, e4info, E93801 ) ;
 | 
						|
   #endif
 | 
						|
   return tran4fileRead( t4->c4trans->transFile, t4->pos, &t4->header, &t4->c4trans->c4->tranData, &t4->c4trans->c4->tranDataLen ) ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION tran4fileTop( TRAN4FILE *t4, TRAN4 *trans )
 | 
						|
{
 | 
						|
   int rc ;
 | 
						|
   unsigned lenRead ;
 | 
						|
   TRAN4ENTRY_LEN len ;
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( ( rc = tran4fileVerify( t4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   lenRead = file4read( &t4->file, 0L, &len, sizeof( len ) ) ;
 | 
						|
   if ( lenRead != sizeof( len ) )
 | 
						|
      return r4bof ;
 | 
						|
 | 
						|
   trans->pos = len - sizeof( LOG4HEADER ) ;
 | 
						|
 | 
						|
   rc = tran4read( trans ) ;
 | 
						|
   if ( rc < 0 )
 | 
						|
   {
 | 
						|
      trans->pos = -1 ;
 | 
						|
      return rc ;
 | 
						|
   }
 | 
						|
   return 0 ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION tran4fileBottom( TRAN4FILE *t4, TRAN4 *trans )
 | 
						|
{
 | 
						|
   int rc ;
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( ( rc = tran4fileVerify( t4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   trans->pos = file4len( &t4->file ) - sizeof( LOG4HEADER ) ;
 | 
						|
   if ( trans->pos < 0 )
 | 
						|
      return r4eof ;
 | 
						|
   rc = tran4read( trans ) ;
 | 
						|
   if ( rc < 0 )
 | 
						|
   {
 | 
						|
      trans->pos = -1 ;
 | 
						|
      return rc ;
 | 
						|
   }
 | 
						|
   return 0 ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION tran4fileSkip( TRAN4FILE *t4, TRAN4 *trans, const int direction )
 | 
						|
{
 | 
						|
   int rc ;
 | 
						|
   TRAN4ENTRY_LEN len ;
 | 
						|
 | 
						|
   #ifdef E4PARM_LOW
 | 
						|
      if ( t4 == 0 || trans == 0 || ( direction != TRAN4FORWARDS && direction != TRAN4BACKWARDS ) )
 | 
						|
         return error4( 0, e4parm, E93801 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( trans->pos < 0L )   /* empty file ... */
 | 
						|
   {
 | 
						|
      if ( direction == TRAN4BACKWARDS )
 | 
						|
         return r4eof ;
 | 
						|
      else
 | 
						|
         return r4bof ;
 | 
						|
   }
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( ( rc = tran4fileVerify( t4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( direction == TRAN4BACKWARDS )
 | 
						|
   {
 | 
						|
      trans->pos -= tran4entryLen( &trans->header ) ;
 | 
						|
      if ( trans->pos < 0L )
 | 
						|
         return r4bof ;
 | 
						|
      rc = tran4read( trans ) ;
 | 
						|
      if ( rc< 0 )
 | 
						|
      {
 | 
						|
         trans->pos = -1 ;
 | 
						|
         return rc ;
 | 
						|
      }
 | 
						|
   }
 | 
						|
   else
 | 
						|
   {
 | 
						|
      trans->pos += sizeof( LOG4HEADER ) ;
 | 
						|
      if ( (long)trans->pos + (long)sizeof( TRAN4ENTRY_LEN ) >= file4len( &t4->file ) )
 | 
						|
         return r4eof ;
 | 
						|
      rc = file4readAll( &t4->file, trans->pos, &len, sizeof( TRAN4ENTRY_LEN ) ) ;
 | 
						|
      if ( rc < 0 )
 | 
						|
         return rc ;
 | 
						|
 | 
						|
      trans->pos += len - sizeof( LOG4HEADER ) ;
 | 
						|
 | 
						|
      if ( trans->pos >= file4len( &t4->file ) )
 | 
						|
         return r4eof ;
 | 
						|
 | 
						|
      rc = tran4read( trans ) ;
 | 
						|
      if ( rc< 0 )
 | 
						|
      {
 | 
						|
         trans->pos = -1 ;
 | 
						|
         return rc ;
 | 
						|
      }
 | 
						|
   }
 | 
						|
 | 
						|
   return 0 ;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
int S4FUNCTION tran4fileSeek( TRAN4FILE *t4, TRAN4 *trans, long transIdno )
 | 
						|
{
 | 
						|
   int rc ;
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( ( rc = tran4fileVerify( t4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   for ( trans->pos = file4len( &t4->file ) - sizeof( LOG4HEADER ) ; trans->pos > 0L ; trans->pos -= tran4entryLen( &trans->header ) )
 | 
						|
   {
 | 
						|
      rc = file4readAll( &t4->file, trans->pos, &trans->header, sizeof( LOG4HEADER ) ) ;
 | 
						|
      if ( rc < 0 )
 | 
						|
      {
 | 
						|
         trans->pos = -1L ;
 | 
						|
         return rc ;
 | 
						|
      }
 | 
						|
      if ( trans->header.transId == transIdno )
 | 
						|
         return tran4read( trans ) ;
 | 
						|
   }
 | 
						|
 | 
						|
   trans->pos = -1L ;
 | 
						|
   return error4( t4->c4trans->c4, e4trans, E83803 ) ;
 | 
						|
}
 | 
						|
*/
 | 
						|
 | 
						|
#ifndef S4INLINE
 | 
						|
long S4FUNCTION tran4id( TRAN4 *t4 )
 | 
						|
{
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      int rc ;
 | 
						|
 | 
						|
      if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   return t4->header.transId ;
 | 
						|
}
 | 
						|
 | 
						|
long S4FUNCTION tran4clientId( TRAN4 *t4 )
 | 
						|
{
 | 
						|
   int rc ;
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   return t4->header.clientId ;
 | 
						|
}
 | 
						|
 | 
						|
unsigned long S4FUNCTION tran4clientDataId( TRAN4 *t4 )
 | 
						|
{
 | 
						|
   int rc ;
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   return t4->header.clientDataId ;
 | 
						|
}
 | 
						|
 | 
						|
unsigned long S4FUNCTION tran4serverDataId( TRAN4 *t4 )
 | 
						|
{
 | 
						|
   int rc ;
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   return t4->header.serverDataId ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION tran4type( TRAN4 *t4 )
 | 
						|
{
 | 
						|
   int rc ;
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   return t4->header.type ;
 | 
						|
}
 | 
						|
 | 
						|
unsigned S4FUNCTION tran4len( TRAN4 *t4 )
 | 
						|
{
 | 
						|
   int rc ;
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   return t4->header.dataLen ;
 | 
						|
}
 | 
						|
#endif  /* S4INLINE */
 | 
						|
 | 
						|
/* data may be larger than can be contained in memory... new coding reqd */
 | 
						|
void *S4FUNCTION tran4getData( TRAN4 *t4, const long pos )
 | 
						|
{
 | 
						|
   CODE4 *c4 ;
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( tran4verify( t4, 1 ) < 0 )
 | 
						|
         return 0 ;
 | 
						|
      if ( t4->c4trans->transFile == 0 )
 | 
						|
      {
 | 
						|
         error4( t4->c4trans->c4, e4struct, E93801 ) ;
 | 
						|
         return 0 ;
 | 
						|
      }
 | 
						|
   #endif
 | 
						|
 | 
						|
   c4 = t4->c4trans->c4 ;
 | 
						|
 | 
						|
   if ( c4->tranData != 0 )
 | 
						|
   {
 | 
						|
      if ( c4->tranDataLen < t4->header.dataLen + 1 )
 | 
						|
      {
 | 
						|
         error4( c4, e4trans, E93801 ) ;
 | 
						|
         return 0 ;
 | 
						|
      }
 | 
						|
      c4->tranData[ t4->header.dataLen ] = 0 ;
 | 
						|
   }
 | 
						|
   return c4->tranData + pos ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION tran4set( TRAN4 *t4, const int status, const long id1, const long id2, const int typ,
 | 
						|
                         const unsigned int dLen, const long clientId, const long serverId )
 | 
						|
{
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      int rc ;
 | 
						|
 | 
						|
      if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( status == r4active || typ == TRAN4START || typ == TRAN4ROLLBACK )
 | 
						|
   {
 | 
						|
      if ( id1 == -1 )
 | 
						|
         t4->header.transId = tran4getTransId( t4 ) ;
 | 
						|
      else
 | 
						|
         t4->header.transId = id1 ;
 | 
						|
   }
 | 
						|
   else
 | 
						|
      t4->header.transId = 0 ;
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( t4->c4trans->transFile == 0 )
 | 
						|
         return error4( t4->c4trans->c4, e4struct, E93801 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( t4->header.transId < 0 )
 | 
						|
      return error4( t4->c4trans->c4, e4trans, E93801 ) ;
 | 
						|
 | 
						|
   t4->header.clientId = id2 ;
 | 
						|
   t4->header.type = typ ;
 | 
						|
   t4->header.dataLen = dLen ;
 | 
						|
   t4->header.clientDataId = clientId ;
 | 
						|
   t4->header.serverDataId = serverId ;
 | 
						|
   time( &t4->header.time ) ;
 | 
						|
 | 
						|
   return 0 ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION tran4putData( TRAN4 *t4, void *dta, unsigned dLen )
 | 
						|
{
 | 
						|
   CODE4 *c4 ;
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      int rc ;
 | 
						|
 | 
						|
      if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
      if ( t4->c4trans->transFile == 0 || dLen <= 0 )
 | 
						|
         return error4( t4->c4trans->c4, e4info, E93801 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   c4 = t4->c4trans->c4 ;
 | 
						|
 | 
						|
   if ( t4->dataPos + dLen + 1 > c4->tranDataLen )
 | 
						|
      if ( u4allocAgain( c4, &c4->tranData, &c4->tranDataLen, dLen + t4->dataPos + 1 ) != 0 )
 | 
						|
         return e4memory ;
 | 
						|
 | 
						|
   memcpy( c4->tranData + t4->dataPos, dta, dLen ) ;
 | 
						|
   t4->dataPos += dLen ;
 | 
						|
   return 0 ;
 | 
						|
}
 | 
						|
 | 
						|
#ifndef S4INLINE
 | 
						|
int S4FUNCTION tran4bottom( TRAN4 *t4 )
 | 
						|
{
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      int rc ;
 | 
						|
 | 
						|
      if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
      if ( t4->c4trans->transFile == 0 )
 | 
						|
         return error4( t4->c4trans->c4, e4struct, E93801 ) ;
 | 
						|
   #endif
 | 
						|
   return tran4fileBottom( t4->c4trans->transFile, t4 ) ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION tran4top( TRAN4 *t4 )
 | 
						|
{
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      int rc ;
 | 
						|
 | 
						|
      if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
      if ( t4->c4trans->transFile == 0 )
 | 
						|
         return error4( t4->c4trans->c4, e4info, E93801 ) ;
 | 
						|
   #endif
 | 
						|
   return tran4fileTop( t4->c4trans->transFile, t4 ) ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION tran4skip( TRAN4 *t4, int direction )
 | 
						|
{
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      int rc ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifdef E4PARM_LOW
 | 
						|
      if ( direction != TRAN4FORWARDS && direction != TRAN4BACKWARDS )
 | 
						|
         return error4( 0, e4parm, E93801 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( ( rc = tran4verify( t4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
      if ( t4->c4trans->transFile == 0 )
 | 
						|
         return error4( t4->c4trans->c4, e4struct, E93801 ) ;
 | 
						|
   #endif
 | 
						|
   return tran4fileSkip( t4->c4trans->transFile, t4, direction ) ;
 | 
						|
}
 | 
						|
#endif  /* S4INLINE */
 | 
						|
 | 
						|
int tran4lowUnappend( TRAN4 *trans )
 | 
						|
{
 | 
						|
   DATA4 *data ;
 | 
						|
   int rc ;
 | 
						|
   long recNo ;
 | 
						|
 | 
						|
   #ifdef E4PARM_LOW
 | 
						|
      if ( trans == 0 )
 | 
						|
         return error4( 0, e4parm_null, E93801 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   recNo = *((long *)(tran4getData( trans, 0L ) ) ) ;
 | 
						|
 | 
						|
   data = tran4dataFull( trans, tran4serverDataId( trans ), tran4clientDataId( trans ) ) ;
 | 
						|
   if ( data == 0 )
 | 
						|
      return error4( trans->c4trans->c4, e4name, E93801 ) ;
 | 
						|
 | 
						|
   #ifndef S4OFF_MULTI
 | 
						|
      if ( dfile4lockTestAppend( data->dataFile, tran4clientDataId( trans ), tran4serverDataId( trans ) ) == 0 )
 | 
						|
         return error4( trans->c4trans->c4, e4lock, E83804 ) ;
 | 
						|
   #endif
 | 
						|
   if ( d4recCount( data ) != recNo )
 | 
						|
   {
 | 
						|
      if ( d4recCount( data ) == recNo - 1 )   /* already unappended */
 | 
						|
         return 0 ;
 | 
						|
      else
 | 
						|
         return error4( trans->c4trans->c4, e4rollback, E83805 ) ;
 | 
						|
   }
 | 
						|
 | 
						|
   memcpy( data->record, tran4getData( trans, sizeof( long ) ), dfile4recWidth( data->dataFile ) ) ;
 | 
						|
   rc = d4unappend( data ) ;
 | 
						|
   memset( data->record, 0, dfile4recWidth( data->dataFile ) ) ;
 | 
						|
   if ( rc < 0 )
 | 
						|
      return error4stack( trans->c4trans->c4, rc, E93801 ) ;
 | 
						|
 | 
						|
   return d4update( data ) ;
 | 
						|
}
 | 
						|
 | 
						|
int tran4lowUnwrite( TRAN4 *trans )
 | 
						|
{
 | 
						|
   DATA4 *data ;
 | 
						|
   int rc, doSpecial ;
 | 
						|
   long recNo ;
 | 
						|
   char *rec, *saveRec = 0;
 | 
						|
   CODE4 *c4 ;
 | 
						|
   #ifndef S4MEMO_OFF
 | 
						|
      int i ;
 | 
						|
      unsigned long ptrLen, pos ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifdef E4PARM_LOW
 | 
						|
      if ( trans == 0 )
 | 
						|
         return error4( 0, e4parm_null, E93801 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   c4 = trans->c4trans->c4 ;
 | 
						|
   recNo = *((long *)(tran4getData( trans, 0L ) ) ) ;
 | 
						|
   rec = (char *)tran4getData( trans, (long)sizeof( long ) ) ;
 | 
						|
 | 
						|
   data = tran4dataFull( trans, tran4serverDataId( trans ), tran4clientDataId( trans ) ) ;
 | 
						|
   if ( data == 0 )
 | 
						|
      return error4( c4, e4name, E93801 ) ;
 | 
						|
 | 
						|
   doSpecial = 0 ;
 | 
						|
   if ( data->recordChanged == 1 )   /* override flush */
 | 
						|
   {
 | 
						|
      if ( d4recNo( data ) == recNo )
 | 
						|
      {
 | 
						|
         /* special, case (automatic rollback) -- save record for user */
 | 
						|
         doSpecial = 1 ;
 | 
						|
         saveRec = data->record ;
 | 
						|
         data->record =(char*) u4allocFree( c4, dfile4recWidth( data->dataFile ) + 1 ) ;
 | 
						|
         if ( data->record == 0 )
 | 
						|
         {
 | 
						|
            /* user will lose changes, due to low memory, but can at least rollback */
 | 
						|
            data->record = saveRec ;
 | 
						|
            doSpecial = 0 ;
 | 
						|
         }
 | 
						|
         else
 | 
						|
            memcpy( data->record, saveRec, dfile4recWidth( data->dataFile ) ) ;
 | 
						|
      }
 | 
						|
      data->recordChanged = 0 ;
 | 
						|
   }
 | 
						|
   rc = 0 ;
 | 
						|
   if ( doSpecial == 0 )
 | 
						|
      rc = d4go( data, recNo ) ;
 | 
						|
 | 
						|
   if ( rc == 0 )
 | 
						|
   #ifndef S4OFF_MULTI
 | 
						|
      if ( dfile4lockTest( data->dataFile, tran4clientDataId( trans ), tran4serverDataId( trans ), recNo ) == 0 )
 | 
						|
         rc = error4( c4, e4lock, E83804 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( rc == 0 )
 | 
						|
   {
 | 
						|
      memcpy( d4record( data ), rec, (size_t)dfile4recWidth( data->dataFile ) ) ;
 | 
						|
      #ifndef S4MEMO_OFF
 | 
						|
         pos = (long)sizeof( long ) + 2L * dfile4recWidth( data->dataFile ) ;
 | 
						|
         for ( i = 0; i < data->dataFile->nFieldsMemo; i++ )
 | 
						|
         {
 | 
						|
            ptrLen = *( (unsigned int *)tran4getData( trans, pos ) ) ;
 | 
						|
            pos += sizeof( ptrLen ) ;
 | 
						|
            if ( ptrLen != 0 )
 | 
						|
               f4memoAssignN( data->fieldsMemo[i].field, (char *)tran4getData( trans, pos ), (unsigned int)ptrLen ) ;
 | 
						|
            pos += ptrLen ;
 | 
						|
            #ifdef S4DATA_ALIGN
 | 
						|
               memcpy(&ptrLen, tran4getData(trans, pos), sizeof(ptrLen));
 | 
						|
            #else
 | 
						|
               ptrLen = *( (unsigned long *)tran4getData( trans, pos ) ) ;
 | 
						|
            #endif
 | 
						|
            pos += sizeof( ptrLen ) + ptrLen ;
 | 
						|
         }
 | 
						|
      #endif
 | 
						|
   }
 | 
						|
 | 
						|
   if ( rc == 0 )
 | 
						|
      rc = d4writeLow( data, recNo, 0 ) ;
 | 
						|
 | 
						|
   if ( rc == 0 )
 | 
						|
      rc = d4update( data ) ;
 | 
						|
 | 
						|
   if ( doSpecial )
 | 
						|
   {
 | 
						|
      u4free( data->record ) ;
 | 
						|
      data->record = saveRec ;
 | 
						|
      data->recordChanged = 1 ;
 | 
						|
   }
 | 
						|
 | 
						|
   return rc ;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef P4ARGS_USED
 | 
						|
   #pragma argsused
 | 
						|
#endif
 | 
						|
/* clientId is a unique id for the transactee.  In the single user case, there is only one */
 | 
						|
int S4FUNCTION tran4lowStart( TRAN4 *trans, long clientId, int doUnlock )
 | 
						|
{
 | 
						|
   int rc ;
 | 
						|
   #ifdef S4STAND_ALONE_TRANS
 | 
						|
      int oldLockAttempts ;
 | 
						|
   #endif
 | 
						|
   CODE4 *c4 ;
 | 
						|
 | 
						|
   #ifdef E4PARM_HIGH
 | 
						|
      if ( trans == 0 )
 | 
						|
         return error4( 0, e4parm_null, E93801 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   c4 = trans->c4trans->c4 ;
 | 
						|
 | 
						|
   if ( trans->c4trans->enabled == 0 )
 | 
						|
   {
 | 
						|
      #ifdef S4STAND_ALONE
 | 
						|
         if ( c4->logOpen == 0 )
 | 
						|
            return error4( c4, e4trans, E83814 ) ;
 | 
						|
      #endif
 | 
						|
      #ifdef S4STAND_ALONE
 | 
						|
         rc = code4logOpen( c4, 0, 0 ) ;
 | 
						|
      #else
 | 
						|
         rc = code4transFileEnable( trans->c4trans, 0, 0 ) ;
 | 
						|
      #endif
 | 
						|
      if ( rc < 0 )
 | 
						|
         return rc ;
 | 
						|
   }
 | 
						|
 | 
						|
   if ( trans->c4trans->enabled != 1 )
 | 
						|
      return error4( c4, e4trans, E83807 ) ;
 | 
						|
 | 
						|
   #ifdef S4STAND_ALONE
 | 
						|
      if ( trans->currentTranStatus == r4active )   /* already in a transactional state */
 | 
						|
         return error4( c4, e4trans, E93801 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( trans->c4trans->transFile->status != 0 )
 | 
						|
      return error4( c4, e4trans, E83801 ) ;
 | 
						|
 | 
						|
   #ifndef S4OFF_MULTI
 | 
						|
      if ( doUnlock == 1 )
 | 
						|
      {
 | 
						|
         rc = code4unlock( c4 ) ;
 | 
						|
         if ( rc < 0 )
 | 
						|
            return rc ;
 | 
						|
      }
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifdef S4STAND_ALONE_TRANS
 | 
						|
      oldLockAttempts = c4->lockAttempts ;
 | 
						|
      c4->lockAttempts = WAIT4EVER ;
 | 
						|
      rc = code4tranLockTransactions( c4->c4trans, TRAN4LOCK_MULTIPLE ) ;
 | 
						|
      c4->lockAttempts = oldLockAttempts ;
 | 
						|
      if ( rc < 0 )
 | 
						|
         rc = error4( c4, rc, E93801 ) ;
 | 
						|
      tran4bottom( trans ) ;
 | 
						|
      switch( tran4type( trans ) )
 | 
						|
      {
 | 
						|
         case TRAN4COMPLETE:
 | 
						|
         case TRAN4ROLLBACK:
 | 
						|
         case TRAN4OPEN:
 | 
						|
         case TRAN4CLOSE:
 | 
						|
      }
 | 
						|
   #endif
 | 
						|
 | 
						|
   rc = tran4set( trans, trans->currentTranStatus, -1L, clientId, TRAN4START, 0, 0L, 0L ) ;
 | 
						|
   if ( rc < 0 )
 | 
						|
      return rc ;
 | 
						|
   if ( tran4lowAppend( trans, "\0" ) != 0 )
 | 
						|
      return e4transAppend ;
 | 
						|
 | 
						|
   trans->currentTranStatus = r4active ;
 | 
						|
 | 
						|
   #ifndef S4OFF_MULTI
 | 
						|
      trans->savedUnlockAuto = trans->unlockAuto ;
 | 
						|
      trans->unlockAuto = 0 ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   return 0 ;
 | 
						|
}
 | 
						|
 | 
						|
/*int S4FUNCTION tran4lowRollback( TRAN4 *trans, long id, int doUnlock )*/
 | 
						|
int S4FUNCTION tran4lowRollback( TRAN4 *trans, long id, const int doInvalidate )
 | 
						|
{
 | 
						|
   int done, saveErr, rc ;
 | 
						|
   long transId ;
 | 
						|
   CODE4 *c4 ;
 | 
						|
 | 
						|
   #ifdef E4PARM_HIGH
 | 
						|
      if ( trans == 0 )
 | 
						|
         return error4( 0, e4parm, E93801 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   c4 = trans->c4trans->c4 ;
 | 
						|
   saveErr = error4set( c4, 0 ) ;
 | 
						|
   transId = tran4getTransId( trans ) ;
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( transId <= 0 )
 | 
						|
         return error4( 0, e4info, E93801 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( trans->c4trans->enabled != 1 )
 | 
						|
         return error4( c4, e4rollback, E83807 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( trans->currentTranStatus != r4active )
 | 
						|
      return error4( c4, e4trans, E83808 ) ;
 | 
						|
 | 
						|
   if ( trans->c4trans->transFile->status != 0 )
 | 
						|
      return error4( c4, e4trans, E83801 ) ;
 | 
						|
   trans->c4trans->transFile->status = 1 ;
 | 
						|
 | 
						|
   trans->currentTranStatus = r4rollback ;
 | 
						|
 | 
						|
   /* first rollback all the transactions, then mark a rollback as having occurred */
 | 
						|
   rc = tran4bottom( trans ) ;
 | 
						|
   if ( rc != 0 )
 | 
						|
      return error4stack( c4, rc, E93801 ) ;
 | 
						|
 | 
						|
   for( done = 0, rc = 0; !done && !rc ; )
 | 
						|
   {
 | 
						|
      if ( tran4id( trans ) == transId )
 | 
						|
      {
 | 
						|
         switch( tran4type( trans ) )
 | 
						|
         {
 | 
						|
            case TRAN4START:
 | 
						|
               done = 1 ;
 | 
						|
               break ;
 | 
						|
            case TRAN4WRITE:
 | 
						|
               rc = tran4lowUnwrite( trans ) ;
 | 
						|
               break ;
 | 
						|
            case TRAN4APPEND:
 | 
						|
               rc = tran4lowUnappend( trans ) ;
 | 
						|
               break ;
 | 
						|
            case TRAN4VOID:   /* transaction connectioning to next was voided, so skip... */
 | 
						|
            case TRAN4OPEN:
 | 
						|
            case TRAN4OPEN_TEMP:
 | 
						|
            case TRAN4CLOSE:
 | 
						|
               break ;
 | 
						|
            default:
 | 
						|
               rc = error4( c4, e4rollback, E83809 ) ;
 | 
						|
         }
 | 
						|
      }
 | 
						|
      if ( !done && !rc )
 | 
						|
         rc = tran4skip( trans, TRAN4BACKWARDS ) ;
 | 
						|
   }
 | 
						|
   if ( rc > 0 )
 | 
						|
      rc = 0 ;
 | 
						|
 | 
						|
   if ( rc == 0 )
 | 
						|
   {
 | 
						|
      tran4set( trans, trans->currentTranStatus, transId, id, TRAN4ROLLBACK, 0, 0L, 0L ) ;
 | 
						|
      if ( tran4lowAppend( trans, "\0" ) != 0 )
 | 
						|
         return e4transAppend ;
 | 
						|
   }
 | 
						|
 | 
						|
   trans->currentTranStatus = r4inactive ;
 | 
						|
   trans->transId = 0;
 | 
						|
 | 
						|
   #ifndef S4OFF_MULTI
 | 
						|
      trans->unlockAuto = trans->savedUnlockAuto ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifdef S4STAND_ALONE_TRANS
 | 
						|
      #ifndef S4UTILS
 | 
						|
         rc = code4tranUnlockTransactions( c4->c4trans, TRAN4LOCK_MULTIPLE ) ;
 | 
						|
      #endif
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( saveErr != 0 )
 | 
						|
      error4set( c4, saveErr ) ;
 | 
						|
 | 
						|
   if ( rc == 0 )
 | 
						|
      trans->c4trans->transFile->status = 0 ;
 | 
						|
   tran4lowCloseDelayed( trans ) ;
 | 
						|
   #ifndef S4SERVER
 | 
						|
      if ( doInvalidate )
 | 
						|
         code4invalidate( c4 ) ;
 | 
						|
   #endif
 | 
						|
   return rc ;
 | 
						|
}
 | 
						|
 | 
						|
static int tran4lowRemoveKeys( TRAN4 *trans )
 | 
						|
{
 | 
						|
   DATA4 *data ;
 | 
						|
   #ifndef S4OFF_INDEX
 | 
						|
      int rc, saveRc ;
 | 
						|
      TAG4 *tag ;
 | 
						|
      TAG4KEY_REMOVED *removed ;
 | 
						|
 | 
						|
      saveRc = 0 ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   for ( data = 0 ;; )  /* first do open files */
 | 
						|
   {
 | 
						|
      data =(DATA4 *) l4next( tran4dataList( trans ), data ) ;
 | 
						|
      if ( data == 0 )
 | 
						|
         break ;
 | 
						|
      #ifndef S4OFF_INDEX
 | 
						|
         for ( tag = 0 ;; )
 | 
						|
         {
 | 
						|
            tag = d4tagNext( data, tag ) ;
 | 
						|
            if ( tag == 0 )
 | 
						|
               break ;
 | 
						|
            for ( removed = 0 ;; )
 | 
						|
            {
 | 
						|
               removed = (TAG4KEY_REMOVED *)l4first( &tag->removedKeys ) ;
 | 
						|
               if ( removed == 0 )
 | 
						|
                  break ;
 | 
						|
               rc = tfile4remove( tag->tagFile, removed->key, removed->recno ) ;
 | 
						|
               if ( rc < 0 )
 | 
						|
                  saveRc = rc ;
 | 
						|
               l4remove( &tag->removedKeys, removed ) ;
 | 
						|
               u4free( removed ) ;
 | 
						|
            }
 | 
						|
         }
 | 
						|
      #endif
 | 
						|
   }
 | 
						|
   for ( data = 0 ;; )  /* now do closed files */
 | 
						|
   {
 | 
						|
      data =(DATA4 *) l4next( &trans->closedDataFiles, data ) ;
 | 
						|
      if ( data == 0 )
 | 
						|
         break ;
 | 
						|
      #ifndef S4OFF_INDEX
 | 
						|
         for ( tag = 0 ;; )
 | 
						|
         {
 | 
						|
            tag = d4tagNext( data, tag ) ;
 | 
						|
            if ( tag == 0 )
 | 
						|
               break ;
 | 
						|
            for ( removed = 0 ;; )
 | 
						|
            {
 | 
						|
               removed = (TAG4KEY_REMOVED *)l4first( &tag->removedKeys ) ;
 | 
						|
               if ( removed == 0 )
 | 
						|
                  break ;
 | 
						|
               rc = tfile4remove( tag->tagFile, removed->key, removed->recno ) ;
 | 
						|
               if ( rc < 0 )
 | 
						|
                  saveRc = rc ;
 | 
						|
               l4remove( &tag->removedKeys, removed ) ;
 | 
						|
               u4free( removed ) ;
 | 
						|
            }
 | 
						|
         }
 | 
						|
      #endif
 | 
						|
   }
 | 
						|
   #ifndef S4OFF_INDEX
 | 
						|
      return saveRc ;
 | 
						|
   #else
 | 
						|
      return 0 ;
 | 
						|
   #endif
 | 
						|
}
 | 
						|
 | 
						|
static int tran4updateData( TRAN4 *trans )
 | 
						|
{
 | 
						|
   DATA4 *data ;
 | 
						|
   int rc, saveRc, oldTransStatus ;
 | 
						|
 | 
						|
   /* changes trans status to force an update */
 | 
						|
   oldTransStatus = trans->currentTranStatus ;
 | 
						|
   trans->currentTranStatus = r4off ;
 | 
						|
   for ( data = 0, saveRc = 0 ;; )
 | 
						|
   {
 | 
						|
      data = (DATA4 *)l4next( trans->dataList, data ) ;
 | 
						|
      if ( data == 0 )
 | 
						|
         break ;
 | 
						|
      if ( data->dataFile->fileChanged == 1 )
 | 
						|
      {
 | 
						|
         #ifndef S4OFF_MULTI
 | 
						|
            if ( d4lockTestAppend( data ) == 1 )
 | 
						|
         #endif
 | 
						|
         {
 | 
						|
            rc = dfile4updateHeader( data->dataFile, 1, 1 ) ;
 | 
						|
            if ( rc < 0 )
 | 
						|
               saveRc = rc ;
 | 
						|
         }
 | 
						|
      }
 | 
						|
   }
 | 
						|
 | 
						|
   trans->currentTranStatus = oldTransStatus ;
 | 
						|
   return saveRc ;
 | 
						|
}
 | 
						|
 | 
						|
static int tran4lowFlush( TRAN4 *trans )
 | 
						|
{
 | 
						|
   DATA4 *dataOn ;
 | 
						|
   int rc ;
 | 
						|
 | 
						|
   for ( dataOn = 0 ;; )
 | 
						|
   {
 | 
						|
      dataOn = (DATA4 *)l4next( tran4dataList( trans ), dataOn ) ;
 | 
						|
      if ( dataOn == 0 )
 | 
						|
         break ;
 | 
						|
      #ifndef S4OFF_MULTI
 | 
						|
         if ( d4lockTestAppend( dataOn ) )
 | 
						|
      #endif
 | 
						|
         dfile4updateHeader( dataOn->dataFile, 1, 1 ) ;
 | 
						|
      rc = d4flush( dataOn ) ;
 | 
						|
      if ( rc != 0 )
 | 
						|
         return rc ;
 | 
						|
   }
 | 
						|
 | 
						|
   return 0 ;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef P4ARGS_USED
 | 
						|
   #pragma argsused
 | 
						|
#endif
 | 
						|
int S4FUNCTION tran4lowCommit( TRAN4 *trans, long id, unsigned short int numServers, int doUnlock )
 | 
						|
{
 | 
						|
   int rc ;
 | 
						|
   CODE4 *c4 ;
 | 
						|
 | 
						|
   #ifdef E4PARM_LOW
 | 
						|
      if ( trans == 0 )
 | 
						|
         return error4( 0, e4parm_null, E93801 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   c4 = trans->c4trans->c4 ;
 | 
						|
 | 
						|
   if ( trans->c4trans->enabled != 1 )
 | 
						|
      return error4( c4, e4parm, E83807 ) ;
 | 
						|
 | 
						|
   if ( trans->currentTranStatus == r4inactive )
 | 
						|
      return 0 ;
 | 
						|
 | 
						|
   #ifdef S4DISTRIBUTED
 | 
						|
      if ( trans->currentTranStatus == S4PARTIAL )
 | 
						|
         return error4( c4, e4commit, E93801 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( trans->c4trans->transFile->status != 0 )
 | 
						|
      return error4( c4, e4trans, E83801 ) ;
 | 
						|
 | 
						|
   rc = tran4lowFlush( trans ) ;
 | 
						|
   if ( rc != 0 )
 | 
						|
      return rc ;
 | 
						|
 | 
						|
   trans->c4trans->transFile->status = 1 ;
 | 
						|
 | 
						|
   rc = tran4set( trans, trans->currentTranStatus, -1L, id, TRAN4COMPLETE, 0, 0L, 0L ) ;
 | 
						|
   if ( rc < 0 )
 | 
						|
      return rc ;
 | 
						|
   #ifdef S4DISTRIBUTED
 | 
						|
      rc = tran4putData( trans, &numServers, sizeof( numServers ) ) ;
 | 
						|
      if ( rc < 0 )
 | 
						|
         return rc ;
 | 
						|
   #endif
 | 
						|
   if ( tran4lowAppend( trans, "\0" ) != 0 )
 | 
						|
      return e4transAppend ;
 | 
						|
 | 
						|
   #ifdef S4DISTRIBUTED
 | 
						|
      trans->currentTranStatus = r4partial ;
 | 
						|
      if ( numServers == 1 )   /* simple commit, perform completion as well */
 | 
						|
         rc = tran4complete( trans, id ) ;
 | 
						|
      else
 | 
						|
         rc = 0 ;
 | 
						|
   #else
 | 
						|
      rc = tran4lowRemoveKeys( trans ) ;
 | 
						|
      if ( rc < 0 )
 | 
						|
         return error4stack( c4, rc, E93801 ) ;
 | 
						|
      trans->currentTranStatus = r4inactive ;
 | 
						|
      trans->transId = 0;
 | 
						|
      #ifdef S4STAND_ALONE_TRANS
 | 
						|
         #ifndef S4UTILS
 | 
						|
            rc = code4tranUnlockTransactions( c4->c4trans, TRAN4LOCK_MULTIPLE ) ;
 | 
						|
            if ( rc == 0 )
 | 
						|
            {
 | 
						|
         #endif
 | 
						|
      #endif
 | 
						|
      #ifdef S4OFF_MULTI
 | 
						|
         rc = 0 ;
 | 
						|
      #else
 | 
						|
         trans->unlockAuto = trans->savedUnlockAuto ;
 | 
						|
         rc = tran4updateData( trans ) ;
 | 
						|
         if ( rc == 0 && doUnlock )
 | 
						|
         {
 | 
						|
            if ( code4unlockAuto( c4 ) == 1 )
 | 
						|
               rc = code4unlock( c4 ) ;
 | 
						|
         }
 | 
						|
      #endif
 | 
						|
      #ifdef S4STAND_ALONE_TRANS
 | 
						|
         #ifndef S4UTILS
 | 
						|
            }
 | 
						|
         #endif
 | 
						|
      #endif
 | 
						|
   #endif
 | 
						|
   if ( rc == 0 )
 | 
						|
      trans->c4trans->transFile->status = 0 ;
 | 
						|
 | 
						|
   tran4lowCloseDelayed( trans ) ;
 | 
						|
   return rc ;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef S4DISTRIBUTED
 | 
						|
int tran4lowComplete( TRAN4 *trans, long id )
 | 
						|
{
 | 
						|
   int rc ;
 | 
						|
   #ifdef E4PARM_LOW
 | 
						|
      if ( trans == 0 )
 | 
						|
         return error4( 0, e4parm_null, E93801 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( trans->currentTranStatus != S4PARTIAL )
 | 
						|
      return error4( trans->c4trans->c4, e4commit, E83811 ) ;
 | 
						|
 | 
						|
   rc = tran4set( trans, trans->currentTranStatus, -1, id, TRAN4COMMIT, 0, 0L, 0L ) ;
 | 
						|
   if ( rc < 0 )
 | 
						|
      return rc ;
 | 
						|
   if ( tran4lowAppend( trans, "\0" ) != 0 )
 | 
						|
      return e4transAppend ;
 | 
						|
 | 
						|
   trans->currentTranStatus = TRAN4INACTIVE ;
 | 
						|
   trans->unlockAuto = trans->savedUnlockAuto ;
 | 
						|
 | 
						|
   return 0 ;
 | 
						|
}
 | 
						|
#endif  /* S4DISTRIBUTED */
 | 
						|
#endif  /* not S4CLIENT */
 | 
						|
 | 
						|
#ifdef S4SERVER
 | 
						|
#ifndef S4INLINE
 | 
						|
int S4FUNCTION code4tranStart( CODE4 *c4 )
 | 
						|
{
 | 
						|
   return tran4lowStart( &c4->currentClient->trans, connection4id( c4->currentClient->connection ), 0 ) ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION code4tranStartSingle( CODE4 *c4 )
 | 
						|
{
 | 
						|
   return tran4lowStart( &c4->currentClient->trans, connection4id( c4->currentClient->connection ), 0 ) ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION code4tranCommit( CODE4 *c4 )
 | 
						|
{
 | 
						|
   int rc ;
 | 
						|
 | 
						|
   rc = code4flush( c4 ) ;
 | 
						|
   if ( rc != 0 )
 | 
						|
      return rc ;
 | 
						|
 | 
						|
   return tran4lowCommit( &c4->currentClient->trans, connection4id( c4->currentClient->connection ), 1 ) ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION code4tranRollback( CODE4 *c4 )
 | 
						|
{
 | 
						|
   return tran4lowRollback( &c4->currentClient->trans, connection4id( c4->currentClient->connection ), 1 ) ;
 | 
						|
}
 | 
						|
#endif  /* S4INLINE */
 | 
						|
#endif  /* S4SERVER */
 | 
						|
 | 
						|
 | 
						|
#ifndef S4SERVER
 | 
						|
 | 
						|
/* places all DATA4's into an invalid state */
 | 
						|
static void code4invalidate( CODE4 *c4 )
 | 
						|
{
 | 
						|
   DATA4 *dataOn ;
 | 
						|
 | 
						|
   #ifdef E4PARM_LOW
 | 
						|
      if ( c4 == 0 )
 | 
						|
      {
 | 
						|
         error4( 0, e4parm_null, E93827 ) ;
 | 
						|
         return ;
 | 
						|
      }
 | 
						|
   #endif
 | 
						|
 | 
						|
   for ( dataOn = 0 ;; )
 | 
						|
   {
 | 
						|
      dataOn = (DATA4 *)l4next( c4->c4trans.trans.dataList, dataOn ) ;
 | 
						|
      if ( dataOn == 0 )
 | 
						|
         break ;
 | 
						|
      /* 04/24/96 --> d4blank() replacing memset due to S4FOX binary
 | 
						|
         fields having non-blank contents to represent blank */
 | 
						|
/*      memset( dataOn->record, ' ', dfile4recWidth( dataOn->dataFile ) ) ; */
 | 
						|
      dataOn->recNum = dataOn->recNumOld = -1 ;  /* ensure that d4blank works with lock-enforce on, plus reset record # */
 | 
						|
      d4blank( dataOn ) ;
 | 
						|
      d4changed( dataOn, 0 ) ;
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
#ifndef S4CLIENT
 | 
						|
S4EXPORT int S4FUNCTION code4tranCommit( CODE4 *c4 )
 | 
						|
{
 | 
						|
   int saveErr, rc ;
 | 
						|
 | 
						|
   #ifdef E4PARM_HIGH
 | 
						|
      if ( c4 == 0 )
 | 
						|
         return error4( 0, e4parm_null, E93828 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( code4transEnabled( c4 ) != 1 )
 | 
						|
      return error4( c4, e4trans, E83807 ) ;
 | 
						|
 | 
						|
   rc = code4flush( c4 ) ;
 | 
						|
   if ( rc != 0 )
 | 
						|
      return rc ;
 | 
						|
 | 
						|
   saveErr = error4code( c4 ) ;
 | 
						|
   if ( saveErr < 0 )
 | 
						|
      error4set( c4, 0 ) ;
 | 
						|
 | 
						|
   rc = tran4lowCommit( &c4->c4trans.trans, 0, 1, 1 ) ;
 | 
						|
 | 
						|
   #ifndef S4OFF_MULTI
 | 
						|
      if ( code4unlockAuto( c4 ) == 1 )
 | 
						|
         if ( code4unlock( c4 ) != 0 )
 | 
						|
            return error4( c4, e4unlock, E93828 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( saveErr == 0 )
 | 
						|
      saveErr = rc ;
 | 
						|
   if ( saveErr != 0 )
 | 
						|
      error4set( c4, saveErr ) ;
 | 
						|
 | 
						|
   return rc ;
 | 
						|
}
 | 
						|
 | 
						|
S4EXPORT int S4FUNCTION code4tranStart( CODE4 *c4 )
 | 
						|
{
 | 
						|
   #ifdef E4PARM_HIGH
 | 
						|
      if ( c4 == 0 )
 | 
						|
         return error4( 0, e4parm_null, E93829 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   return tran4lowStart( &c4->c4trans.trans, 0, 0 ) ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION code4tranStartSingle( CODE4 *c4 )
 | 
						|
{
 | 
						|
   #ifdef E4PARM_HIGH
 | 
						|
      if ( c4 == 0 )
 | 
						|
         return error4( 0, e4parm_null, E93829 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   return tran4lowStart( &c4->c4trans.trans, 0, 0 ) ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION code4tranRollback( CODE4 *c4 )
 | 
						|
{
 | 
						|
   int rc ;
 | 
						|
 | 
						|
   #ifdef E4PARM_HIGH
 | 
						|
      if ( c4 == 0 )
 | 
						|
         return error4( 0, e4parm_null, E93830 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( code4transEnabled( c4 ) != 1 )
 | 
						|
      return error4( c4, e4trans, E83807 ) ;
 | 
						|
 | 
						|
   rc = tran4lowRollback( &c4->c4trans.trans, 0, 1 ) ;
 | 
						|
   if ( rc < 0 )
 | 
						|
      return rc ;
 | 
						|
 | 
						|
/*   rc = code4invalidate( c4 ) ;   --> moved to low rollback.*/
 | 
						|
/*   if ( rc < 0 )*/
 | 
						|
/*      return rc ;*/
 | 
						|
 | 
						|
   #ifdef S4OFF_MULTI
 | 
						|
      return 0 ;
 | 
						|
   #else
 | 
						|
      return code4unlock( c4 ) ;
 | 
						|
   #endif
 | 
						|
}
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef S4CLIENT
 | 
						|
int S4FUNCTION code4tranCommit( CODE4 *c4 )
 | 
						|
{
 | 
						|
   int saveRc, saveErr ;
 | 
						|
   SOCKET4 *socket4 ;
 | 
						|
   CONNECTION4 *connection ;
 | 
						|
   CONNECTION4COMMIT_INFO_IN info ;
 | 
						|
   #ifdef S4DISTRIBUTED
 | 
						|
      unsigned int dataLen ;
 | 
						|
      char *data ;
 | 
						|
      int numServers, rc ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      socket4 = 0 ;
 | 
						|
      connection = 0 ;
 | 
						|
      memset( &info, 0, sizeof( CONNECTION4COMMIT_INFO_IN ) ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifdef E4PARM_HIGH
 | 
						|
      if ( c4 == 0 )
 | 
						|
         return error4( 0, e4parm_null, E93828 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( code4transEnabled( c4 ) != 1 )
 | 
						|
      return error4( c4, e4trans, E83807 ) ;
 | 
						|
 | 
						|
   if ( c4->c4trans.trans.currentTranStatus == r4inactive )
 | 
						|
      return error4( c4, e4trans, E83812 ) ;
 | 
						|
 | 
						|
   saveRc = code4flush( c4 ) ;
 | 
						|
   if ( saveRc != 0 )
 | 
						|
      return saveRc ;
 | 
						|
 | 
						|
   #ifdef S4DISTRIBUTED
 | 
						|
      if ( c4->servers.nLink == 0 )
 | 
						|
   #else
 | 
						|
      if ( c4->defaultServer == 0 )
 | 
						|
   #endif
 | 
						|
      if ( c4->defaultServer == 0 )
 | 
						|
         return error4( c4, e4connection, E80304 ) ;
 | 
						|
 | 
						|
   if ( error4code( c4 ) < 0 )
 | 
						|
   {
 | 
						|
      saveErr = error4code( c4 ) ;
 | 
						|
      error4set( c4, 0 ) ;
 | 
						|
   }
 | 
						|
   else
 | 
						|
      saveErr = 0 ;
 | 
						|
 | 
						|
   saveRc = 0 ;
 | 
						|
 | 
						|
   #ifdef S4DISTRIBUTED
 | 
						|
      if ( c4->servers.nLink == 1 )   /* simple commit only required */
 | 
						|
      {
 | 
						|
   #endif
 | 
						|
      info.numServers = 1 ;
 | 
						|
      #ifdef S4DISTRIBUTED
 | 
						|
         socket4 = (SOCKET4 *)l4first( &c4->servers ) ;
 | 
						|
      #else
 | 
						|
         socket4 = c4->defaultServer ;
 | 
						|
      #endif
 | 
						|
      connection = socket4->connect ;
 | 
						|
      connection4assign( connection, CON4COMMIT, 0, 0 ) ;
 | 
						|
      connection4addData( connection, &info, sizeof( CONNECTION4COMMIT_INFO_IN ), 0 ) ;
 | 
						|
      connection4send( connection ) ;
 | 
						|
      saveRc = connection4receive( connection ) ;
 | 
						|
      if ( saveRc >= 0 )
 | 
						|
         saveRc = connection4status( connection ) ;
 | 
						|
   #ifdef S4DISTRIBUTED
 | 
						|
      }
 | 
						|
      else
 | 
						|
      {
 | 
						|
         info.numServers = c4->servers.nLink ;
 | 
						|
 | 
						|
         dataLen = sizeof( CONNECTION4COMMIT_INFO_IN ) + info.numServers * S4STAND_ALONE_ALIAS_LEN ;
 | 
						|
         data = (char *)u4allocFree( c4, dataLen ) ;
 | 
						|
         if ( data == 0 )
 | 
						|
            return error4stack( c4, e4memory, E93828 ) ;
 | 
						|
 | 
						|
         memcpy( data, &info, sizeof( CONNECTION4COMMIT_INFO_IN ) ) ;
 | 
						|
 | 
						|
         rc = 0 ;
 | 
						|
         socket4 = 0 ;
 | 
						|
         for( numServers = 0 ;; numServers++ )  /* prepare the info packets */
 | 
						|
         {
 | 
						|
            socket4 = (SOCKET4 *)l4next( &c4->servers, socket4 ) ;
 | 
						|
            if ( socket4 == 0 )
 | 
						|
               break ;
 | 
						|
            connection = socket4->connect ;
 | 
						|
            if ( connection == 0 )
 | 
						|
               return error4( c4, e4info, E93828 ) ;
 | 
						|
            memcpy( data + sizeof( CONNECTION4COMMIT_INFO_IN ) + numServers * S4STAND_ALONE_ALIAS_LEN, socket4->serverName, NEED A LOCAL FOR SERVER NAME, SET TO SIZE AND S4MAX_SERVER_NAME_SI
 | 
						|
         }
 | 
						|
 | 
						|
         rc = 0 ;
 | 
						|
         socket4 = 0 ;
 | 
						|
         for( ;; )  /* set commit message to all connected servers */
 | 
						|
         {
 | 
						|
            socket4 = (SOCKET4 *)l4next( &c4->servers, socket4 ) ;
 | 
						|
            if ( socket4 == 0 )
 | 
						|
               break ;
 | 
						|
            connection = socket4->connect ;
 | 
						|
            connection4assign( connection, CON4COMMIT, 0, 0 ) ;
 | 
						|
            connection4addData( connection, data, dataLen, 0 ) ;
 | 
						|
            connection4send( connection ) ;
 | 
						|
            rc = connection4receive( connection ) ;
 | 
						|
            if ( rc < 0 )
 | 
						|
               break ;
 | 
						|
            rc = connection4status( connection ) ;
 | 
						|
            if ( rc != 0 )
 | 
						|
               break ;
 | 
						|
         }
 | 
						|
 | 
						|
         if ( rc != 0 )  /* rollback everybody */
 | 
						|
         {
 | 
						|
            for( ;; )
 | 
						|
            {
 | 
						|
               socket4 = (SOCKET4 *)l4prev( &c4->servers, socket4 ) ;
 | 
						|
               if ( socket4 == 0 )
 | 
						|
                  break ;
 | 
						|
               connection = socket4->connect ;
 | 
						|
               connection4assign( connection, S4CANCEL_TRANSACTION, 0, 0 ) ;
 | 
						|
               connection4send( connection ) ;
 | 
						|
               connection4receive( connection, rc ) ;
 | 
						|
            }
 | 
						|
 | 
						|
            return rc ;
 | 
						|
         }
 | 
						|
 | 
						|
         socket4 = 0 ;
 | 
						|
         for( ;; )  /* complete the commits */
 | 
						|
         {
 | 
						|
            socket4 = (SOCKET4 *)l4next( &c4->servers, socket4 ) ;
 | 
						|
            if ( socket4 == 0 )
 | 
						|
               break ;
 | 
						|
            connection = socket4->connect ;
 | 
						|
            connection4assign( connection, S4COMPLETE, 0, 0 ) ;
 | 
						|
            connection4send( connection ) ;
 | 
						|
            rc = connection4receive( connection ) ;
 | 
						|
            if ( rc < 0 )
 | 
						|
            {
 | 
						|
               saveRc = rc ;
 | 
						|
               error4set( c4, 0 ) ;
 | 
						|
               continue ;
 | 
						|
            }
 | 
						|
            rc = connection4status( connection ) ;
 | 
						|
            if ( rc < 0 )
 | 
						|
            {
 | 
						|
               saveRc = rc ;
 | 
						|
               error4set( c4, 0 ) ;
 | 
						|
               continue ;
 | 
						|
            }
 | 
						|
         }
 | 
						|
      }
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( saveErr == 0 )
 | 
						|
      saveErr = saveRc ;
 | 
						|
   if ( saveErr != 0 )
 | 
						|
      error4set( c4, saveErr ) ;
 | 
						|
 | 
						|
   c4->c4trans.trans.currentTranStatus = r4inactive ;
 | 
						|
   tran4lowCloseDelayed( &c4->c4trans.trans ) ;
 | 
						|
   return 0 ;
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION code4tranStart( CODE4 *c4 )
 | 
						|
{
 | 
						|
   CONNECTION4 *connection ;
 | 
						|
   int rc ;
 | 
						|
   #ifdef S4DISTRIBUTED
 | 
						|
      SOCKET4 *socket4 ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifdef E4PARM_HIGH
 | 
						|
      if ( c4 == 0 )
 | 
						|
         return error4( 0, e4parm_null, E93829 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( code4transEnabled( c4 ) != 1 )
 | 
						|
      return error4( c4, e4trans, E83807 ) ;
 | 
						|
 | 
						|
   if ( c4->c4trans.trans.currentTranStatus == r4active )
 | 
						|
      return error4( c4, e4trans, E93829 ) ;
 | 
						|
 | 
						|
   rc = 0 ;
 | 
						|
   #ifdef S4DISTRIBUTED
 | 
						|
      socket4 = 0 ;
 | 
						|
      for( ;; )  /* set start message to all connected servers */
 | 
						|
      {
 | 
						|
         socket4 = (SOCKET4 *)l4next( &c4->servers, socket4 ) ;
 | 
						|
         if ( socket4 == 0 )
 | 
						|
         break ;
 | 
						|
         connection = socket4->connect ;
 | 
						|
         connection4assign( connection, CON4START, 0, 0 ) ;
 | 
						|
         connection4send( connection ) ;
 | 
						|
         rc = connection4receive( connection ) ;
 | 
						|
         if ( rc < 0 )
 | 
						|
            break ;
 | 
						|
         rc = connection4status( connection ) ;
 | 
						|
         if ( rc != 0 )
 | 
						|
         {
 | 
						|
            if ( rc < 0 )
 | 
						|
               connection4error( connection, c4, rc, E93829 ) ;
 | 
						|
            break ;
 | 
						|
         }
 | 
						|
      }
 | 
						|
   #else
 | 
						|
      if ( c4->defaultServer == 0 )
 | 
						|
         return error4( c4, e4connection, E80304 ) ;
 | 
						|
 | 
						|
      if ( c4->defaultServer != 0 )
 | 
						|
      {
 | 
						|
         connection = c4->defaultServer->connect ;
 | 
						|
         connection4assign( connection, CON4START, 0, 0 ) ;
 | 
						|
         connection4send( connection ) ;
 | 
						|
         rc = connection4receive( connection ) ;
 | 
						|
         if ( rc >= 0 )
 | 
						|
            rc = connection4status( connection ) ;
 | 
						|
      }
 | 
						|
 | 
						|
      if ( rc < 0 )
 | 
						|
         return error4stack( c4, rc, E93829 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   c4->c4trans.trans.currentTranStatus = r4active ;
 | 
						|
 | 
						|
   return rc ;
 | 
						|
 | 
						|
/* code4save()*/
 | 
						|
}
 | 
						|
 | 
						|
int S4FUNCTION code4tranRollback( CODE4 *c4 )
 | 
						|
{
 | 
						|
   CONNECTION4 *connection ;
 | 
						|
   int rc ;
 | 
						|
   #ifdef S4DISTRIBUTED
 | 
						|
      SOCKET4 *socket4 ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifdef E4PARM_HIGH
 | 
						|
      if ( c4 == 0 )
 | 
						|
         return error4( 0, e4parm_null, E93830 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( code4transEnabled( c4 ) != 1 )
 | 
						|
      return error4( c4, e4trans, E83807 ) ;
 | 
						|
 | 
						|
   if ( c4->c4trans.trans.currentTranStatus == r4inactive )
 | 
						|
      return error4( c4, e4trans, E83808 ) ;
 | 
						|
 | 
						|
   #ifdef S4DISTRIBUTED
 | 
						|
      socket4 = 0 ;
 | 
						|
      for( ;; )  /* set start message to all connected servers */
 | 
						|
      {
 | 
						|
         socket4 = (SOCKET4 *)l4next( &c4->servers, socket4 ) ;
 | 
						|
         if ( socket4 == 0 )
 | 
						|
            break ;
 | 
						|
         connection = socket4->connect ;
 | 
						|
         connection4assign( connection, TRAN4ROLLBACK, 0, 0 ) ;
 | 
						|
         connection4send( connection ) ;
 | 
						|
         rc = connection4receive( connection ) ;
 | 
						|
         if ( rc < 0 )
 | 
						|
            return error4( c4, rc, E93830 ) ;
 | 
						|
         rc = connection4status( connection ) ;
 | 
						|
         if ( rc < 0 )
 | 
						|
            return connection4error( connection, c4, rc, E93830 ) ;
 | 
						|
      }
 | 
						|
   #else
 | 
						|
      if ( c4->defaultServer == 0 )
 | 
						|
         return error4( c4, e4connection, E80304 ) ;
 | 
						|
 | 
						|
      if ( c4->defaultServer != 0 )
 | 
						|
      {
 | 
						|
         connection = c4->defaultServer->connect ;
 | 
						|
         connection4assign( connection, CON4ROLLBACK, 0, 0 ) ;
 | 
						|
         connection4send( connection ) ;
 | 
						|
         rc = connection4receive( connection ) ;
 | 
						|
         if ( rc >= 0 )
 | 
						|
            rc = connection4status( connection ) ;
 | 
						|
         if ( rc != 0 )
 | 
						|
            return error4stack( c4, rc, E93830 ) ;
 | 
						|
      }
 | 
						|
   #endif
 | 
						|
 | 
						|
   c4->c4trans.trans.currentTranStatus = r4inactive ;
 | 
						|
 | 
						|
   /* 04/24/96 AS --> moved code4invalidate before unlock call, so that any
 | 
						|
      changes left to records won't be flushed as a result of the unlock
 | 
						|
      call */
 | 
						|
   code4invalidate( c4 ) ;
 | 
						|
 | 
						|
   rc = code4unlock( c4 ) ;
 | 
						|
   if ( rc < 0 )
 | 
						|
      return rc ;
 | 
						|
   tran4lowCloseDelayed( &c4->c4trans.trans ) ;
 | 
						|
 | 
						|
   return 0 ;
 | 
						|
/*   code4restore( c4 ) ;*/
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef S4STAND_ALONE
 | 
						|
int S4FUNCTION code4transFileEnable( CODE4TRANS *c4trans, const char *logName, const int doCreate )
 | 
						|
#else
 | 
						|
int code4transFileEnable( CODE4TRANS *c4trans, const char *logName, const int doCreate )
 | 
						|
#endif
 | 
						|
{
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      int rc ;
 | 
						|
   #else
 | 
						|
      #ifndef S4CLIENT
 | 
						|
         int rc ;
 | 
						|
      #endif
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifndef S4CLIENT
 | 
						|
      CODE4 *c4 ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( c4trans->enabled == 1 )
 | 
						|
      return 0 ;
 | 
						|
 | 
						|
   #ifdef S4STAND_ALONE
 | 
						|
      rc = code4tranInitLow( &c4trans->trans, c4trans ) ;
 | 
						|
      if ( rc < 0 )
 | 
						|
         return rc ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( ( rc = code4transVerify( c4trans, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifndef S4CLIENT
 | 
						|
      rc = 0 ;
 | 
						|
 | 
						|
      c4 = c4trans->c4 ;
 | 
						|
 | 
						|
      if ( c4trans->enabled == 0 )
 | 
						|
      {
 | 
						|
         if ( logName != 0 )
 | 
						|
         {
 | 
						|
            if ( c4->transFileName != 0 )
 | 
						|
               u4free( c4->transFileName ) ;
 | 
						|
            c4->transFileName = (char *)u4allocFree( c4, (long)strlen( logName ) + 1L ) ;
 | 
						|
            if ( c4->transFileName == 0 )
 | 
						|
               rc = e4memory ;
 | 
						|
            else
 | 
						|
               strcpy( c4->transFileName, logName ) ;
 | 
						|
         }
 | 
						|
 | 
						|
         if( c4->transFileName != 0 )
 | 
						|
         {
 | 
						|
            #ifdef S4SERVER
 | 
						|
               rc = tran4fileInit( &c4->server->transFile, c4trans ) ;
 | 
						|
            #else
 | 
						|
               rc = tran4fileInit( &c4->transFile, c4trans ) ;
 | 
						|
            #endif
 | 
						|
            if ( rc == 0 )
 | 
						|
            {
 | 
						|
               if ( doCreate == 0 )
 | 
						|
               {
 | 
						|
                  #ifdef S4SERVER
 | 
						|
                     rc = tran4fileOpen( &c4->server->transFile, c4->transFileName ) ;
 | 
						|
                  #else
 | 
						|
                     rc = tran4fileOpen( &c4->transFile, c4->transFileName ) ;
 | 
						|
                  #endif
 | 
						|
               }
 | 
						|
               else
 | 
						|
               {
 | 
						|
                  #ifdef S4SERVER
 | 
						|
                     rc = tran4fileCreate( &c4->server->transFile, c4->transFileName ) ;
 | 
						|
                  #else
 | 
						|
                     rc = tran4fileCreate( &c4->transFile, c4->transFileName ) ;
 | 
						|
                  #endif
 | 
						|
               }
 | 
						|
               if ( rc == 0 )
 | 
						|
               {
 | 
						|
                  c4trans->enabled = 1 ;
 | 
						|
                  #ifdef S4SERVER
 | 
						|
                     c4trans->transFile = &c4->server->transFile ;
 | 
						|
                  #else
 | 
						|
                     c4trans->transFile = &c4->transFile ;
 | 
						|
                  #endif
 | 
						|
               }
 | 
						|
            }
 | 
						|
         }
 | 
						|
      }
 | 
						|
      if ( rc != 0 )
 | 
						|
      {
 | 
						|
         u4free( c4->transFileName ) ;
 | 
						|
         c4->transFileName = 0 ;
 | 
						|
      }
 | 
						|
      return rc ;
 | 
						|
   #else
 | 
						|
      return 0 ;
 | 
						|
   #endif
 | 
						|
}
 | 
						|
 | 
						|
#ifndef S4CLIENT
 | 
						|
int tran4addUser( TRAN4 *trans, const long clientId, const char *charId, const unsigned short int lenIn )
 | 
						|
{
 | 
						|
   int rc ;
 | 
						|
   short int netIdLen ;
 | 
						|
   unsigned short int len ;
 | 
						|
   char *netId ;
 | 
						|
   CODE4 *c4 ;
 | 
						|
   #ifdef S4STAND_ALONE
 | 
						|
      #ifndef S4OFF_MULTI
 | 
						|
         int i, oldNumAttempts ;
 | 
						|
      #endif
 | 
						|
   #endif
 | 
						|
 | 
						|
   len = lenIn ;
 | 
						|
   c4 = trans->c4trans->c4 ;
 | 
						|
 | 
						|
   if ( trans->c4trans->enabled == 1 && code4tranStatus( c4 ) != r4off )
 | 
						|
   {
 | 
						|
      #ifdef S4STAND_ALONE
 | 
						|
         #ifdef S4OFF_MULTI
 | 
						|
            trans->userIdNo = 1 ;   /* only one user */
 | 
						|
         #else
 | 
						|
            if ( clientId == 0L )  /* need to manually get the id */
 | 
						|
            {
 | 
						|
               for ( i = 0 ;; i++ )
 | 
						|
               {
 | 
						|
                  if ( i >= TRAN4MAX_USERS )
 | 
						|
                     return error4( c4, e4max, E83816 ) ;
 | 
						|
                  oldNumAttempts = c4->lockAttempts ;
 | 
						|
                  c4->lockAttempts = 1 ;
 | 
						|
                  rc = file4lock( &trans->c4trans->transFile->file, TRAN4LOCK_USERS+i+1, 1 ) ;
 | 
						|
                  c4->lockAttempts = oldNumAttempts ;
 | 
						|
                  if ( rc == 0 )
 | 
						|
                  {
 | 
						|
                     trans->userIdNo = i + 1 ;
 | 
						|
                     break ;
 | 
						|
                  }
 | 
						|
               }
 | 
						|
            }
 | 
						|
         #endif
 | 
						|
      #endif
 | 
						|
      if ( len > sizeof( trans->userId ) )
 | 
						|
         len = sizeof( trans->userId ) - 1 ;
 | 
						|
      memcpy( trans->userId, charId, len ) ;
 | 
						|
      trans->userId[len] = 0 ;
 | 
						|
      #ifdef S4SERVER
 | 
						|
         netId = connection4netUserId( c4->currentClient->connection->net ) ;
 | 
						|
         if ( netId == 0 )
 | 
						|
            netIdLen = 0 ;
 | 
						|
         else
 | 
						|
            netIdLen = strlen( netId ) ;
 | 
						|
      #else
 | 
						|
         netId = (char *)0 ;
 | 
						|
         netIdLen = 0 ;
 | 
						|
      #endif
 | 
						|
      rc = tran4set( trans, trans->currentTranStatus, -1L, clientId, TRAN4INIT, len + netIdLen + sizeof( len ) + sizeof( netIdLen), 0L, 0L ) ;
 | 
						|
      if ( rc < 0 )
 | 
						|
         return rc ;
 | 
						|
      if ( tran4putData( trans, (void *)&netIdLen, sizeof( netIdLen ) ) == e4memory )
 | 
						|
         return e4memory ;
 | 
						|
      if ( netIdLen != 0 )
 | 
						|
         if ( tran4putData( trans, (void *)netId, (unsigned int)netIdLen ) == e4memory )
 | 
						|
            return e4memory ;
 | 
						|
      if ( tran4putData( trans, (void *)&len, sizeof( len ) ) == e4memory )
 | 
						|
         return e4memory ;
 | 
						|
      if ( tran4putData( trans, (void *)charId, len ) == e4memory )
 | 
						|
         return e4memory ;
 | 
						|
      if ( tran4lowAppend( trans, 0 ) != 0 )
 | 
						|
         return e4transAppend ;
 | 
						|
   }
 | 
						|
   else
 | 
						|
      return e4trans ;  /* must return error to client so it is known that code4tranInit failed */
 | 
						|
 | 
						|
   return 0 ;
 | 
						|
}
 | 
						|
#endif /* S4CLIENT */
 | 
						|
 | 
						|
#endif /* S4OFF_WRITE */
 | 
						|
#endif  /* S4OFF_TRAN */
 | 
						|
 | 
						|
#ifndef S4SERVER
 | 
						|
#ifdef P4ARGS_USED
 | 
						|
   #pragma argsused
 | 
						|
#endif
 | 
						|
int S4FUNCTION code4lock( CODE4 *c4 )
 | 
						|
{
 | 
						|
   #ifdef S4OFF_MULTI
 | 
						|
      return 0 ;
 | 
						|
   #else
 | 
						|
      LOCK4 *lock ;
 | 
						|
      #ifdef S4CLIENT
 | 
						|
         int numLocks, unlockData ;
 | 
						|
         int outRc = 0 ;
 | 
						|
         CONNECTION4 *connection ;
 | 
						|
         CONNECTION4LOCK_GROUP_INFO_IN info ;
 | 
						|
      #else
 | 
						|
         LOCK4 *lockNext ;
 | 
						|
         LIST4 locked ;
 | 
						|
         int saveErr, count, saveUnlockAuto ;
 | 
						|
      #endif
 | 
						|
      int rc = 0 ;
 | 
						|
      CODE4TRANS *c4trans ;
 | 
						|
 | 
						|
      #ifdef E4ANALYZE
 | 
						|
         if ( ( rc = code4verify( c4, 1 ) ) < 0 )
 | 
						|
            return rc ;
 | 
						|
      #endif
 | 
						|
 | 
						|
      c4trans = &c4->c4trans ;
 | 
						|
 | 
						|
      #ifdef S4CLIENT
 | 
						|
         numLocks = c4trans->trans.locks.nLink ;
 | 
						|
         if ( numLocks > 0 )
 | 
						|
         {
 | 
						|
            lock = (LOCK4 *)l4first( &c4trans->trans.locks ) ;  /* for next line */
 | 
						|
            connection = lock->data->dataFile->connection ;
 | 
						|
            info.numLocks = numLocks ;
 | 
						|
 | 
						|
            connection4assign( connection, CON4LOCK_GROUP, 0L, 0L ) ;
 | 
						|
            connection4addData( connection, &info, sizeof( info ), 0 ) ;
 | 
						|
            lock = (LOCK4 *)l4first( &c4trans->trans.locks ) ;  /* reset */
 | 
						|
            unlockData = ( code4unlockAuto( c4 ) == LOCK4DATA ) ;  /* must perform and register data unlock */
 | 
						|
            for( numLocks = info.numLocks ; numLocks > 0 ; numLocks-- )
 | 
						|
            {
 | 
						|
               #ifdef E4ANALYZE
 | 
						|
                  if ( lock == 0 )
 | 
						|
                     return error4stack( c4, e4struct, E91008 ) ;
 | 
						|
               #endif
 | 
						|
               if ( unlockData )
 | 
						|
                  d4unlockClientData( lock->data ) ;
 | 
						|
               connection4addData( connection, &lock->id, sizeof( LOCK4ID ), 0 ) ;
 | 
						|
               lock = (LOCK4 *)l4next( &c4trans->trans.locks, lock ) ;
 | 
						|
            }
 | 
						|
            outRc = connection4repeat( connection, -2, -1, -1, 0 ) ;
 | 
						|
            if ( outRc < 0 )
 | 
						|
               return connection4error( connection, c4, outRc, E91008 ) ;
 | 
						|
 | 
						|
            if ( outRc == r4locked )
 | 
						|
               return outRc ;
 | 
						|
 | 
						|
            for( ;; )  /* now free lock memory, and record locks if required */
 | 
						|
            {
 | 
						|
               lock = (LOCK4 *)l4first( &c4trans->trans.locks ) ;
 | 
						|
               if ( lock == 0 )
 | 
						|
                  break ;
 | 
						|
               if ( outRc == 0 )   /* record lock */
 | 
						|
               {
 | 
						|
                  switch( lock->id.type )
 | 
						|
                  {
 | 
						|
                     case LOCK4APPEND:
 | 
						|
                        lock->data->dataFile->appendLock = lock->data ;
 | 
						|
                        break ;
 | 
						|
                     case LOCK4FILE:
 | 
						|
                        lock->data->dataFile->fileLock = lock->data ;
 | 
						|
                        break ;
 | 
						|
                     case LOCK4ALL:
 | 
						|
                        lock->data->dataFile->fileLock = lock->data ;
 | 
						|
                        break ;
 | 
						|
                     case LOCK4RECORD:
 | 
						|
                        d4localLockSet( lock->data, lock->id.recNum ) ;
 | 
						|
                        break ;
 | 
						|
                     #ifdef E4ANALYZE
 | 
						|
                        default:
 | 
						|
                           return error4( c4, e4lock, E81505 ) ;
 | 
						|
                     #endif
 | 
						|
                  }
 | 
						|
               }
 | 
						|
               l4remove( &c4trans->trans.locks, lock ) ;
 | 
						|
               mem4free( c4->lockMemory, lock ) ;
 | 
						|
            }
 | 
						|
         }
 | 
						|
         return outRc ;
 | 
						|
      #else
 | 
						|
         saveUnlockAuto = code4unlockAuto( c4 ) ;
 | 
						|
 | 
						|
         if ( saveUnlockAuto == 1 )
 | 
						|
         {
 | 
						|
            rc = code4unlockDo( tran4dataList( &c4->c4trans.trans ) ) ;
 | 
						|
            if ( rc < 0 )
 | 
						|
               return error4stack( c4, rc, E91008 ) ;
 | 
						|
         }
 | 
						|
 | 
						|
         code4unlockAutoSet( c4, 0 ) ;
 | 
						|
 | 
						|
         memset( &locked, 0, sizeof( locked ) ) ;
 | 
						|
         for ( lock = 0, count = -1 ;; )
 | 
						|
         {
 | 
						|
            if ( lock == 0 )
 | 
						|
            {
 | 
						|
               lock = (LOCK4 *)l4first( &c4trans->trans.locks ) ;
 | 
						|
               count++ ;
 | 
						|
 | 
						|
               if ( c4->lockAttemptsSingle != WAIT4EVER )
 | 
						|
                  if ( count >= c4->lockAttemptsSingle )  /* timed out */
 | 
						|
                     for ( ;; )
 | 
						|
                     {
 | 
						|
                        lock = (LOCK4 *)l4first( &locked ) ;
 | 
						|
                        if ( lock == 0 )
 | 
						|
                        {
 | 
						|
                           code4unlockAutoSet( c4, saveUnlockAuto ) ;
 | 
						|
                           return r4locked ;
 | 
						|
                        }
 | 
						|
                        lockNext = (LOCK4 *)l4next( &locked, lock ) ;
 | 
						|
                        l4remove( &locked, lock ) ;
 | 
						|
                        l4add( &c4trans->trans.locks, lock ) ;
 | 
						|
                        lock = lockNext ;
 | 
						|
                     }
 | 
						|
            }
 | 
						|
 | 
						|
            if ( lock == 0 )
 | 
						|
            {
 | 
						|
               code4unlockAutoSet( c4, saveUnlockAuto ) ;
 | 
						|
               return 0 ;
 | 
						|
            }
 | 
						|
 | 
						|
            switch( lock4lock( lock ) )
 | 
						|
            {
 | 
						|
               case r4success:
 | 
						|
                  lockNext = (LOCK4 *)l4next( &c4trans->trans.locks, lock ) ;
 | 
						|
                  l4remove( &c4trans->trans.locks, lock ) ;
 | 
						|
                  l4add( &locked, lock ) ;
 | 
						|
                  lock = lockNext ;
 | 
						|
                  if ( lock == 0 )
 | 
						|
                  {
 | 
						|
                     for ( ;; )
 | 
						|
                     {
 | 
						|
                        lock = (LOCK4 *)l4first( &locked ) ;
 | 
						|
                        if ( lock == 0 )
 | 
						|
                           break ;
 | 
						|
                        l4remove( &locked, lock ) ;
 | 
						|
                        mem4free( c4->lockMemory, lock ) ;
 | 
						|
                     }
 | 
						|
                     code4unlockAutoSet( c4, saveUnlockAuto ) ;
 | 
						|
                     return 0 ;
 | 
						|
                  }
 | 
						|
                  break ;
 | 
						|
               case r4locked:
 | 
						|
                  lock = (LOCK4 *)l4next( &c4trans->trans.locks, lock ) ;
 | 
						|
                  break ;
 | 
						|
               default:
 | 
						|
                  saveErr = error4set( c4trans->c4, 0 ) ;
 | 
						|
                  for ( ;; )
 | 
						|
                  {
 | 
						|
                     lock = (LOCK4 *)l4first( &locked ) ;
 | 
						|
                     if ( lock == 0 )
 | 
						|
                     {
 | 
						|
                        error4set( c4trans->c4, saveErr ) ;
 | 
						|
                        code4unlockAutoSet( c4, saveUnlockAuto ) ;
 | 
						|
                        return -1 ;
 | 
						|
                     }
 | 
						|
 | 
						|
                     l4remove( &locked, lock ) ;
 | 
						|
                     l4add( &c4trans->trans.locks, lock ) ;
 | 
						|
                     lock4unlock( lock ) ;
 | 
						|
                  }
 | 
						|
            }
 | 
						|
         }
 | 
						|
      #endif  /* S4CLIENT */
 | 
						|
   #endif  /* S4OFF_MULTI */
 | 
						|
}
 | 
						|
#endif  /* not S4SERVER */
 | 
						|
 | 
						|
#ifdef S4SERVER
 | 
						|
int tran4closeAll( TRAN4 *trans )
 | 
						|
{
 | 
						|
   DATA4 *dataOn, *dataNext ;
 | 
						|
   int rc ;
 | 
						|
   LIST4 *list ;
 | 
						|
 | 
						|
   #ifdef E4PARM_LOW
 | 
						|
      if ( trans == 0 )
 | 
						|
         return error4( 0, e4parm_null, E93801 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   rc = 0 ;
 | 
						|
   list = tran4dataList( trans ) ;
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( list == 0 )
 | 
						|
         return error4( trans->c4trans->c4, e4struct, E93801 ) ;
 | 
						|
   #endif
 | 
						|
   for ( dataNext = (DATA4 *)l4first( list ) ;; )
 | 
						|
   {
 | 
						|
      dataOn = dataNext ;
 | 
						|
      if ( !dataOn )
 | 
						|
         break ;
 | 
						|
      dataNext = (DATA4 *)l4next( list, dataNext ) ;
 | 
						|
 | 
						|
      if ( d4close( dataOn ) < 0 )
 | 
						|
         rc = -1 ;
 | 
						|
   }
 | 
						|
 | 
						|
   if ( error4code( trans->c4trans->c4 ) < 0 )
 | 
						|
      return -1 ;
 | 
						|
 | 
						|
   return rc ;
 | 
						|
}
 | 
						|
#endif  /* S4SERVER */
 | 
						|
 | 
						|
#ifdef E4ANALYZE
 | 
						|
static int code4transVerify( CODE4TRANS *c4trans, int subs )
 | 
						|
{
 | 
						|
   int rc ;
 | 
						|
 | 
						|
   if ( c4trans == 0 )
 | 
						|
      return error4( 0, e4parm_null, E93832 ) ;
 | 
						|
 | 
						|
   if ( subs == 1 )
 | 
						|
   {
 | 
						|
      if ( ( rc = code4verify( c4trans->c4, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
   }
 | 
						|
   else
 | 
						|
      if ( c4trans->c4 == 0 )
 | 
						|
         return error4( 0, e4struct, E93832 ) ;
 | 
						|
 | 
						|
   #ifndef S4OFF_TRAN
 | 
						|
      #ifndef S4OFF_WRITE
 | 
						|
         #ifndef S4CLIENT
 | 
						|
            if ( c4trans->enabled == 1 )
 | 
						|
               if ( c4trans->transFile == 0 )
 | 
						|
                  return error4( c4trans->c4, e4struct, E93832 ) ;
 | 
						|
         #endif
 | 
						|
      #endif
 | 
						|
   #endif
 | 
						|
 | 
						|
   return 0 ;
 | 
						|
}
 | 
						|
 | 
						|
int tran4verify( TRAN4 *t4, int subs )
 | 
						|
{
 | 
						|
   int rc ;
 | 
						|
   #ifndef S4OFF_TRAN
 | 
						|
      CODE4 *c4 ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( t4 == 0 )
 | 
						|
      return error4( 0, e4parm_null, E93801 ) ;
 | 
						|
 | 
						|
   if ( t4->c4trans == 0 )
 | 
						|
      return error4( 0, e4struct, E93801 ) ;
 | 
						|
 | 
						|
   #ifndef S4OFF_TRAN
 | 
						|
      c4 = t4->c4trans->c4 ;
 | 
						|
 | 
						|
      if ( ( c4->tranDataLen != 0 && c4->tranData == 0 ) || ( c4->tranDataLen == 0 && c4->tranData != 0 ) )
 | 
						|
         return error4( c4, e4struct, E93801 ) ;
 | 
						|
 | 
						|
      if ( ( t4->dataPos != 0 && c4->tranDataLen == 0 ) )
 | 
						|
         return error4( c4, e4struct, E93801 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( subs == 1 )
 | 
						|
      if ( ( rc = code4transVerify( t4->c4trans, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
 | 
						|
   return 0 ;
 | 
						|
}
 | 
						|
#endif  /* E4ANALYZE */
 | 
						|
 | 
						|
int code4tranInitLow( TRAN4 *t4, CODE4TRANS *c4trans )
 | 
						|
{
 | 
						|
   #ifdef E4PARM_LOW
 | 
						|
      if ( t4 == 0 || c4trans == 0 )
 | 
						|
         return error4( 0, e4parm_null, E93834 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   t4->c4trans = c4trans ;
 | 
						|
 | 
						|
   #ifndef S4OFF_WRITE
 | 
						|
      t4->transId = -1 ;
 | 
						|
      t4->dataPos = 0 ;
 | 
						|
      t4->pos = -1 ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifdef S4CLIENT
 | 
						|
      t4->dataIdCount = 1 ;
 | 
						|
   #endif
 | 
						|
   #ifdef S4SERVER
 | 
						|
      t4->unlockAuto = 1 ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifndef S4OFF_WRITE
 | 
						|
      t4->currentTranStatus = r4inactive ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   tran4dataListSet( t4, &(t4->localDataList) ) ;
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      return tran4verify( t4, 0 ) ;
 | 
						|
   #else
 | 
						|
      return 0 ;
 | 
						|
   #endif
 | 
						|
}
 | 
						|
 | 
						|
#ifdef P4ARGS_USED
 | 
						|
   #pragma argsused
 | 
						|
#endif
 | 
						|
int S4FUNCTION code4transInitUndo( CODE4TRANS *c4trans )
 | 
						|
{
 | 
						|
   #ifndef S4OFF_WRITE
 | 
						|
      #ifndef S4CLIENT
 | 
						|
         CODE4 *c4 ;
 | 
						|
         #ifndef S4OFF_TRAN
 | 
						|
            int rc, oldError ;
 | 
						|
            LOG4HEADER header ;
 | 
						|
            short int i ;
 | 
						|
            #ifdef S4STAND_ALONE
 | 
						|
               #ifndef S4OFF_MULTI
 | 
						|
                  int oldNumAttempts ;
 | 
						|
               #endif
 | 
						|
            #endif
 | 
						|
         #endif
 | 
						|
      #endif
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifdef E4PARM_LOW
 | 
						|
      if ( c4trans == 0 )
 | 
						|
         return error4( 0, e4parm_null, E93835 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifdef S4OFF_WRITE
 | 
						|
      return 0 ;
 | 
						|
   #else
 | 
						|
      #ifdef S4CLIENT
 | 
						|
         return 0 ;
 | 
						|
      #else
 | 
						|
         c4 = c4trans->c4 ;
 | 
						|
         if ( c4 != 0 )
 | 
						|
            if ( c4->transFileName != 0 )
 | 
						|
            {
 | 
						|
               u4free( c4->transFileName ) ;
 | 
						|
               c4->transFileName = 0 ;
 | 
						|
            }
 | 
						|
 | 
						|
         #ifndef S4OFF_TRAN
 | 
						|
            oldError = error4set( c4trans->c4, 0 ) ;
 | 
						|
            rc = 0 ;
 | 
						|
            if ( c4trans->transFile != 0 )
 | 
						|
            {
 | 
						|
               #ifdef S4STAND_ALONE
 | 
						|
                  #ifndef S4UTILS
 | 
						|
                     code4tranInitUndoLow( &c4trans->trans, 0L ) ;
 | 
						|
                     if (c4trans->trans.currentTranStatus == r4inactive)
 | 
						|
                     {
 | 
						|
                        #ifndef S4OFF_MULTI
 | 
						|
                           file4unlock( &c4trans->transFile->file, TRAN4LOCK_USERS + c4trans->trans.userIdNo, 1 ) ;
 | 
						|
                           oldNumAttempts = c4->lockAttempts ;
 | 
						|
                           c4->lockAttempts = 1 ;
 | 
						|
                           if ( file4lock( &c4trans->transFile->file, TRAN4LOCK_USERS, TRAN4MAX_USERS ) != r4locked ) /* last user, so shutdown */
 | 
						|
                        #endif
 | 
						|
                        {
 | 
						|
                  #endif /* S4UTILS */
 | 
						|
               #endif /* S4STAND_ALONE */
 | 
						|
               #ifndef S4UTILS
 | 
						|
                        if ( c4trans->transFile->status == 0 )
 | 
						|
                        {
 | 
						|
                           memset( &header, 0, sizeof( header ) ) ;
 | 
						|
                           header.type = TRAN4SHUTDOWN ;
 | 
						|
                           header.serverDataId = TRAN4VERSION_NUM ;
 | 
						|
                           tran4fileAppend( c4trans->transFile, &header, "\0" ) ;
 | 
						|
                        }
 | 
						|
               #endif
 | 
						|
               #ifdef S4STAND_ALONE
 | 
						|
                  #ifndef S4UTILS
 | 
						|
                        #ifndef S4OFF_MULTI
 | 
						|
                           file4unlock( &c4trans->transFile->file, TRAN4LOCK_USERS, TRAN4MAX_USERS ) ;
 | 
						|
                        #endif
 | 
						|
                     }
 | 
						|
                     #ifndef S4OFF_MULTI
 | 
						|
                        c4->lockAttempts = oldNumAttempts ;
 | 
						|
                     #endif
 | 
						|
                  }
 | 
						|
                  #endif /* S4UTILS */
 | 
						|
               #endif  /* S4STAND_ALONE */
 | 
						|
               i = -1;
 | 
						|
               #ifndef S4OFF_MULTI
 | 
						|
                  #ifndef S4UTILS
 | 
						|
                     while ( (1UL << ++i ) <= c4trans->transFile->fileLocks )
 | 
						|
                        if ( c4trans->transFile->fileLocks & ( 1UL << i ) )
 | 
						|
                           code4tranUnlockTransactions( c4trans, TRAN4LOCK_BASE + i ) ;
 | 
						|
                  #endif
 | 
						|
               #endif
 | 
						|
               rc = tran4fileClose( c4trans->transFile ) ;
 | 
						|
               c4trans->transFile = 0 ;
 | 
						|
            }
 | 
						|
            c4trans->enabled = 0 ;
 | 
						|
            error4set( c4trans->c4, oldError ) ;
 | 
						|
            return rc ;
 | 
						|
         #else
 | 
						|
            return 0 ;
 | 
						|
         #endif  /* S4OFF_TRAN */
 | 
						|
      #endif  /* S4CLIENT */
 | 
						|
   #endif
 | 
						|
}
 | 
						|
 | 
						|
#ifdef S4SERVER
 | 
						|
int code4transInit( CODE4TRANS *c4trans, CODE4 *c4 )
 | 
						|
{
 | 
						|
   #ifndef S4SERVER
 | 
						|
      int rc ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifdef E4PARM_LOW
 | 
						|
      if ( c4trans == 0 || c4 == 0 )
 | 
						|
         return error4( 0, e4parm_null, E93836 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifndef S4OFF_TRAN
 | 
						|
      #ifndef S4CLIENT
 | 
						|
         #ifdef E4ANALYZE
 | 
						|
            if ( c4trans->enabled != 0 )
 | 
						|
               return error4( 0, e4struct, E93836 ) ;
 | 
						|
         #endif
 | 
						|
      #endif
 | 
						|
   #endif
 | 
						|
 | 
						|
   memset( c4trans, 0, sizeof( c4trans ) ) ;
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( c4->debugInt != E4DEBUG_INT )   /* not initialized */
 | 
						|
         return error4( 0, e4struct, E81301 ) ;
 | 
						|
   #endif
 | 
						|
   c4trans->c4 = c4 ;
 | 
						|
 | 
						|
   #ifndef S4SERVER
 | 
						|
      rc = code4tranInitLow( &c4trans->trans, c4trans ) ;
 | 
						|
      if ( rc < 0 )
 | 
						|
         return rc ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      return code4transVerify( c4trans, 0 ) ;
 | 
						|
   #else
 | 
						|
      return 0 ;
 | 
						|
   #endif
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef S4CLIENT
 | 
						|
#ifdef S4SERVER
 | 
						|
/*
 | 
						|
int d4tagUniqueSync( DATA4 *data )
 | 
						|
{
 | 
						|
   TAG4 *tag ;
 | 
						|
 | 
						|
   #ifdef E4PARM_LOW
 | 
						|
      if ( data == 0 )
 | 
						|
         return error4( 0, e4parm_null, E96501 ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   for ( tag = 0 ;; )
 | 
						|
   {
 | 
						|
      tag = d4tagNext( data, tag ) ;
 | 
						|
      if ( tag == 0 )
 | 
						|
         break ;
 | 
						|
      tag->tagFile->uniqueError = tag->uniqueError ;
 | 
						|
   }
 | 
						|
 | 
						|
   return 0 ;
 | 
						|
}
 | 
						|
*/
 | 
						|
#endif /* S4SERVER */
 | 
						|
 | 
						|
#ifndef S4OFF_MULTI
 | 
						|
#ifndef S4OFF_TRAN
 | 
						|
/* ensure only one process is accessing the transaction file */
 | 
						|
int S4FUNCTION code4tranLockTransactions( CODE4TRANS *c4trans, long lockByte )
 | 
						|
{
 | 
						|
   int rc, oldAttempts ;
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( code4transVerify( c4trans, 1 ) < 0 )
 | 
						|
         return 0 ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   if ( lockByte < TRAN4LOCK_BASE )
 | 
						|
      return e4parm ;
 | 
						|
   if ( c4trans->transFile->fileLocks & ( 1UL << ( lockByte - TRAN4LOCK_BASE ) ) )
 | 
						|
      return 0 ;
 | 
						|
   oldAttempts = c4trans->c4->lockAttempts ;
 | 
						|
   c4trans->c4->lockAttempts = 1 ;
 | 
						|
   rc = file4lock( &c4trans->transFile->file, lockByte, 1L ) ;
 | 
						|
   c4trans->c4->lockAttempts = oldAttempts ;
 | 
						|
   if ( rc == 0 )
 | 
						|
      c4trans->transFile->fileLocks |= ( 1UL << ( lockByte - TRAN4LOCK_BASE ) ) ;
 | 
						|
   return rc ;
 | 
						|
}
 | 
						|
 | 
						|
#ifndef S4UTILS
 | 
						|
int S4FUNCTION code4tranUnlockTransactions( CODE4TRANS *c4trans, long lockByte )
 | 
						|
{
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( code4transVerify( c4trans, 1 ) < 0 )
 | 
						|
         return 0 ;
 | 
						|
   #endif
 | 
						|
   if ( lockByte < TRAN4LOCK_BASE )
 | 
						|
      return e4parm ;
 | 
						|
   if ( !(c4trans->transFile->fileLocks & ( 1UL << ( lockByte - TRAN4LOCK_BASE ) ) ) )
 | 
						|
      return e4unlock ;
 | 
						|
   return file4unlock( &c4trans->transFile->file, lockByte, 1L ) ;
 | 
						|
}
 | 
						|
#endif /* S4UTILS */
 | 
						|
#endif /* S4OFF_TRAN */
 | 
						|
 | 
						|
int tran4lock( TRAN4 *trans )
 | 
						|
{
 | 
						|
   LOCK4 *lock, *lockNext ;
 | 
						|
   LIST4 locked ;
 | 
						|
   int saveErr, rc, saveUnlockAuto ;
 | 
						|
   CODE4 *c4 ;
 | 
						|
 | 
						|
   #ifdef E4ANALYZE
 | 
						|
      if ( ( rc = tran4verify( trans, 1 ) ) < 0 )
 | 
						|
         return rc ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   c4 = trans->c4trans->c4 ;
 | 
						|
 | 
						|
   saveUnlockAuto = code4unlockAuto( c4 ) ;
 | 
						|
 | 
						|
   if ( saveUnlockAuto == 1 )
 | 
						|
   {
 | 
						|
      rc = code4unlockDo( tran4dataList( trans ) ) ;
 | 
						|
      if ( rc < 0 )
 | 
						|
         return error4stack( c4, rc, 0L ) ;
 | 
						|
   }
 | 
						|
 | 
						|
   code4unlockAutoSet( c4, 0 ) ;
 | 
						|
 | 
						|
   #ifndef S4CLIENT
 | 
						|
      memset( &locked, 0, sizeof( locked ) ) ;
 | 
						|
   #endif
 | 
						|
 | 
						|
   lock = (LOCK4 *)l4first( &trans->locks ) ;
 | 
						|
   for ( ;; )
 | 
						|
   {
 | 
						|
      if ( lock == 0 )
 | 
						|
      {
 | 
						|
         for ( ;; )
 | 
						|
         {
 | 
						|
            lock = (LOCK4 *)l4first( &locked ) ;
 | 
						|
            if ( lock == 0 )
 | 
						|
            {
 | 
						|
               code4unlockAutoSet( c4, saveUnlockAuto ) ;
 | 
						|
 | 
						|
               #ifdef S4CLIENT
 | 
						|
                  return saveRc ;
 | 
						|
               #else
 | 
						|
                  return 0 ;
 | 
						|
               #endif
 | 
						|
            }
 | 
						|
            lockNext = (LOCK4 *)l4next( &locked, lock ) ;
 | 
						|
            l4remove( &locked, lock ) ;
 | 
						|
            mem4free( c4->lockMemory, lock ) ;
 | 
						|
            lock = lockNext ;
 | 
						|
         }
 | 
						|
      }
 | 
						|
 | 
						|
      switch( lock4lock( lock ) )
 | 
						|
      {
 | 
						|
         case r4success:
 | 
						|
            lockNext = (LOCK4 *)l4next( &trans->locks, lock ) ;
 | 
						|
            l4remove( &trans->locks, lock ) ;
 | 
						|
            l4add( &locked, lock ) ;
 | 
						|
            lock = lockNext ;
 | 
						|
            break ;
 | 
						|
         case r4locked:
 | 
						|
            lock = (LOCK4 *)l4next( &trans->locks, lock ) ;
 | 
						|
            #ifdef S4SERVER
 | 
						|
               for ( ;; )
 | 
						|
               {
 | 
						|
                  lock = (LOCK4 *)l4first( &locked ) ;
 | 
						|
                  if ( lock == 0 )
 | 
						|
                     return r4locked ;
 | 
						|
                  l4remove( &locked, lock ) ;
 | 
						|
                  l4add( &trans->locks, lock ) ;
 | 
						|
                  lock4unlock( lock ) ;
 | 
						|
               }
 | 
						|
            #else
 | 
						|
               break ;
 | 
						|
            #endif
 | 
						|
         default:
 | 
						|
            saveErr = error4set( trans->c4trans->c4, 0 ) ;
 | 
						|
 | 
						|
            for ( ;; )
 | 
						|
            {
 | 
						|
               lock = (LOCK4 *)l4first( &locked ) ;
 | 
						|
               if ( lock == 0 )
 | 
						|
               {
 | 
						|
                  code4unlockAutoSet( c4, saveUnlockAuto ) ;
 | 
						|
                  error4set( trans->c4trans->c4, saveErr ) ;
 | 
						|
                  return -1 ;
 | 
						|
               }
 | 
						|
 | 
						|
               l4remove( &locked, lock ) ;
 | 
						|
               l4add( &trans->locks, lock ) ;
 | 
						|
               lock4unlock( lock ) ;
 | 
						|
            }
 | 
						|
      }
 | 
						|
   }
 | 
						|
}
 | 
						|
#endif  /* S4OFF_MULTI */
 | 
						|
#endif  /* S4SERVER */
 | 
						|
 | 
						|
#ifndef S4CLIENT
 | 
						|
static DATA4 *tran4dataFull( TRAN4 *trans, const long serverId, const long clientId )
 | 
						|
{
 | 
						|
   DATA4 *data ;
 | 
						|
   LIST4 *oldList ;
 | 
						|
 | 
						|
   data = tran4data( trans, serverId, clientId ) ;
 | 
						|
   if ( data != 0 )
 | 
						|
      return data ;
 | 
						|
 | 
						|
   oldList = tran4dataList( trans ) ;
 | 
						|
   tran4dataListSet( trans, &trans->closedDataFiles ) ;
 | 
						|
   data = tran4data( trans, serverId, clientId ) ;
 | 
						|
   tran4dataListSet( trans, oldList ) ;
 | 
						|
 | 
						|
   return data ;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef S4SERVER
 | 
						|
/* to get a DATA4 based on id instead of TRAN4 */
 | 
						|
DATA4 *code4idData( CODE4 *c4, const long serverId, const long clientId )
 | 
						|
{
 | 
						|
   SERVER4CLIENT *client ;
 | 
						|
   DATA4 *data ;
 | 
						|
 | 
						|
   for( client = 0 ;; )
 | 
						|
   {
 | 
						|
      client = (SERVER4CLIENT *)l4next( &c4->server->clients, client ) ;
 | 
						|
      if ( client == 0 )
 | 
						|
         break ;
 | 
						|
      data = tran4data( &client->trans, serverId, clientId ) ;
 | 
						|
      if ( data != 0 )
 | 
						|
         return data ;
 | 
						|
   }
 | 
						|
 | 
						|
   return 0 ;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef S4CLIENT
 | 
						|
#ifdef P4ARGS_USED
 | 
						|
   #pragma argsused
 | 
						|
#endif
 | 
						|
/* are there any active transactions which conflict with the data4? */
 | 
						|
int tran4active( CODE4 *c4, DATA4 *data )
 | 
						|
{
 | 
						|
   #ifndef S4OFF_TRAN
 | 
						|
      #ifndef S4STAND_ALONE
 | 
						|
         SERVER4CLIENT *client ;
 | 
						|
         DATA4 *dataLoop ;
 | 
						|
      #endif
 | 
						|
   #endif
 | 
						|
 | 
						|
   #ifndef S4OFF_TRAN
 | 
						|
      if ( code4transEnabled( c4 ) )
 | 
						|
         if ( code4trans( c4 )->currentTranStatus == r4active )
 | 
						|
            return e4transViolation ;
 | 
						|
 | 
						|
      #ifdef S4STAND_ALONE
 | 
						|
         if ( data->logVal == LOG4TRANS )   /* not logging this datafile, and not a transaction in progress... */
 | 
						|
            return 0 ;
 | 
						|
      #endif
 | 
						|
 | 
						|
      #ifdef S4SERVER
 | 
						|
         if ( data->accessMode != OPEN4DENY_NONE )  /* if denying others write access, then can proceed */
 | 
						|
            return 0 ;
 | 
						|
      #endif
 | 
						|
      #ifdef S4OFF_MULTI
 | 
						|
         return 0 ;
 | 
						|
      #else
 | 
						|
         #ifdef S4STAND_ALONE
 | 
						|
            if ( d4lockTestFile( data ) == 1 )
 | 
						|
               return 0 ;
 | 
						|
            if ( data->dataFile->file.lowAccessMode != OPEN4DENY_NONE )
 | 
						|
               return 0 ;
 | 
						|
            /* in stand-alone, can't check active transactions, so just deny */
 | 
						|
            return error4( c4, e4transViolation, E81504 ) ;
 | 
						|
         #else
 | 
						|
            if ( dfile4lockTestFile( data->dataFile, data4clientId( data ), data4serverId( data ) ) == 1 )
 | 
						|
               return 0 ;
 | 
						|
            /* if file not ultimately opened exclusively, may be problems */
 | 
						|
            if ( data->dataFile->file.lowAccessMode == OPEN4DENY_NONE )
 | 
						|
               return error4( c4, e4transViolation, E81504 ) ;
 | 
						|
            for ( client = 0 ;; )
 | 
						|
            {
 | 
						|
               client = (SERVER4CLIENT *)l4next( &c4->server->clients, client ) ;
 | 
						|
               if ( client == 0 )
 | 
						|
                  break ;
 | 
						|
               if ( client->trans.c4trans->enabled )
 | 
						|
                  if ( client->trans.currentTranStatus == r4active )
 | 
						|
                  {
 | 
						|
                     /* check if that user has a data4 using the same datafile */
 | 
						|
                     for( dataLoop = 0 ;; )
 | 
						|
                     {
 | 
						|
                        dataLoop = (DATA4 *)l4next( client->trans.dataList, dataLoop ) ;
 | 
						|
                        if ( dataLoop == 0 )
 | 
						|
                           break ;
 | 
						|
                        if ( dataLoop->readOnly == 0 )
 | 
						|
                           if ( dataLoop->dataFile == data->dataFile )
 | 
						|
                              return error4( c4, e4transViolation, E81504 ) ;
 | 
						|
                     }
 | 
						|
                  }
 | 
						|
            }
 | 
						|
            return 0 ;
 | 
						|
         #endif
 | 
						|
      #endif
 | 
						|
   #else
 | 
						|
      return 0 ;
 | 
						|
   #endif  /* S4OFF_TRAN */
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef P4ARGS_USED
 | 
						|
   #pragma argsused
 | 
						|
#endif
 | 
						|
void S4FUNCTION code4lockClear( CODE4 *c4 )
 | 
						|
{
 | 
						|
   #ifndef S4OFF_MULTI
 | 
						|
      LOCK4 *lock ;
 | 
						|
      TRAN4 *trans ;
 | 
						|
 | 
						|
      #ifdef E4PARM_HIGH
 | 
						|
         if ( c4 == 0 )
 | 
						|
         {
 | 
						|
            error4( 0, e4parm_null, E91018 ) ;
 | 
						|
            return ;
 | 
						|
         }
 | 
						|
      #endif
 | 
						|
 | 
						|
      #ifdef S4SERVER
 | 
						|
         trans = &c4->currentClient->trans ;
 | 
						|
      #else
 | 
						|
         trans = &c4->c4trans.trans ;
 | 
						|
      #endif
 | 
						|
 | 
						|
      for ( ;; )
 | 
						|
      {
 | 
						|
         lock = (LOCK4 *)l4first( &trans->locks ) ;
 | 
						|
         if ( lock == 0 )
 | 
						|
            break ;
 | 
						|
         l4remove( &trans->locks, lock ) ;
 | 
						|
         mem4free( c4->lockMemory, lock ) ;
 | 
						|
      }
 | 
						|
   #endif /* S4OFF_MULTI */
 | 
						|
   return ;
 | 
						|
}
 |