📄 dirctl.c
字号:
/*
* COPYRIGHT: GNU GENERAL PUBLIC LICENSE VERSION 2
* PROJECT: ReiserFs file system driver for Windows NT/2000/XP/Vista.
* FILE: dirctl.c
* PURPOSE:
* PROGRAMMER: Mark Piper, Matt Wu, Bo Brant閚.
* HOMEPAGE:
* UPDATE HISTORY:
*/
/* INCLUDES *****************************************************************/
#include "rfsd.h"
/* GLOBALS ***************************************************************/
extern PRFSD_GLOBAL RfsdGlobal;
/* DEFINITIONS *************************************************************/
NTSTATUS
RfsdDirectoryCallback(
ULONG BlockNumber,
PVOID pContext);
typedef struct _RFSD_CALLBACK_CONTEXT {
PRFSD_VCB Vcb;
PRFSD_CCB Ccb;
PRFSD_KEY_IN_MEMORY pDirectoryKey;
ULONG idxStartingDentry; // The dentry at which the callback should beging triggering output to the Buffer
ULONG idxCurrentDentry; // The current dentry (relative to entire set of dentrys, across all spans)
// These parameters are forwarded to ProcessDirectoryEntry
FILE_INFORMATION_CLASS FileInformationClass; // [s]
PVOID Buffer; // [s]
ULONG BufferLength; // [s]
BOOLEAN ReturnSingleEntry; // [s]
PULONG pUsedLength;
PVOID pPreviousEntry;
} RFSD_CALLBACK_CONTEXT, *PRFSD_CALLBACK_CONTEXT;
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, RfsdGetInfoLength)
#pragma alloc_text(PAGE, RfsdProcessDirEntry)
#pragma alloc_text(PAGE, RfsdQueryDirectory)
#pragma alloc_text(PAGE, RfsdNotifyChangeDirectory)
#pragma alloc_text(PAGE, RfsdDirectoryControl)
#pragma alloc_text(PAGE, RfsdIsDirectoryEmpty)
#pragma alloc_text(PAGE, RfsdDirectoryCallback)
#endif
ULONG
RfsdGetInfoLength(IN FILE_INFORMATION_CLASS FileInformationClass)
{
switch (FileInformationClass) {
case FileDirectoryInformation:
return sizeof(FILE_DIRECTORY_INFORMATION);
break;
case FileFullDirectoryInformation:
return sizeof(FILE_FULL_DIR_INFORMATION);
break;
case FileBothDirectoryInformation:
return sizeof(FILE_BOTH_DIR_INFORMATION);
break;
case FileNamesInformation:
return sizeof(FILE_NAMES_INFORMATION);
break;
default:
break;
}
return 0;
}
ULONG // Returns 0 on error, or InfoLength + NameLength (the amount of the buffer used for the entry given)
RfsdProcessDirEntry(
IN PRFSD_VCB Vcb,
IN FILE_INFORMATION_CLASS FileInformationClass, // Identifier indicating the type of file information this function should report
IN __u32 Key_ParentDirectoryID,
IN __u32 Key_ObjectID,
IN PVOID Buffer, // The user's buffer, as obtained from the IRP context (it is already gauranteed to be valid)
IN ULONG UsedLength, // Length of Buffer used so far
IN ULONG Length, // Length of Buffer remaining, beyond UsedLength
IN ULONG FileIndex, // Byte offset of the dentry?? (This will just be placed into the file info structure of the same name)
IN PUNICODE_STRING pName, // Filled unicode equivalent of the name (as pulled out from the dentry)
IN BOOLEAN Single, // Whether or not QueryDirectory is only supposed to return a single entry
IN PVOID pPreviousEntry ) // A pointer to the previous dir entry in Buffer, which will be linked into the newly added entry if one is created
{
RFSD_INODE inode;
PFILE_DIRECTORY_INFORMATION FDI;
PFILE_FULL_DIR_INFORMATION FFI;
PFILE_BOTH_DIR_INFORMATION FBI;
PFILE_NAMES_INFORMATION FNI;
ULONG InfoLength = 0;
ULONG NameLength = 0;
ULONG dwBytes = 0;
LONGLONG FileSize;
LONGLONG AllocationSize;
// Calculate the size of the entry
NameLength = pName->Length;
InfoLength = RfsdGetInfoLength(FileInformationClass);
if (!InfoLength || InfoLength + NameLength - sizeof(WCHAR) > Length) {
RfsdPrint((DBG_INFO, "RfsdPricessDirEntry: Buffer is not enough.\n"));
return 0;
}
// Given the incoming key for this dentry, load the corresponding stat data.
{
RFSD_KEY_IN_MEMORY key;
key.k_dir_id = Key_ParentDirectoryID;
key.k_objectid = Key_ObjectID;
if(!RfsdLoadInode(Vcb, &key, &inode)) {
RfsdPrint((DBG_ERROR, "RfsdPricessDirEntry: Loading stat data %xh, %xh error.\n", Key_ParentDirectoryID, Key_ObjectID));
DbgBreak();
return 0;
}
}
FileSize = (LONGLONG) inode.i_size;
AllocationSize = CEILING_ALIGNED(FileSize, (ULONGLONG)Vcb->BlockSize); // TODO: THIS ISN'T QUITE RIGHT
// Link the previous entry into this entry
if (pPreviousEntry) {
// NOTE: All entries begin with NextEntryOffset, so it doesn't matter what type I cast to.
((PFILE_NAMES_INFORMATION) (pPreviousEntry))->NextEntryOffset =
(ULONG) ((PUCHAR) Buffer + UsedLength - (PUCHAR) (pPreviousEntry));
}
switch(FileInformationClass) {
case FileDirectoryInformation:
FDI = (PFILE_DIRECTORY_INFORMATION) ((PUCHAR)Buffer + UsedLength);
FDI->NextEntryOffset = 0;
FDI->FileIndex = FileIndex;
FDI->CreationTime = RfsdSysTime(inode.i_ctime);
FDI->LastAccessTime = RfsdSysTime(inode.i_atime);
FDI->LastWriteTime = RfsdSysTime(inode.i_mtime);
FDI->ChangeTime = RfsdSysTime(inode.i_mtime);
FDI->EndOfFile.QuadPart = FileSize;
FDI->AllocationSize.QuadPart = AllocationSize;
FDI->FileAttributes = FILE_ATTRIBUTE_NORMAL;
if (FlagOn(Vcb->Flags, VCB_READ_ONLY) || RfsdIsReadOnly(inode.i_mode)) {
SetFlag(FDI->FileAttributes, FILE_ATTRIBUTE_READONLY);
}
if (S_ISDIR(inode.i_mode))
FDI->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
FDI->FileNameLength = NameLength;
RtlCopyMemory(FDI->FileName, pName->Buffer, NameLength);
dwBytes = InfoLength + NameLength - sizeof(WCHAR);
break;
case FileFullDirectoryInformation:
FFI = (PFILE_FULL_DIR_INFORMATION) ((PUCHAR)Buffer + UsedLength);
FFI->NextEntryOffset = 0;
FFI->FileIndex = FileIndex;
FFI->CreationTime = RfsdSysTime(inode.i_ctime);
FFI->LastAccessTime = RfsdSysTime(inode.i_atime);
FFI->LastWriteTime = RfsdSysTime(inode.i_mtime);
FFI->ChangeTime = RfsdSysTime(inode.i_mtime);
FFI->EndOfFile.QuadPart = FileSize;
FFI->AllocationSize.QuadPart = AllocationSize;
FFI->FileAttributes = FILE_ATTRIBUTE_NORMAL;
if (IsFlagOn(Vcb->Flags, VCB_READ_ONLY) || RfsdIsReadOnly(inode.i_mode)) {
SetFlag(FFI->FileAttributes, FILE_ATTRIBUTE_READONLY);
}
if (S_ISDIR(inode.i_mode))
FFI->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
FFI->FileNameLength = NameLength;
RtlCopyMemory(FFI->FileName, pName->Buffer, NameLength);
dwBytes = InfoLength + NameLength - sizeof(WCHAR);
break;
case FileBothDirectoryInformation:
FBI = (PFILE_BOTH_DIR_INFORMATION) ((PUCHAR)Buffer + UsedLength);
FBI->NextEntryOffset = 0;
FBI->CreationTime = RfsdSysTime(inode.i_ctime);
FBI->LastAccessTime = RfsdSysTime(inode.i_atime);
FBI->LastWriteTime = RfsdSysTime(inode.i_mtime);
FBI->ChangeTime = RfsdSysTime(inode.i_mtime);
FBI->FileIndex = FileIndex;
FBI->EndOfFile.QuadPart = FileSize;
FBI->AllocationSize.QuadPart = AllocationSize;
FBI->FileAttributes = FILE_ATTRIBUTE_NORMAL;
if (FlagOn(Vcb->Flags, VCB_READ_ONLY) || RfsdIsReadOnly(inode.i_mode)) {
SetFlag(FBI->FileAttributes, FILE_ATTRIBUTE_READONLY);
}
if (S_ISDIR(inode.i_mode))
FBI->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
FBI->FileNameLength = NameLength;
RtlCopyMemory(FBI->FileName, pName->Buffer, NameLength);
dwBytes = InfoLength + NameLength - sizeof(WCHAR);
break;
case FileNamesInformation:
FNI = (PFILE_NAMES_INFORMATION) ((PUCHAR)Buffer + UsedLength);
FNI->NextEntryOffset = 0;
FNI->FileNameLength = NameLength;
RtlCopyMemory(FNI->FileName, pName->Buffer, NameLength);
dwBytes = InfoLength + NameLength - sizeof(WCHAR);
break;
default:
break;
}
return dwBytes;
}
/**
caller suplies a ptr to a file obj for an open target dir, a search pattern to use when listing, and a spec of the info requested.
FSD expected to search and return matching info [503]
The Fcb->RfsdMcb->Key will determine which directory to list the contents of.
*/
NTSTATUS
RfsdQueryDirectory (IN PRFSD_IRP_CONTEXT IrpContext)
{
PDEVICE_OBJECT DeviceObject;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
PRFSD_VCB Vcb;
PFILE_OBJECT FileObject;
PRFSD_FCB Fcb;
PRFSD_CCB Ccb;
PIRP Irp;
PIO_STACK_LOCATION IoStackLocation;
FILE_INFORMATION_CLASS FileInformationClass;
ULONG Length;
PUNICODE_STRING FileName;
ULONG FileIndex;
BOOLEAN RestartScan;
BOOLEAN ReturnSingleEntry;
BOOLEAN IndexSpecified;
PUCHAR Buffer;
BOOLEAN FirstQuery;
PRFSD_KEY_IN_MEMORY pQueryKey; // The key of the directory item that is being retrieved
BOOLEAN FcbResourceAcquired = FALSE;
ULONG UsedLength = 0;
__try {
ASSERT(IrpContext);
ASSERT((IrpContext->Identifier.Type == RFSDICX) &&
(IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT)));
DeviceObject = IrpContext->DeviceObject;
//
// This request is not allowed on the main device object
//
if (DeviceObject == RfsdGlobal->DeviceObject) {
Status = STATUS_INVALID_DEVICE_REQUEST;
__leave;
}
Vcb = (PRFSD_VCB) DeviceObject->DeviceExtension;
ASSERT(Vcb != NULL);
ASSERT((Vcb->Identifier.Type == RFSDVCB) &&
(Vcb->Identifier.Size == sizeof(RFSD_VCB)));
ASSERT(IsMounted(Vcb));
FileObject = IrpContext->FileObject;
Fcb = (PRFSD_FCB) FileObject->FsContext;
pQueryKey = &(Fcb->RfsdMcb->Key);
ASSERT(Fcb);
KdPrint(("QueryDirectory on Key {%x,%x,%x,%x}\n",
pQueryKey->k_dir_id, pQueryKey->k_objectid, pQueryKey->k_offset, pQueryKey->k_type));
//
// This request is not allowed on volumes
//
if (Fcb->Identifier.Type == RFSDVCB) {
Status = STATUS_INVALID_PARAMETER;
__leave;
}
ASSERT((Fcb->Identifier.Type == RFSDFCB) &&
(Fcb->Identifier.Size == sizeof(RFSD_FCB)));
if (!IsDirectory(Fcb)) {
Status = STATUS_INVALID_PARAMETER;
__leave;
}
Ccb = (PRFSD_CCB) FileObject->FsContext2;
ASSERT(Ccb);
ASSERT((Ccb->Identifier.Type == RFSDCCB) &&
(Ccb->Identifier.Size == sizeof(RFSD_CCB)));
Irp = IrpContext->Irp;
IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
#ifndef _GNU_NTIFS_
FileInformationClass =
IoStackLocation->Parameters.QueryDirectory.FileInformationClass;
Length = IoStackLocation->Parameters.QueryDirectory.Length;
FileName = IoStackLocation->Parameters.QueryDirectory.FileName;
FileIndex = IoStackLocation->Parameters.QueryDirectory.FileIndex;
#else // _GNU_NTIFS_
FileInformationClass = ((PEXTENDED_IO_STACK_LOCATION)
IoStackLocation)->Parameters.QueryDirectory.FileInformationClass;
Length = ((PEXTENDED_IO_STACK_LOCATION)
IoStackLocation)->Parameters.QueryDirectory.Length;
FileName = ((PEXTENDED_IO_STACK_LOCATION)
IoStackLocation)->Parameters.QueryDirectory.FileName;
FileIndex = ((PEXTENDED_IO_STACK_LOCATION)
IoStackLocation)->Parameters.QueryDirectory.FileIndex;
#endif // _GNU_NTIFS_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -