+Implemented TraceFS W32 Cache Manager debug tracer
authorshort <>
Sun, 3 Aug 2003 08:00:27 +0000 (08:00 +0000)
committershort <>
Sun, 3 Aug 2003 08:00:27 +0000 (08:00 +0000)
12 files changed:
NEWS
autogen.pl
configure.in
src/Makefile.am
src/TraceFS/Makefile.am [new file with mode: 0644]
src/TraceFS/TraceFS-W32/Sources [new file with mode: 0644]
src/TraceFS/TraceFS-W32/TraceFS.c [new file with mode: 0644]
src/TraceFS/TraceFS-W32/TraceFS.def [new file with mode: 0644]
src/TraceFS/TraceFS-W32/TraceFS.reg [new file with mode: 0644]
src/TraceFS/TraceFS-W32/makeFile [new file with mode: 0644]
src/TraceFS/checktrace.pl [new file with mode: 0755]
src/TraceFS/hookfs.pl [new file with mode: 0755]

diff --git a/NEWS b/NEWS
index f8afc21..00b9745 100644 (file)
--- 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)
index 5bca278..8f69d12 100755 (executable)
@@ -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;
index 294a0e8..40d8a3f 100644 (file)
@@ -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
index 40ce399..a4d4274 100644 (file)
@@ -1,6 +1,6 @@
 # $Id$
 # automake source for the topsrclevel Makefile 
-# Copyright (C) 2002 Jan Kratochvil <project-captive@jankratochvil.net>
+# Copyright (C) 2002-2003 Jan Kratochvil <project-captive@jankratochvil.net>
 # 
 # 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 (file)
index 0000000..e8cb696
--- /dev/null
@@ -0,0 +1,48 @@
+# $Id$
+# UNIX automake source for the makefile of TraceFS
+# Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
+# 
+# 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 (file)
index 0000000..7be5a62
--- /dev/null
@@ -0,0 +1,30 @@
+# $Id$\r
+# Makefile for W32 build of TraceFS by build.exe\r
+# Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>\r
+# \r
+# This program is free software; you can redistribute it and/or modify\r
+# it under the terms of the GNU General Public License as published by\r
+# the Free Software Foundation; exactly version 2 of June 1991 is required\r
+# \r
+# This program is distributed in the hope that it will be useful,\r
+# but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+# GNU General Public License for more details.\r
+# \r
+# You should have received a copy of the GNU General Public License\r
+# along with this program; if not, write to the Free Software\r
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+\r
+\r
+TARGETNAME=TraceFS\r
+TARGETPATH=obj\r
+\r
+TARGETTYPE=EXPORT_DRIVER\r
+DRIVERTYPE=FS\r
+NO_NTDLL=1\r
+UMTYPE=nt\r
+\r
+MSC_WARNING_LEVEL=/W3 /WX\r
+\r
+SOURCES= \\r
+       tracefs.c\r
diff --git a/src/TraceFS/TraceFS-W32/TraceFS.c b/src/TraceFS/TraceFS-W32/TraceFS.c
new file mode 100644 (file)
index 0000000..3bdd145
--- /dev/null
@@ -0,0 +1,1366 @@
+/* $Id$\r
+ * Debugging tracer of IRPs and Cc* (Cache Manager) calls for W32\r
+ * Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>\r
+ * \r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; exactly version 2 of June 1991 is required\r
+ * \r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ */\r
+\r
+#include <ntddk.h>\r
+\r
+\r
+#define CACHE_SIZE 0x200\r
+\r
+\r
+#define G_N_ELEMENTS(arr) (sizeof(arr)/sizeof((arr)[0]))\r
+\r
+NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath);\r
+\r
+#ifdef ALLOC_PRAGMA\r
+#pragma alloc_text (INIT, DriverEntry)\r
+#endif\r
+\r
+static FAST_MUTEX lock_mutex;\r
+\r
+static void lock_init(void)\r
+{\r
+       ExInitializeFastMutex(&lock_mutex);\r
+}\r
+\r
+static void lock(void)\r
+{\r
+       ExAcquireFastMutex(&lock_mutex);\r
+}\r
+\r
+static void unlock(void)\r
+{\r
+       ExReleaseFastMutex(&lock_mutex);\r
+}\r
+\r
+#define DBGPREFIX "TraceFS(0x%08lX/0x%08lX): "\r
+#define DBGARG PsGetCurrentProcess(),PsGetCurrentThread()\r
+\r
+static int dbgindent=0;\r
+\r
+/* lock() will protect dbg_unicode_string() static buffer. */\r
+#define DBGSINGLE6(fmt,arg1,arg2,arg3,arg4,arg5,arg6) \\r
+               do { lock(); DbgPrint("%*s" DBGPREFIX fmt "\n",dbgindent,"",DBGARG,arg1,arg2,arg3,arg4,arg5,arg6); unlock(); } while (0)\r
+#define DBGSINGLE5(fmt,arg1,arg2,arg3,arg4,arg5) DBGSINGLE6(fmt,arg1,arg2,arg3,arg4,arg5,0)\r
+#define DBGSINGLE4(fmt,arg1,arg2,arg3,arg4)      DBGSINGLE5(fmt,arg1,arg2,arg3,arg4,0)\r
+#define DBGSINGLE3(fmt,arg1,arg2,arg3)           DBGSINGLE4(fmt,arg1,arg2,arg3,0)\r
+#define DBGSINGLE2(fmt,arg1,arg2)                DBGSINGLE3(fmt,arg1,arg2,0)\r
+#define DBGSINGLE1(fmt,arg1)                     DBGSINGLE2(fmt,arg1,0)\r
+#define DBGSINGLE0(fmt)                          DBGSINGLE1(fmt,0)\r
+#define DBGSINGLEENTER6(fmt,arg1,arg2,arg3,arg4,arg5,arg6) \\r
+               do { DBGSINGLE6("enter: " fmt,arg1,arg2,arg3,arg4,arg5,arg6); dbgindent++; } while (0)\r
+#define DBGSINGLEENTER5(fmt,arg1,arg2,arg3,arg4,arg5) DBGSINGLEENTER6(fmt,arg1,arg2,arg3,arg4,arg5,0)\r
+#define DBGSINGLEENTER4(fmt,arg1,arg2,arg3,arg4)      DBGSINGLEENTER5(fmt,arg1,arg2,arg3,arg4,0)\r
+#define DBGSINGLEENTER3(fmt,arg1,arg2,arg3)           DBGSINGLEENTER4(fmt,arg1,arg2,arg3,0)\r
+#define DBGSINGLEENTER2(fmt,arg1,arg2)                DBGSINGLEENTER3(fmt,arg1,arg2,0)\r
+#define DBGSINGLEENTER1(fmt,arg1)                     DBGSINGLEENTER2(fmt,arg1,0)\r
+#define DBGSINGLEENTER0(fmt)                          DBGSINGLEENTER1(fmt,0)\r
+#define DBGSINGLELEAVE3(fmt,arg1,arg2,arg3) \\r
+               do { dbgindent--; DBGSINGLE3("leave: " fmt,arg1,arg2,arg3); } while (0)\r
+#define DBGSINGLELEAVE2(fmt,arg1,arg2) DBGSINGLELEAVE3(fmt,arg1,arg2,0)\r
+#define DBGSINGLELEAVE1(fmt,arg1)      DBGSINGLELEAVE2(fmt,arg1,0)\r
+#define DBGSINGLELEAVE0(fmt)           DBGSINGLELEAVE1(fmt,0)\r
+\r
+\r
+/* We cannot use DbgPrint("%wZ",...) as it must have IRQL PASSIVE_LEVEL which\r
+ * is not satisfied.\r
+ */\r
+static const char *dbg_unicode_string(UNICODE_STRING *unicode_string)\r
+{\r
+static char buf[0x100];\r
+char *d;\r
+PWSTR s;\r
+\r
+       if (!unicode_string || !unicode_string->Buffer)\r
+               return "NULL";\r
+       d=buf;\r
+       *d++='\'';\r
+       for (s=unicode_string->Buffer;s<unicode_string->Buffer+(unicode_string->Length/2);s++) {\r
+               if (d>=buf+sizeof(buf)-4)\r
+                       break;\r
+               *d++=(char)*s;\r
+               }\r
+       *d++='\'';\r
+       *d=0;\r
+       return buf;\r
+}\r
+\r
+NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)\r
+{\r
+NTSTATUS r;\r
+DEVICE_OBJECT *device_object;\r
+\r
+       lock_init();\r
+\r
+       DBGSINGLEENTER1("DriverEntry: RegistryPath=%s",dbg_unicode_string(RegistryPath));\r
+       DBGSINGLE1("DriverEntry: %s","$Id$");\r
+       r=IoCreateDevice(\r
+                       DriverObject,   /* DriverObject */\r
+                       0,      /* DeviceExtensionSize */\r
+                       NULL,   /* DeviceName; optional */\r
+                       FILE_DEVICE_UNKNOWN,    /* DeviceType */\r
+                       0,      /* DeviceCharacteristics */\r
+                       FALSE,  /* Exclusive */\r
+                       &device_object);        /* DeviceObject */\r
+       DBGSINGLELEAVE1("DriverEntry: r=0x%lX",(long)r);\r
+       return r;\r
+}\r
+\r
+static const char *const irp_mj_dump_FILE_SYSTEM_CONTROL_MinorFunction_names[]={\r
+               "IRP_MN_USER_FS_REQUEST",\r
+               "IRP_MN_MOUNT_VOLUME",\r
+               "IRP_MN_VERIFY_VOLUME",\r
+               "IRP_MN_LOAD_FILE_SYSTEM",\r
+               "IRP_MN_KERNEL_CALL",\r
+               };\r
+\r
+/* Compatibility with DDK; the structures match. */\r
+#define FileSystemControl DeviceIoControl\r
+#define FsControlCode IoControlCode\r
+#ifndef FSCTL_REQUEST_BATCH_OPLOCK\r
+#define FSCTL_REQUEST_BATCH_OPLOCK CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2,METHOD_BUFFERED,FILE_ANY_ACCESS)\r
+#endif\r
+#ifndef FSCTL_LOCK_VOLUME\r
+#define FSCTL_LOCK_VOLUME          CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 6,METHOD_BUFFERED,FILE_ANY_ACCESS)\r
+#endif\r
+#ifndef FSCTL_UNLOCK_VOLUME\r
+#define FSCTL_UNLOCK_VOLUME        CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 7,METHOD_BUFFERED,FILE_ANY_ACCESS)\r
+#endif\r
+#ifndef FSCTL_DISMOUNT_VOLUME\r
+#define FSCTL_DISMOUNT_VOLUME      CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 8,METHOD_BUFFERED,FILE_ANY_ACCESS)\r
+#endif\r
+#ifndef FSCTL_MARK_VOLUME_DIRTY\r
+#define FSCTL_MARK_VOLUME_DIRTY    CTL_CODE(FILE_DEVICE_FILE_SYSTEM,12,METHOD_BUFFERED,FILE_ANY_ACCESS)\r
+#endif\r
+#ifndef FSCTL_INVALIDATE_VOLUMES\r
+#define FSCTL_INVALIDATE_VOLUMES   CTL_CODE(FILE_DEVICE_FILE_SYSTEM,21,METHOD_BUFFERED,FILE_ANY_ACCESS)\r
+#endif\r
+#ifndef FSCTL_IS_VOLUME_DIRTY\r
+#define FSCTL_IS_VOLUME_DIRTY      CTL_CODE(FILE_DEVICE_FILE_SYSTEM,30,METHOD_BUFFERED,FILE_ANY_ACCESS)\r
+#endif\r
+#ifndef FSCTL_FILE_PREFETCH\r
+#define FSCTL_FILE_PREFETCH        CTL_CODE(FILE_DEVICE_FILE_SYSTEM,72,METHOD_BUFFERED,FILE_SPECIAL_ACCESS)\r
+#endif\r
+\r
+static void irp_mj_dump(struct _DEVICE_OBJECT *DeviceObject,struct _IRP *Irp)\r
+{\r
+IO_STACK_LOCATION *IoStackLocation;\r
+FILE_OBJECT *FileObject;\r
+\r
+       if (!Irp) {\r
+               DBGSINGLE0("Irp==NULL");\r
+               return;\r
+               }\r
+       IoStackLocation=IoGetCurrentIrpStackLocation(Irp);\r
+       if (!IoStackLocation) {\r
+               DBGSINGLE0("IoStackLocation==NULL");\r
+               return;\r
+               }\r
+       if (!(FileObject=IoStackLocation->FileObject))\r
+               DBGSINGLE0("FileObject=NULL");\r
+       else\r
+               DBGSINGLE5("FileObject=0x%lX: FileName=%s,Flags=0x%lX,SectionObjectPointer=0x%lX,->SharedCacheMap=0x%lX",\r
+                               (long)FileObject,\r
+                               dbg_unicode_string(&FileObject->FileName),FileObject->Flags,\r
+                               (long)FileObject->SectionObjectPointer,\r
+                               (!FileObject->SectionObjectPointer ? -1 : (long)FileObject->SectionObjectPointer->SharedCacheMap));\r
+       switch (IoStackLocation->MajorFunction) {\r
+               case IRP_MJ_READ:\r
+                       DBGSINGLE2("READ: ByteOffset=0x%lX,Length=0x%lX",\r
+                                       (long)IoStackLocation->Parameters.Read.ByteOffset.QuadPart,\r
+                                       IoStackLocation->Parameters.Read.Length);\r
+                       break;\r
+               case IRP_MJ_WRITE:\r
+                       DBGSINGLE2("WRITE: ByteOffset=0x%lX,Length=0x%lX",\r
+                                       (long)IoStackLocation->Parameters.Write.ByteOffset.QuadPart,\r
+                                       IoStackLocation->Parameters.Write.Length);\r
+                       break;\r
+               case IRP_MJ_FILE_SYSTEM_CONTROL:\r
+                       DBGSINGLE2("FILE_SYSTEM_CONTROL: MinorFunction=%s (%d)",\r
+                                       ((1\r
+                                                                       && IoStackLocation->MinorFunction>=0\r
+                                                                       && IoStackLocation->MinorFunction<G_N_ELEMENTS(irp_mj_dump_FILE_SYSTEM_CONTROL_MinorFunction_names))\r
+                                                       ? irp_mj_dump_FILE_SYSTEM_CONTROL_MinorFunction_names[IoStackLocation->MinorFunction] : "???"),\r
+                                       IoStackLocation->MinorFunction);\r
+                       switch (IoStackLocation->MinorFunction) {\r
+                               case IRP_MN_USER_FS_REQUEST: {\r
+const char *FsControlCode_name;\r
+                                       switch (IoStackLocation->Parameters.FileSystemControl.FsControlCode) {\r
+                                               case FSCTL_REQUEST_BATCH_OPLOCK: FsControlCode_name="FSCTL_REQUEST_BATCH_OPLOCK"; break;\r
+                                               case FSCTL_LOCK_VOLUME:          FsControlCode_name="FSCTL_LOCK_VOLUME";          break;\r
+                                               case FSCTL_UNLOCK_VOLUME:        FsControlCode_name="FSCTL_UNLOCK_VOLUME";        break;\r
+                                               case FSCTL_DISMOUNT_VOLUME:      FsControlCode_name="FSCTL_DISMOUNT_VOLUME";      break;\r
+                                               case FSCTL_MARK_VOLUME_DIRTY:    FsControlCode_name="FSCTL_MARK_VOLUME_DIRTY";    break;\r
+                                               case FSCTL_INVALIDATE_VOLUMES:   FsControlCode_name="FSCTL_INVALIDATE_VOLUMES";   break;\r
+                                               case FSCTL_IS_VOLUME_DIRTY:      FsControlCode_name="FSCTL_IS_VOLUME_DIRTY";      break;\r
+                                               case FSCTL_FILE_PREFETCH:        FsControlCode_name="FSCTL_FILE_PREFETCH";        break;\r
+                                               default:                         FsControlCode_name="???";                        break;\r
+                                               }\r
+                                       DBGSINGLE2("USER_FS_REQUEST: FsControlCode=%s (%d)",FsControlCode_name,\r
+                                                       IoStackLocation->Parameters.FileSystemControl.FsControlCode);\r
+                                       } break;\r
+                               }\r
+               }\r
+}\r
+\r
+#define TRACEFS_MAJORS \\r
+               TRACEFS_MAJOR(IRP_MJ_CREATE) \\r
+               TRACEFS_MAJOR(IRP_MJ_CREATE_NAMED_PIPE) \\r
+               TRACEFS_MAJOR(IRP_MJ_CLOSE) \\r
+               TRACEFS_MAJOR(IRP_MJ_READ) \\r
+               TRACEFS_MAJOR(IRP_MJ_WRITE) \\r
+               TRACEFS_MAJOR(IRP_MJ_QUERY_INFORMATION) \\r
+               TRACEFS_MAJOR(IRP_MJ_SET_INFORMATION) \\r
+               TRACEFS_MAJOR(IRP_MJ_QUERY_EA) \\r
+               TRACEFS_MAJOR(IRP_MJ_SET_EA) \\r
+               TRACEFS_MAJOR(IRP_MJ_FLUSH_BUFFERS) \\r
+               TRACEFS_MAJOR(IRP_MJ_QUERY_VOLUME_INFORMATION) \\r
+               TRACEFS_MAJOR(IRP_MJ_SET_VOLUME_INFORMATION) \\r
+               TRACEFS_MAJOR(IRP_MJ_DIRECTORY_CONTROL) \\r
+               TRACEFS_MAJOR(IRP_MJ_FILE_SYSTEM_CONTROL) \\r
+               TRACEFS_MAJOR(IRP_MJ_DEVICE_CONTROL) \\r
+               TRACEFS_MAJOR(IRP_MJ_INTERNAL_DEVICE_CONTROL) \\r
+               TRACEFS_MAJOR(IRP_MJ_SHUTDOWN) \\r
+               TRACEFS_MAJOR(IRP_MJ_LOCK_CONTROL) \\r
+               TRACEFS_MAJOR(IRP_MJ_CLEANUP) \\r
+               TRACEFS_MAJOR(IRP_MJ_CREATE_MAILSLOT) \\r
+               TRACEFS_MAJOR(IRP_MJ_QUERY_SECURITY) \\r
+               TRACEFS_MAJOR(IRP_MJ_SET_SECURITY) \\r
+               TRACEFS_MAJOR(IRP_MJ_POWER) \\r
+               TRACEFS_MAJOR(IRP_MJ_SYSTEM_CONTROL) \\r
+               TRACEFS_MAJOR(IRP_MJ_DEVICE_CHANGE) \\r
+               TRACEFS_MAJOR(IRP_MJ_QUERY_QUOTA) \\r
+               TRACEFS_MAJOR(IRP_MJ_SET_QUOTA) \\r
+               TRACEFS_MAJOR(IRP_MJ_PNP)\r
+\r
+\r
+#define TRACEFS_MAJOR(irp_mj_name) \\r
+static NTSTATUS (*tracefs_major_##irp_mj_name##_orig)(IN struct _DEVICE_OBJECT *DeviceObject,IN struct _IRP *Irp); \\r
+static NTSTATUS tracefs_major_##irp_mj_name(IN struct _DEVICE_OBJECT *DeviceObject,IN struct _IRP *Irp) \\r
+{ \\r
+NTSTATUS r; \\r
+ \\r
+       DBGSINGLEENTER0( #irp_mj_name ); \\r
+       irp_mj_dump(DeviceObject,Irp); \\r
+       r=(*tracefs_major_##irp_mj_name##_orig)(DeviceObject,Irp); \\r
+       DBGSINGLELEAVE1( #irp_mj_name ": r=0x%lX",(long)r); \\r
+       return r; \\r
+}\r
+\r
+TRACEFS_MAJORS\r
+\r
+#undef TRACEFS_MAJOR\r
+\r
+\r
+VOID IoRegisterFileSystem(IN OUT PDEVICE_OBJECT DeviceObject);\r
+VOID ToRegisterFileSystem(IN OUT PDEVICE_OBJECT DeviceObject)\r
+{\r
+       DBGSINGLEENTER0("IoRegisterFileSystem");\r
+\r
+#define TRACEFS_MAJOR(irp_mj_name) do { \\r
+               tracefs_major_##irp_mj_name##_orig=DeviceObject->DriverObject->MajorFunction[irp_mj_name]; \\r
+               DeviceObject->DriverObject->MajorFunction[irp_mj_name]=tracefs_major_##irp_mj_name; \\r
+               } while (0);\r
+\r
+TRACEFS_MAJORS\r
+\r
+#undef TRACEFS_MAJOR\r
+\r
+       IoRegisterFileSystem(DeviceObject);\r
+       DBGSINGLELEAVE0("IoRegisterFileSystem");\r
+}\r
+\r
+\r
+static char PsCreateSystemThread_bogusthread;\r
+\r
+NTSTATUS TsCreateSystemThread(\r
+    OUT PHANDLE ThreadHandle,\r
+    IN ULONG DesiredAccess,\r
+    IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,\r
+    IN HANDLE ProcessHandle OPTIONAL,\r
+    OUT PCLIENT_ID ClientId OPTIONAL,\r
+    IN PKSTART_ROUTINE StartRoutine,\r
+    IN PVOID StartContext\r
+    )\r
+{\r
+       DBGSINGLEENTER1("PsCreateSystemThread: StartRoutine=0x%lX",(long)StartRoutine);\r
+       if (ThreadHandle)\r
+               *ThreadHandle=(HANDLE)&PsCreateSystemThread_bogusthread;\r
+       DBGSINGLELEAVE0("PsCreateSystemThread");\r
+       return STATUS_SUCCESS;\r
+}\r
+\r
+NTSTATUS\r
+NTAPI\r
+TwClose(\r
+    IN HANDLE Handle\r
+    )\r
+{\r
+       DBGSINGLEENTER0("ZwClose");\r
+       if (Handle==(HANDLE)&PsCreateSystemThread_bogusthread) {\r
+               DBGSINGLELEAVE0("ZwClose: bogusthread catched");\r
+               return STATUS_SUCCESS;\r
+               }\r
+       DBGSINGLELEAVE0("ZwClose: passed");\r
+       return ZwClose(Handle);\r
+}\r
+\r
+\r
+BOOLEAN\r
+CcCanIWrite (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN ULONG BytesToWrite,\r
+    IN BOOLEAN Wait,\r
+    IN BOOLEAN Retrying\r
+    );\r
+BOOLEAN\r
+TcCanIWrite (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN ULONG BytesToWrite,\r
+    IN BOOLEAN Wait,\r
+    IN BOOLEAN Retrying\r
+    )\r
+{\r
+BOOLEAN r;\r
+\r
+       DBGSINGLEENTER4("CcCanIWrite: FileObject=0x%lX,BytesToWrite=0x%lX,Wait=%d,Retrying=%d",\r
+                       (long)FileObject,BytesToWrite,Wait,Retrying);\r
+       r=CcCanIWrite (\r
+FileObject,\r
+BytesToWrite,\r
+Wait,\r
+Retrying\r
+    );\r
+       DBGSINGLELEAVE1("CcCanIWrite: r=%d",r);\r
+       return r;\r
+}\r
+\r
+BOOLEAN\r
+CcCopyRead (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PLARGE_INTEGER FileOffset,\r
+    IN ULONG Length,\r
+    IN BOOLEAN Wait,\r
+    OUT PVOID Buffer,\r
+    OUT PIO_STATUS_BLOCK IoStatus\r
+    );\r
+BOOLEAN\r
+TcCopyRead (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PLARGE_INTEGER FileOffset,\r
+    IN ULONG Length,\r
+    IN BOOLEAN Wait,\r
+    OUT PVOID Buffer,\r
+    OUT PIO_STATUS_BLOCK IoStatus\r
+    )\r
+{\r
+BOOLEAN r;\r
+\r
+       DBGSINGLEENTER5("CcCopyRead: FileObject=0x%lX,FileOffset=0x%lX,Length=0x%lX,Wait=%d,Buffer=0x%lX",\r
+                       (long)FileObject,(!FileOffset ? -1 : (long)FileOffset->QuadPart),Length,Wait,(long)Buffer);\r
+       r=CcCopyRead (\r
+FileObject,\r
+FileOffset,\r
+Length,\r
+Wait,\r
+Buffer,\r
+IoStatus\r
+    );\r
+       DBGSINGLELEAVE3("CcCopyRead: r=%d,IoStatus->Status=0x%lX,IoStatus->Information=0x%lX",\r
+                       r,(!IoStatus ? -1 : (long)IoStatus->Status),(!IoStatus ? -1 : (long)IoStatus->Information));\r
+       return r;\r
+}\r
+\r
+BOOLEAN\r
+CcCopyWrite (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PLARGE_INTEGER FileOffset,\r
+    IN ULONG Length,\r
+    IN BOOLEAN Wait,\r
+    IN PVOID Buffer\r
+    );\r
+BOOLEAN\r
+TcCopyWrite (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PLARGE_INTEGER FileOffset,\r
+    IN ULONG Length,\r
+    IN BOOLEAN Wait,\r
+    IN PVOID Buffer\r
+    )\r
+{\r
+BOOLEAN r;\r
+\r
+       DBGSINGLEENTER5("CcCopyWrite: FileObject=0x%lX,FileOffset=0x%lX,Length=0x%lX,Wait=%d,Buffer=0x%lX",\r
+                       (long)FileObject,(!FileOffset ? -1 : (long)FileOffset->QuadPart),Length,Wait,(long)Buffer);\r
+       r=CcCopyWrite (\r
+FileObject,\r
+FileOffset,\r
+Length,\r
+Wait,\r
+Buffer\r
+    );\r
+       DBGSINGLELEAVE1("CcCopyWrite: r=%d",r);\r
+       return r;\r
+}\r
+\r
+typedef\r
+VOID (*PCC_POST_DEFERRED_WRITE) (\r
+    IN PVOID Context1,\r
+    IN PVOID Context2\r
+    );\r
+VOID\r
+CcDeferWrite (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PCC_POST_DEFERRED_WRITE PostRoutine,\r
+    IN PVOID Context1,\r
+    IN PVOID Context2,\r
+    IN ULONG BytesToWrite,\r
+    IN BOOLEAN Retrying\r
+    );\r
+TcDeferWrite (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PCC_POST_DEFERRED_WRITE PostRoutine,\r
+    IN PVOID Context1,\r
+    IN PVOID Context2,\r
+    IN ULONG BytesToWrite,\r
+    IN BOOLEAN Retrying\r
+    )\r
+{\r
+       DBGSINGLEENTER6("CcDeferWrite: FileObject=0x%lX,PostRoutine=0x%lX,Context1=0x%lX,Context2=0x%lX,"\r
+                                       "BytesToWrite=0x%lX,Retrying=%d",\r
+                       (long)FileObject,(long)PostRoutine,(long)Context1,(long)Context2,\r
+                                       BytesToWrite,Retrying);\r
+       CcDeferWrite (\r
+FileObject,\r
+PostRoutine,\r
+Context1,\r
+Context2,\r
+BytesToWrite,\r
+Retrying\r
+    );\r
+       DBGSINGLELEAVE0("CcDeferWrite");\r
+}\r
+\r
+VOID\r
+CcFastCopyRead (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN ULONG FileOffset,\r
+    IN ULONG Length,\r
+    IN ULONG PageCount,\r
+    OUT PVOID Buffer,\r
+    OUT PIO_STATUS_BLOCK IoStatus\r
+    );\r
+VOID\r
+TcFastCopyRead (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN ULONG FileOffset,\r
+    IN ULONG Length,\r
+    IN ULONG PageCount,\r
+    OUT PVOID Buffer,\r
+    OUT PIO_STATUS_BLOCK IoStatus\r
+    )\r
+{\r
+       DBGSINGLEENTER5("CcFastCopyRead: FileObject=0x%lX,FileOffset=0x%lX,Length=0x%lX,PageCount=0x%lX,Buffer=0x%lX",\r
+                       (long)FileObject,FileOffset,Length,PageCount,(long)Buffer);\r
+       CcFastCopyRead (\r
+FileObject,\r
+FileOffset,\r
+Length,\r
+PageCount,\r
+Buffer,\r
+IoStatus\r
+    );\r
+       DBGSINGLELEAVE2("CcFastCopyRead: IoStatus->Status=0x%lX,IoStatus->Information=0x%lX",\r
+                       (!IoStatus ? -1 : (long)IoStatus->Status),(!IoStatus ? -1 : (long)IoStatus->Information));\r
+}\r
+\r
+VOID\r
+CcFastCopyWrite (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN ULONG FileOffset,\r
+    IN ULONG Length,\r
+    IN PVOID Buffer\r
+    );\r
+VOID\r
+TcFastCopyWrite (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN ULONG FileOffset,\r
+    IN ULONG Length,\r
+    IN PVOID Buffer\r
+    )\r
+{\r
+       DBGSINGLEENTER4("CcFastCopyWrite: FileObject=0x%lX,FileOffset=0x%lX,Length=0x%lX,Buffer=0x%lX",\r
+                       (long)FileObject,FileOffset,Length,(long)Buffer);\r
+       CcFastCopyWrite (\r
+FileObject,\r
+FileOffset,\r
+Length,\r
+Buffer\r
+    );\r
+       DBGSINGLELEAVE0("CcFastCopyWrite");\r
+}\r
+\r
+VOID\r
+CcFlushCache (\r
+    IN PSECTION_OBJECT_POINTERS SectionObjectPointer,\r
+    IN PLARGE_INTEGER FileOffset OPTIONAL,\r
+    IN ULONG Length,\r
+    OUT PIO_STATUS_BLOCK IoStatus OPTIONAL\r
+    );\r
+VOID\r
+TcFlushCache (\r
+    IN PSECTION_OBJECT_POINTERS SectionObjectPointer,\r
+    IN PLARGE_INTEGER FileOffset OPTIONAL,\r
+    IN ULONG Length,\r
+    OUT PIO_STATUS_BLOCK IoStatus OPTIONAL\r
+    )\r
+{\r
+       DBGSINGLEENTER4("CcFlushCache: SectionObjectPointer=0x%lX,->SharedCacheMap=0x%lX,FileOffset=0x%lX,Length=0x%lX",\r
+                               (long)SectionObjectPointer,\r
+                               (!SectionObjectPointer ? -1 : (long)SectionObjectPointer->SharedCacheMap),\r
+                               (!FileOffset ? -1 : (long)FileOffset->QuadPart),Length);\r
+       CcFlushCache (\r
+SectionObjectPointer,\r
+FileOffset,\r
+Length,\r
+IoStatus\r
+    );\r
+       DBGSINGLELEAVE2("CcFlushCache: IoStatus->Status=0x%lX,IoStatus->Information=0x%lX",\r
+                       (!IoStatus ? -1 : (long)IoStatus->Status),(!IoStatus ? -1 : (long)IoStatus->Information));\r
+}\r
+\r
+typedef\r
+VOID (*PDIRTY_PAGE_ROUTINE) (\r
+            IN PFILE_OBJECT FileObject,\r
+            IN PLARGE_INTEGER FileOffset,\r
+            IN ULONG Length,\r
+            IN PLARGE_INTEGER OldestLsn,\r
+            IN PLARGE_INTEGER NewestLsn,\r
+            IN PVOID Context1,\r
+            IN PVOID Context2\r
+            );\r
+\r
+static PDIRTY_PAGE_ROUTINE TcGetDirtyPages_DirtyPageRoutine_orig;\r
+static BOOLEAN TcGetDirtyPages_DirtyPageRoutine_used=FALSE;\r
+\r
+static VOID TcGetDirtyPages_DirtyPageRoutine(IN PFILE_OBJECT FileObject,IN PLARGE_INTEGER FileOffset,IN ULONG Length,\r
+               IN PLARGE_INTEGER OldestLsn,IN PLARGE_INTEGER NewestLsn,IN PVOID Context1,IN PVOID Context2)\r
+{\r
+       DBGSINGLEENTER5("DirtyPageRoutine: FileObject=0x%lX,FileOffset=0x%lX,Length=0x%lX,"\r
+                                       "OldestLsn=0x%lX,NewestLsn=0x%lX,Context1,Context2",\r
+                       (long)FileObject,(!FileOffset ? -1 : (long)FileOffset->QuadPart),Length,\r
+                       (!OldestLsn ? -1 : (long)OldestLsn->QuadPart),(!NewestLsn ? -1 : (long)NewestLsn->QuadPart));\r
+       (*TcGetDirtyPages_DirtyPageRoutine_orig)(FileObject,FileOffset,Length,OldestLsn,NewestLsn,Context1,Context2);\r
+       DBGSINGLELEAVE0("DirtyPageRoutine");\r
+}\r
+\r
+LARGE_INTEGER\r
+CcGetDirtyPages (\r
+    IN PVOID LogHandle,\r
+    IN PDIRTY_PAGE_ROUTINE DirtyPageRoutine,\r
+    IN PVOID Context1,\r
+    IN PVOID Context2\r
+    );\r
+LARGE_INTEGER\r
+TcGetDirtyPages (\r
+    IN PVOID LogHandle,\r
+    IN PDIRTY_PAGE_ROUTINE DirtyPageRoutine,\r
+    IN PVOID Context1,\r
+    IN PVOID Context2\r
+    )\r
+{\r
+LARGE_INTEGER r;\r
+\r
+       DBGSINGLEENTER4("CcGetDirtyPages: LogHandle=0x%lX,DirtyPageRoutine=0x%lX,Context1=0x%lX,Context2=0x%lX",\r
+                       (long)LogHandle,(long)DirtyPageRoutine,(long)Context1,(long)Context2);\r
+       if (TcGetDirtyPages_DirtyPageRoutine_used)\r
+               DBGSINGLE0("CcGetDirtyPages: ERROR: TcGetDirtyPages_DirtyPageRoutine_used");\r
+       else {\r
+               TcGetDirtyPages_DirtyPageRoutine_used=TRUE;\r
+               TcGetDirtyPages_DirtyPageRoutine_orig=DirtyPageRoutine;\r
+               DirtyPageRoutine=TcGetDirtyPages_DirtyPageRoutine;\r
+               }\r
+       r=CcGetDirtyPages (\r
+LogHandle,\r
+DirtyPageRoutine,\r
+Context1,\r
+Context2\r
+    );\r
+       if (DirtyPageRoutine==TcGetDirtyPages_DirtyPageRoutine)\r
+               TcGetDirtyPages_DirtyPageRoutine_used=FALSE;\r
+       DBGSINGLELEAVE1("CcGetDirtyPages: r=0x%lX",(long)r.QuadPart);\r
+       return r;\r
+}\r
+\r
+typedef BOOLEAN (*PACQUIRE_FOR_LAZY_WRITE)(IN PVOID Context,IN BOOLEAN Wait);\r
+typedef VOID (*PRELEASE_FROM_LAZY_WRITE)(IN PVOID Context);\r
+typedef BOOLEAN (*PACQUIRE_FOR_READ_AHEAD)(IN PVOID Context,IN BOOLEAN Wait);\r
+typedef VOID (*PRELEASE_FROM_READ_AHEAD)(IN PVOID Context);\r
+typedef struct _CACHE_MANAGER_CALLBACKS {\r
+               PACQUIRE_FOR_LAZY_WRITE AcquireForLazyWrite;\r
+               PRELEASE_FROM_LAZY_WRITE ReleaseFromLazyWrite;\r
+               PACQUIRE_FOR_READ_AHEAD AcquireForReadAhead;\r
+               PRELEASE_FROM_READ_AHEAD ReleaseFromReadAhead;\r
+               } CACHE_MANAGER_CALLBACKS,*PCACHE_MANAGER_CALLBACKS;\r
+\r
+static struct Callbacks {\r
+       FILE_OBJECT *FileObject;\r
+       CACHE_MANAGER_CALLBACKS Callbacks;\r
+       PVOID LazyWriteContext;\r
+       } Callbacks_cache[CACHE_SIZE];\r
+static int Callbacks_cache_used=0;\r
+\r
+static struct Callbacks *Callbacks_set(FILE_OBJECT *FileObject,CACHE_MANAGER_CALLBACKS *Callbacks,PVOID LazyWriteContext)\r
+{\r
+struct Callbacks *callbacksp;\r
+\r
+       for (callbacksp=Callbacks_cache;callbacksp<Callbacks_cache+Callbacks_cache_used;callbacksp++) {\r
+               if (callbacksp->FileObject==FileObject)\r
+                       break;\r
+               }\r
+       if (callbacksp>=Callbacks_cache+G_N_ELEMENTS(Callbacks_cache))\r
+               return NULL;\r
+       if (callbacksp==Callbacks_cache+Callbacks_cache_used)\r
+               Callbacks_cache_used++;\r
+       callbacksp->FileObject=FileObject;\r
+       callbacksp->Callbacks=*Callbacks;\r
+       callbacksp->LazyWriteContext=LazyWriteContext;\r
+       return callbacksp;\r
+}\r
+\r
+static BOOLEAN TcInitializeCacheMap_AcquireForLazyWrite(IN PVOID Context,IN BOOLEAN Wait)\r
+{\r
+struct Callbacks *callbacksp=Context;\r
+BOOLEAN r;\r
+\r
+       DBGSINGLEENTER3("AcquireForLazyWrite: FileObject=0x%lX,Context=0x%lX,Wait=%d",\r
+                       (long)callbacksp->FileObject,(long)callbacksp->LazyWriteContext,Wait);\r
+       r=(*callbacksp->Callbacks.AcquireForLazyWrite)(callbacksp->LazyWriteContext,Wait);\r
+       DBGSINGLELEAVE1("AcquireForLazyWrite: r=%d",r);\r
+       return r;\r
+}\r
+\r
+static VOID TcInitializeCacheMap_ReleaseFromLazyWrite(IN PVOID Context)\r
+{\r
+struct Callbacks *callbacksp=Context;\r
+\r
+       DBGSINGLEENTER2("ReleaseFromLazyWrite: FileObject=0x%lX,Context=0x%lX",\r
+                       (long)callbacksp->FileObject,(long)callbacksp->LazyWriteContext);\r
+       (*callbacksp->Callbacks.ReleaseFromLazyWrite)(callbacksp->LazyWriteContext);\r
+       DBGSINGLELEAVE0("ReleaseFromLazyWrite");\r
+}\r
+\r
+static BOOLEAN TcInitializeCacheMap_AcquireForReadAhead(IN PVOID Context,IN BOOLEAN Wait)\r
+{\r
+struct Callbacks *callbacksp=Context;\r
+BOOLEAN r;\r
+\r
+       DBGSINGLEENTER3("AcquireForReadAhead: FileObject=0x%lX,Context=0x%lX,Wait=%d",\r
+                       (long)callbacksp->FileObject,(long)callbacksp->LazyWriteContext,Wait);\r
+       r=(*callbacksp->Callbacks.AcquireForReadAhead)(callbacksp->LazyWriteContext,Wait);\r
+       DBGSINGLELEAVE1("AcquireForReadAhead: r=%d",r);\r
+       return r;\r
+}\r
+\r
+static VOID TcInitializeCacheMap_ReleaseFromReadAhead(IN PVOID Context)\r
+{\r
+struct Callbacks *callbacksp=Context;\r
+\r
+       DBGSINGLEENTER2("ReleaseFromReadAhead: FileObject=0x%lX,Context=0x%lX",\r
+                       (long)callbacksp->FileObject,(long)callbacksp->LazyWriteContext);\r
+       (*callbacksp->Callbacks.ReleaseFromReadAhead)(callbacksp->LazyWriteContext);\r
+       DBGSINGLELEAVE0("ReleaseFromReadAhead");\r
+}\r
+\r
+static CACHE_MANAGER_CALLBACKS TcInitializeCacheMap_Callbacks={\r
+               TcInitializeCacheMap_AcquireForLazyWrite,\r
+               TcInitializeCacheMap_ReleaseFromLazyWrite,\r
+               TcInitializeCacheMap_AcquireForReadAhead,\r
+               TcInitializeCacheMap_ReleaseFromReadAhead,\r
+               };\r
+\r
+typedef struct _CC_FILE_SIZES {\r
+               LARGE_INTEGER AllocationSize;\r
+               LARGE_INTEGER FileSize;\r
+               LARGE_INTEGER ValidDataLength;\r
+               } CC_FILE_SIZES,*PCC_FILE_SIZES;\r
+\r
+VOID\r
+CcInitializeCacheMap (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PCC_FILE_SIZES FileSizes,\r
+    IN BOOLEAN PinAccess,\r
+    IN PCACHE_MANAGER_CALLBACKS Callbacks,\r
+    IN PVOID LazyWriteContext\r
+    );\r
+VOID\r
+TcInitializeCacheMap (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PCC_FILE_SIZES FileSizes,\r
+    IN BOOLEAN PinAccess,\r
+    IN PCACHE_MANAGER_CALLBACKS Callbacks,\r
+    IN PVOID LazyWriteContext\r
+    )\r
+{\r
+struct Callbacks *callbacksp;\r
+\r
+       DBGSINGLEENTER5("CcInitializeCacheMap: FileObject=0x%lX,"\r
+                                       "FileSizes,->AllocationSize=0x%lX,->FileSize=0x%lX,->ValidDataLength=0x%lX,"\r
+                                       "PinAccess=%d,Callbacks,LazyWriteContext",\r
+                       (long)FileObject,\r
+                                       (!FileSizes ? -1 : (long)FileSizes->AllocationSize.QuadPart),\r
+                                       (!FileSizes ? -1 : (long)FileSizes->FileSize.QuadPart),\r
+                                       (!FileSizes ? -1 : (long)FileSizes->ValidDataLength.QuadPart),\r
+                                       PinAccess);\r
+       if ((callbacksp=Callbacks_set(FileObject,Callbacks,LazyWriteContext))) {\r
+               Callbacks=&TcInitializeCacheMap_Callbacks;\r
+               LazyWriteContext=callbacksp;\r
+               if (Callbacks->AcquireForLazyWrite !=TcInitializeCacheMap_AcquireForLazyWrite)\r
+                       DBGSINGLE1("CcInitializeCacheMap: ERROR: AcquireForLazyWrite =0x%lX",Callbacks->AcquireForLazyWrite);\r
+               if (Callbacks->ReleaseFromLazyWrite!=TcInitializeCacheMap_ReleaseFromLazyWrite)\r
+                       DBGSINGLE1("CcInitializeCacheMap: ERROR: ReleaseFromLazyWrite=0x%lX",Callbacks->ReleaseFromLazyWrite);\r
+               if (Callbacks->AcquireForReadAhead !=TcInitializeCacheMap_AcquireForReadAhead)\r
+                       DBGSINGLE1("CcInitializeCacheMap: ERROR: AcquireForReadAhead =0x%lX",Callbacks->AcquireForReadAhead);\r
+               if (Callbacks->ReleaseFromReadAhead!=TcInitializeCacheMap_ReleaseFromReadAhead)\r
+                       DBGSINGLE1("CcInitializeCacheMap: ERROR: ReleaseFromReadAhead=0x%lX",Callbacks->ReleaseFromReadAhead);\r
+               }\r
+       CcInitializeCacheMap (\r
+FileObject,\r
+FileSizes,\r
+PinAccess,\r
+Callbacks,\r
+LazyWriteContext\r
+    );\r
+       DBGSINGLELEAVE0("CcInitializeCacheMap");\r
+}\r
+\r
+BOOLEAN\r
+CcMapData (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PLARGE_INTEGER FileOffset,\r
+    IN ULONG Length,\r
+    IN ULONG Flags,\r
+    OUT PVOID *Bcb,\r
+    OUT PVOID *Buffer\r
+    );\r
+BOOLEAN\r
+TcMapData (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PLARGE_INTEGER FileOffset,\r
+    IN ULONG Length,\r
+    IN ULONG Flags,\r
+    OUT PVOID *Bcb,\r
+    OUT PVOID *Buffer\r
+    )\r
+{\r
+BOOLEAN r;\r
+\r
+       DBGSINGLEENTER4("CcMapData: FileObject=0x%lX,FileOffset=0x%lX,Length=0x%lX,Flags=0x%lX",\r
+                       (long)FileObject,(!FileOffset ? -1 : (long)FileOffset->QuadPart),Length,Flags);\r
+       r=CcMapData (\r
+FileObject,\r
+FileOffset,\r
+Length,\r
+Flags,\r
+Bcb,\r
+Buffer\r
+    );\r
+       DBGSINGLELEAVE3("CcMapData: r=%d,Bcb=0x%lX,Buffer=0x%lX",\r
+                       r,(!Bcb ? -1 : (long)*Bcb),(!Buffer ? -1 : (long)*Buffer));\r
+       return r;\r
+}\r
+\r
+VOID\r
+CcMdlRead (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PLARGE_INTEGER FileOffset,\r
+    IN ULONG Length,\r
+    OUT PMDL *MdlChain,\r
+    OUT PIO_STATUS_BLOCK IoStatus\r
+    );\r
+VOID\r
+TcMdlRead (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PLARGE_INTEGER FileOffset,\r
+    IN ULONG Length,\r
+    OUT PMDL *MdlChain,\r
+    OUT PIO_STATUS_BLOCK IoStatus\r
+    )\r
+{\r
+       DBGSINGLEENTER3("CcMdlRead: FileObject=0x%lX,FileOffset=0x%lX,Length=0x%lX",\r
+                       (long)FileObject,(!FileOffset ? -1 : (long)FileOffset->QuadPart),Length);\r
+       CcMdlRead (\r
+FileObject,\r
+FileOffset,\r
+Length,\r
+MdlChain,\r
+IoStatus\r
+    );\r
+       DBGSINGLELEAVE3("CcMdlRead: MdlChain=0x%lX,IoStatus->Status=0x%lX,IoStatus->Information=0x%lX",\r
+                       (!MdlChain ? -1 : (long)*MdlChain),\r
+                       (!IoStatus ? -1 : (long)IoStatus->Status),(!IoStatus ? -1 : (long)IoStatus->Information));\r
+}\r
+\r
+VOID\r
+CcMdlReadComplete (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PMDL MdlChain\r
+    );\r
+VOID\r
+TcMdlReadComplete (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PMDL MdlChain\r
+    )\r
+{\r
+       DBGSINGLEENTER2("CcMdlReadComplete: FileObject=0x%lX,MdlChain=0x%lX",\r
+                       (long)FileObject,(long)MdlChain);\r
+       CcMdlReadComplete (\r
+FileObject,\r
+MdlChain\r
+    );\r
+       DBGSINGLELEAVE0("CcMdlReadComplete");\r
+}\r
+\r
+VOID\r
+CcMdlWriteAbort (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PMDL MdlChain\r
+    );\r
+VOID\r
+TcMdlWriteAbort (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PMDL MdlChain\r
+    )\r
+{\r
+       DBGSINGLEENTER2("CcMdlWriteAbort: FileObject=0x%lX,MdlChain=0x%lX",\r
+                       (long)FileObject,(long)MdlChain);\r
+       CcMdlWriteAbort (\r
+FileObject,\r
+MdlChain\r
+    );\r
+       DBGSINGLELEAVE0("CcMdlWriteAbort");\r
+}\r
+\r
+VOID\r
+CcMdlWriteComplete (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PLARGE_INTEGER FileOffset,\r
+    IN PMDL MdlChain\r
+    );\r
+VOID\r
+TcMdlWriteComplete (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PLARGE_INTEGER FileOffset,\r
+    IN PMDL MdlChain\r
+    )\r
+{\r
+       DBGSINGLEENTER3("CcMdlWriteComplete: FileObject=0x%lX,FileOffset=0x%lX,MdlChain=0x%lX",\r
+                       (long)FileObject,(!FileOffset ? -1 : (long)FileOffset->QuadPart),(long)MdlChain);\r
+       CcMdlWriteComplete (\r
+FileObject,\r
+FileOffset,\r
+MdlChain\r
+    );\r
+       DBGSINGLELEAVE0("CcMdlWriteComplete");\r
+}\r
+\r
+BOOLEAN\r
+CcPinMappedData (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PLARGE_INTEGER FileOffset,\r
+    IN ULONG Length,\r
+    IN ULONG Flags,\r
+    IN OUT PVOID *Bcb\r
+    );\r
+BOOLEAN\r
+TcPinMappedData (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PLARGE_INTEGER FileOffset,\r
+    IN ULONG Length,\r
+    IN ULONG Flags,\r
+    IN OUT PVOID *Bcb\r
+    )\r
+{\r
+BOOLEAN r;\r
+\r
+       DBGSINGLEENTER4("CcPinMappedData: FileObject=0x%lX,FileOffset=0x%lX,Length=0x%lX,Flags=0x%lX",\r
+                       (long)FileObject,(!FileOffset ? -1 : (long)FileOffset->QuadPart),Length,Flags);\r
+       r=CcPinMappedData (\r
+FileObject,\r
+FileOffset,\r
+Length,\r
+Flags,\r
+Bcb\r
+    );\r
+       DBGSINGLELEAVE2("CcPinMappedData: r=%d,Bcb=0x%lX",\r
+                       r,(!Bcb ? -1 : (long)*Bcb));\r
+       return r;\r
+}\r
+\r
+BOOLEAN\r
+CcPinRead (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PLARGE_INTEGER FileOffset,\r
+    IN ULONG Length,\r
+    IN ULONG Flags,\r
+    OUT PVOID *Bcb,\r
+    OUT PVOID *Buffer\r
+    );\r
+BOOLEAN\r
+TcPinRead (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PLARGE_INTEGER FileOffset,\r
+    IN ULONG Length,\r
+    IN ULONG Flags,\r
+    OUT PVOID *Bcb,\r
+    OUT PVOID *Buffer\r
+    )\r
+{\r
+BOOLEAN r;\r
+\r
+       DBGSINGLEENTER4("CcPinRead: FileObject=0x%lX,FileOffset=0x%lX,Length=0x%lX,Flags=0x%lX",\r
+                       (long)FileObject,(!FileOffset ? -1 : (long)FileOffset->QuadPart),Length,Flags);\r
+       r=CcPinRead (\r
+FileObject,\r
+FileOffset,\r
+Length,\r
+Flags,\r
+Bcb,\r
+Buffer\r
+    );\r
+       DBGSINGLELEAVE3("CcPinRead: r=%d,Bcb=0x%lX,Buffer=0x%lX",\r
+                       r,(!Bcb ? -1 : (long)*Bcb),(!Buffer ? -1 : (long)*Buffer));\r
+       return r;\r
+}\r
+\r
+VOID\r
+CcPrepareMdlWrite (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PLARGE_INTEGER FileOffset,\r
+    IN ULONG Length,\r
+    OUT PMDL *MdlChain,\r
+    OUT PIO_STATUS_BLOCK IoStatus\r
+    );\r
+VOID\r
+TcPrepareMdlWrite (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PLARGE_INTEGER FileOffset,\r
+    IN ULONG Length,\r
+    OUT PMDL *MdlChain,\r
+    OUT PIO_STATUS_BLOCK IoStatus\r
+    )\r
+{\r
+       DBGSINGLEENTER3("CcPrepareMdlWrite: FileObject=0x%lX,FileOffset=0x%lX,Length=0x%lX",\r
+                       (long)FileObject,(!FileOffset ? -1 : (long)FileOffset->QuadPart),Length);\r
+       CcPrepareMdlWrite (\r
+FileObject,\r
+FileOffset,\r
+Length,\r
+MdlChain,\r
+IoStatus\r
+    );\r
+       DBGSINGLELEAVE3("CcPrepareMdlWrite: MdlChain=0x%lX,IoStatus->Status=0x%lX,IoStatus->Information=0x%lX",\r
+                       (!MdlChain ? -1 : (long)*MdlChain),\r
+                       (!IoStatus ? -1 : (long)IoStatus->Status),(!IoStatus ? -1 : (long)IoStatus->Information));\r
+}\r
+\r
+BOOLEAN\r
+CcPreparePinWrite (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PLARGE_INTEGER FileOffset,\r
+    IN ULONG Length,\r
+    IN BOOLEAN Zero,\r
+    IN ULONG Flags,\r
+    OUT PVOID *Bcb,\r
+    OUT PVOID *Buffer\r
+    );\r
+BOOLEAN\r
+TcPreparePinWrite (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PLARGE_INTEGER FileOffset,\r
+    IN ULONG Length,\r
+    IN BOOLEAN Zero,\r
+    IN ULONG Flags,\r
+    OUT PVOID *Bcb,\r
+    OUT PVOID *Buffer\r
+    )\r
+{\r
+BOOLEAN r;\r
+\r
+       DBGSINGLEENTER5("CcPreparePinWrite: FileObject=0x%lX,FileOffset=0x%lX,Length=0x%lX,Zero=%d,Flags=0x%lX",\r
+                       (long)FileObject,(!FileOffset ? -1 : (long)FileOffset->QuadPart),Length,Zero,Flags);\r
+       r=CcPreparePinWrite (\r
+FileObject,\r
+FileOffset,\r
+Length,\r
+Zero,\r
+Flags,\r
+Bcb,\r
+Buffer\r
+    );\r
+       DBGSINGLELEAVE3("CcPreparePinWrite: r=%d,Bcb=0x%lX,Buffer=0x%lX",\r
+                       r,(!Bcb ? -1 : (long)*Bcb),(!Buffer ? -1 : (long)*Buffer));\r
+       return r;\r
+}\r
+\r
+BOOLEAN\r
+CcPurgeCacheSection (\r
+    IN PSECTION_OBJECT_POINTERS SectionObjectPointer,\r
+    IN PLARGE_INTEGER FileOffset OPTIONAL,\r
+    IN ULONG Length,\r
+    IN BOOLEAN UninitializeCacheMaps\r
+    );\r
+BOOLEAN\r
+TcPurgeCacheSection (\r
+    IN PSECTION_OBJECT_POINTERS SectionObjectPointer,\r
+    IN PLARGE_INTEGER FileOffset OPTIONAL,\r
+    IN ULONG Length,\r
+    IN BOOLEAN UninitializeCacheMaps\r
+    )\r
+{\r
+BOOLEAN r;\r
+\r
+       DBGSINGLEENTER5("CcPurgeCacheSection: SectionObjectPointer=0x%lX,->SharedCacheMap=0x%lX,FileOffset=0x%lX,Length=0x%lX,"\r
+                                               "UninitializeCacheMaps=%d",\r
+                               (long)SectionObjectPointer,\r
+                               (!SectionObjectPointer ? -1 : (long)SectionObjectPointer->SharedCacheMap),\r
+                               (!FileOffset ? -1 : (long)FileOffset->QuadPart),Length,\r
+                                               UninitializeCacheMaps);\r
+       r=CcPurgeCacheSection (\r
+SectionObjectPointer,\r
+FileOffset,\r
+Length,\r
+UninitializeCacheMaps\r
+    );\r
+       DBGSINGLELEAVE1("CcPurgeCacheSection: r=%d",r);\r
+       return r;\r
+}\r
+\r
+PVOID\r
+CcRemapBcb (\r
+    IN PVOID Bcb\r
+    );\r
+PVOID\r
+TcRemapBcb (\r
+    IN PVOID Bcb\r
+    )\r
+{\r
+PVOID r;\r
+\r
+       DBGSINGLEENTER1("CcRemapBcb: Bcb=0x%lX",(long)Bcb);\r
+       r=CcRemapBcb (\r
+Bcb\r
+    );\r
+       DBGSINGLELEAVE1("CcRemapBcb: r=0x%lX",(long)r);\r
+       return r;\r
+}\r
+\r
+VOID\r
+CcSetAdditionalCacheAttributes (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN BOOLEAN DisableReadAhead,\r
+    IN BOOLEAN DisableWriteBehind\r
+    );\r
+VOID\r
+TcSetAdditionalCacheAttributes (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN BOOLEAN DisableReadAhead,\r
+    IN BOOLEAN DisableWriteBehind\r
+    )\r
+{\r
+       DBGSINGLEENTER3("CcSetAdditionalCacheAttributes: FileObject=0x%lX,DisableReadAhead=%d,DisableWriteBehind=%d",\r
+                       (long)FileObject,DisableReadAhead,DisableWriteBehind);\r
+       CcSetAdditionalCacheAttributes (\r
+FileObject,\r
+DisableReadAhead,\r
+DisableWriteBehind\r
+    );\r
+       DBGSINGLELEAVE0("CcSetAdditionalCacheAttributes");\r
+}\r
+\r
+VOID\r
+CcSetBcbOwnerPointer (\r
+    IN PVOID Bcb,\r
+    IN PVOID OwnerPointer\r
+    );\r
+VOID\r
+TcSetBcbOwnerPointer (\r
+    IN PVOID Bcb,\r
+    IN PVOID OwnerPointer\r
+    )\r
+{\r
+       DBGSINGLEENTER2("CcSetBcbOwnerPointer: Bcb=0x%lX,OwnerPointer=0x%lX",\r
+                       (long)Bcb,(long)OwnerPointer);\r
+       CcSetBcbOwnerPointer (\r
+Bcb,\r
+OwnerPointer\r
+    );\r
+       DBGSINGLELEAVE0("CcSetBcbOwnerPointer");\r
+}\r
+\r
+VOID\r
+CcSetDirtyPinnedData (\r
+    IN PVOID BcbVoid,\r
+    IN PLARGE_INTEGER Lsn OPTIONAL\r
+    );\r
+VOID\r
+TcSetDirtyPinnedData (\r
+    IN PVOID BcbVoid,\r
+    IN PLARGE_INTEGER Lsn OPTIONAL\r
+    )\r
+{\r
+       DBGSINGLEENTER2("CcSetDirtyPinnedData: BcbVoid=0x%lX,Lsn=0x%lX",\r
+                       (long)BcbVoid,(!Lsn ? -1 : (long)Lsn->QuadPart));\r
+       CcSetDirtyPinnedData (\r
+BcbVoid,\r
+Lsn\r
+    );\r
+       DBGSINGLELEAVE0("CcSetDirtyPinnedData");\r
+}\r
+\r
+VOID\r
+CcSetFileSizes (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PCC_FILE_SIZES FileSizes\r
+    );\r
+VOID\r
+TcSetFileSizes (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PCC_FILE_SIZES FileSizes\r
+    )\r
+{\r
+       DBGSINGLEENTER4("CcSetFileSizes: FileObject=0x%lX,"\r
+                                       "FileSizes,->AllocationSize=0x%lX,->FileSize=0x%lX,->ValidDataLength=0x%lX",\r
+                       (long)FileObject,\r
+                                       (!FileSizes ? -1 : (long)FileSizes->AllocationSize.QuadPart),\r
+                                       (!FileSizes ? -1 : (long)FileSizes->FileSize.QuadPart),\r
+                                       (!FileSizes ? -1 : (long)FileSizes->ValidDataLength.QuadPart));\r
+       CcSetFileSizes (\r
+FileObject,\r
+FileSizes\r
+    );\r
+       DBGSINGLELEAVE0("CcSetFileSizes");\r
+}\r
+\r
+typedef VOID (*PFLUSH_TO_LSN)(IN PVOID LogHandle,IN LARGE_INTEGER Lsn);\r
+\r
+static struct LogHandle {\r
+       PVOID LogHandle;\r
+       PFLUSH_TO_LSN FlushToLsnRoutine;\r
+       } LogHandle_cache[CACHE_SIZE];\r
+static int LogHandle_cache_used=0;\r
+\r
+static BOOLEAN LogHandle_set(PVOID LogHandle,PFLUSH_TO_LSN FlushToLsnRoutine)\r
+{\r
+struct LogHandle *loghandlep;\r
+\r
+       for (loghandlep=LogHandle_cache;loghandlep<LogHandle_cache+LogHandle_cache_used;loghandlep++) {\r
+               if (loghandlep->LogHandle==LogHandle)\r
+                       break;\r
+               }\r
+       if (loghandlep>=LogHandle_cache+G_N_ELEMENTS(LogHandle_cache))\r
+               return FALSE;\r
+       if (loghandlep==LogHandle_cache+LogHandle_cache_used)\r
+               LogHandle_cache_used++;\r
+       loghandlep->LogHandle=LogHandle;\r
+       loghandlep->FlushToLsnRoutine=FlushToLsnRoutine;\r
+       return TRUE;\r
+}\r
+\r
+static PFLUSH_TO_LSN LogHandle_find(PVOID LogHandle)\r
+{\r
+struct LogHandle *loghandlep;\r
+\r
+       for (loghandlep=LogHandle_cache;loghandlep<LogHandle_cache+LogHandle_cache_used;loghandlep++) {\r
+               if (loghandlep->LogHandle==LogHandle)\r
+                       return loghandlep->FlushToLsnRoutine;\r
+               }\r
+       return NULL;\r
+}\r
+\r
+static VOID TcSetLogHandleForFile_FlushToLsnRoutine(IN PVOID LogHandle,IN LARGE_INTEGER Lsn)\r
+{\r
+PFLUSH_TO_LSN FlushToLsnRoutine;\r
+\r
+       DBGSINGLEENTER2("FlushToLsnRoutine: LogHandle=0x%lX,Lsn=0x%lX",\r
+                       (long)LogHandle,(long)Lsn.QuadPart);\r
+       if ((FlushToLsnRoutine=LogHandle_find(LogHandle)))\r
+               (*FlushToLsnRoutine)(LogHandle,Lsn);\r
+       DBGSINGLELEAVE0("FlushToLsnRoutine");\r
+}\r
+\r
+VOID\r
+CcSetLogHandleForFile (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PVOID LogHandle,\r
+    IN PFLUSH_TO_LSN FlushToLsnRoutine\r
+    );\r
+VOID\r
+TcSetLogHandleForFile (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PVOID LogHandle,\r
+    IN PFLUSH_TO_LSN FlushToLsnRoutine\r
+    )\r
+{\r
+       DBGSINGLEENTER3("CcSetLogHandleForFile: FileObject=0x%lX,LogHandle=0x%lX,FlushToLsnRoutine=0x%lX",\r
+                       (long)FileObject,(long)LogHandle,(long)FlushToLsnRoutine);\r
+       if (LogHandle_set(LogHandle,FlushToLsnRoutine))\r
+               FlushToLsnRoutine=TcSetLogHandleForFile_FlushToLsnRoutine;\r
+       CcSetLogHandleForFile (\r
+FileObject,\r
+LogHandle,\r
+FlushToLsnRoutine\r
+    );\r
+       DBGSINGLELEAVE0("CcSetLogHandleForFile");\r
+}\r
+\r
+VOID\r
+CcSetReadAheadGranularity (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN ULONG Granularity\r
+    );\r
+VOID\r
+TcSetReadAheadGranularity (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN ULONG Granularity\r
+    )\r
+{\r
+       DBGSINGLEENTER2("CcSetReadAheadGranularity: FileObject=0x%lX,Granularity=0x%lX",\r
+                       (long)FileObject,Granularity);\r
+       CcSetReadAheadGranularity (\r
+FileObject,\r
+Granularity\r
+    );\r
+       DBGSINGLELEAVE0("CcSetReadAheadGranularity");\r
+}\r
+\r
+typedef struct _CACHE_UNINITIALIZE_EVENT {\r
+       struct _CACHE_UNINITIALIZE_EVENT *Next;\r
+       KEVENT Event;\r
+       } CACHE_UNINITIALIZE_EVENT,*PCACHE_UNINITIALIZE_EVENT;\r
+\r
+BOOLEAN\r
+CcUninitializeCacheMap (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PLARGE_INTEGER TruncateSize OPTIONAL,\r
+    IN PCACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent OPTIONAL\r
+    );\r
+BOOLEAN\r
+TcUninitializeCacheMap (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PLARGE_INTEGER TruncateSize OPTIONAL,\r
+    IN PCACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent OPTIONAL\r
+    )\r
+{\r
+BOOLEAN r;\r
+\r
+       DBGSINGLEENTER3("CcUninitializeCacheMap: FileObject=0x%lX,TruncateSize=0x%lX,UninitializeCompleteEvent=0x%lX",\r
+                       (long)FileObject,(!TruncateSize ? -1 : (long)TruncateSize->QuadPart),(long)UninitializeCompleteEvent);\r
+       r=CcUninitializeCacheMap (\r
+FileObject,\r
+TruncateSize,\r
+UninitializeCompleteEvent\r
+    );\r
+       DBGSINGLELEAVE1("CcUninitializeCacheMap: r=%d",r);\r
+       return r;\r
+}\r
+\r
+VOID\r
+CcUnpinData (\r
+    IN PVOID Bcb\r
+    );\r
+VOID\r
+TcUnpinData (\r
+    IN PVOID Bcb\r
+    )\r
+{\r
+       DBGSINGLEENTER1("CcUnpinData: Bcb=0x%lX",(long)Bcb);\r
+       CcUnpinData (\r
+Bcb\r
+    );\r
+       DBGSINGLELEAVE0("CcUnpinData");\r
+}\r
+\r
+VOID\r
+CcUnpinDataForThread (\r
+    IN PVOID Bcb,\r
+    IN ERESOURCE_THREAD ResourceThreadId\r
+    );\r
+VOID\r
+TcUnpinDataForThread (\r
+    IN PVOID Bcb,\r
+    IN ERESOURCE_THREAD ResourceThreadId\r
+    )\r
+{\r
+       DBGSINGLEENTER2("CcUnpinDataForThread: Bcb=0x%lX,ResourceThreadId=0x%lX",\r
+                       (long)Bcb,(long)ResourceThreadId);\r
+       CcUnpinDataForThread (\r
+Bcb,\r
+ResourceThreadId\r
+    );\r
+       DBGSINGLELEAVE0("CcUnpinDataForThread");\r
+}\r
+\r
+NTSTATUS\r
+CcWaitForCurrentLazyWriterActivity (\r
+    VOID\r
+    );\r
+NTSTATUS\r
+TcWaitForCurrentLazyWriterActivity (\r
+    VOID\r
+    )\r
+{\r
+NTSTATUS r;\r
+\r
+       DBGSINGLEENTER0("CcWaitForCurrentLazyWriterActivity");\r
+       r=CcWaitForCurrentLazyWriterActivity (\r
+    );\r
+       DBGSINGLELEAVE1("CcWaitForCurrentLazyWriterActivity: r=0x%lX",r);\r
+       return r;\r
+}\r
+\r
+BOOLEAN\r
+CcZeroData (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PLARGE_INTEGER StartOffset,\r
+    IN PLARGE_INTEGER EndOffset,\r
+    IN BOOLEAN Wait\r
+    );\r
+BOOLEAN\r
+TcZeroData (\r
+    IN PFILE_OBJECT FileObject,\r
+    IN PLARGE_INTEGER StartOffset,\r
+    IN PLARGE_INTEGER EndOffset,\r
+    IN BOOLEAN Wait\r
+    )\r
+{\r
+BOOLEAN r;\r
+\r
+       DBGSINGLEENTER4("CcZeroData: FileObject=0x%lX,StartOffset=0x%lX,EndOffset=0x%lX,Wait=%d",\r
+                       (long)FileObject,\r
+                       (!StartOffset ? -1 : (long)StartOffset->QuadPart),\r
+                       (!EndOffset ? -1 : (long)EndOffset->QuadPart),\r
+                       Wait);\r
+       r=CcZeroData (\r
+FileObject,\r
+StartOffset,\r
+EndOffset,\r
+Wait\r
+    );\r
+       DBGSINGLELEAVE1("CcZeroData: r=%d",r);\r
+       return r;\r
+}\r
diff --git a/src/TraceFS/TraceFS-W32/TraceFS.def b/src/TraceFS/TraceFS-W32/TraceFS.def
new file mode 100644 (file)
index 0000000..f913323
--- /dev/null
@@ -0,0 +1,55 @@
+; $Id$\r
+; Exports definition file for W32 build of TraceFS by build.exe\r
+; Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>\r
+; \r
+; This program is free software; you can redistribute it and/or modify\r
+; it under the terms of the GNU General Public License as published by\r
+; the Free Software Foundation; exactly version 2 of June 1991 is required\r
+; \r
+; This program is distributed in the hope that it will be useful,\r
+; but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+; GNU General Public License for more details.\r
+; \r
+; You should have received a copy of the GNU General Public License\r
+; along with this program; if not, write to the Free Software\r
+; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+\r
+\r
+EXPORTS\r
+       ToRegisterFileSystem\r
+\r
+       TsCreateSystemThread\r
+       TwClose\r
+\r
+       TcCanIWrite\r
+       TcCopyRead\r
+       TcCopyWrite\r
+       TcDeferWrite\r
+       TcFastCopyRead\r
+       TcFastCopyWrite\r
+       TcFlushCache\r
+       TcGetDirtyPages\r
+       TcInitializeCacheMap\r
+       TcMapData\r
+       TcMdlRead\r
+       TcMdlReadComplete\r
+       TcMdlWriteAbort\r
+       TcMdlWriteComplete\r
+       TcPinMappedData\r
+       TcPinRead\r
+       TcPrepareMdlWrite\r
+       TcPreparePinWrite\r
+       TcPurgeCacheSection\r
+       TcRemapBcb\r
+       TcSetAdditionalCacheAttributes\r
+       TcSetBcbOwnerPointer\r
+       TcSetDirtyPinnedData\r
+       TcSetFileSizes\r
+       TcSetLogHandleForFile\r
+       TcSetReadAheadGranularity\r
+       TcUninitializeCacheMap\r
+       TcUnpinData\r
+       TcUnpinDataForThread\r
+       TcWaitForCurrentLazyWriterActivity\r
+       TcZeroData\r
diff --git a/src/TraceFS/TraceFS-W32/TraceFS.reg b/src/TraceFS/TraceFS-W32/TraceFS.reg
new file mode 100644 (file)
index 0000000..5ed5cf5
--- /dev/null
@@ -0,0 +1,28 @@
+Windows Registry Editor Version 5.00\r
+\r
+\r
+; $Id$\r
+; Registry settings to load C:\Windows\System32\Drivers\TraceFS.sys\r
+; Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>\r
+; \r
+; This program is free software; you can redistribute it and/or modify\r
+; it under the terms of the GNU General Public License as published by\r
+; the Free Software Foundation; exactly version 2 of June 1991 is required\r
+; \r
+; This program is distributed in the hope that it will be useful,\r
+; but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+; GNU General Public License for more details.\r
+; \r
+; You should have received a copy of the GNU General Public License\r
+; along with this program; if not, write to the Free Software\r
+; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+\r
+\r
+[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\TraceFS]\r
+"ErrorControl"=dword:00000001\r
+"Group"="Base"\r
+"Start"=dword:00000000\r
+"Tag"=dword:00000001\r
+"Type"=dword:00000001\r
+\r
diff --git a/src/TraceFS/TraceFS-W32/makeFile b/src/TraceFS/TraceFS-W32/makeFile
new file mode 100644 (file)
index 0000000..1bd62a8
--- /dev/null
@@ -0,0 +1,22 @@
+# $Id$
+# Stub makefile required by W32 build of TraceFS by build.exe
+# Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
+# 
+# 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 (executable)
index 0000000..6439405
--- /dev/null
@@ -0,0 +1,277 @@
+#! /usr/bin/perl
+# 
+# $Id$
+# Checks assumptions on Cc* (Cache Manager) behaviour by reading TraceFS log
+# Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
+# 
+# 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 (executable)
index 0000000..43279f3
--- /dev/null
@@ -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 <project-captive@jankratochvil.net>
+# 
+# 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));