af15e0698b
git-svn-id: svn://10.65.10.50/trunk@4679 c028cbd2-c16b-5b4b-a496-9718f37d4682
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 ;
|
|
}
|