589 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			589 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /* 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 <sys\locking.h>
 | |
|          #define S4LOCKING
 | |
|       #endif
 | |
|       #ifdef __ZTC__
 | |
|          extern int  errno ;
 | |
|       #endif
 | |
|       #ifdef _MSC_VER
 | |
|          #include <sys\locking.h>
 | |
|       #endif
 | |
|    #endif
 | |
|    #include <share.h>
 | |
| #endif /* S4WINTEL */
 | |
| 
 | |
| #include <fcntl.h>
 | |
| #include <errno.h>
 | |
| 
 | |
| #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 ;
 | |
| }
 |