/* d4open.c (c)Copyright Sequiter Software Inc., 1988-1996. All rights reserved. */ #include "d4all.h" #ifdef __TURBOC__ #pragma hdrstop #endif #ifdef S4OFF_MEMO extern char f4memoNullChar ; #endif /* */ #ifdef S4UNIX #include #else #include "sys\stat.h" #endif /* */ static DATA4FILE *data4reopen( DATA4FILE *, char ** ) ; static DATA4 *d4openInit( CODE4 *c4 ) { DATA4 *d4 ; #ifdef S4STAND_ALONE #ifndef S4OFF_TRAN int rc; #endif #endif #ifdef S4VBASIC if ( c4parm_check( c4, 1, E94301 ) ) return 0 ; #endif if ( error4code( c4 ) < 0 ) return 0 ; #ifdef E4ANALYZE if ( c4->debugInt != 0x5281 ) { error4( 0, e4result, E81301 ) ; return 0 ; } #endif #ifdef S4STAND_ALONE #ifndef S4OFF_TRAN if ( c4->logOpen ) { rc = code4logOpen( c4, 0, 0 ) ; if ( rc < 0 ) return 0 ; else error4set( c4, 0 ) ; /* remove r4open if it already existed */ } #endif #endif #ifndef S4CLIENT #ifdef E4ANALYZE #ifndef S4STAND_ALONE if ( c4->currentClient == 0 ) { error4( c4, e4struct, E94301 ) ; return 0 ; } if ( c4->currentClient->trans.c4trans == 0 ) { error4( c4, e4struct, E94301 ) ; return 0 ; } #endif #endif #endif if ( c4->dataMemory == 0 ) { c4->dataMemory = mem4create( c4, c4->memStartData, sizeof(DATA4), c4->memExpandData, 0 ) ; if ( c4->dataMemory == 0 ) { #ifdef E4STACK error4stack( c4, e4memory, E94301 ) ; #endif return 0 ; } } d4 = (DATA4 *)mem4alloc( c4->dataMemory ) ; if ( d4 == 0 ) { #ifdef E4STACK error4stack( c4, e4memory, E94301 ) ; #endif return 0 ; } #ifdef S4VBASIC d4->debugInt = E4DEBUG_INT ; #endif d4->codeBase = c4 ; #ifdef S4SERVER d4->clientId = 1L ; /* should get overridden at a later point, unless this is a server-only data file */ d4->serverId = c4->server->serverDataCount ; c4->server->serverDataCount++ ; d4->trans = &c4->currentClient->trans ; l4add( tran4dataList( d4->trans ), d4 ) ; #else d4->trans = &c4->c4trans.trans ; l4add( tran4dataList( (&(c4->c4trans.trans)) ), d4 ) ; #endif return d4 ; } static int d4openConclude( DATA4 *d4, const char *name, char *info ) { CODE4 *c4 ; int iFields, fieldType ; unsigned int recOffset ; long recWidth ; #ifdef S4CLIENT_OR_FOX int nullCount ; #endif char fieldBuf[2] ; FIELD4IMAGE *image ; #ifndef S4CLIENT #ifdef S4CLIPPER #ifndef S4OFF_INDEX char nameBuf[258] ; #else #ifndef S4OFF_TRAN #ifndef S4OFF_WRITE char nameBuf[258] ; #endif #endif #endif #else #ifndef S4OFF_TRAN #ifndef S4OFF_WRITE char nameBuf[258] ; #endif #endif #endif #ifndef S4OFF_WRITE #ifndef S4OFF_TRAN TRAN4 *trans ; int tranCode ; /* */ struct stat bufStat ; /* */ /* */ /* */ /* */ long connectionId, rcl ; short rc ; #endif #endif #ifndef S4OFF_INDEX INDEX4 *i4 ; #ifndef S4SERVER #ifndef S4CLIPPER int oldSingleOpen ; #endif #endif #endif #else #ifndef S4OFF_INDEX char nameBuf[258] ; #endif #endif #ifndef S4OFF_MEMO int i_memo ; #endif c4 = d4->codeBase ; #ifdef E4ANALYZE if ( d4->dataFile->nFields == 0 ) return error4describe( c4, e4struct, E94301, name, 0, 0 ) ; #endif u4namePiece( d4->alias, sizeof( d4->alias ), name, 0, 0 ) ; d4->alias[ sizeof( d4->alias ) - 1 ] = 0 ; recWidth = dfile4recWidth( d4->dataFile ) ; if ( ( ( recWidth + 50L + 1L ) * 2L + (long)sizeof( FIELD4 ) * (long)d4->dataFile->nFields ) > (long)UINT_MAX ) /* try allocating records and fields together, 50 bytes for overhead */ { d4->groupRecordAlloc = (char *)u4allocFree( c4, (recWidth + 1L) * 2L + (long)sizeof( FIELD4 ) * (long)d4->dataFile->nFields ) ; if ( d4->groupRecordAlloc != 0 ) { d4->record = d4->groupRecordAlloc ; d4->recordOld = d4->groupRecordAlloc + recWidth + 1 ; d4->fields = (FIELD4 *)(d4->groupRecordAlloc + 2 * ( recWidth + 1 ) ) ; } } if ( d4->groupRecordAlloc == 0 ) { d4->record = (char *)u4allocFree( c4, recWidth + 1 ) ; d4->recordOld = (char *)u4allocFree( c4, recWidth + 1 ) ; d4->fields = (FIELD4 *)u4allocFree( c4, sizeof( FIELD4 ) * (long)d4->dataFile->nFields ) ; } if ( d4->record == 0 || d4->recordOld == 0 || d4->fields == 0 ) return error4stack( c4, e4memory, E94301 ) ; recOffset = 1 ; #ifdef S4CLIENT_OR_FOX nullCount = 0 ; #endif if ( !( error4code( c4 ) < 0 ) ) for ( iFields = 0 ; iFields < d4->dataFile->nFields ; iFields++ ) { image = (FIELD4IMAGE *)( info + iFields * 32 ) ; u4ncpy( d4->fields[iFields].name, image->name, sizeof( d4->fields->name ) ) ; u4ncpy( fieldBuf, &image->type, 2 ) ; c4upper( fieldBuf ) ; d4->fields[iFields].type = *fieldBuf ; fieldType = d4->fields[iFields].type ; #ifdef S4CLIENT_OR_FOX if ( d4version( d4 ) == 0x30 ) /* FOX 3.0 */ { d4->fields[iFields].null = ( image->nullBinary & 0x02 ) ? 1 : 0 ; if ( d4->fields[iFields].null == 1 ) { d4->fields[iFields].nullBit = nullCount ; nullCount++ ; } if ( image->nullBinary & 0x04 ) d4->fields[iFields].binary = 1 ; else { if ( fieldType == r4memo || fieldType == r4gen ) /* memo fields are also stored binary */ d4->fields[iFields].binary = 2 ; else d4->fields[iFields].binary = 0 ; } } #endif switch( fieldType ) { #ifdef S4CLIENT_OR_FOX case r4int: #endif case r4log: case r4date: d4->fields[iFields].len = image->len ; break ; case r4double: /* same as r4bin */ if ( d4version( d4 ) == 0x30 ) /* double */ { d4->fields[iFields].len = image->len ; d4->fields[iFields].dec = image->dec ; } else /* binary */ d4->fields[iFields].len = image->len ; break ; case r4num: case r4float: #ifdef S4CLIENT_OR_FOX case r4currency: case r4dateTime: #endif d4->fields[iFields].len = image->len ; d4->fields[iFields].dec = image->dec ; break ; case r4memo: case r4gen: /* #ifdef S4OFF_MEMO */ /* d4->fields[iFields].memo = (F4MEMO *)&f4memoNullChar ; */ /* #endif */ d4->fields[iFields].len = image->len ; break ; default: d4->fields[iFields].len = image->len + ( image->dec << 8 ) ; break ; } #ifdef S4VBASIC d4->fields[iFields].debugInt = E4DEBUG_INT ; #endif d4->fields[iFields].offset = recOffset ; recOffset += d4->fields[iFields].len ; d4->fields[iFields].data = d4 ; } #ifndef S4OFF_MEMO if ( d4->dataFile->nFieldsMemo > 0 && !( error4code( c4 ) < 0 ) ) { i_memo = 0 ; d4->fieldsMemo = (F4MEMO *)u4allocFree( c4, (long)sizeof(F4MEMO) * d4->dataFile->nFieldsMemo ) ; #ifdef E4STACK if ( d4->fieldsMemo == 0 ) error4stack( c4, e4memory, E94301 ) ; #endif if ( d4->fieldsMemo != 0 ) for ( iFields = 0 ; iFields < d4->dataFile->nFields ; iFields++ ) { fieldType = d4->fields[iFields].type ; if ( fieldType == r4memo || fieldType == r4gen || ( fieldType == r4bin && d4version( d4 ) != 0x30 ) ) { d4->fields[iFields].memo = d4->fieldsMemo+i_memo ; d4->fieldsMemo[i_memo].status = 1 ; d4->fieldsMemo[i_memo].field = d4->fields+iFields ; i_memo++ ; } } } #endif if ( error4code( c4 ) < 0 ) return -1 ; d4->recNum = d4->recNumOld = -1 ; d4blank( d4 ) ; memcpy( d4->recordOld, d4->record, (unsigned)recWidth ) ; d4->recordChanged = 0 ; d4->record[recWidth] = 0 ; d4->recordOld[recWidth] = 0 ; #ifndef S4OFF_INDEX #ifdef S4CLIENT /* client will get all the index tags if autoOpen set to 1, else will get none -- this is an undocumented side-effect */ if ( d4->dataFile->indexes.nLink > 0 && c4->autoOpen == 1 ) { u4namePiece( nameBuf, sizeof( nameBuf ), name, 0, 0 ) ; if ( i4setup( c4, d4, nameBuf, 1, 0 ) < 0 ) return -1 ; } #else #ifdef S4CLIPPER if ( c4->autoOpen ) { if ( d4->dataFile->userCount > 1 ) /* already open, just set up tags */ { u4namePiece( nameBuf, sizeof( nameBuf ), name, 0, 0 ) ; if ( i4setup( c4, d4, nameBuf, 1 ) < 0 ) return -1 ; } else { #ifdef S4SERVER /* if a temp file, tags already available... */ if ( d4->dataFile->file.isTemp == 1 ) { if ( i4setup( c4, d4, nameBuf, 1 ) < 0 ) return -1 ; } #endif i4 = i4open( d4, 0 ) ; #ifdef S4SERVER if ( i4 == 0 ) /* server version, if no .cgp file then don't open index */ error4set( c4, 0 ) ; #else if ( i4 == 0 ) return -1 ; #endif } } #else #ifdef S4STAND_ALONE d4->dataFile->openMdx = 0 ; #endif if ( ( d4->dataFile->hasMdxMemo & 0x01 ) && c4->autoOpen ) { #ifndef S4SERVER oldSingleOpen = c4->singleOpen ; c4->singleOpen = OPEN4SPECIAL ; #endif i4 = i4open( d4, 0 ) ; #ifndef S4SERVER c4->singleOpen = oldSingleOpen ; #endif if ( i4 == 0 ) return -1 ; #ifdef S4MDX if ( !i4->indexFile->header.isProduction ) i4close( i4 ) ; #endif #ifdef S4STAND_ALONE d4->dataFile->openMdx = 1 ; #endif } #endif #endif /* S4CLIENT */ #endif /* S4OFF_INDEX */ #ifndef S4SERVER c4->clientDataCount++ ; d4->clientId = c4->clientDataCount ; #endif #ifndef S4OFF_WRITE #ifndef S4OFF_TRAN #ifndef S4CLIENT if ( code4transEnabled( c4 ) ) { trans = code4trans( c4 ) ; #ifdef S4STAND_ALONE connectionId = 0L ; #else connectionId = connection4id( c4->currentClient->connection ) ; #endif rc = u4nameCurrent( nameBuf, sizeof( nameBuf ), dfile4name( d4->dataFile ) ) ; if ( rc < 0 ) return error4stack( c4, rc, E94301 ) ; #ifdef S4CASE_SEN rc = u4nameExt( nameBuf, sizeof( nameBuf ), "dbf", 0 ) ; #else rc = u4nameExt( nameBuf, sizeof( nameBuf ), "DBF", 0 ) ; #endif if ( rc < 0 ) return error4stack( c4, rc, E94301 ) ; rc = strlen(nameBuf) ; if (c4->createTemp == 1) tranCode = TRAN4OPEN_TEMP ; else tranCode = TRAN4OPEN ; if ( tran4set( trans, trans->currentTranStatus, -1L, connectionId, tranCode, (unsigned)rc + 19, data4clientId( d4 ), data4serverId( d4 ) ) == 0 ) { tran4putData( trans, &rc, 2 ) ; tran4putData( trans, nameBuf, (unsigned)rc ) ; rcl = recWidth ; tran4putData( trans, &rcl, 4 ) ; rc = d4numFields( d4 ) ; tran4putData( trans, &rc, 2 ) ; rcl = d4recCount( d4 ) ; tran4putData( trans, &rcl, 4 ) ; /* */ if ( stat( nameBuf, &bufStat ) != 0 ) return -1 ; tran4putData( trans, &bufStat.st_atime, 4 ) ; /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ tran4putData( trans, &d4->dataFile->yy, 3 ) ; tran4lowAppend( trans, 0 ) ; } else return -1 ; } #endif /* S4CLIENT */ #endif /* S4OFF_TRAN */ #endif /* S4OFF_WRITE */ #ifdef S4SERVER d4->accessMode = c4->singleClient ; if ( d4->accessMode == OPEN4DENY_RW ) d4->dataFile->exclusiveOpen = d4 ; #endif #ifndef S4CLIENT d4->readOnly = c4->readOnly ; #endif #ifndef S4OFF_TRAN #ifndef S4CLIENT if ( code4transEnabled( d4->codeBase ) == 1 ) d4->logVal = c4->log ; #endif #endif return 0 ; } DATA4 *S4FUNCTION d4open( CODE4 *c4, const char *name ) { int rc ; char *info ; DATA4 *d4 ; #ifdef E4PARM_HIGH if ( c4 == 0 || name == 0 ) { error4( 0, e4parm_null, E94301 ) ; return 0 ; } #endif d4 = d4openInit( c4 ) ; if ( d4 != 0 ) { d4->dataFile = dfile4open( c4, d4, name, &info ) ; if ( d4->dataFile == 0 ) { d4close( d4 ) ; return 0 ; } rc = d4openConclude( d4, name, info ) ; if ( rc < 0 ) { d4close( d4 ) ; return 0 ; } } return d4 ; } DATA4 *S4FUNCTION d4openClone( DATA4 *dataOld ) { DATA4 *d4 ; int rc ; char *info ; #ifndef S4SERVER int oldSingleOpen ; #endif #ifdef E4PARM_HIGH if ( dataOld == 0 ) { error4( 0, e4parm_null, E94301 ) ; return 0 ; } #endif d4 = d4openInit( dataOld->codeBase ) ; if ( d4 == 0 ) return 0 ; #ifndef S4SERVER oldSingleOpen = dataOld->codeBase->singleOpen ; dataOld->codeBase->singleOpen = OPEN4DENY_NONE ; #endif d4->dataFile = data4reopen( dataOld->dataFile, &info ) ; if ( d4->dataFile == 0 ) { #ifndef S4SERVER dataOld->codeBase->singleOpen = oldSingleOpen ; #endif d4close( d4 ) ; return 0 ; } rc = d4openConclude( d4, dfile4name( d4->dataFile ), info ) ; #ifndef S4SERVER dataOld->codeBase->singleOpen = oldSingleOpen ; #endif if ( rc < 0 ) { d4close( d4 ) ; return 0 ; } return d4 ; } #ifndef S4OFF_INDEX #ifdef S4CLIENT int client4indexSetup( CODE4 *c4, DATA4 *d4, DATA4FILE *data, unsigned int numTags, const char *info, unsigned int iLen, const char *indexAlias, INDEX4 *i4ndx ) { unsigned int i ; TAG4FILE *tag, *first ; INDEX4FILE *i4file ; long infoLen ; DATA4FILE *oldDataFile ; int doTags ; #ifdef E4PARM_LOW if ( c4 == 0 || d4 == 0 || data == 0 || info == 0 ) return error4( c4, e4parm_null, E94302 ) ; #endif infoLen = iLen ; if ( numTags == 0 ) return 0 ; if ( c4->index4fileMemory == 0 ) { c4->index4fileMemory = mem4create( c4, c4->memStartIndexFile, sizeof(INDEX4FILE), c4->memExpandIndexFile, 0 ) ; if ( c4->index4fileMemory == 0 ) return e4memory ; } if ( c4->tagFileMemory == 0 ) { c4->tagFileMemory = mem4create( c4, c4->memStartTagFile, sizeof(TAG4FILE), c4->memExpandTagFile, 0 ) ; if ( c4->tagFileMemory == 0 ) return e4memory ; } oldDataFile = d4->dataFile ; ; d4->dataFile = data ; /* passing non-null into index4open will ensure that an actual open does not occur, but simply a check will occur ... */ if ( i4ndx != 0 ) i4file = i4ndx->indexFile ; else i4file = index4open( d4, indexAlias, (INDEX4 *)1 ) ; if ( i4file == 0 ) { i4file = (INDEX4FILE *)mem4alloc( c4->index4fileMemory ) ; if ( i4file == 0 ) { d4->dataFile = oldDataFile ; return error4stack( c4, e4memory, E94302 ) ; } i4file->codeBase = c4 ; i4file->autoOpened = 1 ; i4file->dataFile = data ; i4file->clientId = data4clientId( d4 ) ; i4file->serverId = data4serverId( d4 ) ; d4->dataFile = oldDataFile ; #ifdef E4MISC if ( strlen( indexAlias ) > sizeof( i4file->accessName ) ) return error4describe( c4, e4name, E91102, indexAlias, 0, 0 ) ; #endif strcpy( i4file->accessName, indexAlias ) ; c4upper( i4file->accessName ) ; l4add( &data->indexes, i4file ) ; doTags = 1 ; } else doTags = 0 ; /* only execute next if i4file was not blank and i4ndx was blank */ if ( i4ndx != 0 || doTags == 1 ) /* new index file, or add to existing */ { for ( i = 0 ; i < numTags ; i++ ) { tag = (TAG4FILE *)mem4alloc( c4->tagFileMemory ) ; if ( tag == 0 ) return e4memory ; infoLen -= LEN4TAG_ALIAS ; if ( infoLen < 0 ) return e4connection ; memcpy( tag->alias, info, LEN4TAG_ALIAS ) ; tag->indexFile = i4file ; info += LEN4TAG_ALIAS ; tag->errUniqueHold = *(int *)info ; info += sizeof( short int ) ; first = (TAG4FILE *)l4first( &i4file->tags ) ; if ( first == 0 ) l4add( &i4file->tags, tag ) ; else l4addBefore( &i4file->tags, first, tag ) ; } } else d4->dataFile = oldDataFile ; return 0 ; } #endif /* S4CLIENT */ #endif /* not S4OFF_INDEX */ #ifdef S4SERVER /* what is the maximal read and access setting on the data file */ /* does not report results for current client */ static void dfile4accesses( DATA4FILE *d4, int *readMode, int *accessMode, int *otherUsers ) { SERVER4CLIENT *client ; DATA4 *data ; *readMode = 1 ; *accessMode = OPEN4DENY_NONE ; *otherUsers = 0 ; for ( client = 0 ;; ) { client = (SERVER4CLIENT *)l4next( &d4->c4->server->clients, client ) ; if ( client == 0 ) break ; if ( client == d4->c4->currentClient ) continue ; for ( data = 0 ;; ) { data = (DATA4 *)l4next( tran4dataList( &client->trans ), data ) ; if ( data == 0 ) break ; if ( data->dataFile == d4 ) { *otherUsers = 1 ; if ( data->readOnly == 0 ) *readMode = 0 ; if ( *accessMode != OPEN4DENY_RW) if ( data->accessMode != *accessMode ) if ( data->accessMode != OPEN4DENY_NONE ) *accessMode = data->accessMode ; if ( *readMode == 0 && *accessMode == OPEN4DENY_RW ) /* maximal already */ return ; } } } return ; } /* returns 1 if file can be accessed in desired mode */ static int dfile4checkAccess( DATA4FILE *d4, int accessRequested, int readOnly ) { int maxAccess, maxRead, otherUsers ; if ( d4->userCount == 0 ) return 1 ; /* first get maximal access and read modes of other users */ dfile4accesses( d4, &maxRead, &maxAccess, &otherUsers ) ; if ( otherUsers == 0 ) /* no other users, so any requests are ok */ return 1 ; if ( accessRequested == OPEN4DENY_RW ) /* others users accessing, so no */ return 0 ; if ( maxAccess == OPEN4DENY_RW ) /* other user is disallowing our access */ return 0 ; if ( readOnly == 0 ) /* need write access */ { if ( maxAccess != OPEN4DENY_NONE ) return 0 ; /* maxAccess is DENY_NONE, so continue */ switch( accessRequested ) { case OPEN4DENY_NONE: return 1 ; case OPEN4DENY_WRITE: if ( maxRead == 1 ) /* others only reading, so ok */ return 1 ; /* fall through, and any other case, access denied */ default: return 0 ; } } /* is readOnly, so deny_write allowable by others */ switch( maxAccess ) { case OPEN4DENY_RW: return 0 ; case OPEN4DENY_WRITE: switch ( accessRequested ) { case OPEN4DENY_NONE: return 1 ; case OPEN4DENY_WRITE: if ( maxRead == 1 ) return 1 ; /* fall through or default, no access */ default: return 0 ; } default: break ; } return 1 ; } #endif /* S4SERVER */ static DATA4FILE *data4reopen( DATA4FILE *d4, char **info ) { #ifndef S4CLIENT #ifndef S4OFF_MULTI int rc ; #ifndef S4OFF_INDEX #ifdef S4CLIPPER TAG4FILE *t4file ; #else INDEX4FILE *i4file ; #ifdef E4ANALYZE #ifndef S4CLIPPER unsigned short int nCheck ; #endif #endif #endif #endif #endif #endif #ifndef S4SERVER #ifndef S4OFF_TRAN DATA4 *data4 ; LIST4 *list ; #endif #endif CODE4 *c4 ; if ( d4 == 0 ) return 0 ; c4 = d4->c4 ; #ifndef S4CLIENT if ( d4->userCount == 0 ) { #ifndef S4OFF_MULTI if ( d4->file.lowAccessMode != c4->accessMode ) /* need to open in updated mode */ { rc = dfile4closeLow( d4 ) ; if ( rc != 0 ) return 0 ; #ifndef S4OFF_INDEX #ifdef S4CLIPPER for ( t4file = 0 ;; ) { t4file = (TAG4FILE *)l4next( &d4->tagfiles, t4file ) ; if ( t4file == 0 ) break ; rc = tfile4close( t4file, d4 ) ; if ( rc < 0 ) return 0 ; } #else if ( d4->indexes.nLink != ((unsigned int)d4->hasMdxMemo & 0x01 ) ) { for ( i4file = 0 ;; ) { i4file = (INDEX4FILE *)l4next( &d4->indexes, i4file ) ; if ( i4file == 0 ) break ; if ( index4isProduction( i4file ) == 1 ) continue ; #ifdef E4ANALYZE nCheck = d4->indexes.nLink ; #endif rc = index4close( i4file ) ; #ifdef E4ANALYZE if ( nCheck != d4->indexes.nLink + 1 ) { error4describe( c4, e4result, E91102, dfile4name( d4 ), 0, 0 ) ; return 0 ; } #endif if ( rc < 0 ) return 0 ; } } #endif /* S4CLIPPER */ #endif /* S4OFF_INDEX */ d4 = 0 ; } #endif /* S4OFF_MULTI */ } else { #endif /* S4CLIENT */ #ifndef S4SERVER if ( c4->singleOpen != OPEN4DENY_NONE ) /* only one instance allowed... */ { #ifndef S4SERVER #ifndef S4OFF_TRAN /* verify that data4 not on the closed data list if within a transaction (which is allowed) */ if ( code4tranStatus( c4 ) == r4active ) { list = tran4dataList( code4trans( c4 ) ) ; for ( data4 = 0 ;; ) { data4 = (DATA4 *)l4next( list, data4 ) ; if ( data4 == 0 ) break ; if ( data4->dataFile == d4 ) { error4describe( c4, e4instance, E91102, dfile4name( d4 ), 0, 0 ) ; return 0 ; } } #ifdef E4ANALYZE /* ensure that the datafile exists somewhere! */ list = &( code4trans( c4 )->closedDataFiles ) ; for ( data4 = 0 ;; ) { data4 = (DATA4 *)l4next( list, data4 ) ; if ( data4 == 0 ) { error4describe( c4, e4struct, E91102, dfile4name( d4 ), 0, 0 ) ; return 0 ; } if ( data4->dataFile == d4 ) break ; } #endif } else #endif /* S4OFF_TRAN */ #endif /* S4STAND_ALONE */ { error4describe( c4, e4instance, E91102, dfile4name( d4 ), 0, 0 ) ; return 0 ; } } #endif #ifdef E4ANALYZE if ( d4->info == 0 ) { error4describe( c4, e4struct, E91102, dfile4name( d4 ), 0, 0 ) ; return 0 ; } #endif /* verify that the desired access level is available in terms of the actual physical open */ #ifndef S4OFF_MULTI switch( c4->accessMode ) { case OPEN4DENY_NONE: break ; case OPEN4DENY_RW: #ifdef S4CLIENT if ( d4->accessMode != OPEN4DENY_RW ) #else if ( d4->file.lowAccessMode != OPEN4DENY_RW ) #endif { error4describe( c4, e4access, E84307, dfile4name( d4 ), 0, 0 ) ; return 0 ; } break ; case OPEN4DENY_WRITE: #ifdef S4CLIENT if ( d4->accessMode == OPEN4DENY_NONE ) #else if ( d4->file.lowAccessMode == OPEN4DENY_NONE ) #endif { error4describe( c4, e4access, E84307, dfile4name( d4 ), 0, 0 ) ; return 0 ; } break ; default: { error4describe( c4, e4access, E82502, dfile4name( d4 ), 0, 0 ) ; return 0 ; } } #endif /* S4OFF_MULTI */ #ifdef S4SERVER /* singleClient is the client's requested access mode */ if ( d4 != 0 ) if ( dfile4checkAccess( d4, c4->singleClient, c4->readOnly ) == 0 ) /* access denied */ { error4describe( c4, e4access, E91102, dfile4name( d4 ), 0, 0 ) ; return 0 ; } #endif #ifndef S4CLIENT } #endif if ( d4 != 0 ) { d4->userCount++ ; *info = d4->info ; #ifdef E4ANALYZE if ( d4->nFields == 0 ) { error4describe( c4, e4struct, E91102, dfile4name( d4 ), 0, 0 ) ; return 0 ; } #endif return d4 ; } return 0 ; } #ifdef P4ARGS_USED #pragma argsused #endif DATA4FILE *dfile4open( CODE4 *c4, DATA4 *data, const char *name, char **info ) { int rc ; DATA4FILE *d4 ; unsigned int count ; int iFields ; FIELD4IMAGE *image ; #ifdef S4CLIENT SOCKET4 *socket ; CONNECTION4 *connection ; int len2, len3 ; CONNECTION4OPEN_INFO_IN dataIn ; CONNECTION4OPEN_INFO_OUT *dataInfo ; #ifndef S4OFF_INDEX char indexName[258] ; #endif #else char nameBuf[258] ; DATA4HEADER_FULL fullHeader ; unsigned fieldDataLen ; #ifndef S4OFF_MEMO int hasMemo ; #endif #ifndef S4OFF_CATALOG int i ; #endif #endif #ifdef S4VBASIC if ( c4parm_check( c4, 1, E91102 ) ) return 0 ; #endif #ifdef E4PARM_LOW if ( c4 == 0 || name == 0 ) { error4( c4, e4parm_null, E91102 ) ; return 0 ; } #ifdef S4CLIENT if ( data == 0 ) { error4( c4, e4parm_null, E91102 ) ; return 0 ; } #endif #endif if ( error4code( c4 ) < 0 ) return 0 ; #ifdef E4ANALYZE if ( c4->debugInt != 0x5281 ) { error4( 0, e4result, E81301 ) ; return 0 ; } #endif #ifdef S4CLIENT d4 = dfile4data( c4, name ) ; #else u4nameCurrent( nameBuf, sizeof( nameBuf ), name ) ; u4nameExt( nameBuf, sizeof(nameBuf), "dbf", 0 ) ; #ifndef S4CASE_SEN /* preserve the case sensitivity for unix */ c4upper( nameBuf ) ; #endif d4 = dfile4data( c4, nameBuf ) ; #endif if ( d4 != 0 ) { d4 = data4reopen( d4, info ) ; if ( error4code( c4 ) < 0 ) return 0 ; if ( d4 != 0 ) return d4 ; } #ifdef S4CLIENT #ifdef E4MISC if ( strlen( name ) > LEN4PATH ) { error4describe( c4, e4name, E84301, name, 0, 0 ) ; return 0 ; } #endif if ( c4->defaultServer == 0 ) { rc = code4connect( c4, 0, DEF4PROCESS_ID, 0, 0, 0 ) ; if ( rc == 0 ) { if ( c4->defaultServer == 0 ) { error4describe( c4, e4connection, E84302, DEF4SERVER_ID, DEF4PROCESS_ID, 0 ) ; return 0 ; } rc = code4dateFormatSet( c4, code4dateFormat( c4 ) ) ; } if ( rc != 0 ) { if ( c4->defaultServer != 0 ) { socket4initUndo( c4->defaultServer ) ; socket4free( c4->defaultServer ) ; c4->defaultServer = 0 ; } error4describe( c4, e4connection, E81001, DEF4SERVER_ID, DEF4PROCESS_ID, 0 ) ; return 0 ; } } socket = c4->defaultServer ; memset( &dataIn, 0, sizeof( CONNECTION4OPEN_INFO_IN ) ) ; if ( socket == 0 ) { error4( c4, e4connection, E84303 ) ; return 0 ; } connection = socket->connect ; if ( connection == 0 ) { error4( c4, e4connection, E84303 ) ; return 0 ; } connection4assign( connection, CON4OPEN, data->trans->dataIdCount,0 ) ; data->trans->dataIdCount++ ; len3 = strlen( name ) + 1 ; if ( len3 > LEN4PATH ) len3 = LEN4PATH ; memcpy( dataIn.name, name, len3 ) ; dataIn.name[LEN4PATH] = 0 ; #ifdef S4OFF_MULTI dataIn.exclusiveClient = 1 ; #else dataIn.accessMode = c4->accessMode ; #endif dataIn.readOnly = c4->readOnly ; dataIn.safety = c4->safety ; /* for catalog */ dataIn.errDefaultUnique = c4->errDefaultUnique ; dataIn.openForCreate = c4->openForCreate ; dataIn.singleOpen = c4->singleOpen ; dataIn.log = c4->log ; connection4addData( connection, &dataIn, sizeof( CONNECTION4OPEN_INFO_IN ), 0 ) ; connection4send( connection ) ; rc = connection4receive( connection ) ; if ( rc < 0 ) { error4( c4, rc, E91102 ) ; return 0 ; } if ( connection4type( connection ) != CON4OPEN ) { error4( c4, e4connection, E84304 ) ; return 0 ; } rc = connection4status( connection ) ; if ( rc < 0 ) { if ( c4->errOpen == 0 ) error4set( c4, r4noOpen ) ; else connection4errorDescribe( connection, c4, rc, E91102, name, 0, 0 ) ; return 0 ; } if ( connection4len( connection ) < sizeof( CONNECTION4OPEN_INFO_OUT ) ) { error4( c4, e4connection, E84305 ) ; return 0 ; } dataInfo = (CONNECTION4OPEN_INFO_OUT *)connection4data( connection ) ; #endif /* S4CLIENT */ if ( c4->data4fileMemory == 0 ) { c4->data4fileMemory = mem4create( c4, c4->memStartDataFile, sizeof(DATA4FILE), c4->memExpandDataFile, 0 ) ; if ( c4->data4fileMemory == 0 ) { error4( c4, e4memory, E91102 ) ; return 0 ; } } d4 = (DATA4FILE *)mem4alloc( c4->data4fileMemory ) ; if ( d4 == 0 ) { error4( c4, e4memory, E91102 ) ; return 0 ; } d4->c4 = c4 ; d4->userCount = 1 ; #ifndef S4CLIENT #ifndef S4OFF_MEMO d4->memoFile.file.hand = -1 ; #endif #ifdef S4SERVER #ifndef S4OFF_CATALOG if ( cat4avail( c4->catalog ) ) { u4ncpy( nameBuf, cat4pathName( c4->catalog ), (unsigned int)cat4pathNameLen( c4->catalog ) ) ; for ( i = 0 ; i < cat4pathNameLen( c4->catalog ) ; i++ ) if ( nameBuf[i] == ' ' ) { nameBuf[i] = 0 ; break ; } } #endif /* S4OFF_CATALOG */ #endif /* S4SERVER */ rc = file4open( &d4->file, c4, nameBuf, 1 ) ; if ( rc ) { dfile4close( d4 ) ; return 0 ; } #endif l4add( &c4->dataFileList, &d4->link ) ; #ifdef S4CLIENT #ifdef E4MISC if ( strlen( name ) > sizeof( d4->accessName ) ) { error4describe( c4, e4name, E91102, name, 0, 0 ) ; dfile4close( d4 ) ; return 0 ; } #endif strcpy( d4->accessName, name ) ; c4upper( d4->accessName ) ; d4->connection = connection ; d4->recWidth = dataInfo->recWidth ; d4->headerLen = dataInfo->headerLen ; d4->version = dataInfo->version ; d4->serverId = dataInfo->serverId ; data->readOnly = dataInfo->readOnly ; d4->info = (char *)u4allocFree( c4, dataInfo->infoLen ) ; if ( d4->info == 0 ) { dfile4close( d4 ) ; return 0 ; } len2 = sizeof( CONNECTION4OPEN_INFO_OUT ) ; memcpy( d4->info, connection4data( connection ) + len2, dataInfo->infoLen ) ; d4->infoLen = dataInfo->infoLen ; len2 += dataInfo->infoLen ; #ifndef S4OFF_INDEX /* index file information... */ if ( c4->autoOpen == 1 && dataInfo->numTags > 0 ) { u4namePiece( indexName, sizeof(indexName), name, 1, 0 ) ; rc = client4indexSetup( c4, data, d4, dataInfo->numTags, connection4data( connection ) + len2, (unsigned int)connection4len( connection ) - len2, indexName, 0 ) ; if ( rc < 0 ) { dfile4close( d4 ) ; return 0 ; } } #endif #else if ( file4readAll( &d4->file, 0L, &fullHeader, sizeof( fullHeader ) ) < 0 ) { dfile4close( d4 ) ; return 0 ; } #ifdef S4BYTE_SWAP fullHeader.numRecs = x4reverseLong( (void *)&fullHeader.numRecs ) ; fullHeader.headerLen = x4reverseShort( (void *)&fullHeader.headerLen ) ; fullHeader.recordLen = x4reverseShort( (void *)&fullHeader.recordLen ) ; #endif #ifdef S4DEMO if ( fullHeader.numRecs > 200L) { error4( c4, e4demo, 0 ) ; dfile4close( d4 ) ; return 0 ; } #endif if ( fullHeader.recordLen == 0 ) /* divide by zero */ { error4describe( c4, e4data, E83805, nameBuf, dfile4name( d4 ), (char *)0 ) ; dfile4close( d4 ) ; return 0 ; } #ifndef S4CLIENT /* if the file is opened deny write/exclusively, and this was the first open, then verify that the record count matches the file length (i.e. to avoid data file corruption) */ if ( c4->accessMode == OPEN4DENY_WRITE || c4->accessMode == OPEN4DENY_RW ) if ( fullHeader.numRecs != ( file4len( &d4->file ) - fullHeader.headerLen ) / fullHeader.recordLen ) { error4describe( c4, e4data, E83805, nameBuf, dfile4name( d4 ), (char *)0 ) ; dfile4close( d4 ) ; return 0 ; } #endif if ( fullHeader.numRecs < 0L || fullHeader.numRecs > ( 1 + ( file4len ( &d4->file ) - fullHeader.headerLen ) / fullHeader.recordLen ) ) { error4describe( c4, e4data, E83805, nameBuf, dfile4name( d4 ), (char *)0 ) ; dfile4close( d4 ) ; return 0 ; } memcpy( (void *)&d4->version, (void *)&fullHeader.version, (4+(sizeof(S4LONG))+(sizeof(short))) ) ; #ifdef S4FOX data->codePage = fullHeader.codePage ; #endif d4->hasMdxMemo = fullHeader.hasMdxMemo ; fieldDataLen = fullHeader.headerLen-sizeof(fullHeader) ; if ( fullHeader.headerLen <= sizeof(fullHeader) ) { error4describe( c4, e4data, E83805, nameBuf, dfile4name( d4 ), (char *)0 ) ; dfile4close( d4 ) ; return 0 ; } d4->info = (char *)u4allocFree( c4, (long)fieldDataLen ) ; d4->infoLen = fieldDataLen ; d4->headerLen = fullHeader.headerLen ; if ( d4->info == 0 ) { #ifdef E4STACK error4stack( c4, e4memory, E91102 ) ; #endif dfile4close( d4 ) ; return 0 ; } /* 06/18/96 AS --> fullHeader not read in prior place, must be after previous read */ #ifndef S4OFF_OPTIMIZE file4optimizeLow( &d4->file, c4->optimize, OPT4DBF, fullHeader.recordLen, d4 ) ; #endif if ( file4readAll( &d4->file, (long)sizeof(fullHeader), d4->info, fieldDataLen ) < 0 ) { error4describe( c4, e4data, E84306, name, 0, 0 ) ; dfile4close( d4 ) ; return 0 ; } if ( error4code( c4 ) < 0 ) { dfile4close( d4 ) ; return 0 ; } #ifndef S4OFF_MEMO if ( d4->version == 0x30 ) /* visual FP 3.0 */ hasMemo = fullHeader.hasMdxMemo & 0x02 ; else hasMemo = d4->version & 0x80 ; if ( hasMemo ) { #ifdef S4MFOX #ifdef S4CASE_SEN u4nameExt( nameBuf, sizeof(nameBuf), "fpt", 1 ) ; #else u4nameExt( nameBuf, sizeof(nameBuf), "FPT", 1 ) ; #endif #else #ifdef S4CASE_SEN u4nameExt( nameBuf, sizeof(nameBuf), "dbt", 1 ) ; #else u4nameExt( nameBuf, sizeof(nameBuf), "DBT", 1 ) ; #endif #endif if ( memo4fileOpen( &d4->memoFile, d4, nameBuf ) < 0 ) { dfile4close( d4 ) ; return 0 ; } } #endif #endif d4->numRecs = -1L ; *info = d4->info ; /* count the number of fields */ for ( count = 0 ; d4->info[count] != 0xD ; count += 32 ) ; d4->nFields = (int)( count / 32 ) ; #ifdef E4ANALYZE if ( d4->nFields == 0 ) { error4describe( c4, e4data, E84309, name, dfile4name( d4 ), 0 ) ; return 0 ; } #endif d4->recWidth = 1 ; d4->nFieldsMemo = 0 ; for ( iFields = 0; iFields < d4->nFields; iFields++ ) { image = (FIELD4IMAGE *)(((char *)*info) + iFields * 32 ) ; switch( image->type ) { case r4memo: case r4gen: d4->nFieldsMemo++ ; d4->recWidth += image->len ; break ; case r4num: case r4float: case r4log: case r4date: d4->recWidth += image->len ; break ; case r4str: d4->recWidth += ( image->len + (image->dec << 8) ) ; break ; case r4double: /* r4bin and r4double the same */ if ( d4->version == 0x30 ) { d4->recWidth += image->len ; if ( d4->version != 0x30 ) /* 2.5 data files disallowed these fields */ { dfile4close( d4 ) ; #ifdef S4SERVER error4describe( c4, e4data, E80501, nameBuf, dfile4name( d4 ), 0 ) ; #else error4describe( c4, e4data, E80501, name, dfile4name( d4 ), 0 ) ; #endif return 0 ; } } else { d4->nFieldsMemo++ ; d4->recWidth += image->len ; } break ; #ifdef S4CLIENT_OR_FOX case r4currency: case r4int: case r4dateTime: d4->recWidth += image->len ; if ( d4->version != 0x30 ) /* 2.5 data files disallowed these fields */ { dfile4close( d4 ) ; #ifdef S4SERVER error4describe( c4, e4data, E80501, nameBuf, dfile4name( d4 ), 0 ) ; #else error4describe( c4, e4data, E80501, name, dfile4name( d4 ), 0 ) ; #endif return 0 ; } break ; case r4system: /* null-fields/system field */ if ( ( d4->version != 0x30 ) || ( memcmp( image->name, "_NullFlags", 10 ) != 0 ) ) /* not visual FP 3.0 */ { dfile4close( d4 ) ; #ifdef S4SERVER error4describe( c4, e4data, E80501, nameBuf, dfile4name( d4 ), 0 ) ; #else error4describe( c4, e4data, E80501, name, dfile4name( d4 ), 0 ) ; #endif } d4->recWidth += image->len ; break ; #endif default: dfile4close( d4 ) ; #ifdef S4SERVER error4describe( c4, e4data, E80501, nameBuf, dfile4name( d4 ), 0 ) ; #else error4describe( c4, e4data, E80501, name, dfile4name( d4 ), 0 ) ; #endif return 0 ; } } #ifdef S4SERVER if ( d4->recWidth != fullHeader.recordLen ) { dfile4close( d4 ) ; error4describe( c4, e4data, E91102, nameBuf, dfile4name( d4 ), 0 ) ; return 0 ; } #endif #ifdef S4CLIENT d4->accessMode = c4->accessMode ; #else d4->valid = 1 ; /* valid, so low closes will leave open. */ #endif return d4 ; } #ifdef S4VB_DOS DATA4 * d4open_v( CODE4 *c4, char *name ) { return d4open( c4, c4str(name) ) ; } #endif