Something went wrong. Try again.
Reactos
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277/* * COPYRIGHT: See COPYRIGHT.TXT * PROJECT: Ext2 File System Driver for WinNT/2K/XP * FILE: dirctl.c * PROGRAMMER: Matt Wu <mattwu@163.com> * HOMEPAGE: http://www.ext2fsd.com * UPDATE HISTORY: */
/* INCLUDES *****************************************************************/
#include "ext2fs.h"
/* GLOBALS ***************************************************************/
extern PEXT2_GLOBAL Ext2Global;
/* DEFINITIONS *************************************************************/
#ifdef ALLOC_PRAGMA#pragma alloc_text(PAGE, Ext2GetInfoLength)#pragma alloc_text(PAGE, Ext2ProcessEntry)#pragma alloc_text(PAGE, Ext2QueryDirectory)#pragma alloc_text(PAGE, Ext2NotifyChangeDirectory)#pragma alloc_text(PAGE, Ext2DirectoryControl)#pragma alloc_text(PAGE, Ext2IsDirectoryEmpty)#endif
ULONGExt2GetInfoLength(IN FILE_INFORMATION_CLASS FileInformationClass){ switch (FileInformationClass) {
case FileDirectoryInformation: return FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName[0]);
case FileFullDirectoryInformation: return FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName[0]);
case FileBothDirectoryInformation: return FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName[0]);
case FileNamesInformation: return FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName[0]);
case FileIdFullDirectoryInformation: return FIELD_OFFSET(FILE_ID_FULL_DIR_INFORMATION, FileName[0]);
case FileIdBothDirectoryInformation: return FIELD_OFFSET(FILE_ID_BOTH_DIR_INFORMATION, FileName[0]);
default: break; }
return 0;}
NTSTATUSExt2ProcessEntry( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_FCB Dcb, IN FILE_INFORMATION_CLASS FileInformationClass, IN ULONG in, IN PVOID Buffer, IN ULONG UsedLength, IN ULONG Length, IN ULONG FileIndex, IN PUNICODE_STRING pName, OUT PULONG EntrySize, IN BOOLEAN Single){ PFILE_DIRECTORY_INFORMATION FDI = NULL; PFILE_FULL_DIR_INFORMATION FFI = NULL; PFILE_ID_FULL_DIR_INFORMATION FIF = NULL;
PFILE_BOTH_DIR_INFORMATION FBI = NULL; PFILE_ID_BOTH_DIR_INFORMATION FIB = NULL;
PFILE_NAMES_INFORMATION FNI = NULL;
PEXT2_MCB Mcb = NULL; PEXT2_MCB Target = NULL;
NTSTATUS Status = STATUS_SUCCESS; struct inode Inode = { 0 };
ULONG InfoLength = 0; ULONG NameLength = 0;#ifndef __REACTOS__ ULONG dwBytes = 0;#endif LONGLONG FileSize = 0; LONGLONG AllocationSize; ULONG FileAttributes = 0;
BOOLEAN IsEntrySymlink = FALSE;
*EntrySize = 0; NameLength = pName->Length; ASSERT((UsedLength & 7) == 0);
InfoLength = Ext2GetInfoLength(FileInformationClass); if (InfoLength == 0) { DEBUG(DL_ERR, ("Ext2ProcessDirEntry: Invalid Info Class %xh for %wZ in %wZ\n", FileInformationClass, pName, &Dcb->Mcb->FullName )); return STATUS_INVALID_INFO_CLASS; }
if (InfoLength + NameLength > Length) { DEBUG(DL_INF, ( "Ext2PricessDirEntry: Buffer is not enough.\n")); Status = STATUS_BUFFER_OVERFLOW; if (UsedLength || InfoLength > Length) { DEBUG(DL_CP, ("Ext2ProcessDirEntry: Buffer overflows for %wZ in %wZ\n", pName, &Dcb->Mcb->FullName )); return Status; } }
DEBUG(DL_CP, ("Ext2ProcessDirEntry: %wZ in %wZ\n", pName, &Dcb->Mcb->FullName ));
Mcb = Ext2SearchMcb(Vcb, Dcb->Mcb, pName); if (NULL != Mcb) { if (S_ISLNK(Mcb->Inode.i_mode) && NULL == Mcb->Target) { Ext2FollowLink( IrpContext, Vcb, Dcb->Mcb, Mcb, 0); }
} else {
Inode.i_ino = in; Inode.i_sb = &Vcb->sb; if (!Ext2LoadInode(Vcb, &Inode)) { DEBUG(DL_ERR, ("Ext2PricessDirEntry: Loading inode %xh (%wZ) error.\n", in, pName )); DbgBreak(); Status = STATUS_SUCCESS; goto errorout; }
if (S_ISDIR(Inode.i_mode) || S_ISREG(Inode.i_mode)) { } else if (S_ISLNK(Inode.i_mode)) { DEBUG(DL_RES, ("Ext2ProcessDirEntry: SymLink: %wZ\\%wZ\n", &Dcb->Mcb->FullName, pName)); Ext2LookupFile(IrpContext, Vcb, pName, Dcb->Mcb, &Mcb,0);
if (Mcb && IsMcbSpecialFile(Mcb)) { Ext2DerefMcb(Mcb); Mcb = NULL; } } else { Inode.i_size = 0; } }
if (Mcb != NULL) {
FileAttributes = Mcb->FileAttr; if (IsMcbSymLink(Mcb)) { Target = Mcb->Target; ASSERT(Target); ASSERT(!IsMcbSymLink(Target)); if (IsMcbDirectory(Target)) { FileSize = 0; FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; } else { FileSize = Target->Inode.i_size; } if (IsFileDeleted(Target)) { ClearFlag(FileAttributes, FILE_ATTRIBUTE_DIRECTORY); FileSize = 0; } } else { if (IsMcbDirectory(Mcb)) { FileSize = 0; } else { FileSize = Mcb->Inode.i_size; } }
if (IsInodeSymLink(&Mcb->Inode)) { IsEntrySymlink = TRUE; }
} else {
if (S_ISDIR(Inode.i_mode)) { FileSize = 0; } else { FileSize = Inode.i_size; }
if (S_ISDIR(Inode.i_mode)) { FileAttributes = FILE_ATTRIBUTE_DIRECTORY; } else if (S_ISLNK(Inode.i_mode)) { FileAttributes = FILE_ATTRIBUTE_REPARSE_POINT; IsEntrySymlink = TRUE; } else { FileAttributes = FILE_ATTRIBUTE_NORMAL; }
if (!Ext2CheckInodeAccess(Vcb, &Inode, Ext2FileCanWrite)) { SetFlag(FileAttributes, FILE_ATTRIBUTE_READONLY); } }
if (FileAttributes == 0) FileAttributes = FILE_ATTRIBUTE_NORMAL;
AllocationSize = CEILING_ALIGNED(ULONGLONG, FileSize, BLOCK_SIZE);
/* process special files under root directory */ if (IsRoot(Dcb)) { /* set hidden and system attributes for Recycled / RECYCLER / pagefile.sys */ BOOLEAN IsDirectory = IsFlagOn(FileAttributes, FILE_ATTRIBUTE_DIRECTORY); if (Ext2IsSpecialSystemFile(pName, IsDirectory)) { SetFlag(FileAttributes, FILE_ATTRIBUTE_HIDDEN); SetFlag(FileAttributes, FILE_ATTRIBUTE_SYSTEM); } }
/* set hidden attribute for all entries starting with '.' */ if (( pName->Length >= 4 && pName->Buffer[0] == L'.') && ((pName->Length == 4 && pName->Buffer[1] != L'.') || pName->Length >= 6 )) { SetFlag(FileAttributes, FILE_ATTRIBUTE_HIDDEN); }
switch (FileInformationClass) {
case FileIdFullDirectoryInformation: FIF = (PFILE_ID_FULL_DIR_INFORMATION) ((PUCHAR)Buffer + UsedLength); case FileFullDirectoryInformation: FFI = (PFILE_FULL_DIR_INFORMATION) ((PUCHAR)Buffer + UsedLength); case FileDirectoryInformation: FDI = (PFILE_DIRECTORY_INFORMATION) ((PUCHAR)Buffer + UsedLength);
if (!Single) { FDI->NextEntryOffset = CEILING_ALIGNED(ULONG, InfoLength + NameLength, 8); }
FDI->FileIndex = FileIndex;
if (Mcb) {
FDI->CreationTime = Mcb->CreationTime; FDI->LastAccessTime = Mcb->LastAccessTime; FDI->LastWriteTime = Mcb->LastWriteTime; FDI->ChangeTime = Mcb->ChangeTime;
} else {
FDI->CreationTime = Ext2NtTime(Inode.i_ctime); FDI->LastAccessTime = Ext2NtTime(Inode.i_atime); FDI->LastWriteTime = Ext2NtTime(Inode.i_mtime); FDI->ChangeTime = Ext2NtTime(Inode.i_mtime); }
FDI->FileAttributes = FileAttributes; FDI->EndOfFile.QuadPart = FileSize; FDI->AllocationSize.QuadPart = AllocationSize;
FDI->FileNameLength = NameLength; if (InfoLength + NameLength > Length) { NameLength = Length - InfoLength; }
if (FIF) { FIF->FileId.QuadPart = (LONGLONG) in; if (IsEntrySymlink) { FIF->EaSize = IO_REPARSE_TAG_SYMLINK; } RtlCopyMemory(&FIF->FileName[0], &pName->Buffer[0], NameLength); } else if (FFI) { if (IsEntrySymlink) { FFI->EaSize = IO_REPARSE_TAG_SYMLINK; } RtlCopyMemory(&FFI->FileName[0], &pName->Buffer[0], NameLength); } else { RtlCopyMemory(&FDI->FileName[0], &pName->Buffer[0], NameLength); }
*EntrySize = InfoLength + NameLength; break;
case FileIdBothDirectoryInformation: FIB = (PFILE_ID_BOTH_DIR_INFORMATION)((PUCHAR)Buffer + UsedLength); case FileBothDirectoryInformation: FBI = (PFILE_BOTH_DIR_INFORMATION) ((PUCHAR)Buffer + UsedLength);
if (!Single) { FBI->NextEntryOffset = CEILING_ALIGNED(ULONG, InfoLength + NameLength, 8); }
FBI->FileIndex = FileIndex; FBI->EndOfFile.QuadPart = FileSize; FBI->AllocationSize.QuadPart = AllocationSize;
if (Mcb) {
FBI->CreationTime = Mcb->CreationTime; FBI->LastAccessTime = Mcb->LastAccessTime; FBI->LastWriteTime = Mcb->LastWriteTime; FBI->ChangeTime = Mcb->ChangeTime;
} else {
FBI->CreationTime = Ext2NtTime(Inode.i_ctime); FBI->LastAccessTime = Ext2NtTime(Inode.i_atime); FBI->LastWriteTime = Ext2NtTime(Inode.i_mtime); FBI->ChangeTime = Ext2NtTime(Inode.i_mtime); }
FBI->FileAttributes = FileAttributes;
FBI->FileNameLength = NameLength; if (InfoLength + NameLength > Length) { NameLength = Length - InfoLength; }
if (FIB) { FIB->FileId.QuadPart = (LONGLONG)in; if (IsEntrySymlink) { FIB->EaSize = IO_REPARSE_TAG_SYMLINK; } RtlCopyMemory(&FIB->FileName[0], &pName->Buffer[0], NameLength); } else { RtlCopyMemory(&FBI->FileName[0], &pName->Buffer[0], NameLength); }
*EntrySize = InfoLength + NameLength; break;
case FileNamesInformation:
FNI = (PFILE_NAMES_INFORMATION) ((PUCHAR)Buffer + UsedLength); if (!Single) { FNI->NextEntryOffset = CEILING_ALIGNED(ULONG, InfoLength + NameLength, 8); }
FNI->FileNameLength = NameLength; if (InfoLength + NameLength > Length) { NameLength = Length - InfoLength; } RtlCopyMemory(&FNI->FileName[0], &pName->Buffer[0], NameLength);
*EntrySize = InfoLength + NameLength; break;
default: Status = STATUS_INVALID_INFO_CLASS; break; }
if (Mcb) { Ext2DerefMcb(Mcb); }
errorout:
DEBUG(DL_CP, ("Ext2ProcessDirEntry: Status = %xh for %wZ in %wZ\n", Status, pName, &Dcb->Mcb->FullName ));
return Status;}
BOOLEANExt2IsWearingCloak( IN PEXT2_VCB Vcb, IN POEM_STRING OemName){ size_t PatLen = 0;
/* we could not filter the files: "." and ".." */ if (OemName->Length >= 1 && OemName->Buffer[0] == '.') {
if ( OemName->Length == 2 && OemName->Buffer[1] == '.') { return FALSE; } else if (OemName->Length == 1) { return FALSE; } }
/* checking name prefix */ if (Vcb->bHidingPrefix) { PatLen = strlen(&Vcb->sHidingPrefix[0]); if (PatLen > 0 && PatLen <= OemName->Length) { if ( _strnicmp( OemName->Buffer, Vcb->sHidingPrefix, PatLen ) == 0) { return TRUE; } } }
/* checking name suffix */ if (Vcb->bHidingSuffix) { PatLen = strlen(&Vcb->sHidingSuffix[0]); if (PatLen > 0 && PatLen <= OemName->Length) { if ( _strnicmp(&OemName->Buffer[OemName->Length - PatLen], Vcb->sHidingSuffix, PatLen ) == 0) { return TRUE; } } }
return FALSE;}
static int Ext2FillEntry(void *context, const char *name, int namlen, ULONG offset, __u32 ino, unsigned int d_type){ PEXT2_FILLDIR_CONTEXT fc = context; PEXT2_IRP_CONTEXT IrpContext = fc->efc_irp;
PEXT2_FCB Fcb = IrpContext->Fcb; PEXT2_CCB Ccb = IrpContext->Ccb; PEXT2_VCB Vcb = Fcb->Vcb;
OEM_STRING Oem; UNICODE_STRING Unicode = { 0 }; NTSTATUS Status = STATUS_SUCCESS; ULONG EntrySize; USHORT NameLen; int rc = 0;
if (fc->efc_start > 0 && (fc->efc_single || (fc->efc_size < fc->efc_start + namlen * 2 + Ext2GetInfoLength(fc->efc_fi)) )) { rc = 1; goto errorout; }
Oem.Buffer = (void *)name; Oem.Length = namlen & 0xFF; Oem.MaximumLength = Oem.Length;
/* skip . and .. */ if ((Oem.Length == 1 && name[0] == '.') || (Oem.Length == 2 && name[0] == '.' && name[1] == '.' )) { goto errorout; }
if (Ext2IsWearingCloak(Vcb, &Oem)) { goto errorout; }
NameLen = (USHORT)Ext2OEMToUnicodeSize(Vcb, &Oem); if (NameLen <= 0) { fc->efc_status = STATUS_INSUFFICIENT_RESOURCES; rc = -ENOMEM; goto errorout; }
Unicode.MaximumLength = NameLen + 2; Unicode.Buffer = Ext2AllocatePool( PagedPool, Unicode.MaximumLength, EXT2_INAME_MAGIC ); if (!Unicode.Buffer) { DEBUG(DL_ERR, ( "Ex2QueryDirectory: failed to " "allocate InodeFileName.\n")); fc->efc_status = STATUS_INSUFFICIENT_RESOURCES; rc = -ENOMEM; goto errorout; } RtlZeroMemory(Unicode.Buffer, Unicode.MaximumLength); INC_MEM_COUNT(PS_INODE_NAME, Unicode.Buffer, Unicode.MaximumLength);
Status = Ext2OEMToUnicode(Vcb, &Unicode, &Oem); if (!NT_SUCCESS(Status)) { DEBUG(DL_ERR, ( "Ex2QueryDirectory: Ext2OEMtoUnicode failed with %xh.\n", Status)); fc->efc_status = STATUS_INSUFFICIENT_RESOURCES; rc = -ENOMEM; goto errorout; }
if (FsRtlDoesNameContainWildCards( &Ccb->DirectorySearchPattern) ? FsRtlIsNameInExpression(&Ccb->DirectorySearchPattern, &Unicode, TRUE, NULL) : !RtlCompareUnicodeString(&Ccb->DirectorySearchPattern, &Unicode, TRUE)) { Status = Ext2ProcessEntry(fc->efc_irp, Vcb, Fcb, fc->efc_fi, ino, fc->efc_buf, CEILING_ALIGNED(ULONG, fc->efc_start, 8), fc->efc_size - CEILING_ALIGNED(ULONG, fc->efc_start, 8), offset, &Unicode, &EntrySize, fc->efc_single); if (NT_SUCCESS(Status)) { if (EntrySize > 0) { fc->efc_prev = CEILING_ALIGNED(ULONG, fc->efc_start, 8); fc->efc_start = fc->efc_prev + EntrySize; } else { DbgBreak(); } } else { if (Status == STATUS_BUFFER_OVERFLOW) { if (fc->efc_start == 0) { fc->efc_start = EntrySize; } else { Status = STATUS_SUCCESS; } } rc = 1; } }
errorout:
fc->efc_status = Status; if (Unicode.Buffer) { DEC_MEM_COUNT(PS_INODE_NAME, Unicode.Buffer, Unicode.MaximumLength ); Ext2FreePool(Unicode.Buffer, EXT2_INAME_MAGIC); }
return rc;}
NTSTATUSExt2QueryDirectory (IN PEXT2_IRP_CONTEXT IrpContext){ PDEVICE_OBJECT DeviceObject; NTSTATUS Status = STATUS_UNSUCCESSFUL; PEXT2_VCB Vcb = NULL; PFILE_OBJECT FileObject = NULL; PEXT2_FCB Fcb = NULL; PEXT2_MCB Mcb = NULL; PEXT2_CCB Ccb = NULL; PIRP Irp = NULL; PIO_STACK_LOCATION IoStackLocation = NULL;
ULONG Length; ULONG FileIndex; PUNICODE_STRING FileName; PUCHAR Buffer;
BOOLEAN RestartScan; BOOLEAN ReturnSingleEntry; BOOLEAN IndexSpecified; BOOLEAN FirstQuery; BOOLEAN FcbResourceAcquired = FALSE;
USHORT NameLen; FILE_INFORMATION_CLASS fi;
OEM_STRING Oem = { 0 }; UNICODE_STRING Unicode = { 0 }; PEXT2_DIR_ENTRY2 pDir = NULL;
ULONG ByteOffset; ULONG RecLen = 0; ULONG EntrySize = 0;
EXT2_FILLDIR_CONTEXT fc = { 0 };
_SEH2_TRY {
ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
DeviceObject = IrpContext->DeviceObject;
// // This request is not allowed on the main device object // if (IsExt2FsDevice(DeviceObject)) { Status = STATUS_INVALID_DEVICE_REQUEST; _SEH2_LEAVE; }
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == EXT2VCB) && (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
if (!IsMounted(Vcb)) { Status = STATUS_VOLUME_DISMOUNTED; _SEH2_LEAVE; }
if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) { Status = STATUS_ACCESS_DENIED; _SEH2_LEAVE; }
FileObject = IrpContext->FileObject; Fcb = (PEXT2_FCB) FileObject->FsContext; if (Fcb == NULL) { Status = STATUS_INVALID_PARAMETER; _SEH2_LEAVE; } Mcb = Fcb->Mcb; if (NULL == Mcb) { Status = STATUS_INVALID_PARAMETER; _SEH2_LEAVE; } ASSERT (!IsMcbSymLink(Mcb));
// // This request is not allowed on volumes // if (Fcb->Identifier.Type == EXT2VCB) { Status = STATUS_INVALID_PARAMETER; _SEH2_LEAVE; }
ASSERT((Fcb->Identifier.Type == EXT2FCB) && (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
if (!IsMcbDirectory(Mcb)) { Status = STATUS_NOT_A_DIRECTORY; _SEH2_LEAVE; }
if (IsFileDeleted(Mcb)) { Status = STATUS_NOT_A_DIRECTORY; _SEH2_LEAVE; }
Ccb = (PEXT2_CCB) FileObject->FsContext2;
ASSERT(Ccb); ASSERT((Ccb->Identifier.Type == EXT2CCB) && (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
Irp = IrpContext->Irp; IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
#ifndef _GNU_NTIFS_
fi = IoStackLocation->Parameters.QueryDirectory.FileInformationClass;
Length = IoStackLocation->Parameters.QueryDirectory.Length;
FileName = (PUNICODE_STRING)IoStackLocation->Parameters.QueryDirectory.FileName;
FileIndex = IoStackLocation->Parameters.QueryDirectory.FileIndex;
#else // _GNU_NTIFS_
fi = ((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_
RestartScan = FlagOn(((PEXTENDED_IO_STACK_LOCATION) IoStackLocation)->Flags, SL_RESTART_SCAN); ReturnSingleEntry = FlagOn(((PEXTENDED_IO_STACK_LOCATION) IoStackLocation)->Flags, SL_RETURN_SINGLE_ENTRY); IndexSpecified = FlagOn(((PEXTENDED_IO_STACK_LOCATION) IoStackLocation)->Flags, SL_INDEX_SPECIFIED);
Buffer = Ext2GetUserBuffer(Irp); if (Buffer == NULL) { DbgBreak(); Status = STATUS_INVALID_USER_BUFFER; _SEH2_LEAVE; }
if (!IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) { Status = STATUS_PENDING; _SEH2_LEAVE; }
if (!ExAcquireResourceSharedLite( &Fcb->MainResource, IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) { Status = STATUS_PENDING; _SEH2_LEAVE; } FcbResourceAcquired = TRUE;
if (FileName != NULL) {
if (Ccb->DirectorySearchPattern.Buffer != NULL) {
FirstQuery = FALSE;
} else {
FirstQuery = TRUE;
Ccb->DirectorySearchPattern.Length = Ccb->DirectorySearchPattern.MaximumLength = FileName->Length;
Ccb->DirectorySearchPattern.Buffer = Ext2AllocatePool(PagedPool, FileName->Length, EXT2_DIRSP_MAGIC);
if (Ccb->DirectorySearchPattern.Buffer == NULL) { DEBUG(DL_ERR, ( "Ex2QueryDirectory: failed to allocate SerarchPattern.\n")); Status = STATUS_INSUFFICIENT_RESOURCES; _SEH2_LEAVE; }
INC_MEM_COUNT( PS_DIR_PATTERN, Ccb->DirectorySearchPattern.Buffer, Ccb->DirectorySearchPattern.MaximumLength);
Status = RtlUpcaseUnicodeString( &(Ccb->DirectorySearchPattern), FileName, FALSE);
if (!NT_SUCCESS(Status)) { _SEH2_LEAVE; } }
} else if (Ccb->DirectorySearchPattern.Buffer != NULL) {
FirstQuery = FALSE; FileName = &Ccb->DirectorySearchPattern;
} else {
FirstQuery = TRUE;
Ccb->DirectorySearchPattern.Length = Ccb->DirectorySearchPattern.MaximumLength = 2;
Ccb->DirectorySearchPattern.Buffer = Ext2AllocatePool(PagedPool, 4, EXT2_DIRSP_MAGIC);
if (Ccb->DirectorySearchPattern.Buffer == NULL) { DEBUG(DL_ERR, ( "Ex2QueryDirectory: failed to allocate SerarchPattern (1st).\n")); Status = STATUS_INSUFFICIENT_RESOURCES; _SEH2_LEAVE; }
INC_MEM_COUNT( PS_DIR_PATTERN, Ccb->DirectorySearchPattern.Buffer, Ccb->DirectorySearchPattern.MaximumLength);
RtlZeroMemory(Ccb->DirectorySearchPattern.Buffer, 4); RtlCopyMemory( Ccb->DirectorySearchPattern.Buffer, L"*\0", 2); }
if (IndexSpecified) { Ccb->filp.f_pos = FileIndex; } else { if (RestartScan || FirstQuery) { Ccb->filp.f_pos = FileIndex = 0; } else { FileIndex = (ULONG)Ccb->filp.f_pos; } }
RtlZeroMemory(Buffer, Length);
fc.efc_irp = IrpContext; fc.efc_buf = Buffer; fc.efc_size = Length; fc.efc_start = 0; fc.efc_single = ReturnSingleEntry; fc.efc_fi = fi; fc.efc_status = STATUS_SUCCESS;
#ifdef EXT2_HTREE_INDEX
if (EXT3_HAS_COMPAT_FEATURE(Mcb->Inode.i_sb, EXT3_FEATURE_COMPAT_DIR_INDEX) && ((EXT3_I(&Mcb->Inode)->i_flags & EXT3_INDEX_FL) || ((Mcb->Inode.i_size >> BLOCK_BITS) == 1)) ) { int rc = ext3_dx_readdir(&Ccb->filp, Ext2FillEntry, &fc); Status = fc.efc_status; if (rc != ERR_BAD_DX_DIR) { goto errorout; } /* * We don't set the inode dirty flag since it's not * critical that it get flushed back to the disk. */ EXT3_I(&Mcb->Inode)->i_flags &= ~EXT3_INDEX_FL; }#endif
if (Mcb->Inode.i_size <= Ccb->filp.f_pos) { Status = STATUS_NO_MORE_FILES; _SEH2_LEAVE; }
pDir = Ext2AllocatePool( PagedPool, sizeof(EXT2_DIR_ENTRY2), EXT2_DENTRY_MAGIC );
if (!pDir) { DEBUG(DL_ERR, ( "Ex2QueryDirectory: failed to allocate pDir.\n")); Status = STATUS_INSUFFICIENT_RESOURCES; _SEH2_LEAVE; }
INC_MEM_COUNT(PS_DIR_ENTRY, pDir, sizeof(EXT2_DIR_ENTRY2)); ByteOffset = FileIndex;
DEBUG(DL_CP, ("Ex2QueryDirectory: Dir: %wZ Index=%xh Pattern : %wZ.\n", &Fcb->Mcb->FullName, FileIndex, &Ccb->DirectorySearchPattern));
while ((ByteOffset < Mcb->Inode.i_size) && (CEILING_ALIGNED(ULONG, fc.efc_start, 8) < Length)) {
RtlZeroMemory(pDir, sizeof(EXT2_DIR_ENTRY2));
Status = Ext2ReadInode( IrpContext, Vcb, Mcb, (ULONGLONG)ByteOffset, (PVOID)pDir, sizeof(EXT2_DIR_ENTRY2), FALSE, &EntrySize);
if (!NT_SUCCESS(Status)) { DbgBreak(); _SEH2_LEAVE; }
if (pDir->rec_len == 0) { RecLen = BLOCK_SIZE - (ByteOffset & (BLOCK_SIZE - 1)); } else { RecLen = ext3_rec_len_from_disk(pDir->rec_len); }
if (!pDir->inode || pDir->inode >= INODES_COUNT) { goto ProcessNextEntry; }
/* skip . and .. */ if ((pDir->name_len == 1 && pDir->name[0] == '.') || (pDir->name_len == 2 && pDir->name[0] == '.' && pDir->name[1] == '.' )) { goto ProcessNextEntry; }
Oem.Buffer = pDir->name; Oem.Length = (pDir->name_len & 0xff); Oem.MaximumLength = Oem.Length;
if (Ext2IsWearingCloak(Vcb, &Oem)) { goto ProcessNextEntry; }
NameLen = (USHORT) Ext2OEMToUnicodeSize(Vcb, &Oem);
if (NameLen <= 0) { DEBUG(DL_CP, ("Ext2QueryDirectory: failed to count unicode length for inode: %xh\n", pDir->inode)); Status = STATUS_INSUFFICIENT_RESOURCES; break; }
if ( Unicode.Buffer != NULL && Unicode.MaximumLength > NameLen) { /* reuse buffer */ } else { /* free and re-allocate it */ if (Unicode.Buffer) { DEC_MEM_COUNT(PS_INODE_NAME, Unicode.Buffer, Unicode.MaximumLength); Ext2FreePool(Unicode.Buffer, EXT2_INAME_MAGIC); } Unicode.MaximumLength = NameLen + 2; Unicode.Buffer = Ext2AllocatePool( PagedPool, Unicode.MaximumLength, EXT2_INAME_MAGIC ); if (!Unicode.Buffer) { DEBUG(DL_ERR, ( "Ex2QueryDirectory: failed to " "allocate InodeFileName.\n")); Status = STATUS_INSUFFICIENT_RESOURCES; _SEH2_LEAVE; } INC_MEM_COUNT(PS_INODE_NAME, Unicode.Buffer, Unicode.MaximumLength); }
Unicode.Length = 0; RtlZeroMemory(Unicode.Buffer, Unicode.MaximumLength);
Status = Ext2OEMToUnicode(Vcb, &Unicode, &Oem); if (!NT_SUCCESS(Status)) { DEBUG(DL_ERR, ( "Ex2QueryDirectory: Ext2OEMtoUnicode failed with %xh.\n", Status)); Status = STATUS_INSUFFICIENT_RESOURCES; _SEH2_LEAVE; }
DEBUG(DL_CP, ( "Ex2QueryDirectory: process inode: %xh / %wZ (%d).\n", pDir->inode, &Unicode, Unicode.Length));
if (FsRtlDoesNameContainWildCards( &(Ccb->DirectorySearchPattern)) ? FsRtlIsNameInExpression( &(Ccb->DirectorySearchPattern), &Unicode, TRUE, NULL) : !RtlCompareUnicodeString( &(Ccb->DirectorySearchPattern), &Unicode, TRUE) ) {
Status = Ext2ProcessEntry( IrpContext, Vcb, Fcb, fi, pDir->inode, Buffer, CEILING_ALIGNED(ULONG, fc.efc_start, 8), Length - CEILING_ALIGNED(ULONG, fc.efc_start, 8), ByteOffset, &Unicode, &EntrySize, ReturnSingleEntry );
if (NT_SUCCESS(Status)) { if (EntrySize > 0) { fc.efc_prev = CEILING_ALIGNED(ULONG, fc.efc_start, 8); fc.efc_start = fc.efc_prev + EntrySize; } else { DbgBreak(); } } else { if (Status == STATUS_BUFFER_OVERFLOW) { if (fc.efc_start == 0) { fc.efc_start = EntrySize; } else { Status = STATUS_SUCCESS; } } else { _SEH2_LEAVE; } break; } }
ProcessNextEntry:
ByteOffset += RecLen; Ccb->filp.f_pos = ByteOffset;
if (fc.efc_start && ReturnSingleEntry) { Status = STATUS_SUCCESS; goto errorout; } }
errorout:
((PULONG)((PUCHAR)Buffer + fc.efc_prev))[0] = 0; FileIndex = ByteOffset;
if (Status == STATUS_BUFFER_OVERFLOW) { /* just return fc.efc_start/EntrySize bytes that we filled */ } else if (!fc.efc_start) { if (NT_SUCCESS(Status)) { if (FirstQuery) { Status = STATUS_NO_SUCH_FILE; } else { Status = STATUS_NO_MORE_FILES; } } } else { Status = STATUS_SUCCESS; }
} _SEH2_FINALLY {
if (FcbResourceAcquired) { ExReleaseResourceLite(&Fcb->MainResource); }
if (pDir != NULL) { Ext2FreePool(pDir, EXT2_DENTRY_MAGIC); DEC_MEM_COUNT(PS_DIR_ENTRY, pDir, sizeof(EXT2_DIR_ENTRY2)); }
if (Unicode.Buffer != NULL) { DEC_MEM_COUNT(PS_INODE_NAME, Unicode.Buffer, Unicode.MaximumLength); Ext2FreePool(Unicode.Buffer, EXT2_INAME_MAGIC); }
if (!IrpContext->ExceptionInProgress) {
if ( Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
Status = Ext2LockUserBuffer( IrpContext->Irp, Length, IoWriteAccess );
if (NT_SUCCESS(Status)) { Status = Ext2QueueRequest(IrpContext); } else { Ext2CompleteIrpContext(IrpContext, Status); } } else { IrpContext->Irp->IoStatus.Information = fc.efc_start; Ext2CompleteIrpContext(IrpContext, Status); } } } _SEH2_END;
return Status;}
NTSTATUSExt2NotifyChangeDirectory ( IN PEXT2_IRP_CONTEXT IrpContext){ PDEVICE_OBJECT DeviceObject; BOOLEAN CompleteRequest = TRUE; NTSTATUS Status = STATUS_UNSUCCESSFUL; PEXT2_VCB Vcb = NULL; PEXT2_FCB Fcb = NULL; PEXT2_CCB Ccb = NULL; PIRP Irp = NULL; PIO_STACK_LOCATION IrpSp; PFILE_OBJECT FileObject; ULONG CompletionFilter; BOOLEAN WatchTree;
BOOLEAN bFcbAcquired = FALSE;
_SEH2_TRY {
ASSERT(IrpContext); ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
// // Always set the wait flag in the Irp context for the original request. //
SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
DeviceObject = IrpContext->DeviceObject;
if (IsExt2FsDevice(DeviceObject)) { Status = STATUS_INVALID_DEVICE_REQUEST; _SEH2_LEAVE; }
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
ASSERT(Vcb != NULL); ASSERT((Vcb->Identifier.Type == EXT2VCB) && (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
FileObject = IrpContext->FileObject; Fcb = (PEXT2_FCB) FileObject->FsContext; ASSERT(Fcb); if (Fcb->Identifier.Type == EXT2VCB) { DbgBreak(); Status = STATUS_INVALID_PARAMETER; _SEH2_LEAVE; } ASSERT((Fcb->Identifier.Type == EXT2FCB) && (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
Ccb = (PEXT2_CCB) FileObject->FsContext2; ASSERT(Ccb); ASSERT((Ccb->Identifier.Type == EXT2CCB) && (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
/* do nothing if target fie was deleted */ if (FlagOn(Fcb->Flags, FCB_DELETE_PENDING)) { Status = STATUS_FILE_DELETED; _SEH2_LEAVE; }
if (!IsDirectory(Fcb)) { DbgBreak(); Status = STATUS_INVALID_PARAMETER; _SEH2_LEAVE; }
if (ExAcquireResourceExclusiveLite( &Fcb->MainResource, TRUE )) { bFcbAcquired = TRUE; } else { Status = STATUS_PENDING; _SEH2_LEAVE; }
Irp = IrpContext->Irp;
IrpSp = IoGetCurrentIrpStackLocation(Irp);
#ifndef _GNU_NTIFS_
CompletionFilter = IrpSp->Parameters.NotifyDirectory.CompletionFilter;
#else // _GNU_NTIFS_
CompletionFilter = ((PEXTENDED_IO_STACK_LOCATION) IrpSp)->Parameters.NotifyDirectory.CompletionFilter;
#endif // _GNU_NTIFS_
WatchTree = IsFlagOn(IrpSp->Flags, SL_WATCH_TREE);
if (FlagOn(Fcb->Flags, FCB_DELETE_PENDING)) { Status = STATUS_DELETE_PENDING; _SEH2_LEAVE; }
FsRtlNotifyFullChangeDirectory( Vcb->NotifySync, &Vcb->NotifyList, FileObject->FsContext2, (PSTRING)(&Fcb->Mcb->FullName), WatchTree, FALSE, CompletionFilter, Irp, NULL, NULL );
CompleteRequest = FALSE;
Status = STATUS_PENDING;
/* Currently the driver is read-only but here is an example on how to use the FsRtl-functions to report a change:
ANSI_STRING TestString; USHORT FileNamePartLength;
RtlInitAnsiString(&TestString, "\\ntifs.h");
FileNamePartLength = 7;
FsRtlNotifyReportChange( Vcb->NotifySync, // PNOTIFY_SYNC NotifySync &Vcb->NotifyList, // PLIST_ENTRY NotifyList &TestString, // PSTRING FullTargetName &FileNamePartLength, // PUSHORT FileNamePartLength FILE_NOTIFY_CHANGE_NAME // ULONG FilterMatch );
or
ANSI_STRING TestString;
RtlInitAnsiString(&TestString, "\\ntifs.h");
FsRtlNotifyFullReportChange( Vcb->NotifySync, // PNOTIFY_SYNC NotifySync &Vcb->NotifyList, // PLIST_ENTRY NotifyList &TestString, // PSTRING FullTargetName 1, // USHORT TargetNameOffset NULL, // PSTRING StreamName OPTIONAL NULL, // PSTRING NormalizedParentName OPTIONAL FILE_NOTIFY_CHANGE_NAME, // ULONG FilterMatch 0, // ULONG Action NULL // PVOID TargetContext ); */
} _SEH2_FINALLY {
if (bFcbAcquired) { ExReleaseResourceLite(&Fcb->MainResource); }
if (!IrpContext->ExceptionInProgress) { if (CompleteRequest) { if (Status == STATUS_PENDING) { Ext2QueueRequest(IrpContext); } else { Ext2CompleteIrpContext(IrpContext, Status); } } else { IrpContext->Irp = NULL; Ext2CompleteIrpContext(IrpContext, Status); } } } _SEH2_END;
return Status;}
VOIDExt2NotifyReportChange ( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_MCB Mcb, IN ULONG Filter, IN ULONG Action ){ USHORT Offset;
Offset = (USHORT) ( Mcb->FullName.Length - Mcb->ShortName.Length);
FsRtlNotifyFullReportChange( Vcb->NotifySync, &(Vcb->NotifyList), (PSTRING) (&Mcb->FullName), (USHORT) Offset, (PSTRING)NULL, (PSTRING) NULL, (ULONG) Filter, (ULONG) Action, (PVOID) NULL );
// ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);}
NTSTATUSExt2DirectoryControl (IN PEXT2_IRP_CONTEXT IrpContext){ NTSTATUS Status;
ASSERT(IrpContext);
ASSERT((IrpContext->Identifier.Type == EXT2ICX) && (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
switch (IrpContext->MinorFunction) {
case IRP_MN_QUERY_DIRECTORY: Status = Ext2QueryDirectory(IrpContext); break;
case IRP_MN_NOTIFY_CHANGE_DIRECTORY: Status = Ext2NotifyChangeDirectory(IrpContext); break;
default: Status = STATUS_INVALID_DEVICE_REQUEST; Ext2CompleteIrpContext(IrpContext, Status); }
return Status;}
BOOLEANExt2IsDirectoryEmpty ( PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb, PEXT2_MCB Mcb){ if (!IsMcbDirectory(Mcb) || IsMcbSymLink(Mcb)) { return TRUE; }
return !!ext3_is_dir_empty(IrpContext, &Mcb->Inode);}