xbox-kernel/private/ntos/io/dir.c
2020-09-30 17:17:25 +02:00

257 lines
8.1 KiB
C

/*++
Copyright (c) 1989-2001 Microsoft Corporation
Module Name:
dir.c
Abstract:
This module contains the code to implement the NtQueryDirectoryFile
system service for the NT I/O system.
--*/
#include "iop.h"
NTSTATUS
NtQueryDirectoryFile(
IN HANDLE FileHandle,
IN HANDLE Event OPTIONAL,
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
IN PVOID ApcContext OPTIONAL,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID FileInformation,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInformationClass,
IN POBJECT_STRING FileName OPTIONAL,
IN BOOLEAN RestartScan
)
/*++
Routine Description:
This service operates on a directory file specified by the FileHandle
parameter. The service returns information about files in the directory
specified by the file handle. The ReturnSingleEntry parameter specifies
that only a single entry should be returned rather than filling the buffer.
The actual number of files whose information is returned, is the smallest
of the following:
o One entry, if the ReturnSingleEntry parameter is TRUE.
o The number of files whose information fits into the specified
buffer.
o The number of files that exist.
o One entry if the optional FileName parameter is specified.
If the optional FileName parameter is specified, then the only information
that is returned is for that single file, if it exists. Note that the
file name may not specify any wildcard characters according to the naming
conventions of the target file system. The ReturnSingleEntry parameter is
simply ignored.
The information that is obtained about the files in the directory is based
on the FileInformationClass parameter. The legal values are as follows:
o FileNamesInformation
o FileDirectoryInformation
o FileFullDirectoryInformation
Arguments:
FileHandle - Supplies a handle to the directory file for which information
should be returned.
Event - Supplies an optional event to be set to the Signaled state when
the query is complete.
ApcRoutine - Supplies an optional APC routine to be executed when the
query is complete.
ApcContext - Supplies a context parameter to be passed to the ApcRoutine,
if an ApcRoutine was specified.
IoStatusBlock - Address of the caller's I/O status block.
FileInformation - Supplies a buffer to receive the requested information
returned about the contents of the directory.
Length - Supplies the length, in bytes, of the FileInformation buffer.
FileInformationClass - Specfies the type of information that is to be
returned about the files in the specified directory.
ReturnSingleEntry - Supplies a BOOLEAN value that, if TRUE, indicates that
only a single entry should be returned.
FileName - Optionally supplies a file name within the specified directory.
RestartScan - Supplies a BOOLEAN value that, if TRUE, indicates that the
scan should be restarted from the beginning. This parameter must be
set to TRUE by the caller the first time the service is invoked.
Return Value:
The status returned is success if the query operation was properly queued
to the I/O system. Once the operation completes, the status of the query
can be determined by examining the Status field of the I/O status block.
--*/
{
NTSTATUS status;
BOOLEAN synchronousIo;
PDEVICE_OBJECT deviceObject;
PFILE_OBJECT fileObject;
PIRP irp;
PKEVENT eventObject = (PKEVENT) NULL;
PIO_STACK_LOCATION irpSp;
PAGED_CODE();
//
// Reference the file object so the target device can be found and the
// access rights mask can be used in the following checks for callers in
// user mode. Note that if the handle does not refer to a file object,
// then it will fail.
//
status = ObReferenceObjectByHandle( FileHandle,
&IoFileObjectType,
(PVOID *) &fileObject );
if (!NT_SUCCESS( status )) {
return status;
}
//
// If this file has an I/O completion port associated w/it, then ensure
// that the caller did not supply an APC routine, as the two are mutually
// exclusive methods for I/O completion notification.
//
if (fileObject->CompletionContext && IopApcRoutinePresent( ApcRoutine )) {
ObDereferenceObject( fileObject );
return STATUS_INVALID_PARAMETER;
}
//
// Get the address of the event object and set the event to the Not-
// Signaled state, if an event was specified. Note here, too, that if
// the handle does not refer to an event, or if the event cannot be
// written, then the reference will fail.
//
if (ARGUMENT_PRESENT( Event )) {
status = ObReferenceObjectByHandle( Event,
&ExEventObjectType,
(PVOID *) &eventObject );
if (!NT_SUCCESS( status )) {
ObDereferenceObject( fileObject );
return status;
} else {
KeClearEvent( eventObject );
}
}
//
// Make a special check here to determine whether this is a synchronous
// I/O operation. If it is, then wait here until the file is owned by
// the current thread.
//
if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
IopAcquireFileObjectLock(fileObject);
synchronousIo = TRUE;
} else {
synchronousIo = FALSE;
}
//
// Set the file object to the Not-Signaled state.
//
KeClearEvent( &fileObject->Event );
//
// Get the address of the target device object.
//
deviceObject = fileObject->DeviceObject;
//
// Allocate and initialize the I/O Request Packet (IRP) for this operation.
// The allocation is performed with an exception handler in case the
// caller does not have enough quota to allocate the packet.
irp = IoAllocateIrp( deviceObject->StackSize );
if (!irp) {
//
// An IRP could not be allocated. Cleanup and return an appropriate
// error status code.
//
return IopAllocateIrpCleanup( fileObject, eventObject );
}
irp->Tail.Overlay.OriginalFileObject = fileObject;
irp->Tail.Overlay.Thread = PsGetCurrentThread();
//
// Fill in the service independent parameters in the IRP.
//
irp->UserEvent = eventObject;
irp->UserIosb = IoStatusBlock;
irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
irp->Flags |= IRP_DEFER_IO_COMPLETION;
//
// Get a pointer to the stack location for the first driver. This will be
// used to pass the original function codes and parameters.
//
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
irpSp->FileObject = fileObject;
//
// Pass the address of the user's buffer so the driver has access to
// it. It is now the driver's responsibility to do everything.
//
irp->UserBuffer = FileInformation;
//
// Copy the caller's parameters to the service-specific portion of the
// IRP.
//
irpSp->Parameters.QueryDirectory.Length = Length;
irpSp->Parameters.QueryDirectory.FileInformationClass = FileInformationClass;
irpSp->Parameters.QueryDirectory.FileName = FileName;
if (RestartScan) {
irpSp->Flags = SL_RESTART_SCAN;
}
//
// Queue the packet, call the driver, and synchronize appopriately with
// I/O completion.
//
status = IopSynchronousServiceTail( deviceObject,
irp,
fileObject,
TRUE,
synchronousIo );
return status;
}