|
|
/*************************************************************************
* * * IOFTS.C * * * * Copyright (C) Microsoft Corporation 1990-1994 * * All Rights reserved. * * * ************************************************************************** * * * Module Intent * * Provide disk I/O for various types of files currently supported, * * which include: FS system file, FS subfile, regular files * * The I/O functions supported are: * * - File exist * * - File open, create * * - File seek/write * * - File sequential write * * - File seek/read * * - File sequential read * * - File close * * * * Comments: * * There are some PLATFORM DEPENDENT codes in the modules for * * calls such as _lopen, _lread, _lwrite. * * There are calls that are not supported, such as create a * * regular DOS file, since we never use them. Those calls can be * * implemented when the need arises * ************************************************************************** * * * Written By : Binh Nguyen * * Current Owner: Binh Nguyen * * * **************************************************************************/
#include <mvopsys.h>
#include <mem.h>
#include <misc.h>
//#include <mvsearch.h>
#include <iterror.h>
#include <wrapstor.h>
#include <io.h>
#include <fcntl.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <string.h>
#include <_mvutil.h>
#include "iofts.h"
#ifdef _DEBUG
static BYTE NEAR s_aszModule[] = __FILE__; // Used by error return functions.
#endif
PRIVATE HANDLE NEAR PASCAL IoftsWin32Create(LPCSTR lpstr, DWORD w); PRIVATE HANDLE NEAR PASCAL IoftsWin32Open(LPCSTR lpstr, DWORD w);
#ifdef _WIN32
#define CREAT(sz, w) IoftsWin32Create(sz, w)
#define OPEN(sz, w) IoftsWin32Open(sz, w)
#define _COMMIT(hfile) (FlushFileBuffers(hfile) ? 0 : GetLastError())
/* seek origins */ #if !defined(wFSSeekSet)
#define wFSSeekSet FILE_BEGIN
#define wFSSeekCur FILE_CURRENT
#define wFSSeekEnd FILE_END
#endif // !defined(wFSSeekSet)
#else // if ! _NT
#define CREAT _lcreat
#define OPEN _lopen
#define _COMMIT _commit
/* seek origins */ #define wFSSeekSet 0
#define wFSSeekCur 1
#define wFSSeekEnd 2
#endif // ! _NT
#define OPENED_HFS (BYTE)0x80
/*************************************************************************
* INTERNAL PRIVATE FUNCTIONS * * Those functions should be declared NEAR *************************************************************************/
// return pointer to portion of filename after !
// fill lszTemp with copy of first half before !
LPCSTR NEAR PASCAL GetSubFilename(LPCSTR lszFilename, LSZ lszTemp) { LSZ lszTempOriginal = lszTemp; LPCSTR lszFilenameOriginal=lszFilename;
if (lszTemp) { while ((*lszFilename) && (*lszFilename!='!')) { *lszTemp++=*lszFilename++; } *lszTemp=0x00; } else { while ((*lszFilename) && (*lszFilename!='!')) { lszFilename++; } }
if (*lszFilename=='!') lszFilename++;
if (!*lszFilename) { if (lszTempOriginal) *lszTempOriginal=0x00; lszFilename=lszFilenameOriginal; } return lszFilename; }
LPSTR FAR PASCAL CreateDefaultFilename(LPCSTR szFilename, LPCSTR szDefault, LPSTR szFullName) { LPCSTR szSubFilename = GetSubFilename(szFilename,szFullName); // Use default if no "!" was found.
if (!*szFullName) wsprintf(szFullName,"%s!%s",szFilename,szDefault); else lstrcpy(szFullName,szFilename); return szFullName; }
// Get an Hfs based on HFPB and Filename
// if bCreate==FALSE, open for READ ONLY
// if bCreate==TRUE, open for READ WRITE (create if non existant)
HFS FAR PASCAL HfsFromHfpb(HFPB hfpb) { LPFPB lpfpbFS; HFS hfs=NULL;
if (!hfpb) return NULL; lpfpbFS = (LPFPB)_GLOBALLOCK(hfpb); _ENTERCRITICALSECTION(&lpfpbFS->cs); hfs=lpfpbFS->fs.hfs; _LEAVECRITICALSECTION(&lpfpbFS->cs); _GLOBALUNLOCK(hfpb); return hfs; }
HFS FAR PASCAL GetHfs(HFPB hfpbSysFile, LPCSTR lszFilename, BOOL bCreate, PHRESULT phr) { HFS hfs = NULL; if (!hfpbSysFile) { BYTE lszTemp[cbMAX_PATH]; LPCSTR lszSubFilename; lszSubFilename=GetSubFilename(lszFilename,lszTemp); if (*lszSubFilename) { FM fm; fm = FmNewSzDir((LPSTR)lszTemp, dirCurrent, NULL); if (bCreate) { hfs = HfsOpenFm(fm, FSH_READWRITE, phr); if (!hfs) { if (!FileExist(NULL, lszTemp, FS_SYSTEMFILE)) { hfs = HfsCreateFileSysFm(fm, NULL, phr); } } } else hfs = HfsOpenFm(fm, FSH_READONLY, phr);
DisposeFm(fm); } else SetErrCode(phr,E_INVALIDARG); } else { LPFPB lpfpbFS = (LPFPB)_GLOBALLOCK(hfpbSysFile); _ENTERCRITICALSECTION(&lpfpbFS->cs); hfs=lpfpbFS->fs.hfs; if (!hfs) SetErrCode(phr,E_ASSERT); _LEAVECRITICALSECTION(&lpfpbFS->cs); _GLOBALUNLOCK(hfpbSysFile); }
return hfs; }
// if hfpbSysFile==NULL, and fFileType==FS_SUBFILE, then
// lszFilename must contain filesys!subfile
PUBLIC HRESULT FAR PASCAL FileExist (HFPB hfpbSysFile, LPCSTR lszFilename, int fFileType) { HFS hfs=NULL; FM fm; HRESULT errb; HRESULT rc=E_ASSERT;
if (lszFilename == NULL ) { SetErrCode (&errb, E_INVALIDARG); return 0; }
errb=S_OK;
switch (fFileType) { case FS_SYSTEMFILE:
fm = FmNewSzDir((LPSTR)lszFilename, dirCurrent, NULL); if (FExistFm(fm)) errb=S_OK; else errb=E_NOTEXIST; DisposeFm(fm);
break;
case FS_SUBFILE: hfs = GetHfs(hfpbSysFile,lszFilename,FALSE,&errb);
if (hfs) { if (FAccessHfs(hfs,GetSubFilename(lszFilename,NULL), FACCESS_EXISTS,&errb)) rc=S_OK; else rc = errb; // if it wasn't given to us above, remove it now
if (!hfpbSysFile) RcCloseHfs(hfs); } else rc=errb; break; case REGULAR_FILE: /* There is no need to call this function for DOS files. */
fm = FmNewSzDir((LPSTR)lszFilename, dirCurrent, NULL); if (FExistFm(fm)) errb=S_OK; else errb=E_NOTEXIST; DisposeFm(fm); break;
default: SetErrCode(&errb,E_INVALIDARG); return 0; }
return errb; }
#ifndef ITWRAP
PUBLIC HFPB FAR PASCAL FileCreate (HFPB hfpbSysFile, LPCSTR lszFilename, int fFileType, PHRESULT phr) { LPFPB lpfpb; /* Pointer to file parameter block */ FM fm; //HRESULT rc; /* Default open error code */
HANDLE hMem; HFPB hfpb;
/* Check for valid filename */ if (lszFilename == NULL ) { SetErrCode (phr, E_INVALIDARG); return 0; }
/* Allocate a file's parameter block */ if (!(hMem = _GLOBALALLOC(GMEM_ZEROINIT, sizeof(FPB)))) { SetErrCode(phr,ERR_MEMORY); return NULL; }
if (!(lpfpb = (LPFPB)_GLOBALLOCK(hMem))) { _GLOBALUNLOCK(hMem); SetErrCode(phr,ERR_MEMORY); return NULL; }
_INITIALIZECRITICALSECTION(&lpfpb->cs); lpfpb->hStruct=hMem;
switch (fFileType) { case FS_SYSTEMFILE: fm = FmNewSzDir((LPSTR)lszFilename, dirCurrent, NULL); lpfpb->fs.hfs = HfsCreateFileSysFm(fm, NULL, phr); DisposeFm(fm); if (lpfpb->fs.hfs== NULL) { goto ErrorExit; } break;
case FS_SUBFILE: { HFS hfs = GetHfs(hfpbSysFile,lszFilename,TRUE,phr); if (hfs) { lpfpb->fs.hf = HfCreateFileHfs(hfs,GetSubFilename(lszFilename, NULL),HFOPEN_READWRITE,phr); lpfpb->ioMode = OF_READWRITE; if (lpfpb->fs.hf == 0) { if (!hfpbSysFile) RcCloseHfs(hfs); goto ErrorExit; } else { if (!hfpbSysFile) lpfpb->ioMode|=OPENED_HFS; } } else { goto ErrorExit; } break; } case REGULAR_FILE: /* Open the file */ /* PLATFORM DEPENDENT code: _lcreat */ if ((lpfpb->fs.hFile = (HFILE_GENERIC)CREAT (lszFilename, 0)) == HFILE_GENERIC_ERROR) { SetErrCode(phr,ERR_FILECREAT_FAILED); goto ErrorExit; } lpfpb->ioMode = OF_READWRITE; break; }
/* Set the filetype */ lpfpb->fFileType = fFileType;
_GLOBALUNLOCK(hfpb = lpfpb->hStruct); return hfpb;
ErrorExit: _DELETECRITICALSECTION(&lpfpb->cs); _GLOBALFREE(hMem); return 0; } #endif
#ifndef ITWRAP
PUBLIC HFPB FAR PASCAL FileOpen (HFPB hfpbSysFile, LPCSTR lszFilename, int fFileType, int ioMode, PHRESULT phr) { LPFPB lpfpb; /* Pointer to file parameter block */ FM fm; //HRESULT rc; /* Default open error code */
HANDLE hMem; HFPB hfpb;
/* Check for valid filename */ if (lszFilename == NULL ) { SetErrCode (phr, E_INVALIDARG); return 0; }
/* Allocate a file's parameter block */ if (!(hMem = _GLOBALALLOC(GMEM_ZEROINIT, sizeof(FPB)))) { SetErrCode(phr,ERR_MEMORY); return NULL; }
if (!(lpfpb = (LPFPB)_GLOBALLOCK(hMem))) { _GLOBALUNLOCK(hMem); SetErrCode(phr,ERR_MEMORY); return NULL; }
_INITIALIZECRITICALSECTION(&lpfpb->cs); lpfpb->hStruct=hMem;
switch (fFileType) { case FS_SYSTEMFILE: fm = FmNewSzDir((LPSTR)lszFilename, dirCurrent, NULL); lpfpb->fs.hfs = HfsOpenFm(fm,(BYTE)((ioMode==READ)? FSH_READONLY:FSH_READWRITE), phr); DisposeFm(fm); if (lpfpb->fs.hfs== NULL) { goto ErrorExit; } break;
case FS_SUBFILE: { HFS hfs = GetHfs(hfpbSysFile,lszFilename,FALSE,phr); if (hfs) { lpfpb->fs.hf = HfOpenHfs(hfs,GetSubFilename(lszFilename, NULL),(BYTE)((ioMode==READ)?HFOPEN_READ:HFOPEN_READWRITE),phr); lpfpb->ioMode = ioMode; if (lpfpb->fs.hf == 0) { if (!hfpbSysFile) RcCloseHfs(hfs); SetErrCode (phr, E_NOTEXIST); goto ErrorExit; } else { if (!hfpbSysFile) lpfpb->ioMode|=OPENED_HFS; } } else { SetErrCode (phr, E_NOTEXIST); goto ErrorExit; } break; } case REGULAR_FILE: /* Set the IO mode and appropriate error messages */ if (ioMode == READ) { /* Open the file */ /* PLATFORM DEPENDENT code: _lopen */ if ((lpfpb->fs.hFile = (HFILE_GENERIC)OPEN (lszFilename, ioMode)) == HFILE_GENERIC_ERROR) { SetErrCode(phr,E_NOTEXIST); goto ErrorExit; }
} else { ioMode = OF_READWRITE; /* Open the file */ /* PLATFORM DEPENDENT code: _lcreat */ if ((lpfpb->fs.hFile = (HFILE_GENERIC)OPEN(lszFilename, ioMode)) == HFILE_GENERIC_ERROR) { SetErrCode(phr,ERR_FILECREAT_FAILED); goto ErrorExit; } } lpfpb->ioMode = ioMode; }
/* Set the filetype */ lpfpb->fFileType = fFileType;
_GLOBALUNLOCK(hfpb = lpfpb->hStruct); return hfpb;
ErrorExit: _DELETECRITICALSECTION(&lpfpb->cs); _GLOBALFREE(hMem); return 0; } #endif
/*************************************************************************
* @doc INTERNAL * * @func FILEOFFSET FAR PASCAL | FileSeek | * Seek to a location in a file * * @parm HFPB | hfpb | * Handle to file paramter block * * @parm FILEOFFSET | foSeek | * Location to seek to * * @parm WORD | wOrigin | * Base of seek (0=begin, 1=current, 2=end) * * @parm PHRESULT | phr | * Error buffer. * * @rdesc Returns the location actually seeked to * *************************************************************************/
PUBLIC FILEOFFSET FAR PASCAL FileSeek(HFPB hfpb, FILEOFFSET fo, WORD wOrigin, PHRESULT phr) { LPFPB lpfpb; HRESULT fCallBackRet; FILEOFFSET foSeeked=foInvalid; if (hfpb == NULL) { SetErrCode(phr, E_HANDLE); return foSeeked; } lpfpb = (LPFPB)_GLOBALLOCK(hfpb); _ENTERCRITICALSECTION(&lpfpb->cs);
/* Execute user's status functions */ if (lpfpb->lpfnfInterCb != NULL && (fCallBackRet = (*lpfpb->lpfnfInterCb)(lpfpb->lpvInterCbParms)) != S_OK) { SetErrCode(phr, fCallBackRet); goto ErrorExit; }
if (phr) *phr = S_OK; switch (lpfpb->fFileType) { case FS_SYSTEMFILE: /* We should not seek a system file */ SetErrCode(phr, E_ASSERT); goto ErrorExit; break;
case FS_SUBFILE: foSeeked=FoSeekHf(lpfpb->fs.hf,fo,wOrigin,phr); break;
case REGULAR_FILE: /* Regular files */ #ifdef _WIN32
foSeeked=fo; foSeeked.dwOffset=SetFilePointer(lpfpb->fs.hFile, fo.dwOffset, &foSeeked.dwHigh,(DWORD)wOrigin); #else
foSeeked.dwHigh=0L; foSeeked.dwOffset=(DWORD)_llseek(lpfpb->fs.hFile, fo.dwOffset, wOrigin); #endif
if (!FoEquals(fo,foSeeked)) { SetErrCode (phr, E_FILESEEK); } break; }
ErrorExit: _LEAVECRITICALSECTION(&lpfpb->cs); _GLOBALUNLOCK(hfpb); return foSeeked; }
/*************************************************************************
* @doc INTERNAL * * @func FILEOFFSET FAR PASCAL | FileSize | * Get the size of an opened file * * @parm HFPB | hfpb | * Handle to file paramter block * * @parm PHRESULT | phr | * Error buffer. * * @rdesc Returns the size of the file. If an error occurs, it returns * foInvalid, and phr contains the error info. For files under 2 gigs, * just look at the .dwOffset member of the returned file offset. * *************************************************************************/
PUBLIC FILEOFFSET FAR PASCAL FileSize(HFPB hfpb, PHRESULT phr) { LPFPB lpfpb; FILEOFFSET foSeeked=foInvalid; FILEOFFSET foTemp; if (hfpb == NULL) { SetErrCode(phr, E_HANDLE); return foSeeked; } lpfpb = (LPFPB)_GLOBALLOCK(hfpb); _ENTERCRITICALSECTION(&lpfpb->cs);
if (phr) *phr = S_OK; switch (lpfpb->fFileType) { case FS_SYSTEMFILE: /* We should not get the size of a system file */ SetErrCode(phr, E_ASSERT); goto ErrorExit; break;
case FS_SUBFILE: foSeeked=FoSizeHf(lpfpb->fs.hf, phr); break;
case REGULAR_FILE: /* Regular files */ #ifdef _WIN32
// foTemp has current file position
foTemp=foNil; foTemp.dwOffset=SetFilePointer(lpfpb->fs.hFile, 0L, &foTemp.dwHigh, FILE_CURRENT); foSeeked=foNil; foSeeked.dwOffset=SetFilePointer(lpfpb->fs.hFile, 0L, &foSeeked.dwHigh, FILE_END); SetFilePointer(lpfpb->fs.hFile,foTemp.dwOffset,&foTemp.dwHigh, FILE_BEGIN); #else
foTemp.dwHigh=0L; foTemp.dwOffset=(DWORD)_llseek(lpfpb->fs.hFile, 0L, FILE_CURRENT); foSeeked=foNil; foSeeked.dwOffset=(DWORD)_llseek(lpfpb->fs.hFile, 0L, FILE_END); _llseek(lpfpb->fs.hFile, foTemp.dwOffset, FILE_BEGIN); #endif
break; }
ErrorExit: _LEAVECRITICALSECTION(&lpfpb->cs); _GLOBALUNLOCK(hfpb); return foSeeked; }
/*************************************************************************
* @doc INTERNAL * * @func FILEOFFSET FAR PASCAL | FileOffset | * Get the offset of a file if baggage * * @parm HFPB | hfpb | * Handle to file paramter block (of baggage file) * * @parm PHRESULT | phr | * Error buffer. * * @rdesc Returns the offset the file lives inside it's parent file. * This is the offset into an M20 of a baggage file, or zero for any * other type of file. If an error occurs, it returns * foInvalid, and phr contains the error info. For files under 2 gigs, * just look at the .dwOffset member of the returned file offset. * *************************************************************************/
PUBLIC FILEOFFSET FAR PASCAL FileOffset(HFPB hfpb, PHRESULT phr) { LPFPB lpfpb; FILEOFFSET foOffset=foInvalid; if (hfpb == NULL) { SetErrCode(phr, E_HANDLE); return foOffset; } lpfpb = (LPFPB)_GLOBALLOCK(hfpb); _ENTERCRITICALSECTION(&lpfpb->cs);
if (phr) *phr = S_OK; switch (lpfpb->fFileType) { case FS_SYSTEMFILE: /* We should not get the size of a system file */ foOffset=foNil; goto ErrorExit; break;
case FS_SUBFILE: foOffset=FoOffsetHf(lpfpb->fs.hf, phr); break;
case REGULAR_FILE: /* Regular files */ foOffset=foNil; goto ErrorExit; break; }
ErrorExit: _LEAVECRITICALSECTION(&lpfpb->cs); _GLOBALUNLOCK(hfpb); return foOffset; }
/*************************************************************************
* @doc INTERNAL * * @func LONG FAR PASCAL | FileSeekRead | * Returns the number of bytes read * * @parm HFPB | hfpb | * Handle to file paramter block * * @parm LPV | lpvData | * Buffer to read into. * * @parm FILEOFFSET | foSeek | * File offset to read at. * * @parm LONG | lcbSize | * How many bytes to read. * * @parm PHRESULT | phr | * Error buffer. * * @rdesc Returns the number of bytes actually read * *************************************************************************/
PUBLIC LONG FAR PASCAL FileSeekRead(HFPB hfpb, LPV lpvData, FILEOFFSET fo, LONG lcbSize, PHRESULT phr) { LONG lRead=0L; LPFPB lpfpb; HRESULT fCallBackRet; FILEOFFSET foSeeked=foInvalid;
if (hfpb == NULL) { SetErrCode(phr, E_HANDLE); return 0L; } lpfpb = (LPFPB)_GLOBALLOCK(hfpb); _ENTERCRITICALSECTION(&lpfpb->cs);
/* Execute user's status functions */ if (lpfpb->lpfnfInterCb != NULL && (fCallBackRet = (*lpfpb->lpfnfInterCb)(lpfpb->lpvInterCbParms)) != S_OK) { SetErrCode(phr, fCallBackRet); goto ErrorExit; } if (phr) *phr = S_OK; switch (lpfpb->fFileType) { case FS_SYSTEMFILE:
/* We should not read from a system file */
SetErrCode(phr, E_ASSERT); goto ErrorExit; break;
case FS_SUBFILE: foSeeked=fo; foSeeked=FoSeekHf(lpfpb->fs.hf,fo,0,phr); if (!FoEquals(foSeeked,fo)) { SetErrCode (phr, E_FILESEEK); goto ErrorExit; } lRead=LcbReadHf(lpfpb->fs.hf, lpvData, lcbSize, phr); break; case REGULAR_FILE: /* Regular files */ /* PLATFORM DEPENDENT code: _lread */ #ifdef _WIN32
foSeeked=fo; foSeeked.dwOffset=SetFilePointer(lpfpb->fs.hFile, fo.dwOffset, &foSeeked.dwHigh,0); #else
foSeeked.dwHigh=0L; foSeeked.dwOffset=(DWORD)_llseek(lpfpb->fs.hFile, fo.dwOffset, 0); #endif
if (!FoEquals(fo,foSeeked)) { SetErrCode (phr, E_FILESEEK); goto ErrorExit; }
#ifdef _WIN32
ReadFile(lpfpb->fs.hFile, lpvData, lcbSize, &lRead, NULL); #else
lRead=_lread(lpfpb->fs.hFile, lpvData, lcbSize); #endif
break; }
ErrorExit: _LEAVECRITICALSECTION(&lpfpb->cs); _GLOBALUNLOCK(hfpb); return lRead; }
/*************************************************************************
* @doc INTERNAL * * @func WORD FAR PASCAL | FileRead | * Read a number of bytes from a file * * @parm LPV | lpvData | * Buffer to read into. * * @parm LONG | lcbSize | * How many bytes to read. * * @parm PHRESULT | phr | * Error buffer. * * @rdesc Returns the number of bytes actually read. * *************************************************************************/
PUBLIC LONG FAR PASCAL FileRead(HFPB hfpb, LPV lpvData, LONG lcbSize, PHRESULT phr) { LONG lRead=0L; LPFPB lpfpb; HRESULT fCallBackRet;
if (hfpb == NULL || lpvData == NULL) { SetErrCode(phr, E_INVALIDARG); return 0L; } lpfpb = (LPFPB)_GLOBALLOCK(hfpb); _ENTERCRITICALSECTION(&lpfpb->cs);
/* Execute user's status functions */ if (lpfpb->lpfnfInterCb != NULL && (fCallBackRet = (*lpfpb->lpfnfInterCb)(lpfpb->lpvInterCbParms)) != S_OK) { SetErrCode(phr, fCallBackRet); goto ErrorExit; } if (phr) *phr = S_OK; switch (lpfpb->fFileType) { case FS_SYSTEMFILE:
/* We should not read from a system file */
SetErrCode(phr, E_ASSERT); goto ErrorExit; break;
case FS_SUBFILE: lRead=LcbReadHf(lpfpb->fs.hf, lpvData, lcbSize, phr); break; case REGULAR_FILE: /* Regular files */ /* PLATFORM DEPENDENT code: _lread */ #ifdef _WIN32
ReadFile(lpfpb->fs.hFile, lpvData, lcbSize, &lRead, NULL); #else
lRead=_lread(lpfpb->fs.hFile, lpvData, lcbSize); #endif
break; }
ErrorExit: _LEAVECRITICALSECTION(&lpfpb->cs); _GLOBALUNLOCK(hfpb); return lRead; }
/*************************************************************************
* @doc INTERNAL * * @func int FAR PASCAL | FileSeekWrite | * Write number of bytes to a file at some specific location * * @parm HFPB | hfpb | * Handle to file parameter block * * @parm LPV | lpvData | * Buffer to write. * * @parm FILEOFFSET | foSeek | * File offset to write at. * * @parm LONG | lcbSize | * How many bytes to write. * * @parm PHRESULT | phr | * Error buffer. * * @rdesc Returns the number of bytes written * *************************************************************************/
PUBLIC LONG FAR PASCAL FileSeekWrite(HFPB hfpb, LPV lpvData, FILEOFFSET fo, LONG lcbSize, PHRESULT phr) { LONG lWrote=0L; LPFPB lpfpb; HRESULT fCallBackRet; FILEOFFSET foSeeked=foInvalid;
if (hfpb == NULL) { SetErrCode(phr, E_HANDLE); return 0L; } lpfpb = (LPFPB)_GLOBALLOCK(hfpb); _ENTERCRITICALSECTION(&lpfpb->cs);
/* Execute user's status functions */ if (lpfpb->lpfnfInterCb != NULL && (fCallBackRet = (*lpfpb->lpfnfInterCb)(lpfpb->lpvInterCbParms)) != S_OK) { SetErrCode(phr, fCallBackRet); goto ErrorExit; } if (phr) *phr = S_OK; switch (lpfpb->fFileType) { case FS_SYSTEMFILE:
/* We should not read from a system file */ SetErrCode(phr, E_ASSERT); goto ErrorExit; break;
case FS_SUBFILE: foSeeked=FoSeekHf(lpfpb->fs.hf,fo,0,phr); if (!FoEquals(foSeeked,fo)) { SetErrCode (phr, E_FILESEEK); goto ErrorExit; } lWrote=LcbWriteHf(lpfpb->fs.hf, lpvData, lcbSize, phr); break; case REGULAR_FILE: /* Regular files */ /* PLATFORM DEPENDENT code: _lread */ #ifdef _WIN32
foSeeked=fo; foSeeked.dwOffset=SetFilePointer(lpfpb->fs.hFile, fo.dwOffset, &foSeeked.dwHigh,0); #else
foSeeked.dwHigh=0L; foSeeked.dwOffset=(DWORD)_llseek(lpfpb->fs.hFile, fo.dwOffset, 0); #endif
if (!FoEquals(fo,foSeeked)) { SetErrCode (phr, E_FILESEEK); goto ErrorExit; }
#ifdef _WIN32
WriteFile(lpfpb->fs.hFile, lpvData, lcbSize, &lWrote, NULL); #else
lWrote=_lread(lpfpb->fs.hFile, lpvData, lcbSize); #endif
break; }
if (lWrote != lcbSize) SetErrCode (phr, E_DISKFULL); ErrorExit: _LEAVECRITICALSECTION(&lpfpb->cs); _GLOBALUNLOCK(hfpb); return lWrote;
}
/*************************************************************************
* @doc INTERNAL * * @func LONG FAR PASCAL | FileWrite | * Write data to a file * * @parm HFPB | hfpb | * Handle to file parameter block * * @parm LPV | lpvData | * Buffer to write. * * @parm LONG | lcbSize | * How many bytes to write. * * @parm PHRESULT | phr | * Error buffer. * * @rdesc Returns the number of bytes written * *************************************************************************/
PUBLIC LONG FAR PASCAL FileWrite(HFPB hfpb, LPV lpvData, LONG lcbSize, PHRESULT phr) { LONG lWrote=0L; LPFPB lpfpb; HRESULT fCallBackRet;
if (hfpb == NULL) { SetErrCode(phr, E_HANDLE); return 0L; } lpfpb = (LPFPB)_GLOBALLOCK(hfpb); _ENTERCRITICALSECTION(&lpfpb->cs);
/* Execute user's status functions */ if (lpfpb->lpfnfInterCb != NULL && (fCallBackRet = (*lpfpb->lpfnfInterCb)(lpfpb->lpvInterCbParms)) != S_OK) { SetErrCode(phr, fCallBackRet); goto ErrorExit; } if (phr) *phr = S_OK; switch (lpfpb->fFileType) { case FS_SYSTEMFILE: /* We should not read from a system file */ SetErrCode(phr, E_ASSERT); goto ErrorExit; break;
case FS_SUBFILE: lWrote=LcbWriteHf(lpfpb->fs.hf, lpvData, lcbSize, phr); break; case REGULAR_FILE: /* Regular files */ /* PLATFORM DEPENDENT code: _lread */ #ifdef _WIN32
WriteFile(lpfpb->fs.hFile, lpvData, lcbSize, &lWrote, NULL); #else
lWrote=_lwrite(lpfpb->fs.hFile, lpvData, lcbSize); #endif
break; }
if (lWrote != lcbSize) SetErrCode (phr, E_DISKFULL); ErrorExit: _LEAVECRITICALSECTION(&lpfpb->cs); _GLOBALUNLOCK(hfpb); return lWrote; }
/*************************************************************************
* @doc INTERNAL * * @func VOID | SetFCallBack | * This function provides a simple interface to set the user's * interrupt function and parameters. The function will be called * everytime we do an I/O * * @parm GHANDLE | hfpb | * File's parameter block * * @parm INTERRUPT_FUNC | lpfnfInterCb | * User's interrupt function * * @parm LPV | lpvInterCbParms | * User's function parameters *************************************************************************/
PUBLIC VOID SetFCallBack (GHANDLE hfpb, INTERRUPT_FUNC lpfnfInterCb, LPV lpvInterCbParms) { LPFPB lpfpb;
if (hfpb == 0) return; if (lpfpb = (LPFPB)_GLOBALLOCK(hfpb)) { _ENTERCRITICALSECTION(&lpfpb->cs); lpfpb->lpfnfInterCb = lpfnfInterCb; lpfpb->lpvInterCbParms = lpvInterCbParms; _LEAVECRITICALSECTION(&lpfpb->cs); } _GLOBALUNLOCK(hfpb); }
/*************************************************************************
* @doc PRIVATE * * @func VOID PASCAL | GetFSName | * * Given a filename which may include a system file and a sub-system * filename separated by '!', this function will break the given name * into separate components. If there is no sub-system filename, it * will use the default name * * @parm LSZ | lszFName | * Pointer to filename to be parsed * * @parm LSZ | aszNameBuf | * Common buffer to store the two names * * @parm LSZ FAR * | lplszSubFilename | * Pointer to subfile name to be updated * * @parm LSZ | lszDefaultName | * Default subname to be used *************************************************************************/ PUBLIC VOID PASCAL FAR GetFSName(LSZ lszFName, LSZ aszNameBuf, LSZ FAR *lplszSubFilename, LSZ lszDefaultName) { register LSZ lsztmp = aszNameBuf;
/* Look for the '!' delimiter */ for (lsztmp = aszNameBuf; (*lsztmp = *lszFName) && *lsztmp != '!'; lsztmp++, lszFName++);
*lsztmp++ = 0;
if (*lszFName == 0) { /* No subfile's name specified, use default */ *lplszSubFilename = lszDefaultName; } else { /* Copy the index subfile's name */ *lplszSubFilename = lsztmp; lszFName++; // Skip the !
while (*lsztmp++ = *lszFName++); } }
/*************************************************************************
* @doc PRIVATE * * @func int PASCAL | IsFsName | * * Given a filename, determine if it is a sub-system filename or not * The idea is to search for '!', which is a sub-system filename * delimiter * * @parm LSZ | lszFName | * Pointer to filename to be parsed * * @rdesc TRUE if the name is a sub-system file name, FALSE otherwise *************************************************************************/ PUBLIC int PASCAL FAR IsFsName (register LSZ lszFName) { if (lszFName) { for (; *lszFName; lszFName ++) { if (*lszFName == '!') return TRUE; } } return FALSE; }
/*************************************************************************
* @doc INTERNAL * * @func int FAR PASCAL | FileFlush | * Flush the file * * @parm HANDLE | hfpb | * If non-zero, handle to a file parameter block * * @rdesc S_OK if ereything is OK, else various errors *************************************************************************/
PUBLIC int FAR PASCAL FileFlush(HFPB hfpb) { HRESULT errDos; LPFPB lpfpb;
if (hfpb == NULL) return E_HANDLE;
lpfpb = (LPFPB)_GLOBALLOCK(hfpb); _ENTERCRITICALSECTION(&lpfpb->cs);
switch (lpfpb->fFileType) { case FS_SYSTEMFILE: errDos = E_ASSERT; break;
case FS_SUBFILE: errDos=RcFlushHf(lpfpb->fs.hf); break;
case REGULAR_FILE: if ((errDos = (WORD)_COMMIT(lpfpb->fs.hFile)) != 0) errDos = E_FILEWRITE; break; }
_LEAVECRITICALSECTION(&lpfpb->cs); _GLOBALUNLOCK (hfpb); return errDos; }
/*************************************************************************
* @doc INTERNAL * * @func int FAR PASCAL | FileClose | * Close the file and get rid of the file parameter block * * @parm HANDLE | hfpb | * If non-zero, handle to a file parameter block * * @rdesc S_OK if ereything is OK, else various errors *************************************************************************/ #ifndef ITWRAP
PUBLIC HRESULT FAR PASCAL FileClose(HFPB hfpb) { HRESULT rc; LPFPB lpfpb;
if (hfpb == NULL) return E_HANDLE;
lpfpb = (LPFPB)_GLOBALLOCK(hfpb); _ENTERCRITICALSECTION(&lpfpb->cs);
rc = S_OK; switch (lpfpb->fFileType) { case FS_SYSTEMFILE: rc = RcCloseHfs(lpfpb->fs.hfs); break;
case FS_SUBFILE: { HFS hfs=NULL; if (lpfpb->ioMode&OPENED_HFS) hfs=HfsGetFromHf(lpfpb->fs.hf); rc = RcCloseHf(lpfpb->fs.hf); if (hfs) rc = RcCloseHfs(hfs); break; } case REGULAR_FILE: #ifdef _WIN32
rc = (!CloseHandle(lpfpb->fs.hFile))?ERR_CLOSEFAILED:S_OK; #else
rc = (_lclose(lpfpb->fs.hFile))?ERR_CLOSEFAILED:S_OK; #endif
break; }
_LEAVECRITICALSECTION(&lpfpb->cs); _DELETECRITICALSECTION(&lpfpb->cs);
/* Free the file parameter block structure */ _GLOBALFREE(lpfpb->hStruct);
return rc; } #endif
/*************************************************************************
* * @doc INTERNAL * * @func int FAR PASCAL | FileUnlink | * Unlink a file. This function is an example of difference between * platforms. The filename is a far pointer under Windows, but * _unlink() requires a near pointer in medium model. What happens * is that we have to copy the name into an allocated near buffer * for _unlink() * * @parm LPCSTR | lszFilename | * Pointer to filename * * @parm int | iFileType | * Any of FS_SYSTEMFILE, FS_SUBFILE, or REGULAR_FILE. * * @rdesc Return S_OK, ERR_MEMORY, or return value of _unlink() * *************************************************************************/ PUBLIC HRESULT FAR PASCAL FileUnlink (HFPB hfpbSysFile, LPCSTR lszFilename, int fFileType) { OFSTRUCT ofStruct; HRESULT rc; HRESULT errb; FM fm;
switch (fFileType) { case FS_SYSTEMFILE: fm = FmNewSzDir((LPSTR)lszFilename, dirCurrent, NULL); rc = RcDestroyFileSysFm(fm); DisposeFm(fm); break;
case FS_SUBFILE: { HFS hfs = GetHfs(hfpbSysFile,lszFilename,TRUE,&errb); if (hfs) { rc=RcUnlinkFileHfs(hfs, GetSubFilename(lszFilename,NULL)); if (!hfpbSysFile) RcCloseHfs(hfs); } else rc=errb; break; } case REGULAR_FILE: if ((HFILE) OpenFile(lszFilename, &ofStruct, OF_DELETE) != (HFILE_ERROR)) rc=S_OK; else rc=E_FILEDELETE; break;
default: rc=E_ASSERT; } return rc; }
#if !defined(MOSMAP) // {
#ifdef _NT // {
// Can't have NULL as path... must be a string
WORD EXPORT_API PASCAL FAR GetTempFileNameEx( LPCSTR lpszPath, /* address of name of dir. where temp. file is created */ LPCSTR lpszPrefix, /* address of prefix of temp. filename */ WORD uUnique, /* number used to create temp. filename */ LPSTR lpszTempFile /* address buffer that will receive temp. filename */ ) { char lpszBuf[_MAX_PATH] ;
if (!lpszPath) { if (sizeof(lpszBuf) >= GetTempPath(sizeof(lpszBuf), lpszBuf)) lpszPath = lpszBuf ; else // default to current directory
lpszPath = "." ; }
// Now call the regular function
return (WORD) GetTempFileName(lpszPath, lpszPrefix, uUnique, lpszTempFile) ; } #endif // _NT }
#endif // MOSMAP }
/*************************************************************************
* @doc PRIVATE * * @func LPFBI PASCAL FAR | FileBufAlloc | * Allocate an I/O buffer associated with a file. This is to speed * up I/O * * @parm HFPB | hfpb | * Handle to file parameter block for an already opened file * * @parm WORD | Size | * Size of the buffer * * @rdesc Pointer to a file buffer info if everything is OK, NULL * if out of memory, or invalid file handle *************************************************************************/
PUBLIC LPFBI PASCAL FAR EXPORT_API FileBufAlloc (HFPB hfpb, WORD Size) { LPFBI lpfbi; /* Pointer to file buffer info */ LPFPB lpfpb; HANDLE hMem; /* Sanity check, the file must be already opened */ if (hfpb == 0) return NULL;
/* Allocate the structure. All fields are zeroed */
if (!(hMem=_GLOBALALLOC(GMEM_ZEROINIT,sizeof(FBI) + Size))) { return NULL; }
if (!(lpfbi=(LPFBI)_GLOBALLOCK(hMem))) { _GLOBALFREE(hMem); return NULL; } /* Initialize the fields */ lpfbi->lrgbBuf = (LPB)lpfbi + sizeof(FBI); lpfbi->hStruct = hMem;
/* Get the DOS file handle associated with the file parameter block */ lpfpb = (LPFPB)_GLOBALLOCK(hfpb); _ENTERCRITICALSECTION(&lpfpb->cs); lpfbi->hFile = lpfpb->fs.hFile;
/* Update fields */ lpfbi->cbBufSize = Size; lpfbi->hfpb = hfpb;
/* For read only file, assume the file's size is huge */ if (lpfpb->ioMode == READ) lpfbi->foExtent = foMax;
_LEAVECRITICALSECTION(&lpfpb->cs); _GLOBALUNLOCK(hfpb); return lpfbi; }
/*************************************************************************
* @doc PRIVATE * * @func int PASCAL FAR | FileBufFlush | * Flush the buffer to the disk * * @parm LPFBI | lpfbi | * Pointer to file buffer info * * @rdesc S_OK if everything is OK, else errors *************************************************************************/
PUBLIC int PASCAL FAR FileBufFlush (LPFBI lpfbi) { LONG lWrote; WORD cByteWritten; HRESULT errb; int fRet;
/* Sanity check */ if (lpfbi == NULL) return E_INVALIDARG;
/* Calculate how many bytes are to be written */ cByteWritten = lpfbi->ibBuf;
lWrote = FileSeekWrite(lpfbi->hfpb, lpfbi->lrgbBuf, lpfbi->foExtent, cByteWritten, &errb);
fRet=errb;
if (lWrote==(LONG)cByteWritten) { fRet=S_OK; /* Update the the current offset into the file */ lpfbi->foExtent=lpfbi->fo=(FoAddDw(lpfbi->fo,cByteWritten)); lpfbi->ibBuf = lpfbi->cbBuf = 0; } return fRet; }
/*************************************************************************
* @doc PRIVATE * * @func VOID PASCAL FAR | FileBufFree | * Free all memory associated with the file buffer info * * @parm LPFBI | lpfbi | * Pointer to file buffer info *************************************************************************/
PUBLIC VOID PASCAL FAR FileBufFree (LPFBI lpfbi) { if (lpfbi == NULL) return; _GLOBALFREE(lpfbi->hStruct); }
/*************************************************************************
* @doc PRIVATE * * @func BOOL FAR PASCAL | FileBufRewind | * This function will: * - Flush the file, update the file size * - Reset the logical file offset to 0 * It prepares the file for reading * * @parm LPFBI | lpfbi | * Pointer to file parameter info block * * @rdesc Error code or S_OK *************************************************************************/
PUBLIC BOOL FAR PASCAL FileBufRewind (LPFBI lpfbi) { int fRet;
/* Sanity check */ if (lpfbi == NULL) return E_INVALIDARG;
/* Flush the buffer. This will reset the size of the file (foExtent) */ if ((fRet = FileBufFlush(lpfbi)) != S_OK) return fRet;
#if 0
/* Make sure that things go out to disk */ if ((fRet = FileFlush(lpfbi->hfpb)) != S_OK) return fRet; #endif
/* Reset the offset of the file */ lpfbi->fo = foNil; return S_OK; }
/*************************************************************************
* @doc PRIVATE * * @func int FAR PASCAL | FileBufFill | * This function helps with file reads. It copies the left-over * data in the I/O buffer to the start of the buffer, then fills * the rest of the buffer with new data. * * @parm LPFBI | lpfbi | * File buffer info. * * @parm PHRESULT | phr | * Error return. * * @rdesc The function returns the number of bytes read, or cbIO_ERROR * if error *************************************************************************/
PUBLIC int FAR PASCAL FileBufFill (LPFBI lpfbi, PHRESULT phr) { WORD cbRead; // Number of bytes read.
WORD cbByteLeft; // Number of bytes left
DWORD dwFileByteLeft;
if (FoCompare(lpfbi->foExtent,lpfbi->fo)<=0) return 0; dwFileByteLeft = FoSubFo(lpfbi->foExtent,lpfbi->fo).dwOffset; if (lpfbi->cbBuf < lpfbi->ibBuf) { SetErrCode (phr, E_INVALIDARG); return cbIO_ERROR; }
/* Preserve left-over data. */
if (cbByteLeft = lpfbi->cbBuf - lpfbi->ibBuf) { MEMCPY(lpfbi->lrgbBuf, lpfbi->lrgbBuf + lpfbi->ibBuf, cbByteLeft); lpfbi->ibBuf = 0; lpfbi->cbBuf = cbByteLeft; } else { /* There is nothing left. The buffer is considered to be empty */ lpfbi->cbBuf = lpfbi->ibBuf = 0; }
/* Get new data. */
cbRead = lpfbi->cbBufSize - cbByteLeft; if ((DWORD)cbRead > dwFileByteLeft) cbRead = (WORD)dwFileByteLeft;
if ((cbRead = (WORD)FileSeekRead(lpfbi->hfpb, lpfbi->lrgbBuf + cbByteLeft, lpfbi->fo, cbRead, phr)) != cbIO_ERROR) { lpfbi->cbBuf = cbByteLeft + cbRead; lpfbi->fo=FoAddDw(lpfbi->fo,cbRead); } return cbRead; }
/*************************************************************************
* @doc PRIVATE * * @func BOOL FAR PASCAL | FileBufBackPatch | * This function will batchpatch a file at a certain location, in * memory or at a some physical offset * * @parm LPFBI | lpfbi | * Pointer to file buffer info block * * @parm LPV | lpvData | * Pointer to data tempplate * * @parm FO | fo | * File offset to write it at. * * @parm WORD | cbBytes | * How many bytes to write. * * @rdesc Error code of S_OK *************************************************************************/
PUBLIC BOOL FAR PASCAL FileBufBackPatch(LPFBI lpfbi, LPV lpvData, FILEOFFSET fo, WORD cbBytes) { HRESULT errb; if (FoCompare(fo,lpfbi->fo)>=0) { // Not flushed, do copy.
MEMCPY(lpfbi->lrgbBuf + (short)FoSubFo(fo,lpfbi->fo).dwOffset, lpvData, cbBytes); return S_OK; } return (FileSeekWrite(lpfbi->hfpb, lpvData, fo, cbBytes, &errb)==(LONG)cbBytes)?S_OK:errb; }
#ifndef ITWRAP
PRIVATE HANDLE NEAR PASCAL IoftsWin32Create(LPCSTR lpstr, DWORD w) { SECURITY_ATTRIBUTES sa; HANDLE hfile;
sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = 0;
hfile= CreateFile(lpstr, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); return hfile; }
PRIVATE HANDLE NEAR PASCAL IoftsWin32Open(LPCSTR lpstr, DWORD w) { SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = 0;
return CreateFile(lpstr, (w == READ) ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, &sa,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); } #endif
/*************************************************************************
* @doc PRIVATE * * @func HSFB PASCAL FAR | FpbFromHfs | * Allocate a file parameter buffer, set to hfs * * @parm HFS | hfsHandle | * Handle of an HFS system file * * @parm PHRESULT | phr | * Error buffer * * @rdesc Return a pointer to the newly allocated file parameter block * if succeeded, else NULL *************************************************************************/
PUBLIC HSFB PASCAL FAR FpbFromHfs(HFS hfsHandle, PHRESULT phr) { HFPB hfpb; LPFPB lpfpb;
if ((hfpb = _GLOBALALLOC(GMEM_MOVEABLE | GMEM_ZEROINIT, (WORD)sizeof(FPB))) == NULL) { SetErrCode(phr, E_OUTOFMEMORY); return NULL; } lpfpb = (LPFPB)_GLOBALLOCK(hfpb); _INITIALIZECRITICALSECTION(&lpfpb->cs); lpfpb->hStruct = hfpb; lpfpb->lpvInterCbParms = NULL; lpfpb->lpfnfInterCb = NULL; lpfpb->fFileType=FS_SYSTEMFILE; lpfpb->fs.hfs = (HFS)hfsHandle; _GLOBALUNLOCK(hfpb);
return hfpb; }
/*************************************************************************
* @doc PRIVATE * * @func HSFB PASCAL FAR | FpbFromHf | * Allocate a file parameter buffer, set to hf * * @parm HF | hfHandle | * Handle of a subfile. * * @parm PHRESULT | phr | * Error buffer * * @rdesc Return a pointer to the newly allocated file parameter block * if succeeded, else NULL *************************************************************************/
PUBLIC HSFB PASCAL FAR FpbFromHf(HF hfHandle, PHRESULT phr) { HFPB hfpb; LPFPB lpfpb;
if ((hfpb = _GLOBALALLOC(GMEM_MOVEABLE | GMEM_ZEROINIT, (WORD)sizeof(FPB))) == NULL) { SetErrCode(phr, E_OUTOFMEMORY); return NULL; } lpfpb = (LPFPB)_GLOBALLOCK(hfpb); lpfpb->hStruct = hfpb; lpfpb->lpvInterCbParms = NULL; lpfpb->lpfnfInterCb = NULL; lpfpb->fFileType=FS_SUBFILE; lpfpb->fs.hf = (HF)hfHandle; _INITIALIZECRITICALSECTION(&lpfpb->cs); _GLOBALUNLOCK(hfpb);
return hfpb; }
/*************************************************************************
* @doc PRIVATE * * @func DWORD PASCAL FAR | FsTypeFromHfpb | * Returns the type of file pointed to by a FPB. * * @parm HFPB | hfpb | * Handle to a file parameter block. * * @rdesc Returns one of the following if successful: * FS_SYSTEMFILE, FS_SUBFILE, REGULARFILE Returns 0 if unsuccessful. *************************************************************************/
PUBLIC DWORD PASCAL FAR FsTypeFromHfpb(HFPB hfpb) { LPFPB lpfpb; DWORD dwFileType = 0;
if (hfpb != NULL) { lpfpb = (LPFPB)_GLOBALLOCK(hfpb); _ENTERCRITICALSECTION(&lpfpb->cs); dwFileType = (DWORD) lpfpb->fFileType; _LEAVECRITICALSECTION(&lpfpb->cs); _GLOBALUNLOCK(hfpb); }
return (dwFileType); }
// Frees the critical section and the HFPB
PUBLIC VOID PASCAL FAR FreeHfpb(HFPB hfpb) { LPFPB lpfpb;
lpfpb = (LPFPB)_GLOBALLOCK(hfpb); _DELETECRITICALSECTION(&lpfpb->cs);
_GLOBALUNLOCK(hfpb); _GLOBALFREE(hfpb);
}
|