📄 create.c
字号:
/*
* COPYRIGHT: GNU GENERAL PUBLIC LICENSE VERSION 2
* PROJECT: ReiserFs file system driver for Windows NT/2000/XP/Vista.
* FILE: create.c
* PURPOSE:
* PROGRAMMER: Mark Piper, Matt Wu, Bo Brant閚.
* HOMEPAGE:
* UPDATE HISTORY:
*/
/* INCLUDES *****************************************************************/
#include "ntifs.h"
#include "rfsd.h"
/* GLOBALS *****************************************************************/
extern PRFSD_GLOBAL RfsdGlobal;
/* DEFINITIONS *************************************************************/
NTSTATUS
RfsdScanDirCallback(
ULONG BlockNumber,
PVOID pContext );
typedef struct _RFSD_SCANDIR_CALLBACK_CONTEXT {
IN PRFSD_VCB Vcb;
IN PRFSD_KEY_IN_MEMORY pDirectoryKey;
IN PUNICODE_STRING pTargetFilename;
ULONG idxCurrentDentry; /// Running count of the dentries processed, so that MatchingIndex will be relative to all dentry spans
OUT PRFSD_DENTRY_HEAD pMatchingDentry; /// If a matching dentry is found, the callback will fill this structure with it
OUT PULONG pMatchingIndex; /// Index of the matching entry (relative to all dentry spans for the directory)
} RFSD_SCANDIR_CALLBACK_CONTEXT, *PRFSD_SCANDIR_CALLBACK_CONTEXT;
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, RfsdLookupFileName)
#pragma alloc_text(PAGE, RfsdSearchFcbList)
#pragma alloc_text(PAGE, RfsdScanDir)
#pragma alloc_text(PAGE, RfsdCreateFile)
#pragma alloc_text(PAGE, RfsdCreateVolume)
#pragma alloc_text(PAGE, RfsdCreate)
#if DISABLED
#pragma alloc_text(PAGE, RfsdCreateInode)
#pragma alloc_text(PAGE, RfsdSupersedeOrOverWriteFile)
#endif
#pragma alloc_text(PAGE, RfsdScanDirCallback)
#endif
NTSTATUS
RfsdLookupFileName (IN PRFSD_VCB Vcb,
IN PUNICODE_STRING FullFileName,
IN PRFSD_MCB ParentMcb,
OUT PRFSD_MCB * RfsdMcb,
IN OUT PRFSD_INODE Inode) // An allocated, but unfilled inode, to which the matching file's information will be put
{
NTSTATUS Status;
UNICODE_STRING FileName;
PRFSD_MCB Mcb;
RFSD_DENTRY_HEAD DirectoryEntry;
int i = 0;
BOOLEAN bRun = TRUE;
BOOLEAN bParent = FALSE;
RFSD_INODE in;
ULONG off = 0;
Status = STATUS_OBJECT_NAME_NOT_FOUND;
*RfsdMcb = NULL;
// Determine the parent node
if (ParentMcb) {
// Looking up a file in the tree, starting at an arbitrary parent node.
bParent = TRUE;
} else if (FullFileName->Buffer[0] == L'\\') {
// Looking up from the root (so there was no parent). Assign the root node parent from the VCB.
ParentMcb = Vcb->McbTree;
} else {
// Otherwise, fail attempt to lookup non-rooted filename
return STATUS_OBJECT_PATH_NOT_FOUND;
}
RtlZeroMemory(&DirectoryEntry, sizeof(RFSD_DENTRY_HEAD));
// Sanity check that the filename is valid
if (FullFileName->Length == 0) {
return Status;
}
// Only if we're looking up *exactly* the root node, load it, and return it
if (FullFileName->Length == 2 && FullFileName->Buffer[0] == L'\\') {
if (!RfsdLoadInode(Vcb, &(ParentMcb->Key), Inode)) {
return Status;
}
*RfsdMcb = Vcb->McbTree;
return STATUS_SUCCESS;
}
// Begin lookup from the parent node
while (bRun && i < FullFileName->Length/2) {
int Length;
ULONG FileAttr = FILE_ATTRIBUTE_NORMAL;
if (bParent) {
bParent = FALSE;
} else {
// Advance through the (potentially) consecutive '\' path seperators in the filename
while(i < FullFileName->Length/2 && FullFileName->Buffer[i] == L'\\') i++;
}
Length = i;
// Advance to the next '\' path seperator
while(i < FullFileName->Length/2 && (FullFileName->Buffer[i] != L'\\')) i++;
if ( (i - Length) <= 0) {
// All of the tokens have been parsed...
break;
}
else {
// There remains a token between the path seperators...
// FileName is a (non-null-terminated) view into the FullFileName structure
FileName = *FullFileName;
FileName.Buffer += Length;
FileName.Length = (USHORT)((i - Length) * 2);
// Check to see if the parent MCB already contains a child MCB matching the target FileName
Mcb = RfsdSearchMcb(Vcb, ParentMcb, &FileName);
if (Mcb) {
ParentMcb = Mcb;
Status = STATUS_SUCCESS;
if (!IsFlagOn(Mcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY)) {
if (i < FullFileName->Length/2) {
Status = STATUS_OBJECT_PATH_NOT_FOUND;
}
break;
}
} else {
// The parent has no child MCB, or there was no child MCB sibling named FileName. Check the disk using ScanDir...
// Load the parent directory's inode / stat data structure
// For ReiserFS, I'd need the parent's key. This has to be a key leading to a directory... I'm just getting it to pass it to scan.
if (!RfsdLoadInode(Vcb, &(ParentMcb->Key), &in)) {
Status = STATUS_OBJECT_NAME_NOT_FOUND;
break;
}
// Sanity check that we loaded a directory (unless we loaded the last token, in which case it's ok that we loaded something else??)
if (!S_ISDIR(in.i_mode)) {
if (i < FullFileName->Length/2) {
Status = STATUS_OBJECT_NAME_NOT_FOUND;
break;
}
}
Status = RfsdScanDir (
Vcb,
ParentMcb,
&FileName,
&off, // <
&(DirectoryEntry) ); // <
if (!NT_SUCCESS(Status)) {
// No such file (or an error occurred), so drop out.
bRun = FALSE;
/*
if (i >= FullFileName->Length/2)
{
*RfsdMcb = ParentMcb;
}
*/
} else {
// We've found what we were looking for...
#if 0 // disabled by ffs too
if (IsFlagOn( SUPER_BLOCK->s_feature_incompat,
RFSD_FEATURE_INCOMPAT_FILETYPE)) {
if (rfsd_dir.file_type == RFSD_FT_DIR)
SetFlag(FileAttr, FILE_ATTRIBUTE_DIRECTORY);
} else
#endif
{
RFSD_KEY_IN_MEMORY key;
key.k_dir_id = DirectoryEntry.deh_dir_id;
key.k_objectid = DirectoryEntry.deh_objectid;
if (!RfsdLoadInode(Vcb, &key, &in)) {
Status = STATUS_OBJECT_NAME_NOT_FOUND;
break;
}
if (S_ISDIR(in.i_mode)) {
SetFlag(FileAttr, FILE_ATTRIBUTE_DIRECTORY);
}
}
SetFlag(ParentMcb->Flags, MCB_IN_USE);
Mcb = RfsdAllocateMcb(Vcb, &FileName, FileAttr);
ClearFlag(ParentMcb->Flags, MCB_IN_USE);
if (!Mcb) {
Status = STATUS_OBJECT_NAME_NOT_FOUND;
break;
}
// NOTE: It should be OK to leave off the 3rd / 4th part of key, because (AFAIK) the only place this is used is ScanDir
Mcb->Key.k_dir_id = DirectoryEntry.deh_dir_id;
Mcb->Key.k_objectid = DirectoryEntry.deh_objectid;
Mcb->Key.k_offset = Mcb->Key.k_type = 0;
Mcb->DeOffset = off;
RfsdAddMcbNode(Vcb, ParentMcb, Mcb);
ParentMcb = Mcb;
}
}
}
}
if (NT_SUCCESS(Status)) {
// If the name has been found, load it according to the inode number in the MCB...
// The result will be returned to the caller via Inode
*RfsdMcb = Mcb;
if (Inode) {
if (!RfsdLoadInode(Vcb, &(Mcb->Key), Inode)) {
RfsdPrint((DBG_ERROR, "RfsdLookupFileName: error loading Inode %x,%xh\n",
Mcb->Key.k_dir_id, Mcb->Key.k_objectid));
Status = STATUS_INSUFFICIENT_RESOURCES;
}
}
}
return Status;
}
/** (This function is only called by LookupFileName.)
NOTE: The offset and type of the key passed are irrelevant, as the function will always open a a directory for searching, and will search for the contents by file name -- not key.
STATUS_INSUFFICIENT_RESOURCES if the filename or diskreading buffer could not be allocated
STATUS_UNSUCCESSFUL if the buffer could not be read from disk
STATUS_NO_SUCH_FILE if the FileName given was not found in the directory scanned
*/
NTSTATUS
RfsdScanDir (IN PRFSD_VCB Vcb,
IN PRFSD_MCB ParentMcb, // Mcb of the directory to be scanned (which holds the ->Key of the directory)
IN PUNICODE_STRING FileName, // Short file name (not necisarilly null-terminated!)
IN OUT PULONG Index, // Offset (in bytes) of the dentry relative to the start of the directory listing
IN OUT PRFSD_DENTRY_HEAD rfsd_dir) // Directory entry of the found item
{
NTSTATUS Status = STATUS_UNSUCCESSFUL;
RFSD_KEY_IN_MEMORY DirectoryKey;
// Construct the key (for the directory to be searched), by copying the structure
DirectoryKey = ParentMcb->Key;
DirectoryKey.k_offset = 0x1;
DirectoryKey.k_type = RFSD_KEY_TYPE_v2_DIRENTRY;
// Request that the filesystem tree be parsed, looking for FileName in directory spans belonging to DirectoryKey
{
RFSD_SCANDIR_CALLBACK_CONTEXT CallbackContext;
CallbackContext.Vcb = Vcb;
CallbackContext.pDirectoryKey = &DirectoryKey;
CallbackContext.pTargetFilename = FileName;
CallbackContext.idxCurrentDentry = 0;
CallbackContext.pMatchingDentry = rfsd_dir;
CallbackContext.pMatchingIndex = Index;
Status = RfsdParseFilesystemTree(Vcb, &DirectoryKey, Vcb->SuperBlock->s_root_block, &RfsdScanDirCallback, &CallbackContext);
if (Status == STATUS_EVENT_DONE)
{
Status = STATUS_SUCCESS;
}
else if (Status == STATUS_SUCCESS)
{
Status = STATUS_NO_SUCH_FILE;
}
else
{
Status = STATUS_UNSUCCESSFUL;
}
}
RfsdPrint((DBG_TRACE, __FUNCTION__ " returning %s\n", RfsdNtStatusToString(Status)));
return Status;
}
NTSTATUS
RfsdCreateFile(PRFSD_IRP_CONTEXT IrpContext, PRFSD_VCB Vcb)
{
NTSTATUS Status = STATUS_UNSUCCESSFUL;
PIO_STACK_LOCATION IrpSp;
PRFSD_FCB Fcb = NULL;
PRFSD_MCB RfsdMcb = NULL;
PRFSD_FCB ParentFcb = NULL;
PRFSD_MCB ParentMcb = NULL;
BOOLEAN bParentFcbCreated = FALSE;
PRFSD_CCB Ccb = NULL;
PRFSD_INODE Inode;
BOOLEAN VcbResourceAcquired = FALSE;
BOOLEAN bDir = FALSE;
BOOLEAN bFcbAllocated = FALSE;
BOOLEAN bCreated = FALSE;
UNICODE_STRING FileName;
PIRP Irp;
ULONG Options;
ULONG CreateDisposition;
BOOLEAN OpenDirectory;
BOOLEAN OpenTargetDirectory;
BOOLEAN CreateDirectory;
BOOLEAN SequentialOnly;
BOOLEAN NoIntermediateBuffering;
BOOLEAN IsPagingFile;
BOOLEAN DirectoryFile;
BOOLEAN NonDirectoryFile;
BOOLEAN NoEaKnowledge;
BOOLEAN DeleteOnClose;
BOOLEAN TemporaryFile;
BOOLEAN CaseSensitive;
ACCESS_MASK DesiredAccess;
ULONG ShareAccess;
Irp = IrpContext->Irp;
IrpSp = IoGetCurrentIrpStackLocation(Irp);
Options = IrpSp->Parameters.Create.Options;
DirectoryFile = IsFlagOn(Options, FILE_DIRECTORY_FILE);
OpenTargetDirectory = IsFlagOn(IrpSp->Flags, SL_OPEN_TARGET_DIRECTORY);
NonDirectoryFile = IsFlagOn(Options, FILE_NON_DIRECTORY_FILE);
SequentialOnly = IsFlagOn(Options, FILE_SEQUENTIAL_ONLY);
NoIntermediateBuffering = IsFlagOn( Options, FILE_NO_INTERMEDIATE_BUFFERING );
NoEaKnowledge = IsFlagOn(Options, FILE_NO_EA_KNOWLEDGE);
DeleteOnClose = IsFlagOn(Options, FILE_DELETE_ON_CLOSE);
CaseSensitive = IsFlagOn(IrpSp->Flags, SL_CASE_SENSITIVE);
TemporaryFile = IsFlagOn(IrpSp->Parameters.Create.FileAttributes,
FILE_ATTRIBUTE_TEMPORARY );
CreateDisposition = (Options >> 24) & 0x000000ff;
IsPagingFile = IsFlagOn(IrpSp->Flags, SL_OPEN_PAGING_FILE);
CreateDirectory = (BOOLEAN)(DirectoryFile &&
((CreateDisposition == FILE_CREATE) ||
(CreateDisposition == FILE_OPEN_IF)));
OpenDirectory = (BOOLEAN)(DirectoryFile &&
((CreateDisposition == FILE_OPEN) ||
(CreateDisposition == FILE_OPEN_IF)));
DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
ShareAccess = IrpSp->Parameters.Create.ShareAccess;
FileName.Buffer = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -