windows-nt/Source/XPSP1/NT/enduser/stuff/itircl/common/iofts.c
2020-09-26 16:20:57 +08:00

1797 lines
41 KiB
C

/*************************************************************************
* *
* 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);
}