Index: /trunk/kStuff/include/k/kHlpString.h
===================================================================
--- /trunk/kStuff/include/k/kHlpString.h	(revision 3545)
+++ /trunk/kStuff/include/k/kHlpString.h	(revision 3546)
@@ -28,8 +28,5 @@
 #define ___k_kHlpString_h___
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
+#if 0 /* optimize / fix this later */
 #ifdef __GNUC__
 /** memchr */
@@ -65,4 +62,5 @@
 # error "Port Me"
 #endif
+#endif /* disabled */
 
 #ifdef __cplusplus
@@ -77,5 +75,5 @@
 #endif
 #ifndef kHlpMemCopy
-void   *kHlpMemMopy(void *pv1, const void *pv2, KSIZE cb);
+void   *kHlpMemCopy(void *pv1, const void *pv2, KSIZE cb);
 #endif
 #ifndef kHlpMemMove
Index: /trunk/kStuff/include/k/kRdr.h
===================================================================
--- /trunk/kStuff/include/k/kRdr.h	(revision 3545)
+++ /trunk/kStuff/include/k/kRdr.h	(revision 3546)
@@ -31,9 +31,4 @@
 #include <k/kTypes.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
 /** @defgroup grp_kRdr      kRdr - The File Provider
  * @{ */
@@ -43,4 +38,8 @@
 /** Pointer to a file provider instance pointer. */
 typedef struct KRDR **PPKRDR;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 int     kRdrOpen(PPKRDR ppRdr, const char *pszFilename);
@@ -56,12 +55,10 @@
 KSIZE   kRdrPageSize(PKRDR pRdr);
 #ifndef ___k_kLdr___
-int     kRdrMap(     PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, unsigned fFixed);
+int     kRdrMap(     PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed);
 int     kRdrRefresh( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments);
-int     kRdrProtect( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect);
+int     kRdrProtect( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect);
 int     kRdrUnmap(   PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments);
 #endif /* !___k_kLdr___ */
 void    kRdrDone(    PKRDR pRdr);
-
-/** @} */
 
 #ifdef __cplusplus
@@ -69,4 +66,6 @@
 #endif
 
+/** @} */
+
 #endif
 
Index: /trunk/kStuff/include/k/kRdrAll.h
===================================================================
--- /trunk/kStuff/include/k/kRdrAll.h	(revision 3545)
+++ /trunk/kStuff/include/k/kRdrAll.h	(revision 3546)
@@ -67,5 +67,5 @@
     int     (* pfnDestroy)( PKRDR pRdr);
     /** @copydoc kRdrRead */
-    int     (* pfnRead)(    PKRDR pRdr, void *pvBuf, size_t cb, KFOFF off);
+    int     (* pfnRead)(    PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off);
     /** @copydoc kRdrAllMap */
     int     (* pfnAllMap)(  PKRDR pRdr, const void **ppvBits);
@@ -83,9 +83,9 @@
     KSIZE   (* pfnPageSize)(PKRDR pRdr);
     /** @copydoc kRdrMap */
-    int     (* pfnMap)(     PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, unsigned fFixed);
+    int     (* pfnMap)(     PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed);
     /** @copydoc kRdrRefresh */
     int     (* pfnRefresh)( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments);
     /** @copydoc kRdrProtect */
-    int     (* pfnProtect)( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect);
+    int     (* pfnProtect)( PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect);
     /** @copydoc kRdrUnmap */
     int     (* pfnUnmap)(   PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments);
Index: /trunk/kStuff/kRdr/Makefile.kmk
===================================================================
--- /trunk/kStuff/kRdr/Makefile.kmk	(revision 3545)
+++ /trunk/kStuff/kRdr/Makefile.kmk	(revision 3546)
@@ -36,6 +36,6 @@
 kRdrStatic_INCS = ../kLdr
 kRdrStatic_SOURCES = \
-	kRdr.c \
-	kRdrFile.c
+	kRdr.cpp \
+	kRdrFile.cpp
 
 # Generate the rules
Index: unk/kStuff/kRdr/kRdr.c
===================================================================
--- /trunk/kStuff/kRdr/kRdr.c	(revision 3545)
+++ 	(revision )
@@ -1,280 +1,0 @@
-/* $Id$ */
-/** @file
- * kRdr - The File Provider.
- */
-
-/*
- * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
- *
- * This file is part of kStuff.
- *
- * kStuff is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * kStuff 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with kStuff; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-
-/*******************************************************************************
-*   Header Files                                                               *
-*******************************************************************************/
-#include <k/kRdrAll.h>
-#include <k/kErrors.h>
-#include "kRdrInternal.h"
-
-
-/*******************************************************************************
-*   Global Variables                                                           *
-*******************************************************************************/
-/** The list of file providers. */
-static PCKRDROPS g_pRdrHead = &g_kRdrFileOps;
-
-
-/**
- * Adds a new file provider.
- *
- * @param   pAdd        The new file provider.
- */
-void kRdrAddProvider(PKRDROPS pAdd)
-{
-    pAdd->pNext = g_pRdrHead;
-    g_pRdrHead = pAdd;
-}
-
-
-/**
- * Tries to opens a file.
- *
- * @returns 0 on success, OS status code on failure.
- * @param   ppRdr           Where to store the file provider instance.
- * @param   pszFilename     The filename.
- */
-int kRdrOpen(PPKRDR ppRdr, const char *pszFilename)
-{
-    int             rc = -1;
-    PCKRDROPS    pCur;
-    for (pCur = g_pRdrHead; pCur; pCur = pCur->pNext)
-    {
-        rc = pCur->pfnCreate(ppRdr, pszFilename);
-        if (!rc)
-            return 0;
-    }
-    return rc;
-}
-
-
-/**
- * Closes the file.
- *
- * @returns 0 on success, OS specific error code on failure.
- *          On failure, the file provider instance will be in an indeterminate state - don't touch it!
- * @param   pRdr        The file provider instance.
- */
-int kRdrClose(PKRDR pRdr)
-{
-    KRDR_VALIDATE(pRdr);
-    return pRdr->pOps->pfnDestroy(pRdr);
-}
-
-
-/** Read bits from the file.
- *
- * @returns 0 on success, OS specific error code on failure.
- * @param   pRdr        The file provider instance.
- * @param   pvBuf       Where to put the bits.
- * @param   cb          The number of bytes to read.
- * @param   off         Where to start reading.
- */
-int kRdrRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off)
-{
-    KRDR_VALIDATE(pRdr);
-    return pRdr->pOps->pfnRead(pRdr, pvBuf, cb, off);
-}
-
-
-/** Map all the file bits into memory (read only).
- *
- * @returns 0 on success, OS specific error code on failure.
- * @param   pRdr        The file provider instance.
- * @param   ppvBits     Where to store the address of the mapping.
- *                      The size can be obtained using pfnSize.
- */
-int kRdrAllMap(PKRDR pRdr, const void **ppvBits)
-{
-    KRDR_VALIDATE(pRdr);
-    return pRdr->pOps->pfnAllMap(pRdr, ppvBits);
-}
-
-
-/** Unmap a file bits mapping obtained by KRDROPS::pfnAllMap.
- *
- * @returns 0 on success, OS specific error code on failure.
- * @param   pRdr        The file provider instance.
- * @param   pvBits      The mapping address.
- */
-int kRdrAllUnmap(PKRDR pRdr, const void *pvBits)
-{
-    KRDR_VALIDATE(pRdr);
-    return pRdr->pOps->pfnAllUnmap(pRdr, pvBits);
-}
-
-
-/** Get the file size.
- *
- * @returns The file size. Returns -1 on failure.
- * @param   pRdr        The file provider instance.
- */
-KFOFF kRdrSize(PKRDR pRdr)
-{
-    KRDR_VALIDATE(pRdr);
-    return pRdr->pOps->pfnSize(pRdr);
-}
-
-
-/** Get the file pointer offset.
- *
- * @returns The file pointer offset. Returns -1 on failure.
- * @param   pRdr        The file provider instance.
- */
-KFOFF kRdrTell(PKRDR pRdr)
-{
-    KRDR_VALIDATE(pRdr);
-    return pRdr->pOps->pfnTell(pRdr);
-}
-
-
-/** Get the file name.
- *
- * @returns The file name. Returns NULL on failure.
- * @param   pRdr        The file provider instance.
- */
-const char *kRdrName(PKRDR pRdr)
-{
-    KRDR_VALIDATE_EX(pRdr, NULL);
-    return pRdr->pOps->pfnName(pRdr);
-}
-
-
-/** Get the native file handle if possible.
- *
- * @returns The native file handle. Returns -1 if not available.
- * @param   pRdr        The file provider instance.
- */
-KIPTR kRdrNativeFH(PKRDR pRdr)
-{
-    KRDR_VALIDATE_EX(pRdr, -1);
-    return pRdr->pOps->pfnNativeFH(pRdr);
-}
-
-
-/**
- * Gets the page size used when mapping sections of the file.
- *
- * @returns The page size.
- * @param   pRdr        The file provider instance.
- */
-KSIZE kRdrPageSize(PKRDR pRdr)
-{
-    KRDR_VALIDATE_EX(pRdr, 0x10000);
-    return pRdr->pOps->pfnPageSize(pRdr);
-}
-
-
-/**
- * Maps the segments of a image into memory.
- *
- * The file reader will be using the RVA member of each segment to figure out where
- * it goes relative to the image base address.
- *
- * @returns 0 on success, OS specific error code on failure.
- * @param   pRdr        The file provider instance.
- * @param   ppvBase     On input when fFixed is set, this contains the base address of the mapping.
- *                      On output this contains the base of the image mapping.
- * @param   cSegments   The number of segments in the array pointed to by paSegments.
- * @param   paSegments  The segments thats going to be mapped.
- * @param   fFixed      If set, the address at *ppvBase should be the base address of the mapping.
- */
-int kRdrMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, unsigned fFixed)
-{
-    KRDR_VALIDATE(pRdr);
-    return pRdr->pOps->pfnMap(pRdr, ppvBase, cSegments, paSegments, fFixed);
-}
-
-
-/**
- * Reloads dirty pages in mapped image.
- *
- * @returns 0 on success, OS specific error code on failure.
- * @param   pRdr        The file provider instance.
- * @param   pvBase      The base address of the image mapping.
- * @param   cSegments   The number of segments in the array pointed to by paSegments.
- * @param   paSegments  The segments thats going to be mapped.
- */
-int kRdrRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments)
-{
-    KRDR_VALIDATE(pRdr);
-    return pRdr->pOps->pfnRefresh(pRdr, pvBase, cSegments, paSegments);
-}
-
-
-/**
- * Protects or unprotects an image mapping.
- *
- * This is typically used for getting write access to read or execute only
- * pages while applying fixups.
- *
- * @returns 0 on success, OS specific error code on failure.
- * @param   pRdr        The file provider instance.
- * @param   pvBase      The base address of the image mapping.
- * @param   cSegments   The number of segments in the array pointed to by paSegments.
- * @param   paSegments  The segments thats going to be mapped.
- * @param   fUnprotectOrProtect     When set the all mapped segments are made writable.
- *                                  When clean the segment protection is restored.
- */
-int kRdrProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect)
-{
-    KRDR_VALIDATE(pRdr);
-    return pRdr->pOps->pfnProtect(pRdr, pvBase, cSegments, paSegments, fUnprotectOrProtect);
-}
-
-
-/**
- * Unmaps a image mapping.
- *
- * @returns 0 on success, OS specific error code on failure.
- * @param   pRdr        The file provider instance.
- * @param   pvBase      The base address of the image mapping.
- * @param   cSegments   The number of segments in the array pointed to by paSegments.
- * @param   paSegments  The segments thats going to be mapped.
- */
-int kRdrUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments)
-{
-    KRDR_VALIDATE(pRdr);
-    return pRdr->pOps->pfnUnmap(pRdr, pvBase, cSegments, paSegments);
-}
-
-
-/**
- * We're done reading from the file but would like to keep file mappings.
- *
- * If the OS support closing the file handle while the file is mapped,
- * the reader should do so.
- *
- * @param   pRdr        The file provider instance.
- */
-void kRdrDone(PKRDR pRdr)
-{
-    KRDR_VALIDATE_VOID(pRdr);
-    pRdr->pOps->pfnDone(pRdr);
-}
-
Index: /trunk/kStuff/kRdr/kRdr.cpp
===================================================================
--- /trunk/kStuff/kRdr/kRdr.cpp	(revision 3546)
+++ /trunk/kStuff/kRdr/kRdr.cpp	(revision 3546)
@@ -0,0 +1,280 @@
+/* $Id$ */
+/** @file
+ * kRdr - The File Provider.
+ */
+
+/*
+ * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kStuff 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <k/kRdrAll.h>
+#include <k/kErrors.h>
+#include "kRdrInternal.h"
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/** The list of file providers. */
+static PCKRDROPS g_pRdrHead = &g_kRdrFileOps;
+
+
+/**
+ * Adds a new file provider.
+ *
+ * @param   pAdd        The new file provider.
+ */
+void kRdrAddProvider(PKRDROPS pAdd)
+{
+    pAdd->pNext = g_pRdrHead;
+    g_pRdrHead = pAdd;
+}
+
+
+/**
+ * Tries to opens a file.
+ *
+ * @returns 0 on success, OS status code on failure.
+ * @param   ppRdr           Where to store the file provider instance.
+ * @param   pszFilename     The filename.
+ */
+int kRdrOpen(PPKRDR ppRdr, const char *pszFilename)
+{
+    int             rc = -1;
+    PCKRDROPS    pCur;
+    for (pCur = g_pRdrHead; pCur; pCur = pCur->pNext)
+    {
+        rc = pCur->pfnCreate(ppRdr, pszFilename);
+        if (!rc)
+            return 0;
+    }
+    return rc;
+}
+
+
+/**
+ * Closes the file.
+ *
+ * @returns 0 on success, OS specific error code on failure.
+ *          On failure, the file provider instance will be in an indeterminate state - don't touch it!
+ * @param   pRdr        The file provider instance.
+ */
+int kRdrClose(PKRDR pRdr)
+{
+    KRDR_VALIDATE(pRdr);
+    return pRdr->pOps->pfnDestroy(pRdr);
+}
+
+
+/** Read bits from the file.
+ *
+ * @returns 0 on success, OS specific error code on failure.
+ * @param   pRdr        The file provider instance.
+ * @param   pvBuf       Where to put the bits.
+ * @param   cb          The number of bytes to read.
+ * @param   off         Where to start reading.
+ */
+int kRdrRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off)
+{
+    KRDR_VALIDATE(pRdr);
+    return pRdr->pOps->pfnRead(pRdr, pvBuf, cb, off);
+}
+
+
+/** Map all the file bits into memory (read only).
+ *
+ * @returns 0 on success, OS specific error code on failure.
+ * @param   pRdr        The file provider instance.
+ * @param   ppvBits     Where to store the address of the mapping.
+ *                      The size can be obtained using pfnSize.
+ */
+int kRdrAllMap(PKRDR pRdr, const void **ppvBits)
+{
+    KRDR_VALIDATE(pRdr);
+    return pRdr->pOps->pfnAllMap(pRdr, ppvBits);
+}
+
+
+/** Unmap a file bits mapping obtained by KRDROPS::pfnAllMap.
+ *
+ * @returns 0 on success, OS specific error code on failure.
+ * @param   pRdr        The file provider instance.
+ * @param   pvBits      The mapping address.
+ */
+int kRdrAllUnmap(PKRDR pRdr, const void *pvBits)
+{
+    KRDR_VALIDATE(pRdr);
+    return pRdr->pOps->pfnAllUnmap(pRdr, pvBits);
+}
+
+
+/** Get the file size.
+ *
+ * @returns The file size. Returns -1 on failure.
+ * @param   pRdr        The file provider instance.
+ */
+KFOFF kRdrSize(PKRDR pRdr)
+{
+    KRDR_VALIDATE(pRdr);
+    return pRdr->pOps->pfnSize(pRdr);
+}
+
+
+/** Get the file pointer offset.
+ *
+ * @returns The file pointer offset. Returns -1 on failure.
+ * @param   pRdr        The file provider instance.
+ */
+KFOFF kRdrTell(PKRDR pRdr)
+{
+    KRDR_VALIDATE(pRdr);
+    return pRdr->pOps->pfnTell(pRdr);
+}
+
+
+/** Get the file name.
+ *
+ * @returns The file name. Returns NULL on failure.
+ * @param   pRdr        The file provider instance.
+ */
+const char *kRdrName(PKRDR pRdr)
+{
+    KRDR_VALIDATE_EX(pRdr, NULL);
+    return pRdr->pOps->pfnName(pRdr);
+}
+
+
+/** Get the native file handle if possible.
+ *
+ * @returns The native file handle. Returns -1 if not available.
+ * @param   pRdr        The file provider instance.
+ */
+KIPTR kRdrNativeFH(PKRDR pRdr)
+{
+    KRDR_VALIDATE_EX(pRdr, -1);
+    return pRdr->pOps->pfnNativeFH(pRdr);
+}
+
+
+/**
+ * Gets the page size used when mapping sections of the file.
+ *
+ * @returns The page size.
+ * @param   pRdr        The file provider instance.
+ */
+KSIZE kRdrPageSize(PKRDR pRdr)
+{
+    KRDR_VALIDATE_EX(pRdr, 0x10000);
+    return pRdr->pOps->pfnPageSize(pRdr);
+}
+
+
+/**
+ * Maps the segments of a image into memory.
+ *
+ * The file reader will be using the RVA member of each segment to figure out where
+ * it goes relative to the image base address.
+ *
+ * @returns 0 on success, OS specific error code on failure.
+ * @param   pRdr        The file provider instance.
+ * @param   ppvBase     On input when fFixed is set, this contains the base address of the mapping.
+ *                      On output this contains the base of the image mapping.
+ * @param   cSegments   The number of segments in the array pointed to by paSegments.
+ * @param   paSegments  The segments thats going to be mapped.
+ * @param   fFixed      If set, the address at *ppvBase should be the base address of the mapping.
+ */
+int kRdrMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, unsigned fFixed)
+{
+    KRDR_VALIDATE(pRdr);
+    return pRdr->pOps->pfnMap(pRdr, ppvBase, cSegments, paSegments, fFixed);
+}
+
+
+/**
+ * Reloads dirty pages in mapped image.
+ *
+ * @returns 0 on success, OS specific error code on failure.
+ * @param   pRdr        The file provider instance.
+ * @param   pvBase      The base address of the image mapping.
+ * @param   cSegments   The number of segments in the array pointed to by paSegments.
+ * @param   paSegments  The segments thats going to be mapped.
+ */
+int kRdrRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments)
+{
+    KRDR_VALIDATE(pRdr);
+    return pRdr->pOps->pfnRefresh(pRdr, pvBase, cSegments, paSegments);
+}
+
+
+/**
+ * Protects or unprotects an image mapping.
+ *
+ * This is typically used for getting write access to read or execute only
+ * pages while applying fixups.
+ *
+ * @returns 0 on success, OS specific error code on failure.
+ * @param   pRdr        The file provider instance.
+ * @param   pvBase      The base address of the image mapping.
+ * @param   cSegments   The number of segments in the array pointed to by paSegments.
+ * @param   paSegments  The segments thats going to be mapped.
+ * @param   fUnprotectOrProtect     When set the all mapped segments are made writable.
+ *                                  When clean the segment protection is restored.
+ */
+int kRdrProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect)
+{
+    KRDR_VALIDATE(pRdr);
+    return pRdr->pOps->pfnProtect(pRdr, pvBase, cSegments, paSegments, fUnprotectOrProtect);
+}
+
+
+/**
+ * Unmaps a image mapping.
+ *
+ * @returns 0 on success, OS specific error code on failure.
+ * @param   pRdr        The file provider instance.
+ * @param   pvBase      The base address of the image mapping.
+ * @param   cSegments   The number of segments in the array pointed to by paSegments.
+ * @param   paSegments  The segments thats going to be mapped.
+ */
+int kRdrUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments)
+{
+    KRDR_VALIDATE(pRdr);
+    return pRdr->pOps->pfnUnmap(pRdr, pvBase, cSegments, paSegments);
+}
+
+
+/**
+ * We're done reading from the file but would like to keep file mappings.
+ *
+ * If the OS support closing the file handle while the file is mapped,
+ * the reader should do so.
+ *
+ * @param   pRdr        The file provider instance.
+ */
+void kRdrDone(PKRDR pRdr)
+{
+    KRDR_VALIDATE_VOID(pRdr);
+    pRdr->pOps->pfnDone(pRdr);
+}
+
Index: unk/kStuff/kRdr/kRdrFile.c
===================================================================
--- /trunk/kStuff/kRdr/kRdrFile.c	(revision 3545)
+++ 	(revision )
@@ -1,1180 +1,0 @@
-/* $Id$ */
-/** @file
- * kRdrFile - The Native File Provider
- */
-
-/*
- * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
- *
- * This file is part of kStuff.
- *
- * kStuff is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * kStuff 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with kStuff; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-
-/*******************************************************************************
-*   Header Files                                                               *
-*******************************************************************************/
-#include <k/kDefs.h>
-
-#if K_OS == K_OS_OS2
-# define INCL_ERRORS
-# define INCL_BASE
-# include <os2.h>
-
-#elif K_OS == K_OS_WINDOWS
-# define WIN32_NO_STATUS
-# include <Windows.h>
-# ifndef __WIN__
-#  define __WIN__
-# endif
-# include <ntsecapi.h>
-# include <ntstatus.h>
-
-  /** @todo find a non-conflicting header with NTSTATUS, NTAPI, ++ */
-  typedef LONG NTSTATUS;
-  #define NT_SUCCESS(x) ((x)>=0)
-
-  typedef struct _OBJECT_ATTRIBUTES
-  {
-      ULONG   Length;
-      HANDLE  RootDirectory;
-      PUNICODE_STRING ObjectName;
-      ULONG   Attributes;
-      PVOID   SecurityDescriptor;
-      PVOID   SecurityQualityOfService;
-  } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
-
-  typedef enum _SECTION_INHERIT
-  {
-      ViewShare = 1,
-      ViewUnmap = 2
-  } SECTION_INHERIT;
-
-# define NTOSAPI __declspec(dllimport)
-# define NtCurrentProcess() GetCurrentProcess()
-
-# ifndef MEM_DOS_LIM
-#  define MEM_DOS_LIM 0x40000000UL
-# endif
-
-  NTOSAPI
-  NTSTATUS
-  NTAPI
-  NtCreateSection(
-      OUT PHANDLE SectionHandle,
-      IN ACCESS_MASK DesiredAccess,
-      IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
-      IN PLARGE_INTEGER SectionSize OPTIONAL,
-      IN ULONG Protect,
-      IN ULONG Attributes,
-      IN HANDLE FileHandle OPTIONAL
-  );
-
-  NTOSAPI
-  NTSTATUS
-  NTAPI
-  NtMapViewOfSection(
-      IN HANDLE SectionHandle,
-      IN HANDLE ProcessHandle,
-      IN OUT PVOID *BaseAddress,
-      IN ULONG ZeroBits,
-      IN ULONG CommitSize,
-      IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
-      IN OUT PSIZE_T ViewSize,
-      IN SECTION_INHERIT InheritDisposition,
-      IN ULONG AllocationType,
-      IN ULONG Protect
-  );
-
-  NTOSAPI
-  NTSTATUS
-  NTAPI
-  NtUnmapViewOfSection(
-      IN HANDLE ProcessHandle,
-      IN PVOID BaseAddress
-  );
-
-  NTOSAPI
-  NTSTATUS
-  NTAPI
-  NtClose(
-      IN HANDLE Handle
-  );
-
-  NTOSAPI
-  NTSTATUS
-  NTAPI
-  ZwProtectVirtualMemory(
-      IN HANDLE ProcessHandle,
-      IN OUT PVOID *BaseAddress,
-      IN OUT PULONG ProtectSize,
-      IN ULONG NewProtect,
-      OUT PULONG OldProtect
-  );
-# define NtProtectVirtualMemory ZwProtectVirtualMemory
-
-  NTOSAPI
-  NTSTATUS
-  NTAPI
-  NtAllocateVirtualMemory(
-      IN HANDLE ProcessHandle,
-      IN OUT PVOID *BaseAddress,
-      IN ULONG ZeroBits,
-      IN OUT PULONG AllocationSize,
-      IN ULONG AllocationType,
-      IN ULONG Protect
-  );
-
-  NTOSAPI
-  NTSTATUS
-  NTAPI
-  NtFreeVirtualMemory(
-      IN HANDLE ProcessHandle,
-      IN OUT PVOID *BaseAddress,
-      IN OUT PULONG FreeSize,
-      IN ULONG FreeType
-  );
-
-#else
-# error "port me"
-#endif
-
-#include "kRdrInternal.h"
-#include <k/kHlpAlloc.h>
-#include <k/kHlpString.h>
-
-
-/*******************************************************************************
-*   Structures and Typedefs                                                    *
-*******************************************************************************/
-/**
- * Prepared stuff.
- */
-typedef struct KRDRFILEPREP
-{
-    /** The address of the prepared region. */
-    void           *pv;
-    /** The size of the prepared region. */
-    KSIZE           cb;
-#if K_OS == K_OS_WINDOWS
-    /** Handle to the section created to map the file. */
-    HANDLE          hSection;
-#endif
-} KRDRFILEPREP, *PKRDRFILEPREP;
-
-/**
- * The file provier instance for native files.
- */
-typedef struct KRDRFILE
-{
-    /** The file reader vtable. */
-    KRDR                Core;
-    /** The file handle. */
-#if K_OS == K_OS_OS2
-    HFILE               File;
-#elif K_OS == K_OS_WINDOWS
-    HANDLE              File;
-#else
-# error "Port me!"
-#endif
-    /** The current file offset. */
-    KFOFF               off;
-    /** The file size. */
-    KFOFF               cb;
-    /** Array where we stuff the mapping area data. */
-    KRDRFILEPREP        aPreps[4];
-    /** The number of current preps. */
-    KU32                cPreps;
-    /** Number of mapping references. */
-    KI32                cMappings;
-    /** The memory mapping. */
-    void               *pvMapping;
-    /** The filename. */
-    char                szFilename[1];
-} KRDRFILE, *PKRDRFILE;
-
-
-/*******************************************************************************
-*   Internal Functions                                                         *
-*******************************************************************************/
-static void     krdrFileDone(PKRDR pRdr);
-static int      krdrFileUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments);
-static int      krdrFileGenericUnmap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments);
-static int      krdrFileProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect);
-static int      krdrFileGenericProtect(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect);
-static int      krdrFileRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments);
-static int      krdrFileGenericRefresh(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments);
-static int      krdrFileMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, unsigned fFixed);
-static int      krdrFileGenericMap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, unsigned fFixed);
-static KSIZE   krdrFilePageSize(PKRDR pRdr);
-static const char *krdrFileName(PKRDR pRdr);
-static KIPTR    krdrFileNativeFH(PKRDR pRdr);
-static KFOFF    krdrFileTell(PKRDR pRdr);
-static KFOFF    krdrFileSize(PKRDR pRdr);
-static int      krdrFileAllUnmap(PKRDR pRdr, const void *pvBits);
-static int      krdrFileAllMap(PKRDR pRdr, const void **ppvBits);
-static int      krdrFileRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off);
-static int      krdrFileDestroy(PKRDR pRdr);
-static int      krdrFileCreate(PPKRDR ppRdr, const char *pszFilename);
-
-
-/*******************************************************************************
-*   Global Variables                                                           *
-*******************************************************************************/
-/** Native file provider operations. */
-const KRDROPS g_kRdrFileOps =
-{
-    "native file",
-    NULL,
-    krdrFileCreate,
-    krdrFileDestroy,
-    krdrFileRead,
-    krdrFileAllMap,
-    krdrFileAllUnmap,
-    krdrFileSize,
-    krdrFileTell,
-    krdrFileName,
-    krdrFileNativeFH,
-    krdrFilePageSize,
-    krdrFileMap,
-    krdrFileRefresh,
-    krdrFileProtect,
-    krdrFileUnmap,
-    krdrFileDone,
-    42
-};
-
-
-#if K_OS == K_OS_WINDOWS
-/**
- * Converts a kLdr segment protection to NT protection for a mapping.
- *
- * @returns Nt page protection.
- * @param   enmProt     kLdr protection.
- */
-static ULONG krdrFileGetNtMapProt(KLDRPROT enmProt)
-{
-    switch (enmProt)
-    {
-        case KLDRPROT_NOACCESS:             return PAGE_NOACCESS;
-        case KLDRPROT_READONLY:             return PAGE_READONLY;
-        case KLDRPROT_READWRITE:            return PAGE_READWRITE;
-        case KLDRPROT_WRITECOPY:            return PAGE_WRITECOPY;
-        case KLDRPROT_EXECUTE:              return PAGE_EXECUTE;
-        case KLDRPROT_EXECUTE_READ:         return PAGE_EXECUTE_READ;
-        case KLDRPROT_EXECUTE_READWRITE:    return PAGE_EXECUTE_READWRITE;
-        case KLDRPROT_EXECUTE_WRITECOPY:    return PAGE_EXECUTE_WRITECOPY;
-        default:                            return ~(ULONG)0;
-    }
-}
-
-
-/**
- * Converts a kLdr segment protection to NT protection for a allocation.
- *
- * @returns Nt page protection.
- * @param   enmProt     kLdr protection.
- */
-static ULONG krdrFileGetNtAllocProt(KLDRPROT enmProt)
-{
-    switch (enmProt)
-    {
-        case KLDRPROT_NOACCESS:             return PAGE_NOACCESS;
-        case KLDRPROT_READONLY:             return PAGE_READONLY;
-        case KLDRPROT_WRITECOPY:
-        case KLDRPROT_READWRITE:            return PAGE_READWRITE;
-        case KLDRPROT_EXECUTE:              return PAGE_EXECUTE;
-        case KLDRPROT_EXECUTE_READ:         return PAGE_EXECUTE_READ;
-        case KLDRPROT_EXECUTE_WRITECOPY:
-        case KLDRPROT_EXECUTE_READWRITE:    return PAGE_EXECUTE_READWRITE;
-        default:                            return ~(ULONG)0;
-    }
-}
-#endif
-
-
-/** @copydoc KRDROPS::pfnDone */
-static void     krdrFileDone(PKRDR pRdr)
-{
-}
-
-
-/**
- * Finds a prepared mapping region.
- *
- * @returns Pointer to the aPrep entry.
- * @param   pFile   The instance data.
- * @param   pv      The base of the region.
- */
-static PKRDRFILEPREP krdrFileFindPrepExact(PKRDRFILE pFile, void *pv)
-{
-    KI32 i = pFile->cPreps;
-    while (i-- > 0)
-        if (pFile->aPreps[i].pv == pv)
-            return &pFile->aPreps[i];
-    return NULL;
-}
-
-
-/** @copydoc KRDROPS::pfnUnmap */
-static int      krdrFileUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments)
-{
-    PKRDRFILE        pRdrFile = (PKRDRFILE)pRdr;
-    PKRDRFILEPREP       pPrep = krdrFileFindPrepExact(pRdrFile, pvBase);
-    int                 rc;
-    if (!pPrep)
-        return KERR_INVALID_PARAMETER;
-
-#if K_OS == K_OS_WINDOWS
-    if (pPrep->hSection != NULL)
-    {
-        /** @todo implement me. */
-        return -1;
-    }
-#endif
-
-    rc = krdrFileGenericUnmap(pRdr, pPrep, cSegments, paSegments);
-
-    /* remove the mapping data on success. */
-    if (!rc)
-    {
-        pRdrFile->cPreps--;
-        if (pPrep != &pRdrFile->aPreps[pRdrFile->cPreps])
-            *pPrep = pRdrFile->aPreps[pRdrFile->cPreps];
-    }
-    return rc;
-}
-
-
-/** Generic implementation of krdrFileUnmap. */
-static int krdrFileGenericUnmap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments)
-{
-    krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
-    return kHlpPageFree(pPrep->pv, pPrep->cb);
-}
-
-
-/** @copydoc KRDROPS::pfnProtect */
-static int      krdrFileProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect)
-{
-    PKRDRFILE        pRdrFile = (PKRDRFILE)pRdr;
-    PKRDRFILEPREP    pPrep = krdrFileFindPrepExact(pRdrFile, pvBase);
-    if (!pPrep)
-        return KERR_INVALID_PARAMETER;
-
-#if K_OS == K_OS_WINDOWS
-    if (pPrep->hSection != NULL)
-    {
-        /** @todo implement me. */
-        return -1;
-    }
-#endif
-
-    return krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, fUnprotectOrProtect);
-}
-
-
-/** Generic implementation of krdrFileProtect. */
-static int krdrFileGenericProtect(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect)
-{
-    KU32 i;
-
-    /*
-     * Iterate the segments and apply memory protection changes.
-     */
-    for (i = 0; i < cSegments; i++)
-    {
-        int rc;
-        void *pv;
-        KLDRPROT enmProt;
-
-        if (paSegments[i].RVA == NIL_KLDRADDR)
-            continue;
-
-        /* calc new protection. */
-        enmProt = paSegments[i].enmProt;
-        if (fUnprotectOrProtect)
-        {
-            switch (enmProt)
-            {
-                case KLDRPROT_NOACCESS:
-                case KLDRPROT_READONLY:
-                case KLDRPROT_READWRITE:
-                case KLDRPROT_WRITECOPY:
-                    enmProt = KLDRPROT_READWRITE;
-                    break;
-                case KLDRPROT_EXECUTE:
-                case KLDRPROT_EXECUTE_READ:
-                case KLDRPROT_EXECUTE_READWRITE:
-                case KLDRPROT_EXECUTE_WRITECOPY:
-                    enmProt = KLDRPROT_EXECUTE_READWRITE;
-                    break;
-                default:
-                    kRdrAssert(!"bad enmProt");
-                    return -1;
-            }
-        }
-        else
-        {
-            /* copy on write -> normal write. */
-            if (enmProt == KLDRPROT_EXECUTE_WRITECOPY)
-                enmProt = KLDRPROT_EXECUTE_READWRITE;
-            else if (enmProt == KLDRPROT_WRITECOPY)
-                enmProt = KLDRPROT_READWRITE;
-        }
-
-        pv = (uint8_t *)pPrep->pv + paSegments[i].RVA;
-
-        rc = kHlpPageProtect(pv, paSegments[i].cbMapped, enmProt);
-        if (rc)
-            break;
-    }
-
-    return 0;
-}
-
-
-/** @copydoc KRDROPS::pfnRefresh */
-static int      krdrFileRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments)
-{
-    PKRDRFILE        pRdrFile = (PKRDRFILE)pRdr;
-    PKRDRFILEPREP    pPrep = krdrFileFindPrepExact(pRdrFile, pvBase);
-    if (!pPrep)
-        return KERR_INVALID_PARAMETER;
-
-#if K_OS == K_OS_WINDOWS
-    if (pPrep->hSection != NULL)
-    {
-        /** @todo implement me. */
-        return -1;
-    }
-#endif
-
-    return krdrFileGenericRefresh(pRdr, pPrep, cSegments, paSegments);
-}
-
-
-/** Generic implementation of krdrFileRefresh. */
-static int      krdrFileGenericRefresh(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments)
-{
-    int rc;
-    int rc2;
-    KU32 i;
-
-    /*
-     * Make everything writable again.
-     */
-    rc = krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
-    if (rc)
-    {
-        krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
-        return rc;
-    }
-
-    /*
-     * Clear everything.
-     */
-    /** @todo only zero the areas not covered by raw file bits. */
-    kHlpMemSet(pPrep->pv, 0, pPrep->cb);
-
-    /*
-     * Reload all the segments.
-     * We could possibly skip some segments, but we currently have
-     * no generic way of figuring out which at the moment.
-     */
-    for (i = 0; i < cSegments; i++)
-    {
-        void *pv;
-
-        if (    paSegments[i].RVA == NIL_KLDRADDR
-            ||  paSegments[i].cbFile <= 0)
-            continue;
-
-        pv = (uint8_t *)pPrep->pv + paSegments[i].RVA;
-        rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile);
-        if (rc)
-            break;
-    }
-
-    /*
-     * Protect the bits again.
-     */
-    rc2 = krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
-    if (rc2 && rc)
-        rc = rc2;
-
-    return rc;
-}
-
-
-/** @copydoc KRDROPS::pfnMap */
-static int      krdrFileMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, unsigned fFixed)
-{
-    PKRDRFILE       pRdrFile = (PKRDRFILE)pRdr;
-    PKRDRFILEPREP   pPrep = &pRdrFile->aPreps[pRdrFile->cPreps];
-    KLDRSIZE        cbTotal;
-    const KSIZE     cbPage = pRdr->pOps->pfnPageSize(pRdr);
-    int             rc;
-    KU32            i;
-
-    if (pRdrFile->cPreps >= K_ELEMENTS(pRdrFile->aPreps))
-        return KRDR_ERR_TOO_MANY_MAPPINGS;
-
-    /*
-     * Calc the total mapping space needed.
-     */
-    cbTotal = 0;
-    for (i = 0; i < cSegments; i++)
-    {
-        KLDRSIZE uRVASegmentEnd;
-        if (paSegments[i].RVA == NIL_KLDRADDR)
-            continue;
-        uRVASegmentEnd = paSegments[i].RVA + paSegments[i].cbMapped;
-        if (cbTotal < uRVASegmentEnd)
-            cbTotal = uRVASegmentEnd;
-    }
-    pPrep->cb = (KSIZE)cbTotal;
-    if (pPrep->cb != cbTotal)
-        return KLDR_ERR_ADDRESS_OVERFLOW;
-    pPrep->cb = (pPrep->cb + (cbPage - 1)) & ~(cbPage- 1);
-
-#if K_OS == K_OS_WINDOWS
-    /*
-     * The NT memory mapped file API sucks in a lot of ways. Unless you're actually
-     * trying to map a PE image and the kernel can parse the file for it self, the
-     * API just isn't up to scratch.
-     *
-     * Problems:
-     *      1. Reserving memory for the views is risky because you can't reserve and
-     *         map into the reserved space. So, other threads might grab the memory
-     *         before we get to it.
-     *      2. The page aligning of file offsets makes it impossible to map most
-     *         executable images since these are commonly sector aligned.
-     *      3. When mapping a read+execute file, its not possible to create section
-     *         larger than the file since the section size is bound to the data file
-     *         size. This wouldn't have been such a problem if it was possible to
-     *         map views beyond the section restriction, i.e. have a file size and
-     *         view size.
-     *      4. Only x86 can map views at page granularity it seems, and that only
-     *         using an undocument flag. The default granularity is 64KB.
-     *      5. There is more crappyness here...
-     *
-     * So, first we'll have to check if we can the file using the crappy NT APIs.
-     * Chances are we can't.
-     */
-    for (i = 0; i < cSegments; i++)
-    {
-        if (paSegments[i].RVA == NIL_KLDRADDR)
-            continue;
-
-        /* The file backing of the segments must be page aligned. */
-        if (    paSegments[i].cbFile > 0
-            &&  paSegments[i].offFile & (cbPage - 1))
-            break;
-
-        /* Only page alignment gaps between the file size and the mapping size. */
-        if (    paSegments[i].cbFile > 0
-            &&  (paSegments[i].cbFile & ~(cbPage - 1)) != (paSegments[i].cbMapped & ~(cbPage - 1)) )
-            break;
-
-        /* The mapping addresses of the segments must be page aligned.
-         * Non-x86 will probably require 64KB alignment here. */
-        if (paSegments[i].RVA & (cbPage - 1))
-            break;
-
-        /* If we do have to allocate the segment it's RVA must be 64KB aligned. */
-        if (    paSegments[i].cbFile > 0
-            &&  (paSegments[i].RVA & 0xffff))
-            break;
-    }
-    /** @todo if this is a PE image, we might just try a SEC_IMAGE mapping. It'll work if the host and image machines matches. */
-    if (i == cSegments)
-    {
-        /* WOW! it may work out! Incredible! */
-        SIZE_T          ViewSize;
-        LARGE_INTEGER   SectionOffset;
-        LARGE_INTEGER   MaxiumSize;
-        NTSTATUS        Status;
-        PVOID           pv;
-
-        MaxiumSize.QuadPart = pRdr->pOps->pfnSize(pRdr);
-        if (MaxiumSize.QuadPart > (LONGLONG)cbTotal)
-            MaxiumSize.QuadPart = cbTotal;
-
-        Status = NtCreateSection(&pPrep->hSection,
-                                 SECTION_MAP_EXECUTE | SECTION_MAP_READ,    /* desired access */
-                                 NULL,                                      /* object attributes */
-                                 &MaxiumSize,
-                                 PAGE_EXECUTE_WRITECOPY,                    /* page attributes */
-                                 SEC_COMMIT,                                /* section attributes */
-                                 pRdrFile->File);
-        if (!NT_SUCCESS(Status))
-            return (int)Status;
-
-        /*
-         * Determin the base address.
-         */
-        if (fFixed)
-            pPrep->pv = *ppvBase;
-        else
-        {
-            pv = NULL;
-            ViewSize = (KSIZE)cbTotal;
-
-            Status = NtAllocateVirtualMemory(NtCurrentProcess(),
-                                             &pv,
-                                             0,                             /* ZeroBits */
-                                             &ViewSize,
-                                             MEM_RESERVE,
-                                             PAGE_READONLY);
-            if (NT_SUCCESS(Status))
-            {
-                pPrep->pv = *ppvBase = pv;
-                ViewSize = 0;
-                Status = NtFreeVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, MEM_RELEASE);
-            }
-            if (!NT_SUCCESS(Status))
-            {
-                NtClose(pPrep->hSection);
-                return Status;
-            }
-        }
-
-        /*
-         * Map the segments.
-         */
-        for (i = 0; i < cSegments; i++)
-        {
-            ULONG fPageProt;
-
-            if (paSegments[i].RVA == NIL_KLDRADDR)
-                continue;
-
-            pv = (uint8_t *)pPrep->pv + paSegments[i].RVA;
-            if (paSegments[i].cbFile > 0)
-            {
-                SectionOffset.QuadPart = paSegments[i].offFile;
-                ViewSize = paSegments[i].cbFile;
-                fPageProt = krdrFileGetNtMapProt(paSegments[i].enmProt);
-                /* STATUS_MAPPED_ALIGNMENT
-                   STATUS_CONFLICTING_ADDRESSES
-                   STATUS_INVALID_VIEW_SIZE */
-                Status = NtMapViewOfSection(pPrep->hSection, NtCurrentProcess(),
-                                            &pv,
-                                            0,                                  /* ZeroBits */
-                                            0,                                  /* CommitSize */
-                                            &SectionOffset,                     /* SectionOffset */
-                                            &ViewSize,
-                                            ViewUnmap,
-                                            MEM_DOS_LIM,                        /* AllocationType */
-                                            fPageProt);
-                /* do we have to zero anything? */
-                if (    NT_SUCCESS(Status)
-                    &&  0/*later*/)
-                {
-                    /*ULONG OldPageProt = 0;
-                      NtProtectVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, , */
-                }
-            }
-            else
-            {
-                ViewSize = paSegments[i].cbMapped;
-                fPageProt = krdrFileGetNtAllocProt(paSegments[i].enmProt);
-                Status = NtAllocateVirtualMemory(NtCurrentProcess(),
-                                                 &pv,
-                                                 0,                             /* ZeroBits */
-                                                 &ViewSize,
-                                                 MEM_COMMIT,
-                                                 fPageProt);
-            }
-            if (!NT_SUCCESS(Status))
-                break;
-        }
-
-        /*
-         * On success, commit the mapping and return.
-         */
-        if (NT_SUCCESS(Status))
-        {
-            pRdrFile->cPreps++;
-            return 0;
-        }
-
-        /* bail out and fall back on the generic code. */
-        while (i-- > 0)
-        {
-            PVOID pv;
-
-            if (paSegments[i].RVA == NIL_KLDRADDR)
-                continue;
-
-            pv = (uint8_t *)pPrep->pv + paSegments[i].RVA;
-            if (paSegments[i].cbFile > 0)
-                NtUnmapViewOfSection(NtCurrentProcess(), pv);
-            else
-                NtFreeVirtualMemory(NtCurrentProcess(), &pv, NULL, MEM_RELEASE);
-        }
-        NtClose(pPrep->hSection);
-    }
-    /* else: fall back to the generic code */
-    pPrep->hSection = NULL;
-#endif
-
-    /*
-     * Use the generic map emulation.
-     */
-    pPrep->pv = fFixed ? *ppvBase : NULL;
-    rc = krdrFileGenericMap(pRdr, pPrep, cSegments, paSegments, fFixed);
-    if (!rc)
-    {
-        *ppvBase = pPrep->pv;
-        pRdrFile->cPreps++;
-    }
-
-    return rc;
-}
-
-
-/** Generic implementation of krdrFileMap. */
-static int  krdrFileGenericMap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, unsigned fFixed)
-{
-    int rc;
-    KU32 i;
-
-    /*
-     * Generic mapping code using kHlpPageAlloc(), kHlpPageFree() and kHlpPageProtect().
-     */
-    rc = kHlpPageAlloc(&pPrep->pv, pPrep->cb, KLDRPROT_EXECUTE_READWRITE, fFixed);
-    if (rc)
-        return rc;
-
-    /*
-     * Load the data.
-     */
-    for (i = 0; i < cSegments; i++)
-    {
-        void *pv;
-
-        if (    paSegments[i].RVA == NIL_KLDRADDR
-            ||  paSegments[i].cbFile <= 0)
-            continue;
-
-        pv = (uint8_t *)pPrep->pv + paSegments[i].RVA;
-        rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile);
-        if (rc)
-            break;
-    }
-
-    /*
-     * Set segment protection.
-     */
-    if (!rc)
-    {
-        rc = krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
-        if (!rc)
-            return 0;
-        krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
-    }
-
-    /* bailout */
-    kHlpPageFree(pPrep->pv, pPrep->cb);
-    return rc;
-}
-
-
-/** @copydoc KRDROPS::pfnPageSize */
-static KSIZE   krdrFilePageSize(PKRDR pRdr)
-{
-#if K_OS == K_OS_OS2
-    /* The page size on OS/2 wont change anytime soon. :-) */
-    return 0x1000;
-
-#elif K_OS == K_OS_WINDOWS
-    SYSTEM_INFO SysInfo;
-    GetSystemInfo(&SysInfo);
-    return SysInfo.dwPageSize;
-    /*return SysInfo.dwAllocationGranularity;*/
-#else
-# error "port me"
-#endif
-}
-
-
-/** @copydoc KRDROPS::pfnName */
-static const char *krdrFileName(PKRDR pRdr)
-{
-    PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
-    return &pRdrFile->szFilename[0];
-}
-
-
-static KIPTR krdrFileNativeFH(PKRDR pRdr)
-{
-    PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
-#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS
-    return (KIPTR)pRdrFile->File;
-#else
-# error "port me"
-#endif
-}
-
-
-/** @copydoc KRDROPS::pfnTell */
-static KFOFF krdrFileTell(PKRDR pRdr)
-{
-    PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
-
-    /*
-     * If the offset is undefined, try figure out what it is.
-     */
-    if (pRdrFile->off == -1)
-    {
-#if K_OS == K_OS_OS2
-        ULONG ulNew;
-        APIRET rc = DosSetFilePtr(pRdrFile->File, 0, FILE_CURRENT, &ulNew);
-        if (rc)
-            return -1;
-        pRdrFile->off = ulNew;
-
-#elif K_OS == K_OS_WINDOWS
-        LONG offHigh = 0;
-        LONG offLow;
-        int rc;
-
-        SetLastError(0);
-        offLow = SetFilePointer(pRdrFile->File, 0, &offHigh, FILE_CURRENT);
-        rc = GetLastError();
-        if (rc)
-            return -1;
-        pRdrFile->off = ((KFOFF)offHigh << 32) | offLow;
-
-#else
-# error "port me."
-#endif
-    }
-    return pRdrFile->off;
-}
-
-
-/** @copydoc KRDROPS::pfnSize */
-static KFOFF krdrFileSize(PKRDR pRdr)
-{
-    PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
-    return pRdrFile->cb;
-}
-
-
-/** @copydoc KRDROPS::pfnAllUnmap */
-static int krdrFileAllUnmap(PKRDR pRdr, const void *pvBits)
-{
-    PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
-
-    /* check for underflow */
-    if (pRdrFile->cMappings <= 0)
-#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS
-        return ERROR_INVALID_PARAMETER;
-#else
-# error "port me"
-#endif
-
-    /* decrement usage counter, free mapping if no longer in use. */
-    if (!--pRdrFile->cMappings)
-    {
-        kHlpFree(pRdrFile->pvMapping);
-        pRdrFile->pvMapping = NULL;
-    }
-
-    return 0;
-}
-
-
-/** @copydoc KRDROPS::pfnAllMap */
-static int krdrFileAllMap(PKRDR pRdr, const void **ppvBits)
-{
-    PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
-
-    /*
-     * Do we need to map it?
-     */
-    if (!pRdrFile->pvMapping)
-    {
-        int rc;
-        KFOFF cb = pRdrFile->Core.pOps->pfnSize(pRdr);
-
-        pRdrFile->pvMapping = kHlpAlloc(cb);
-        if (!pRdrFile->pvMapping)
-#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS
-            return ERROR_NOT_ENOUGH_MEMORY;
-#else
-# error "port me"
-#endif
-        rc = pRdrFile->Core.pOps->pfnRead(pRdr, pRdrFile->pvMapping, cb, 0);
-        if (rc)
-        {
-            kHlpFree(pRdrFile->pvMapping);
-            pRdrFile->pvMapping = NULL;
-            return rc;
-        }
-        pRdrFile->cMappings = 0;
-    }
-
-    *ppvBits = pRdrFile->pvMapping;
-    pRdrFile->cMappings++;
-    return 0;
-}
-
-
-/** @copydoc KRDROPS::pfnRead */
-static int krdrFileRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off)
-{
-    PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
-
-    /*
-     * Do a seek if needed.
-     */
-    if (pRdrFile->off != off)
-    {
-#if K_OS == K_OS_OS2
-        ULONG ulNew;
-        APIRET rc;
-
-        rc = DosSetFilePtr(pRdrFile->File, off, FILE_BEGIN, &ulNew);
-        if (rc)
-        {
-            pRdrFile->off = -1;
-            return rc;
-        }
-
-#elif K_OS == K_OS_WINDOWS
-        LONG offHigh;
-        LONG offLow;
-
-        offHigh = sizeof(KFOFF) == 4 ? 0 : (off >> 32);
-        offLow = SetFilePointer(pRdrFile->File, (LONG)off, &offHigh, FILE_BEGIN);
-        if (    offLow != (LONG)off
-            ||  offHigh != (LONG)(sizeof(KFOFF) == 4 ? 0 : (off >> 32)))
-        {
-            int rc = GetLastError();
-            if (!rc)
-                rc = ERROR_GEN_FAILURE;
-            pRdrFile->off = -1;
-            return rc;
-        }
-
-#else
-# error "port me."
-#endif
-    }
-
-    /*
-     * Do the read.
-     */
-#if K_OS == K_OS_OS2
-    {
-    ULONG cbRead = 0;
-    APIRET rc = DosRead(pRdrFile->File, pvBuf, cb, &cbRead);
-    if (rc)
-    {
-        pRdrFile->off = -1;
-        return rc;
-    }
-    if (cbRead != cb)
-    {
-        pRdrFile->off = -1;
-        return ERROR_GEN_FAILURE;
-    }
-    }
-
-#elif K_OS == K_OS_WINDOWS
-    {
-    DWORD cbRead = 0;
-    if (!ReadFile(pRdrFile->File, pvBuf, cb, &cbRead, NULL))
-    {
-        int rc = GetLastError();
-        if (!rc)
-            rc = ERROR_GEN_FAILURE;
-        pRdrFile->off = -1;
-        return rc;
-    }
-    if (cbRead != cb)
-    {
-        pRdrFile->off = -1;
-        return ERROR_GEN_FAILURE;
-    }
-    }
-
-#else
-# error "port me."
-#endif
-
-    pRdrFile->off = off + cb;
-    return 0;
-}
-
-
-/** @copydoc KRDROPS::pfnDestroy */
-static int krdrFileDestroy(PKRDR pRdr)
-{
-    PKRDRFILE    pRdrFile = (PKRDRFILE)pRdr;
-    int             rc;
-#if K_OS == K_OS_OS2
-    rc = DosClose(pRdrFile->File);
-
-#elif K_OS == K_OS_WINDOWS
-    rc = 0;
-    if (!CloseHandle(pRdrFile->File))
-        rc = GetLastError();
-
-#else
-# error "port me"
-#endif
-
-    if (pRdrFile->pvMapping)
-    {
-        kHlpFree(pRdrFile->pvMapping);
-        pRdrFile->pvMapping = NULL;
-    }
-
-    kHlpFree(pRdr);
-    return rc;
-}
-
-
-/** @copydoc KRDROPS::pfnCreate */
-static int krdrFileCreate(PPKRDR ppRdr, const char *pszFilename)
-{
-    KSIZE       cchFilename;
-    PKRDRFILE   pRdrFile;
-
-    /*
-     * Open the file and determin its size.
-     */
-#if K_OS == K_OS_OS2
-    ULONG           ulAction = 0;
-    FILESTATUS3     Info;
-    APIRET          rc;
-    HFILE           File = 0;
-    KFOFF           cb;
-    char            szFilename[CCHMAXPATH];
-
-    if ((uintptr_t)pszFilename >= 0x20000000)
-    {
-        char *psz;
-        cchFilename = kHlpStrLen(szFilename);
-        psz = (char *)kHlpAllocA(cchFilename + 1);
-        kHlpMemCopy(psz, pszFilename, cchFilename + 1);
-        pszFilename = psz;
-    }
-    rc = DosOpen((PCSZ)pszFilename, &File, &ulAction, 0, FILE_NORMAL,
-                 OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW,
-                 OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY | OPEN_FLAGS_RANDOMSEQUENTIAL,
-                 NULL);
-    if (rc)
-        return rc;
-
-    rc = DosQueryPathInfo((PCSZ)pszFilename, FIL_QUERYFULLNAME, szFilename, sizeof(szFilename));
-    if (rc)
-    {
-        DosClose(File);
-        return rc;
-    }
-
-    rc = DosQueryFileInfo(File, FIL_STANDARD, &Info, sizeof(Info));
-    if (rc)
-    {
-        DosClose(File);
-        return rc;
-    }
-    cb = Info.cbFile;
-
-#elif K_OS == K_OS_WINDOWS
-    SECURITY_ATTRIBUTES SecAttr;
-    DWORD               High;
-    DWORD               Low;
-    int                 rc;
-    HANDLE              File;
-    KFOFF            cb;
-    char                szFilename[MAX_PATH];
-
-    SecAttr.bInheritHandle = FALSE;
-    SecAttr.lpSecurityDescriptor = NULL;
-    SecAttr.nLength = 0;
-    File = CreateFile(pszFilename, GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ, &SecAttr, OPEN_EXISTING, 0, NULL);
-    if (File == INVALID_HANDLE_VALUE)
-        return GetLastError();
-
-    if (!GetFullPathName(pszFilename, sizeof(szFilename), szFilename, NULL))
-    {
-        rc = GetLastError();
-        CloseHandle(File);
-        return rc;
-    }
-
-    SetLastError(0);
-    Low = GetFileSize(File, &High);
-    rc = GetLastError();
-    if (rc)
-    {
-        CloseHandle(File);
-        return rc;
-    }
-    if (sizeof(KFOFF) == 4)
-        cb = High ? 0x7fffffff : Low;
-    else
-        cb = ((KFOFF)High << 32) | Low;
-
-#else
-# error "port me"
-#endif
-
-
-    /*
-     * Allocate the reader instance.
-     */
-    cchFilename = kHlpStrLen(szFilename);
-    pRdrFile = (PKRDRFILE)kHlpAlloc(sizeof(*pRdrFile) + cchFilename);
-    if (!pRdrFile)
-#if K_OS == K_OS_OS2
-    {
-        DosClose(File);
-        return ERROR_NOT_ENOUGH_MEMORY;
-    }
-#elif K_OS == K_OS_WINDOWS
-    {
-        CloseHandle(File);
-        return ERROR_NOT_ENOUGH_MEMORY;
-    }
-#else
-# error "port me"
-#endif
-
-    /*
-     * Initialize it and return successfully.
-     */
-    pRdrFile->Core.u32Magic = KLDRRDR_MAGIC;
-    pRdrFile->Core.pOps = &g_kRdrFileOps;
-    pRdrFile->File = File;
-    pRdrFile->cb = cb;
-    pRdrFile->off = 0;
-    pRdrFile->cMappings = 0;
-    pRdrFile->cPreps = 0;
-    kHlpMemCopy(&pRdrFile->szFilename[0], szFilename, cchFilename + 1);
-
-    *ppRdr = &pRdrFile->Core;
-    return 0;
-}
-
Index: /trunk/kStuff/kRdr/kRdrFile.cpp
===================================================================
--- /trunk/kStuff/kRdr/kRdrFile.cpp	(revision 3546)
+++ /trunk/kStuff/kRdr/kRdrFile.cpp	(revision 3546)
@@ -0,0 +1,1178 @@
+/* $Id$ */
+/** @file
+ * kRdrFile - The Native File Provider
+ */
+
+/*
+ * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kStuff.
+ *
+ * kStuff is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kStuff 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with kStuff; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "kRdrInternal.h"
+#include <k/kHlpAlloc.h>
+#include <k/kHlpString.h>
+
+#if K_OS == K_OS_OS2
+# define INCL_ERRORS
+# define INCL_BASE
+# include <os2.h>
+
+#elif K_OS == K_OS_WINDOWS
+# define WIN32_NO_STATUS
+# include <Windows.h>
+# ifndef __WIN__
+#  define __WIN__
+# endif
+# include <ntsecapi.h>
+# include <ntstatus.h>
+
+  /** @todo find a non-conflicting header with NTSTATUS, NTAPI, ++ */
+  typedef LONG NTSTATUS;
+  #define NT_SUCCESS(x) ((x)>=0)
+
+  typedef struct _OBJECT_ATTRIBUTES
+  {
+      ULONG   Length;
+      HANDLE  RootDirectory;
+      PUNICODE_STRING ObjectName;
+      ULONG   Attributes;
+      PVOID   SecurityDescriptor;
+      PVOID   SecurityQualityOfService;
+  } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
+
+  typedef enum _SECTION_INHERIT
+  {
+      ViewShare = 1,
+      ViewUnmap = 2
+  } SECTION_INHERIT;
+
+# define NTOSAPI __declspec(dllimport)
+# define NtCurrentProcess() GetCurrentProcess()
+
+# ifndef MEM_DOS_LIM
+#  define MEM_DOS_LIM 0x40000000UL
+# endif
+
+  NTOSAPI
+  NTSTATUS
+  NTAPI
+  NtCreateSection(
+      OUT PHANDLE SectionHandle,
+      IN ACCESS_MASK DesiredAccess,
+      IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
+      IN PLARGE_INTEGER SectionSize OPTIONAL,
+      IN ULONG Protect,
+      IN ULONG Attributes,
+      IN HANDLE FileHandle OPTIONAL
+  );
+
+  NTOSAPI
+  NTSTATUS
+  NTAPI
+  NtMapViewOfSection(
+      IN HANDLE SectionHandle,
+      IN HANDLE ProcessHandle,
+      IN OUT PVOID *BaseAddress,
+      IN ULONG ZeroBits,
+      IN ULONG CommitSize,
+      IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
+      IN OUT PSIZE_T ViewSize,
+      IN SECTION_INHERIT InheritDisposition,
+      IN ULONG AllocationType,
+      IN ULONG Protect
+  );
+
+  NTOSAPI
+  NTSTATUS
+  NTAPI
+  NtUnmapViewOfSection(
+      IN HANDLE ProcessHandle,
+      IN PVOID BaseAddress
+  );
+
+  NTOSAPI
+  NTSTATUS
+  NTAPI
+  NtClose(
+      IN HANDLE Handle
+  );
+
+  NTOSAPI
+  NTSTATUS
+  NTAPI
+  ZwProtectVirtualMemory(
+      IN HANDLE ProcessHandle,
+      IN OUT PVOID *BaseAddress,
+      IN OUT PULONG ProtectSize,
+      IN ULONG NewProtect,
+      OUT PULONG OldProtect
+  );
+# define NtProtectVirtualMemory ZwProtectVirtualMemory
+
+  NTOSAPI
+  NTSTATUS
+  NTAPI
+  NtAllocateVirtualMemory(
+      IN HANDLE ProcessHandle,
+      IN OUT PVOID *BaseAddress,
+      IN ULONG ZeroBits,
+      IN OUT PULONG AllocationSize,
+      IN ULONG AllocationType,
+      IN ULONG Protect
+  );
+
+  NTOSAPI
+  NTSTATUS
+  NTAPI
+  NtFreeVirtualMemory(
+      IN HANDLE ProcessHandle,
+      IN OUT PVOID *BaseAddress,
+      IN OUT PULONG FreeSize,
+      IN ULONG FreeType
+  );
+
+#else
+# error "port me"
+#endif
+
+
+/*******************************************************************************
+*   Structures and Typedefs                                                    *
+*******************************************************************************/
+/**
+ * Prepared stuff.
+ */
+typedef struct KRDRFILEPREP
+{
+    /** The address of the prepared region. */
+    void           *pv;
+    /** The size of the prepared region. */
+    KSIZE           cb;
+#if K_OS == K_OS_WINDOWS
+    /** Handle to the section created to map the file. */
+    HANDLE          hSection;
+#endif
+} KRDRFILEPREP, *PKRDRFILEPREP;
+
+/**
+ * The file provier instance for native files.
+ */
+typedef struct KRDRFILE
+{
+    /** The file reader vtable. */
+    KRDR                Core;
+    /** The file handle. */
+#if K_OS == K_OS_OS2
+    HFILE               File;
+#elif K_OS == K_OS_WINDOWS
+    HANDLE              File;
+#else
+# error "Port me!"
+#endif
+    /** The current file offset. */
+    KFOFF               off;
+    /** The file size. */
+    KFOFF               cb;
+    /** Array where we stuff the mapping area data. */
+    KRDRFILEPREP        aPreps[4];
+    /** The number of current preps. */
+    KU32                cPreps;
+    /** Number of mapping references. */
+    KI32                cMappings;
+    /** The memory mapping. */
+    void               *pvMapping;
+    /** The filename. */
+    char                szFilename[1];
+} KRDRFILE, *PKRDRFILE;
+
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+static void     krdrFileDone(PKRDR pRdr);
+static int      krdrFileUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments);
+static int      krdrFileGenericUnmap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments);
+static int      krdrFileProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect);
+static int      krdrFileGenericProtect(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect);
+static int      krdrFileRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments);
+static int      krdrFileGenericRefresh(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments);
+static int      krdrFileMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed);
+static int      krdrFileGenericMap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed);
+static KSIZE   krdrFilePageSize(PKRDR pRdr);
+static const char *krdrFileName(PKRDR pRdr);
+static KIPTR    krdrFileNativeFH(PKRDR pRdr);
+static KFOFF    krdrFileTell(PKRDR pRdr);
+static KFOFF    krdrFileSize(PKRDR pRdr);
+static int      krdrFileAllUnmap(PKRDR pRdr, const void *pvBits);
+static int      krdrFileAllMap(PKRDR pRdr, const void **ppvBits);
+static int      krdrFileRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off);
+static int      krdrFileDestroy(PKRDR pRdr);
+static int      krdrFileCreate(PPKRDR ppRdr, const char *pszFilename);
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+/** Native file provider operations. */
+const KRDROPS g_kRdrFileOps =
+{
+    "native file",
+    NULL,
+    krdrFileCreate,
+    krdrFileDestroy,
+    krdrFileRead,
+    krdrFileAllMap,
+    krdrFileAllUnmap,
+    krdrFileSize,
+    krdrFileTell,
+    krdrFileName,
+    krdrFileNativeFH,
+    krdrFilePageSize,
+    krdrFileMap,
+    krdrFileRefresh,
+    krdrFileProtect,
+    krdrFileUnmap,
+    krdrFileDone,
+    42
+};
+
+
+#if K_OS == K_OS_WINDOWS
+/**
+ * Converts a kLdr segment protection to NT protection for a mapping.
+ *
+ * @returns Nt page protection.
+ * @param   enmProt     kLdr protection.
+ */
+static ULONG krdrFileGetNtMapProt(KLDRPROT enmProt)
+{
+    switch (enmProt)
+    {
+        case KLDRPROT_NOACCESS:             return PAGE_NOACCESS;
+        case KLDRPROT_READONLY:             return PAGE_READONLY;
+        case KLDRPROT_READWRITE:            return PAGE_READWRITE;
+        case KLDRPROT_WRITECOPY:            return PAGE_WRITECOPY;
+        case KLDRPROT_EXECUTE:              return PAGE_EXECUTE;
+        case KLDRPROT_EXECUTE_READ:         return PAGE_EXECUTE_READ;
+        case KLDRPROT_EXECUTE_READWRITE:    return PAGE_EXECUTE_READWRITE;
+        case KLDRPROT_EXECUTE_WRITECOPY:    return PAGE_EXECUTE_WRITECOPY;
+        default:                            return ~(ULONG)0;
+    }
+}
+
+
+/**
+ * Converts a kLdr segment protection to NT protection for a allocation.
+ *
+ * @returns Nt page protection.
+ * @param   enmProt     kLdr protection.
+ */
+static ULONG krdrFileGetNtAllocProt(KLDRPROT enmProt)
+{
+    switch (enmProt)
+    {
+        case KLDRPROT_NOACCESS:             return PAGE_NOACCESS;
+        case KLDRPROT_READONLY:             return PAGE_READONLY;
+        case KLDRPROT_WRITECOPY:
+        case KLDRPROT_READWRITE:            return PAGE_READWRITE;
+        case KLDRPROT_EXECUTE:              return PAGE_EXECUTE;
+        case KLDRPROT_EXECUTE_READ:         return PAGE_EXECUTE_READ;
+        case KLDRPROT_EXECUTE_WRITECOPY:
+        case KLDRPROT_EXECUTE_READWRITE:    return PAGE_EXECUTE_READWRITE;
+        default:                            return ~(ULONG)0;
+    }
+}
+#endif
+
+
+/** @copydoc KRDROPS::pfnDone */
+static void     krdrFileDone(PKRDR pRdr)
+{
+}
+
+
+/**
+ * Finds a prepared mapping region.
+ *
+ * @returns Pointer to the aPrep entry.
+ * @param   pFile   The instance data.
+ * @param   pv      The base of the region.
+ */
+static PKRDRFILEPREP krdrFileFindPrepExact(PKRDRFILE pFile, void *pv)
+{
+    KI32 i = pFile->cPreps;
+    while (i-- > 0)
+        if (pFile->aPreps[i].pv == pv)
+            return &pFile->aPreps[i];
+    return NULL;
+}
+
+
+/** @copydoc KRDROPS::pfnUnmap */
+static int      krdrFileUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments)
+{
+    PKRDRFILE        pRdrFile = (PKRDRFILE)pRdr;
+    PKRDRFILEPREP       pPrep = krdrFileFindPrepExact(pRdrFile, pvBase);
+    int                 rc;
+    if (!pPrep)
+        return KERR_INVALID_PARAMETER;
+
+#if K_OS == K_OS_WINDOWS
+    if (pPrep->hSection != NULL)
+    {
+        /** @todo implement me. */
+        return -1;
+    }
+#endif
+
+    rc = krdrFileGenericUnmap(pRdr, pPrep, cSegments, paSegments);
+
+    /* remove the mapping data on success. */
+    if (!rc)
+    {
+        pRdrFile->cPreps--;
+        if (pPrep != &pRdrFile->aPreps[pRdrFile->cPreps])
+            *pPrep = pRdrFile->aPreps[pRdrFile->cPreps];
+    }
+    return rc;
+}
+
+
+/** Generic implementation of krdrFileUnmap. */
+static int krdrFileGenericUnmap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments)
+{
+    krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
+    return kHlpPageFree(pPrep->pv, pPrep->cb);
+}
+
+
+/** @copydoc KRDROPS::pfnProtect */
+static int      krdrFileProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect)
+{
+    PKRDRFILE        pRdrFile = (PKRDRFILE)pRdr;
+    PKRDRFILEPREP    pPrep = krdrFileFindPrepExact(pRdrFile, pvBase);
+    if (!pPrep)
+        return KERR_INVALID_PARAMETER;
+
+#if K_OS == K_OS_WINDOWS
+    if (pPrep->hSection != NULL)
+    {
+        /** @todo implement me. */
+        return -1;
+    }
+#endif
+
+    return krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, fUnprotectOrProtect);
+}
+
+
+/** Generic implementation of krdrFileProtect. */
+static int krdrFileGenericProtect(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect)
+{
+    KU32 i;
+
+    /*
+     * Iterate the segments and apply memory protection changes.
+     */
+    for (i = 0; i < cSegments; i++)
+    {
+        int rc;
+        void *pv;
+        KPROT enmProt;
+
+        if (paSegments[i].RVA == NIL_KLDRADDR)
+            continue;
+
+        /* calc new protection. */
+        enmProt = (KPROT)paSegments[i].enmProt; /** @todo drop cast */
+        if (fUnprotectOrProtect)
+        {
+            switch (enmProt)
+            {
+                case KPROT_NOACCESS:
+                case KPROT_READONLY:
+                case KPROT_READWRITE:
+                case KPROT_WRITECOPY:
+                    enmProt = KPROT_READWRITE;
+                    break;
+                case KPROT_EXECUTE:
+                case KPROT_EXECUTE_READ:
+                case KPROT_EXECUTE_READWRITE:
+                case KPROT_EXECUTE_WRITECOPY:
+                    enmProt = KPROT_EXECUTE_READWRITE;
+                    break;
+                default:
+                    kRdrAssert(!"bad enmProt");
+                    return -1;
+            }
+        }
+        else
+        {
+            /* copy on write -> normal write. */
+            if (enmProt == KPROT_EXECUTE_WRITECOPY)
+                enmProt = KPROT_EXECUTE_READWRITE;
+            else if (enmProt == KPROT_WRITECOPY)
+                enmProt = KPROT_READWRITE;
+        }
+
+        pv = (uint8_t *)pPrep->pv + paSegments[i].RVA;
+
+        rc = kHlpPageProtect(pv, paSegments[i].cbMapped, enmProt);
+        if (rc)
+            break;
+    }
+
+    return 0;
+}
+
+
+/** @copydoc KRDROPS::pfnRefresh */
+static int      krdrFileRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments)
+{
+    PKRDRFILE        pRdrFile = (PKRDRFILE)pRdr;
+    PKRDRFILEPREP    pPrep = krdrFileFindPrepExact(pRdrFile, pvBase);
+    if (!pPrep)
+        return KERR_INVALID_PARAMETER;
+
+#if K_OS == K_OS_WINDOWS
+    if (pPrep->hSection != NULL)
+    {
+        /** @todo implement me. */
+        return -1;
+    }
+#endif
+
+    return krdrFileGenericRefresh(pRdr, pPrep, cSegments, paSegments);
+}
+
+
+/** Generic implementation of krdrFileRefresh. */
+static int      krdrFileGenericRefresh(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments)
+{
+    int rc;
+    int rc2;
+    KU32 i;
+
+    /*
+     * Make everything writable again.
+     */
+    rc = krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
+    if (rc)
+    {
+        krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
+        return rc;
+    }
+
+    /*
+     * Clear everything.
+     */
+    /** @todo only zero the areas not covered by raw file bits. */
+    kHlpMemSet(pPrep->pv, 0, pPrep->cb);
+
+    /*
+     * Reload all the segments.
+     * We could possibly skip some segments, but we currently have
+     * no generic way of figuring out which at the moment.
+     */
+    for (i = 0; i < cSegments; i++)
+    {
+        void *pv;
+
+        if (    paSegments[i].RVA == NIL_KLDRADDR
+            ||  paSegments[i].cbFile <= 0)
+            continue;
+
+        pv = (uint8_t *)pPrep->pv + paSegments[i].RVA;
+        rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile);
+        if (rc)
+            break;
+    }
+
+    /*
+     * Protect the bits again.
+     */
+    rc2 = krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
+    if (rc2 && rc)
+        rc = rc2;
+
+    return rc;
+}
+
+
+/** @copydoc KRDROPS::pfnMap */
+static int      krdrFileMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed)
+{
+    PKRDRFILE       pRdrFile = (PKRDRFILE)pRdr;
+    PKRDRFILEPREP   pPrep = &pRdrFile->aPreps[pRdrFile->cPreps];
+    KLDRSIZE        cbTotal;
+    const KSIZE     cbPage = pRdr->pOps->pfnPageSize(pRdr);
+    int             rc;
+    KU32            i;
+
+    if (pRdrFile->cPreps >= K_ELEMENTS(pRdrFile->aPreps))
+        return KRDR_ERR_TOO_MANY_MAPPINGS;
+
+    /*
+     * Calc the total mapping space needed.
+     */
+    cbTotal = 0;
+    for (i = 0; i < cSegments; i++)
+    {
+        KLDRSIZE uRVASegmentEnd;
+        if (paSegments[i].RVA == NIL_KLDRADDR)
+            continue;
+        uRVASegmentEnd = paSegments[i].RVA + paSegments[i].cbMapped;
+        if (cbTotal < uRVASegmentEnd)
+            cbTotal = uRVASegmentEnd;
+    }
+    pPrep->cb = (KSIZE)cbTotal;
+    if (pPrep->cb != cbTotal)
+        return KLDR_ERR_ADDRESS_OVERFLOW;
+    pPrep->cb = (pPrep->cb + (cbPage - 1)) & ~(cbPage- 1);
+
+#if K_OS == K_OS_WINDOWS
+    /*
+     * The NT memory mapped file API sucks in a lot of ways. Unless you're actually
+     * trying to map a PE image and the kernel can parse the file for it self, the
+     * API just isn't up to scratch.
+     *
+     * Problems:
+     *      1. Reserving memory for the views is risky because you can't reserve and
+     *         map into the reserved space. So, other threads might grab the memory
+     *         before we get to it.
+     *      2. The page aligning of file offsets makes it impossible to map most
+     *         executable images since these are commonly sector aligned.
+     *      3. When mapping a read+execute file, its not possible to create section
+     *         larger than the file since the section size is bound to the data file
+     *         size. This wouldn't have been such a problem if it was possible to
+     *         map views beyond the section restriction, i.e. have a file size and
+     *         view size.
+     *      4. Only x86 can map views at page granularity it seems, and that only
+     *         using an undocument flag. The default granularity is 64KB.
+     *      5. There is more crappyness here...
+     *
+     * So, first we'll have to check if we can the file using the crappy NT APIs.
+     * Chances are we can't.
+     */
+    for (i = 0; i < cSegments; i++)
+    {
+        if (paSegments[i].RVA == NIL_KLDRADDR)
+            continue;
+
+        /* The file backing of the segments must be page aligned. */
+        if (    paSegments[i].cbFile > 0
+            &&  paSegments[i].offFile & (cbPage - 1))
+            break;
+
+        /* Only page alignment gaps between the file size and the mapping size. */
+        if (    paSegments[i].cbFile > 0
+            &&  (paSegments[i].cbFile & ~(cbPage - 1)) != (paSegments[i].cbMapped & ~(cbPage - 1)) )
+            break;
+
+        /* The mapping addresses of the segments must be page aligned.
+         * Non-x86 will probably require 64KB alignment here. */
+        if (paSegments[i].RVA & (cbPage - 1))
+            break;
+
+        /* If we do have to allocate the segment it's RVA must be 64KB aligned. */
+        if (    paSegments[i].cbFile > 0
+            &&  (paSegments[i].RVA & 0xffff))
+            break;
+    }
+    /** @todo if this is a PE image, we might just try a SEC_IMAGE mapping. It'll work if the host and image machines matches. */
+    if (i == cSegments)
+    {
+        /* WOW! it may work out! Incredible! */
+        SIZE_T          ViewSize;
+        LARGE_INTEGER   SectionOffset;
+        LARGE_INTEGER   MaxiumSize;
+        NTSTATUS        Status;
+        PVOID           pv;
+
+        MaxiumSize.QuadPart = pRdr->pOps->pfnSize(pRdr);
+        if (MaxiumSize.QuadPart > (LONGLONG)cbTotal)
+            MaxiumSize.QuadPart = cbTotal;
+
+        Status = NtCreateSection(&pPrep->hSection,
+                                 SECTION_MAP_EXECUTE | SECTION_MAP_READ,    /* desired access */
+                                 NULL,                                      /* object attributes */
+                                 &MaxiumSize,
+                                 PAGE_EXECUTE_WRITECOPY,                    /* page attributes */
+                                 SEC_COMMIT,                                /* section attributes */
+                                 pRdrFile->File);
+        if (!NT_SUCCESS(Status))
+            return (int)Status;
+
+        /*
+         * Determin the base address.
+         */
+        if (fFixed)
+            pPrep->pv = *ppvBase;
+        else
+        {
+            pv = NULL;
+            ViewSize = (KSIZE)cbTotal;
+
+            Status = NtAllocateVirtualMemory(NtCurrentProcess(),
+                                             &pv,
+                                             0,                             /* ZeroBits */
+                                             &ViewSize,
+                                             MEM_RESERVE,
+                                             PAGE_READONLY);
+            if (NT_SUCCESS(Status))
+            {
+                pPrep->pv = *ppvBase = pv;
+                ViewSize = 0;
+                Status = NtFreeVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, MEM_RELEASE);
+            }
+            if (!NT_SUCCESS(Status))
+            {
+                NtClose(pPrep->hSection);
+                return Status;
+            }
+        }
+
+        /*
+         * Map the segments.
+         */
+        for (i = 0; i < cSegments; i++)
+        {
+            ULONG fPageProt;
+
+            if (paSegments[i].RVA == NIL_KLDRADDR)
+                continue;
+
+            pv = (uint8_t *)pPrep->pv + paSegments[i].RVA;
+            if (paSegments[i].cbFile > 0)
+            {
+                SectionOffset.QuadPart = paSegments[i].offFile;
+                ViewSize = paSegments[i].cbFile;
+                fPageProt = krdrFileGetNtMapProt(paSegments[i].enmProt);
+                /* STATUS_MAPPED_ALIGNMENT
+                   STATUS_CONFLICTING_ADDRESSES
+                   STATUS_INVALID_VIEW_SIZE */
+                Status = NtMapViewOfSection(pPrep->hSection, NtCurrentProcess(),
+                                            &pv,
+                                            0,                                  /* ZeroBits */
+                                            0,                                  /* CommitSize */
+                                            &SectionOffset,                     /* SectionOffset */
+                                            &ViewSize,
+                                            ViewUnmap,
+                                            MEM_DOS_LIM,                        /* AllocationType */
+                                            fPageProt);
+                /* do we have to zero anything? */
+                if (    NT_SUCCESS(Status)
+                    &&  0/*later*/)
+                {
+                    /*ULONG OldPageProt = 0;
+                      NtProtectVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, , */
+                }
+            }
+            else
+            {
+                ViewSize = paSegments[i].cbMapped;
+                fPageProt = krdrFileGetNtAllocProt(paSegments[i].enmProt);
+                Status = NtAllocateVirtualMemory(NtCurrentProcess(),
+                                                 &pv,
+                                                 0,                             /* ZeroBits */
+                                                 &ViewSize,
+                                                 MEM_COMMIT,
+                                                 fPageProt);
+            }
+            if (!NT_SUCCESS(Status))
+                break;
+        }
+
+        /*
+         * On success, commit the mapping and return.
+         */
+        if (NT_SUCCESS(Status))
+        {
+            pRdrFile->cPreps++;
+            return 0;
+        }
+
+        /* bail out and fall back on the generic code. */
+        while (i-- > 0)
+        {
+            PVOID pv;
+
+            if (paSegments[i].RVA == NIL_KLDRADDR)
+                continue;
+
+            pv = (uint8_t *)pPrep->pv + paSegments[i].RVA;
+            if (paSegments[i].cbFile > 0)
+                NtUnmapViewOfSection(NtCurrentProcess(), pv);
+            else
+                NtFreeVirtualMemory(NtCurrentProcess(), &pv, NULL, MEM_RELEASE);
+        }
+        NtClose(pPrep->hSection);
+    }
+    /* else: fall back to the generic code */
+    pPrep->hSection = NULL;
+#endif
+
+    /*
+     * Use the generic map emulation.
+     */
+    pPrep->pv = fFixed ? *ppvBase : NULL;
+    rc = krdrFileGenericMap(pRdr, pPrep, cSegments, paSegments, fFixed);
+    if (!rc)
+    {
+        *ppvBase = pPrep->pv;
+        pRdrFile->cPreps++;
+    }
+
+    return rc;
+}
+
+
+/** Generic implementation of krdrFileMap. */
+static int  krdrFileGenericMap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed)
+{
+    int rc;
+    KU32 i;
+
+    /*
+     * Generic mapping code using kHlpPageAlloc(), kHlpPageFree() and kHlpPageProtect().
+     */
+    rc = kHlpPageAlloc(&pPrep->pv, pPrep->cb, KPROT_EXECUTE_READWRITE, fFixed);
+    if (rc)
+        return rc;
+
+    /*
+     * Load the data.
+     */
+    for (i = 0; i < cSegments; i++)
+    {
+        void *pv;
+
+        if (    paSegments[i].RVA == NIL_KLDRADDR
+            ||  paSegments[i].cbFile <= 0)
+            continue;
+
+        pv = (uint8_t *)pPrep->pv + paSegments[i].RVA;
+        rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile);
+        if (rc)
+            break;
+    }
+
+    /*
+     * Set segment protection.
+     */
+    if (!rc)
+    {
+        rc = krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
+        if (!rc)
+            return 0;
+        krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
+    }
+
+    /* bailout */
+    kHlpPageFree(pPrep->pv, pPrep->cb);
+    return rc;
+}
+
+
+/** @copydoc KRDROPS::pfnPageSize */
+static KSIZE   krdrFilePageSize(PKRDR pRdr)
+{
+#if K_OS == K_OS_OS2
+    /* The page size on OS/2 wont change anytime soon. :-) */
+    return 0x1000;
+
+#elif K_OS == K_OS_WINDOWS
+    SYSTEM_INFO SysInfo;
+    GetSystemInfo(&SysInfo);
+    return SysInfo.dwPageSize;
+    /*return SysInfo.dwAllocationGranularity;*/
+#else
+# error "port me"
+#endif
+}
+
+
+/** @copydoc KRDROPS::pfnName */
+static const char *krdrFileName(PKRDR pRdr)
+{
+    PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
+    return &pRdrFile->szFilename[0];
+}
+
+
+static KIPTR krdrFileNativeFH(PKRDR pRdr)
+{
+    PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
+#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS
+    return (KIPTR)pRdrFile->File;
+#else
+# error "port me"
+#endif
+}
+
+
+/** @copydoc KRDROPS::pfnTell */
+static KFOFF krdrFileTell(PKRDR pRdr)
+{
+    PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
+
+    /*
+     * If the offset is undefined, try figure out what it is.
+     */
+    if (pRdrFile->off == -1)
+    {
+#if K_OS == K_OS_OS2
+        ULONG ulNew;
+        APIRET rc = DosSetFilePtr(pRdrFile->File, 0, FILE_CURRENT, &ulNew);
+        if (rc)
+            return -1;
+        pRdrFile->off = ulNew;
+
+#elif K_OS == K_OS_WINDOWS
+        LONG offHigh = 0;
+        LONG offLow;
+        int rc;
+
+        SetLastError(0);
+        offLow = SetFilePointer(pRdrFile->File, 0, &offHigh, FILE_CURRENT);
+        rc = GetLastError();
+        if (rc)
+            return -1;
+        pRdrFile->off = ((KFOFF)offHigh << 32) | offLow;
+
+#else
+# error "port me."
+#endif
+    }
+    return pRdrFile->off;
+}
+
+
+/** @copydoc KRDROPS::pfnSize */
+static KFOFF krdrFileSize(PKRDR pRdr)
+{
+    PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
+    return pRdrFile->cb;
+}
+
+
+/** @copydoc KRDROPS::pfnAllUnmap */
+static int krdrFileAllUnmap(PKRDR pRdr, const void *pvBits)
+{
+    PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
+
+    /* check for underflow */
+    if (pRdrFile->cMappings <= 0)
+#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS
+        return ERROR_INVALID_PARAMETER;
+#else
+# error "port me"
+#endif
+
+    /* decrement usage counter, free mapping if no longer in use. */
+    if (!--pRdrFile->cMappings)
+    {
+        kHlpFree(pRdrFile->pvMapping);
+        pRdrFile->pvMapping = NULL;
+    }
+
+    return 0;
+}
+
+
+/** @copydoc KRDROPS::pfnAllMap */
+static int krdrFileAllMap(PKRDR pRdr, const void **ppvBits)
+{
+    PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
+
+    /*
+     * Do we need to map it?
+     */
+    if (!pRdrFile->pvMapping)
+    {
+        int rc;
+        KFOFF cbFile = pRdrFile->Core.pOps->pfnSize(pRdr);
+        KSIZE cb = (KSIZE)cbFile;
+        if (cb != cbFile)
+            return ERROR_NOT_ENOUGH_MEMORY;
+
+        pRdrFile->pvMapping = kHlpAlloc(cb);
+        if (!pRdrFile->pvMapping)
+#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS
+            return ERROR_NOT_ENOUGH_MEMORY;
+#else
+# error "port me"
+#endif
+        rc = pRdrFile->Core.pOps->pfnRead(pRdr, pRdrFile->pvMapping, cb, 0);
+        if (rc)
+        {
+            kHlpFree(pRdrFile->pvMapping);
+            pRdrFile->pvMapping = NULL;
+            return rc;
+        }
+        pRdrFile->cMappings = 0;
+    }
+
+    *ppvBits = pRdrFile->pvMapping;
+    pRdrFile->cMappings++;
+    return 0;
+}
+
+
+/** @copydoc KRDROPS::pfnRead */
+static int krdrFileRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off)
+{
+    PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
+
+    /*
+     * Do a seek if needed.
+     */
+    if (pRdrFile->off != off)
+    {
+#if K_OS == K_OS_OS2
+        ULONG ulNew;
+        APIRET rc;
+
+        rc = DosSetFilePtr(pRdrFile->File, off, FILE_BEGIN, &ulNew);
+        if (rc)
+        {
+            pRdrFile->off = -1;
+            return rc;
+        }
+
+#elif K_OS == K_OS_WINDOWS
+        LONG offHigh;
+        LONG offLow;
+
+        offHigh = (LONG)(off >> 32);
+        offLow = SetFilePointer(pRdrFile->File, (LONG)off, &offHigh, FILE_BEGIN);
+        if (    offLow != (LONG)off
+            ||  offHigh != (LONG)(off >> 32))
+        {
+            int rc = GetLastError();
+            if (!rc)
+                rc = ERROR_GEN_FAILURE;
+            pRdrFile->off = -1;
+            return rc;
+        }
+
+#else
+# error "port me."
+#endif
+    }
+
+    /*
+     * Do the read.
+     */
+#if K_OS == K_OS_OS2
+    {
+    ULONG cbRead = 0;
+    APIRET rc = DosRead(pRdrFile->File, pvBuf, cb, &cbRead);
+    if (rc)
+    {
+        pRdrFile->off = -1;
+        return rc;
+    }
+    if (cbRead != cb)
+    {
+        pRdrFile->off = -1;
+        return ERROR_GEN_FAILURE;
+    }
+    }
+
+#elif K_OS == K_OS_WINDOWS
+    {
+    DWORD cbRead = 0;
+    if (!ReadFile(pRdrFile->File, pvBuf, cb, &cbRead, NULL))
+    {
+        int rc = GetLastError();
+        if (!rc)
+            rc = ERROR_GEN_FAILURE;
+        pRdrFile->off = -1;
+        return rc;
+    }
+    if (cbRead != cb)
+    {
+        pRdrFile->off = -1;
+        return ERROR_GEN_FAILURE;
+    }
+    }
+
+#else
+# error "port me."
+#endif
+
+    pRdrFile->off = off + cb;
+    return 0;
+}
+
+
+/** @copydoc KRDROPS::pfnDestroy */
+static int krdrFileDestroy(PKRDR pRdr)
+{
+    PKRDRFILE    pRdrFile = (PKRDRFILE)pRdr;
+    int             rc;
+#if K_OS == K_OS_OS2
+    rc = DosClose(pRdrFile->File);
+
+#elif K_OS == K_OS_WINDOWS
+    rc = 0;
+    if (!CloseHandle(pRdrFile->File))
+        rc = GetLastError();
+
+#else
+# error "port me"
+#endif
+
+    if (pRdrFile->pvMapping)
+    {
+        kHlpFree(pRdrFile->pvMapping);
+        pRdrFile->pvMapping = NULL;
+    }
+
+    kHlpFree(pRdr);
+    return rc;
+}
+
+
+/** @copydoc KRDROPS::pfnCreate */
+static int krdrFileCreate(PPKRDR ppRdr, const char *pszFilename)
+{
+    KSIZE       cchFilename;
+    PKRDRFILE   pRdrFile;
+
+    /*
+     * Open the file and determin its size.
+     */
+#if K_OS == K_OS_OS2
+    ULONG           ulAction = 0;
+    FILESTATUS3     Info;
+    APIRET          rc;
+    HFILE           File = 0;
+    KFOFF           cb;
+    char            szFilename[CCHMAXPATH];
+
+    if ((uintptr_t)pszFilename >= 0x20000000)
+    {
+        char *psz;
+        cchFilename = kHlpStrLen(szFilename);
+        psz = (char *)kHlpAllocA(cchFilename + 1);
+        kHlpMemCopy(psz, pszFilename, cchFilename + 1);
+        pszFilename = psz;
+    }
+    rc = DosOpen((PCSZ)pszFilename, &File, &ulAction, 0, FILE_NORMAL,
+                 OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW,
+                 OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY | OPEN_FLAGS_RANDOMSEQUENTIAL,
+                 NULL);
+    if (rc)
+        return rc;
+
+    rc = DosQueryPathInfo((PCSZ)pszFilename, FIL_QUERYFULLNAME, szFilename, sizeof(szFilename));
+    if (rc)
+    {
+        DosClose(File);
+        return rc;
+    }
+
+    rc = DosQueryFileInfo(File, FIL_STANDARD, &Info, sizeof(Info));
+    if (rc)
+    {
+        DosClose(File);
+        return rc;
+    }
+    cb = Info.cbFile;
+
+#elif K_OS == K_OS_WINDOWS
+    SECURITY_ATTRIBUTES SecAttr;
+    DWORD               High;
+    DWORD               Low;
+    int                 rc;
+    HANDLE              File;
+    KFOFF            cb;
+    char                szFilename[MAX_PATH];
+
+    SecAttr.bInheritHandle = FALSE;
+    SecAttr.lpSecurityDescriptor = NULL;
+    SecAttr.nLength = 0;
+    File = CreateFile(pszFilename, GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ, &SecAttr, OPEN_EXISTING, 0, NULL);
+    if (File == INVALID_HANDLE_VALUE)
+        return GetLastError();
+
+    if (!GetFullPathName(pszFilename, sizeof(szFilename), szFilename, NULL))
+    {
+        rc = GetLastError();
+        CloseHandle(File);
+        return rc;
+    }
+
+    SetLastError(0);
+    Low = GetFileSize(File, &High);
+    rc = GetLastError();
+    if (rc)
+    {
+        CloseHandle(File);
+        return rc;
+    }
+    cb = ((KFOFF)High << 32) | Low;
+
+#else
+# error "port me"
+#endif
+
+
+    /*
+     * Allocate the reader instance.
+     */
+    cchFilename = kHlpStrLen(szFilename);
+    pRdrFile = (PKRDRFILE)kHlpAlloc(sizeof(*pRdrFile) + cchFilename);
+    if (!pRdrFile)
+#if K_OS == K_OS_OS2
+    {
+        DosClose(File);
+        return ERROR_NOT_ENOUGH_MEMORY;
+    }
+#elif K_OS == K_OS_WINDOWS
+    {
+        CloseHandle(File);
+        return ERROR_NOT_ENOUGH_MEMORY;
+    }
+#else
+# error "port me"
+#endif
+
+    /*
+     * Initialize it and return successfully.
+     */
+    pRdrFile->Core.u32Magic = KLDRRDR_MAGIC;
+    pRdrFile->Core.pOps = &g_kRdrFileOps;
+    pRdrFile->File = File;
+    pRdrFile->cb = cb;
+    pRdrFile->off = 0;
+    pRdrFile->cMappings = 0;
+    pRdrFile->cPreps = 0;
+    kHlpMemCopy(&pRdrFile->szFilename[0], szFilename, cchFilename + 1);
+
+    *ppRdr = &pRdrFile->Core;
+    return 0;
+}
+
