home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
listings
/
v_08_10
/
8n10034a
< prev
next >
Wrap
Text File
|
1990-06-10
|
47KB
|
1,710 lines
Listing 3: transact.c
/*************************
File: TRANSACT.C
Created
By: Russell Cook
*************************/
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include "environ.h"
#include "transact.h"
/*===== MODULE STATIC VARIABLE TYPES =====*/
/* offset: long file offset where user believes file is positioned */
/* fd: valid file descriptor for CLOSED_FILE (when free) */
/* openMode: mode with which file was opened */
/* openPerms: access permissions used for open */
/* index: handle of associated trans. file (bFileType == USER_FILE) */
/* nUseCount: # of associated user files (file type is trans. file) */
/* bFileType: USER_FILE or a valid transaction log file type specifier */
/* npcFileName: near pointer to a null-terminated filename */
typedef struct {
long offset;
int fd;
int openMode;
int openPerms;
union {
FHANDLE index;
int nUseCount;
} unionData;
BOOL bFileType;
char NEAR *npcFileName;
} TFile;
#define FILEOFFSET( npFile ) (npFile)->offset
#define FILEDESCRIPTOR( npFile ) (npFile)->fd
#define FILEMODE( npFile ) (npFile)->openMode
#define FILEPERMS( npFile ) (npFile)->openPerms
#define FILEINDEX( npFile ) (npFile)->unionData.index
#define FILEUSECOUNT( npFile ) (npFile)->unionData.nUseCount
#define FILETYPE( npFile ) (npFile)->bFileType
#define FILENAME( npFile ) (npFile)->npcFileName
/* lOffset: offset in USER data file where data should be written */
/* DataBytes: number of bytes of data extracted from USER file */
/* FileMode: read/write accessibility used to open file */
/* FilePermissions: access permissions used when USER file opened */
/* NOTE: NEW_FILE already stripped */
/* sOperation: action which caused transaction logging */
/* NameLen: # of bytes (including null) in filename field */
typedef struct {
long lOffset;
unsigned int DataBytes;
int FileMode;
int FilePermissions;
int NameLen;
short sOperation;
} TRollBackStruct;
#define ROLLOFFSET( npRoll ) (npRoll)->lOffset
#define ROLLBYTES( npRoll ) (npRoll)->DataBytes
#define ROLLMODE( npRoll ) (npRoll)->FileMode
#define ROLLPERMS( npRoll ) (npRoll)->FilePermissions
#define ROLLOP( npRoll ) (npRoll)->sOperation
#define ROLLNAMELEN( npRoll ) (npRoll)->NameLen
/*===== MODULE STATIC MANIFEST CONSTANTS =====*/
#ifdef MSC51_ENV
# include <io.h>
# include <stdlib.h>
# include <malloc.h>
# include <dos.h>
# include <sys/locking.h>
# include <limits.h>
# define ERROR_CODE 1
# define SUCCESS_CODE 0
# define NEW_FILE (O_CREAT | O_EXCL)
# define READ_FILE O_RDONLY
# define WRITE_FILE O_WRONLY
# define BINARY_FILE O_BINARY
# define SHARED_FILE S_IWRITE | S_IREAD
# define SYNC_FILE 0
# define _LPN_MAX_ _MAX_DIR
# define _LFN_MAX_ ( _MAX_FNAME + _MAX_EXT )
# define MAXUINT UINT_MAX
# define OPEN(name,mode,perms,pFd) \
((*pFd = open(name,mode,perms)) == -1 ? ERROR_CODE : SUCCESS_CODE )
# define READ(fd,buf,count,pNum) _dos_read(fd,buf,count,pNum)
# define WRITE(fd,buf,count,pNum) _dos_write(fd,buf,count,pNum)
# define LSEEK(fd,offset,whence,pPos) \
((*pPos = lseek(fd,offset,whence)) == -1L ? ERROR_CODE : SUCCESS_CODE)
# define CLOSE(fd) (close(fd) == -1 ? ERROR_CODE : SUCCESS_CODE)
# define CHSIZE(fd,lbytes) \
(chsize(fd,lbytes) == -1 ? ERROR_CODE : SUCCESS_CODE )
# define UNLINK(npName) \
(unlink(npName) == -1 ? ERROR_CODE : SUCCESS_CODE )
# define FSTAT(fd,buf) \
(fstat(fd,buf) == -1 ? ERROR_CODE : SUCCESS_CODE )
# ifdef MIXED_MODEL
# define FSTRCPY(lpDest,lpSource) farStrcpy(lpDest,lpSource)
# define FSTRLEN(lpString) farStrlen(lpString)
# else
# define FSTRCPY(lpDest,lpSource) strcpy(lpDest,lpSource)
# define FSTRLEN(lpString) strlen(lpString)
# endif /* MIXED_MODEL */
# define STRCMP(npStr1,npStr2) stricmp(npStr1,npStr2)
# define STRDUP( npString ) strdup( npString )
# define MALLOC( bytes ) malloc( bytes )
# define REALLOC( ptr, bytes ) realloc( ptr, bytes )
# define FREE( ptr ) free( ptr )
# define BYTE_BITS 8
# define BITS(x) (BYTE_BITS * sizeof(x))
#endif /* MS-DOS environment */
#ifdef TURBOC_ENV
# include <io.h>
# include <stdlib.h>
# include <alloc.h>
# include <dos.h>
# include <limits.h>
# define ERROR_CODE 1
# define SUCCESS_CODE 0
# define NEW_FILE (O_CREAT | O_EXCL)
# define READ_FILE O_RDONLY
# define WRITE_FILE O_WRONLY
# define BINARY_FILE O_BINARY
# define SHARED_FILE S_IWRITE | S_IREAD
# define SYNC_FILE 0
# define _LPN_MAX_ 128
# define _LFN_MAX_ ( 13 )
# define MAXUINT UINT_MAX
# define OPEN(name,mode,perms,pFd) \
((*pFd = open(name,mode,perms)) == -1 ? ERROR_CODE : SUCCESS_CODE )
# define READ(fd,buf,count,pNum) \
((*pNum = read(fd,buf,count)) == -1 ? ERROR_CODE : SUCCESS_CODE )
# define WRITE(fd,buf,count,pNum) \
((*pNum = write(fd,buf,count)) == -1 ? ERROR_CODE : SUCCESS_CODE )
# define LSEEK(fd,offset,whence,pPos) \
((*pPos = lseek(fd,offset,whence)) == -1L ? ERROR_CODE : SUCCESS_CODE)
# define CLOSE(fd) (close(fd) == -1 ? ERROR_CODE : SUCCESS_CODE)
# define CHSIZE(fd,lbytes) \
(chsize(fd,lbytes) == -1 ? ERROR_CODE : SUCCESS_CODE )
# define UNLINK(npName) \
(unlink(npName) == -1 ? ERROR_CODE : SUCCESS_CODE )
# define FSTAT(fd,buf) \
(fstat(fd,buf) == -1 ? ERROR_CODE : SUCCESS_CODE )
# define FSTRCPY(lpDest,lpSource) strcpy(lpDest,lpSource)
# define FSTRLEN(lpString) strlen(lpString)
# define STRCMP(npStr1,npStr2) stricmp(npStr1,npStr2)
# define STRDUP( npString ) strdup( npString )
# define MALLOC( bytes ) malloc( bytes )
# define REALLOC( ptr, bytes ) realloc( ptr, bytes )
# define FREE( ptr ) free( ptr )
# define BYTE_BITS 8
# define BITS(x) (BYTE_BITS * sizeof(x))
#endif /* TurboC environment */
#ifdef SCOUNIX_ENV
# include <stdlib.h>
# include <values.h>
# include <mnttab.h>
# include <limits.h>
# define ERROR_CODE 1
# define SUCCESS_CODE 0
# define NEW_FILE (O_CREAT | O_EXCL)
# define READ_FILE O_RDONLY
# define WRITE_FILE O_WRONLY
# define BINARY_FILE 0
# define SYNC_FILE O_SYNC
# define SHARED_FILE 0666
# define _LPN_MAX_ LPNMAX
# define _LFN_MAX_ LFNMAX
# define MAXUINT UINT_MAX
extern int open(char *,int,int);
extern int close( int );
extern long lseek( int, long, int );
extern int read( int, char *, unsigned );
extern int write( int, char *, unsigned );
extern int fstat(int,struct stat *);
extern int unlink( char * );
# define OPEN(name,mode,perms,pFd) \
((*pFd = open(name,mode,perms)) == -1 ? ERROR_CODE : SUCCESS_CODE )
# define READ(fd,buf,count,pNum) \
((*pNum = read(fd,buf,count)) == -1 ? ERROR_CODE : SUCCESS_CODE )
# define WRITE(fd,buf,count,pNum) \
((*pNum = write(fd,buf,count)) == -1 ? ERROR_CODE : SUCCESS_CODE )
# define LSEEK(fd,offset,whence,pPos) \
((*pPos = lseek(fd,offset,whence)) == -1L ? ERROR_CODE : SUCCESS_CODE)
# define CLOSE(fd) (close(fd) == -1 ? ERROR_CODE : SUCCESS_CODE)
# define CHSIZE(fd,lbytes) ERROR_CODE
# define UNLINK(npName) \
(unlink(npName) == -1 ? ERROR_CODE : SUCCESS_CODE )
# define FSTAT(fd,buf) \
(fstat(fd,buf) == -1 ? ERROR_CODE : SUCCESS_CODE )
# define FSTRCPY(lpDest,lpSource) strcpy(lpDest,lpSource)
# define FSTRLEN(lpString) strlen(lpString)
# define STRCMP(npStr1,npStr2) strcmp(npStr1,npStr2)
# define STRDUP( npString ) strdup( npString )
# define MALLOC( bytes ) malloc( bytes )
# define REALLOC( ptr, bytes ) realloc( ptr, bytes )
# define FREE( ptr ) free( ptr )
#endif /* some variation of Unix environment */
#ifndef READ
1 = 0; /* didn't get an environment specifier */
#endif
#define HANDLE_MASK ((FHANDLE)(1 << (BITS(FHANDLE) - 2) ))
#define USER_FILE ((BOOL)0)
#define CLOSED_FILE ((int)-1)
#define INCR_COUNT ( 5 )
#define BAD_FTYPE ((BOOL)(1 << (BITS( BOOL ) - 1)))
#define APPEND_OP ((short) 1)
#define OVERWR_OP ((short) 2)
#define CHSIZE_OP ((short) 4)
#define DATA_AREA 256
#define XFER_SIZE (sizeof(TRollBackStruct) + sizeof(short) + \
_LPN_MAX_ + _LFN_MAX_ + DATA_AREA )
/*===== MODULE STATIC, GLOBAL VARIABLES =====*/
static TFile NEAR *npFileArray = (TFile NEAR *)0;
static int nArrayElements = 0;
static int nElementsInUse = 0;
static int nLastError = ENONE;
/*===== MODULE STATIC FUNCTIONS =====*/
static FHANDLE NEARFNCT AddFileToTable( char FAR *, int, int, BOOL);
static BOOL NEARFNCT WriteTransRecord( short, unsigned int,\
long, TFile NEAR * );
#ifdef MIXED_MODEL
static int NEARFNCT farStrlen(char FAR * );
static void NEARFNCT farStrcpy(char FAR *, char FAR * );
#endif /* MIXED_MODEL */
#ifdef NEED_FLUSH
static BOOL NEARFNCT FlushFile( TFile NEAR * );
#else
# define FlushFile( lpFile ) TRUE
#endif /* NEED_FLUSH */
/*FDB**************************************************
Function: VFOpen
Inputs: far pointer to null-termainated file name
int specifying operation to perform for open
int specifying permission settings for file
Outputs:
Return: a valid handle for the file or BADFHANDLE
Assumptions: the file name MUST be a fully qualified, valid name
for the current environment
See Also:
******************************************************/
FHANDLE FARFNCT VFOpen( char FAR *lpcName, /* name of data file */\
int mode, /* open flags (O_RDONLY...) */\
int perms /* permissions */\
)
{
FHANDLE index;
nLastError = ENONE;
errno = 0;
if ((index = AddFileToTable( lpcName, mode, perms,
USER_FILE )) == BADFHANDLE)
return BADFHANDLE;
return index | HANDLE_MASK;
}
/*FDB**************************************************
Function: VFClose
Inputs: file handle from VFOpen()
Outputs:
Return: TRUE if file is closed else FALSE
Assumptions:
See Also: VFOpen
******************************************************/
BOOL FARFNCT VFClose( FHANDLE FileHandle )
{
int index = FileHandle & ~HANDLE_MASK;
BOOL ret;
TFile NEAR *npFile;
nLastError = ENONE;
errno = 0;
if (FileHandle == BADFHANDLE)
{
nLastError = EHANDLE;
ret = FALSE;
}
else if (FILEDESCRIPTOR((npFile = npFileArray + index)) == CLOSED_FILE)
{
nLastError = ECLOSED;
ret = FALSE; /* file not open */
}
else if (FILETYPE( npFile ) != USER_FILE)
{
nLastError = ENOTUSER;
ret = FALSE; /* trying to close non-user file */
}
else if (FILEINDEX( npFile ) != BADFHANDLE)
{
nLastError = EACTIVE;
ret = FALSE; /* there's an active transaction */
}
else if ((ret = (CLOSE( FILEDESCRIPTOR( npFile ) ) ==
ERROR_CODE ? FALSE : TRUE )) == TRUE)
{
FILEDESCRIPTOR( npFile ) = CLOSED_FILE;
FILEINDEX( npFile ) = BADFHANDLE;
FREE( FILENAME( npFile ) );
--nElementsInUse;
}
else nLastError = ECLOSE;
return ret;
}
/*FDB**************************************************
Function: OpenTransact
Inputs: far pointer to null-terminated file name
int specifying type of transaction file to be created
Outputs:
Return: BADFHANDLE if unable to (1)rollback and existing transaction
file or (2) if the file cannot be created
Assumptions: if specified file exists, a prior transaction failed before
completion. Therefore, a rollback of the files contents
is attempted. If this succeeds, the transaction file is
deleted and recreated. Otherwise, BADFHANDLE is returned.
Also, the transaction file name MUST be a fully qualified,
valid name for the current environment.
See Also: CloseTransact, DeleteTransact
******************************************************/
FHANDLE FARFNCT OpenTransact( char FAR *lpcTransName, \
BOOL bTransType )
{
FHANDLE index;
nLastError = ENONE;
errno = 0;
if (bTransType != NORMAL_TRANS && bTransType != DEL_ON_CLOSE)
{
nLastError = ETTYPE;
return BADFHANDLE;
}
else if (RollBack( lpcTransName ) == FALSE)
return BADFHANDLE; /* nLastError set by RollBack() */
else if ((index = AddFileToTable( lpcTransName,
NEW_FILE | WRITE_FILE | BINARY_FILE | SYNC_FILE,
SHARED_FILE,
bTransType )) == BADFHANDLE)
return BADFHANDLE; /* nLastError set by AddFileToTable() */
FILEUSECOUNT( npFileArray + index ) = 0;
return index | HANDLE_MASK;
}
/*FDB**************************************************
Function: CloseTransact
Inputs: file handle of open transact file from TransactOpen()
Outputs:
Return: TRUE if file is closed and/or deleted else FALSE
Assumptions: If the transaction file was opened as DEL_ON_CLOSE,
the file will be deleted after closure. Otherwise, the
caller is responsible for calling DeleteTransactFile().
See Also: OpenTransact, DeleteTransactionFile
******************************************************/
BOOL FARFNCT CloseTransact( FHANDLE TransHandle )
{
int index = TransHandle & ~HANDLE_MASK;
BOOL ret;
TFile NEAR *npFile;
nLastError = ENONE;
errno = 0;
if (TransHandle == BADFHANDLE)
{
nLastError = EHANDLE;
ret = FALSE;
}
else if (FILEDESCRIPTOR((npFile = npFileArray + index)) == CLOSED_FILE)
{
nLastError = ECLOSED;
ret = FALSE; /* file not open */
}
else if (FILETYPE( npFile ) == USER_FILE)
{
nLastError = EUSER;
ret = FALSE; /* trying to close a user file */
}
else if (FILEUSECOUNT( npFile ) != 0)
{
nLastError = EACTIVE;
ret = FALSE; /* there's an active transaction */
}
else if ((ret = (CLOSE( FILEDESCRIPTOR( npFile ) ) ==
ERROR_CODE ? FALSE : TRUE )) == TRUE)
{
FILEDESCRIPTOR( npFile ) = CLOSED_FILE;
FILEUSECOUNT( npFile ) = BADFHANDLE;
if (FILETYPE( npFile ) == DEL_ON_CLOSE &&
UNLINK( FILENAME( npFile ) ) == ERROR_CODE)
{
nLastError = EUNLINK;
ret = FALSE;
}
FREE( FILENAME( npFile ) );
--nElementsInUse;
}
else nLastError = ECLOSE;
return ret;
}
/*FDB**************************************************
Function: DeleteTransactionFile
Inputs: far pointer to null-terminated transaction file name
Outputs:
Return: TRUE if file is removed from the file system else FALSE
Assumptions: non-existence of the file is equivalent to deletion. Also,
the transaction file name MUST be a fully qualified, valid
name for the current environment.
See Also: OpenTransact, CloseTransact
******************************************************/
BOOL FARFNCT DeleteTransactionFile( char FAR *lpcTransName )
{
char NEAR *npFileName;
int index;
TFile NEAR *npFile;
#ifdef MIXED_MODEL
char nearName[ _LPN_MAX_ + _LFN_MAX_ ];
FSTRCPY( nearName, lpcTransName );
npFileName = nearName;
#else
npFileName = lpcTransName;
#endif
nLastError = ENONE;
errno = 0;
for (index = 0,
npFile = npFileArray;
index < nArrayElements;
++index, ++npFile)
{
/* can use strcmp() since both string pointers are */
/* guaranteed to be no larger than the default */
/* pointer size for the model in use. */
if (FILENAME( npFile ) != (char NEAR *)0 &&
STRCMP( FILENAME( npFile ), npFileName ) == 0 &&
FILEDESCRIPTOR( npFile ) != CLOSED_FILE)
{
nLastError = ENOTCLOSED;
return FALSE;
}
}
if (UNLINK( npFileName ) == ERROR_CODE)
{
nLastError = EUNLINK;
return FALSE;
}
return TRUE;
}
/*FDB**************************************************
Function: BeginTransaction
Inputs: handle to file opened using VFOpen()
handle of transaction file opened unsing OpenTransact()
Outputs:
Return: TRUE if a transaction is started else FALSE
Assumptions:
See Also: VFOpen, OpenTransact
******************************************************/
BOOL FARFNCT BeginTransaction( FHANDLE fileHandle, \
FHANDLE transHandle )
{
int fileIndex = fileHandle & ~HANDLE_MASK,
transIndex = transHandle & ~HANDLE_MASK;
BOOL ret = TRUE;
TFile NEAR *npUserFile, NEAR *npTransFile;
nLastError = ENONE;
errno = 0;
if (fileHandle == BADFHANDLE)
{
nLastError = EHANDLE;
ret = FALSE;
}
else if (FILEDESCRIPTOR((npUserFile = npFileArray + fileIndex)) ==
CLOSED_FILE)
{
nLastError = ECLOSED;
ret = FALSE; /* file not open */
}
else if (FILETYPE( npUserFile ) != USER_FILE)
{
nLastError = ENOTUSER;
ret = FALSE; /* fileHandle does not ref a user file */
}
else if (FILEINDEX( npUserFile ) != BADFHANDLE)
{
nLastError = EACTIVE;
ret = FALSE; /* there's an active transaction */
}
else if (transHandle == BADFHANDLE)
{
nLastError = EHANDLE;
ret = FALSE;
}
else if (FILEDESCRIPTOR((npTransFile = npFileArray + transIndex)) ==
CLOSED_FILE)
{
nLastError = ECLOSED;
ret = FALSE; /* file not open */
}
else if (FILETYPE( npTransFile ) == USER_FILE)
{
nLastError = EUSER;
ret = FALSE; /* transHandle does not ref a trans file */
}
else {
FILEINDEX( npUserFile ) = transIndex;
++FILEUSECOUNT( npTransFile );
}
return ret;
}
/*FDB**************************************************
Function: EndTransaction
Inputs: handle for a file opened using VFOpen
handle of a transaction file opened using TransactOpen
Outputs:
Return: TRUE if an active transaction between the handles is
terminated successfully else FALSE
Assumptions: a BeginTransaction() call using the same handles was
successful and no EndTransaction() has been executed
using these handles
See Also: VFOpen, OpenTransact, BeginTransaction
******************************************************/
BOOL FARFNCT EndTransaction( FHANDLE fileHandle, \
FHANDLE transHandle )
{
int fileIndex = fileHandle & ~HANDLE_MASK,
transIndex = transHandle & ~HANDLE_MASK;
BOOL ret = TRUE;
TFile NEAR *npUserFile, NEAR *npTransFile;
nLastError = ENONE;
errno = 0;
if (fileHandle == BADFHANDLE)
{
nLastError = EHANDLE;
ret = FALSE;
}
else if (FILEDESCRIPTOR((npUserFile = npFileArray + fileIndex)) ==
CLOSED_FILE)
{
nLastError = ECLOSED;
ret = FALSE; /* file not open */
}
else if (FILETYPE( npUserFile ) != USER_FILE)
{
nLastError = ENOTUSER;
ret = FALSE; /* fileHandle does not ref a user file */
}
else if (FILEINDEX( npUserFile ) != transIndex)
{
nLastError = ENOTTRACK;
ret = FALSE; /* file's transactions going someplace else */
}
else if (transHandle == BADFHANDLE)
{
nLastError = EHANDLE;
ret = FALSE;
}
else if (FILEDESCRIPTOR((npTransFile = npFileArray + transIndex)) ==
CLOSED_FILE)
{
nLastError = ECLOSED;
ret = FALSE; /* file not open */
}
else if (FILETYPE( npTransFile ) == USER_FILE)
{
nLastError = EUSER;
ret = FALSE; /* transHandle does not ref a trans file */
}
else {
FILEINDEX( npUserFile ) = BADFHANDLE;
--FILEUSECOUNT( npTransFile );
}
return ret;
}
/*FDB**************************************************
Function: VFRead
Inputs: handle of a file opened using VFOpen()
far pointer to a buffer
unsigned int # of bytes to be read into the buffer
Outputs: the first n bytes of the buffer are filled with data
from the file where n is the return value of the fnct
Return: -1 on failure else n where n is the # of bytes placed
into the buffer
Assumptions: the buffer to be filled is at least as large as the
number of bytes to be read
See Also: VFOpen
******************************************************/
int FARFNCT VFRead( FHANDLE FileHandle,\
VOID FAR *lpvBuffer,\
unsigned int numBytes )
{
int index = FileHandle & ~HANDLE_MASK;
int ret;
TFile NEAR *npFile;
long lOffset;
nLastError = ENONE;
errno = 0;
if (FileHandle == BADFHANDLE)
{
nLastError = EHANDLE;
ret = -1;
}
else if (FILEDESCRIPTOR((npFile = npFileArray + index)) == CLOSED_FILE)
{
nLastError = ECLOSED;
ret = -1; /* file not open */
}
else if (FILETYPE( npFile ) != USER_FILE)
{
nLastError = ENOTUSER;
ret = -1; /* trying to read non-user file */
}
else if (FILEOFFSET( npFile ) == -1L)
{
nLastError = EPOS;
ret = -1;
}
else if (LSEEK( FILEDESCRIPTOR( npFile ), FILEOFFSET( npFile ),
0, &lOffset ) == ERROR_CODE ||
lOffset != FILEOFFSET( npFile ))
{
nLastError = ESEEK;
ret = -1;
}
else if (READ( FILEDESCRIPTOR( npFile ), lpvBuffer, numBytes,
&ret ) == ERROR_CODE)
nLastError = EREAD;
return ret;
}
/*FDB**************************************************
Function: VFWrite
Inputs: handle of file to be read opened using VFOpen()
far pointer to buffer to be written
# of bytes in buffer to be written
Outputs:
Return: # bytes written to file
Assumptions:
See Also:
******************************************************/
int FARFNCT VFWrite( FHANDLE fileHandle,\
VOID FAR *lpvBuffer,\
unsigned int numBytes )
{
int index = fileHandle & ~HANDLE_MASK;
int ret;
TFile NEAR *npFile;
long lFileOffset, lFileLength;
nLastError = ENONE;
errno = 0;
if (fileHandle == BADFHANDLE)
{
nLastError = EHANDLE;
ret = -1L;
}
else if (FILEDESCRIPTOR((npFile = npFileArray + index)) == CLOSED_FILE)
{
nLastError = ECLOSED;
ret = -1L; /* file not open */
}
else if (FILETYPE( npFile ) != USER_FILE)
{
nLastError = ENOTUSER;
ret = -1L; /* trying to seek a non-user file */
}
else if (FILEOFFSET( npFile ) == -1L)
{
nLastError = EPOS;
ret = -1;
}
else if (LSEEK( FILEDESCRIPTOR( npFile ), 0L, 2,
&lFileLength ) == ERROR_CODE ||
LSEEK( FILEDESCRIPTOR( npFile ),
FILEOFFSET( npFile ), 0, &lFileOffset) == ERROR_CODE ||
lFileOffset != FILEOFFSET( npFile ))
{
nLastError = ESEEK;
ret = -1;
}
else if (lFileOffset > lFileLength)
{
nLastError = EPOS;
ret = -1;
}
else if (FILEINDEX( npFile ) == BADFHANDLE)
{
/* user file is NOT being tracked */
if (WRITE( FILEDESCRIPTOR( npFile ), lpvBuffer, numBytes,
&ret) == ERROR_CODE)
{
FILEOFFSET( npFile ) = -1L;
nLastError = EWRITE;
ret = -1;
}
else FILEOFFSET( npFile ) += numBytes;
}
else { /* user file IS being tracked */
if (WriteTransRecord(
(lFileOffset < lFileLength ? OVERWR_OP : APPEND_OP),
numBytes,
(lFileOffset < lFileLength ? lFileOffset : lFileLength),
npFile ) == FALSE)
ret = -1; /* nLastError already set */
else if (WRITE( FILEDESCRIPTOR( npFile ), lpvBuffer,
numBytes, &ret ) == ERROR_CODE)
{
FILEOFFSET( npFile ) = -1L;
nLastError = EWRITE;
ret = -1;
}
else FILEOFFSET( npFile ) += numBytes;
}
return ret;
}
/*FDB**************************************************
Function: VFLseek
Inputs: file handle returned by VFOpen()
signed long # of bytes to be moved
int location specifying origin of movement
Outputs:
Return: -1L on error else new file location in bytes from
start of file
Assumptions:
See Also: VFOpen
******************************************************/
long FARFNCT VFLSeek( FHANDLE fileHandle, \
long lOffset, \
int whence )
{
int index = fileHandle & ~HANDLE_MASK;
long ret;
TFile NEAR *npFile;
nLastError = ENONE;
errno = 0;
if (fileHandle == BADFHANDLE)
{
nLastError = EHANDLE;
ret = -1L;
}
else if (FILEDESCRIPTOR((npFile = npFileArray + index)) == CLOSED_FILE)
{
nLastError = ECLOSED;
ret = -1L; /* file not open */
}
else if (FILETYPE( npFile ) != USER_FILE)
{
nLastError = ENOTUSER;
ret = -1L; /* trying to seek a non-user file */
}
else {
switch( whence )
{
case 0: /* start of file */
if (lOffset < 0L)
{
nLastError = EOFFSET;
ret = FILEOFFSET( npFile ) = -1L;
}
else ret = FILEOFFSET( npFile ) = lOffset;
break;
case 1: /* current location */
if ((ret = (FILEOFFSET( npFile ) += lOffset)) < 0L)
{
ret = FILEOFFSET( npFile ) = -1L;
nLastError = EPOS;
}
break;
case 2: /* from EOF */
if (lOffset > 0L)
{
nLastError = EOFFSET;
ret = FILEOFFSET(npFile) = -1L; /* can't seek past EOF */
}
else if (LSEEK( FILEDESCRIPTOR( npFile ),
0L, 2, &ret) == ERROR_CODE)
{
nLastError = ESEEK;
ret = FILEOFFSET( npFile ) = -1L;
}
else if ((FILEOFFSET( npFile ) = ret + lOffset) < 0L)
{
nLastError = ESEEK;
ret = FILEOFFSET( npFile ) = -1L;
}
break;
default:
ret = FILEOFFSET( npFile ) = -1L;
}
}
return ret;
}
/*FDB**************************************************
Function: VFTell
Inputs: handle of a file opened using VFOpen()
Outputs:
Return: long file position from start of file in bytes
Assumptions:
See Also: VFOpen, VFLSeek
******************************************************/
long FARFNCT VFTell( FHANDLE fileHandle )
{
int index = fileHandle & ~HANDLE_MASK;
long ret;
TFile NEAR *npFile;
nLastError = ENONE;
errno = 0;
if (fileHandle == BADFHANDLE)
{
nLastError = EHANDLE;
ret = -1L;
}
else if (FILEDESCRIPTOR((npFile = npFileArray + index)) == CLOSED_FILE)
{
nLastError = ECLOSED;
ret = -1L; /* file not open */
}
else if (FILETYPE( npFile ) != USER_FILE)
{
nLastError = ENOTUSER;
ret = -1L; /* trying to close non-user file */
}
else if ((ret = FILEOFFSET( npFile )) == -1L)
nLastError = EPOS;
return ret;
}
/*FDB**************************************************
Function: VFLocking
Inputs: file handle returned by VFOpen
int specifying type of lock desired
long # of bytes in file to be locked; 0 means to CURRENT
end of file
Outputs:
Return: TRUE if lock is granted else FALSE
Assumptions: the lock begins at the current position in the
file as specified by VFTell()
See Also: VFOpen, VFTell
******************************************************/
BOOL FARFNCT VFLocking( FHANDLE fileHandle,\
int LockType, \
long numBytes )
{
int index = fileHandle & ~HANDLE_MASK;
BOOL ret = TRUE;
TFile NEAR *npFile;
nLastError = ENONE;
errno = 0;
if (fileHandle == BADFHANDLE)
{
nLastError = EHANDLE;
ret = FALSE;
}
else if (FILEDESCRIPTOR((npFile = npFileArray + index)) == CLOSED_FILE)
{
nLastError = ECLOSED;
ret = FALSE; /* file not open */
}
else if (FILETYPE( npFile ) != USER_FILE)
{
nLastError = ENOTUSER;
ret = FALSE; /* trying to close non-user file */
}
else if (FILEOFFSET(npFile) == -1L)
{
nLastError = EPOS;
ret = -1L;
}
else if (LockType != UNLOCK_BYTES &&
LockType != SHARED_LOCK &&
LockType != EXCLUSIVE_LOCK)
{
nLastError = ELTYPE;
ret = FALSE;
}
else {
#ifdef MSC51_ENV
long lPos;
if (LSEEK( FILEDESCRIPTOR( npFile ),
FILEOFFSET( npFile ), 0, &lPos ) == ERROR_CODE ||
lPos != FILEOFFSET( npFile ))
{
nLastError = ESEEK;
ret = FALSE;
}
else if (locking( FILEDESCRIPTOR( npFile ),
(LockType == UNLOCK_BYTES ? LK_UNLCK : LK_LOCK),
numBytes ) != 0)
{
nLastError = ELOCK;
ret = FALSE;
}
#endif /* MSC51_ENV */
#ifdef TURBOC_ENV
if ((LockType == SHARED_LOCK || LockType == EXCLUSIVE_LOCK))
{
if (lock( FILEDESCRIPTOR( npFile ),
FILEOFFSET( npFile ), numBytes ) != 0)
{
nLastError = ELOCK;
ret = FALSE;
}
}
else if (unlock( FILEDESCRIPTOR( npFile ),
FILEOFFSET( npFile ), numBytes ) != 0)
{
nLastError = ELOCK;
ret = FALSE;
}
#endif /* TURBOC_ENV */
#ifdef UNIX_ENV
struct flock FLock;
FLock.l_type = (LockType == SHARED_LOCK ? F_RDLCK :
(LockType == EXCL_LOCK ? F_WRLCK : F_UNLCK ));
FLock.l_whence = 0;
FLock.l_start = FILEOFFSET( npFile );
FLock.l_len = numBytes;
if (fcntl( FILEDESCRIPTOR( npFile ), F_SETLKW , &FLock ) == -1)
{
nLastError = ELOCK;
ret = FALSE;
}
#endif /* UNIX_ENV */
}
return ret;
}
/*FDB**************************************************
Function: VFChangeSize
Inputs: file handle returned from VFOpen()
long new size of file in bytes
Outputs:
Return: TRUE if file's size is changed to desired value
FALSE if file's size could not be changed
Assumptions: If file's size is INCREASED, 0s are written to the
new bytes. If the size is DECREASED, the bytes at
the END of the file are moved to the associated transaction
file (if one exists).
See Also: VFOpen
******************************************************/
BOOL FARFNCT VFChangeSize( FHANDLE fileHandle, \
long lNewSize )
{
int index = fileHandle & ~HANDLE_MASK;
BOOL ret = TRUE;
TFile NEAR *npFile;
long lFileLength;
nLastError = ENONE;
errno = 0;
if (fileHandle == BADFHANDLE)
{
nLastError = EHANDLE;
ret = FALSE;
}
else if (FILEDESCRIPTOR((npFile = npFileArray + index)) == CLOSED_FILE)
{
nLastError = ECLOSED;
ret = FALSE; /* file not open */
}
else if (FILETYPE( npFile ) != USER_FILE)
{
nLastError = ENOTUSER;
ret = FALSE; /* trying to change size of a non-user file */
}
else if (FILEINDEX( npFile ) == BADFHANDLE)
{
/* no related transaction file; issue system change size */
if ((ret = (CHSIZE( FILEDESCRIPTOR( npFile ) , lNewSize ) ==
ERROR_CODE ? FALSE : TRUE )) == FALSE)
nLastError = ECHSIZ;
}
else {
/* must track the size change */
if (LSEEK( FILEDESCRIPTOR( npFile ), 0L, 2, &lFileLength ) ==
ERROR_CODE)
{
nLastError = ESEEK;
ret = FALSE;
}
else if (lFileLength != lNewSize)
{
if (labs(lFileLength - lNewSize) > MAXUINT)
{
/* too much to be tracked */
nLastError = EDELTA;
ret = FALSE;
}
else if ((ret = WriteTransRecord(
(lFileLength < lNewSize ? APPEND_OP : OVERWR_OP),
(unsigned int)(lFileLength < lNewSize ?
(lNewSize - lFileLength) : (lFileLength - lNewSize)),
(lFileLength < lNewSize ? lFileLength : lNewSize ),
npFile)) == TRUE)
{
if ((ret = (CHSIZE( FILEDESCRIPTOR( npFile ) , lNewSize ) ==
ERROR_CODE ? FALSE : TRUE )) == FALSE)
nLastError = ECHSIZ;
}
/* else nLastError set by WriteTransRecord() */
}
/* else lNewSize == lFileLength and nothing need be done */
}
return ret;
}
/*FDB**************************************************
Function: VFStat
Inputs: file handle from VFOpen()
near pointer to stat structure
Outputs: stat structure is filled with data on the file
when TRUE is returned
Return: TRUE if able to fill structure else FALSE
Assumptions:
See Also: VFOpen
******************************************************/
BOOL FARFNCT VFStat( FHANDLE fileHandle, \
struct stat NEAR * npStatStruct )
{
int index = fileHandle & ~HANDLE_MASK;
BOOL ret = TRUE;
TFile NEAR *npFile;
nLastError = ENONE;
errno = 0;
if (fileHandle == BADFHANDLE)
{
nLastError = EHANDLE;
ret = FALSE;
}
else if (FILEDESCRIPTOR((npFile = npFileArray + index)) == CLOSED_FILE)
{
nLastError = ECLOSED;
ret = FALSE; /* file not open */
}
else if (FILETYPE( npFile ) != USER_FILE)
{
nLastError = ENOTUSER;
ret = FALSE;
}
else if (FSTAT( FILEDESCRIPTOR( npFile ),
npStatStruct) == ERROR_CODE)
{
nLastError = EFSTAT;
ret = FALSE;
}
return ret;
}
/*FDB**************************************************
Function: VFLastError
Inputs:
Outputs:
Return: identification value of last error encountered
Assumptions: return value is from set of values defined in transact.h
See Also: transact.h
******************************************************/
int FARFNCT VFLastError()
{
return nLastError;
}
/*FDB**************************************************
Function: AddFileToTable
Inputs: far pointer to null-terminated string
int file open mode
int file permissions
type of file being opened
Outputs:
Return: unmasked file handle on success else BADFHANDLE
Assumptions:
See Also:
******************************************************/
static FHANDLE NEARFNCT AddFileToTable( char FAR *lpcName, int mode,
int perms, BOOL bFileType )
{
int fd;
FHANDLE index;
TFile NEAR *npFile;
char NEAR *npFileName;
#ifdef MIXED_MODEL
char nearName[ _LPN_MAX_ + _LFN_MAX_ ];
FSTRCPY( nearName, lpcName );
npFileName = nearName;
#else
npFileName = lpcName; /* both are default sized pointers */
#endif /* !MIXED_MODEL */
if (npFileArray == (TFile NEAR *)0)
{
/* array has never been allocated */
if ((npFileArray =
(TFile NEAR *)MALLOC( INCR_COUNT * sizeof(TFile) )) ==
(TFile NEAR *)0)
{
nLastError = EMALLOC;
return BADFHANDLE;
}
/* initialize the new array elements */
for (index = (FHANDLE)0,
npFile = npFileArray,
nArrayElements += INCR_COUNT;
index < nArrayElements;
++index, ++npFile)
{
FILEOFFSET( npFile ) = 0L;
FILEDESCRIPTOR( npFile ) = CLOSED_FILE;
FILEMODE( npFile ) = FILEPERMS( npFile ) = 0;
FILEINDEX( npFile ) = BADFHANDLE;
FILETYPE( npFile ) = BAD_FTYPE;
FILENAME( npFile ) = (char NEAR *)0;
}
/* 1st free element is the first element */
index = 0;
npFile = npFileArray;
}
else if (nElementsInUse == nArrayElements)
{
/* the array must be made bigger */
if ((npFileArray =
(TFile NEAR *)REALLOC( (char NEAR *)npFileArray,
(nArrayElements + INCR_COUNT) * sizeof(TFile) )) ==
(TFile NEAR *)0)
{
nLastError = EREALLOC;
return BADFHANDLE;
}
/* initialize the new array elements */
for (index = (FHANDLE)nArrayElements,
npFile = npFileArray + nArrayElements;
index < nArrayElements + INCR_COUNT;
++index, ++npFile)
{
FILEOFFSET( npFile ) = 0L;
FILEDESCRIPTOR( npFile ) = CLOSED_FILE;
FILEMODE( npFile ) = FILEPERMS( npFile ) = 0;
FILEINDEX( npFile ) = BADFHANDLE;
FILETYPE( npFile ) = BAD_FTYPE;
FILENAME( npFile ) = (char NEAR *)0;
}
/* indicate the 1st free array element */
npFile = npFileArray + nArrayElements;
index = nArrayElements;
nArrayElements += INCR_COUNT;
}
else {
/* locate an unused entry in the file table. */
/* It's guaranteed at least 1 is available. */
for (index = (FHANDLE)0,
npFile = npFileArray;
index < nArrayElements;
++index, ++npFile)
{
if (FILEDESCRIPTOR( npFile ) == CLOSED_FILE)
break;
}
}
if (OPEN( npFileName, mode, perms, &fd ) == ERROR_CODE)
{
nLastError = EOPEN;
return BADFHANDLE;
}
if ((FILENAME( npFile ) =
(char NEAR *)STRDUP( npFileName )) == (char NEAR *)0)
{
(void)CLOSE( fd );
nLastError = ESTRDUP;
return BADFHANDLE;
}
FILEOFFSET( npFile ) = 0L;
FILEMODE( npFile ) = mode & ~NEW_FILE;
FILEPERMS( npFile ) = perms;
FILEINDEX( npFile ) = BADFHANDLE;
FILEDESCRIPTOR( npFile ) = fd;
FILETYPE( npFile ) = bFileType;
++nElementsInUse;
return index;
}
/*FDB**************************************************
Function: WriteTransRecord
Inputs: short operation ID
unsigned int number of bytes to be tracked
long offset of first byte to track (or current file length)
near pointer to user file structure
Outputs:
Return: FALSE if unable to successfully track the change described
TRUE if necessary transaction records are written to the
log file
Assumptions: the file structure contains the FHANDLE of the trans. file
to be used. Will output multiple transaction records
to the trans file if this is required by the operation
being undertaken.
See Also: RollBack
******************************************************/
static BOOL NEARFNCT WriteTransRecord( short sOp, unsigned int numBytes,
long lUserOffset, TFile NEAR *npFile )
{
char NEAR *npDataArea;
char XFerBuffer[ XFER_SIZE ];
char NEAR *npNameBuff = (char NEAR *)(XFerBuffer +
sizeof(unsigned int));
int bytesXFerred = 0;
int nameLen = strlen( FILENAME( npFile ) ) + 1; /* count the NULL */
/* safe to use strelen() since name is in data segment. */
int dataAreaSize = sizeof(XFerBuffer) - sizeof( unsigned int ) -
nameLen - sizeof( TRollBackStruct );
unsigned int bytesToXFer;
unsigned int bytesReadWrite;
long lPos;
long lOffset;
BOOL ret = TRUE;
TRollBackStruct NEAR *npRBackStruct;
TFile NEAR *npTrans = npFileArray + FILEINDEX( npFile );
(void)strcpy( npNameBuff, FILENAME( npFile ) );
npDataArea = npNameBuff + nameLen ;
if (sOp == APPEND_OP)
{
*(unsigned int NEAR *)XFerBuffer = (unsigned int)(
sizeof( TRollBackStruct ) + nameLen + sizeof(unsigned int));
npRBackStruct = (TRollBackStruct NEAR *)npDataArea;
ROLLOFFSET( npRBackStruct ) = lUserOffset; /* length of user file */
ROLLBYTES( npRBackStruct ) = 0; /* no data written from user file */
ROLLMODE( npRBackStruct ) = FILEMODE( npFile );
ROLLPERMS( npRBackStruct ) = FILEPERMS( npFile );
ROLLOP( npRBackStruct ) = APPEND_OP;
ROLLNAMELEN( npRBackStruct ) = nameLen;
/* OK to write record to the END of the trans. file */
/* after seeking to the end of the trans. file. */
if (LSEEK( FILEDESCRIPTOR( npTrans ), 0L, 2, &lPos ) == ERROR_CODE ||
WRITE( FILEDESCRIPTOR( npTrans ),
XFerBuffer, *(unsigned int NEAR *)XFerBuffer,
&bytesXFerred ) == ERROR_CODE ||
(unsigned int)bytesXFerred != *(unsigned int NEAR *)XFerBuffer)
{
FILEOFFSET( npTrans ) = -1L;
nLastError = ETRACK;
ret = FALSE;
}
else FILEOFFSET( npTrans ) += *(unsigned int NEAR *)XFerBuffer;
}
else {
/* OVERWR_OP */
if (LSEEK( FILEDESCRIPTOR( npFile ), lUserOffset, 0,
&lOffset ) == ERROR_CODE ||
lOffset != lUserOffset)
{
FILEOFFSET( npFile ) = -1L;
nLastError = ETRACK;
ret = FALSE;
}
else {
if (LSEEK( FILEDESCRIPTOR( npTrans ), 0L, 2,
&lPos ) == ERROR_CODE)
{
FILEOFFSET( npTrans ) = -1L;
nLastError = ETRACK;
ret = FALSE;
}
for ( ;
ret == TRUE && (unsigned int)bytesXFerred != numBytes;
bytesXFerred += bytesToXFer,
lOffset += bytesToXFer)
{
bytesToXFer = (numBytes - bytesXFerred > dataAreaSize ?
dataAreaSize : numBytes - bytesXFerred );
if (READ( FILEDESCRIPTOR( npFile ), npDataArea,
bytesToXFer, &bytesReadWrite ) == ERROR_CODE ||
bytesReadWrite != bytesToXFer)
{
nLastError = ETRACK;
ret = FALSE;
continue;
}
npRBackStruct =(TRollBackStruct NEAR *)(npDataArea +
bytesReadWrite);
ROLLOFFSET( npRBackStruct ) = lOffset;
ROLLBYTES( npRBackStruct ) = bytesReadWrite;
ROLLMODE( npRBackStruct ) = FILEMODE( npFile );
ROLLPERMS( npRBackStruct ) = FILEPERMS( npFile );
ROLLOP( npRBackStruct ) = OVERWR_OP;
ROLLNAMELEN( npRBackStruct ) = nameLen;
*(unsigned int NEAR *)XFerBuffer =
(unsigned int)(sizeof(unsigned int) +
sizeof(TRollBackStruct) +
nameLen + bytesReadWrite);
/* OK to write record to the END of the trans. file */
/* after seeking to the end of the trans. file. */
if (WRITE( FILEDESCRIPTOR( npTrans ),
XFerBuffer, *(unsigned int NEAR *)XFerBuffer,
&bytesReadWrite ) == ERROR_CODE ||
bytesReadWrite != *(unsigned int NEAR *)XFerBuffer)
{
FILEOFFSET( npTrans ) = -1L;
nLastError = ETRACK;
ret = FALSE;
continue;
}
FILEOFFSET( npTrans ) +=
*(unsigned int NEAR *)XFerBuffer;
} /* end-for */
if (ret == TRUE &&
LSEEK( FILEDESCRIPTOR( npFile ), lUserOffset, 0,
&lOffset ) == ERROR_CODE ||
lUserOffset != lOffset)
{
FILEOFFSET( npFile ) = -1L;
nLastError = ETRACK;
ret = FALSE;
}
} /* end-else */
}
if (ret == TRUE &&
(ret = FlushFile( npTrans )) == FALSE)
nLastError = ETRACK;
return ret;
}
/*FDB**************************************************
Function: RollBack
Inputs: far pointer to null-terminated transaction logfile name
Outputs:
Return: FALSE if unable to rollback an existing transaction log file
TRUE if file does not exist or is successfully rolled back
and deleted
Assumptions: Data in transaction file is a collection of records of the
following format:
Entry Length (unsigned int)
User filename (char[])
Data from user file (char [])
TRollBackStruct
See Also: VFWrite, WriteTransRecord
******************************************************/
BOOL FARFNCT RollBack( char FAR *lpTransName )
{
int TransFD, UserFD;
char NEAR *npTransName;
char NEAR *npDataArea;
char XFerBuffer[ XFER_SIZE ];
char NEAR *npNameBuff = (char NEAR *)(XFerBuffer +
sizeof(unsigned int));
unsigned int bytesToXFer;
unsigned int bytesReadWrite;
long lPos;
long lOffset;
BOOL ret = TRUE;
TRollBackStruct RBackStruct;
#ifdef MIXED_MODEL
char nearName[ _LPN_MAX_ + _LFN_MAX_ ];
FSTRCPY( nearName, lpTransName );
npTransName = nearName;
#else
npTransName = lpTransName; /* both are default sized pointers */
#endif /* !MIXED_MODEL */
nLastError = ENONE;
errno = 0;
/* open the transaction log file */
if (OPEN( npTransName, READ_FILE | BINARY_FILE,
SHARED_FILE, &TransFD ) == ERROR_CODE)
{
if (errno == ENOENT)
return TRUE; /* trans. file doesn't exist */
nLastError = EOPEN;
return FALSE;
}
/* trans. file is open; roll it back */
if (LSEEK( TransFD, 0L, 0, &lOffset ) == ERROR_CODE)
{
(void) CLOSE( TransFD );
nLastError = ESEEK;
return FALSE;
}
/* read each record in the trans. file to find the */
/* last complete record (lPos == end of last one). */
do {
/* get the record's total length field */
if (READ( TransFD, XFerBuffer, sizeof(unsigned int),
&bytesReadWrite ) == ERROR_CODE)
{
(void)CLOSE( TransFD );
nLastError = EROLL;
return FALSE;
}
if (bytesReadWrite != (unsigned int)sizeof(unsigned int))
break; /* incomplete record */
/* get the name, data and structure of record */
if (READ( TransFD, npNameBuff,
(bytesToXFer = *(unsigned int NEAR *)XFerBuffer) -
(unsigned int)sizeof(unsigned int),
&bytesReadWrite ) == ERROR_CODE)
{
(void)CLOSE( TransFD );
nLastError = EROLL;
return FALSE;
}
if (bytesReadWrite != bytesToXFer -
(unsigned int)sizeof(unsigned int))
break;
/* read a complete transaction record */
lOffset += (long)bytesToXFer;
}
while (bytesReadWrite == bytesToXFer -
(unsigned int)sizeof(unsigned int));
/* if lOffset > 0L, at least one valid transaction record exists */
while (lOffset > 0L)
{
/* back up and read the rollback control structure */
if (LSEEK( TransFD, (lOffset -= (long)sizeof(TRollBackStruct)), 0,
&lPos ) == ERROR_CODE ||
lPos != lOffset)
{
(void)CLOSE( TransFD );
nLastError = EROLL;
return FALSE;
}
if (READ( TransFD, (VOID NEAR *)&RBackStruct,
sizeof(TRollBackStruct), &bytesReadWrite ) == ERROR_CODE ||
bytesReadWrite != sizeof(TRollBackStruct))
{
(void)CLOSE( TransFD );
nLastError = EROLL;
return FALSE;
}
/* back up to the beginning of the transaction record and read it */
if (LSEEK( TransFD,
(lOffset -= (long)((bytesToXFer = sizeof(unsigned int) +
ROLLBYTES( &RBackStruct ) + ROLLNAMELEN( &RBackStruct )))),
0, &lPos ) == ERROR_CODE ||
lPos != lOffset)
{
(void)CLOSE( TransFD );
nLastError = EROLL;
return FALSE;
}
if (READ( TransFD, (VOID NEAR *)XFerBuffer, bytesToXFer,
&bytesReadWrite ) == ERROR_CODE ||
bytesReadWrite != bytesToXFer)
{
(void)CLOSE( TransFD );
nLastError = EROLL;
return FALSE;
}
/* open the user data file with old permissions */
if (OPEN( npNameBuff, ROLLMODE( &RBackStruct ),
ROLLPERMS( &RBackStruct ), &UserFD ) == ERROR_CODE)
{
(void)CLOSE( TransFD );
nLastError = EROLL;
return FALSE;
}
if (ROLLOP( &RBackStruct ) == APPEND_OP)
{
/* change file size to ROLLOFFSET() */
/* NOTE: SCO Unix does not provide a chsize() fnct */
/* so simply ignore the append op rollback. */
#ifndef SCOUNIX_ENV
if (CHSIZE( UserFD, ROLLOFFSET( &RBackStruct ) ) == ERROR_CODE)
{
(void)CLOSE( TransFD );
(void)CLOSE( UserFD );
nLastError = EROLL;
return FALSE;
}
#endif /* !SCOUNIX_ENV */
}
else {
/* write data from trans record back to user file */
if (LSEEK( UserFD, ROLLOFFSET( &RBackStruct ),
0, &lPos ) == ERROR_CODE ||
lPos != ROLLOFFSET( &RBackStruct ))
{
(void)CLOSE( TransFD );
(void)CLOSE( UserFD );
nLastError = EROLL;
return FALSE;
}
npDataArea = npNameBuff + ROLLNAMELEN( &RBackStruct );
if (WRITE( UserFD, npDataArea,
ROLLBYTES( &RBackStruct ),
&bytesReadWrite ) == ERROR_CODE ||
bytesReadWrite != ROLLBYTES( &RBackStruct ))
{
(void)CLOSE( TransFD );
(void)CLOSE( UserFD );
nLastError = EROLL;
return FALSE;
}
(void)CLOSE( UserFD );
} /* overwrite operation */
} /* end-while */
/* close and delete the transaction log file */
(void)CLOSE( TransFD );
if ((ret = (UNLINK( npTransName ) == ERROR_CODE ? FALSE : TRUE)) == FALSE)
nLastError = EUNLINK;
return ret;
}
#ifdef MIXED_MODEL
/*FDB**************************************************
Function: farStrcpy
Inputs: far pointer to destination buffer
far pointer to null-terminated string
Outputs: copy of string is placed into buffer w/null terminator
Return:
Assumptions: the destination buffer is large enough to hold the
string
See Also: farStrlen
******************************************************/
void NEARFNCT farStrcpy(char FAR *lpcDest, char FAR *lpcSource)
{
int nLoop;
for (nLoop = 0;
nLoop < _LPN_MAX_ + _LFN_MAX_ - 1 &&
(*lpcDest++ = *lpcSource++) != '\0';
++nLoop)
;
*lpcDest = '\0'; /* guarantee a null terminator */
}
#endif /* MIXED_MODEL */
#ifdef MIXED_MODEL
/*FDB**************************************************
Function: farStrlen
Inputs: far pointer to null-terminated string
Outputs:
Return: the length of the string
Assumptions:
See Also: farStrcpy
******************************************************/
int NEARFNCT farStrlen(char FAR *lpcString )
{
int nLoop;
for (nLoop = 0;
*lpcString++ != '\0';
++nLoop)
;
return nLoop;
}
#endif /* MIXED_MODEL */
#ifdef NEED_FLUSH
/*FDB**************************************************
Function: FlushFile
Inputs: near pointer to a file structure in the file array
Outputs:
Return: TRUE if able to successfully flush the contents of
the file to disk else FALSE
Assumptions:
See Also:
******************************************************/
static BOOL NEARFNCT FlushFile( TFile NEAR *npFile )
{
int newFD;
if (CLOSE( FILEDESCRIPTOR( npFile )) == ERROR_CODE)
{
nLastError = ECLOSE;
return FALSE;
}
if (OPEN( FILENAME( npFile ),
FILEMODE( npFile ) & ~NEW_FILE ,
FILEPERMS( npFile ),
&newFD ) == ERROR_CODE)
{
nLastError = EOPEN;
return FALSE;
}
FILEDESCRIPTOR( npFile ) = newFD;
return TRUE;
}
#endif /* NEED_FLUSH */