From: short <> Date: Sun, 3 Aug 2003 08:00:27 +0000 (+0000) Subject: +Implemented TraceFS W32 Cache Manager debug tracer X-Git-Tag: bp_captive~104 X-Git-Url: http://git.jankratochvil.net/?p=captive.git;a=commitdiff_plain;h=095f675195194fbe86f5feb0eea97ed1e5d99c77 +Implemented TraceFS W32 Cache Manager debug tracer --- diff --git a/NEWS b/NEWS index f8afc21..00b9745 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,7 @@ NEWS for captive-0.9 * Finished and deployed CORBA sandbox separation * Implemented filesystem unmount to successfuly remount ntfs volume * Generates --bug-pathname resources file for sandbox crash bugreport +* Implemented TraceFS W32 Cache Manager debug tracer NEWS for captive-0.8 (2003-05-02) diff --git a/autogen.pl b/autogen.pl index 5bca278..8f69d12 100755 --- a/autogen.pl +++ b/autogen.pl @@ -52,6 +52,15 @@ AutoGen->run( ./src/libcaptive/sandbox/sandbox-stubs.c ./src/libcaptive/sandbox/sandbox.h ./src/libcaptive/sandbox/sandbox-skelimpl.c + ./src/TraceFS/TraceFS-W32/obj + ./src/TraceFS/TraceFS-W32/objchk + ./src/TraceFS/TraceFS-W32/objfre + ./src/TraceFS/TraceFS-W32/buildchk.log + ./src/TraceFS/TraceFS-W32/buildchk.wrn + ./src/TraceFS/TraceFS-W32/buildchk.err + ./src/TraceFS/TraceFS-W32/buildfre.log + ./src/TraceFS/TraceFS-W32/buildfre.wrn + ./src/TraceFS/TraceFS-W32/buildfre.err )], "prep"=>sub { local *F; diff --git a/configure.in b/configure.in index 294a0e8..40d8a3f 100644 --- a/configure.in +++ b/configure.in @@ -271,6 +271,7 @@ Makefile ./src/client/cmdline/Makefile ./src/client/libcaptive-gnomevfs/Makefile ./src/client/sandbox-server/Makefile +./src/TraceFS/Makefile ./doc/Makefile ./doc/apiref/Makefile ./src/client/libcaptive-gnomevfs/captive.conf diff --git a/src/Makefile.am b/src/Makefile.am index 40ce399..a4d4274 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,6 @@ # $Id$ # automake source for the topsrclevel Makefile -# Copyright (C) 2002 Jan Kratochvil +# Copyright (C) 2002-2003 Jan Kratochvil # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -18,7 +18,4 @@ include $(top_srcdir)/Makefile-head.am -SUBDIRS=libcaptive client - -#EXTRA_DIST+= \ -# Makefile.cflags +SUBDIRS=libcaptive client TraceFS diff --git a/src/TraceFS/Makefile.am b/src/TraceFS/Makefile.am new file mode 100644 index 0000000..e8cb696 --- /dev/null +++ b/src/TraceFS/Makefile.am @@ -0,0 +1,48 @@ +# $Id$ +# UNIX automake source for the makefile of TraceFS +# Copyright (C) 2003 Jan Kratochvil +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; exactly version 2 of June 1991 is required +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +include $(top_srcdir)/Makefile-head.am + +# We cannot use SUBDIRS as build.exe requires file named "Makefile" +# and its syntax is not compatible with automake / UNIX make. + +# TraceFS.sys is built but we consider it as source file here as not everyone +# has Microsoft DDK environment available. +# FIXME: Check for MinGW cross-compiler build possibility. + +EXTRA_DIST+= \ + TraceFS-W32/makeFile \ + TraceFS-W32/Sources \ + TraceFS-W32/TraceFS.c \ + TraceFS-W32/TraceFS.def \ + TraceFS-W32/TraceFS.reg \ + TraceFS-W32/TraceFS.sys \ + \ + checktrace.pl \ + hookfs.pl + +CLEANFILES+= \ + TraceFS-W32/obj \ + TraceFS-W32/objchk \ + TraceFS-W32/objfre \ + TraceFS-W32/buildchk.log \ + TraceFS-W32/buildchk.wrn \ + TraceFS-W32/buildchk.err \ + TraceFS-W32/buildfre.log \ + TraceFS-W32/buildfre.wrn \ + TraceFS-W32/buildfre.err diff --git a/src/TraceFS/TraceFS-W32/Sources b/src/TraceFS/TraceFS-W32/Sources new file mode 100644 index 0000000..7be5a62 --- /dev/null +++ b/src/TraceFS/TraceFS-W32/Sources @@ -0,0 +1,30 @@ +# $Id$ +# Makefile for W32 build of TraceFS by build.exe +# Copyright (C) 2003 Jan Kratochvil +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; exactly version 2 of June 1991 is required +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +TARGETNAME=TraceFS +TARGETPATH=obj + +TARGETTYPE=EXPORT_DRIVER +DRIVERTYPE=FS +NO_NTDLL=1 +UMTYPE=nt + +MSC_WARNING_LEVEL=/W3 /WX + +SOURCES= \ + tracefs.c diff --git a/src/TraceFS/TraceFS-W32/TraceFS.c b/src/TraceFS/TraceFS-W32/TraceFS.c new file mode 100644 index 0000000..3bdd145 --- /dev/null +++ b/src/TraceFS/TraceFS-W32/TraceFS.c @@ -0,0 +1,1366 @@ +/* $Id$ + * Debugging tracer of IRPs and Cc* (Cache Manager) calls for W32 + * Copyright (C) 2003 Jan Kratochvil + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; exactly version 2 of June 1991 is required + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + + +#define CACHE_SIZE 0x200 + + +#define G_N_ELEMENTS(arr) (sizeof(arr)/sizeof((arr)[0])) + +NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (INIT, DriverEntry) +#endif + +static FAST_MUTEX lock_mutex; + +static void lock_init(void) +{ + ExInitializeFastMutex(&lock_mutex); +} + +static void lock(void) +{ + ExAcquireFastMutex(&lock_mutex); +} + +static void unlock(void) +{ + ExReleaseFastMutex(&lock_mutex); +} + +#define DBGPREFIX "TraceFS(0x%08lX/0x%08lX): " +#define DBGARG PsGetCurrentProcess(),PsGetCurrentThread() + +static int dbgindent=0; + +/* lock() will protect dbg_unicode_string() static buffer. */ +#define DBGSINGLE6(fmt,arg1,arg2,arg3,arg4,arg5,arg6) \ + do { lock(); DbgPrint("%*s" DBGPREFIX fmt "\n",dbgindent,"",DBGARG,arg1,arg2,arg3,arg4,arg5,arg6); unlock(); } while (0) +#define DBGSINGLE5(fmt,arg1,arg2,arg3,arg4,arg5) DBGSINGLE6(fmt,arg1,arg2,arg3,arg4,arg5,0) +#define DBGSINGLE4(fmt,arg1,arg2,arg3,arg4) DBGSINGLE5(fmt,arg1,arg2,arg3,arg4,0) +#define DBGSINGLE3(fmt,arg1,arg2,arg3) DBGSINGLE4(fmt,arg1,arg2,arg3,0) +#define DBGSINGLE2(fmt,arg1,arg2) DBGSINGLE3(fmt,arg1,arg2,0) +#define DBGSINGLE1(fmt,arg1) DBGSINGLE2(fmt,arg1,0) +#define DBGSINGLE0(fmt) DBGSINGLE1(fmt,0) +#define DBGSINGLEENTER6(fmt,arg1,arg2,arg3,arg4,arg5,arg6) \ + do { DBGSINGLE6("enter: " fmt,arg1,arg2,arg3,arg4,arg5,arg6); dbgindent++; } while (0) +#define DBGSINGLEENTER5(fmt,arg1,arg2,arg3,arg4,arg5) DBGSINGLEENTER6(fmt,arg1,arg2,arg3,arg4,arg5,0) +#define DBGSINGLEENTER4(fmt,arg1,arg2,arg3,arg4) DBGSINGLEENTER5(fmt,arg1,arg2,arg3,arg4,0) +#define DBGSINGLEENTER3(fmt,arg1,arg2,arg3) DBGSINGLEENTER4(fmt,arg1,arg2,arg3,0) +#define DBGSINGLEENTER2(fmt,arg1,arg2) DBGSINGLEENTER3(fmt,arg1,arg2,0) +#define DBGSINGLEENTER1(fmt,arg1) DBGSINGLEENTER2(fmt,arg1,0) +#define DBGSINGLEENTER0(fmt) DBGSINGLEENTER1(fmt,0) +#define DBGSINGLELEAVE3(fmt,arg1,arg2,arg3) \ + do { dbgindent--; DBGSINGLE3("leave: " fmt,arg1,arg2,arg3); } while (0) +#define DBGSINGLELEAVE2(fmt,arg1,arg2) DBGSINGLELEAVE3(fmt,arg1,arg2,0) +#define DBGSINGLELEAVE1(fmt,arg1) DBGSINGLELEAVE2(fmt,arg1,0) +#define DBGSINGLELEAVE0(fmt) DBGSINGLELEAVE1(fmt,0) + + +/* We cannot use DbgPrint("%wZ",...) as it must have IRQL PASSIVE_LEVEL which + * is not satisfied. + */ +static const char *dbg_unicode_string(UNICODE_STRING *unicode_string) +{ +static char buf[0x100]; +char *d; +PWSTR s; + + if (!unicode_string || !unicode_string->Buffer) + return "NULL"; + d=buf; + *d++='\''; + for (s=unicode_string->Buffer;sBuffer+(unicode_string->Length/2);s++) { + if (d>=buf+sizeof(buf)-4) + break; + *d++=(char)*s; + } + *d++='\''; + *d=0; + return buf; +} + +NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath) +{ +NTSTATUS r; +DEVICE_OBJECT *device_object; + + lock_init(); + + DBGSINGLEENTER1("DriverEntry: RegistryPath=%s",dbg_unicode_string(RegistryPath)); + DBGSINGLE1("DriverEntry: %s","$Id$"); + r=IoCreateDevice( + DriverObject, /* DriverObject */ + 0, /* DeviceExtensionSize */ + NULL, /* DeviceName; optional */ + FILE_DEVICE_UNKNOWN, /* DeviceType */ + 0, /* DeviceCharacteristics */ + FALSE, /* Exclusive */ + &device_object); /* DeviceObject */ + DBGSINGLELEAVE1("DriverEntry: r=0x%lX",(long)r); + return r; +} + +static const char *const irp_mj_dump_FILE_SYSTEM_CONTROL_MinorFunction_names[]={ + "IRP_MN_USER_FS_REQUEST", + "IRP_MN_MOUNT_VOLUME", + "IRP_MN_VERIFY_VOLUME", + "IRP_MN_LOAD_FILE_SYSTEM", + "IRP_MN_KERNEL_CALL", + }; + +/* Compatibility with DDK; the structures match. */ +#define FileSystemControl DeviceIoControl +#define FsControlCode IoControlCode +#ifndef FSCTL_REQUEST_BATCH_OPLOCK +#define FSCTL_REQUEST_BATCH_OPLOCK CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2,METHOD_BUFFERED,FILE_ANY_ACCESS) +#endif +#ifndef FSCTL_LOCK_VOLUME +#define FSCTL_LOCK_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 6,METHOD_BUFFERED,FILE_ANY_ACCESS) +#endif +#ifndef FSCTL_UNLOCK_VOLUME +#define FSCTL_UNLOCK_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 7,METHOD_BUFFERED,FILE_ANY_ACCESS) +#endif +#ifndef FSCTL_DISMOUNT_VOLUME +#define FSCTL_DISMOUNT_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 8,METHOD_BUFFERED,FILE_ANY_ACCESS) +#endif +#ifndef FSCTL_MARK_VOLUME_DIRTY +#define FSCTL_MARK_VOLUME_DIRTY CTL_CODE(FILE_DEVICE_FILE_SYSTEM,12,METHOD_BUFFERED,FILE_ANY_ACCESS) +#endif +#ifndef FSCTL_INVALIDATE_VOLUMES +#define FSCTL_INVALIDATE_VOLUMES CTL_CODE(FILE_DEVICE_FILE_SYSTEM,21,METHOD_BUFFERED,FILE_ANY_ACCESS) +#endif +#ifndef FSCTL_IS_VOLUME_DIRTY +#define FSCTL_IS_VOLUME_DIRTY CTL_CODE(FILE_DEVICE_FILE_SYSTEM,30,METHOD_BUFFERED,FILE_ANY_ACCESS) +#endif +#ifndef FSCTL_FILE_PREFETCH +#define FSCTL_FILE_PREFETCH CTL_CODE(FILE_DEVICE_FILE_SYSTEM,72,METHOD_BUFFERED,FILE_SPECIAL_ACCESS) +#endif + +static void irp_mj_dump(struct _DEVICE_OBJECT *DeviceObject,struct _IRP *Irp) +{ +IO_STACK_LOCATION *IoStackLocation; +FILE_OBJECT *FileObject; + + if (!Irp) { + DBGSINGLE0("Irp==NULL"); + return; + } + IoStackLocation=IoGetCurrentIrpStackLocation(Irp); + if (!IoStackLocation) { + DBGSINGLE0("IoStackLocation==NULL"); + return; + } + if (!(FileObject=IoStackLocation->FileObject)) + DBGSINGLE0("FileObject=NULL"); + else + DBGSINGLE5("FileObject=0x%lX: FileName=%s,Flags=0x%lX,SectionObjectPointer=0x%lX,->SharedCacheMap=0x%lX", + (long)FileObject, + dbg_unicode_string(&FileObject->FileName),FileObject->Flags, + (long)FileObject->SectionObjectPointer, + (!FileObject->SectionObjectPointer ? -1 : (long)FileObject->SectionObjectPointer->SharedCacheMap)); + switch (IoStackLocation->MajorFunction) { + case IRP_MJ_READ: + DBGSINGLE2("READ: ByteOffset=0x%lX,Length=0x%lX", + (long)IoStackLocation->Parameters.Read.ByteOffset.QuadPart, + IoStackLocation->Parameters.Read.Length); + break; + case IRP_MJ_WRITE: + DBGSINGLE2("WRITE: ByteOffset=0x%lX,Length=0x%lX", + (long)IoStackLocation->Parameters.Write.ByteOffset.QuadPart, + IoStackLocation->Parameters.Write.Length); + break; + case IRP_MJ_FILE_SYSTEM_CONTROL: + DBGSINGLE2("FILE_SYSTEM_CONTROL: MinorFunction=%s (%d)", + ((1 + && IoStackLocation->MinorFunction>=0 + && IoStackLocation->MinorFunctionMinorFunction] : "???"), + IoStackLocation->MinorFunction); + switch (IoStackLocation->MinorFunction) { + case IRP_MN_USER_FS_REQUEST: { +const char *FsControlCode_name; + switch (IoStackLocation->Parameters.FileSystemControl.FsControlCode) { + case FSCTL_REQUEST_BATCH_OPLOCK: FsControlCode_name="FSCTL_REQUEST_BATCH_OPLOCK"; break; + case FSCTL_LOCK_VOLUME: FsControlCode_name="FSCTL_LOCK_VOLUME"; break; + case FSCTL_UNLOCK_VOLUME: FsControlCode_name="FSCTL_UNLOCK_VOLUME"; break; + case FSCTL_DISMOUNT_VOLUME: FsControlCode_name="FSCTL_DISMOUNT_VOLUME"; break; + case FSCTL_MARK_VOLUME_DIRTY: FsControlCode_name="FSCTL_MARK_VOLUME_DIRTY"; break; + case FSCTL_INVALIDATE_VOLUMES: FsControlCode_name="FSCTL_INVALIDATE_VOLUMES"; break; + case FSCTL_IS_VOLUME_DIRTY: FsControlCode_name="FSCTL_IS_VOLUME_DIRTY"; break; + case FSCTL_FILE_PREFETCH: FsControlCode_name="FSCTL_FILE_PREFETCH"; break; + default: FsControlCode_name="???"; break; + } + DBGSINGLE2("USER_FS_REQUEST: FsControlCode=%s (%d)",FsControlCode_name, + IoStackLocation->Parameters.FileSystemControl.FsControlCode); + } break; + } + } +} + +#define TRACEFS_MAJORS \ + TRACEFS_MAJOR(IRP_MJ_CREATE) \ + TRACEFS_MAJOR(IRP_MJ_CREATE_NAMED_PIPE) \ + TRACEFS_MAJOR(IRP_MJ_CLOSE) \ + TRACEFS_MAJOR(IRP_MJ_READ) \ + TRACEFS_MAJOR(IRP_MJ_WRITE) \ + TRACEFS_MAJOR(IRP_MJ_QUERY_INFORMATION) \ + TRACEFS_MAJOR(IRP_MJ_SET_INFORMATION) \ + TRACEFS_MAJOR(IRP_MJ_QUERY_EA) \ + TRACEFS_MAJOR(IRP_MJ_SET_EA) \ + TRACEFS_MAJOR(IRP_MJ_FLUSH_BUFFERS) \ + TRACEFS_MAJOR(IRP_MJ_QUERY_VOLUME_INFORMATION) \ + TRACEFS_MAJOR(IRP_MJ_SET_VOLUME_INFORMATION) \ + TRACEFS_MAJOR(IRP_MJ_DIRECTORY_CONTROL) \ + TRACEFS_MAJOR(IRP_MJ_FILE_SYSTEM_CONTROL) \ + TRACEFS_MAJOR(IRP_MJ_DEVICE_CONTROL) \ + TRACEFS_MAJOR(IRP_MJ_INTERNAL_DEVICE_CONTROL) \ + TRACEFS_MAJOR(IRP_MJ_SHUTDOWN) \ + TRACEFS_MAJOR(IRP_MJ_LOCK_CONTROL) \ + TRACEFS_MAJOR(IRP_MJ_CLEANUP) \ + TRACEFS_MAJOR(IRP_MJ_CREATE_MAILSLOT) \ + TRACEFS_MAJOR(IRP_MJ_QUERY_SECURITY) \ + TRACEFS_MAJOR(IRP_MJ_SET_SECURITY) \ + TRACEFS_MAJOR(IRP_MJ_POWER) \ + TRACEFS_MAJOR(IRP_MJ_SYSTEM_CONTROL) \ + TRACEFS_MAJOR(IRP_MJ_DEVICE_CHANGE) \ + TRACEFS_MAJOR(IRP_MJ_QUERY_QUOTA) \ + TRACEFS_MAJOR(IRP_MJ_SET_QUOTA) \ + TRACEFS_MAJOR(IRP_MJ_PNP) + + +#define TRACEFS_MAJOR(irp_mj_name) \ +static NTSTATUS (*tracefs_major_##irp_mj_name##_orig)(IN struct _DEVICE_OBJECT *DeviceObject,IN struct _IRP *Irp); \ +static NTSTATUS tracefs_major_##irp_mj_name(IN struct _DEVICE_OBJECT *DeviceObject,IN struct _IRP *Irp) \ +{ \ +NTSTATUS r; \ + \ + DBGSINGLEENTER0( #irp_mj_name ); \ + irp_mj_dump(DeviceObject,Irp); \ + r=(*tracefs_major_##irp_mj_name##_orig)(DeviceObject,Irp); \ + DBGSINGLELEAVE1( #irp_mj_name ": r=0x%lX",(long)r); \ + return r; \ +} + +TRACEFS_MAJORS + +#undef TRACEFS_MAJOR + + +VOID IoRegisterFileSystem(IN OUT PDEVICE_OBJECT DeviceObject); +VOID ToRegisterFileSystem(IN OUT PDEVICE_OBJECT DeviceObject) +{ + DBGSINGLEENTER0("IoRegisterFileSystem"); + +#define TRACEFS_MAJOR(irp_mj_name) do { \ + tracefs_major_##irp_mj_name##_orig=DeviceObject->DriverObject->MajorFunction[irp_mj_name]; \ + DeviceObject->DriverObject->MajorFunction[irp_mj_name]=tracefs_major_##irp_mj_name; \ + } while (0); + +TRACEFS_MAJORS + +#undef TRACEFS_MAJOR + + IoRegisterFileSystem(DeviceObject); + DBGSINGLELEAVE0("IoRegisterFileSystem"); +} + + +static char PsCreateSystemThread_bogusthread; + +NTSTATUS TsCreateSystemThread( + OUT PHANDLE ThreadHandle, + IN ULONG DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN HANDLE ProcessHandle OPTIONAL, + OUT PCLIENT_ID ClientId OPTIONAL, + IN PKSTART_ROUTINE StartRoutine, + IN PVOID StartContext + ) +{ + DBGSINGLEENTER1("PsCreateSystemThread: StartRoutine=0x%lX",(long)StartRoutine); + if (ThreadHandle) + *ThreadHandle=(HANDLE)&PsCreateSystemThread_bogusthread; + DBGSINGLELEAVE0("PsCreateSystemThread"); + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +TwClose( + IN HANDLE Handle + ) +{ + DBGSINGLEENTER0("ZwClose"); + if (Handle==(HANDLE)&PsCreateSystemThread_bogusthread) { + DBGSINGLELEAVE0("ZwClose: bogusthread catched"); + return STATUS_SUCCESS; + } + DBGSINGLELEAVE0("ZwClose: passed"); + return ZwClose(Handle); +} + + +BOOLEAN +CcCanIWrite ( + IN PFILE_OBJECT FileObject, + IN ULONG BytesToWrite, + IN BOOLEAN Wait, + IN BOOLEAN Retrying + ); +BOOLEAN +TcCanIWrite ( + IN PFILE_OBJECT FileObject, + IN ULONG BytesToWrite, + IN BOOLEAN Wait, + IN BOOLEAN Retrying + ) +{ +BOOLEAN r; + + DBGSINGLEENTER4("CcCanIWrite: FileObject=0x%lX,BytesToWrite=0x%lX,Wait=%d,Retrying=%d", + (long)FileObject,BytesToWrite,Wait,Retrying); + r=CcCanIWrite ( +FileObject, +BytesToWrite, +Wait, +Retrying + ); + DBGSINGLELEAVE1("CcCanIWrite: r=%d",r); + return r; +} + +BOOLEAN +CcCopyRead ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Wait, + OUT PVOID Buffer, + OUT PIO_STATUS_BLOCK IoStatus + ); +BOOLEAN +TcCopyRead ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Wait, + OUT PVOID Buffer, + OUT PIO_STATUS_BLOCK IoStatus + ) +{ +BOOLEAN r; + + DBGSINGLEENTER5("CcCopyRead: FileObject=0x%lX,FileOffset=0x%lX,Length=0x%lX,Wait=%d,Buffer=0x%lX", + (long)FileObject,(!FileOffset ? -1 : (long)FileOffset->QuadPart),Length,Wait,(long)Buffer); + r=CcCopyRead ( +FileObject, +FileOffset, +Length, +Wait, +Buffer, +IoStatus + ); + DBGSINGLELEAVE3("CcCopyRead: r=%d,IoStatus->Status=0x%lX,IoStatus->Information=0x%lX", + r,(!IoStatus ? -1 : (long)IoStatus->Status),(!IoStatus ? -1 : (long)IoStatus->Information)); + return r; +} + +BOOLEAN +CcCopyWrite ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Wait, + IN PVOID Buffer + ); +BOOLEAN +TcCopyWrite ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Wait, + IN PVOID Buffer + ) +{ +BOOLEAN r; + + DBGSINGLEENTER5("CcCopyWrite: FileObject=0x%lX,FileOffset=0x%lX,Length=0x%lX,Wait=%d,Buffer=0x%lX", + (long)FileObject,(!FileOffset ? -1 : (long)FileOffset->QuadPart),Length,Wait,(long)Buffer); + r=CcCopyWrite ( +FileObject, +FileOffset, +Length, +Wait, +Buffer + ); + DBGSINGLELEAVE1("CcCopyWrite: r=%d",r); + return r; +} + +typedef +VOID (*PCC_POST_DEFERRED_WRITE) ( + IN PVOID Context1, + IN PVOID Context2 + ); +VOID +CcDeferWrite ( + IN PFILE_OBJECT FileObject, + IN PCC_POST_DEFERRED_WRITE PostRoutine, + IN PVOID Context1, + IN PVOID Context2, + IN ULONG BytesToWrite, + IN BOOLEAN Retrying + ); +TcDeferWrite ( + IN PFILE_OBJECT FileObject, + IN PCC_POST_DEFERRED_WRITE PostRoutine, + IN PVOID Context1, + IN PVOID Context2, + IN ULONG BytesToWrite, + IN BOOLEAN Retrying + ) +{ + DBGSINGLEENTER6("CcDeferWrite: FileObject=0x%lX,PostRoutine=0x%lX,Context1=0x%lX,Context2=0x%lX," + "BytesToWrite=0x%lX,Retrying=%d", + (long)FileObject,(long)PostRoutine,(long)Context1,(long)Context2, + BytesToWrite,Retrying); + CcDeferWrite ( +FileObject, +PostRoutine, +Context1, +Context2, +BytesToWrite, +Retrying + ); + DBGSINGLELEAVE0("CcDeferWrite"); +} + +VOID +CcFastCopyRead ( + IN PFILE_OBJECT FileObject, + IN ULONG FileOffset, + IN ULONG Length, + IN ULONG PageCount, + OUT PVOID Buffer, + OUT PIO_STATUS_BLOCK IoStatus + ); +VOID +TcFastCopyRead ( + IN PFILE_OBJECT FileObject, + IN ULONG FileOffset, + IN ULONG Length, + IN ULONG PageCount, + OUT PVOID Buffer, + OUT PIO_STATUS_BLOCK IoStatus + ) +{ + DBGSINGLEENTER5("CcFastCopyRead: FileObject=0x%lX,FileOffset=0x%lX,Length=0x%lX,PageCount=0x%lX,Buffer=0x%lX", + (long)FileObject,FileOffset,Length,PageCount,(long)Buffer); + CcFastCopyRead ( +FileObject, +FileOffset, +Length, +PageCount, +Buffer, +IoStatus + ); + DBGSINGLELEAVE2("CcFastCopyRead: IoStatus->Status=0x%lX,IoStatus->Information=0x%lX", + (!IoStatus ? -1 : (long)IoStatus->Status),(!IoStatus ? -1 : (long)IoStatus->Information)); +} + +VOID +CcFastCopyWrite ( + IN PFILE_OBJECT FileObject, + IN ULONG FileOffset, + IN ULONG Length, + IN PVOID Buffer + ); +VOID +TcFastCopyWrite ( + IN PFILE_OBJECT FileObject, + IN ULONG FileOffset, + IN ULONG Length, + IN PVOID Buffer + ) +{ + DBGSINGLEENTER4("CcFastCopyWrite: FileObject=0x%lX,FileOffset=0x%lX,Length=0x%lX,Buffer=0x%lX", + (long)FileObject,FileOffset,Length,(long)Buffer); + CcFastCopyWrite ( +FileObject, +FileOffset, +Length, +Buffer + ); + DBGSINGLELEAVE0("CcFastCopyWrite"); +} + +VOID +CcFlushCache ( + IN PSECTION_OBJECT_POINTERS SectionObjectPointer, + IN PLARGE_INTEGER FileOffset OPTIONAL, + IN ULONG Length, + OUT PIO_STATUS_BLOCK IoStatus OPTIONAL + ); +VOID +TcFlushCache ( + IN PSECTION_OBJECT_POINTERS SectionObjectPointer, + IN PLARGE_INTEGER FileOffset OPTIONAL, + IN ULONG Length, + OUT PIO_STATUS_BLOCK IoStatus OPTIONAL + ) +{ + DBGSINGLEENTER4("CcFlushCache: SectionObjectPointer=0x%lX,->SharedCacheMap=0x%lX,FileOffset=0x%lX,Length=0x%lX", + (long)SectionObjectPointer, + (!SectionObjectPointer ? -1 : (long)SectionObjectPointer->SharedCacheMap), + (!FileOffset ? -1 : (long)FileOffset->QuadPart),Length); + CcFlushCache ( +SectionObjectPointer, +FileOffset, +Length, +IoStatus + ); + DBGSINGLELEAVE2("CcFlushCache: IoStatus->Status=0x%lX,IoStatus->Information=0x%lX", + (!IoStatus ? -1 : (long)IoStatus->Status),(!IoStatus ? -1 : (long)IoStatus->Information)); +} + +typedef +VOID (*PDIRTY_PAGE_ROUTINE) ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN PLARGE_INTEGER OldestLsn, + IN PLARGE_INTEGER NewestLsn, + IN PVOID Context1, + IN PVOID Context2 + ); + +static PDIRTY_PAGE_ROUTINE TcGetDirtyPages_DirtyPageRoutine_orig; +static BOOLEAN TcGetDirtyPages_DirtyPageRoutine_used=FALSE; + +static VOID TcGetDirtyPages_DirtyPageRoutine(IN PFILE_OBJECT FileObject,IN PLARGE_INTEGER FileOffset,IN ULONG Length, + IN PLARGE_INTEGER OldestLsn,IN PLARGE_INTEGER NewestLsn,IN PVOID Context1,IN PVOID Context2) +{ + DBGSINGLEENTER5("DirtyPageRoutine: FileObject=0x%lX,FileOffset=0x%lX,Length=0x%lX," + "OldestLsn=0x%lX,NewestLsn=0x%lX,Context1,Context2", + (long)FileObject,(!FileOffset ? -1 : (long)FileOffset->QuadPart),Length, + (!OldestLsn ? -1 : (long)OldestLsn->QuadPart),(!NewestLsn ? -1 : (long)NewestLsn->QuadPart)); + (*TcGetDirtyPages_DirtyPageRoutine_orig)(FileObject,FileOffset,Length,OldestLsn,NewestLsn,Context1,Context2); + DBGSINGLELEAVE0("DirtyPageRoutine"); +} + +LARGE_INTEGER +CcGetDirtyPages ( + IN PVOID LogHandle, + IN PDIRTY_PAGE_ROUTINE DirtyPageRoutine, + IN PVOID Context1, + IN PVOID Context2 + ); +LARGE_INTEGER +TcGetDirtyPages ( + IN PVOID LogHandle, + IN PDIRTY_PAGE_ROUTINE DirtyPageRoutine, + IN PVOID Context1, + IN PVOID Context2 + ) +{ +LARGE_INTEGER r; + + DBGSINGLEENTER4("CcGetDirtyPages: LogHandle=0x%lX,DirtyPageRoutine=0x%lX,Context1=0x%lX,Context2=0x%lX", + (long)LogHandle,(long)DirtyPageRoutine,(long)Context1,(long)Context2); + if (TcGetDirtyPages_DirtyPageRoutine_used) + DBGSINGLE0("CcGetDirtyPages: ERROR: TcGetDirtyPages_DirtyPageRoutine_used"); + else { + TcGetDirtyPages_DirtyPageRoutine_used=TRUE; + TcGetDirtyPages_DirtyPageRoutine_orig=DirtyPageRoutine; + DirtyPageRoutine=TcGetDirtyPages_DirtyPageRoutine; + } + r=CcGetDirtyPages ( +LogHandle, +DirtyPageRoutine, +Context1, +Context2 + ); + if (DirtyPageRoutine==TcGetDirtyPages_DirtyPageRoutine) + TcGetDirtyPages_DirtyPageRoutine_used=FALSE; + DBGSINGLELEAVE1("CcGetDirtyPages: r=0x%lX",(long)r.QuadPart); + return r; +} + +typedef BOOLEAN (*PACQUIRE_FOR_LAZY_WRITE)(IN PVOID Context,IN BOOLEAN Wait); +typedef VOID (*PRELEASE_FROM_LAZY_WRITE)(IN PVOID Context); +typedef BOOLEAN (*PACQUIRE_FOR_READ_AHEAD)(IN PVOID Context,IN BOOLEAN Wait); +typedef VOID (*PRELEASE_FROM_READ_AHEAD)(IN PVOID Context); +typedef struct _CACHE_MANAGER_CALLBACKS { + PACQUIRE_FOR_LAZY_WRITE AcquireForLazyWrite; + PRELEASE_FROM_LAZY_WRITE ReleaseFromLazyWrite; + PACQUIRE_FOR_READ_AHEAD AcquireForReadAhead; + PRELEASE_FROM_READ_AHEAD ReleaseFromReadAhead; + } CACHE_MANAGER_CALLBACKS,*PCACHE_MANAGER_CALLBACKS; + +static struct Callbacks { + FILE_OBJECT *FileObject; + CACHE_MANAGER_CALLBACKS Callbacks; + PVOID LazyWriteContext; + } Callbacks_cache[CACHE_SIZE]; +static int Callbacks_cache_used=0; + +static struct Callbacks *Callbacks_set(FILE_OBJECT *FileObject,CACHE_MANAGER_CALLBACKS *Callbacks,PVOID LazyWriteContext) +{ +struct Callbacks *callbacksp; + + for (callbacksp=Callbacks_cache;callbackspFileObject==FileObject) + break; + } + if (callbacksp>=Callbacks_cache+G_N_ELEMENTS(Callbacks_cache)) + return NULL; + if (callbacksp==Callbacks_cache+Callbacks_cache_used) + Callbacks_cache_used++; + callbacksp->FileObject=FileObject; + callbacksp->Callbacks=*Callbacks; + callbacksp->LazyWriteContext=LazyWriteContext; + return callbacksp; +} + +static BOOLEAN TcInitializeCacheMap_AcquireForLazyWrite(IN PVOID Context,IN BOOLEAN Wait) +{ +struct Callbacks *callbacksp=Context; +BOOLEAN r; + + DBGSINGLEENTER3("AcquireForLazyWrite: FileObject=0x%lX,Context=0x%lX,Wait=%d", + (long)callbacksp->FileObject,(long)callbacksp->LazyWriteContext,Wait); + r=(*callbacksp->Callbacks.AcquireForLazyWrite)(callbacksp->LazyWriteContext,Wait); + DBGSINGLELEAVE1("AcquireForLazyWrite: r=%d",r); + return r; +} + +static VOID TcInitializeCacheMap_ReleaseFromLazyWrite(IN PVOID Context) +{ +struct Callbacks *callbacksp=Context; + + DBGSINGLEENTER2("ReleaseFromLazyWrite: FileObject=0x%lX,Context=0x%lX", + (long)callbacksp->FileObject,(long)callbacksp->LazyWriteContext); + (*callbacksp->Callbacks.ReleaseFromLazyWrite)(callbacksp->LazyWriteContext); + DBGSINGLELEAVE0("ReleaseFromLazyWrite"); +} + +static BOOLEAN TcInitializeCacheMap_AcquireForReadAhead(IN PVOID Context,IN BOOLEAN Wait) +{ +struct Callbacks *callbacksp=Context; +BOOLEAN r; + + DBGSINGLEENTER3("AcquireForReadAhead: FileObject=0x%lX,Context=0x%lX,Wait=%d", + (long)callbacksp->FileObject,(long)callbacksp->LazyWriteContext,Wait); + r=(*callbacksp->Callbacks.AcquireForReadAhead)(callbacksp->LazyWriteContext,Wait); + DBGSINGLELEAVE1("AcquireForReadAhead: r=%d",r); + return r; +} + +static VOID TcInitializeCacheMap_ReleaseFromReadAhead(IN PVOID Context) +{ +struct Callbacks *callbacksp=Context; + + DBGSINGLEENTER2("ReleaseFromReadAhead: FileObject=0x%lX,Context=0x%lX", + (long)callbacksp->FileObject,(long)callbacksp->LazyWriteContext); + (*callbacksp->Callbacks.ReleaseFromReadAhead)(callbacksp->LazyWriteContext); + DBGSINGLELEAVE0("ReleaseFromReadAhead"); +} + +static CACHE_MANAGER_CALLBACKS TcInitializeCacheMap_Callbacks={ + TcInitializeCacheMap_AcquireForLazyWrite, + TcInitializeCacheMap_ReleaseFromLazyWrite, + TcInitializeCacheMap_AcquireForReadAhead, + TcInitializeCacheMap_ReleaseFromReadAhead, + }; + +typedef struct _CC_FILE_SIZES { + LARGE_INTEGER AllocationSize; + LARGE_INTEGER FileSize; + LARGE_INTEGER ValidDataLength; + } CC_FILE_SIZES,*PCC_FILE_SIZES; + +VOID +CcInitializeCacheMap ( + IN PFILE_OBJECT FileObject, + IN PCC_FILE_SIZES FileSizes, + IN BOOLEAN PinAccess, + IN PCACHE_MANAGER_CALLBACKS Callbacks, + IN PVOID LazyWriteContext + ); +VOID +TcInitializeCacheMap ( + IN PFILE_OBJECT FileObject, + IN PCC_FILE_SIZES FileSizes, + IN BOOLEAN PinAccess, + IN PCACHE_MANAGER_CALLBACKS Callbacks, + IN PVOID LazyWriteContext + ) +{ +struct Callbacks *callbacksp; + + DBGSINGLEENTER5("CcInitializeCacheMap: FileObject=0x%lX," + "FileSizes,->AllocationSize=0x%lX,->FileSize=0x%lX,->ValidDataLength=0x%lX," + "PinAccess=%d,Callbacks,LazyWriteContext", + (long)FileObject, + (!FileSizes ? -1 : (long)FileSizes->AllocationSize.QuadPart), + (!FileSizes ? -1 : (long)FileSizes->FileSize.QuadPart), + (!FileSizes ? -1 : (long)FileSizes->ValidDataLength.QuadPart), + PinAccess); + if ((callbacksp=Callbacks_set(FileObject,Callbacks,LazyWriteContext))) { + Callbacks=&TcInitializeCacheMap_Callbacks; + LazyWriteContext=callbacksp; + if (Callbacks->AcquireForLazyWrite !=TcInitializeCacheMap_AcquireForLazyWrite) + DBGSINGLE1("CcInitializeCacheMap: ERROR: AcquireForLazyWrite =0x%lX",Callbacks->AcquireForLazyWrite); + if (Callbacks->ReleaseFromLazyWrite!=TcInitializeCacheMap_ReleaseFromLazyWrite) + DBGSINGLE1("CcInitializeCacheMap: ERROR: ReleaseFromLazyWrite=0x%lX",Callbacks->ReleaseFromLazyWrite); + if (Callbacks->AcquireForReadAhead !=TcInitializeCacheMap_AcquireForReadAhead) + DBGSINGLE1("CcInitializeCacheMap: ERROR: AcquireForReadAhead =0x%lX",Callbacks->AcquireForReadAhead); + if (Callbacks->ReleaseFromReadAhead!=TcInitializeCacheMap_ReleaseFromReadAhead) + DBGSINGLE1("CcInitializeCacheMap: ERROR: ReleaseFromReadAhead=0x%lX",Callbacks->ReleaseFromReadAhead); + } + CcInitializeCacheMap ( +FileObject, +FileSizes, +PinAccess, +Callbacks, +LazyWriteContext + ); + DBGSINGLELEAVE0("CcInitializeCacheMap"); +} + +BOOLEAN +CcMapData ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN ULONG Flags, + OUT PVOID *Bcb, + OUT PVOID *Buffer + ); +BOOLEAN +TcMapData ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN ULONG Flags, + OUT PVOID *Bcb, + OUT PVOID *Buffer + ) +{ +BOOLEAN r; + + DBGSINGLEENTER4("CcMapData: FileObject=0x%lX,FileOffset=0x%lX,Length=0x%lX,Flags=0x%lX", + (long)FileObject,(!FileOffset ? -1 : (long)FileOffset->QuadPart),Length,Flags); + r=CcMapData ( +FileObject, +FileOffset, +Length, +Flags, +Bcb, +Buffer + ); + DBGSINGLELEAVE3("CcMapData: r=%d,Bcb=0x%lX,Buffer=0x%lX", + r,(!Bcb ? -1 : (long)*Bcb),(!Buffer ? -1 : (long)*Buffer)); + return r; +} + +VOID +CcMdlRead ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + OUT PMDL *MdlChain, + OUT PIO_STATUS_BLOCK IoStatus + ); +VOID +TcMdlRead ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + OUT PMDL *MdlChain, + OUT PIO_STATUS_BLOCK IoStatus + ) +{ + DBGSINGLEENTER3("CcMdlRead: FileObject=0x%lX,FileOffset=0x%lX,Length=0x%lX", + (long)FileObject,(!FileOffset ? -1 : (long)FileOffset->QuadPart),Length); + CcMdlRead ( +FileObject, +FileOffset, +Length, +MdlChain, +IoStatus + ); + DBGSINGLELEAVE3("CcMdlRead: MdlChain=0x%lX,IoStatus->Status=0x%lX,IoStatus->Information=0x%lX", + (!MdlChain ? -1 : (long)*MdlChain), + (!IoStatus ? -1 : (long)IoStatus->Status),(!IoStatus ? -1 : (long)IoStatus->Information)); +} + +VOID +CcMdlReadComplete ( + IN PFILE_OBJECT FileObject, + IN PMDL MdlChain + ); +VOID +TcMdlReadComplete ( + IN PFILE_OBJECT FileObject, + IN PMDL MdlChain + ) +{ + DBGSINGLEENTER2("CcMdlReadComplete: FileObject=0x%lX,MdlChain=0x%lX", + (long)FileObject,(long)MdlChain); + CcMdlReadComplete ( +FileObject, +MdlChain + ); + DBGSINGLELEAVE0("CcMdlReadComplete"); +} + +VOID +CcMdlWriteAbort ( + IN PFILE_OBJECT FileObject, + IN PMDL MdlChain + ); +VOID +TcMdlWriteAbort ( + IN PFILE_OBJECT FileObject, + IN PMDL MdlChain + ) +{ + DBGSINGLEENTER2("CcMdlWriteAbort: FileObject=0x%lX,MdlChain=0x%lX", + (long)FileObject,(long)MdlChain); + CcMdlWriteAbort ( +FileObject, +MdlChain + ); + DBGSINGLELEAVE0("CcMdlWriteAbort"); +} + +VOID +CcMdlWriteComplete ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN PMDL MdlChain + ); +VOID +TcMdlWriteComplete ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN PMDL MdlChain + ) +{ + DBGSINGLEENTER3("CcMdlWriteComplete: FileObject=0x%lX,FileOffset=0x%lX,MdlChain=0x%lX", + (long)FileObject,(!FileOffset ? -1 : (long)FileOffset->QuadPart),(long)MdlChain); + CcMdlWriteComplete ( +FileObject, +FileOffset, +MdlChain + ); + DBGSINGLELEAVE0("CcMdlWriteComplete"); +} + +BOOLEAN +CcPinMappedData ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN ULONG Flags, + IN OUT PVOID *Bcb + ); +BOOLEAN +TcPinMappedData ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN ULONG Flags, + IN OUT PVOID *Bcb + ) +{ +BOOLEAN r; + + DBGSINGLEENTER4("CcPinMappedData: FileObject=0x%lX,FileOffset=0x%lX,Length=0x%lX,Flags=0x%lX", + (long)FileObject,(!FileOffset ? -1 : (long)FileOffset->QuadPart),Length,Flags); + r=CcPinMappedData ( +FileObject, +FileOffset, +Length, +Flags, +Bcb + ); + DBGSINGLELEAVE2("CcPinMappedData: r=%d,Bcb=0x%lX", + r,(!Bcb ? -1 : (long)*Bcb)); + return r; +} + +BOOLEAN +CcPinRead ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN ULONG Flags, + OUT PVOID *Bcb, + OUT PVOID *Buffer + ); +BOOLEAN +TcPinRead ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN ULONG Flags, + OUT PVOID *Bcb, + OUT PVOID *Buffer + ) +{ +BOOLEAN r; + + DBGSINGLEENTER4("CcPinRead: FileObject=0x%lX,FileOffset=0x%lX,Length=0x%lX,Flags=0x%lX", + (long)FileObject,(!FileOffset ? -1 : (long)FileOffset->QuadPart),Length,Flags); + r=CcPinRead ( +FileObject, +FileOffset, +Length, +Flags, +Bcb, +Buffer + ); + DBGSINGLELEAVE3("CcPinRead: r=%d,Bcb=0x%lX,Buffer=0x%lX", + r,(!Bcb ? -1 : (long)*Bcb),(!Buffer ? -1 : (long)*Buffer)); + return r; +} + +VOID +CcPrepareMdlWrite ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + OUT PMDL *MdlChain, + OUT PIO_STATUS_BLOCK IoStatus + ); +VOID +TcPrepareMdlWrite ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + OUT PMDL *MdlChain, + OUT PIO_STATUS_BLOCK IoStatus + ) +{ + DBGSINGLEENTER3("CcPrepareMdlWrite: FileObject=0x%lX,FileOffset=0x%lX,Length=0x%lX", + (long)FileObject,(!FileOffset ? -1 : (long)FileOffset->QuadPart),Length); + CcPrepareMdlWrite ( +FileObject, +FileOffset, +Length, +MdlChain, +IoStatus + ); + DBGSINGLELEAVE3("CcPrepareMdlWrite: MdlChain=0x%lX,IoStatus->Status=0x%lX,IoStatus->Information=0x%lX", + (!MdlChain ? -1 : (long)*MdlChain), + (!IoStatus ? -1 : (long)IoStatus->Status),(!IoStatus ? -1 : (long)IoStatus->Information)); +} + +BOOLEAN +CcPreparePinWrite ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Zero, + IN ULONG Flags, + OUT PVOID *Bcb, + OUT PVOID *Buffer + ); +BOOLEAN +TcPreparePinWrite ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Zero, + IN ULONG Flags, + OUT PVOID *Bcb, + OUT PVOID *Buffer + ) +{ +BOOLEAN r; + + DBGSINGLEENTER5("CcPreparePinWrite: FileObject=0x%lX,FileOffset=0x%lX,Length=0x%lX,Zero=%d,Flags=0x%lX", + (long)FileObject,(!FileOffset ? -1 : (long)FileOffset->QuadPart),Length,Zero,Flags); + r=CcPreparePinWrite ( +FileObject, +FileOffset, +Length, +Zero, +Flags, +Bcb, +Buffer + ); + DBGSINGLELEAVE3("CcPreparePinWrite: r=%d,Bcb=0x%lX,Buffer=0x%lX", + r,(!Bcb ? -1 : (long)*Bcb),(!Buffer ? -1 : (long)*Buffer)); + return r; +} + +BOOLEAN +CcPurgeCacheSection ( + IN PSECTION_OBJECT_POINTERS SectionObjectPointer, + IN PLARGE_INTEGER FileOffset OPTIONAL, + IN ULONG Length, + IN BOOLEAN UninitializeCacheMaps + ); +BOOLEAN +TcPurgeCacheSection ( + IN PSECTION_OBJECT_POINTERS SectionObjectPointer, + IN PLARGE_INTEGER FileOffset OPTIONAL, + IN ULONG Length, + IN BOOLEAN UninitializeCacheMaps + ) +{ +BOOLEAN r; + + DBGSINGLEENTER5("CcPurgeCacheSection: SectionObjectPointer=0x%lX,->SharedCacheMap=0x%lX,FileOffset=0x%lX,Length=0x%lX," + "UninitializeCacheMaps=%d", + (long)SectionObjectPointer, + (!SectionObjectPointer ? -1 : (long)SectionObjectPointer->SharedCacheMap), + (!FileOffset ? -1 : (long)FileOffset->QuadPart),Length, + UninitializeCacheMaps); + r=CcPurgeCacheSection ( +SectionObjectPointer, +FileOffset, +Length, +UninitializeCacheMaps + ); + DBGSINGLELEAVE1("CcPurgeCacheSection: r=%d",r); + return r; +} + +PVOID +CcRemapBcb ( + IN PVOID Bcb + ); +PVOID +TcRemapBcb ( + IN PVOID Bcb + ) +{ +PVOID r; + + DBGSINGLEENTER1("CcRemapBcb: Bcb=0x%lX",(long)Bcb); + r=CcRemapBcb ( +Bcb + ); + DBGSINGLELEAVE1("CcRemapBcb: r=0x%lX",(long)r); + return r; +} + +VOID +CcSetAdditionalCacheAttributes ( + IN PFILE_OBJECT FileObject, + IN BOOLEAN DisableReadAhead, + IN BOOLEAN DisableWriteBehind + ); +VOID +TcSetAdditionalCacheAttributes ( + IN PFILE_OBJECT FileObject, + IN BOOLEAN DisableReadAhead, + IN BOOLEAN DisableWriteBehind + ) +{ + DBGSINGLEENTER3("CcSetAdditionalCacheAttributes: FileObject=0x%lX,DisableReadAhead=%d,DisableWriteBehind=%d", + (long)FileObject,DisableReadAhead,DisableWriteBehind); + CcSetAdditionalCacheAttributes ( +FileObject, +DisableReadAhead, +DisableWriteBehind + ); + DBGSINGLELEAVE0("CcSetAdditionalCacheAttributes"); +} + +VOID +CcSetBcbOwnerPointer ( + IN PVOID Bcb, + IN PVOID OwnerPointer + ); +VOID +TcSetBcbOwnerPointer ( + IN PVOID Bcb, + IN PVOID OwnerPointer + ) +{ + DBGSINGLEENTER2("CcSetBcbOwnerPointer: Bcb=0x%lX,OwnerPointer=0x%lX", + (long)Bcb,(long)OwnerPointer); + CcSetBcbOwnerPointer ( +Bcb, +OwnerPointer + ); + DBGSINGLELEAVE0("CcSetBcbOwnerPointer"); +} + +VOID +CcSetDirtyPinnedData ( + IN PVOID BcbVoid, + IN PLARGE_INTEGER Lsn OPTIONAL + ); +VOID +TcSetDirtyPinnedData ( + IN PVOID BcbVoid, + IN PLARGE_INTEGER Lsn OPTIONAL + ) +{ + DBGSINGLEENTER2("CcSetDirtyPinnedData: BcbVoid=0x%lX,Lsn=0x%lX", + (long)BcbVoid,(!Lsn ? -1 : (long)Lsn->QuadPart)); + CcSetDirtyPinnedData ( +BcbVoid, +Lsn + ); + DBGSINGLELEAVE0("CcSetDirtyPinnedData"); +} + +VOID +CcSetFileSizes ( + IN PFILE_OBJECT FileObject, + IN PCC_FILE_SIZES FileSizes + ); +VOID +TcSetFileSizes ( + IN PFILE_OBJECT FileObject, + IN PCC_FILE_SIZES FileSizes + ) +{ + DBGSINGLEENTER4("CcSetFileSizes: FileObject=0x%lX," + "FileSizes,->AllocationSize=0x%lX,->FileSize=0x%lX,->ValidDataLength=0x%lX", + (long)FileObject, + (!FileSizes ? -1 : (long)FileSizes->AllocationSize.QuadPart), + (!FileSizes ? -1 : (long)FileSizes->FileSize.QuadPart), + (!FileSizes ? -1 : (long)FileSizes->ValidDataLength.QuadPart)); + CcSetFileSizes ( +FileObject, +FileSizes + ); + DBGSINGLELEAVE0("CcSetFileSizes"); +} + +typedef VOID (*PFLUSH_TO_LSN)(IN PVOID LogHandle,IN LARGE_INTEGER Lsn); + +static struct LogHandle { + PVOID LogHandle; + PFLUSH_TO_LSN FlushToLsnRoutine; + } LogHandle_cache[CACHE_SIZE]; +static int LogHandle_cache_used=0; + +static BOOLEAN LogHandle_set(PVOID LogHandle,PFLUSH_TO_LSN FlushToLsnRoutine) +{ +struct LogHandle *loghandlep; + + for (loghandlep=LogHandle_cache;loghandlepLogHandle==LogHandle) + break; + } + if (loghandlep>=LogHandle_cache+G_N_ELEMENTS(LogHandle_cache)) + return FALSE; + if (loghandlep==LogHandle_cache+LogHandle_cache_used) + LogHandle_cache_used++; + loghandlep->LogHandle=LogHandle; + loghandlep->FlushToLsnRoutine=FlushToLsnRoutine; + return TRUE; +} + +static PFLUSH_TO_LSN LogHandle_find(PVOID LogHandle) +{ +struct LogHandle *loghandlep; + + for (loghandlep=LogHandle_cache;loghandlepLogHandle==LogHandle) + return loghandlep->FlushToLsnRoutine; + } + return NULL; +} + +static VOID TcSetLogHandleForFile_FlushToLsnRoutine(IN PVOID LogHandle,IN LARGE_INTEGER Lsn) +{ +PFLUSH_TO_LSN FlushToLsnRoutine; + + DBGSINGLEENTER2("FlushToLsnRoutine: LogHandle=0x%lX,Lsn=0x%lX", + (long)LogHandle,(long)Lsn.QuadPart); + if ((FlushToLsnRoutine=LogHandle_find(LogHandle))) + (*FlushToLsnRoutine)(LogHandle,Lsn); + DBGSINGLELEAVE0("FlushToLsnRoutine"); +} + +VOID +CcSetLogHandleForFile ( + IN PFILE_OBJECT FileObject, + IN PVOID LogHandle, + IN PFLUSH_TO_LSN FlushToLsnRoutine + ); +VOID +TcSetLogHandleForFile ( + IN PFILE_OBJECT FileObject, + IN PVOID LogHandle, + IN PFLUSH_TO_LSN FlushToLsnRoutine + ) +{ + DBGSINGLEENTER3("CcSetLogHandleForFile: FileObject=0x%lX,LogHandle=0x%lX,FlushToLsnRoutine=0x%lX", + (long)FileObject,(long)LogHandle,(long)FlushToLsnRoutine); + if (LogHandle_set(LogHandle,FlushToLsnRoutine)) + FlushToLsnRoutine=TcSetLogHandleForFile_FlushToLsnRoutine; + CcSetLogHandleForFile ( +FileObject, +LogHandle, +FlushToLsnRoutine + ); + DBGSINGLELEAVE0("CcSetLogHandleForFile"); +} + +VOID +CcSetReadAheadGranularity ( + IN PFILE_OBJECT FileObject, + IN ULONG Granularity + ); +VOID +TcSetReadAheadGranularity ( + IN PFILE_OBJECT FileObject, + IN ULONG Granularity + ) +{ + DBGSINGLEENTER2("CcSetReadAheadGranularity: FileObject=0x%lX,Granularity=0x%lX", + (long)FileObject,Granularity); + CcSetReadAheadGranularity ( +FileObject, +Granularity + ); + DBGSINGLELEAVE0("CcSetReadAheadGranularity"); +} + +typedef struct _CACHE_UNINITIALIZE_EVENT { + struct _CACHE_UNINITIALIZE_EVENT *Next; + KEVENT Event; + } CACHE_UNINITIALIZE_EVENT,*PCACHE_UNINITIALIZE_EVENT; + +BOOLEAN +CcUninitializeCacheMap ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER TruncateSize OPTIONAL, + IN PCACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent OPTIONAL + ); +BOOLEAN +TcUninitializeCacheMap ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER TruncateSize OPTIONAL, + IN PCACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent OPTIONAL + ) +{ +BOOLEAN r; + + DBGSINGLEENTER3("CcUninitializeCacheMap: FileObject=0x%lX,TruncateSize=0x%lX,UninitializeCompleteEvent=0x%lX", + (long)FileObject,(!TruncateSize ? -1 : (long)TruncateSize->QuadPart),(long)UninitializeCompleteEvent); + r=CcUninitializeCacheMap ( +FileObject, +TruncateSize, +UninitializeCompleteEvent + ); + DBGSINGLELEAVE1("CcUninitializeCacheMap: r=%d",r); + return r; +} + +VOID +CcUnpinData ( + IN PVOID Bcb + ); +VOID +TcUnpinData ( + IN PVOID Bcb + ) +{ + DBGSINGLEENTER1("CcUnpinData: Bcb=0x%lX",(long)Bcb); + CcUnpinData ( +Bcb + ); + DBGSINGLELEAVE0("CcUnpinData"); +} + +VOID +CcUnpinDataForThread ( + IN PVOID Bcb, + IN ERESOURCE_THREAD ResourceThreadId + ); +VOID +TcUnpinDataForThread ( + IN PVOID Bcb, + IN ERESOURCE_THREAD ResourceThreadId + ) +{ + DBGSINGLEENTER2("CcUnpinDataForThread: Bcb=0x%lX,ResourceThreadId=0x%lX", + (long)Bcb,(long)ResourceThreadId); + CcUnpinDataForThread ( +Bcb, +ResourceThreadId + ); + DBGSINGLELEAVE0("CcUnpinDataForThread"); +} + +NTSTATUS +CcWaitForCurrentLazyWriterActivity ( + VOID + ); +NTSTATUS +TcWaitForCurrentLazyWriterActivity ( + VOID + ) +{ +NTSTATUS r; + + DBGSINGLEENTER0("CcWaitForCurrentLazyWriterActivity"); + r=CcWaitForCurrentLazyWriterActivity ( + ); + DBGSINGLELEAVE1("CcWaitForCurrentLazyWriterActivity: r=0x%lX",r); + return r; +} + +BOOLEAN +CcZeroData ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER StartOffset, + IN PLARGE_INTEGER EndOffset, + IN BOOLEAN Wait + ); +BOOLEAN +TcZeroData ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER StartOffset, + IN PLARGE_INTEGER EndOffset, + IN BOOLEAN Wait + ) +{ +BOOLEAN r; + + DBGSINGLEENTER4("CcZeroData: FileObject=0x%lX,StartOffset=0x%lX,EndOffset=0x%lX,Wait=%d", + (long)FileObject, + (!StartOffset ? -1 : (long)StartOffset->QuadPart), + (!EndOffset ? -1 : (long)EndOffset->QuadPart), + Wait); + r=CcZeroData ( +FileObject, +StartOffset, +EndOffset, +Wait + ); + DBGSINGLELEAVE1("CcZeroData: r=%d",r); + return r; +} diff --git a/src/TraceFS/TraceFS-W32/TraceFS.def b/src/TraceFS/TraceFS-W32/TraceFS.def new file mode 100644 index 0000000..f913323 --- /dev/null +++ b/src/TraceFS/TraceFS-W32/TraceFS.def @@ -0,0 +1,55 @@ +; $Id$ +; Exports definition file for W32 build of TraceFS by build.exe +; Copyright (C) 2003 Jan Kratochvil +; +; This program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation; exactly version 2 of June 1991 is required +; +; This program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, write to the Free Software +; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +EXPORTS + ToRegisterFileSystem + + TsCreateSystemThread + TwClose + + TcCanIWrite + TcCopyRead + TcCopyWrite + TcDeferWrite + TcFastCopyRead + TcFastCopyWrite + TcFlushCache + TcGetDirtyPages + TcInitializeCacheMap + TcMapData + TcMdlRead + TcMdlReadComplete + TcMdlWriteAbort + TcMdlWriteComplete + TcPinMappedData + TcPinRead + TcPrepareMdlWrite + TcPreparePinWrite + TcPurgeCacheSection + TcRemapBcb + TcSetAdditionalCacheAttributes + TcSetBcbOwnerPointer + TcSetDirtyPinnedData + TcSetFileSizes + TcSetLogHandleForFile + TcSetReadAheadGranularity + TcUninitializeCacheMap + TcUnpinData + TcUnpinDataForThread + TcWaitForCurrentLazyWriterActivity + TcZeroData diff --git a/src/TraceFS/TraceFS-W32/TraceFS.reg b/src/TraceFS/TraceFS-W32/TraceFS.reg new file mode 100644 index 0000000..5ed5cf5 --- /dev/null +++ b/src/TraceFS/TraceFS-W32/TraceFS.reg @@ -0,0 +1,28 @@ +Windows Registry Editor Version 5.00 + + +; $Id$ +; Registry settings to load C:\Windows\System32\Drivers\TraceFS.sys +; Copyright (C) 2003 Jan Kratochvil +; +; This program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation; exactly version 2 of June 1991 is required +; +; This program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, write to the Free Software +; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\TraceFS] +"ErrorControl"=dword:00000001 +"Group"="Base" +"Start"=dword:00000000 +"Tag"=dword:00000001 +"Type"=dword:00000001 + diff --git a/src/TraceFS/TraceFS-W32/makeFile b/src/TraceFS/TraceFS-W32/makeFile new file mode 100644 index 0000000..1bd62a8 --- /dev/null +++ b/src/TraceFS/TraceFS-W32/makeFile @@ -0,0 +1,22 @@ +# $Id$ +# Stub makefile required by W32 build of TraceFS by build.exe +# Copyright (C) 2003 Jan Kratochvil +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; exactly version 2 of June 1991 is required +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +# We are named 'makeFile' to prevent being used on UNIX system. + + +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/src/TraceFS/checktrace.pl b/src/TraceFS/checktrace.pl new file mode 100755 index 0000000..6439405 --- /dev/null +++ b/src/TraceFS/checktrace.pl @@ -0,0 +1,277 @@ +#! /usr/bin/perl +# +# $Id$ +# Checks assumptions on Cc* (Cache Manager) behaviour by reading TraceFS log +# Copyright (C) 2003 Jan Kratochvil +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; exactly version 2 of June 1991 is required +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +use strict; +use warnings; +use Carp qw(cluck confess); +use Data::Dumper; + + +my $filter=0; +$Data::Dumper::Sortkeys=1; + +my %init; +my %Bcb; + +END { + print Data::Dumper->Dump([\%init,\%Bcb],[qw(%init %Bcb)]) if !$filter; + } + +local $_; +my $hex='0x[\dA-F]+'; +my(@lastmap_CcMapData,@lastmap_CcPinRead,@lastmap_CcPreparePinWrite,@lastmap_CcPinMappedData,@lastmap_CcRemapBcb); +my $last_irp_mj; +while (<>) { + chomp; + s#^ *TraceFS[(]($hex)/($hex)[)]: ## or do { print "$_\n" if $filter; next; }; + my($process,$thread)=($1,$2); + + if (my($FileObject,$AllocationSize,$FileSize,$ValidDataLength)= + /^enter: CcInitializeCacheMap: FileObject=($hex),FileSizes,->AllocationSize=($hex),->FileSize=($hex),->ValidDataLength=($hex),PinAccess=([01]),/) { + $AllocationSize=eval($AllocationSize); + $FileSize=eval($FileSize); + 0==($AllocationSize%0x200) or die; + int($AllocationSize/0x200)==int(($FileSize+0x1FF)/0x200) or die; + $ValidDataLength eq "0x".("F"x8) or eval($ValidDataLength)==$FileSize or die; + !exists $init{$FileObject} or die; + $init{$FileObject}={ + "FileObject"=>$FileObject, + "size"=>$FileSize, + "unmaps"=>0, + "maps"=>[], + "line"=>$., + "Bcb_map"=>undef(), + "Bcb_pin"=>{}, + }; + next; + } + if (my($FileObject,$TruncateSize)= + /^enter: CcUninitializeCacheMap: FileObject=($hex),TruncateSize=($hex),/) { + $TruncateSize=eval($TruncateSize); + next if !exists $init{$FileObject}; + $init{$FileObject}->{"unmaps"}==@{$init{$FileObject}->{"maps"}} or die; + delete $init{$FileObject}; + next; + } + + if (my($FileObject,$FileOffset,$Length)= + /^enter: CcMapData: FileObject=($hex),FileOffset=($hex),Length=($hex),Flags=0x1/) { + $FileOffset=eval $FileOffset; + $Length=eval $Length; + die if !(my $reg=$init{$FileObject}); + die if $FileOffset+$Length>$reg->{"size"}; + my $newmap={ + "FileOffset"=>$FileOffset, + "Length"=>$Length, + "init"=>$reg, + "line"=>$., + "by"=>"CcMapData", + }; + push @{$reg->{"maps"}},$newmap; + push @lastmap_CcMapData,$newmap; + next; + } + if (my($Bcb,$Buffer)= + /^leave: CcMapData: r=1,Bcb=($hex),Buffer=($hex)/) { + die if !(my $lastmap=pop @lastmap_CcMapData); + $lastmap->{"Bcb"}=$Bcb; + $lastmap->{"Buffer"}=$Buffer; + $lastmap->{"process"}=$process; + $lastmap->{"thread"}=$thread; + $Bcb{$Bcb}=$lastmap->{"init"}; + die if $lastmap->{"init"}->{"Bcb_map"} && $lastmap->{"init"}->{"Bcb_map"} ne $Bcb; + $lastmap->{"init"}->{"Bcb_map"}=$Bcb; + for my $pinoffs (keys(%{$lastmap->{"init"}->{"Bcb_pin"}})) { + die $pinoffs if $lastmap->{"init"}->{"Bcb_pin"}->{$pinoffs} eq $Bcb; + } + next; + } + + if (my($FileObject,$FileOffset,$Length)= + /^enter: CcPinRead: FileObject=($hex),FileOffset=($hex),Length=($hex),Flags=0x1/) { + $FileOffset=eval $FileOffset; + $Length=eval $Length; + die if !(my $reg=$init{$FileObject}); + die if $FileOffset+$Length>$reg->{"size"}; + my $newmap={ + "FileOffset"=>$FileOffset, + "Length"=>$Length, + "init"=>$reg, + "line"=>$., + "by"=>"CcPinRead", + }; + push @{$reg->{"maps"}},$newmap; + push @lastmap_CcPinRead,$newmap; + next; + } + if (my($Bcb,$Buffer)= + /^leave: CcPinRead: r=1,Bcb=($hex),Buffer=($hex)/) { + die if !(my $lastmap=pop @lastmap_CcPinRead); + $lastmap->{"Bcb"}=$Bcb; + $lastmap->{"Buffer"}=$Buffer; + $lastmap->{"process"}=$process; + $lastmap->{"thread"}=$thread; + $Bcb{$Bcb}=$lastmap->{"init"}; + my $myoffs=$lastmap->{"FileOffset"}&~0xFFF; + die if defined $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs} && $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs} ne $Bcb; + for my $pinoffs (keys(%{$lastmap->{"init"}->{"Bcb_pin"}})) { + next if $pinoffs==$myoffs; + die $pinoffs if $lastmap->{"init"}->{"Bcb_pin"}->{$pinoffs} eq $Bcb; + } + $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs}=$Bcb; + die if $lastmap->{"init"}->{"Bcb_map"} && $lastmap->{"init"}->{"Bcb_map"} eq $Bcb; + next; + } + + if (my($FileObject,$FileOffset,$Length)= + /^enter: CcPreparePinWrite: FileObject=($hex),FileOffset=($hex),Length=($hex),Zero=([01]),Flags=0x1/) { + $FileOffset=eval $FileOffset; + $Length=eval $Length; + die if !(my $reg=$init{$FileObject}); + die if $FileOffset+$Length>$reg->{"size"}; + my $newmap={ + "FileOffset"=>$FileOffset, + "Length"=>$Length, + "init"=>$reg, + "line"=>$., + "by"=>"CcPreparePinWrite", + }; + push @{$reg->{"maps"}},$newmap; + push @lastmap_CcPreparePinWrite,$newmap; + next; + } + if (my($Bcb,$Buffer)= + /^leave: CcPreparePinWrite: r=1,Bcb=($hex),Buffer=($hex)/) { + die if !(my $lastmap=pop @lastmap_CcPreparePinWrite); + $lastmap->{"Bcb"}=$Bcb; + $lastmap->{"Buffer"}=$Buffer; + $lastmap->{"process"}=$process; + $lastmap->{"thread"}=$thread; + $Bcb{$Bcb}=$lastmap->{"init"}; + my $myoffs=$lastmap->{"FileOffset"}&~0xFFF; + die if defined $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs} && $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs} ne $Bcb; + for my $pinoffs (keys(%{$lastmap->{"init"}->{"Bcb_pin"}})) { + next if $pinoffs==$myoffs; + die $pinoffs if $lastmap->{"init"}->{"Bcb_pin"}->{$pinoffs} eq $Bcb; + } + $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs}=$Bcb; + die if $lastmap->{"init"}->{"Bcb_map"} && $lastmap->{"init"}->{"Bcb_map"} eq $Bcb; + next; + } + + if (my($FileObject,$FileOffset,$Length)= + /^enter: CcPinMappedData: FileObject=($hex),FileOffset=($hex),Length=($hex),Flags=0x1/) { + $FileOffset=eval $FileOffset; + $Length=eval $Length; + die if !(my $reg=$init{$FileObject}); + die if $FileOffset+$Length>$reg->{"size"}; + my $newmap={ + "FileOffset"=>$FileOffset, + "Length"=>$Length, + "init"=>$reg, + "line"=>$., + "by"=>"CcPinMappedData", + }; + push @{$reg->{"maps"}},$newmap; + push @lastmap_CcPinMappedData,$newmap; + next; + } + if (my($Bcb,$Buffer)= + /^leave: CcPinMappedData: r=1,Bcb=($hex)/) { + die if !(my $lastmap=pop @lastmap_CcPinMappedData); + $lastmap->{"Bcb"}=$Bcb; + $lastmap->{"process"}=$process; + $lastmap->{"thread"}=$thread; + $Bcb{$Bcb}=$lastmap->{"init"}; + my $myoffs=$lastmap->{"FileOffset"}&~0xFFF; + die if defined $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs} && $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs} ne $Bcb; + for my $pinoffs (keys(%{$lastmap->{"init"}->{"Bcb_pin"}})) { + next if $pinoffs==$myoffs; + die $pinoffs if $lastmap->{"init"}->{"Bcb_pin"}->{$pinoffs} eq $Bcb; + } + $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs}=$Bcb; + die if $lastmap->{"init"}->{"Bcb_map"} && $lastmap->{"init"}->{"Bcb_map"} eq $Bcb; + next; + } + + if (my($Bcb)= + /^enter: CcRemapBcb: Bcb=($hex)/) { + die if !(my $reg=$Bcb{$Bcb}); + my $newmap={ + "remap"=>1, + "Bcb"=>$Bcb, + "init"=>$reg, + "line"=>$., + "by"=>"CcRemapBcb of $Bcb", + }; + push @{$reg->{"maps"}},$newmap; + push @lastmap_CcRemapBcb,$newmap; + } + if (my($r)= + /^leave: CcRemapBcb: r=($hex)/) { + die if !(my $lastmap=pop @lastmap_CcRemapBcb); + $lastmap->{"process"}=$process; + $lastmap->{"thread"}=$thread; + die "CcRemapBcb enterBcb ".$lastmap->{"Bcb"}." != leaveBcb ".$r + if $lastmap->{"Bcb"} ne $r; + next; + } + + if (my($Bcb)= + /^enter: CcUnpinData(?:|ForThread): Bcb=($hex)/) { + die if !(my $regbcb=$Bcb{$Bcb}); + $regbcb->{"unmaps"}++; + die if $regbcb->{"unmaps"}>@{$regbcb->{"maps"}}; + if ($regbcb->{"unmaps"}==@{$regbcb->{"maps"}}) { + warn "Full CcUnPinData for FileObject ".$regbcb->{"FileObject"}; +# $regbcb->{"unmaps"}=0; +# $regbcb->{"maps"}=[]; + $regbcb->{"unmaps"}++; + push @{$regbcb->{"maps"}},{ + "unpinned"=>"=========================================", + "line"=>$., + }; + } + $regbcb->{"Bcb_map"}=undef() if $regbcb->{"Bcb_map"} && $regbcb->{"Bcb_map"} eq $Bcb; + for my $pinoffs (keys(%{$regbcb->{"Bcb_pin"}})) { + delete $regbcb->{"Bcb_pin"}->{$pinoffs} if $regbcb->{"Bcb_pin"}->{$pinoffs} eq $Bcb; + } + next; + } + + if (my($irp_mj)= + /^enter: (IRP_MJ_.*)/) { + $last_irp_mj=$irp_mj; + next; + } + + if (my($FileObject)= + /^debug_irp: IoStackLocation->FileObject=($hex):/) { + next if $last_irp_mj ne "IRP_MJ_CLOSE"; + warn "IRP_MJ_CLOSE: still mapped $FileObject" if $init{$FileObject}->{"unmaps"}!=@{$init{$FileObject}->{"maps"}}; + delete $init{$FileObject}; + next; + } + + print "$_\n" if $filter; + } +for my $key (keys(%init)) { + warn "EXIT: still mapped $key" if $init{$key}->{"unmaps"}!=@{$init{$key}->{"maps"}}; + } diff --git a/src/TraceFS/hookfs.pl b/src/TraceFS/hookfs.pl new file mode 100755 index 0000000..43279f3 --- /dev/null +++ b/src/TraceFS/hookfs.pl @@ -0,0 +1,381 @@ +#! /usr/bin/perl +# +# $Id$ +# Redirect system calls of the specified file system driver to TraceFS.sys +# Copyright (C) 2003 Jan Kratochvil +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; exactly version 2 of June 1991 is required +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +use strict; +use warnings; +use Carp qw(cluck confess); + + +my $D=0; + +my $IMAGE_FILE_IMPORT_DIRECTORY=1; +my $IMAGE_FILE_EXPORT_DIRECTORY=0; +my $IMAGE_DATA_DIRECTORY_sizeof=8; +my $VirtualAddress_rel_to_DATA_DIRECTORY_offs=0; +my $Size_rel_to_DATA_DIRECTORY_offs=4; +my $IMAGE_EXPORT_DIRECTORY_sizeof=0x28; +my $IMAGE_IMPORT_DESCRIPTOR_sizeof=0x14; +my $Name_rel_to_IMAGE_EXPORT_DIRECTORY_offs=0xC; +my $NumberOfNames_rel_to_IMAGE_EXPORT_DIRECTORY_offs=0x18; +my $AddressOfNames_rel_to_IMAGE_EXPORT_DIRECTORY_offs=0x20; +my $OriginalFirstThunk_rel_to_IMPORT_DIRECTORY_offs=0x0; +my $FirstThunk_rel_to_IMPORT_DIRECTORY_offs=0x10; +my $Name_rel_to_IMAGE_IMPORT_BY_NAME_offs=0x2; +my $IMAGE_SECTION_HEADER_sizeof=0x28; +my $Name_rel_to_IMAGE_SECTION_HEADER_offs=0x00; +my $VirtualSize_rel_to_IMAGE_SECTION_HEADER_offs=0x08; +my $VirtualAddress_rel_to_IMAGE_SECTION_HEADER_offs=0x0C; +my $SizeOfRawData_rel_to_IMAGE_SECTION_HEADER_offs=0x10; +my $PointerToRawData_rel_to_IMAGE_SECTION_HEADER_offs=0x14; +my $Characteristics_rel_to_IMAGE_SECTION_HEADER_offs=0x24; + + +sub uintX_get($$$) +{ +my($file,$offset,$bits)=@_; + + my $r=0; + for (my $byte=0;$byte<$bits/8;$byte++) { + confess if !defined $file->[$offset+$byte]; + $r|=($file->[$offset+$byte])<<($byte*8); + } + return $r; +} +sub uint32_get($$) { return uintX_get($_[0],$_[1],32); } +sub uint16_get($$) { return uintX_get($_[0],$_[1],16); } +sub uint8_get($$) { return uintX_get($_[0],$_[1], 8); } + +sub uintX_put($$$$) +{ +my($file,$offset,$num,$bits)=@_; + + for (my $byte=0;$byte<$bits/8;$byte++) { + confess if !defined $offset; + $file->[$offset+$byte]=($num>>($byte*8))&0xFF; + } +} +sub uint32_put($$$) { return uintX_put($_[0],$_[1],$_[2],32); } +sub uint16_put($$$) { return uintX_put($_[0],$_[1],$_[2],16); } +sub uint8_put($$$) { return uintX_put($_[0],$_[1],$_[2], 8); } +sub uint32_push($$) { return uintX_put($_[0],@{$_[0]},$_[1],32); } +sub uint16_push($$) { return uintX_put($_[0],@{$_[0]},$_[1],16); } +sub uint8_push($$) { return uintX_put($_[0],@{$_[0]},$_[1], 8); } + + +sub sum_offs($) +{ +my($file)=@_; + + return uint32_get($file,0x3C) # 3c: Offset to extended header + +0x18 # OptionalHeader + +0x40; # CheckSum +} + +sub sum_get($) +{ +my($file)=@_; + + return uint32_get($file,sum_offs($file)); +} + +sub sum_put($$) +{ +my($file,$sum)=@_; + + return uint32_put($file,sum_offs($file),$sum); +} + +sub sum_calc($) +{ +my($file)=@_; + + $file=[ @$file ]; + sum_put($file,0); + my $length=@$file; + my $sum=0; + while (@$file) { + $sum+=(shift @$file || 0) | (shift @$file || 0)<<8; + $sum=($sum&0xFFFF)+($sum>>16); + } + $sum+=$length; + return $sum; +} + +sub align($$) +{ +my($file,$align)=@_; + + push @$file,0 while @$file%$align; +} + +sub stringz_put($$$) +{ +my($file,$offset,$stringz)=@_; + + $stringz=[ map({ ord(); } split //,$stringz),0 ]; + while (@$stringz) { + uint8_put($file,$offset,shift @$stringz); + $offset++; + } +} + +sub stringz_push($$) +{ +my($file,$stringz)=@_; + + stringz_put($file,@$file,$stringz); + align $file,4; +} + +sub stringz_get($$) +{ +my($file,$offset)=@_; + + my $r=""; + while ((my $ord=uint8_get($file,$offset))) { + $r.=chr $ord; + $offset++; + } + return $r; +} + +sub zeroes_push($$) +{ +my($file,$count)=@_; + + push @$file,0 while $count-->0; +} + +sub SizeOfImage_offs($) +{ +my($file)=@_; + + return uint32_get($file,0x3C) # 3c: Offset to extended header + +0x18 # OptionalHeader + +0x38; # SizeOfImage +} + +my $align=0x80; + +sub sanity($$) +{ +my($file,$file_id)=@_; + + my $calced=sum_calc($file); + if ($calced!=sum_get($file)) { + warn sprintf "$file_id: Original checksum wrong: found=0x%08X, calced=0x%08X",sum_get($file),$calced; + } + + die sprintf "$file_id: Length 0x%X not aligned",scalar(@$file) if @$file%$align; + my $SizeOfImage=uint32_get($file,SizeOfImage_offs($file)); + die sprintf "$file_id: SizeOfImage==0x%X but file size==0x%X",$SizeOfImage,scalar(@$file) if $SizeOfImage!=@$file; +} + +sub export_names_get($) +{ +my($tracefs)=@_; + + my $EXPORT_DIRECTORY_offs=uint32_get($tracefs,0x3C) # 3c: Offset to extended header + +0x18 # OptionalHeader + +0x60 # DataDirectory + +$IMAGE_FILE_EXPORT_DIRECTORY*$IMAGE_DATA_DIRECTORY_sizeof; + my $EXPORT_DIRECTORY_VirtualAddress=uint32_get($tracefs,$EXPORT_DIRECTORY_offs+$VirtualAddress_rel_to_DATA_DIRECTORY_offs); + my $EXPORT_DIRECTORY_Size=uint32_get($tracefs,$EXPORT_DIRECTORY_offs+$Size_rel_to_DATA_DIRECTORY_offs); + die sprintf "EXPORT_DIRECTORY_Size 0x%X less than IMAGE_IMPORT_DESCRIPTOR_sizeof 0x%X", + $EXPORT_DIRECTORY_Size,$IMAGE_IMPORT_DESCRIPTOR_sizeof if $EXPORT_DIRECTORY_Size<$IMAGE_IMPORT_DESCRIPTOR_sizeof; + my $IMAGE_EXPORT_DIRECTORY_Name=uint32_get($tracefs,$EXPORT_DIRECTORY_VirtualAddress + +$Name_rel_to_IMAGE_EXPORT_DIRECTORY_offs); + my $tracefs_export_name=stringz_get($tracefs,$IMAGE_EXPORT_DIRECTORY_Name); + my $tracefs_export_names_num=uint32_get($tracefs,$EXPORT_DIRECTORY_VirtualAddress + +$NumberOfNames_rel_to_IMAGE_EXPORT_DIRECTORY_offs); + my $tracefs_export_AddressOfNames=uint32_get($tracefs,$EXPORT_DIRECTORY_VirtualAddress + +$AddressOfNames_rel_to_IMAGE_EXPORT_DIRECTORY_offs); + my @tracefs_export_names; + print STDERR "$tracefs_export_name exports:\n" if $D; + for (my $namei=0;$namei<$tracefs_export_names_num;$namei++) { + my $name_address=uint32_get($tracefs,$tracefs_export_AddressOfNames+4*$namei); + my $name=stringz_get($tracefs,$name_address); + push @tracefs_export_names,$name; + print STDERR "\t$name\n" if $D; + } + + return ($tracefs_export_name,@tracefs_export_names); +} + + +undef $/; +my $file=[ map({ ord(); } split //,<>) ]; +my $tracefs=[ map({ ord(); } split //,<>) ]; + +sanity($tracefs,"tracefs"); +my($tracefs_export_name,@tracefs_export_names)=export_names_get($tracefs); +for my $tname (@tracefs_export_names) { + die "tracefs exported tname is not /^T/ compliant: $tname" if $tname!~/^T/; + } +# FIXME: compiled to .sys tracefs contains internal export name .dll but we need import .sys ! +$tracefs_export_name=~s/[.]dll$/.sys/i; + +sanity($file,"file"); + + +# import directory load + +my $IMPORT_DIRECTORY_offs=uint32_get($file,0x3C) # 3c: Offset to extended header + +0x18 # OptionalHeader + +0x60 # DataDirectory + +$IMAGE_FILE_IMPORT_DIRECTORY*$IMAGE_DATA_DIRECTORY_sizeof; +my $IMPORT_DIRECTORY_VirtualAddress=uint32_get($file,$IMPORT_DIRECTORY_offs+$VirtualAddress_rel_to_DATA_DIRECTORY_offs); +my $IMPORT_DIRECTORY_Size=uint32_get($file,$IMPORT_DIRECTORY_offs+$Size_rel_to_DATA_DIRECTORY_offs); +die sprintf "IMPORT_DIRECTORY_Size 0x%X not aligned to IMAGE_IMPORT_DESCRIPTOR_sizeof 0x%X", + $IMPORT_DIRECTORY_Size,$IMAGE_IMPORT_DESCRIPTOR_sizeof if $IMPORT_DIRECTORY_Size%$IMAGE_IMPORT_DESCRIPTOR_sizeof; + +my $IMPORT_DIRECTORY=[ @{$file}[$IMPORT_DIRECTORY_VirtualAddress + ..($IMPORT_DIRECTORY_VirtualAddress+$IMPORT_DIRECTORY_Size-1)] ]; +uintX_put($file,$IMPORT_DIRECTORY_VirtualAddress,0,8*$IMPORT_DIRECTORY_Size); # zero the original space +for (my $zerotail=0;$zerotail<$IMAGE_IMPORT_DESCRIPTOR_sizeof;$zerotail++) { + die "IMPORT_DIRECTORY tail not zeroed" if pop @$IMPORT_DIRECTORY; + } + + +# import directory entries processing + +my %name_to_FirstThunk; # name->FirstThunk +my %tname_to_name; # string->string{^.->T} +for ( + my $IMPORT_DIRECTORY_offset=0; + $IMPORT_DIRECTORY_offset<@$IMPORT_DIRECTORY; + $IMPORT_DIRECTORY_offset+=$IMAGE_IMPORT_DESCRIPTOR_sizeof) { + my $OriginalFirstThunk_base=uint32_get($IMPORT_DIRECTORY,$IMPORT_DIRECTORY_offset + +$OriginalFirstThunk_rel_to_IMPORT_DIRECTORY_offs); + my $FirstThunk_base=uint32_get($IMPORT_DIRECTORY,$IMPORT_DIRECTORY_offset + +$FirstThunk_rel_to_IMPORT_DIRECTORY_offs); + for (my $OriginalFirstThunk=$OriginalFirstThunk_base;;$OriginalFirstThunk+=4) { + my $AddressOfData=uint32_get($file,$OriginalFirstThunk); + last if !$AddressOfData; + my $name=stringz_get($file,$AddressOfData+$Name_rel_to_IMAGE_IMPORT_BY_NAME_offs); + print STDERR "import $name\n" if $D; + die "Invalid name import as it has leading 'T': $name" if $name=~/^T/; + (my $tname=$name)=~s/^./T/; + die "Name conflict in tname map: $name->$tname" if exists $tname_to_name{$tname}; + $tname_to_name{$tname}=$name; + die if exists $name_to_FirstThunk{$name}; + $name_to_FirstThunk{$name}=$FirstThunk_base+($OriginalFirstThunk-$OriginalFirstThunk_base); + } + } + + +# add-on import directories generation +my $addon_section_base=@$file; + +my $tracefs_export_name_offs=@$file; +stringz_push($file,$tracefs_export_name); + +my $ordinal=1; +for my $tname (@tracefs_export_names) { + die "tracefs exported tname $tname not found in imports" if !exists $tname_to_name{$tname}; + my $name=$tname_to_name{$tname}; + my $FirstThunk=$name_to_FirstThunk{$name}; + + my $IMAGE_IMPORT_BY_NAME_offs=@$file; + uint16_push($file,$ordinal++); # Hint + stringz_push($file,$tname); # Name + + my $OriginalFirstThunk_offs=@$file; + uint32_push($file,$IMAGE_IMPORT_BY_NAME_offs); + uint32_push($file,0); # zero terminator + + uint32_push($IMPORT_DIRECTORY,$OriginalFirstThunk_offs); + uint32_push($IMPORT_DIRECTORY,0); # TimeDateStamp + uint32_push($IMPORT_DIRECTORY,0); # ForwarderChain + uint32_push($IMPORT_DIRECTORY,$tracefs_export_name_offs); # Name + uint32_push($IMPORT_DIRECTORY,$FirstThunk); + } + +zeroes_push $IMPORT_DIRECTORY,$IMAGE_IMPORT_DESCRIPTOR_sizeof; +uint32_put($file,$IMPORT_DIRECTORY_offs+$VirtualAddress_rel_to_DATA_DIRECTORY_offs,scalar(@$file)); +uint32_put($file,$IMPORT_DIRECTORY_offs+$Size_rel_to_DATA_DIRECTORY_offs,scalar(@$IMPORT_DIRECTORY)); +push @$file,@$IMPORT_DIRECTORY; + + +# rebuild the sections for add-on data +align $file,$align; +# concatenate .rdata to .data +my $SizeOfOptionalHeader_offs=uint32_get($file,0x3C) # 3c: Offset to extended header + +0x04 # FileHeader + +0x10; # SizeOfOptionalHeader +my $SizeOfOptionalHeader=uint16_get($file,$SizeOfOptionalHeader_offs); +my $NumberOfSections_offs=uint32_get($file,0x3C) # 3c: Offset to extended header + +0x04 # FileHeader + +0x2; # NumberOfSections +my $NumberOfSections=uint16_get($file,$NumberOfSections_offs); +my $IMAGE_SECTION_HEADER_offs=uint32_get($file,0x3C) # 3c: Offset to extended header + +0x18 # OptionalHeader + +$SizeOfOptionalHeader; + +my($offset_data,$offset_rdata); +for ( + my $IMAGE_SECTION_HEADER_offset=$IMAGE_SECTION_HEADER_offs; + $IMAGE_SECTION_HEADER_offset<$IMAGE_SECTION_HEADER_offs+$NumberOfSections*$IMAGE_SECTION_HEADER_sizeof; + $IMAGE_SECTION_HEADER_offset+=$IMAGE_SECTION_HEADER_sizeof) { + my $VirtualAddress=uint32_get($file,$IMAGE_SECTION_HEADER_offset+$VirtualAddress_rel_to_IMAGE_SECTION_HEADER_offs); + my $PointerToRawData=uint32_get($file,$IMAGE_SECTION_HEADER_offset+$PointerToRawData_rel_to_IMAGE_SECTION_HEADER_offs); + die sprintf "VirtualAddress 0x%X != PointerToRawData 0x%X in IMAGE_SECTION_HEADER at 0x%X", + $VirtualAddress,$PointerToRawData,$IMAGE_SECTION_HEADER_offset if $VirtualAddress!=$PointerToRawData; + my $SizeOfRawData=uint32_get($file,$IMAGE_SECTION_HEADER_offset+$SizeOfRawData_rel_to_IMAGE_SECTION_HEADER_offs); + my $VirtualSize=uint32_get($file,$IMAGE_SECTION_HEADER_offset+$VirtualSize_rel_to_IMAGE_SECTION_HEADER_offs); + $VirtualSize+=$align-1; + $VirtualSize-=$VirtualSize%$align; + die sprintf "up_align(VirtualSize,0x%X) 0x%X != SizeOfRawData 0x%X in IMAGE_SECTION_HEADER at 0x%X", + $align,$VirtualSize.$SizeOfRawData,$IMAGE_SECTION_HEADER_offset if $VirtualSize!=$SizeOfRawData; + my $Characteristics=uint32_get($file,$IMAGE_SECTION_HEADER_offset+$Characteristics_rel_to_IMAGE_SECTION_HEADER_offs); + my $is_data =($Characteristics==0xC8000040); + my $is_rdata=($Characteristics==0x48000040); + die sprintf "Duplicate .data in IMAGE_SECTION_HEADER at 0x%X",$IMAGE_SECTION_HEADER_offset if $is_data && $offset_data; + die sprintf "Duplicate .rdata in IMAGE_SECTION_HEADER at 0x%X",$IMAGE_SECTION_HEADER_offset if $is_rdata && $offset_rdata; + $offset_data=$IMAGE_SECTION_HEADER_offset if $is_data; + $offset_rdata=$IMAGE_SECTION_HEADER_offset if $is_rdata; + } +die ".data section not found" if !$offset_data; +die ".rdata section not found" if !$offset_rdata; +my $data_PointerToRawData=uint32_get($file,$offset_data+$PointerToRawData_rel_to_IMAGE_SECTION_HEADER_offs); +my $data_SizeOfRawData=uint32_get($file,$offset_data+$SizeOfRawData_rel_to_IMAGE_SECTION_HEADER_offs); +my $data_VirtualSize=uint32_get($file,$offset_data+$VirtualSize_rel_to_IMAGE_SECTION_HEADER_offs); +my $rdata_PointerToRawData=uint32_get($file,$offset_rdata+$PointerToRawData_rel_to_IMAGE_SECTION_HEADER_offs); +my $rdata_SizeOfRawData=uint32_get($file,$offset_rdata+$SizeOfRawData_rel_to_IMAGE_SECTION_HEADER_offs); +my $rdata_VirtualSize=uint32_get($file,$offset_rdata+$VirtualSize_rel_to_IMAGE_SECTION_HEADER_offs); +die ".data is not right after .rdata" if $rdata_PointerToRawData+$rdata_SizeOfRawData!=$data_PointerToRawData; +uint32_put($file,$offset_data+$PointerToRawData_rel_to_IMAGE_SECTION_HEADER_offs,$rdata_PointerToRawData); +uint32_put($file,$offset_data+$VirtualAddress_rel_to_IMAGE_SECTION_HEADER_offs,$rdata_PointerToRawData); +uint32_put($file,$offset_data+$SizeOfRawData_rel_to_IMAGE_SECTION_HEADER_offs,$rdata_SizeOfRawData+$data_SizeOfRawData); +uint32_put($file,$offset_data+$VirtualSize_rel_to_IMAGE_SECTION_HEADER_offs,$rdata_SizeOfRawData+$data_VirtualSize); +# .rdata coalesced to .data, .rdata to be rebuilt now: +uintX_put($file,$offset_rdata,0,8*$IMAGE_SECTION_HEADER_sizeof); # zero the original space +stringz_put($file,$offset_rdata+$Name_rel_to_IMAGE_SECTION_HEADER_offs,"INIT"); +uint32_put($file,$offset_rdata+$VirtualSize_rel_to_IMAGE_SECTION_HEADER_offs,@$file-$addon_section_base); +uint32_put($file,$offset_rdata+$VirtualAddress_rel_to_IMAGE_SECTION_HEADER_offs,$addon_section_base); +uint32_put($file,$offset_rdata+$SizeOfRawData_rel_to_IMAGE_SECTION_HEADER_offs,@$file-$addon_section_base); +uint32_put($file,$offset_rdata+$PointerToRawData_rel_to_IMAGE_SECTION_HEADER_offs,$addon_section_base); +uint32_put($file,$offset_rdata+$Characteristics_rel_to_IMAGE_SECTION_HEADER_offs,0xE2000020); + + +# file output finalization +uint32_put($file,SizeOfImage_offs($file),scalar(@$file)); +sum_put($file,sum_calc($file)); +print join("",map({ chr; } @$file));