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 ;
 | |
| }
 |