/* f4open.c (c)Copyright Sequiter Software Inc., 1988-1996. All rights reserved. */ #include "d4all.h" #ifdef __TURBOC__ #pragma hdrstop #endif #ifdef S4TEMP #include "t4test.h" #endif #ifdef S4WINTEL #ifndef S4IBMOS2 #ifndef __TURBOC__ #include #define S4LOCKING #endif #ifdef __ZTC__ extern int errno ; #endif #ifdef _MSC_VER #include #endif #endif #include #endif /* S4WINTEL */ #include #include #ifdef S4TRACK_FILES extern unsigned int numFiles ; extern int f4print ; #endif #ifdef S4ERRNO extern int errno ; #endif /* ** file4openLow() generic outline: ** ** - clear any postive error values ** - if CODE4 is requesting read-only open, then: ** (a) mark file as read only in FILE4 structure ** (b) set the physical file open flag to read only ** - check file physically to see if file has a physical read-only attribute ** (note that this is different than only allowed to have read-only access ** for example on a network drive) --> in some configurations it is not ** possible to make this check. But if it is true: ** (a) mark file as read only in FILE4 structure ** (b) set the physical file open flag to read only ** (c) mark the FILE4 as exclusive open (since nobody can write to it, can ** treat it as such ** - set the shared flag based on CODE4::accessMode ** 3 possible settings: OPEN4DENY_NONE, OPEN4DENY_WRITE, OPEN4DENY_RW. ** return failure if no the setting is invalid. ** - physically attempt the file open ** - if the file open failed, try to determine the cause of failure and return ** the appropriate error message. e4open is returned if the specific ** failure cannot be determined. ** ** Returns: 0 = success, e4... = failure (appropriate error condition) ** ** Notes: ** This routine shouldn't generate a CodeBase error */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ /* */ #ifdef S4UNIX static int file4openLow( FILE4 *file, CODE4 *c4, const char *name ) { int rc = 0 ; int oflag ; #ifdef S4NO_FLOCK struct flock lck; lck.l_whence = SEEK_SET ; lck.l_start = 0 ; lck.l_len = 1000000000 ; #endif error4set( c4, 0 ) ; /* clear positive error values */ if ( c4->readOnly == 1 ) { file->isReadOnly = 1 ; oflag = (int)O_RDONLY ; } else oflag = (int)O_RDWR ; file->hand = open( name, oflag ) ; switch ( c4->accessMode ) { case OPEN4DENY_NONE: case OPEN4DENY_WRITE: #ifndef S4NO_FLOCK rc = flock (file->hand, LOCK_SH|LOCK_NB) ; #else lck.l_type = F_RDLCK ; rc = fcntl (file->hand, F_SETLK, &lck ) ; #endif break; case OPEN4DENY_RW: #ifndef S4NO_FLOCK rc = flock (file->hand, LOCK_EX|LOCK_NB) ; #else lck.l_type = F_WRLCK ; rc = fcntl (file->hand, F_SETLK, &lck ) ; #endif break; default: close(file->hand); file->hand = -1; return e4open; } if (rc!=0) return e4open; if ( file->hand < 0 ) { /* note: getting error classification is required to allow for occasional recovery from exceeded file handle problems */ switch( errno ) /* try to get some clarification on the error */ { case EACCES: return e4permiss ; case EMFILE: /* allow try closing excess files and retrying */ return e4numFiles ; case ENOENT: return e4fileFind ; default: return e4open ; } } return 0 ; } #endif /* S4UNIX */ #ifdef S4WIN32 static int file4openLow( FILE4 *file, CODE4 *c4, const char *name ) { DWORD fdwAccess, fdwShareMode, fAttributes ; error4set( c4, 0 ) ; /* clear positive error values */ fAttributes = GetFileAttributes( name ) ; if ( fAttributes != 0xFFFFFFFF && fAttributes & FILE_ATTRIBUTE_READONLY ) { file->isReadOnly = 1 ; fdwAccess = GENERIC_READ ; #ifndef S4OFF_MULTI file->lowAccessMode = OPEN4DENY_RW ; /* for a file read-only can treat as exclusive */ #endif } else { if ( c4->readOnly == 1 ) { file->isReadOnly = 1 ; fdwAccess = GENERIC_READ ; } else fdwAccess = GENERIC_WRITE | GENERIC_READ ; } #ifdef S4OFF_MULTI #ifdef E4DEBUG /* open in shared mode for debugging to allow other programs to examine */ fdwShareMode = FILE_SHARE_WRITE | FILE_SHARE_READ ; #else /* otherwise, if single-user, file should be opened exclusively */ fdwShareMode = 0 ; #endif #else switch( c4->accessMode ) { case OPEN4DENY_NONE: fdwShareMode = FILE_SHARE_WRITE | FILE_SHARE_READ ; break ; case OPEN4DENY_WRITE: fdwShareMode = FILE_SHARE_READ ; break ; case OPEN4DENY_RW: fdwShareMode = 0 ; break ; default: file->hand = -1 ; return e4open ; } #endif /* S4OFF_MULTI */ file->hand = (int) CreateFile( name, fdwAccess, fdwShareMode, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 ) ; if ( file->hand == (int)INVALID_HANDLE_VALUE ) { /* note: getting error classification is required to allow for occasional recovery from exceeded file handle problems */ switch( errno ) /* try to get some clarification on the error */ { case EACCES: return e4permiss ; #ifdef __TURBOC__ case EINVACC: return e4access ; #endif case EMFILE: /* allow try closing excess files and retrying */ return e4numFiles ; case ENOENT: return e4fileFind ; default: return e4open ; } } #ifdef S4MULTI_THREAD InitializeCriticalSection( &file->critical4file ) ; #endif #ifdef S4ADVANCE_READ file->advanceReadBufStatus = AR4EMPTY ; #endif return 0 ; } #endif /* S4WIN32 */ #ifdef S4WIN16 static int file4openLow( FILE4 *file, CODE4 *c4, const char *name ) { int oflag, sMode ; error4set( c4, 0 ) ; /* clear positive error values */ /* check the file's dos read only attrib -- which improves performance */ if ( c4->readOnly == 1 ) { file->isReadOnly = 1 ; oflag = (int)OF_READ ; } else oflag = (int)OF_READWRITE ; #ifdef S4OFF_MULTI #ifdef E4DEBUG /* open in shared mode for debugging to allow other programs to examine */ sMode = (int)OF_SHARE_DENY_NONE ; #else /* otherwise, if single-user, file should be opened exclusively */ sMode = (int)OF_SHARE_EXCLUSIVE ; #endif #else switch( c4->accessMode ) { case OPEN4DENY_NONE: sMode = (int)OF_SHARE_DENY_NONE ; break ; case OPEN4DENY_WRITE: sMode = (int)OF_SHARE_DENY_WRITE ; break ; case OPEN4DENY_RW: sMode = (int)OF_SHARE_EXCLUSIVE ; break ; default: file->hand = -1 ; return e4open ; } #endif file->hand = _lopen( name, oflag | sMode ) ; if ( file->hand < 0 ) { /* note: getting error classification is required to allow for occasional recovery from exceeded file handle problems */ switch( errno ) /* try to get some clarification on the error */ { case EACCES: return e4permiss ; #ifdef __TURBOC__ case EINVACC: return e4access ; #endif case EMFILE: /* allow try closing excess files and retrying */ return e4numFiles ; case ENOENT: return e4fileFind ; default: return e4open ; } } return 0 ; } #endif /* S4WIN16 */ #ifdef S4WINTEL #ifndef S4WIN16 #ifndef S4WIN32 #ifndef S4OS2 #ifdef __TURBOC__ #define S4USE_CHMOD #endif #ifdef _MSC_VER #define S4USE_CHMOD #endif #endif static int file4openLow( FILE4 *file, CODE4 *c4, const char *name ) { #ifdef _MSC_VER #ifdef S4USE_CHMOD unsigned attribute ; #endif #endif int oflag, shflag ; error4set( c4, 0 ) ; /* clear positive error values */ /* check the file's dos read only attrib -- which improves performance */ #ifdef S4USE_CHMOD errno = 0 ; #ifdef __TURBOC__ if ( _A_RDONLY & _chmod( name, 0 ) ) #endif #ifdef _MSC_VER _dos_getfileattr( name, &attribute ) ; if (_A_RDONLY & attribute ) #endif { if ( errno == ENOENT ) /* file doesn't exist */ { file->hand = -1 ; if ( c4->errOpen ) return e4open ; } file->isReadOnly = 1 ; #ifndef S4OFF_MULTI file->lowAccessMode = OPEN4DENY_RW ; /* for a file read-only can treat as exclusive */ #endif oflag = (int)(O_BINARY | O_RDONLY) ; } else { #endif if ( c4->readOnly == 1 ) { file->isReadOnly = 1 ; oflag = (int)(O_BINARY | O_RDONLY) ; } else { oflag = (int)(O_BINARY | O_RDWR) ; } #ifdef S4USE_CHMOD } #endif #ifdef S4OFF_MULTI shflag = SH_DENYRW ; #else switch ( c4->accessMode ) { case OPEN4DENY_NONE: shflag = SH_DENYNO ; break ; case OPEN4DENY_WRITE: shflag = SH_DENYWR ; break ; case OPEN4DENY_RW: shflag = SH_DENYRW ; break ; default: file->hand = -1 ; return e4open ; } #endif file->hand = sopen( name, oflag, shflag, 0 ) ; if ( file->hand < 0 ) { /* note: getting error classification is required to allow for occasional recovery from exceeded file handle problems */ switch( errno ) /* try to get some clarification on the error */ { case EACCES: return e4permiss ; #ifdef __TURBOC__ case EINVACC: return e4access ; #endif case EMFILE: /* allow try closing excess files and retrying */ return e4numFiles ; case ENOENT: return e4fileFind ; default: return e4open ; } } return 0 ; } #ifdef S4USE_CHMOD #undef S4USE_CHMOD #endif #endif /* S4WIN32 */ #endif /* S4WIN16 */ #endif /* S4WINTEL */ int S4FUNCTION file4open( FILE4 *file, CODE4 *c4, S4CONST char *name, const int doAlloc ) { int rc, len ; #ifdef E4PARM_HIGH if ( file == 0 || c4 == 0 || name == 0 ) return error4( c4, e4parm, E90615 ) ; #endif if ( error4code( c4 ) < 0 ) return e4codeBase ; #ifndef S4OPTIMIZE_OFF code4memStartMaxSet( c4, c4->memMaxPercent ) ; /* start optimization if not enabled and not suspended */ #endif memset( (void *)file, 0, sizeof( FILE4 ) ) ; file->codeBase = c4 ; file->hand = -1 ; rc = file4openLow( file, c4, name ) ; #ifdef S4SERVER if ( rc != 0 ) { if ( rc != 0 && rc != e4fileFind && rc != e4permiss && rc != e4access ) { error4set( c4, 0 ) ; rc = code4dataFileCloseAll( c4 ) ; if ( rc < 0 ) return rc ; rc = file4openLow( file, c4, name ) ; } if ( c4->readOnly == 0 && c4->readOnlyRequest == 1 ) /* try opening in read-only mode */ { error4set( c4, 0 ) ; c4->readOnly = 1 ; rc = file4openLow( file, c4, name ) ; c4->readOnly = 0 ; } } #endif if ( rc != 0 ) { if ( c4->errOpen ) return error4describe( c4, rc, E90615, name, (char *) 0, (char *) 0 ) ; else { error4set( c4, r4noOpen ) ; return r4noOpen ; } } if ( doAlloc ) { len = strlen( name ) + 1 ; file->nameBuf = (char *)u4allocFree( c4, (long)len ) ; if ( file->nameBuf == 0 ) { file4close( file ) ; return error4( c4, e4memory, E90615 ) ; } file->doAllocFree = 1 ; u4ncpy( file->nameBuf, name, (unsigned int)len ) ; file->name = file->nameBuf ; } else file->name = name ; #ifndef S4OFF_MULTI file->lowAccessMode = c4->accessMode ; #endif #ifndef S4OPTIMIZE_OFF file->fileCreated = 1 ; #endif #ifdef S4TRACK_FILES numFiles++ ; if ( f4print != -1 ) { #ifdef S4WINDOWS #ifdef S4TESTING if ( mem4displayPtr == 0 ) error4( 0, e4info, E50101 ) ; d4display_str( mem4displayPtr, "\r\nfile opened: ", 1 ) ; d4display_str( mem4displayPtr, f4print, file->name ) ; #else u4writeErr( "file opened: ", 1 ) ; u4writeErr( file->name, 0 ) ; #endif #else if ( f4print ) fprintf( stdprn, "\r\nfile opened: %s", file->name ) ; else printf( "\r\nfile opened: %s", file->name ) ; #endif } #endif return rc ; } int S4FUNCTION file4openTest( FILE4 *f4 ) { return f4->hand >= 0 ; }