|
|
/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
file.c
Abstract:
This module contains kd host machine file I/O support.
Author:
Drew Bliss (drewb) 21-Feb-2001
Revision History:
--*/
#include "kdp.h"
#pragma hdrstop
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGEKD, KdCreateRemoteFile)
#pragma alloc_text(PAGEKD, KdReadRemoteFile)
#pragma alloc_text(PAGEKD, KdWriteRemoteFile)
#pragma alloc_text(PAGEKD, KdCloseRemoteFile)
#pragma alloc_text(PAGEKD, KdPullRemoteFile)
#pragma alloc_text(PAGEKD, KdPushRemoteFile)
#endif
NTSTATUS KdCreateRemoteFile( OUT PHANDLE Handle, OUT PULONG64 Length, OPTIONAL IN PUNICODE_STRING FileName, IN ACCESS_MASK DesiredAccess, IN ULONG FileAttributes, IN ULONG ShareAccess, IN ULONG CreateDisposition, IN ULONG CreateOptions ) { BOOLEAN Enable; DBGKD_FILE_IO Irp; ULONG Index;
if (FileName->Length > PACKET_MAX_SIZE - sizeof(Irp)) { return STATUS_INVALID_PARAMETER; } if (KdDebuggerNotPresent != FALSE) { return STATUS_DEBUGGER_INACTIVE; } Enable = KdEnterDebugger(NULL, NULL);
//
// Look for an open slot.
//
for (Index = 0; Index < KD_MAX_REMOTE_FILES; Index++) { if (KdpRemoteFiles[Index].RemoteHandle == 0) { break; } }
if (Index >= KD_MAX_REMOTE_FILES) { Irp.Status = STATUS_NO_MEMORY; goto Exit; }
Irp.ApiNumber = DbgKdCreateFileApi; Irp.u.CreateFile.DesiredAccess = DesiredAccess; Irp.u.CreateFile.FileAttributes = FileAttributes; Irp.u.CreateFile.ShareAccess = ShareAccess; Irp.u.CreateFile.CreateDisposition = CreateDisposition; Irp.u.CreateFile.CreateOptions = CreateOptions;
for (;;) { STRING MessageData; STRING MessageHeader; ULONG ReturnCode; ULONG Length;
MessageHeader.Length = sizeof(Irp); MessageHeader.MaximumLength = sizeof(Irp); MessageHeader.Buffer = (PCHAR)&Irp;
// Copy the filename to the message buffer
// so that a terminator can be added.
KdpCopyFromPtr(KdpMessageBuffer, FileName->Buffer, FileName->Length, &Length); MessageData.Length = (USHORT)Length + sizeof(WCHAR); MessageData.Buffer = (PCHAR) KdpMessageBuffer; *(PWCHAR)&MessageData.Buffer[MessageData.Length - sizeof(WCHAR)] = UNICODE_NULL; //
// Send packet to the kernel debugger on the host machine.
//
KdSendPacket(PACKET_TYPE_KD_FILE_IO, &MessageHeader, &MessageData, &KdpContext);
if (KdDebuggerNotPresent != FALSE) { Irp.Status = STATUS_DEBUGGER_INACTIVE; break; } //
// Receive packet from the kernel debugger on the host machine.
//
MessageData.MaximumLength = KDP_MESSAGE_BUFFER_SIZE; MessageData.Buffer = (PCHAR) KdpMessageBuffer;
do { ReturnCode = KdReceivePacket(PACKET_TYPE_KD_FILE_IO, &MessageHeader, &MessageData, &Length, &KdpContext); } while (ReturnCode == KDP_PACKET_TIMEOUT);
if (ReturnCode == KDP_PACKET_RECEIVED) { break; } } if (NT_SUCCESS(Irp.Status)) { KdpRemoteFiles[Index].RemoteHandle = Irp.u.CreateFile.Handle; // Add one so that zero is reserved for invalid-handle.
*Handle = UlongToHandle(Index + 1); if (ARGUMENT_PRESENT(Length)) { *Length = Irp.u.CreateFile.Length; } } Exit: KdExitDebugger(Enable); return Irp.Status; }
NTSTATUS KdReadRemoteFile( IN HANDLE Handle, IN ULONG64 Offset, OUT PVOID Buffer, IN ULONG Length, OUT PULONG Completed ) { BOOLEAN Enable; DBGKD_FILE_IO Irp; ULONG Index; ULONG _Completed = 0;
Index = HandleToUlong(Handle) - 1; if (Index >= KD_MAX_REMOTE_FILES) { return STATUS_INVALID_PARAMETER; } Enable = KdEnterDebugger(NULL, NULL);
if (KdpRemoteFiles[Index].RemoteHandle == 0) { Irp.Status = STATUS_INVALID_PARAMETER; goto Exit; }
Irp.ApiNumber = DbgKdReadFileApi; Irp.Status = STATUS_SUCCESS; Irp.u.ReadFile.Handle = KdpRemoteFiles[Index].RemoteHandle; Irp.u.ReadFile.Offset = Offset;
while (Length > 0) { STRING MessageData; STRING MessageHeader; ULONG ReturnCode; ULONG RecvLength;
if (Length > PACKET_MAX_SIZE - sizeof(Irp)) { Irp.u.ReadFile.Length = PACKET_MAX_SIZE - sizeof(Irp); } else { Irp.u.ReadFile.Length = Length; } MessageHeader.Length = sizeof(Irp); MessageHeader.MaximumLength = sizeof(Irp); MessageHeader.Buffer = (PCHAR)&Irp; //
// Send packet to the kernel debugger on the host machine.
//
KdSendPacket(PACKET_TYPE_KD_FILE_IO, &MessageHeader, NULL, &KdpContext);
//
// Receive packet from the kernel debugger on the host machine.
//
MessageData.MaximumLength = (USHORT)Irp.u.ReadFile.Length; MessageData.Buffer = Buffer;
do { ReturnCode = KdReceivePacket(PACKET_TYPE_KD_FILE_IO, &MessageHeader, &MessageData, &RecvLength, &KdpContext); } while (ReturnCode == KDP_PACKET_TIMEOUT);
if (ReturnCode == KDP_PACKET_RECEIVED) { if (!NT_SUCCESS(Irp.Status)) { break; }
_Completed += RecvLength; Buffer = (PVOID)((PUCHAR)Buffer + RecvLength); Irp.u.ReadFile.Offset += RecvLength; Length -= RecvLength; } } *Completed = _Completed; Exit: KdExitDebugger(Enable); return Irp.Status; }
NTSTATUS KdWriteRemoteFile( IN HANDLE Handle, IN ULONG64 Offset, IN PVOID Buffer, IN ULONG Length, OUT PULONG Completed ) { BOOLEAN Enable; DBGKD_FILE_IO Irp; ULONG Index; ULONG _Completed = 0;
Index = HandleToUlong(Handle) - 1; if (Index >= KD_MAX_REMOTE_FILES) { return STATUS_INVALID_PARAMETER; } Enable = KdEnterDebugger(NULL, NULL);
if (KdpRemoteFiles[Index].RemoteHandle == 0) { Irp.Status = STATUS_INVALID_PARAMETER; goto Exit; }
Irp.ApiNumber = DbgKdWriteFileApi; Irp.Status = STATUS_SUCCESS; Irp.u.WriteFile.Handle = KdpRemoteFiles[Index].RemoteHandle; Irp.u.WriteFile.Offset = Offset;
while (Length > 0) { STRING MessageData; STRING MessageHeader; ULONG ReturnCode; ULONG RecvLength;
if (Length > PACKET_MAX_SIZE - sizeof(Irp)) { Irp.u.WriteFile.Length = PACKET_MAX_SIZE - sizeof(Irp); } else { Irp.u.WriteFile.Length = Length; } MessageHeader.Length = sizeof(Irp); MessageHeader.MaximumLength = sizeof(Irp); MessageHeader.Buffer = (PCHAR)&Irp; MessageData.Length = (USHORT)Irp.u.WriteFile.Length; MessageData.Buffer = Buffer;
//
// Send packet to the kernel debugger on the host machine.
//
KdSendPacket(PACKET_TYPE_KD_FILE_IO, &MessageHeader, &MessageData, &KdpContext);
//
// Receive packet from the kernel debugger on the host machine.
//
MessageData.MaximumLength = KDP_MESSAGE_BUFFER_SIZE; MessageData.Buffer = (PCHAR) KdpMessageBuffer;
do { ReturnCode = KdReceivePacket(PACKET_TYPE_KD_FILE_IO, &MessageHeader, &MessageData, &RecvLength, &KdpContext); } while (ReturnCode == KDP_PACKET_TIMEOUT);
if (ReturnCode == KDP_PACKET_RECEIVED) { if (!NT_SUCCESS(Irp.Status)) { break; }
_Completed += Irp.u.WriteFile.Length; Buffer = (PVOID)((PUCHAR)Buffer + Irp.u.WriteFile.Length); Irp.u.WriteFile.Offset += Irp.u.WriteFile.Length; Length -= Irp.u.WriteFile.Length; } } *Completed = _Completed; Exit: KdExitDebugger(Enable); return Irp.Status; }
NTSTATUS KdCloseRemoteFile( IN HANDLE Handle ) { BOOLEAN Enable; DBGKD_FILE_IO Irp; ULONG Index;
Index = HandleToUlong(Handle) - 1; if (Index >= KD_MAX_REMOTE_FILES) { return STATUS_INVALID_PARAMETER; } Enable = KdEnterDebugger(NULL, NULL);
if (KdpRemoteFiles[Index].RemoteHandle == 0) { Irp.Status = STATUS_INVALID_PARAMETER; goto Exit; }
Irp.ApiNumber = DbgKdCloseFileApi; Irp.u.CloseFile.Handle = KdpRemoteFiles[Index].RemoteHandle;
for (;;) { STRING MessageData; STRING MessageHeader; ULONG ReturnCode; ULONG RecvLength;
MessageHeader.Length = sizeof(Irp); MessageHeader.MaximumLength = sizeof(Irp); MessageHeader.Buffer = (PCHAR)&Irp; //
// Send packet to the kernel debugger on the host machine.
//
KdSendPacket(PACKET_TYPE_KD_FILE_IO, &MessageHeader, NULL, &KdpContext);
//
// Receive packet from the kernel debugger on the host machine.
//
MessageData.MaximumLength = KDP_MESSAGE_BUFFER_SIZE; MessageData.Buffer = (PCHAR) KdpMessageBuffer;
do { ReturnCode = KdReceivePacket(PACKET_TYPE_KD_FILE_IO, &MessageHeader, &MessageData, &RecvLength, &KdpContext); } while (ReturnCode == KDP_PACKET_TIMEOUT);
if (ReturnCode == KDP_PACKET_RECEIVED) { break; } } if (NT_SUCCESS(Irp.Status)) { KdpRemoteFiles[Index].RemoteHandle = 0; } Exit: KdExitDebugger(Enable); return Irp.Status; }
#define TRANSFER_LENGTH 8192
NTSTATUS KdPullRemoteFile( IN PUNICODE_STRING FileName, IN ULONG FileAttributes, IN ULONG CreateDisposition, IN ULONG CreateOptions ) { NTSTATUS Status; PVOID Buffer = NULL; ULONG64 Length; HANDLE RemoteHandle = NULL; HANDLE LocalHandle = NULL; OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatus; LARGE_INTEGER LargeInt; ULONG64 Offset;
// Allocate a buffer for data transfers.
Buffer = ExAllocatePoolWithTag(NonPagedPool, TRANSFER_LENGTH, 'oIdK'); if (Buffer == NULL) { return STATUS_NO_MEMORY; }
// Open the remote file for reading.
Status = KdCreateRemoteFile(&RemoteHandle, &Length, FileName, FILE_GENERIC_READ, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, 0); if (!NT_SUCCESS(Status)) { goto Exit; }
// Open the local file for writing.
LargeInt.QuadPart = Length; InitializeObjectAttributes(&ObjectAttributes, FileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); Status = ZwCreateFile(&LocalHandle, FILE_GENERIC_WRITE, &ObjectAttributes, &IoStatus, &LargeInt, FileAttributes, 0, CreateDisposition, CreateOptions, NULL, 0); if (!NT_SUCCESS(Status)) { goto Exit; }
// Copy the file contents.
Offset = 0; while (Length > 0) { ULONG ReqLength, ReqCompleted;
if (Length > TRANSFER_LENGTH) { ReqLength = TRANSFER_LENGTH; } else { ReqLength = (ULONG)Length; } Status = KdReadRemoteFile(RemoteHandle, Offset, Buffer, ReqLength, &ReqCompleted); if (!NT_SUCCESS(Status) || ReqCompleted == 0) { break; }
LargeInt.QuadPart = Offset; Status = ZwWriteFile(LocalHandle, NULL, NULL, NULL, &IoStatus, Buffer, ReqCompleted, &LargeInt, NULL); if (!NT_SUCCESS(Status)) { break; } if (IoStatus.Information < ReqCompleted) { Status = STATUS_UNSUCCESSFUL; break; }
Offset += IoStatus.Information; Length -= IoStatus.Information; } Exit: if (RemoteHandle != NULL) { KdCloseRemoteFile(RemoteHandle); } if (LocalHandle != NULL) { ZwClose(LocalHandle); } if (Buffer != NULL) { ExFreePool(Buffer); } return Status; }
NTSTATUS KdPushRemoteFile( IN PUNICODE_STRING FileName, IN ULONG FileAttributes, IN ULONG CreateDisposition, IN ULONG CreateOptions ) { NTSTATUS Status; PVOID Buffer = NULL; ULONG64 Length; HANDLE RemoteHandle = NULL; HANDLE LocalHandle = NULL; OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatus; LARGE_INTEGER LargeInt; ULONG64 Offset; FILE_END_OF_FILE_INFORMATION EndOfFile;
// Allocate a buffer for data transfers.
Buffer = ExAllocatePoolWithTag(NonPagedPool, TRANSFER_LENGTH, 'oIdK'); if (Buffer == NULL) { return STATUS_NO_MEMORY; }
// Open the remote file for writing.
Status = KdCreateRemoteFile(&RemoteHandle, &Length, FileName, FILE_GENERIC_WRITE, FileAttributes, 0, CreateDisposition, CreateOptions); if (!NT_SUCCESS(Status)) { goto Exit; }
// Open the local file for reading.
InitializeObjectAttributes(&ObjectAttributes, FileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); Status = ZwOpenFile(&LocalHandle, FILE_GENERIC_READ, &ObjectAttributes, &IoStatus, FILE_SHARE_READ, 0); if (!NT_SUCCESS(Status)) { goto Exit; }
Status = NtQueryInformationFile(LocalHandle, &IoStatus, &EndOfFile, sizeof(EndOfFile), FileEndOfFileInformation); if (!NT_SUCCESS(Status)) { goto Exit; }
// Copy the file contents.
Offset = 0; Length = EndOfFile.EndOfFile.QuadPart; while (Length > 0) { ULONG ReqLength, ReqCompleted;
if (Length > TRANSFER_LENGTH) { ReqLength = TRANSFER_LENGTH; } else { ReqLength = (ULONG)Length; } LargeInt.QuadPart = Offset; Status = ZwReadFile(LocalHandle, NULL, NULL, NULL, &IoStatus, Buffer, ReqLength, &LargeInt, NULL); if (!NT_SUCCESS(Status) || IoStatus.Information == 0) { break; }
Status = KdWriteRemoteFile(RemoteHandle, Offset, Buffer, (ULONG)IoStatus.Information, &ReqCompleted); if (!NT_SUCCESS(Status)) { break; } if (ReqCompleted < IoStatus.Information) { Status = STATUS_UNSUCCESSFUL; break; }
Offset += ReqCompleted; Length -= ReqCompleted; } Exit: if (RemoteHandle != NULL) { KdCloseRemoteFile(RemoteHandle); } if (LocalHandle != NULL) { ZwClose(LocalHandle); } if (Buffer != NULL) { ExFreePool(Buffer); } return Status; }
|