|
|
/*****************************************************************************
* * * FID.C * * * * Copyright (C) Microsoft Corporation 1989 - 1994. * * All Rights reserved. * * * ***************************************************************************** * * * Module Intent * * * * Low level file access layer, Windows version. * * * ***************************************************************************** * * * Current Owner: UNDONE * * * ***************************************************************************** * * * Released by Development: * * * *****************************************************************************/
/*****************************************************************************
* * Revision History: * -- Mar 92 adapted from WinHelp FID.C, DAVIDJES * 9/26/95 davej Autodoc'd * 3/05/97 erinfox Change errors to HRESULTS *****************************************************************************/
/*****************************************************************************
* * Issues: * How to communicate super large (> DWORD) seeks over MOS. See FoSeekFid * *****************************************************************************/
static char s_aszModule[] = __FILE__; /* For error report */
#include <mvopsys.h>
#include <iterror.h>
#ifdef _32BIT
#define FP_OFF
#endif
#include <direct.h>
#include <orkin.h>
#include <misc.h>
#include <wrapstor.h>
#include <_mvutil.h>
#ifdef MOSMAP
#include <mapfile.h>
#endif
#ifndef _MAC
#include <dos.h> /* for FP_OFF macros and file attribute constants */
#endif
#include <io.h> /* for tell() and eof() */
#include <errno.h> /* this is for chsize() */
/***************************************************************************
* * Defines * ***************************************************************************/
#define UCBMAXRW ((WORD)0xFFFE)
#define LCBSIZESEG ((ULONG)0x10000)
/***************************************************************************
* * Macros * ***************************************************************************/
#define _WOpenMode(w) (_rgwOpenMode[ (w) & wRWMask ] | \
_rgwShare[ ((w) & wShareMask) >> wShareShift ] )
/***************************************************************************
* * Private Functions * ***************************************************************************/
HRESULT PASCAL FAR RcMapDOSErrorW(WORD);
/***************************************************************************
* * Public Functions * ***************************************************************************/
/***************************************************************************
* @doc INTERNAL * * @func BOOL PASCAL FAR | FidFlush | * * @parm FID |fid| * * @rdesc TRUE if file flushed OK, FALSE if could not flush. * ***************************************************************************/
// Fill in non-win-32
PUBLIC BOOL PASCAL FAR FidFlush(FID fid) { BOOL bSuccess=TRUE; #ifdef _WIN32
bSuccess=FlushFileBuffers(fid); #else
Need code here #endif
#ifdef _DEBUGMVFS
DPF2("FidFlush: fid %ld, returned %d\n", (LONG)fid, bSuccess); #endif
return bSuccess; }
/***************************************************************************
* * @doc INTERNAL * * @func FID PASCAL FAR | FidCreateFm | * Create a file * * @parm FM | fm | * the file moniker * * @parm WORD | wOpenMode | * read/write/share mode * * @parm WORD | wPerm | * file permissions * * @parm PHRESULT | phr | * Error return * * @rdesc fidNil on failure, valid fid otherwise * ***************************************************************************/
PUBLIC FID FAR PASCAL FidCreateFm(FM fm, WORD wOpenMode, WORD wPerm, PHRESULT phr) { #ifdef MOSMAP // {
// Disable function
SetErrCode(phr, ERR_NOTSUPPORTED); return fidNil; #else // } {
FID fid; QAFM qafm;
if (fm == fmNil) { SetErrCode(phr, E_INVALIDARG); return fidNil; }
qafm = (QAFM)fm; //qafm = _GLOBALLOCK((HANDLE)fm);
#ifdef _WIN32
fid = CreateFile((LPSTR)qafm->rgch, ((wOpenMode&wRead)?GENERIC_READ:0)|((wOpenMode&wWrite)?GENERIC_WRITE:0), ((wOpenMode&wShareRead)?FILE_SHARE_READ:0)|((wOpenMode&wShareWrite)?FILE_SHARE_WRITE:0), NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); // Note: Some really cool optimizations can be made by specifying how the file
// is intended to be used!
#else
fid =_lcreat((LPSTR)qafm->rgch, _rgwPerm[ (wPerm) & wRWMask ]); #endif
if (fid == fidNil) SetErrCode(phr, E_FILECREATE); //_GLOBALUNLOCK((HANDLE)fm);
#ifdef _DEBUGMVFS
DPF2("FidCreateFm: fid %ld for '%s'.\n", (LONG)fid, (LPSTR)qafm->rgch); #endif
return fid; #endif //}
}
/***************************************************************************
* * @doc INTERNAL * * @func FID PASCAL FAR | FidOpenFm | * Open a file in binary mode. * * @parm FM | fm | * the file moniker * * @parm WORD | wOpenMode | * read/write/share modes. Undefined if wRead and wWrite both unset. * * @parm PHRESULT | phr | * Error return * * @rdesc fidNil on failure, else a valid FID. * ***************************************************************************/ PUBLIC FID FAR PASCAL FidOpenFm(FM fm, WORD wOpenMode, PHRESULT phr) { FID fid; QAFM qafm;
if (fm == fmNil) { SetErrCode(phr, E_INVALIDARG); return fidNil; }
qafm = (QAFM)fm; //qafm = _GLOBALLOCK((HANDLE)fm);
#ifdef MOSMAP // {
// Open File Mapping, or get ref to existing one
if ((fid = (HFILE)MosOpenMapFile((LPSTR)qafm->rgch)) == fidNil) SetErrCode(phr, ERR_FAILED); #else // } {
#ifdef _WIN32
if ((fid = CreateFile((LPSTR)qafm->rgch, ((wOpenMode&wRead)?GENERIC_READ:0)|((wOpenMode&wWrite)?GENERIC_WRITE:0), ((wOpenMode&wShareRead)?FILE_SHARE_READ:0)|((wOpenMode&wShareWrite)?FILE_SHARE_WRITE:0), NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == fidNil) #else
if ((fid = _lopen((LPSTR)qafm->rgch, _WOpenMode(wOpenMode))) == fidNil) #endif // _WIN32
SetErrCode(phr, RcGetDOSError()); #endif //}
//_GLOBALUNLOCK((HANDLE)fm);
#ifdef _DEBUGMVFS
DPF2("FidOpenFm: fid %ld for '%s'.\n", (LONG)fid, (LPSTR)qafm->rgch); #endif
return fid; }
/***************************************************************************
* * @doc INTERNAL * * @func LONG PASCAL FAR | LcbReadFid | * Read data from a file. * * @parm FID | fid | * valid FID of an open file * * @parm QV | qv | * pointer to user's buffer assumed huge enough for data * * @parm LONG | lcb | * count of bytes to read (must be less than 2147483648) * * @parm PHRESULT | phr | * Error return * * @rdesc count of bytes actually read or -1 on error * ***************************************************************************/ PUBLIC LONG FAR PASCAL LcbReadFid(FID fid, QV qv, LONG lcb, PHRESULT phr) { LONG lcbTotalRead = (LONG)0; #ifdef MOSMAP // {
// Read map file
lcbTotalRead = MosReadMapFile((LPVOID)fid, qv, lcb) ; if (lcbTotalRead == -1) #else // } {
#ifdef _WIN32
if (!ReadFile(fid, qv, lcb, &lcbTotalRead, NULL)) SetErrCode(phr, RcGetDOSError()); #else
BYTE HUGE *hpb = (BYTE HUGE *)qv; WORD ucb, ucbRead;
do { ucb = (WORD)min(lcb, UCBMAXRW); ucb = (WORD)min((ULONG) ucb, LCBSIZESEG - (ULONG) FP_OFF(hpb)); ucbRead = _lread(fid, hpb, ucb);
if (ucbRead == (WORD)-1) { if (!lcbTotalRead) { lcbTotalRead = (LONG)-1; } break; } else { lcbTotalRead += ucbRead; lcb -= ucbRead; hpb += ucbRead; } } while (lcb > 0 && ucb == ucbRead);
if (ucbRead == (WORD)-1) SetErrCode(phr, ERR_CANTREAD);
#endif
#endif //}
#ifdef _DEBUGMVFS
DPF2("LcbReadFid: fid %ld returned %ld bytes.\n", (LONG)fid, lcbTotalRead); #endif
return lcbTotalRead; }
/***************************************************************************
* * @doc INTERNAL * * @func LONG PASCAL FAR | LcbWriteid | * Write data to a file. * * @parm FID | fid | * valid FID of an open file * * @parm QV | qv | * pointer to user's buffer assumed huge enough for data * * @parm LONG | lcb | * count of bytes to read (must be less than 2147483648) * * @parm PHRESULT | phr | * Error return * * @rdesc count of bytes actually read or -1 on error * ***************************************************************************/ PUBLIC LONG FAR PASCAL LcbWriteFid(FID fid, QV qv, LONG lcb, PHRESULT phr) { LONG lcbTotalWrote = (LONG)0;
#ifdef MOSMAP // {
// Disable function
SetErrCode(phr, ERR_NOTSUPPORTED); return 0; #else // } {
#ifdef _WIN32
if (!WriteFile(fid, qv, lcb, &lcbTotalWrote, NULL)) SetErrCode(phr, RcGetDOSError());
#else
BYTE HUGE *hpb = (BYTE HUGE *)qv; WORD ucb, ucbWrote; if (lcb == 0L) { phr->err = S_OK; return 0L; }
do { ucb = (WORD)min(lcb, (ULONG) UCBMAXRW); ucb = (WORD)min((ULONG) ucb, LCBSIZESEG - (WORD) FP_OFF(hpb)); ucbWrote = _lwrite(fid, hpb, ucb);
if (ucbWrote == (WORD)-1) { if (!lcbTotalWrote) lcbTotalWrote = -1L; break; } else { lcbTotalWrote += ucbWrote; lcb -= ucbWrote; hpb += ucbWrote; } } while (lcb > 0 && ucb == ucbWrote);
if (ucb != ucbWrote) { if (ucbWrote == (WORD)-1L) SetErrCode (phr, RcGetDOSError()); else SetErrCode (phr, E_DISKFULL); } #endif
#endif // }
#ifdef _DEBUGMVFS
DPF2("LcbWriteFid: fid %ld wrote %ld bytes.\n", (LONG)fid, lcbTotalWrote); #endif
return lcbTotalWrote;
}
/***************************************************************************
* * @doc INTERNAL * * @func HRESULT PASCAL FAR | RcCloseFid | * Close a file. * * @parm FID | fid | * valid FID of an open file * * @rdesc rcSuccess or something else * ***************************************************************************/ PUBLIC HRESULT FAR PASCAL RcCloseFid(FID fid) { #ifdef MOSMAP // {
if (MosCloseMapFile((LPVOID)fid) == HFILE_ERROR) { #else // } {
#ifdef _WIN32
if (!CloseHandle(fid)) { #else
if (_lclose( fid) == (HFILE)-1 ) { #endif
#endif //}
#ifdef _DEBUGMVFS
DPF2("RcCloseFid: fid %ld was NOT closed(%d).\n", (LONG)fid, 0); #endif
return E_FILECLOSE; } #ifdef _DEBUGMVFS
DPF2("RcCloseFid: fid %ld was closed(%d).\n", (LONG)fid, 1); #endif
return S_OK; }
/***************************************************************************
* * @doc INTERNAL * * @func LONG PASCAL FAR | LTellFid | * Return current file position in an open file. * * @parm FID | fid | * valid FID of an open file * * @parm PHRESULT | phr | * Error return * * @rdesc offset from beginning of file in bytes; -1L on error. * ***************************************************************************/ LONG FAR PASCAL LTellFid(FID fid, PHRESULT phr) { LONG l;
#ifdef MOSMAP // {
l = MosSeekMapFile((LPVOID)fid, 0L, 1) ; #else // } {
#ifdef _WIN32
DWORD dwHigh = 0L; l = SetFilePointer(fid, 0L, &dwHigh, FILE_CURRENT); // OK, just plain no support for +4gig files here...
if ((l==(LONG)-1L) || (dwHigh)) SetErrCode(phr, E_FILESEEK); #else
l = _llseek(fid, 0L, 1); #endif
#endif //}
if ( l == (LONG)-1L ) SetErrCode(phr, E_FILESEEK); #ifdef _DEBUGMVFS
DPF2("LTellFid: fid %ld is at %ld\n", (LONG)fid, l); #endif
return l; }
/***************************************************************************
* * @doc INTERNAL * * @func LONG PASCAL FAR | LSeekFid | * Move file pointer to a specified location. It is an error * to seek before beginning of file, but not to seek past end * of file. * * @parm FID | fid | * valid FID of an open file * * @parm LONG | lPos | * offset from origin * * @parm WORD | wOrg | * one of: wSeekSet: beginning of file, wSeekCur: current file pos, * wSeekEnd: end of file * * @parm PHRESULT | phr | * Error return * * @rdesc offset in bytes from beginning of file or -1L on error * ***************************************************************************/
PUBLIC LONG FAR PASCAL LSeekFid(FID fid, LONG lPos, WORD wOrg, PHRESULT phr) { LONG l; #ifdef MOSMAP // {
l = MosSeekMapFile((LPVOID)fid, lPos, wOrg) ; #else // } {
#ifdef _WIN32
DWORD dwHigh = 0L; l = SetFilePointer(fid, lPos, &dwHigh, wOrg); // OK, just plain no support for +4gig files here...
if ((l!=lPos) || (dwHigh)) SetErrCode(phr, E_FILESEEK); #else
l = _llseek(fid, lPos, wOrg); if (l == (LONG)-1L) SetErrCode(phr, E_FILESEEK); #endif
#endif //}
#ifdef _DEBUGMVFS
DPF2("LSeekFid: fid %ld is at %ld\n", (LONG)fid, l); #endif
return l; }
/***************************************************************************
* * @doc INTERNAL * * @func FILEOFFSET PASCAL FAR | FoSeekFid | * Move file pointer to a specified location. It is an error * to seek before beginning of file, but not to seek past end * of file. This function is meant to handle offsets larger than 4 * gigabytes. * * @parm FID | fid | * valid FID of an open file * * @parm FILEOFFSET | foPos | * offset from origin * * @parm WORD | wOrg | * one of: wSeekSet: beginning of file, wSeekCur: current file pos, * wSeekEnd: end of file * * @parm PHRESULT | phr | * Error return * * @rdesc offset in bytes from beginning of file or -1L on error * ***************************************************************************/ PUBLIC FILEOFFSET FAR PASCAL FoSeekFid(FID fid, FILEOFFSET foPos, WORD wOrg, PHRESULT phr) { DWORD dw; DWORD dwHigh=0L; FILEOFFSET foSeeked;
#ifdef MOSMAP // {
SetErrCode(phr,ERR_NOTSUPPORTED); return -1L; //l = MosSeekMapFile((LPVOID)fid, lPos, wOrg) ;
#else // } {
#ifdef _WIN32
dwHigh=(LONG)foPos.dwHigh; dw = SetFilePointer((HANDLE)fid, foPos.dwOffset, &dwHigh, wOrg); #else // not really supported for 16-bit
dw = (DWORD)_llseek(fid, foPos.dwOffset, wOrg); #endif
#endif //}
foSeeked.dwOffset=dw; foSeeked.dwHigh=dwHigh; if (dw == (LONG)-1L) { if (GetLastError()!=NO_ERROR) SetErrCode(phr, E_FILESEEK); else *phr = S_OK; } #ifdef _DEBUGMVFS
DPF2("FoSeekFid: fid %ld is at %ld\n", (LONG)fid, foPos.dwOffset); #endif
return foSeeked; }
#if 0
#if !defined ( _WIN32 )
/***************************************************************************
* * @doc INTERNAL * * @func BOOL PASCAL FAR | FEofFid | * Tells ye if ye're at the end of the file. * * @parm FID | fid | * valid FID of an open file * * @rdesc TRUE if at EOF, FALSE if not or error has occurred (?) * ***************************************************************************/ PUBLIC BOOL PASCAL FAR FEofFid(FID fid) { WORD wT;
if (( wT = eof( fid) ) == (WORD)-1 ) SetErrCode(RcGetDOSError()); else SetErrCode(rcSuccess);
return (BOOL)(wT == 1); } #endif // !defined ( _WIN32 )
#endif
PUBLIC HRESULT PASCAL FAR RcGetDOSError (void) {
#ifdef _WIN32
// NT does not support errno in the multi threaded environment.
switch( GetLastError() ) { case NO_ERROR: return S_OK;
case ERROR_ACCESS_DENIED: return E_NOPERMISSION; case ERROR_INVALID_HANDLE: return E_HANDLE;
case ERROR_HANDLE_DISK_FULL: case ERROR_DISK_FULL: return E_DISKFULL;
default: return E_INVALIDARG; } #else
switch (errno) { case EACCES: return E_NOPERMISSION; break;
case EBADF: return E_INVALIDARG; break;
case ENOSPC: return E_DISKFULL; break;
default: return E_INVALIDARG; break; } #endif // _WIN32
}
/***************************************************************************
* * @doc INTERNAL * * @func HRESULT PASCAL FAR | RcChSizeFid | * Change the size of a file * * @parm FID | fid | * valid FID of an open file * * @parm LONG | lcb | * New size of file * * @rdesc Returns S_OK if all OK, else the error. * ***************************************************************************/ PUBLIC HRESULT PASCAL FAR RcChSizeFid(FID fid, LONG lcb) { #if !defined ( _WIN32 )
if (chsize( fid, lcb) == -1 ) return RcGetDOSError(); else #endif // !defined ( _WIN32 )
return S_OK; }
/***************************************************************************
* * @doc INTERNAL * * @func HRESULT PASCAL FAR | RcUnlinkFm | * Delete a DOS file given the filename * * @parm FM | fm | * Name of file to remove. (An FM is the same as an LPSTR). * * @rdesc Returns S_OK if all OK, else the error. * ***************************************************************************/ PUBLIC HRESULT PASCAL FAR EXPORT_API RcUnlinkFm(FM fm) { #ifdef MOSMAP // {
// Disable function
return ERR_NOTSUPPORTED; #else // } {
QAFM qafm = (QAFM)fm; //QAFM qafm = _GLOBALLOCK((HANDLE)fm);
OFSTRUCT ofStruct; int fRet = S_OK;
if (OpenFile((LPSTR)qafm->rgch, &ofStruct, OF_DELETE) == HFILE_ERROR) fRet = E_FILEDELETE; //_GLOBALUNLOCK((HANDLE)fm);
return fRet; #endif // }
}
#ifdef _IT_FULL_CRT // {
#ifndef _MAC // {
/* This function was previously present in dlgopen.c. It has been brought */ /* here as it is making INT21 call. */ /***************************************************************************
* * @doc INTERNAL * * @func BOOL PASCAL FAR | FDriveOk | * Cheks if the drive specified with thwe file name is OK. * * @parm LPSTR | szFile | * Name of file * * @rdesc TRUE if drive is OK. * ***************************************************************************/ PUBLIC BOOL PASCAL FAR EXPORT_API FDriveOk(LPSTR szFile) /* -- Check if drive is valid */ { // the static variables here are static only because we are in a DLL
// and need to pass a near pointer to them to a C Run-Time routine.
// These should be Locally-Alloc'd so they don't waste space in
// our data segment.
static int wDiskCur; int wDisk;
wDiskCur = _getdrive();
/* change to new disk if specified */ if ((wDisk = (int)((*szFile & 0xdf) - ('A' - 1))) != wDiskCur) { if (_chdrive (wDisk) == (int)-1) return FALSE; } return TRUE; } #endif // } _MAC
#endif // }
|