Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

516 lines
12 KiB

/*****************************************************************************
* *
* FSCREATE.C *
* *
* Copyright (C) Microsoft Corporation 1990. *
* All Rights reserved. *
* *
******************************************************************************
* *
* Module Intent *
* *
* FS functions for creating and destroying File Systems and Files. *
* *
******************************************************************************
* *
* Current Owner: JohnSc *
* *
*****************************************************************************/
#include "help.h"
#pragma hdrstop
#include "inc\fspriv.h"
_subsystem( FS );
/***************************************************************************\
*
- Function: HfsCreateFileSysFm( fm, qfsp )
-
* Purpose: create and open a new file system
*
* ASSUMES
* args IN: fm - descriptor of file system
* qfsp - pointer to fine-tuning structure (NULL for default)
*
* PROMISES
* returns: handle to newly created and opened file system
* or NULL on failure
*
* Notes: I don't understand what creating a readonly file system would do.
* I think that would have to be done by Fill or Transform.
* You may dispose of the FM you pass in.
*
\***************************************************************************/
HFS STDCALL HfsCreateFileSysFm(FM fm, FS_PARAMS *qfsp)
{
HFS hfs;
QFSHR qfshr;
BTREE_PARAMS btp;
// make file system header
if ((hfs = GhAlloc(GPTR, sizeof(FSHR))) == NULL) {
SetFSErrorRc(rcOutOfMemory);
return NULL;
}
qfshr = PtrFromGh(hfs);
qfshr->fsh.wMagic = wFileSysMagic;
qfshr->fsh.bVersion = FILESYSVERSION;
qfshr->fsh.bFlags = fFSDirty; // >>>> for now not R/O
qfshr->fsh.lifFirstFree = lifNil;
#ifdef _X86_
qfshr->fsh.lifEof = sizeof(FSH); // first free is after header
#else
qfshr->fsh.sdff_file_id = IRegisterFileSDFF(
qfshr->fsh.bFlags & fFSBigEndian ?
SDFF_FILEFLAGS_BIGENDIAN : SDFF_FILEFLAGS_LITTLEENDIAN,
NULL);
qfshr->fsh.lifEof = LcbStructSizeSDFF(qfshr->fsh.sdff_file_id,SE_FSH);
#endif
// build file system file
qfshr->fm = FmCopyFm(fm);
if (qfshr->fm != NULL)
qfshr->fid = FidCreateFm(qfshr->fm);
if (qfshr->fm == NULL || qfshr->fid == HFILE_ERROR) {
FreeGh(hfs);
SetFSErrorRc(RcGetIOError());
return NULL;
}
// build directory
btp.hfs = hfs;
btp.bFlags = fFSIsDirectory;
if (qfsp != NULL)
btp.cbBlock = qfsp->cbBlock;
else
btp.cbBlock = CBBTREEBLOCKDEFAULT;
strcpy(btp.rgchFormat, "z4");
// Create the FS directory btree
qfshr->hbt = HbtCreateBtreeSz(NULL, &btp);
if (qfshr->hbt == NULL) {
RcCloseFid(qfshr->fid);
RcUnlinkFm(qfshr->fm);
DisposeFm(qfshr->fm);
FreeGh(hfs);
SetFSErrorRc(RcGetBtreeError());
return NULL;
}
// return handle to file system
SetFSErrorRc(rcSuccess);
return hfs;
}
/***************************************************************************\
*
- Function: RcDestroyFileSysFm( fm )
-
* Purpose: Destroy a file system
*
* ASSUMES
* args IN: fm - descriptor of file system
* state IN: file system is currently closed: data will be lost
* if this isn't the case
*
* PROMISES
* returns: standard return code
*
* Note: The passed FM must be disposed by the caller.
* +++
*
* Method: Unlinks the native file comprising the file system.
*
\***************************************************************************/
RC STDCALL RcDestroyFileSysFm(FM fm)
{
FID fid = FidOpenFm(fm, OF_READ);
FSH fsh;
if (fid == HFILE_ERROR)
return RcGetIOError();
#ifdef _X86_
if (LcbReadFid(fid, &fsh, sizeof(FSH)) != sizeof(FSH)) {
#else
if (LcbReadFid(fid, &fsh, (LONG)DISK_SIZEOF_FSH()) != (LONG)DISK_SIZEOF_FSH()) {
#endif
RcCloseFid(fid);
return SetFSErrorRc(rcInvalid);
}
if (fsh.wMagic != wFileSysMagic) {
RcCloseFid(fid);
return SetFSErrorRc(rcInvalid);
}
// REVIEW: unlink all tmp files for open files? assert count == 0?
RcCloseFid(fid); // I'm not checking this return code out of boredom
return SetFSErrorRc(RcUnlinkFm(fm));
}
/***************************************************************************\
*
- Function: HfCreateFileHfs( hfs, sz, bFlags )
-
* Purpose: Create and open a file within a specified file system.
*
* ASSUMES
* args IN: hfs - handle to an open file system
* sz - name of file to open (any valid key)
* bFlags - fFSIsDirectory to create the FS directory
* other flags (readonly) are ignored
*
* PROMISES
* returns: handle to newly created and opened file if successful,
* NULL if not.
*
* Notes: I don't understand why you would create a readonly file.
* +++
*
* Method: Allocate the handle struct and fill it in. Create the
* temp file and put a header into it. Don't make btree
* entry: that happens when the file is closed. Do test
* for permission, though.
*
\***************************************************************************/
HF STDCALL HfCreateFileHfs(HFS hfs, LPCSTR psz, BYTE bFlags)
{
HF hf;
QRWFO qrwfo;
QFSHR qfshr;
FH fh;
ASSERT(hfs != NULL);
qfshr = PtrFromGh(hfs);
// make sure file system is writable
if (qfshr->fsh.bFlags & fFSOpenReadOnly) {
SetFSErrorRc(rcNoPermission);
goto error_return;
}
hf = GhAlloc(GPTR, (DWORD) sizeof(RWFO) +
(psz == NULL ? 0 : lstrlen(psz)));
if (hf == NULL) {
SetFSErrorRc(rcOutOfMemory);
goto error_return;
}
qrwfo = (QRWFO) PtrFromGh(hf);
// if they are trying to create a fs dir, make sure thats ok
if (bFlags & fFSIsDirectory) {
if (qfshr->fsh.bFlags & fFSIsDirectory) {
SetFSErrorRc( rcBadArg );
goto error_locked;
}
else
qfshr->fsh.bFlags |= fFSIsDirectory;
}
else
lstrcpy(qrwfo->rgchKey, psz);
// fill in the open file struct
qrwfo->hfs = hfs;
qrwfo->lifBase = 0L;
qrwfo->lifCurrent = 0L;
qrwfo->lcbFile = 0L;
qrwfo->bFlags = bFlags | fFSNoBlock | fFSDirty;
// make a temp file
if (SetFSErrorRc(RcMakeTempFile(qrwfo)) != rcSuccess)
goto error_locked;
// stick the header in it
#ifdef _X86_
fh.lcbBlock = sizeof(FH);
#else
fh.lcbBlock = (LONG)LcbStructSizeSDFF( ISdffFileIdHfs( hfs ), SE_FH );
#endif
fh.lcbFile = 0;
fh.bPerms = bFlags;
#ifdef _X86_
if (LcbWriteFid(qrwfo->fidT, &fh, sizeof(FH)) != sizeof(FH)) {
SetFSErrorRc(RcGetIOError());
RcCloseFid( qrwfo->fidT );
RcUnlinkFm( qrwfo->fm );
goto error_locked;
}
#else // _X86_
{ FH fhDisk;
LONG lcbStructSize;
LcbReverseMapSDFF( ISdffFileIdHfs( hfs ), SE_FH, &fhDisk, &fh );
lcbStructSize = (LONG)LcbStructSizeSDFF( ISdffFileIdHfs( hfs ), SE_FH );
if ( LcbWriteFid( qrwfo->fidT, &fhDisk, lcbStructSize )
!=
lcbStructSize )
{
SetFSErrorRc( RcGetIOError() );
RcCloseFid( qrwfo->fidT );
RcUnlinkFm( qrwfo->fm );
goto error_locked;
}
}
#endif // _X86_
return hf;
error_locked:
FreeGh(hf);
error_return:
return NULL;
}
/***************************************************************************\
*
- Function: RcUnlinkFileHfs( hfs, sz )
-
* Purpose: Unlink a file within a file system
*
* ASSUMES
* args IN: hfs - handle to file system
* sz - name (key) of file to unlink
* state IN: The FS file speced by sz should be closed. (if it wasn't,
* changes won't be saved and temp file may not be deleted)
*
* PROMISES
* returns: standard return code
*
* BUGS: shouldn't this check if the file is ReadOnly?
*
\***************************************************************************/
RC STDCALL RcUnlinkFileHfs(HFS hfs, LPCSTR sz)
{
QFSHR qfshr;
FILE_REC fr;
ASSERT(hfs != NULL);
qfshr = PtrFromGh(hfs);
if (qfshr->fsh.bFlags & fFSOpenReadOnly) {
return SetFSErrorRc( rcNoPermission );
}
// look it up to get the file base offset
if (SetFSErrorRc(RcLookupByKey(qfshr->hbt, (KEY) sz, NULL, &fr))
!= rcSuccess) {
return rcFSError;
}
#ifndef _X86_
LcbMapSDFF( qfshr->fsh.sdff_file_id, SE_FILE_REC, &fr, &fr );
#endif
if (SetFSErrorRc(RcDeleteHbt(qfshr->hbt, (KEY) sz)) == rcSuccess) {
// put the file block on the free list
if (FPlungeQfshr(qfshr))
FFreeBlock(qfshr, fr.lifBase);
}
return rcFSError;
}
/***************************************************************************\
*
- Function: RcAbandonHf( hf )
-
* Purpose: Abandon an open file. All changes since file was opened
* will be lost. If file was opened with a create, it is
* as if the create never happened.
*
* ASSUMES
* args IN: hf
*
* PROMISES
* returns: rc
*
* globals OUT: rcFSError
* +++
*
* Method: Close and unlink the temp file, then unlock and free
* the open file struct. We depend on not saving the
* filename in the directory until the file is closed.
*
\***************************************************************************/
RC STDCALL RcAbandonHf(HF hf)
{
QRWFO qrwfo;
SetFSErrorRc(rcSuccess);
ASSERT(hf != NULL);
qrwfo = PtrFromGh(hf);
if (qrwfo->bFlags & fFSDirty) {
if (RcCloseFid(qrwfo->fidT) != rcSuccess
||
RcUnlinkFm(qrwfo->fm) != rcSuccess)
SetFSErrorRc(RcGetIOError());
}
FreeGh(hf);
return rcFSError;
}
#ifdef _DEBUG
/***************************************************************************\
*
- Function: VerifyHf( hf )
-
* Purpose: Verify the consistency of an HF. The main criterion is
* whether an RcAbandonHf() would succeed.
*
* ASSUMES
* args IN: hf
*
* PROMISES
* state OUT: Asserts on failure.
*
* Note: hf == NULL is considered OK.
* +++
*
* Method: Check the HF memory; if dirty, check that fid != HFILE_ERROR.
*
\***************************************************************************/
void STDCALL VerifyHf(HF hf)
{
QRWFO qrwfo;
if (hf == NULL)
return;
qrwfo = PtrFromGh(hf);
if (qrwfo->bFlags & fFSDirty) {
ASSERT(qrwfo->fidT != HFILE_ERROR); // more fid checking could go here
}
}
#endif // DEBUG
#ifdef _DEBUG
/***************************************************************************\
*
- Function: VerifyHfs( hfs )
-
* Purpose: Verify the consistency of an HFS.
*
* ASSUMES
* args IN: hfs
*
* PROMISES
* state OUT: Asserts on failure.
*
* Note: hfs == NULL is considered OK.
* +++
*
* Method: Check the HF memory. Check the directory btree.
*
\***************************************************************************/
void STDCALL VerifyHfs(HFS hfs)
{
QFSHR qfshr;
if (hfs == NULL)
return;
qfshr = PtrFromGh(hfs);
VerifyHbt(qfshr->hbt);
}
#endif // DEBUG
/***************************************************************************\
*
- Function: RcRenameFileHfs( hfs, szOld, szNew )
-
* Purpose: Rename an existing file in a FS.
*
* ASSUMES
* args IN: hfs -
* szOld - old file name
* szNew - new file name
*
* PROMISES
* returns: rcSuccess - operation succeeded
* rcNoExists - file named szNew doesn't exist in FS
* rcExists - file named szOld already exists in FS
*
* Certain other terrible errors could cause the file
* to exist under both names. It won't be lost entirely.
*
* state OUT: If szNew
* +++
*
* Method: Lookup key szOld, insert data with key szNew,
* then delete key szOld.
*
\***************************************************************************/
// 22-Nov-1993 [ralphw] This is only here because we export it to dll's
RC STDCALL RcRenameFileHfs(HFS hfs, LPSTR szOld, LPSTR szNew)
{
QFSHR qfshr;
FILE_REC fr;
ASSERT(hfs != NULL);
qfshr = (QFSHR) PtrFromGh(hfs);
if (!FPlungeQfshr(qfshr))
return rcFSError;
if (RcLookupByKey(qfshr->hbt, (KEY) szOld, NULL, &fr) != rcSuccess)
return rcFSError;
if (RcInsertHbt(qfshr->hbt, (KEY) szNew, &fr) != rcSuccess)
return rcFSError;
if (RcDeleteHbt(qfshr->hbt, (KEY) szOld) != rcSuccess) {
// bad trouble here, bud.
if (RcDeleteHbt(qfshr->hbt, (KEY) szNew) == rcSuccess)
SetFSErrorRc(rcFailure);
}
return rcFSError;
}