I used the reference of this project where it creates a handler for IRP_MJ_CREATE. which displays all the files which are created or opened the system. The documentation of IRP_MJ_CREATE is this:
The I/O Manager sends an IRP_MJ_CREATE request when a new file or directory is being created, or when an existing file, device, directory, or volume is being opened.
Normally this IRP is sent on behalf of a user-mode application that has called a Microsoft Win32 function such as CreateFile or on behalf of a kernel-mode component that has called a function such as IoCreateFile, IoCreateFileSpecifyDeviceObjectHint, ZwCreateFile, or ZwOpenFile.
If the create request is completed successfully, the application or kernel-mode component receives a handle to the file object.
This program below prints all the files or volumes which are opened, created.
main.c
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i)
{
DriverObject->MajorFunction[i] = FsFilterDispatchPassThrough;
}
//creating handle for IRP_MJ_CREATE.
DriverObject->MajorFunction[IRP_MJ_CREATE] = FsFilterDispatchCreate;
// IRP_MJ_CREATE IRP Handler
NTSTATUS FsFilterDispatchCreate(
__in PDEVICE_OBJECT DeviceObject,
__in PIRP Irp
)
{
PFILE_OBJECT pFileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
DbgPrint("%wZ\n", &pFileObject->FileName);
return FsFilterDispatchPassThrough(DeviceObject, Irp);
}
I just need the driver to print only when a file or directory is created.
CodePudding user response:
To summarize my comments into an organized solution.
Your filter driver is being called before the actual file system driver. However you want to check the result after the file system driver handled the irp. according to this article, you can simply check irp->IoStatus.Information == FILE_CREATED
.
Now you only need to let the file system driver know that you have more processing to do with the irp, so it won't call IoCompleteRequest
and free the irp. To do so we can use scenario 2 out of the Cheat Sheet. It will end up something like this:
NTSTATUS
CompletionRoutine_2(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
UNREFERENCED_PARAMETER(DeviceObject);
if (Irp->PendingReturned == TRUE) {
//
// You will set the event only if the lower driver has returned
// STATUS_PENDING earlier. This optimization removes the need to
// call KeSetEvent unnecessarily and improves performance because the
// system does not have to acquire an internal lock.
//
KeSetEvent ((PKEVENT) Context, IO_NO_INCREMENT, FALSE);
}
// This is the only status you can return.
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
FsFilterDispatchCreate(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
KEVENT event;
NTSTATUS status;
KeInitializeEvent(&event, NotificationEvent, FALSE);
//
// You are setting completion routine, so you must copy
// current stack location to the next. You cannot skip a location
// here.
//
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,
CompletionRoutine_2,
&event,
TRUE,
TRUE,
TRUE
);
PFSFILTER_DEVICE_EXTENSION pDevExt = (PFSFILTER_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
status = IoCallDriver(pDevExt->AttachedToDeviceObject, Irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&event,
Executive, // WaitReason
KernelMode, // must be Kernelmode to prevent the stack getting paged out
FALSE,
NULL // indefinite wait
);
status = Irp->IoStatus.Status;
}
// Your logic
if (Irp->IoStatus.Information == FILE_CREATED) {
PFILE_OBJECT pFileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
DbgPrint("%wZ\n", &pFileObject->FileName);
}
//
// Because you stopped the completion of the IRP in the CompletionRoutine
// by returning STATUS_MORE_PROCESSING_REQUIRED, you must call
// IoCompleteRequest here.
//
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
When using the example you based on, you can simply change the function to this.