windows-nt/Source/XPSP1/NT/enduser/stuff/itircl/common/filesys/filesys.c

1023 lines
27 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*****************************************************************************
* *
* FILESYS.C *
* *
* Copyright (C) Microsoft Corporation 1995. *
* All Rights reserved. *
* *
******************************************************************************
* *
* Module Intent *
* *
* All main File System commands (opening, closing) *
* any given offset, or in a temp file. *
* *
******************************************************************************
* *
* Current Owner: davej *
*****************************************************************************/
/*****************************************************************************
*
* Created 07/17/95 - davej
* 3/05/97 erinfox Change errors to HRESULTS
*
*****************************************************************************/
static char s_aszModule[] = __FILE__; /* For error report */
#include <mvopsys.h>
#include <iterror.h>
#include <orkin.h>
#include <misc.h>
#include <wrapstor.h>
#include <_mvutil.h>
/*****************************************************************************
* *
* Defines *
* *
*****************************************************************************/
/*****************************************************************************
* *
* Prototypes *
* *
*****************************************************************************/
/***************************************************************************
* *
* Private Functions *
* *
***************************************************************************/
// FACCESS_READWRITE
// FACCESS_READ
BOOL PASCAL FAR FHfsAccess(HFS hfs, BYTE bFlags)
{
QFSHR qfshr;
BOOL bHasAccess=FALSE;
if (hfs == NULL || (qfshr = _GLOBALLOCK(hfs)) == NULL)
{
return FALSE;
}
if ((qfshr->fsh.bFlags&FSH_READWRITE) && (bFlags&FACCESS_READWRITE))
bHasAccess=TRUE;
if (bFlags&FACCESS_READ)
bHasAccess=TRUE;
_GLOBALUNLOCK(hfs);
return bHasAccess;
}
/***************************************************************************
*
* @doc PRIVATE
*
* @func HFS PASCAL NEAR | HfsOpenFileSysFmInternal |
* Open or Create a file system
*
* @parm FM | fmFileName |
* File name of file system to open or create (FM is identical to LPSTR)
*
* @parm BYTE | bFlags |
* Combinations of the FSH_ flags
* @flag FSH_READWRITE | (0x01) FS will be updated
* @flag FSH_READONLY | (0x02) FS will be read only, no updating
* @flag FSH_CREATE | (0x04) Create a new FS
* @flag FSH_M14 | (0x08) Not used really, since we return
* @flag FSH_FASTUPDATE | (0x10) System Btree is not copied to temp file
* unless absolutely necessary
* @flag FSH_DISKBTREE | (0x20) System Btree is always copied to disk if
* possible for speed. Btree may be very very
* large, and this is NOT recommended for on-line
*
* @parm FS_PARAMS FAR * | lpfsp |
* File system initialization parameters (currently btree block size)
*
* @parm PHRESULT | lpErrb |
* Error return
*
* @rdesc Returns a valid HFS or NULL if an error.
*
***************************************************************************/
HFS PASCAL NEAR HfsOpenFileSysFmInternal(FM fm,
BYTE bFlags, FS_PARAMS FAR *qfsp, PHRESULT phr)
{
#ifdef MOSMAP // {
// Disable function
if (bFlags&(FSH_CREATE|FSH_READWRITE))
{
SetErrCode (phr, ERR_NOTSUPPORTED);
return NULL;
}
#else // } {
HFS hfs;
QFSHR qfshr;
BTREE_PARAMS btp;
/* make file system header */
if (( hfs = _GLOBALALLOC(GMEM_ZEROINIT|GMEM_SHARE| GMEM_MOVEABLE,
(LONG)sizeof( FSHR) ) ) == NULL )
{
SetErrCode (phr, E_OUTOFMEMORY);
return NULL;
}
qfshr = _GLOBALLOCK(hfs);
_INITIALIZECRITICALSECTION(&qfshr->cs);
// Copy File Moniker
if ((qfshr->fm = FmCopyFm(fm, phr)) == fmNil)
{
SetErrCode(phr,E_OUTOFMEMORY);
exit0:
_DELETECRITICALSECTION(&qfshr->cs);
_GLOBALUNLOCK(hfs);
_GLOBALFREE(hfs);
return 0;
}
// Open or Create fid
if (bFlags&FSH_CREATE)
qfshr->fid = FidCreateFm(qfshr->fm, wReadWrite, wReadWrite, phr);
else
qfshr->fid = FidOpenFm(qfshr->fm,
(WORD)((bFlags & FSH_READONLY)?(wReadOnly | wShareRead) : (wReadWrite | wShareNone)), phr);
if (qfshr->fid == fidNil)
{
exit1:
//FreeListDestroy(qfshr->hfl);
SetErrCode(phr,E_NOPERMISSION);
DisposeFm(qfshr->fm);
goto exit0;
}
qfshr->hsfbFirst=NULL;
qfshr->hsfbSystem=NULL;
// Initialize global SubFile header blocks array - shared by everyone :-)
// So we take multi-threading precautions
if (!_INTERLOCKEDINCREMENT(&mv_gsfa_count))
{
HANDLE hSfa;
mv_gsfa_count=1L;
mv_gsfa=NULL;
_INITIALIZECRITICALSECTION(&mv_gsfa_cs);
if (((hSfa=_GLOBALALLOC(GMEM_ZEROINIT|GMEM_MOVEABLE|GMEM_SHARE,sizeof(SF)*MAXSUBFILES))==NULL) ||
((mv_gsfa=(SF FAR *)_GLOBALLOCK(hSfa))==NULL))
{
if (hSfa)
_GLOBALFREE(hSfa);
SetErrCode (phr, E_OUTOFMEMORY);
exit2:
if (!(_INTERLOCKEDDECREMENT(&mv_gsfa_count)))
{
if (mv_gsfa)
{
_GLOBALUNLOCK(GlobalHandle(mv_gsfa));
_GLOBALFREE(GlobalHandle(mv_gsfa));
mv_gsfa=NULL;
}
_DELETECRITICALSECTION(&mv_gsfa_cs);
mv_gsfa_count=-1L;
}
goto exit1;
}
mv_gsfa[0].hsfb=(HSFB)-1;
}
if (bFlags&(FSH_READWRITE|FSH_DISKBTREE))
{
// If we are ambitious, we can try lower scratch sizes, but if we are that low
// on memory, chances are we are just going to fail a few steps from here.
HANDLE hBuf;
if (!(hBuf=_GLOBALALLOC(GMEM_ZEROINIT|GMEM_MOVEABLE|GMEM_SHARE,(DWORD)SCRATCHBUFSIZE)))
{
SetErrCode(phr, E_OUTOFMEMORY);
goto exit2;
}
if (!(qfshr->sb.lpvBuffer=_GLOBALLOCK(hBuf)))
{
_GLOBALFREE(hBuf);
goto exit2;
}
qfshr->sb.lcbBuffer=(LONG)SCRATCHBUFSIZE;
_INITIALIZECRITICALSECTION(&qfshr->sb.cs);
}
if (!(bFlags&FSH_CREATE))
{
BYTE bFlagsBtree=0L;
if ((LcbReadFid(qfshr->fid, &qfshr->fsh,(LONG)sizeof(FSH),
phr)) != (LONG)sizeof(FSH))
{
SetErrCode (phr, E_FILEINVALID);
exit3:
if (bFlags&(FSH_READWRITE|FSH_DISKBTREE))
_DELETECRITICALSECTION(&qfshr->sb.cs);
if (qfshr->sb.lpvBuffer)
{
if (!(bFlags&(FSH_READWRITE|FSH_DISKBTREE)))
_DELETECRITICALSECTION(&qfshr->sb.cs);
_GLOBALUNLOCK(GlobalHandle(qfshr->sb.lpvBuffer));
_GLOBALFREE(GlobalHandle(qfshr->sb.lpvBuffer));
}
RcCloseFid(qfshr->fid);
if (bFlags&FSH_CREATE)
RcUnlinkFm(qfshr->fm);
goto exit2;
}
/* Handle MAC swapping */
if (qfshr->fsh.wMagic == SWAPWORD(wFileSysMagic))
{
qfshr->fsh.wMagic = SWAPWORD(qfshr->fsh.wMagic);
qfshr->fsh.foDirectory.dwOffset = SWAPLONG(qfshr->fsh.foDirectory.dwOffset);
qfshr->fsh.foDirectory.dwHigh = SWAPLONG(qfshr->fsh.foDirectory.dwHigh);
qfshr->fsh.foFreeList.dwOffset = SWAPLONG(qfshr->fsh.foFreeList.dwOffset);
qfshr->fsh.foFreeList.dwHigh = SWAPLONG(qfshr->fsh.foFreeList.dwHigh);
qfshr->fsh.foEof.dwOffset = SWAPLONG(qfshr->fsh.foEof.dwOffset);
qfshr->fsh.foEof.dwHigh = SWAPLONG(qfshr->fsh.foEof.dwHigh);
}
qfshr->fsh.bFlags=(qfshr->fsh.bFlags&(~(FSH_READWRITE|FSH_READONLY)))|bFlags;
if (qfshr->fsh.wMagic != wFileSysMagic)
{
SetErrCode (phr, E_FILEINVALID);
goto exit3;
}
if (qfshr->fsh.bVersion != bFileSysVersion)
{
if (qfshr->fsh.bVersion == bFileSysVersionOld)
{
qfshr->fsh.bFlags|=FSH_M14;
SetErrCode(phr, E_BADVERSION); // Try another error specially for M14?
goto exit3;
}
else
{
SetErrCode(phr, E_BADVERSION);
goto exit3;
}
}
// Open Free List if r/w mode
if (bFlags&FSH_READWRITE)
{
if ((!FoEquals(FoSeekFid(qfshr->fid,qfshr->fsh.foFreeList,wSeekSet,
phr),qfshr->fsh.foFreeList)) ||
((qfshr->hfl=FreeListInitFromFid( qfshr->fid, phr ))==NULL))
{
goto exit3;
}
}
// Open Btree making temp file for btree
//if ((qfshr->hbt = HbtOpenBtreeSz(NULL, hfs,
// (BYTE)((qfshr->fsh.bFlags&FSH_READONLY?HFOPEN_READ:HFOPEN_READWRITE)|HFOPEN_SYSTEM),
// NULL, phr)) == NULL)
// Open Btree, temp only gets made if necessary
bFlagsBtree|=HFOPEN_SYSTEM;
if (qfshr->fsh.bFlags&FSH_READONLY)
{
bFlagsBtree|=HFOPEN_READ;
if (qfshr->fsh.bFlags&FSH_DISKBTREE)
bFlagsBtree|=HFOPEN_FORCETEMP;
}
else
{
bFlagsBtree|=HFOPEN_READWRITE;
if (qfshr->fsh.bFlags&FSH_FASTUPDATE)
bFlagsBtree|=HFOPEN_NOTEMP;
}
//if ((qfshr->hbt = HbtOpenBtreeSz(NULL, hfs,
// (BYTE)((qfshr->fsh.bFlags&FSH_READONLY?HFOPEN_READ:
// ((qfshr->fsh.bFlags&FSH_FASTUPDATE)?HFOPEN_NOTEMP:0)|HFOPEN_READWRITE)|
// HFOPEN_SYSTEM),
// NULL, phr)) == NULL)
if ((qfshr->hbt = HbtOpenBtreeSz(NULL, hfs, bFlagsBtree, phr))==NULL)
{
exit4:
if (qfshr->hfl)
FreeListDestroy(qfshr->hfl);
goto exit3;
}
}
else
{
WORD wFreeListSize = wDefaultFreeListSize;
if ((qfsp) && (qfsp->wFreeListSize))
wFreeListSize = qfsp->wFreeListSize;
qfshr->fsh.wMagic = wFileSysMagic;
qfshr->fsh.bVersion = bFileSysVersion;
qfshr->fsh.bFlags = FSH_READWRITE;
qfshr->fsh.foFreeList.dwOffset = sizeof(FSH); // Free list directly after header
qfshr->fsh.foFreeList.dwHigh = 0L;
qfshr->fsh.foDirectory = foNil; // Filled in with system file start
if (bFlags&FSH_READWRITE)
{ if ((qfshr->hfl=FreeListInit(wFreeListSize, phr))==NULL)
{
goto exit3;
}
}
qfshr->fsh.foEof.dwOffset = sizeof(FSH)+FreeListSize(qfshr->hfl,phr); // Free starts here
qfshr->fsh.foEof.dwHigh = 0L;
/* build btree directory */
btp.hfs = hfs;
btp.bFlags = HFOPEN_READWRITE|HFOPEN_SYSTEM;
if (qfsp != NULL)
{
btp.cbBlock = qfsp->cbBlock;
}
else
{
btp.cbBlock = cbBtreeBlockDefault;
}
lstrcpy(btp.rgchFormat, "VOO1"); // "VY", KT_VSTI, FMT_VNUM_FO, FMT_VNUM_LCB, file byte // 'VOL1' works too
qfshr->hbt = HbtCreateBtreeSz(NULL, &btp, phr);
if (qfshr->hbt == NULL)
{
goto exit4;
}
}
// NO harm writing out file system file so far (???)
//LSeekFid(qfshr->fid, 0L, wSeekSet, phr);
//LcbWriteFid(qfshr->fid, &qfshr->fsh, sizeof(FSH), phr);
//Lcb ... also no need to write it out yet!
/* return handle to file system */
_GLOBALUNLOCK(hfs);
return hfs;
#endif //}
}
/***************************************************************************
*
* @doc INTERNAL API
*
* @func HFS PASCAL FAR | HfsCreateFileSysFm |
* Creates a new file system
*
* @parm FM | fmFileName |
* File name of file system to open or create (FM is same as LPSTR)
*
* @parm FS_PARAMS FAR * | lpfsp |
* File system initialization parameters (currently btree block size)
*
* @parm PHRESULT | lpErrb |
* Error return
*
* @rdesc Returns a valid HFS or NULL if an error.
*
***************************************************************************/
PUBLIC HFS PASCAL FAR EXPORT_API HfsCreateFileSysFm(FM fm,
FS_PARAMS FAR *qfsp, PHRESULT phr)
{
return HfsOpenFileSysFmInternal(fm,FSH_CREATE|FSH_READWRITE,qfsp,phr);
}
/***************************************************************************
*
* @doc INTERNAL API
*
* @func HFS PASCAL FAR | HfsOpenFm |
* Open an existing file system
*
* @parm FM | fmFileName |
* File name of file system to open (FM is same as LPSTR)
*
* @parm BYTE | bFlags |
* Any of the FSH_ flags
* @flag FSH_READWRITE | (BYTE)0x01 FS will be updated
* @flag FSH_READONLY | (BYTE)0x02 FS will be read only, no updating
* @flag FSH_M14 | (BYTE)0x08 Not used really, since we return
* @flag FSH_FASTUPDATE | (BYTE)0x10 System Btree is not copied to temp file
* unless absolutely necessary
* @flag FSH_DISKBTREE | (BYTE)0x20 System Btree is always copied to disk if
* possible for speed. Btree may be very very
* large, and this is NOT recommended for on-line
*
* @parm PHRESULT | lpErrb |
* Error return
*
* @rdesc Returns a valid HFS or NULL if an error.
*
***************************************************************************/
PUBLIC HFS PASCAL FAR EXPORT_API HfsOpenFm(FM fm, BYTE bFlags,
PHRESULT phr)
{
if (bFlags&FSH_CREATE)
{
SetErrCode(phr, E_INVALIDARG);
return NULL;
}
return HfsOpenFileSysFmInternal(fm,bFlags,NULL,phr);
}
/***************************************************************************
*
* @doc INTERNAL API
*
* @func HRESULT PASCAL FAR | RcCloseHfs |
* Close an opened File System
*
* @parm HFS | hfs |
* Handle of opened file system
*
* @rdesc Returns S_OK if closed OK, else an error
*
* @comm
* state IN:
* state OUT:
* Notes:
*
***************************************************************************/
HRESULT PASCAL FAR RcCloseHfs(HFS hfs)
{
QFSHR qfshr;
HRESULT errb;
if (hfs == NULL || (qfshr = _GLOBALLOCK(hfs)) == NULL)
{
return(E_INVALIDARG);
}
if (!mv_gsfa_count)
return E_ASSERT;
_ENTERCRITICALSECTION(&qfshr->cs);
// We need to:
// (1) close all subfiles if any open
// (2) close the btree
// (3) r/w write free list
// (4) r/w write header
RcCloseEveryHf(hfs);
//while (qfshr->hsfbFirst)
//{
// qfshr->hsfbFirst=HsfbCloseHsfb(qfshr->hsfbFirst, &errb);
// if (errb.err!=S_OK)
// break;
//}
if ((errb = RcCloseOrFlushHbt(qfshr->hbt, TRUE)) != S_OK)
{
/* out of disk space, internal error, or out of file handles. */
if (errb != E_HANDLE)
{
/* attempt to invalidate FS by clobbering magic number */
LSeekFid(qfshr->fid, 0L, wSeekSet, NULL);
qfshr->fsh.wMagic = 0;
LcbWriteFid(qfshr->fid, &qfshr->fsh, (LONG)sizeof(FSH), NULL);
}
}
else
{
if (qfshr->fsh.bFlags & FSH_READWRITE)
{
FoSeekFid(qfshr->fid, qfshr->fsh.foFreeList, wSeekSet, NULL);
FreeListWriteToFid(qfshr->hfl, qfshr->fid, NULL);
FreeListDestroy(qfshr->hfl);
if (LSeekFid(qfshr->fid, 0L, wSeekSet, &errb) == 0L)
{
LcbWriteFid(qfshr->fid, &qfshr->fsh, (LONG)sizeof(FSH), &errb);
}
}
}
// Remove our access to the global subfile handle object
if (!(_INTERLOCKEDDECREMENT(&mv_gsfa_count)))
{
// Last person using subfile array deletes it too!
// Can we use the GlobalHandle function OK in all environments?
_GLOBALUNLOCK(GlobalHandle(mv_gsfa));
_GLOBALFREE(GlobalHandle(mv_gsfa));
mv_gsfa=NULL;
mv_gsfa_count=-1L;
_DELETECRITICALSECTION(&mv_gsfa_cs);
}
RcCloseFid(qfshr->fid);
_LEAVECRITICALSECTION(&qfshr->cs);
_DELETECRITICALSECTION(&qfshr->cs);
if (qfshr->sb.lpvBuffer)
{
_DELETECRITICALSECTION(&qfshr->sb.cs);
_GLOBALUNLOCK(GlobalHandle(qfshr->sb.lpvBuffer));
_GLOBALFREE(GlobalHandle(qfshr->sb.lpvBuffer));
}
DisposeFm(qfshr->fm);
_GLOBALUNLOCK(hfs);
_GLOBALFREE(hfs);
return errb;
}
/***************************************************************************
*
* @doc INTERNAL API
*
* @func HRESULT PASCAL FAR | RcFlushHfs |
* Write all temporary info in file system to FS file
*
* @parm HFS | hfs |
* Handle of opened file system
*
* @rdesc Returns S_OK if closed OK, else an error
*
* @comm
* state IN:
* state OUT:
* Notes:
*
***************************************************************************/
HRESULT PASCAL FAR RcFlushHfs(HFS hfs)
{
QFSHR qfshr;
HRESULT errb;
//HSFB hsfbCursor;
HRESULT rc=S_OK;
if (hfs == NULL || (qfshr = _GLOBALLOCK(hfs)) == NULL)
{
return(E_INVALIDARG);
}
_ENTERCRITICALSECTION(&qfshr->cs);
// We need to:
// (1) close all subfiles if any open
// (2) close the btree
// (3) r/w write free list
// (4) r/w write header
RcFlushEveryHf(hfs);
/*
hsfbCursor=qfshr->hsfbFirst;
while (hsfbCursor)
{
HSFB hsfbNext=NULL;
QSFB qsfb;
if (!(qsfb = _GLOBALLOCK(hsfbCursor)))
{
rc=E_OUTOFMEMORY;
exit1:
_LEAVECRITICALSECTION(&qfshr->cs);
_GLOBALUNLOCK(hfs);
return rc;
}
hsfbNext=qsfb->hsfbNext;
if ((rc=RcFlushHsfb(hsfbCursor))!=S_OK)
{
_GLOBALUNLOCK(hsfbCursor);
goto exit1;
}
_GLOBALUNLOCK(hsfbCursor);
hsfbCursor=hsfbNext;
}
*/
if ((rc = RcCloseOrFlushHbt(qfshr->hbt, FALSE)) != S_OK)
{
/* out of disk space, internal error, or out of file handles. */
if (rc != E_HANDLE)
{
/* attempt to invalidate FS by clobbering magic number */
LSeekFid(qfshr->fid, 0L, wSeekSet, NULL);
qfshr->fsh.wMagic = 0;
LcbWriteFid(qfshr->fid, &qfshr->fsh, (LONG)sizeof(FSH), NULL);
}
}
else
{
if (qfshr->fsh.bFlags & FSH_READWRITE)
{
FoSeekFid(qfshr->fid, qfshr->fsh.foFreeList, wSeekSet, NULL);
FreeListWriteToFid(qfshr->hfl, qfshr->fid, NULL);
if (LSeekFid(qfshr->fid, 0L, wSeekSet, &errb) == 0L)
{
LcbWriteFid(qfshr->fid, &qfshr->fsh, (LONG)sizeof(FSH), &errb);
}
FidFlush(qfshr->fid);
}
}
_LEAVECRITICALSECTION(&qfshr->cs);
_GLOBALUNLOCK(hfs);
return rc;
}
/***************************************************************************
*
* @doc INTERNAL API
*
* @func HRESULT PASCAL FAR | RcDestroyFileSysFm |
* Deletes a closed file system (removes it from the disk)
*
* @parm FM | fmFileName |
* Name of file to destroy (FM is same as LPSTR)
*
* @rdesc Returns S_OK if deleted
*
***************************************************************************/
PUBLIC HRESULT PASCAL FAR EXPORT_API RcDestroyFileSysFm(FM fm)
{
#ifdef MOSMAP // {
// Disable function
return ERR_NOTSUPPORTED;
#else // } {
HRESULT errb;
FSH fsh;
FID fid = FidOpenFm(fm, wReadOnly, &errb);
if (fid == fidNil)
return errb;
if (LcbReadFid (fid, &fsh, (LONG)sizeof(FSH), &errb) != (LONG)sizeof(FSH))
{
RcCloseFid(fid);
return E_FILEINVALID;
}
if (fsh.wMagic != wFileSysMagic)
{
RcCloseFid(fid);
return E_FILEINVALID;
}
/* REVIEW: unlink all tmp files for open files? assert count == 0? */
RcCloseFid(fid); /* I'm not checking this return code out of boredom */
return (RcUnlinkFm( fm) );
#endif //}
}
#define MAGIC_FSFILEFIND 0x22334455
/***************************************************************************
*
* @doc INTERNAL API
*
* @func HRESULT PASCAL FAR | RcFindFirstFile |
* Finds the first file equal to or after the given filename. This function
* will always find a filename unless the given search filename is past all
* files in the file system.
*
* @parm LPCSTR | szFileName |
* Name of file to look for. OK to use partial filenames, since the
* first file equal to or after the given filename in the directory
* will be found.
*
* @parm LPFSFILEFIND |lpfsfilefind|
* This structure will be filled with information like file length,
* permission attributes, and file name. It will also be passed to
* RcFindNextFile to get the next filename.
*
* @rdesc Returns S_OK if successful.
*
***************************************************************************/
PUBLIC HRESULT PASCAL FAR EXPORT_API RcFindFirstFile(HFS hfs, LPCSTR szFilename, FSFILEFIND * pfind)
{
QFSHR qfshr;
HRESULT rc = S_OK;
KEY key;
BTPOS btpos;
FILE_REC fr;
if ((szFilename==NULL) || (pfind==NULL) || (hfs == NULL) || ((qfshr = _GLOBALLOCK(hfs)) == NULL))
return E_INVALIDARG;
key = NewKeyFromSz(szFilename);
_ENTERCRITICALSECTION(&qfshr->cs);
RcLookupByKeyAux(qfshr->hbt, key, &btpos, &fr, FALSE);
if (btpos.bk == bkNil)
{ rc=E_NOTEXIST;
goto exit1;
}
GetFrData(&fr);
pfind->btpos=btpos;
pfind->foSize=fr.foSize;
pfind->foStart=fr.foStart;
pfind->bFlags=fr.bFlags;
pfind->hfs=hfs;
pfind->magic=MAGIC_FSFILEFIND;
RcLookupByPos( qfshr->hbt, &btpos, (KEY)pfind->szFilename, 256, &fr );
//GetFrData(&fr);
{ DWORD dwLen;
int iOffset;
LPSTR szCursor;
dwLen=FoFromSz(pfind->szFilename).dwOffset;
iOffset=LenSzFo(pfind->szFilename);
szCursor=pfind->szFilename;
while (dwLen--)
{ *szCursor=*(szCursor+iOffset);
szCursor++;
}
*szCursor=0x00;
}
exit1:
_LEAVECRITICALSECTION(&qfshr->cs);
DisposeMemory((LPSTR)key);
_GLOBALUNLOCK(hfs);
return rc;
}
/***************************************************************************
*
* @doc INTERNAL API
*
* @func HRESULT PASCAL FAR | RcFindNextFile |
* Finds the next file in the file system directory.
*
* @parm LPFSFILEFIND |lpfsfilefind|
* This structure will be filled with information like file length,
* permission attributes, and file name. It must have already been filled
* by RcFindFirstFile before calling this function.
*
* @rdesc Returns S_OK if successful
*
***************************************************************************/
PUBLIC HRESULT PASCAL FAR EXPORT_API RcFindNextFile(FSFILEFIND * pfind)
{
QFSHR qfshr;
HRESULT rc = S_OK;
BTPOS btNewPos;
FILE_REC fr;
if ((!pfind) || (pfind->magic!=MAGIC_FSFILEFIND))
return E_INVALIDARG;
if ((pfind->hfs == NULL) || ((qfshr = _GLOBALLOCK(pfind->hfs)) == NULL))
return E_INVALIDARG;
_ENTERCRITICALSECTION(&qfshr->cs);
if (RcNextPos( qfshr->hbt, &pfind->btpos, &btNewPos )==E_NOTEXIST)
{
rc=E_NOTEXIST;
goto exit1;
}
pfind->btpos=btNewPos;
RcLookupByPos( qfshr->hbt, &pfind->btpos, (KEY)pfind->szFilename, 256, &fr );
GetFrData(&fr);
pfind->foSize=fr.foSize;
pfind->bFlags=fr.bFlags;
{ LPSTR szCursor;
DWORD dwLen;
int iOffset;
dwLen=FoFromSz(pfind->szFilename).dwOffset;
iOffset=LenSzFo(pfind->szFilename);
szCursor=pfind->szFilename;
while (dwLen--)
{ *szCursor=*(szCursor+iOffset);
szCursor++;
}
*szCursor=0x00;
}
exit1:
_LEAVECRITICALSECTION(&qfshr->cs);
_GLOBALUNLOCK(pfind->hfs);
return rc;
}
/***************************************************************************
*
* @doc PRIVATE
*
* @func HFREELIST PASCAL FAR | FreeListInitFromFid |
* Initialize a freelist structure from a fid image. Fid image is
* always in Intel byte ordering format.
*
* @parm FID | fid |
* File id
*
* @parm PHRESULT | lpErrb |
* Error code return - S_OK or E_OUTOFMEMORY
*
* @rdesc Returns handle to a FREELIST, otherwise NULL if error.
*
***************************************************************************/
PUBLIC HFREELIST PASCAL FAR EXPORT_API FreeListInitFromFid( FID fid, PHRESULT lpErrb )
{
FREELISTHDR freehdr;
QFREELIST qFreeList;
HFREELIST hFreeList = NULL;
WORD wMaxBlocks;
WORD wNumBlocks;
DWORD dwLostBytes;
assert(fid!=fidNil);
if (LcbReadFid(fid, &freehdr, sizeof(FREELISTHDR), lpErrb)!=sizeof(FREELISTHDR))
{
return NULL;
}
wMaxBlocks = freehdr.wMaxBlocks;
wNumBlocks = freehdr.wNumBlocks;
dwLostBytes = freehdr.dwLostBytes;
//wMaxBlocks = qFreeListMem->flh.wMaxBlocks;
//wNumBlocks = qFreeListMem->flh.wNumBlocks;
// Mac-ify
wMaxBlocks = SWAPWORD(wMaxBlocks);
wNumBlocks = SWAPWORD(wNumBlocks);
dwLostBytes = SWAPLONG(dwLostBytes);
assert( wMaxBlocks );
if (!(hFreeList=_GLOBALALLOC(GMEM_ZEROINIT| GMEM_MOVEABLE,
sizeof(FREEITEM)*wMaxBlocks+sizeof(FREELISTHDR))))
{
SetErrCode(lpErrb,E_OUTOFMEMORY);
return NULL;
}
if (!(qFreeList=_GLOBALLOCK(hFreeList)))
{
SetErrCode(lpErrb,E_OUTOFMEMORY);
goto exit1;
}
qFreeList->flh.wMaxBlocks=wMaxBlocks;
qFreeList->flh.wNumBlocks=wNumBlocks;
qFreeList->flh.dwLostBytes=dwLostBytes;
LcbReadFid( fid, qFreeList->afreeitem, sizeof(FREEITEM) * wMaxBlocks, lpErrb);
#ifdef _BIG_E
{
QFREEITEM qCurrent = qFreeList->afreeitem;
WORD wBlock;
for (wBlock=0;wBlock<wNumBlocks;wBlock++)
{
qCurrent->foStart.dwOffset = SWAPLONG(qCurrent->foStart.dwOffset);
qCurrent->foStart.dwHigh = SWAPLONG(qCurrent->foStart.dwHigh);
qCurrent->foBlock.dwOffset = SWAPLONG(qCurrent->foBlock.dwOffset);
qCurrent->foBlock.dwHigh = SWAPLONG(qCurrent->foBlock.dwHigh);
}
}
#endif // _BIG_E
_GLOBALUNLOCK(hFreeList);
return hFreeList;
exit1:
_GLOBALFREE(hFreeList);
return NULL;
}
/***************************************************************************
*
* @doc PRIVATE
*
* @func HRESULT PASCAL FAR | FreeListWriteToFid |
* Write to fid with freelist data. Call FreeListSize first
* to make sure the space is large enough. Memory image will always
* be in Intel byte ordering format.
*
* @parm HFREELIST | hFreeList |
* List to retrieve
*
* @parm FID | fid |
* FID to contain free list data
*
* @parm PHRESULT | lpErrb |
* Error return
*
* @rdesc Number of bytes written
*
***************************************************************************/
PUBLIC LONG PASCAL FAR EXPORT_API FreeListWriteToFid( HFREELIST hFreeList, FID fid, PHRESULT lpErrb )
{
QFREELIST qFreeList;
WORD wMaxBlocks;
WORD wNumBlocks;
DWORD dwLostBytes;
LONG lcbSize;
LONG lcbWritten=0L;
assert(fid!=fidNil);
assert(hFreeList);
if (!(qFreeList = _GLOBALLOCK(hFreeList)))
{ SetErrCode(lpErrb, E_OUTOFMEMORY);
goto exit0;
}
wMaxBlocks=qFreeList->flh.wMaxBlocks;
wNumBlocks=qFreeList->flh.wNumBlocks;
dwLostBytes=qFreeList->flh.dwLostBytes;
lcbSize = sizeof(FREELISTHDR) + wMaxBlocks * sizeof(FREEITEM);
#ifdef _BIG_E
{
QFREEITEM qCurrent;
WORD wBlock;
HANDLE hMem;
QFREELIST qFreeListMem;
if (!(hMem = _GLOBALALLOC(GMEM_MOVEABLE, lcbSize)))
{
SetErrCode(lpErrb, E_OUTOFMEMORY);
goto exit0;
}
qFreeListMem = (QFREELIST)_GLOBALLOCK(hMem);
qCurrent = qFreeListMem->afreeitem;
qFreeListMem->flh.wNumBlocks = SWAPWORD( qFreeList->flh.wNumBlocks );
qFreeListMem->flh.wMaxBlocks = SWAPWORD( qFreeList->flh.wMaxBlocks );
qFreeListMem->flh.dwLostBytes = SWAPLONG( qFreeList->flh.dwLostBytes );
for (wBlock=0;wBlock<wNumBlocks;wBlock++)
{
qCurrent->foStart.dwOffset = SWAPLONG(qCurrent->foStart.dwOffset);
qCurrent->foStart.dwHigh = SWAPLONG(qCurrent->foStart.dwHigh);
qCurrent->foBlock.dwOffset = SWAPLONG(qCurrent->foBlock.dwOffset);
qCurrent->foBlock.dwHigh = SWAPLONG(qCurrent->foBlock.dwHigh);
}
lcbWritten=LcbWriteFid(fid, qFreeListMem, lcbSize, lpErrb);
_GLOBALUNLOCK(hMem);
_GLOBALFREE(hMem);
}
#else
lcbWritten=LcbWriteFid(fid, qFreeList, lcbSize, lpErrb);
#endif // _BIG_E
_GLOBALUNLOCK(hFreeList);
exit0:
return lcbWritten;
}