📄 kfc.c
字号:
//
// (C) Copyright 1996 OSR Open Systems Resources, Inc.
// All Rights Reserved
//
// Permission to use this code is granted provided that the OSR
// copyright is retained in the original source code and that
// the OSR copyright is displayed anywhere a copyright notice is
// displayed for the product in which this code is used.
//
//
// This sample program demonstrates how to copy data between two
// files.
//
#include "kfc.h"
//
// Forward declarations
//
static NTSTATUS KfcCreateClose(PDEVICE_OBJECT, PIRP);
static NTSTATUS KfcDeviceControl(PDEVICE_OBJECT, PIRP);
static NTSTATUS KfcCopyFile(PFILE_OBJECT, PFILE_OBJECT);
static VOID KfcGetFileStandardInformation(PFILE_OBJECT, PFILE_STANDARD_INFORMATION, PIO_STATUS_BLOCK);
static VOID KfcRead(PFILE_OBJECT, PLARGE_INTEGER, ULONG, PMDL, PIO_STATUS_BLOCK);
static VOID KfcWrite(PFILE_OBJECT, PLARGE_INTEGER, ULONG, PMDL, PIO_STATUS_BLOCK);
static VOID KfcSetFileAllocation(PFILE_OBJECT, PLARGE_INTEGER, PIO_STATUS_BLOCK);
static VOID KfcUnload(PDRIVER_OBJECT);
static NTSTATUS KfcIoCompletion(PDEVICE_OBJECT, PIRP, PVOID);
//
// Internal constants
//
#define KFC_MAX_TRANSFER_SIZE (0x10000)
#define KFC_DEVICE_NAME L"\\Device\\OsrKfc"
#define KFC_DOS_NAME L"\\DosDevices\\OsrKfc"
//
// DriverEntry
//
// This is the entry point for the driver, responsible for initializing the
// data structures used by the driver, setting up the driver object and
// preparing for normal operation.
//
// Inputs:
// DriverObject - the driver object representing THIS driver. This is
// created by the I/O Manager when our driver loads.
//
// RegistryPath - A pointer to the registry path to the key for this driver.
//
//
// Outputs:
// None.
//
// Context:
// Like all driver entry routines, this routine is called in the context
// of the system process.
//
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
UNICODE_STRING deviceName;
UNICODE_STRING dosDeviceName;
PDEVICE_OBJECT deviceObject;
NTSTATUS status;
DbgPrint("KFC Driver Entry called\n");
RtlInitUnicodeString(&deviceName, KFC_DEVICE_NAME);
//
// Create a named device object for the KFC device. This will allow
// communications with the KFC driver.
//
status = IoCreateDevice(DriverObject,
0,
&deviceName,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&deviceObject);
if (!NT_SUCCESS(status)) {
//
// Indicate the error
//
DbgPrint("IoCreateDevice failed 0x%x\n", status);
return status;
}
//
// Create a symbolic link into the DosDevices area to allow access
// to Win32 applications.
//
RtlInitUnicodeString(&dosDeviceName, KFC_DOS_NAME);
status = IoCreateSymbolicLink(&dosDeviceName, &deviceName);
if (!NT_SUCCESS(status)) {
//
// Indicate the error
//
DbgPrint("IoCreateSymbolicLink failed 0x%x\n", status);
IoDeleteDevice(deviceObject);
return status;
}
//
// Overwrite the driver dispatch entry points this driver will
// implement. Remember that the others all point to the "trivial"
// function that returns STATUS_NOT_IMPLEMENTED.
//
DriverObject->MajorFunction[IRP_MJ_CREATE] = KfcCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = KfcCreateClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KfcDeviceControl;
//
// Set up the unload function
//
DriverObject->DriverUnload = KfcUnload;
//
// We are done. Note that if you wanted to export the functionality of
// this driver to Win32 applications, this would be the IDEAL place to
// add a symbolic link. We skip that step for this example, since the
// samke kfcopy application will use the native NT interface instead.
//
return STATUS_SUCCESS;
}
//
// KfcUnload
//
// This routine is called to unload the driver.
//
// Inputs:
// DriverObject - the driver object for this driver
//
// Outputs:
// None.
//
// Returns:
// None.
//
// Notes:
// None.
static VOID KfcUnload(PDRIVER_OBJECT DriverObject)
{
UNICODE_STRING symLinkName;
//
// First, delete the symbolic link.
//
RtlInitUnicodeString(&symLinkName, KFC_DOS_NAME);
IoDeleteSymbolicLink(&symLinkName);
//
// Now, delete the device object.
//
IoDeleteDevice(DriverObject->DeviceObject);
//
// Done!
//
return;
}
//
// KfcCreateClose
//
//
static NTSTATUS KfcCreateClose(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
//
// KfcDeviceControl
//
static NTSTATUS KfcDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
PHANDLE fileHandles;
PFILE_OBJECT source, target;
NTSTATUS status;
switch(irpSp->Parameters.DeviceIoControl.IoControlCode) {
case KFC_COPY_FILE:
//
// Extract the file handles
//
if (irpSp->Parameters.DeviceIoControl.InputBufferLength < 2 * sizeof(PHANDLE)) {
//
// The buffer is not large enough to contain the file handles.
//
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
break;
}
fileHandles = (PHANDLE)Irp->AssociatedIrp.SystemBuffer;
status = ObReferenceObjectByHandle(fileHandles[0],
FILE_READ_ACCESS, // ACCESS_MASK
*IoFileObjectType, // POBJECT_TYPE
UserMode, // Access mode
&source, // output file object
0);
if (!NT_SUCCESS(status)) {
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
break;
}
status = ObReferenceObjectByHandle(fileHandles[1],
FILE_WRITE_ACCESS, // ACCESS_MASK
*IoFileObjectType,
UserMode,
&target,
0);
if (!NT_SUCCESS(status)) {
//
// Failure to dereference the object will cause file object leakage in
// the system.
//
ObDereferenceObject(source);
//
// Fail the request.
//
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
break;
}
//
// If we get to this point, we perform the copy.
//
Irp->IoStatus.Status = KfcCopyFile(target, source);
Irp->IoStatus.Information = 0;
//
// Now release the file object references
//
ObDereferenceObject(source);
ObDereferenceObject(target);
break;
default:
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
Irp->IoStatus.Information = 0;
}
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
//
// KfcCopyFile
//
// This routine implements the fast file copy code.
//
// Inputs:
// TargetFileObject - copying TO
// SourceFileObject - copying FROM
//
// Outputs:
// None.
//
// Returns:
// SUCCESS when it works, otherwise an appropriate error
//
// Notes:
// None.
//
static NTSTATUS KfcCopyFile(PFILE_OBJECT TargetFileObject, PFILE_OBJECT SourceFileObject)
{
PVOID buffer;
PMDL mdl;
IO_STATUS_BLOCK iosb;
FILE_STANDARD_INFORMATION standardInformation;
LARGE_INTEGER currentOffset;
LONGLONG bytesToTransfer;
//
// The algorithm used by this routine is straight-forward: read 64k chunks from the
// source file and write it to the target file, until the entire file itself has been copied.
//
buffer = ExAllocatePoolWithTag(NonPagedPool,
KFC_MAX_TRANSFER_SIZE,
'BcfK');
if (!buffer) {
//
// Allocation must have failed.
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Build an MDL describing the buffer. We'll use THAT to do the
// I/O (rather than a direct buffer address.)
//
mdl = IoAllocateMdl(buffer, KFC_MAX_TRANSFER_SIZE, FALSE, TRUE, 0);
MmBuildMdlForNonPagedPool(mdl);
//
// Set up the current offset information
//
currentOffset.QuadPart = 0;
//
// Get the size of the input file.
//
KfcGetFileStandardInformation(SourceFileObject, &standardInformation, &iosb);
if (!NT_SUCCESS(iosb.Status)) {
//
// This is a failure condition.
//
return (iosb.Status);
}
//
// Set the allocation size of the output file.
//
KfcSetFileAllocation(TargetFileObject,
&standardInformation.AllocationSize,
&iosb);
if (!NT_SUCCESS(iosb.Status)) {
//
// Failure...
//
return (iosb.Status);
}
//
// Save away the information about the # of bytes to transfer.
//
bytesToTransfer = standardInformation.EndOfFile.QuadPart;
//
// Now copy the source to the target until we run out...
//
while (bytesToTransfer) {
ULONG nextTransferSize;
//
// The # of bytes to copy in the next operation is based upon the maximum of
// the balance IN the file, or KFC_MAX_TRANSFER_SIZE
//
nextTransferSize = (bytesToTransfer < KFC_MAX_TRANSFER_SIZE) ?
(ULONG) bytesToTransfer : KFC_MAX_TRANSFER_SIZE;
KfcRead(SourceFileObject, ¤tOffset, nextTransferSize, mdl, &iosb);
if (!NT_SUCCESS(iosb.Status)) {
//
// An error condition occurred.
//
return (iosb.Status);
}
KfcWrite(TargetFileObject, ¤tOffset, nextTransferSize, mdl, &iosb);
if (!NT_SUCCESS(iosb.Status)) {
//
// An error condition occurred.
//
return (iosb.Status);
}
//
// Now, update the offset/bytes to transfer information
//
currentOffset.QuadPart += nextTransferSize;
bytesToTransfer -= nextTransferSize;
}
//
// At this point, we're done with the copy operation. Return success
//
return (STATUS_SUCCESS);
}
//
// KfcGetFileStandardInformation
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -