--- /dev/null
+/* $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
--- /dev/null
+#! /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"}};
+ }
--- /dev/null
+#! /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));