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 >
Text File  |  1990-06-10  |  47KB  |  1,710 lines

  1. Listing 3: transact.c
  2.  
  3.  
  4. /*************************
  5. File:    TRANSACT.C
  6. Created
  7. By:        Russell Cook
  8. *************************/
  9.  
  10. #include <stdio.h>
  11. #include <fcntl.h>
  12. #include <string.h>
  13. #include <sys/types.h>
  14. #include <sys/stat.h>
  15. #include <errno.h>
  16.  
  17. #include "environ.h"
  18. #include "transact.h"
  19.  
  20. /*===== MODULE STATIC VARIABLE TYPES =====*/
  21.     /* offset: long file offset where user believes file is positioned        */
  22.     /* fd:        valid file descriptor for CLOSED_FILE (when free)            */
  23.     /* openMode: mode with which file was opened                            */
  24.     /* openPerms: access permissions used for open                            */
  25.     /* index:    handle of associated trans. file (bFileType == USER_FILE)    */
  26.     /* nUseCount: # of associated user files (file type is trans. file)        */
  27.     /* bFileType: USER_FILE or a valid transaction log file type specifier    */
  28.     /* npcFileName:    near pointer to a null-terminated filename                */
  29. typedef struct {
  30.     long offset;
  31.     int fd;
  32.     int openMode;
  33.     int openPerms;
  34.     union {
  35.         FHANDLE index;
  36.         int nUseCount;
  37.     } unionData;
  38.     BOOL bFileType;
  39.     char NEAR *npcFileName;
  40. } TFile;
  41.  
  42. #define FILEOFFSET( npFile )            (npFile)->offset
  43. #define FILEDESCRIPTOR( npFile )        (npFile)->fd
  44. #define FILEMODE( npFile )                (npFile)->openMode
  45. #define FILEPERMS( npFile )                (npFile)->openPerms
  46. #define FILEINDEX( npFile )                (npFile)->unionData.index
  47. #define FILEUSECOUNT( npFile )            (npFile)->unionData.nUseCount
  48. #define FILETYPE( npFile )                (npFile)->bFileType
  49. #define FILENAME( npFile )                (npFile)->npcFileName
  50.  
  51.     /* lOffset:    offset in USER data file where data should be written    */
  52.     /* DataBytes: number of bytes of data extracted from USER file        */
  53.     /* FileMode: read/write accessibility used to open file                */
  54.     /* FilePermissions: access permissions used when USER file opened    */
  55.     /*                    NOTE: NEW_FILE already stripped                    */
  56.     /* sOperation: action which caused transaction logging                */
  57.     /* NameLen: # of bytes (including null) in filename field            */
  58. typedef struct {
  59.     long lOffset;
  60.     unsigned int DataBytes;
  61.     int FileMode;
  62.     int FilePermissions;
  63.     int NameLen;
  64.     short sOperation;
  65. } TRollBackStruct;
  66.  
  67. #define ROLLOFFSET( npRoll )            (npRoll)->lOffset
  68. #define ROLLBYTES( npRoll )                (npRoll)->DataBytes
  69. #define ROLLMODE( npRoll )                (npRoll)->FileMode
  70. #define ROLLPERMS( npRoll )                (npRoll)->FilePermissions
  71. #define ROLLOP( npRoll )                (npRoll)->sOperation
  72. #define ROLLNAMELEN( npRoll )            (npRoll)->NameLen
  73.  
  74. /*===== MODULE STATIC MANIFEST CONSTANTS =====*/
  75. #ifdef MSC51_ENV
  76. #    include <io.h>
  77. #    include <stdlib.h>
  78. #    include <malloc.h>
  79. #    include <dos.h>
  80. #    include <sys/locking.h>
  81. #    include <limits.h>
  82.  
  83. #    define ERROR_CODE    1
  84. #    define SUCCESS_CODE    0
  85. #    define NEW_FILE        (O_CREAT | O_EXCL)
  86. #    define READ_FILE    O_RDONLY
  87. #    define WRITE_FILE    O_WRONLY
  88. #    define BINARY_FILE    O_BINARY
  89. #    define SHARED_FILE    S_IWRITE | S_IREAD
  90. #    define SYNC_FILE    0
  91. #    define _LPN_MAX_    _MAX_DIR
  92. #    define _LFN_MAX_    ( _MAX_FNAME + _MAX_EXT )
  93. #    define MAXUINT        UINT_MAX
  94.  
  95. #    define OPEN(name,mode,perms,pFd) \
  96.         ((*pFd = open(name,mode,perms)) == -1 ? ERROR_CODE : SUCCESS_CODE )
  97. #    define READ(fd,buf,count,pNum)        _dos_read(fd,buf,count,pNum)
  98. #    define WRITE(fd,buf,count,pNum)        _dos_write(fd,buf,count,pNum)
  99. #    define LSEEK(fd,offset,whence,pPos) \
  100.         ((*pPos = lseek(fd,offset,whence)) == -1L ? ERROR_CODE : SUCCESS_CODE)
  101. #    define CLOSE(fd)    (close(fd) == -1 ? ERROR_CODE : SUCCESS_CODE)
  102.  
  103. #    define CHSIZE(fd,lbytes) \
  104.             (chsize(fd,lbytes) == -1 ? ERROR_CODE : SUCCESS_CODE )
  105. #    define UNLINK(npName) \
  106.             (unlink(npName) == -1 ? ERROR_CODE : SUCCESS_CODE )
  107. #    define FSTAT(fd,buf) \
  108.             (fstat(fd,buf) == -1 ? ERROR_CODE : SUCCESS_CODE )
  109.  
  110. #    ifdef MIXED_MODEL
  111. #        define FSTRCPY(lpDest,lpSource)        farStrcpy(lpDest,lpSource)
  112. #        define FSTRLEN(lpString)            farStrlen(lpString)
  113. #    else
  114. #        define FSTRCPY(lpDest,lpSource)        strcpy(lpDest,lpSource)
  115. #        define FSTRLEN(lpString)            strlen(lpString)
  116. #    endif    /* MIXED_MODEL */
  117.  
  118. #    define STRCMP(npStr1,npStr2)        stricmp(npStr1,npStr2)
  119.  
  120. #    define STRDUP( npString )            strdup( npString )
  121. #    define MALLOC( bytes )                malloc( bytes )
  122. #    define REALLOC( ptr, bytes )        realloc( ptr, bytes )
  123. #    define FREE( ptr )                    free( ptr )
  124.  
  125. #    define BYTE_BITS    8
  126. #    define BITS(x)        (BYTE_BITS * sizeof(x))
  127. #endif    /* MS-DOS environment */
  128.  
  129.  
  130. #ifdef TURBOC_ENV
  131. #    include <io.h>
  132. #    include <stdlib.h>
  133. #    include <alloc.h>
  134. #    include <dos.h>
  135. #    include <limits.h>
  136.  
  137. #    define ERROR_CODE    1
  138. #    define SUCCESS_CODE    0
  139. #    define NEW_FILE        (O_CREAT | O_EXCL)
  140. #    define READ_FILE    O_RDONLY
  141. #    define WRITE_FILE    O_WRONLY
  142. #    define BINARY_FILE    O_BINARY
  143. #    define SHARED_FILE    S_IWRITE | S_IREAD
  144. #    define SYNC_FILE    0
  145. #    define _LPN_MAX_    128
  146. #    define _LFN_MAX_    ( 13 )
  147. #    define MAXUINT        UINT_MAX
  148.  
  149. #    define OPEN(name,mode,perms,pFd) \
  150.         ((*pFd = open(name,mode,perms)) == -1 ? ERROR_CODE : SUCCESS_CODE )
  151. #    define READ(fd,buf,count,pNum) \
  152.         ((*pNum = read(fd,buf,count)) == -1 ? ERROR_CODE : SUCCESS_CODE )
  153. #    define WRITE(fd,buf,count,pNum) \
  154.         ((*pNum = write(fd,buf,count)) == -1 ? ERROR_CODE : SUCCESS_CODE )
  155. #    define LSEEK(fd,offset,whence,pPos) \
  156.         ((*pPos = lseek(fd,offset,whence)) == -1L ? ERROR_CODE : SUCCESS_CODE)
  157. #    define CLOSE(fd)    (close(fd) == -1 ? ERROR_CODE : SUCCESS_CODE)
  158.  
  159. #    define CHSIZE(fd,lbytes) \
  160.             (chsize(fd,lbytes) == -1 ? ERROR_CODE : SUCCESS_CODE )
  161. #    define UNLINK(npName) \
  162.             (unlink(npName) == -1 ? ERROR_CODE : SUCCESS_CODE )
  163. #    define FSTAT(fd,buf) \
  164.             (fstat(fd,buf) == -1 ? ERROR_CODE : SUCCESS_CODE )
  165.  
  166. #    define FSTRCPY(lpDest,lpSource)        strcpy(lpDest,lpSource)
  167. #    define FSTRLEN(lpString)            strlen(lpString)
  168. #    define STRCMP(npStr1,npStr2)        stricmp(npStr1,npStr2)
  169.  
  170. #    define STRDUP( npString )            strdup( npString )
  171. #    define MALLOC( bytes )                malloc( bytes )
  172. #    define REALLOC( ptr, bytes )        realloc( ptr, bytes )
  173. #    define FREE( ptr )                    free( ptr )
  174.  
  175. #    define BYTE_BITS    8
  176. #    define BITS(x)        (BYTE_BITS * sizeof(x))
  177. #endif    /* TurboC environment */
  178.  
  179.  
  180. #ifdef SCOUNIX_ENV
  181. #    include <stdlib.h>
  182. #    include <values.h>
  183. #    include <mnttab.h>
  184. #    include <limits.h>
  185.  
  186. #    define ERROR_CODE    1
  187. #    define SUCCESS_CODE    0
  188. #    define NEW_FILE        (O_CREAT | O_EXCL)
  189. #    define READ_FILE    O_RDONLY
  190. #    define WRITE_FILE    O_WRONLY
  191. #    define BINARY_FILE    0
  192. #    define SYNC_FILE    O_SYNC
  193. #    define SHARED_FILE    0666
  194. #    define _LPN_MAX_    LPNMAX
  195. #    define _LFN_MAX_    LFNMAX
  196. #    define MAXUINT        UINT_MAX
  197.     extern int open(char *,int,int);
  198.     extern int    close( int );
  199.     extern long    lseek( int, long, int );
  200.     extern int    read( int, char *, unsigned );
  201.     extern int    write( int, char *, unsigned );
  202.     extern int fstat(int,struct stat *);
  203.     extern int    unlink( char * );
  204.  
  205. #    define OPEN(name,mode,perms,pFd) \
  206.         ((*pFd = open(name,mode,perms)) == -1 ? ERROR_CODE : SUCCESS_CODE )
  207. #    define READ(fd,buf,count,pNum) \
  208.         ((*pNum = read(fd,buf,count)) == -1 ? ERROR_CODE : SUCCESS_CODE )
  209. #    define WRITE(fd,buf,count,pNum) \
  210.         ((*pNum = write(fd,buf,count)) == -1 ? ERROR_CODE : SUCCESS_CODE )
  211. #    define LSEEK(fd,offset,whence,pPos) \
  212.         ((*pPos = lseek(fd,offset,whence)) == -1L ? ERROR_CODE : SUCCESS_CODE)
  213. #    define CLOSE(fd)    (close(fd) == -1 ? ERROR_CODE : SUCCESS_CODE)
  214.  
  215. #    define CHSIZE(fd,lbytes)            ERROR_CODE
  216. #    define UNLINK(npName) \
  217.             (unlink(npName) == -1 ? ERROR_CODE : SUCCESS_CODE )
  218. #    define FSTAT(fd,buf) \
  219.             (fstat(fd,buf) == -1 ? ERROR_CODE : SUCCESS_CODE )
  220.  
  221. #    define FSTRCPY(lpDest,lpSource)        strcpy(lpDest,lpSource)
  222. #    define FSTRLEN(lpString)            strlen(lpString)
  223. #    define STRCMP(npStr1,npStr2)        strcmp(npStr1,npStr2)
  224.  
  225. #    define STRDUP( npString )            strdup( npString )
  226. #    define MALLOC( bytes )                malloc( bytes )
  227. #    define REALLOC( ptr, bytes )        realloc( ptr, bytes )
  228. #    define FREE( ptr )                    free( ptr )
  229. #endif    /* some variation of Unix environment */
  230.  
  231. #ifndef READ
  232. 1 = 0;        /* didn't get an environment specifier */
  233. #endif
  234.  
  235. #define HANDLE_MASK        ((FHANDLE)(1 << (BITS(FHANDLE) - 2) ))
  236.  
  237. #define USER_FILE        ((BOOL)0)
  238. #define CLOSED_FILE        ((int)-1)
  239.  
  240. #define INCR_COUNT        ( 5 )
  241. #define BAD_FTYPE        ((BOOL)(1 << (BITS( BOOL ) - 1)))
  242.  
  243. #define APPEND_OP        ((short) 1)
  244. #define OVERWR_OP        ((short) 2)
  245. #define CHSIZE_OP        ((short) 4)
  246.  
  247. #define DATA_AREA        256
  248. #define XFER_SIZE        (sizeof(TRollBackStruct) + sizeof(short) + \
  249.                             _LPN_MAX_ + _LFN_MAX_ + DATA_AREA )
  250.  
  251. /*===== MODULE STATIC, GLOBAL VARIABLES =====*/
  252. static TFile NEAR *npFileArray = (TFile NEAR *)0;
  253. static int nArrayElements = 0;
  254. static int nElementsInUse = 0;
  255. static int nLastError = ENONE;
  256.  
  257. /*===== MODULE STATIC FUNCTIONS =====*/
  258. static FHANDLE NEARFNCT AddFileToTable( char FAR *, int, int, BOOL);
  259. static BOOL NEARFNCT WriteTransRecord( short, unsigned int,\
  260.         long, TFile NEAR * );
  261.  
  262. #ifdef MIXED_MODEL
  263.     static int NEARFNCT farStrlen(char FAR * );
  264.     static void NEARFNCT farStrcpy(char FAR *, char FAR * );
  265. #endif    /* MIXED_MODEL */
  266.  
  267. #ifdef NEED_FLUSH
  268.     static BOOL NEARFNCT FlushFile( TFile NEAR * );
  269. #else
  270. #    define FlushFile( lpFile )    TRUE
  271. #endif    /* NEED_FLUSH */
  272. /*FDB**************************************************
  273. Function:        VFOpen
  274. Inputs:            far pointer to null-termainated file name
  275.                 int specifying operation to perform for open
  276.                 int specifying permission settings for file
  277. Outputs:        
  278. Return:            a valid handle for the file or BADFHANDLE
  279. Assumptions:    the file name MUST be a fully qualified, valid name
  280.                 for the current environment
  281. See Also:        
  282. ******************************************************/
  283.  
  284. FHANDLE FARFNCT VFOpen( char FAR *lpcName,    /* name of data file */\
  285.                         int mode,        /* open flags (O_RDONLY...) */\
  286.                         int perms        /* permissions */\
  287.                         )
  288. {
  289.     FHANDLE index;
  290.  
  291.     nLastError = ENONE;
  292.     errno = 0;
  293.  
  294.     if ((index = AddFileToTable( lpcName, mode, perms,
  295.         USER_FILE )) == BADFHANDLE)
  296.             return BADFHANDLE;
  297.  
  298.     return index | HANDLE_MASK;
  299. }
  300. /*FDB**************************************************
  301. Function:        VFClose
  302. Inputs:            file handle from VFOpen()
  303. Outputs:        
  304. Return:            TRUE if file is closed else FALSE
  305. Assumptions:
  306. See Also:        VFOpen
  307. ******************************************************/
  308.  
  309. BOOL FARFNCT VFClose( FHANDLE FileHandle )
  310. {
  311.     int index = FileHandle & ~HANDLE_MASK;
  312.     BOOL ret;
  313.     TFile NEAR *npFile;
  314.  
  315.     nLastError = ENONE;
  316.     errno = 0;
  317.  
  318.     if (FileHandle == BADFHANDLE)
  319.     {
  320.         nLastError = EHANDLE;
  321.         ret = FALSE;
  322.     }
  323.     else if (FILEDESCRIPTOR((npFile = npFileArray + index)) == CLOSED_FILE)
  324.     {
  325.         nLastError = ECLOSED;
  326.         ret = FALSE;    /* file not open */
  327.     }
  328.     else if (FILETYPE( npFile ) != USER_FILE)
  329.     {
  330.         nLastError = ENOTUSER;
  331.         ret = FALSE;    /* trying to close non-user file */
  332.     }
  333.     else if (FILEINDEX( npFile ) != BADFHANDLE)
  334.     {
  335.         nLastError = EACTIVE;
  336.         ret = FALSE;    /* there's an active transaction */
  337.     }
  338.     else if ((ret = (CLOSE( FILEDESCRIPTOR( npFile ) ) ==
  339.         ERROR_CODE ? FALSE : TRUE )) == TRUE)
  340.     {
  341.         FILEDESCRIPTOR( npFile ) = CLOSED_FILE;
  342.         FILEINDEX( npFile ) = BADFHANDLE;
  343.         FREE( FILENAME( npFile ) );
  344.         --nElementsInUse;
  345.     }
  346.     else nLastError = ECLOSE;
  347.     return ret;
  348. }
  349. /*FDB**************************************************
  350. Function:        OpenTransact
  351. Inputs:            far pointer to null-terminated file name
  352.                 int specifying type of transaction file to be created
  353. Outputs:        
  354. Return:            BADFHANDLE if unable to (1)rollback and existing transaction
  355.                 file or (2) if the file cannot be created
  356. Assumptions:    if specified file exists, a prior transaction failed before
  357.                 completion.  Therefore, a rollback of the files contents
  358.                 is attempted.  If this succeeds, the transaction file is
  359.                 deleted and recreated.  Otherwise, BADFHANDLE is returned.
  360.                 Also, the transaction file name MUST be a fully qualified,
  361.                 valid name for the current environment.
  362. See Also:        CloseTransact, DeleteTransact
  363. ******************************************************/
  364.  
  365. FHANDLE FARFNCT OpenTransact( char FAR *lpcTransName, \
  366.                              BOOL bTransType )
  367. {
  368.     FHANDLE index;
  369.  
  370.     nLastError = ENONE;
  371.     errno = 0;
  372.  
  373.     if (bTransType != NORMAL_TRANS && bTransType != DEL_ON_CLOSE)
  374.     {
  375.         nLastError = ETTYPE;
  376.         return BADFHANDLE;
  377.     }
  378.     else if (RollBack( lpcTransName ) == FALSE)
  379.         return BADFHANDLE;    /* nLastError set by RollBack() */
  380.     else if ((index = AddFileToTable( lpcTransName,
  381.             NEW_FILE | WRITE_FILE | BINARY_FILE | SYNC_FILE,
  382.             SHARED_FILE,
  383.             bTransType )) == BADFHANDLE)
  384.         return BADFHANDLE;    /* nLastError set by AddFileToTable() */
  385.  
  386.     FILEUSECOUNT( npFileArray + index ) = 0;
  387.  
  388.     return index | HANDLE_MASK;
  389. }
  390. /*FDB**************************************************
  391. Function:        CloseTransact
  392. Inputs:            file handle of open transact file from TransactOpen()
  393. Outputs:
  394. Return:            TRUE if file is closed and/or deleted else FALSE
  395. Assumptions:    If the transaction file was opened as DEL_ON_CLOSE,
  396.                 the file will be deleted after closure.  Otherwise, the
  397.                 caller is responsible for calling DeleteTransactFile().
  398. See Also:        OpenTransact, DeleteTransactionFile
  399. ******************************************************/
  400.  
  401. BOOL FARFNCT CloseTransact(    FHANDLE TransHandle )
  402. {
  403.     int index = TransHandle & ~HANDLE_MASK;
  404.     BOOL ret;
  405.     TFile NEAR *npFile;
  406.  
  407.     nLastError = ENONE;
  408.     errno = 0;
  409.  
  410.     if (TransHandle == BADFHANDLE)
  411.     {
  412.         nLastError = EHANDLE;
  413.         ret = FALSE;
  414.     }
  415.     else if (FILEDESCRIPTOR((npFile = npFileArray + index)) == CLOSED_FILE)
  416.     {
  417.         nLastError = ECLOSED;
  418.         ret = FALSE;    /* file not open */
  419.     }
  420.     else if (FILETYPE( npFile ) == USER_FILE)
  421.     {
  422.         nLastError = EUSER;
  423.         ret = FALSE;    /* trying to close a user file */
  424.     }
  425.     else if (FILEUSECOUNT( npFile ) != 0)
  426.     {
  427.         nLastError = EACTIVE;
  428.         ret = FALSE;    /* there's an active transaction */
  429.     }
  430.     else if ((ret = (CLOSE( FILEDESCRIPTOR( npFile ) ) ==
  431.         ERROR_CODE ? FALSE : TRUE )) == TRUE)
  432.     {
  433.         FILEDESCRIPTOR( npFile ) = CLOSED_FILE;
  434.         FILEUSECOUNT( npFile ) = BADFHANDLE;
  435.         if (FILETYPE( npFile ) == DEL_ON_CLOSE &&
  436.             UNLINK( FILENAME( npFile ) ) == ERROR_CODE)
  437.         {
  438.             nLastError = EUNLINK;
  439.             ret = FALSE;
  440.         }
  441.         FREE( FILENAME( npFile ) );
  442.         --nElementsInUse;
  443.     }
  444.     else nLastError = ECLOSE;
  445.     return ret;
  446. }
  447. /*FDB**************************************************
  448. Function:        DeleteTransactionFile
  449. Inputs:            far pointer to null-terminated transaction file name
  450. Outputs:        
  451. Return:            TRUE if file is removed from the file system else FALSE
  452. Assumptions:    non-existence of the file is equivalent to deletion. Also,
  453.                 the transaction file name MUST be a fully qualified, valid
  454.                 name for the current environment.
  455. See Also:        OpenTransact, CloseTransact
  456. ******************************************************/
  457.  
  458. BOOL FARFNCT DeleteTransactionFile(    char FAR *lpcTransName )
  459. {
  460.     char NEAR *npFileName;
  461.     int index;
  462.     TFile NEAR *npFile;
  463.  
  464. #ifdef MIXED_MODEL
  465.     char nearName[ _LPN_MAX_ + _LFN_MAX_ ];
  466.  
  467.     FSTRCPY( nearName, lpcTransName );
  468.     npFileName = nearName;
  469. #else
  470.     npFileName = lpcTransName;
  471. #endif
  472.  
  473.     nLastError = ENONE;
  474.     errno = 0;
  475.  
  476.     for (index = 0,
  477.             npFile = npFileArray;
  478.         index < nArrayElements;
  479.         ++index, ++npFile)
  480.     {
  481.         /* can use strcmp() since both string pointers are */
  482.         /* guaranteed to be no larger than the default     */
  483.         /* pointer size for the model in use.              */
  484.         if (FILENAME( npFile ) != (char NEAR *)0 &&
  485.             STRCMP( FILENAME( npFile ), npFileName ) == 0 &&
  486.             FILEDESCRIPTOR( npFile ) != CLOSED_FILE)
  487.         {
  488.             nLastError = ENOTCLOSED;
  489.             return FALSE;
  490.         }
  491.     }
  492.  
  493.     if (UNLINK( npFileName ) == ERROR_CODE)
  494.     {
  495.         nLastError = EUNLINK;
  496.         return FALSE;
  497.     }
  498.  
  499.     return TRUE;
  500. }
  501. /*FDB**************************************************
  502. Function:        BeginTransaction
  503. Inputs:            handle to file opened using VFOpen()
  504.                 handle of transaction file opened unsing OpenTransact()
  505. Outputs:        
  506. Return:            TRUE if a transaction is started else FALSE
  507. Assumptions:    
  508. See Also:        VFOpen, OpenTransact
  509. ******************************************************/
  510.  
  511. BOOL FARFNCT BeginTransaction(    FHANDLE fileHandle, \
  512.                                 FHANDLE transHandle )
  513. {
  514.     int fileIndex = fileHandle & ~HANDLE_MASK,
  515.         transIndex = transHandle & ~HANDLE_MASK;
  516.     BOOL ret = TRUE;
  517.     TFile NEAR *npUserFile, NEAR *npTransFile;
  518.  
  519.     nLastError = ENONE;
  520.     errno = 0;
  521.  
  522.     if (fileHandle == BADFHANDLE)
  523.     {
  524.         nLastError = EHANDLE;
  525.         ret = FALSE;
  526.     }
  527.     else if (FILEDESCRIPTOR((npUserFile = npFileArray + fileIndex)) ==
  528.         CLOSED_FILE)
  529.     {
  530.         nLastError = ECLOSED;
  531.         ret = FALSE;    /* file not open */
  532.     }
  533.     else if (FILETYPE( npUserFile ) != USER_FILE)
  534.     {
  535.         nLastError = ENOTUSER;
  536.         ret = FALSE;    /* fileHandle does not ref a user file */
  537.     }
  538.     else if (FILEINDEX( npUserFile ) != BADFHANDLE)
  539.     {
  540.         nLastError = EACTIVE;
  541.         ret = FALSE;    /* there's an active transaction */
  542.     }
  543.     else if (transHandle == BADFHANDLE)
  544.     {
  545.         nLastError = EHANDLE;
  546.         ret = FALSE;
  547.     }
  548.     else if (FILEDESCRIPTOR((npTransFile = npFileArray + transIndex)) ==
  549.         CLOSED_FILE)
  550.     {
  551.         nLastError = ECLOSED;
  552.         ret = FALSE;    /* file not open */
  553.     }
  554.     else if (FILETYPE( npTransFile ) == USER_FILE)
  555.     {
  556.         nLastError = EUSER;
  557.         ret = FALSE;    /* transHandle does not ref a trans file */
  558.     }
  559.     else {
  560.         FILEINDEX( npUserFile ) = transIndex;
  561.         ++FILEUSECOUNT( npTransFile );
  562.     }
  563.     return ret;
  564. }
  565. /*FDB**************************************************
  566. Function:        EndTransaction
  567. Inputs:            handle for a file opened using VFOpen
  568.                 handle of a transaction file opened using TransactOpen
  569. Outputs:        
  570. Return:            TRUE if an active transaction between the handles is
  571.                 terminated successfully else FALSE
  572. Assumptions:    a BeginTransaction() call using the same handles was
  573.                 successful and no EndTransaction() has been executed
  574.                 using these handles
  575. See Also:        VFOpen, OpenTransact, BeginTransaction
  576. ******************************************************/
  577.  
  578. BOOL FARFNCT EndTransaction(    FHANDLE fileHandle, \
  579.                                 FHANDLE transHandle )
  580. {
  581.     int fileIndex = fileHandle & ~HANDLE_MASK,
  582.         transIndex = transHandle & ~HANDLE_MASK;
  583.     BOOL ret = TRUE;
  584.     TFile NEAR *npUserFile, NEAR *npTransFile;
  585.  
  586.     nLastError = ENONE;
  587.     errno = 0;
  588.  
  589.     if (fileHandle == BADFHANDLE)
  590.     {
  591.         nLastError = EHANDLE;
  592.         ret = FALSE;
  593.     }
  594.     else if (FILEDESCRIPTOR((npUserFile = npFileArray + fileIndex)) ==
  595.         CLOSED_FILE)
  596.     {
  597.         nLastError = ECLOSED;
  598.         ret = FALSE;    /* file not open */
  599.     }
  600.     else if (FILETYPE( npUserFile ) != USER_FILE)
  601.     {
  602.         nLastError = ENOTUSER;
  603.         ret = FALSE;    /* fileHandle does not ref a user file */
  604.     }
  605.     else if (FILEINDEX( npUserFile ) != transIndex)
  606.     {
  607.         nLastError = ENOTTRACK;
  608.         ret = FALSE;    /* file's transactions going someplace else */
  609.     }
  610.     else if (transHandle == BADFHANDLE)
  611.     {
  612.         nLastError = EHANDLE;
  613.         ret = FALSE;
  614.     }
  615.     else if (FILEDESCRIPTOR((npTransFile = npFileArray + transIndex)) ==
  616.         CLOSED_FILE)
  617.     {
  618.         nLastError = ECLOSED;
  619.         ret = FALSE;    /* file not open */
  620.     }
  621.     else if (FILETYPE( npTransFile ) == USER_FILE)
  622.     {
  623.         nLastError = EUSER;
  624.         ret = FALSE;    /* transHandle does not ref a trans file */
  625.     }
  626.     else {
  627.         FILEINDEX( npUserFile ) = BADFHANDLE;
  628.         --FILEUSECOUNT( npTransFile );
  629.     }
  630.     return ret;
  631. }
  632. /*FDB**************************************************
  633. Function:        VFRead
  634. Inputs:            handle of a file opened using VFOpen()
  635.                 far pointer to a buffer
  636.                 unsigned int # of bytes to be read into the buffer
  637. Outputs:        the first n bytes of the buffer are filled with data
  638.                 from the file where n is the return value of the fnct
  639. Return:            -1 on failure else n where n is the # of bytes placed
  640.                 into the buffer
  641. Assumptions:    the buffer to be filled is at least as large as the
  642.                 number of bytes to be read
  643. See Also:        VFOpen
  644. ******************************************************/
  645.  
  646. int FARFNCT VFRead(    FHANDLE FileHandle,\
  647.                     VOID FAR *lpvBuffer,\
  648.                     unsigned int numBytes )
  649. {
  650.     int index = FileHandle & ~HANDLE_MASK;
  651.     int ret;
  652.     TFile NEAR *npFile;
  653.     long lOffset;
  654.  
  655.     nLastError = ENONE;
  656.     errno = 0;
  657.  
  658.     if (FileHandle == BADFHANDLE)
  659.     {
  660.         nLastError = EHANDLE;
  661.         ret = -1;
  662.     }
  663.     else if (FILEDESCRIPTOR((npFile = npFileArray + index)) == CLOSED_FILE)
  664.     {
  665.         nLastError = ECLOSED;
  666.         ret = -1;    /* file not open */
  667.     }
  668.     else if (FILETYPE( npFile ) != USER_FILE)
  669.     {
  670.         nLastError = ENOTUSER;
  671.         ret = -1;    /* trying to read non-user file */
  672.     }
  673.     else if (FILEOFFSET( npFile ) == -1L)
  674.     {
  675.         nLastError = EPOS;
  676.         ret = -1;
  677.     }
  678.     else if (LSEEK( FILEDESCRIPTOR( npFile ), FILEOFFSET( npFile ),
  679.         0, &lOffset ) == ERROR_CODE ||
  680.         lOffset != FILEOFFSET( npFile ))
  681.     {
  682.         nLastError = ESEEK;
  683.         ret = -1;
  684.     }
  685.     else if (READ( FILEDESCRIPTOR( npFile ), lpvBuffer, numBytes,
  686.         &ret ) == ERROR_CODE)
  687.             nLastError = EREAD;
  688.  
  689.     return ret;
  690. }
  691. /*FDB**************************************************
  692. Function:        VFWrite
  693. Inputs:            handle of file to be read opened using VFOpen()
  694.                 far pointer to buffer to be written
  695.                 # of bytes in buffer to be written
  696. Outputs:        
  697. Return:            # bytes written to file
  698. Assumptions:    
  699. See Also:        
  700. ******************************************************/
  701.  
  702. int FARFNCT VFWrite( FHANDLE fileHandle,\
  703.                      VOID FAR *lpvBuffer,\
  704.                      unsigned int numBytes )
  705. {
  706.     int index = fileHandle & ~HANDLE_MASK;
  707.     int ret;
  708.     TFile NEAR *npFile;
  709.     long lFileOffset, lFileLength;
  710.  
  711.     nLastError = ENONE;
  712.     errno = 0;
  713.  
  714.     if (fileHandle == BADFHANDLE)
  715.     {
  716.         nLastError = EHANDLE;
  717.         ret = -1L;
  718.     }
  719.     else if (FILEDESCRIPTOR((npFile = npFileArray + index)) == CLOSED_FILE)
  720.     {
  721.         nLastError = ECLOSED;
  722.         ret = -1L;    /* file not open */
  723.     }
  724.     else if (FILETYPE( npFile ) != USER_FILE)
  725.     {
  726.         nLastError = ENOTUSER;
  727.         ret = -1L;    /* trying to seek a non-user file */
  728.     }
  729.     else if (FILEOFFSET( npFile ) == -1L)
  730.     {
  731.         nLastError = EPOS;
  732.         ret = -1;
  733.     }
  734.     else if (LSEEK( FILEDESCRIPTOR( npFile ), 0L, 2,
  735.             &lFileLength ) == ERROR_CODE ||
  736.         LSEEK( FILEDESCRIPTOR( npFile ),
  737.             FILEOFFSET( npFile ), 0, &lFileOffset) == ERROR_CODE ||
  738.         lFileOffset != FILEOFFSET( npFile ))
  739.     {
  740.         nLastError = ESEEK;
  741.         ret = -1;
  742.     }
  743.     else if (lFileOffset > lFileLength)
  744.     {
  745.         nLastError = EPOS;
  746.         ret = -1;
  747.     }
  748.     else if (FILEINDEX( npFile ) == BADFHANDLE)
  749.     {
  750.         /* user file is NOT being tracked */
  751.         if (WRITE( FILEDESCRIPTOR( npFile ), lpvBuffer, numBytes,
  752.             &ret) == ERROR_CODE)
  753.         {
  754.             FILEOFFSET( npFile ) = -1L;
  755.             nLastError = EWRITE;
  756.             ret = -1;
  757.         }
  758.         else FILEOFFSET( npFile ) += numBytes;
  759.     }
  760.     else {    /* user file IS being tracked */
  761.         if (WriteTransRecord(
  762.                 (lFileOffset < lFileLength ? OVERWR_OP : APPEND_OP),
  763.                 numBytes,
  764.                 (lFileOffset < lFileLength ? lFileOffset : lFileLength),
  765.                 npFile ) == FALSE)
  766.             ret = -1;    /* nLastError already set */
  767.         else if (WRITE( FILEDESCRIPTOR( npFile ), lpvBuffer,
  768.             numBytes, &ret ) == ERROR_CODE)
  769.         {
  770.             FILEOFFSET( npFile ) = -1L;
  771.             nLastError = EWRITE;
  772.             ret = -1;
  773.         }
  774.         else FILEOFFSET( npFile ) += numBytes;
  775.     }
  776.  
  777.     return ret;
  778. }
  779. /*FDB**************************************************
  780. Function:        VFLseek
  781. Inputs:            file handle returned by VFOpen()
  782.                 signed long # of bytes to be moved
  783.                 int location specifying origin of movement
  784. Outputs:        
  785. Return:            -1L on error else new file location in bytes from
  786.                 start of file
  787. Assumptions:    
  788. See Also:        VFOpen
  789. ******************************************************/
  790.  
  791. long FARFNCT VFLSeek( FHANDLE fileHandle, \
  792.                       long lOffset, \
  793.                       int whence )
  794. {
  795.     int index = fileHandle & ~HANDLE_MASK;
  796.     long ret;
  797.     TFile NEAR *npFile;
  798.  
  799.     nLastError = ENONE;
  800.     errno = 0;
  801.  
  802.     if (fileHandle == BADFHANDLE)
  803.     {
  804.         nLastError = EHANDLE;
  805.         ret = -1L;
  806.     }
  807.     else if (FILEDESCRIPTOR((npFile = npFileArray + index)) == CLOSED_FILE)
  808.     {
  809.         nLastError = ECLOSED;
  810.         ret = -1L;    /* file not open */
  811.     }
  812.     else if (FILETYPE( npFile ) != USER_FILE)
  813.     {
  814.         nLastError = ENOTUSER;
  815.         ret = -1L;    /* trying to seek a non-user file */
  816.     }
  817.     else {
  818.         switch( whence )
  819.         {
  820.             case 0:    /* start of file */
  821.                 if (lOffset < 0L)
  822.                 {
  823.                     nLastError = EOFFSET;
  824.                     ret = FILEOFFSET( npFile ) = -1L;
  825.                 }
  826.                 else ret = FILEOFFSET( npFile ) = lOffset;
  827.                 break;
  828.  
  829.             case 1:    /* current location */
  830.                 if ((ret = (FILEOFFSET( npFile ) += lOffset)) < 0L)
  831.                 {
  832.                     ret = FILEOFFSET( npFile ) = -1L;
  833.                     nLastError = EPOS;
  834.                 }
  835.                 break;
  836.  
  837.             case 2:    /* from EOF */
  838.                 if (lOffset > 0L)
  839.                 {
  840.                     nLastError = EOFFSET;
  841.                     ret = FILEOFFSET(npFile) = -1L;    /* can't seek past EOF */
  842.                 }
  843.                 else if (LSEEK( FILEDESCRIPTOR( npFile ),
  844.                     0L, 2, &ret) == ERROR_CODE)
  845.                 {
  846.                     nLastError = ESEEK;
  847.                     ret = FILEOFFSET( npFile ) = -1L;
  848.                 }
  849.                 else if ((FILEOFFSET( npFile ) = ret + lOffset) < 0L)
  850.                 {
  851.                     nLastError = ESEEK;
  852.                     ret = FILEOFFSET( npFile ) = -1L;
  853.                 }
  854.                 break;
  855.             default:
  856.                 ret = FILEOFFSET( npFile ) = -1L;
  857.         }
  858.     }
  859.  
  860.     return ret;
  861. }
  862. /*FDB**************************************************
  863. Function:        VFTell
  864. Inputs:            handle of a file opened using VFOpen()
  865. Outputs:        
  866. Return:            long file position from start of file in bytes
  867. Assumptions:    
  868. See Also:        VFOpen, VFLSeek
  869. ******************************************************/
  870.  
  871. long FARFNCT VFTell( FHANDLE fileHandle )
  872. {
  873.     int index = fileHandle & ~HANDLE_MASK;
  874.     long ret;
  875.     TFile NEAR *npFile;
  876.  
  877.     nLastError = ENONE;
  878.     errno = 0;
  879.  
  880.     if (fileHandle == BADFHANDLE)
  881.     {
  882.         nLastError = EHANDLE;
  883.         ret = -1L;
  884.     }
  885.     else if (FILEDESCRIPTOR((npFile = npFileArray + index)) == CLOSED_FILE)
  886.     {
  887.         nLastError = ECLOSED;
  888.         ret = -1L;    /* file not open */
  889.     }
  890.     else if (FILETYPE( npFile ) != USER_FILE)
  891.     {
  892.         nLastError = ENOTUSER;
  893.         ret = -1L;    /* trying to close non-user file */
  894.     }
  895.     else if ((ret = FILEOFFSET( npFile )) == -1L)
  896.         nLastError = EPOS;
  897.  
  898.     return ret;
  899. }
  900. /*FDB**************************************************
  901. Function:        VFLocking
  902. Inputs:            file handle returned by VFOpen
  903.                 int specifying type of lock desired
  904.                 long # of bytes in file to be locked; 0 means to CURRENT
  905.                     end of file
  906. Outputs:        
  907. Return:            TRUE if lock is granted else FALSE
  908. Assumptions:    the lock begins at the current position in the
  909.                 file as specified by VFTell()
  910. See Also:        VFOpen, VFTell
  911. ******************************************************/
  912.  
  913. BOOL FARFNCT VFLocking(    FHANDLE fileHandle,\
  914.                         int LockType, \
  915.                         long numBytes )
  916. {
  917.     int index = fileHandle & ~HANDLE_MASK;
  918.     BOOL ret = TRUE;
  919.     TFile NEAR *npFile;
  920.  
  921.     nLastError = ENONE;
  922.     errno = 0;
  923.  
  924.     if (fileHandle == BADFHANDLE)
  925.     {
  926.         nLastError = EHANDLE;
  927.         ret = FALSE;
  928.     }
  929.     else if (FILEDESCRIPTOR((npFile = npFileArray + index)) == CLOSED_FILE)
  930.     {
  931.         nLastError = ECLOSED;
  932.         ret = FALSE;    /* file not open */
  933.     }
  934.     else if (FILETYPE( npFile ) != USER_FILE)
  935.     {
  936.         nLastError = ENOTUSER;
  937.         ret = FALSE;    /* trying to close non-user file */
  938.     }
  939.     else if (FILEOFFSET(npFile) == -1L)
  940.     {
  941.         nLastError = EPOS;
  942.         ret = -1L;
  943.     }
  944.     else if (LockType != UNLOCK_BYTES &&
  945.         LockType != SHARED_LOCK &&
  946.         LockType != EXCLUSIVE_LOCK)
  947.     {
  948.         nLastError = ELTYPE;
  949.         ret = FALSE;
  950.     }
  951.     else {
  952. #ifdef MSC51_ENV
  953.         long lPos;
  954.  
  955.         if (LSEEK( FILEDESCRIPTOR( npFile ),
  956.                 FILEOFFSET( npFile ), 0, &lPos ) == ERROR_CODE ||
  957.             lPos != FILEOFFSET( npFile ))
  958.         {
  959.             nLastError = ESEEK;
  960.             ret = FALSE;
  961.         }
  962.         else if (locking( FILEDESCRIPTOR( npFile ),
  963.                 (LockType == UNLOCK_BYTES ? LK_UNLCK : LK_LOCK),
  964.                 numBytes ) != 0)
  965.         {
  966.             nLastError = ELOCK;
  967.             ret = FALSE;
  968.         }
  969. #endif    /* MSC51_ENV */
  970.  
  971. #ifdef TURBOC_ENV
  972.         if ((LockType == SHARED_LOCK || LockType == EXCLUSIVE_LOCK))
  973.         {
  974.             if (lock( FILEDESCRIPTOR( npFile ),
  975.                 FILEOFFSET( npFile ), numBytes ) != 0)
  976.             {
  977.                 nLastError = ELOCK;
  978.                 ret = FALSE;
  979.             }
  980.         }
  981.         else if (unlock( FILEDESCRIPTOR( npFile ),
  982.                 FILEOFFSET( npFile ), numBytes ) != 0)
  983.         {
  984.             nLastError = ELOCK;
  985.             ret = FALSE;
  986.         }
  987. #endif    /* TURBOC_ENV */
  988.  
  989. #ifdef UNIX_ENV
  990.         struct flock FLock;
  991.  
  992.         FLock.l_type = (LockType == SHARED_LOCK ? F_RDLCK :
  993.                     (LockType == EXCL_LOCK ? F_WRLCK : F_UNLCK ));
  994.         FLock.l_whence = 0;
  995.         FLock.l_start = FILEOFFSET( npFile );
  996.         FLock.l_len = numBytes;
  997.  
  998.         if (fcntl( FILEDESCRIPTOR( npFile ), F_SETLKW , &FLock ) == -1)
  999.         {
  1000.             nLastError = ELOCK;
  1001.             ret = FALSE;
  1002.         }
  1003. #endif    /* UNIX_ENV */
  1004.     }
  1005.  
  1006.     return ret;
  1007. }
  1008. /*FDB**************************************************
  1009. Function:        VFChangeSize
  1010. Inputs:            file handle returned from VFOpen()
  1011.                 long new size of file in bytes
  1012. Outputs:        
  1013. Return:            TRUE if file's size is changed to desired value
  1014.                 FALSE if file's size could not be changed
  1015. Assumptions:    If file's size is INCREASED, 0s are written to the
  1016.                 new bytes.  If the size is DECREASED, the bytes at
  1017.                 the END of the file are moved to the associated transaction
  1018.                 file (if one exists).
  1019. See Also:        VFOpen
  1020. ******************************************************/
  1021.  
  1022. BOOL FARFNCT VFChangeSize(    FHANDLE fileHandle, \
  1023.                             long lNewSize )
  1024. {
  1025.     int index = fileHandle & ~HANDLE_MASK;
  1026.     BOOL ret = TRUE;
  1027.     TFile NEAR *npFile;
  1028.     long lFileLength;
  1029.  
  1030.     nLastError = ENONE;
  1031.     errno = 0;
  1032.  
  1033.     if (fileHandle == BADFHANDLE)
  1034.     {
  1035.         nLastError = EHANDLE;
  1036.         ret = FALSE;
  1037.     }
  1038.     else if (FILEDESCRIPTOR((npFile = npFileArray + index)) == CLOSED_FILE)
  1039.     {
  1040.         nLastError = ECLOSED;
  1041.         ret = FALSE;    /* file not open */
  1042.     }
  1043.     else if (FILETYPE( npFile ) != USER_FILE)
  1044.     {
  1045.         nLastError = ENOTUSER;
  1046.         ret = FALSE;    /* trying to change size of a non-user file */
  1047.     }
  1048.     else if (FILEINDEX( npFile ) == BADFHANDLE)
  1049.     {
  1050.         /* no related transaction file; issue system change size */
  1051.         if ((ret = (CHSIZE( FILEDESCRIPTOR( npFile ) , lNewSize ) ==
  1052.                 ERROR_CODE ? FALSE : TRUE )) == FALSE)
  1053.             nLastError = ECHSIZ;
  1054.     }
  1055.     else {
  1056.         /* must track the size change */
  1057.         if (LSEEK( FILEDESCRIPTOR( npFile ), 0L, 2, &lFileLength ) ==
  1058.             ERROR_CODE)
  1059.         {
  1060.             nLastError = ESEEK;
  1061.             ret = FALSE;
  1062.         }
  1063.         else if (lFileLength != lNewSize)
  1064.         {
  1065.             if (labs(lFileLength - lNewSize) > MAXUINT)
  1066.             {
  1067.                 /* too much to be tracked */
  1068.                 nLastError = EDELTA;
  1069.                 ret = FALSE;
  1070.             }
  1071.             else if ((ret = WriteTransRecord(
  1072.                 (lFileLength < lNewSize ? APPEND_OP : OVERWR_OP),
  1073.                 (unsigned int)(lFileLength < lNewSize ?
  1074.                     (lNewSize - lFileLength) : (lFileLength - lNewSize)),
  1075.                 (lFileLength < lNewSize ? lFileLength : lNewSize ),
  1076.                 npFile)) == TRUE)
  1077.             {
  1078.                 if ((ret = (CHSIZE( FILEDESCRIPTOR( npFile ) , lNewSize ) ==
  1079.                         ERROR_CODE ? FALSE : TRUE )) == FALSE)
  1080.                     nLastError = ECHSIZ;
  1081.             }
  1082.             /* else nLastError set by WriteTransRecord() */
  1083.         }
  1084.         /* else lNewSize == lFileLength and nothing need be done */
  1085.     }
  1086.  
  1087.     return ret;
  1088. }
  1089. /*FDB**************************************************
  1090. Function:        VFStat
  1091. Inputs:            file handle from VFOpen()
  1092.                 near pointer to stat structure
  1093. Outputs:        stat structure is filled with data on the file
  1094.                 when TRUE is returned
  1095. Return:            TRUE if able to fill structure else FALSE
  1096. Assumptions:    
  1097. See Also:        VFOpen
  1098. ******************************************************/
  1099.  
  1100. BOOL FARFNCT VFStat( FHANDLE fileHandle, \
  1101.                      struct stat NEAR * npStatStruct )
  1102. {
  1103.     int index = fileHandle & ~HANDLE_MASK;
  1104.     BOOL ret = TRUE;
  1105.     TFile NEAR *npFile;
  1106.  
  1107.     nLastError = ENONE;
  1108.     errno = 0;
  1109.  
  1110.     if (fileHandle == BADFHANDLE)
  1111.     {
  1112.         nLastError = EHANDLE;
  1113.         ret = FALSE;
  1114.     }
  1115.     else if (FILEDESCRIPTOR((npFile = npFileArray + index)) == CLOSED_FILE)
  1116.     {
  1117.         nLastError = ECLOSED;
  1118.         ret = FALSE;    /* file not open */
  1119.     }
  1120.     else if (FILETYPE( npFile ) != USER_FILE)
  1121.     {
  1122.         nLastError = ENOTUSER;
  1123.         ret = FALSE;
  1124.     }
  1125.     else if (FSTAT( FILEDESCRIPTOR( npFile ),
  1126.             npStatStruct) == ERROR_CODE)
  1127.     {
  1128.         nLastError = EFSTAT;
  1129.         ret = FALSE;
  1130.     }
  1131.     return ret;
  1132. }
  1133. /*FDB**************************************************
  1134. Function:        VFLastError
  1135. Inputs:            
  1136. Outputs:        
  1137. Return:            identification value of last error encountered
  1138. Assumptions:    return value is from set of values defined in transact.h
  1139. See Also:        transact.h
  1140. ******************************************************/
  1141.  
  1142. int FARFNCT VFLastError()
  1143. {
  1144.     return nLastError;
  1145. }
  1146. /*FDB**************************************************
  1147. Function:        AddFileToTable
  1148. Inputs:            far pointer to null-terminated string
  1149.                 int file open mode
  1150.                 int file permissions
  1151.                 type of file being opened
  1152. Outputs:        
  1153. Return:            unmasked file handle on success else BADFHANDLE
  1154. Assumptions:    
  1155. See Also:        
  1156. ******************************************************/
  1157.  
  1158. static FHANDLE NEARFNCT AddFileToTable(    char FAR *lpcName, int mode,
  1159.                                         int perms, BOOL bFileType )
  1160. {
  1161.     int fd;
  1162.     FHANDLE index;
  1163.     TFile NEAR *npFile;
  1164.     char NEAR *npFileName;
  1165.  
  1166. #ifdef MIXED_MODEL
  1167.     char nearName[ _LPN_MAX_ + _LFN_MAX_ ];
  1168.  
  1169.     FSTRCPY( nearName, lpcName );
  1170.     npFileName = nearName;
  1171. #else
  1172.     npFileName = lpcName;    /* both are default sized pointers */
  1173. #endif    /* !MIXED_MODEL */
  1174.  
  1175.     if (npFileArray == (TFile NEAR *)0)
  1176.     {
  1177.         /* array has never been allocated */
  1178.         if ((npFileArray =
  1179.             (TFile NEAR *)MALLOC( INCR_COUNT * sizeof(TFile) )) ==
  1180.             (TFile NEAR *)0)
  1181.         {
  1182.             nLastError = EMALLOC;
  1183.             return BADFHANDLE;
  1184.         }
  1185.  
  1186.         /* initialize the new array elements */
  1187.         for (index = (FHANDLE)0,
  1188.                 npFile = npFileArray,
  1189.                 nArrayElements += INCR_COUNT;
  1190.             index < nArrayElements;
  1191.             ++index, ++npFile)
  1192.         {
  1193.             FILEOFFSET( npFile ) = 0L;
  1194.             FILEDESCRIPTOR( npFile ) = CLOSED_FILE;
  1195.             FILEMODE( npFile ) = FILEPERMS( npFile ) = 0;
  1196.             FILEINDEX( npFile ) = BADFHANDLE;
  1197.             FILETYPE( npFile ) = BAD_FTYPE;
  1198.             FILENAME( npFile ) = (char NEAR *)0;
  1199.         }
  1200.  
  1201.         /* 1st free element is the first element */
  1202.         index = 0;
  1203.         npFile = npFileArray;
  1204.     }
  1205.     else if (nElementsInUse == nArrayElements)
  1206.     {
  1207.         /* the array must be made bigger */
  1208.         if ((npFileArray =
  1209.             (TFile NEAR *)REALLOC( (char NEAR *)npFileArray,
  1210.                 (nArrayElements + INCR_COUNT) * sizeof(TFile) )) ==
  1211.             (TFile NEAR *)0)
  1212.         {
  1213.             nLastError = EREALLOC;
  1214.             return BADFHANDLE;
  1215.         }
  1216.  
  1217.         /* initialize the new array elements */
  1218.         for (index = (FHANDLE)nArrayElements,
  1219.                 npFile = npFileArray + nArrayElements;
  1220.             index < nArrayElements + INCR_COUNT;
  1221.             ++index, ++npFile)
  1222.         {
  1223.             FILEOFFSET( npFile ) = 0L;
  1224.             FILEDESCRIPTOR( npFile ) = CLOSED_FILE;
  1225.             FILEMODE( npFile ) = FILEPERMS( npFile ) = 0;
  1226.             FILEINDEX( npFile ) = BADFHANDLE;
  1227.             FILETYPE( npFile ) = BAD_FTYPE;
  1228.             FILENAME( npFile ) = (char NEAR *)0;
  1229.         }
  1230.  
  1231.         /* indicate the 1st free array element */
  1232.         npFile = npFileArray + nArrayElements;
  1233.         index = nArrayElements;
  1234.         nArrayElements += INCR_COUNT;
  1235.     }
  1236.     else {
  1237.         /* locate an unused entry in the file table. */
  1238.         /* It's guaranteed at least 1 is available.  */
  1239.         for (index = (FHANDLE)0,
  1240.                 npFile = npFileArray;
  1241.             index < nArrayElements;
  1242.             ++index, ++npFile)
  1243.         {
  1244.             if (FILEDESCRIPTOR( npFile ) == CLOSED_FILE)
  1245.                 break;
  1246.         }
  1247.     }
  1248.  
  1249.     if (OPEN( npFileName, mode, perms, &fd ) == ERROR_CODE)
  1250.     {
  1251.         nLastError = EOPEN;
  1252.         return BADFHANDLE;
  1253.     }
  1254.  
  1255.     if ((FILENAME( npFile ) =
  1256.         (char NEAR *)STRDUP( npFileName )) == (char NEAR *)0)
  1257.     {
  1258.         (void)CLOSE( fd );
  1259.         nLastError = ESTRDUP;
  1260.         return BADFHANDLE;
  1261.     }
  1262.  
  1263.     FILEOFFSET( npFile ) = 0L;
  1264.     FILEMODE( npFile ) = mode & ~NEW_FILE;
  1265.     FILEPERMS( npFile ) = perms;
  1266.     FILEINDEX( npFile ) = BADFHANDLE;
  1267.     FILEDESCRIPTOR( npFile ) = fd;
  1268.     FILETYPE( npFile ) = bFileType;
  1269.  
  1270.     ++nElementsInUse;
  1271.     return index;
  1272. }
  1273. /*FDB**************************************************
  1274. Function:        WriteTransRecord
  1275. Inputs:            short operation ID
  1276.                 unsigned int number of bytes to be tracked
  1277.                 long offset of first byte to track (or current file length)
  1278.                 near pointer to user file structure
  1279. Outputs:        
  1280. Return:            FALSE if unable to successfully track the change described
  1281.                 TRUE if necessary transaction records are written to the
  1282.                 log file
  1283. Assumptions:    the file structure contains the FHANDLE of the trans. file
  1284.                 to be used.  Will output multiple transaction records
  1285.                 to the trans file if this is required by the operation
  1286.                 being undertaken.
  1287. See Also:        RollBack
  1288. ******************************************************/
  1289.  
  1290. static BOOL NEARFNCT WriteTransRecord( short sOp, unsigned int numBytes,
  1291.             long lUserOffset, TFile NEAR *npFile )
  1292. {
  1293.     char NEAR *npDataArea;
  1294.     char XFerBuffer[ XFER_SIZE ];
  1295.     char NEAR *npNameBuff = (char NEAR *)(XFerBuffer +
  1296.         sizeof(unsigned int));
  1297.     int bytesXFerred = 0;
  1298.     int nameLen = strlen( FILENAME( npFile ) ) + 1;    /* count the NULL */
  1299.             /* safe to use strelen() since name is in data segment. */
  1300.     int dataAreaSize = sizeof(XFerBuffer) - sizeof( unsigned int ) -
  1301.         nameLen - sizeof( TRollBackStruct );
  1302.     unsigned int bytesToXFer;
  1303.     unsigned int bytesReadWrite;
  1304.     long lPos;
  1305.     long lOffset;
  1306.     BOOL ret = TRUE;
  1307.     TRollBackStruct NEAR *npRBackStruct;
  1308.     TFile NEAR *npTrans = npFileArray + FILEINDEX( npFile );
  1309.  
  1310.     (void)strcpy( npNameBuff, FILENAME( npFile ) );
  1311.     npDataArea = npNameBuff + nameLen ;
  1312.  
  1313.     if (sOp == APPEND_OP)
  1314.     {
  1315.         *(unsigned int NEAR *)XFerBuffer = (unsigned int)(
  1316.             sizeof( TRollBackStruct ) + nameLen + sizeof(unsigned int));
  1317.  
  1318.         npRBackStruct = (TRollBackStruct NEAR *)npDataArea;
  1319.         ROLLOFFSET( npRBackStruct ) = lUserOffset;    /* length of user file */
  1320.         ROLLBYTES( npRBackStruct ) = 0;    /* no data written from user file */
  1321.         ROLLMODE( npRBackStruct ) = FILEMODE( npFile );
  1322.         ROLLPERMS( npRBackStruct ) = FILEPERMS( npFile );
  1323.         ROLLOP( npRBackStruct ) = APPEND_OP;
  1324.         ROLLNAMELEN( npRBackStruct ) = nameLen;
  1325.  
  1326.         /* OK to write record to the END of the trans. file */
  1327.         /* after seeking to the end of the trans. file.     */
  1328.         if (LSEEK( FILEDESCRIPTOR( npTrans ), 0L, 2, &lPos ) == ERROR_CODE ||
  1329.             WRITE( FILEDESCRIPTOR( npTrans ),
  1330.                 XFerBuffer, *(unsigned int NEAR *)XFerBuffer,
  1331.                 &bytesXFerred ) == ERROR_CODE ||
  1332.             (unsigned int)bytesXFerred != *(unsigned int NEAR *)XFerBuffer)
  1333.         {
  1334.             FILEOFFSET( npTrans ) = -1L;
  1335.             nLastError = ETRACK;
  1336.             ret = FALSE;
  1337.         }
  1338.         else FILEOFFSET( npTrans ) += *(unsigned int NEAR *)XFerBuffer;
  1339.     }
  1340.     else {
  1341.         /* OVERWR_OP */
  1342.         if (LSEEK( FILEDESCRIPTOR( npFile ), lUserOffset, 0,
  1343.                 &lOffset ) == ERROR_CODE ||
  1344.             lOffset != lUserOffset)
  1345.         {
  1346.             FILEOFFSET( npFile ) = -1L;
  1347.             nLastError = ETRACK;
  1348.             ret = FALSE;
  1349.         }
  1350.         else {
  1351.             if (LSEEK( FILEDESCRIPTOR( npTrans ), 0L, 2,
  1352.                         &lPos ) == ERROR_CODE)
  1353.             {
  1354.                 FILEOFFSET( npTrans ) = -1L;
  1355.                 nLastError = ETRACK;
  1356.                 ret = FALSE;
  1357.             }
  1358.  
  1359.             for ( ;
  1360.                 ret == TRUE && (unsigned int)bytesXFerred != numBytes;
  1361.                 bytesXFerred += bytesToXFer,
  1362.                     lOffset += bytesToXFer)
  1363.             {
  1364.                 bytesToXFer = (numBytes - bytesXFerred > dataAreaSize ?
  1365.                     dataAreaSize : numBytes - bytesXFerred );
  1366.  
  1367.                 if (READ( FILEDESCRIPTOR( npFile ), npDataArea,
  1368.                         bytesToXFer, &bytesReadWrite ) == ERROR_CODE ||
  1369.                     bytesReadWrite != bytesToXFer)
  1370.                 {
  1371.                     nLastError = ETRACK;
  1372.                     ret = FALSE;
  1373.                     continue;
  1374.                 }
  1375.  
  1376.                 npRBackStruct =(TRollBackStruct NEAR *)(npDataArea +
  1377.                     bytesReadWrite);
  1378.                 ROLLOFFSET( npRBackStruct ) = lOffset;
  1379.                 ROLLBYTES( npRBackStruct ) = bytesReadWrite;
  1380.                 ROLLMODE( npRBackStruct ) = FILEMODE( npFile );
  1381.                 ROLLPERMS( npRBackStruct ) = FILEPERMS( npFile );
  1382.                 ROLLOP( npRBackStruct ) = OVERWR_OP;
  1383.                 ROLLNAMELEN( npRBackStruct ) = nameLen;
  1384.  
  1385.                 *(unsigned int NEAR *)XFerBuffer =
  1386.                     (unsigned int)(sizeof(unsigned int) +
  1387.                         sizeof(TRollBackStruct) +
  1388.                         nameLen + bytesReadWrite);
  1389.  
  1390.                 /* OK to write record to the END of the trans. file */
  1391.                 /* after seeking to the end of the trans. file.     */
  1392.                 if (WRITE( FILEDESCRIPTOR( npTrans ),
  1393.                         XFerBuffer, *(unsigned int NEAR *)XFerBuffer,
  1394.                         &bytesReadWrite ) == ERROR_CODE ||
  1395.                     bytesReadWrite != *(unsigned int NEAR *)XFerBuffer)
  1396.                 {
  1397.                     FILEOFFSET( npTrans ) = -1L;
  1398.                     nLastError = ETRACK;
  1399.                     ret = FALSE;
  1400.                     continue;
  1401.                 }
  1402.  
  1403.                 FILEOFFSET( npTrans ) +=
  1404.                     *(unsigned int NEAR *)XFerBuffer;
  1405.  
  1406.             }    /* end-for */
  1407.  
  1408.             if (ret == TRUE &&
  1409.                 LSEEK( FILEDESCRIPTOR( npFile ), lUserOffset, 0,
  1410.                     &lOffset ) == ERROR_CODE ||
  1411.                     lUserOffset != lOffset)
  1412.             {
  1413.                 FILEOFFSET( npFile ) = -1L;
  1414.                 nLastError = ETRACK;
  1415.                 ret = FALSE;
  1416.             }
  1417.         }    /* end-else */
  1418.     }
  1419.  
  1420.     if (ret == TRUE &&
  1421.             (ret = FlushFile( npTrans )) == FALSE)
  1422.         nLastError = ETRACK;
  1423.  
  1424.     return ret;
  1425. }
  1426. /*FDB**************************************************
  1427. Function:        RollBack
  1428. Inputs:            far pointer to null-terminated transaction logfile name
  1429. Outputs:        
  1430. Return:            FALSE if unable to rollback an existing transaction log file
  1431.                 TRUE if file does not exist or is successfully rolled back
  1432.                 and deleted
  1433. Assumptions:    Data in transaction file is a collection of records of the
  1434.                 following format:
  1435.                     Entry Length (unsigned int)
  1436.                     User filename (char[])
  1437.                     Data from user file (char [])
  1438.                     TRollBackStruct
  1439. See Also:        VFWrite, WriteTransRecord
  1440. ******************************************************/
  1441.  
  1442. BOOL FARFNCT RollBack( char FAR *lpTransName )
  1443. {
  1444.     int TransFD, UserFD;
  1445.     char NEAR *npTransName;
  1446.     char NEAR *npDataArea;
  1447.     char XFerBuffer[ XFER_SIZE ];
  1448.     char NEAR *npNameBuff = (char NEAR *)(XFerBuffer +
  1449.         sizeof(unsigned int));
  1450.     unsigned int bytesToXFer;
  1451.     unsigned int bytesReadWrite;
  1452.     long lPos;
  1453.     long lOffset;
  1454.     BOOL ret = TRUE;
  1455.     TRollBackStruct RBackStruct;
  1456.  
  1457. #ifdef MIXED_MODEL
  1458.     char nearName[ _LPN_MAX_ + _LFN_MAX_ ];
  1459.  
  1460.     FSTRCPY( nearName, lpTransName );
  1461.     npTransName = nearName;
  1462. #else
  1463.     npTransName = lpTransName;    /* both are default sized pointers */
  1464. #endif    /* !MIXED_MODEL */
  1465.  
  1466.     nLastError = ENONE;
  1467.     errno = 0;
  1468.  
  1469.     /* open the transaction log file */
  1470.     if (OPEN( npTransName, READ_FILE | BINARY_FILE,
  1471.         SHARED_FILE, &TransFD ) == ERROR_CODE)
  1472.     {
  1473.         if (errno == ENOENT)
  1474.             return TRUE;    /* trans. file doesn't exist */
  1475.         nLastError = EOPEN;
  1476.         return FALSE;
  1477.     }
  1478.  
  1479.     /* trans. file is open; roll it back */
  1480.     if (LSEEK( TransFD, 0L, 0, &lOffset ) == ERROR_CODE)
  1481.     {
  1482.         (void) CLOSE( TransFD );
  1483.         nLastError = ESEEK;
  1484.         return FALSE;
  1485.     }
  1486.  
  1487.     /* read each record in the trans. file to find the */
  1488.     /* last complete record (lPos == end of last one). */
  1489.     do {
  1490.         /* get the record's total length field */
  1491.         if (READ( TransFD, XFerBuffer, sizeof(unsigned int),
  1492.                 &bytesReadWrite ) == ERROR_CODE)
  1493.         {
  1494.             (void)CLOSE( TransFD );
  1495.             nLastError = EROLL;
  1496.             return FALSE;
  1497.         }
  1498.  
  1499.         if (bytesReadWrite != (unsigned int)sizeof(unsigned int))
  1500.             break;    /* incomplete record */
  1501.  
  1502.         /* get the name, data and structure of record */
  1503.         if (READ( TransFD, npNameBuff,
  1504.             (bytesToXFer = *(unsigned int NEAR *)XFerBuffer) -
  1505.                 (unsigned int)sizeof(unsigned int),
  1506.             &bytesReadWrite ) == ERROR_CODE)
  1507.         {
  1508.             (void)CLOSE( TransFD );
  1509.             nLastError = EROLL;
  1510.             return FALSE;
  1511.         }
  1512.  
  1513.         if (bytesReadWrite != bytesToXFer -
  1514.                 (unsigned int)sizeof(unsigned int))
  1515.             break;
  1516.  
  1517.         /* read a complete transaction record */
  1518.         lOffset += (long)bytesToXFer;
  1519.     }
  1520.     while (bytesReadWrite == bytesToXFer -
  1521.         (unsigned int)sizeof(unsigned int));
  1522.  
  1523.     /* if lOffset > 0L, at least one valid transaction record exists */
  1524.     while (lOffset > 0L)
  1525.     {
  1526.         /* back up and read the rollback control structure */
  1527.         if (LSEEK( TransFD, (lOffset -= (long)sizeof(TRollBackStruct)), 0,
  1528.                 &lPos ) == ERROR_CODE ||
  1529.             lPos != lOffset)
  1530.         {
  1531.             (void)CLOSE( TransFD );
  1532.             nLastError = EROLL;
  1533.             return FALSE;
  1534.         }
  1535.  
  1536.         if (READ( TransFD, (VOID NEAR *)&RBackStruct,
  1537.                 sizeof(TRollBackStruct), &bytesReadWrite ) == ERROR_CODE ||
  1538.             bytesReadWrite != sizeof(TRollBackStruct))
  1539.         {
  1540.             (void)CLOSE( TransFD );
  1541.             nLastError = EROLL;
  1542.             return FALSE;
  1543.         }
  1544.  
  1545.         /* back up to the beginning of the transaction record and read it */
  1546.         if (LSEEK( TransFD,
  1547.             (lOffset -= (long)((bytesToXFer = sizeof(unsigned int) +
  1548.                 ROLLBYTES( &RBackStruct ) + ROLLNAMELEN( &RBackStruct )))),
  1549.                 0, &lPos ) == ERROR_CODE ||
  1550.             lPos != lOffset)
  1551.         {
  1552.             (void)CLOSE( TransFD );
  1553.             nLastError = EROLL;
  1554.             return FALSE;
  1555.         }
  1556.  
  1557.         if (READ( TransFD, (VOID NEAR *)XFerBuffer, bytesToXFer,
  1558.                 &bytesReadWrite ) == ERROR_CODE ||
  1559.             bytesReadWrite != bytesToXFer)
  1560.         {
  1561.             (void)CLOSE( TransFD );
  1562.             nLastError = EROLL;
  1563.             return FALSE;
  1564.         }
  1565.  
  1566.         /* open the user data file with old permissions */
  1567.         if (OPEN( npNameBuff, ROLLMODE( &RBackStruct ),
  1568.             ROLLPERMS( &RBackStruct ), &UserFD ) == ERROR_CODE)
  1569.         {
  1570.             (void)CLOSE( TransFD );
  1571.             nLastError = EROLL;
  1572.             return FALSE;
  1573.         }
  1574.  
  1575.         if (ROLLOP( &RBackStruct ) == APPEND_OP)
  1576.         {
  1577.             /* change file size to ROLLOFFSET() */
  1578.             /* NOTE: SCO Unix does not provide a chsize() fnct */
  1579.             /* so simply ignore the append op rollback.        */
  1580. #ifndef SCOUNIX_ENV
  1581.             if (CHSIZE( UserFD, ROLLOFFSET( &RBackStruct ) ) == ERROR_CODE)
  1582.             {
  1583.                 (void)CLOSE( TransFD );
  1584.                 (void)CLOSE( UserFD );
  1585.                 nLastError = EROLL;
  1586.                 return FALSE;
  1587.             }
  1588. #endif    /* !SCOUNIX_ENV */
  1589.         }
  1590.         else {
  1591.             /* write data from trans record back to user file */
  1592.             if (LSEEK( UserFD, ROLLOFFSET( &RBackStruct ),
  1593.                     0, &lPos ) == ERROR_CODE ||
  1594.                 lPos != ROLLOFFSET( &RBackStruct ))
  1595.             {
  1596.                 (void)CLOSE( TransFD );
  1597.                 (void)CLOSE( UserFD );
  1598.                 nLastError = EROLL;
  1599.                 return FALSE;
  1600.             }
  1601.  
  1602.             npDataArea = npNameBuff + ROLLNAMELEN( &RBackStruct );
  1603.  
  1604.             if (WRITE( UserFD, npDataArea,
  1605.                     ROLLBYTES( &RBackStruct ),
  1606.                     &bytesReadWrite ) == ERROR_CODE ||
  1607.                 bytesReadWrite != ROLLBYTES( &RBackStruct ))
  1608.             {
  1609.                 (void)CLOSE( TransFD );
  1610.                 (void)CLOSE( UserFD );
  1611.                 nLastError = EROLL;
  1612.                 return FALSE;
  1613.             }
  1614.             (void)CLOSE( UserFD );
  1615.         }    /* overwrite operation */
  1616.     }    /* end-while */
  1617.  
  1618.     /* close and delete the transaction log file */
  1619.     (void)CLOSE( TransFD );
  1620.     if ((ret = (UNLINK( npTransName ) == ERROR_CODE ? FALSE : TRUE)) == FALSE)
  1621.         nLastError = EUNLINK;
  1622.  
  1623.     return ret;
  1624. }
  1625.  
  1626. #ifdef MIXED_MODEL
  1627.     /*FDB**************************************************
  1628.     Function:        farStrcpy
  1629.     Inputs:            far pointer to destination buffer
  1630.                     far pointer to null-terminated string
  1631.     Outputs:        copy of string is placed into buffer w/null terminator
  1632.     Return:            
  1633.     Assumptions:    the destination buffer is large enough to hold the
  1634.                     string
  1635.     See Also:        farStrlen
  1636.     ******************************************************/
  1637.  
  1638.     void NEARFNCT farStrcpy(char FAR *lpcDest, char FAR *lpcSource)
  1639.     {
  1640.         int nLoop;
  1641.  
  1642.         for (nLoop = 0;
  1643.             nLoop < _LPN_MAX_ + _LFN_MAX_ - 1 &&
  1644.                 (*lpcDest++ = *lpcSource++) != '\0';
  1645.             ++nLoop)
  1646.                 ;
  1647.  
  1648.         *lpcDest = '\0';    /* guarantee a null terminator */
  1649.     }
  1650. #endif    /* MIXED_MODEL */
  1651.  
  1652. #ifdef MIXED_MODEL
  1653.     /*FDB**************************************************
  1654.     Function:        farStrlen
  1655.     Inputs:            far pointer to null-terminated string
  1656.     Outputs:        
  1657.     Return:            the length of the string
  1658.     Assumptions:    
  1659.     See Also:        farStrcpy
  1660.     ******************************************************/
  1661.  
  1662.     int NEARFNCT farStrlen(char FAR *lpcString )
  1663.     {
  1664.         int nLoop;
  1665.  
  1666.         for (nLoop = 0;
  1667.             *lpcString++ != '\0';
  1668.             ++nLoop)
  1669.                 ;
  1670.  
  1671.         return nLoop;
  1672.     }
  1673. #endif    /* MIXED_MODEL */
  1674.  
  1675. #ifdef NEED_FLUSH
  1676.     /*FDB**************************************************
  1677.     Function:        FlushFile
  1678.     Inputs:            near pointer to a file structure in the file array
  1679.     Outputs:        
  1680.     Return:            TRUE if able to successfully flush the contents of
  1681.                     the file to disk else FALSE
  1682.     Assumptions:    
  1683.     See Also:        
  1684.     ******************************************************/
  1685.  
  1686.     static BOOL NEARFNCT FlushFile( TFile NEAR *npFile )
  1687.     {
  1688.         int newFD;
  1689.  
  1690.         if (CLOSE( FILEDESCRIPTOR( npFile )) == ERROR_CODE)
  1691.         {
  1692.             nLastError = ECLOSE;
  1693.             return FALSE;
  1694.         }
  1695.  
  1696.         if (OPEN( FILENAME( npFile ),
  1697.             FILEMODE( npFile ) & ~NEW_FILE ,
  1698.             FILEPERMS( npFile ),
  1699.             &newFD ) == ERROR_CODE)
  1700.         {
  1701.             nLastError = EOPEN;
  1702.             return FALSE;
  1703.         }
  1704.  
  1705.         FILEDESCRIPTOR( npFile ) = newFD;
  1706.         return TRUE;
  1707.  
  1708. }
  1709. #endif    /* NEED_FLUSH */
  1710.