Changeset 2851


Ignore:
Timestamp:
Aug 31, 2016, 7:30:52 PM (9 years ago)
Author:
bird
Message:

updates

Location:
trunk/src/lib
Files:
1 deleted
16 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/lib

  • trunk/src/lib/Makefile.kmk

    r2849 r2851  
    4949       nt/nthlpfs.c \
    5050       nt/ntdir.c \
     51       nt/ntdircache.c \
    5152       nt/ntstat.c \
    5253       nt/ntunlink.c
  • trunk/src/lib/kDep.c

    r2413 r2851  
    55
    66/*
    7  * Copyright (c) 2004-2010 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
    8  *
    9  * This file is part of kBuild.
    10  *
    11  * kBuild is free software; you can redistribute it and/or modify
    12  * it under the terms of the GNU General Public License as published by
    13  * the Free Software Foundation; either version 3 of the License, or
    14  * (at your option) any later version.
    15  *
    16  * kBuild is distributed in the hope that it will be useful,
    17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    19  * GNU General Public License for more details.
    20  *
    21  * You should have received a copy of the GNU General Public License
    22  * along with kBuild.  If not, see <http://www.gnu.org/licenses/>
    23  *
    24  */
     7 * Copyright (c) 2004-2013 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
     8 *
     9 * Permission is hereby granted, free of charge, to any person obtaining a
     10 * copy of this software and associated documentation files (the "Software"),
     11 * to deal in the Software without restriction, including without limitation
     12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     13 * and/or sell copies of the Software, and to permit persons to whom the
     14 * Software is furnished to do so, subject to the following conditions:
     15 *
     16 * The above copyright notice and this permission notice shall be included
     17 * in all copies or substantial portions of the Software.
     18 *
     19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     25 * IN THE SOFTWARE.
     26 *
     27 * Alternatively, the content of this file may be used under the terms of the
     28 * GPL version 2 or later, or LGPL version 2.1 or later.
     29 */
     30
    2531
    2632/*******************************************************************************
  • trunk/src/lib/kDep.h

    r2413 r2851  
    55
    66/*
    7  * Copyright (c) 2004-2010 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
     7 * Copyright (c) 2004-2013 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
    88 *
    9  * This file is part of kBuild.
     9 * Permission is hereby granted, free of charge, to any person obtaining a
     10 * copy of this software and associated documentation files (the "Software"),
     11 * to deal in the Software without restriction, including without limitation
     12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     13 * and/or sell copies of the Software, and to permit persons to whom the
     14 * Software is furnished to do so, subject to the following conditions:
    1015 *
    11  * kBuild is free software; you can redistribute it and/or modify
    12  * it under the terms of the GNU General Public License as published by
    13  * the Free Software Foundation; either version 3 of the License, or
    14  * (at your option) any later version.
     16 * The above copyright notice and this permission notice shall be included
     17 * in all copies or substantial portions of the Software.
    1518 *
    16  * kBuild is distributed in the hope that it will be useful,
    17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    19  * GNU General Public License for more details.
     19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     25 * IN THE SOFTWARE.
    2026 *
    21  * You should have received a copy of the GNU General Public License
    22  * along with kBuild.  If not, see <http://www.gnu.org/licenses/>
    23  *
     27 * Alternatively, the content of this file may be used under the terms of the
     28 * GPL version 2 or later, or LGPL version 2.1 or later.
    2429 */
     30
    2531
    2632#ifndef ___kDep_h
  • trunk/src/lib/kbuild_version.c

    r2844 r2851  
    55
    66/*
    7  * Copyright (c) 2007-2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
     7 * Copyright (c) 2007-2013 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
    88 *
    9  * This file is part of kBuild.
     9 * Permission is hereby granted, free of charge, to any person obtaining a
     10 * copy of this software and associated documentation files (the "Software"),
     11 * to deal in the Software without restriction, including without limitation
     12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     13 * and/or sell copies of the Software, and to permit persons to whom the
     14 * Software is furnished to do so, subject to the following conditions:
    1015 *
    11  * kBuild is free software; you can redistribute it and/or modify
    12  * it under the terms of the GNU General Public License as published by
    13  * the Free Software Foundation; either version 3 of the License, or
    14  * (at your option) any later version.
     16 * The above copyright notice and this permission notice shall be included
     17 * in all copies or substantial portions of the Software.
    1518 *
    16  * kBuild is distributed in the hope that it will be useful,
    17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    19  * GNU General Public License for more details.
     19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     25 * IN THE SOFTWARE.
    2026 *
    21  * You should have received a copy of the GNU General Public License
    22  * along with kBuild.  If not, see <http://www.gnu.org/licenses/>
    23  *
     27 * Alternatively, the content of this file may be used under the terms of the
     28 * GPL version 2 or later, or LGPL version 2.1 or later.
    2429 */
    2530
  • trunk/src/lib/kbuild_version.h

    r2844 r2851  
    55
    66/*
    7  * Copyright (c) 2007-2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
     7 * Copyright (c) 2007-2013 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
    88 *
    9  * This file is part of kBuild.
     9 * Permission is hereby granted, free of charge, to any person obtaining a
     10 * copy of this software and associated documentation files (the "Software"),
     11 * to deal in the Software without restriction, including without limitation
     12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     13 * and/or sell copies of the Software, and to permit persons to whom the
     14 * Software is furnished to do so, subject to the following conditions:
    1015 *
    11  * kBuild is free software; you can redistribute it and/or modify
    12  * it under the terms of the GNU General Public License as published by
    13  * the Free Software Foundation; either version 3 of the License, or
    14  * (at your option) any later version.
     16 * The above copyright notice and this permission notice shall be included
     17 * in all copies or substantial portions of the Software.
    1518 *
    16  * kBuild is distributed in the hope that it will be useful,
    17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    19  * GNU General Public License for more details.
     19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     25 * IN THE SOFTWARE.
    2026 *
    21  * You should have received a copy of the GNU General Public License
    22  * along with kBuild.  If not, see <http://www.gnu.org/licenses/>
    23  *
     27 * Alternatively, the content of this file may be used under the terms of the
     28 * GPL version 2 or later, or LGPL version 2.1 or later.
    2429 */
    2530
  • trunk/src/lib/mytypes.h

    r2442 r2851  
    55
    66/*
    7  * Copyright (c) 2007-2010 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
     7 * Copyright (c) 2007-2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
    88 *
    9  * This file is part of kBuild.
     9 * Permission is hereby granted, free of charge, to any person obtaining a
     10 * copy of this software and associated documentation files (the "Software"),
     11 * to deal in the Software without restriction, including without limitation
     12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     13 * and/or sell copies of the Software, and to permit persons to whom the
     14 * Software is furnished to do so, subject to the following conditions:
    1015 *
    11  * kBuild is free software; you can redistribute it and/or modify
    12  * it under the terms of the GNU General Public License as published by
    13  * the Free Software Foundation; either version 3 of the License, or
    14  * (at your option) any later version.
     16 * The above copyright notice and this permission notice shall be included
     17 * in all copies or substantial portions of the Software.
    1518 *
    16  * kBuild is distributed in the hope that it will be useful,
    17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    19  * GNU General Public License for more details.
     19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     25 * IN THE SOFTWARE.
    2026 *
    21  * You should have received a copy of the GNU General Public License
    22  * along with kBuild.  If not, see <http://www.gnu.org/licenses/>
    23  *
     27 * Alternatively, the content of this file may be used under the terms of the
     28 * GPL version 2 or later, or LGPL version 2.1 or later.
    2429 */
    2530
    26 #ifndef ___mytypes_h__
    27 #define ___mytypes_h__
     31#ifndef ___mytypes_h___
     32#define ___mytypes_h___
    2833
    2934#include <stdlib.h>
  • trunk/src/lib/nt/ntdircache.c

    r2850 r2851  
    11/* $Id$ */
    22/** @file
    3  * kWorker - experimental process reuse worker for Windows.
    4  *
    5  * Note! This module must be linked statically in order to avoid
    6  *       accidentally intercepting our own CRT calls.
     3 * ntdircache.c - NT directory content cache.
    74 */
    85
     
    107 * Copyright (c) 2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
    118 *
    12  * This file is part of kBuild.
    13  *
    14  * kBuild is free software; you can redistribute it and/or modify
    15  * it under the terms of the GNU General Public License as published by
    16  * the Free Software Foundation; either version 3 of the License, or
    17  * (at your option) any later version.
    18  *
    19  * kBuild is distributed in the hope that it will be useful,
    20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    22  * GNU General Public License for more details.
    23  *
    24  * You should have received a copy of the GNU General Public License
    25  * along with kBuild.  If not, see <http://www.gnu.org/licenses/>
    26  *
     9 * Permission is hereby granted, free of charge, to any person obtaining a
     10 * copy of this software and associated documentation files (the "Software"),
     11 * to deal in the Software without restriction, including without limitation
     12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     13 * and/or sell copies of the Software, and to permit persons to whom the
     14 * Software is furnished to do so, subject to the following conditions:
     15 *
     16 * The above copyright notice and this permission notice shall be included
     17 * in all copies or substantial portions of the Software.
     18 *
     19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     25 * IN THE SOFTWARE.
     26 *
     27 * Alternatively, the content of this file may be used under the terms of the
     28 * GPL version 2 or later, or LGPL version 2.1 or later.
    2729 */
    2830
     
    3234*********************************************************************************************************************************/
    3335#include <k/kHlp.h>
    34 #include <k/kLdr.h>
     36
     37#include "nthlp.h"
     38#include "ntstat.h"
    3539
    3640#include <stdio.h>
    37 #include <intrin.h>
    38 #include <setjmp.h>
    39 #include <ctype.h>
    40 
    41 #include "nt/ntstat.h"
    42 #include "kbuild_version.h"
    43 /* lib/nt_fullpath.c */
    44 extern void nt_fullpath(const char *pszPath, char *pszFull, size_t cchFull);
    45 
    46 #include <Windows.h>
    47 #include <winternl.h>
     41//#include <intrin.h>
     42//#include <setjmp.h>
     43//#include <ctype.h>
     44
     45
     46//#include <Windows.h>
     47//#include <winternl.h>
    4848
    4949
     
    5252*   Defined Constants And Macros                                                                                                 *
    5353*********************************************************************************************************************************/
    54 /** Special KWFSOBJ::uCacheGen number indicating that it does not apply. */
    55 #define KFSWOBJ_CACHE_GEN_IGNORE        KU32_MAX
    56 
    57 /** String constant comma length.   */
    58 #define TUPLE(a_sz)                     a_sz, sizeof(a_sz) - 1
     54/** @def KFSCACHE_CFG_UTF16
     55 * Whether to compile in the UTF-16 names support. */
     56#define KFSCACHE_CFG_UTF16                  1
     57/** @def KFSCACHE_CFG_SHORT_NAMES
     58 * Whether to compile in the short name support. */
     59#define KFSCACHE_CFG_SHORT_NAMES            1
     60/** @def KFSCACHE_CFG_PATH_HASH_TAB_SIZE
     61 * Size of the path hash table. */
     62#define KFSCACHE_CFG_PATH_HASH_TAB_SIZE     16381
     63/** The max length paths we consider. */
     64#define KFSCACHE_CFG_MAX_PATH               1024
     65/** The max ANSI name length. */
     66#define KFSCACHE_CFG_MAX_ANSI_NAME          (256*3 + 16)
     67/** The max UTF-16 name length. */
     68#define KFSCACHE_CFG_MAX_UTF16_NAME         (256*2 + 16)
     69
     70
     71
     72/** Special KFSOBJ::uCacheGen number indicating that it does not apply. */
     73#define KFSWOBJ_CACHE_GEN_IGNORE            KU32_MAX
    5974
    6075/** @def KW_LOG
    6176 * Generic logging.
    62  * @param a     Argument list for kwDbgPrintf  */
     77 * @param a     Argument list for kFsCacheDbgPrintf  */
    6378#ifndef NDEBUG
    64 # define KW_LOG(a) kwDbgPrintf a
     79# define KFSCACHE_LOG(a) kFsCacheDbgPrintf a
    6580#else
    66 # define KW_LOG(a) do { } while (0)
    67 #endif
    68 
    69 
    70 /** @def KWFS_LOG
    71  * FS cache logging.
    72  * @param a     Argument list for kwDbgPrintf  */
    73 #ifndef NDEBUG
    74 # define KWFS_LOG(a) kwDbgPrintf a
    75 #else
    76 # define KWFS_LOG(a) do { } while (0)
    77 #endif
    78 
    79 /** Converts a windows handle to a handle table index.
    80  * @note We currently just mask off the 31th bit, and do no shifting or anything
    81  *     else to create an index of the handle.
    82  * @todo consider shifting by 2 or 3. */
    83 #define KW_HANDLE_TO_INDEX(a_hHandle)   ((KUPTR)(a_hHandle) & ~(KUPTR)KU32_C(0x8000000))
    84 /** Maximum handle value we can deal with.   */
    85 #define KW_HANDLE_MAX                   0x20000
    86 
    87 /** @def WITH_TEMP_MEMORY_FILES
    88  * Enables temporary memory files for cl.exe.  */
    89 #define WITH_TEMP_MEMORY_FILES
    90 
    91 /** Max temporary file size (memory backed).  */
    92 #if K_ARCH_BITS >= 64
    93 # define KWFS_TEMP_FILE_MAX             (256*1024*1024)
    94 #else
    95 # define KWFS_TEMP_FILE_MAX             (64*1024*1024)
    96 #endif
     81# define KFSCACHE_LOG(a) do { } while (0)
     82#endif
     83
     84
     85/** @name KFSOBJ_TYPE_XXX - KFSOBJ::bObjType
     86 * @{  */
     87/** Directory, type KFSDIR. */
     88#define KFSOBJ_TYPE_DIR         KU8_C(0x01)
     89/** Regular file - type KFSOBJ. */
     90#define KFSOBJ_TYPE_FILE        KU8_C(0x02)
     91/** Other file - type KFSOBJ. */
     92#define KFSOBJ_TYPE_OTHER       KU8_C(0x03)
     93/** Caching of a negative result - type KFSOBJ.
     94 * @remarks We will allocate enough space for the largest cache node, so this
     95 *          can metamorph into any other object should it actually turn up.  */
     96#define KFSOBJ_TYPE_MISSING     KU8_C(0x04)
     97///** Invalidated entry flag. */
     98//#define KFSOBJ_TYPE_F_INVALID   KU8_C(0x20)
     99/** @} */
     100
     101/** @name KFSOBJ_F_XXX - KFSOBJ::fFlags
     102 * @{ */
     103/** Whether the file system update the modified timestamp of directories
     104 * when something is removed from it or added to it.
     105 * @remarks They say NTFS is the only windows filesystem doing this.  */
     106#define KFSOBJ_F_WORKING_DIR_MTIME      KU32_C(0x00000001)
     107/** NTFS file system volume. */
     108#define KFSOBJ_F_NTFS                   KU32_C(0x80000000)
     109/** @} */
     110
     111
     112#define IS_ALPHA(ch) ( ((ch) >= 'A' && (ch) <= 'Z') || ((ch) >= 'a' && (ch) <= 'z') )
     113#define IS_SLASH(ch) ((ch) == '\\' || (ch) == '/')
    97114
    98115
     
    100117*   Structures and Typedefs                                                                                                      *
    101118*********************************************************************************************************************************/
    102 typedef enum KWLOCATION
    103 {
    104     KWLOCATION_INVALID = 0,
    105     KWLOCATION_EXE_DIR,
    106     KWLOCATION_IMPORTER_DIR,
    107     KWLOCATION_SYSTEM32,
    108     KWLOCATION_UNKNOWN_NATIVE,
    109     KWLOCATION_UNKNOWN,
    110 } KWLOCATION;
    111 
    112 typedef enum KWMODSTATE
    113 {
    114     KWMODSTATE_INVALID = 0,
    115     KWMODSTATE_NEEDS_BITS,
    116     KWMODSTATE_NEEDS_INIT,
    117     KWMODSTATE_BEING_INITED,
    118     KWMODSTATE_INIT_FAILED,
    119     KWMODSTATE_READY,
    120 } KWMODSTATE;
    121 
    122 typedef struct KWMODULE *PKWMODULE;
    123 typedef struct KWMODULE
    124 {
    125     /** Pointer to the next image. */
    126     PKWMODULE           pNext;
    127     /** The normalized path to the image. */
    128     const char         *pszPath;
    129     /** The hash of the program path. */
    130     KU32                uHashPath;
     119/** Pointer to a core object.  */
     120typedef struct KFSOBJ *PKFSOBJ;
     121/** Pointer to a directory object.  */
     122typedef struct KFSDIR *PKFSDIR;
     123/** Pointer to a directory hash table entry. */
     124typedef struct KFSOBJHASH *PKFSOBJHASH;
     125
     126
     127/**
     128 * Directory hash table entry.
     129 *
     130 * There can be two of these per directory entry when the short name differs
     131 * from the long name.
     132 */
     133typedef struct KFSOBJHASH
     134{
     135    /** Pointer to the next entry with the same hash. */
     136    PKFSOBJHASH         pNext;
     137    /** Pointer to the object. */
     138    PKFSOBJ             pObj;
     139} KFSOBJHASH;
     140
     141
     142/**
     143 * Base cache node.
     144 */
     145typedef struct KFSOBJ
     146{
     147    /** Magic value (KFSOBJ_MAGIC). */
     148    KU32                u32Magic;
    131149    /** Number of references. */
    132     KU32                cRefs;
    133     /** UTF-16 version of pszPath. */
    134     const wchar_t      *pwszPath;
    135     /** The offset of the filename in pszPath. */
    136     KU16                offFilename;
    137     /** Set if executable. */
    138     KBOOL               fExe;
    139     /** Set if native module entry. */
    140     KBOOL               fNative;
    141     /** Loader module handle. */
    142     PKLDRMOD            pLdrMod;
    143     /** The windows module handle. */
    144     HMODULE             hOurMod;
    145 
    146     union
    147     {
    148         /** Data for a manually loaded image. */
    149         struct
    150         {
    151             /** The of the loaded image bits. */
    152             KSIZE               cbImage;
    153             /** Where we load the image. */
    154             void               *pvLoad;
    155             /** Virgin copy of the image. */
    156             void               *pvCopy;
    157             /** Ldr pvBits argument.  This is NULL till we've successfully resolved
    158              *  the imports. */
    159             void               *pvBits;
    160             /** The state. */
    161             KWMODSTATE          enmState;
    162             /** Number of imported modules. */
    163             KSIZE               cImpMods;
    164             /** Import array (variable size). */
    165             PKWMODULE           apImpMods[1];
    166         } Manual;
    167     } u;
    168 } KWMODULE;
    169 
    170 
    171 typedef struct KWDYNLOAD *PKWDYNLOAD;
    172 typedef struct KWDYNLOAD
    173 {
    174     /** Pointer to the next in the list. */
    175     PKWDYNLOAD          pNext;
    176 
    177     /** The normalized path to the image. */
    178     const char         *pszPath;
    179     /** The module name (within pszPath). */
    180     const char         *pszModName;
    181     /** UTF-16 version of pszPath. */
    182     const wchar_t      *pwszPath;
    183     /** The hash of the path. */
    184     KU32                uHashPath;
    185 
    186     /** The module handle we present to the application.
    187      * This is the LoadLibraryEx return value for special modules and the
    188      * KWMODULE.hOurMod value for the others. */
    189     HMODULE             hmod;
    190 
    191     /** The module for non-special resource stuff, NULL if special. */
    192     PKWMODULE           pMod;
    193 } KWDYNLOAD;
    194 
    195 
    196 typedef struct KWFSOBJ *PKWFSOBJ;
    197 typedef struct KWFSOBJ
    198 {
    199     /** The object name.  (Allocated after the structure.) */
     150    KU32 volatile       cRefs;
     151    /** The cache generation, see KFSWOBJ_CACHE_GEN_IGNORE. */
     152    KU32                uCacheGen;
     153    /** The object type, KFSOBJ_TYPE_XXX.   */
     154    KU8                 bObjType;
     155    /** Set if the Stats member is valid, clear if not. */
     156    KBOOL               fHaveStats;
     157    /** Unused flags. */
     158    KBOOL               abUnused[2];
     159    /** Flags, KFSOBJ_F_XXX. */
     160    KU32                fFlags;
     161
     162    /** Pointer to the parent (directory).
     163     * This is only NULL for a root. */
     164    PKFSDIR             pParent;
     165
     166    /** The directory name.  (Allocated after the structure.) */
    200167    const char         *pszName;
     168    /** The length of pszName. */
     169    KU16                cchName;
     170    /** The length of the parent path (up to where pszName starts).
     171     * @note This is valuable when constructing an absolute path to this node by
     172     *       means of the parent pointer (no need for recursion). */
     173    KU16                cchParent;
     174#ifdef KFSCACHE_CFG_UTF16
     175    /** The length of pwszName (in wchar_t's). */
     176    KU16                cwcName;
     177    /** The length of the parent UTF-16 path (in wchar_t's).
     178     * @note This is valuable when constructing an absolute path to this node by
     179     *       means of the parent pointer (no need for recursion). */
     180    KU16                cwcParent;
    201181    /** The UTF-16 object name.  (Allocated after the structure.) */
    202182    const wchar_t      *pwszName;
    203     /** The length of pszName. */
    204     KU16                cchName;
    205     /** The length of UTF-16 (in wchar_t's). */
    206     KU16                cwcName;
    207 
     183#endif
     184
     185#ifdef KFSCACHE_CFG_SHORT_NAMES
     186    /** The short object name.  (Allocated after the structure, could be same
     187     *  as pszName.) */
     188    const char         *pszShortName;
     189    /** The length of pszShortName. */
     190    KU16                cchShortName;
     191    /** The length of the short parent path (up to where pszShortName starts). */
     192    KU16                cchShortParent;
     193# ifdef KFSCACHE_CFG_UTF16
     194    /** The length of pwszShortName (in wchar_t's). */
     195    KU16                cwcShortName;
     196    /** The length of the short parent UTF-16 path (in wchar_t's). */
     197    KU16                cwcShortParent;
     198    /** The UTF-16 short object name.  (Allocated after the structure, possibly
     199     *  same as pwszName.) */
     200    const wchar_t      *pwszShortName;
     201# endif
     202#endif
     203
     204    /** Stats - only valid when fHaveStats is set. */
     205    BirdStat_T          Stats;
     206} KFSOBJ;
     207
     208/** The magic for a KFSOBJ structure (Thelonious Sphere Monk). */
     209#define KFSOBJ_MAGIC                KU32_C(0x19171010)
     210
     211
     212/**
     213 * Directory node in the cache.
     214 */
     215typedef struct KFSDIR
     216{
     217    /** The core object information. */
     218    KFSOBJ             Obj;
     219
     220    /** Child objects. */
     221    PKFSOBJ            *papChildren;
    208222    /** The number of child objects. */
    209223    KU32                cChildren;
    210     /** Child objects. */
    211     PKWFSOBJ           *papChildren;
    212     /** Pointer to the parent. */
    213     PKWFSOBJ            pParent;
    214 
    215     /** The cache generation, KFSWOBJ_CACHE_GEN_IGNORE. */
    216     KU32                uCacheGen;
    217     /** The GetFileAttributes result for the file.
    218      * FILE_ATTRIBUTE_XXX or INVALID_FILE_ATTRIBUTES. */
    219     KU32                fAttribs;
    220     /** The GetLastError() for INVALI_FILE_ATTRIBUTES. */
    221     KU32                uLastError;
    222 
    223     /** Cached file handle. */
    224     HANDLE              hCached;
    225     /** The file size. */
    226     KU32                cbCached;
    227     /** Cached file content. */
    228     KU8                *pbCached;
    229 } KWFSOBJ;
     224
     225    /** The size of the hash table.
     226     * @remarks The hash table is optional and only used when there are a lot of
     227     *          entries in the directory. */
     228    KU32                cHashTab;
     229    /** Pointer to the hash table.
     230     * @todo this isn't quite there yet, structure wise. sigh.  */
     231    PKFSOBJHASH         paHashTab;
     232
     233    /** Handle to the directory (we generally keep it open). */
     234    HANDLE              hDir;
     235    /** The device number we queried/inherited when opening it. */
     236    KU64                uDevNo;
     237
     238    /** Set if populated. */
     239    KBOOL               fPopulated;
     240} KFSDIR;
     241
     242
     243/**
     244 * Lookup errors.
     245 */
     246typedef enum KFSLOOKUPERROR
     247{
     248    /** Lookup was a success. */
     249    KFSLOOKUPERROR_SUCCESS = 0,
     250    /** A path component was not found. */
     251    KFSLOOKUPERROR_PATH_COMP_NOT_FOUND,
     252    /** A path component is not a directory. */
     253    KFSLOOKUPERROR_PATH_COMP_NOT_DIR,
     254    /** The final path entry is not a directory (trailing slash). */
     255    KFSLOOKUPERROR_NOT_DIR,
     256    /** Not found. */
     257    KFSLOOKUPERROR_NOT_FOUND,
     258    /** The path is too long. */
     259    KFSLOOKUPERROR_PATH_TOO_LONG,
     260    /** Unsupported path type. */
     261    KFSLOOKUPERROR_UNSUPPORTED,
     262    /** We're out of memory. */
     263    KFSLOOKUPERROR_OUT_OF_MEMORY,
     264
     265    /** Error opening directory. */
     266    KFSLOOKUPERROR_DIR_OPEN_ERROR,
     267    /** Error reading directory. */
     268    KFSLOOKUPERROR_DIR_READ_ERROR,
     269    /** UTF-16 to ANSI conversion error. */
     270    KFSLOOKUPERROR_ANSI_CONVERSION_ERROR,
     271    /** ANSI to UTF-16 conversion error. */
     272    KFSLOOKUPERROR_UTF16_CONVERSION_ERROR,
     273    /** Internal error. */
     274    KFSLOOKUPERROR_INTERNAL_ERROR
     275} KFSLOOKUPERROR;
    230276
    231277
    232278/** Pointer to an ANSI path hash table entry. */
    233 typedef struct KWFSHASHA *PKWFSHASHA;
     279typedef struct KFSHASHA *PKFSHASHA;
    234280/**
    235281 * ANSI file system path hash table entry.
    236282 * The path hash table allows us to skip parsing and walking a path.
    237283 */
    238 typedef struct KWFSHASHA
     284typedef struct KFSHASHA
    239285{
    240286    /** Next entry with the same hash table slot. */
    241     PKWFSHASHA          pNext;
     287    PKFSHASHA           pNext;
    242288    /** Path hash value. */
    243289    KU32                uHashPath;
    244290    /** The path length. */
    245291    KU32                cchPath;
     292    /** The cache generation ID. */
     293    KU32                uCacheGen;
     294    /** The lookup error (when pFsObj is NULL). */
     295    KFSLOOKUPERROR      enmError;
    246296    /** The path.  (Allocated after the structure.) */
    247297    const char         *pszPath;
    248     /** Pointer to the matching FS object. */
    249     PKWFSOBJ            pFsObj;
    250 } KWFSHASHA;
    251 
    252 
     298    /** Pointer to the matching FS object.
     299     * This is NULL for negative path entries? */
     300    PKFSOBJ             pFsObj;
     301} KFSHASHA;
     302
     303
     304#ifdef KFSCACHE_CFG_UTF16
    253305/** Pointer to an UTF-16 path hash table entry. */
    254 typedef struct KWFSHASHW *PKWFSHASHW;
     306typedef struct KFSHASHW *PKFSHASHW;
    255307/**
    256308 * UTF-16 file system path hash table entry. The path hash table allows us
    257309 * to skip parsing and walking a path.
    258310 */
    259 typedef struct KWFSHASHW
     311typedef struct KFSHASHW
    260312{
    261313    /** Next entry with the same hash table slot. */
    262     PKWFSHASHW          pNext;
     314    PKFSHASHW           pNext;
    263315    /** Path hash value. */
    264316    KU32                uHashPath;
    265317    /** The path length (in wchar_t units). */
    266318    KU32                cwcPath;
     319    /** The cache generation ID. */
     320    KU32                uCacheGen;
     321    /** The lookup error (when pFsObj is NULL). */
     322    KFSLOOKUPERROR      enmError;
    267323    /** The path.  (Allocated after the structure.) */
    268324    const wchar_t      *pwszPath;
    269     /** Pointer to the matching FS object. */
    270     PKWFSOBJ            pFsObj;
    271 } KWFSHASHW;
    272 
    273 
    274 
    275 /** Pointer to a normalized path hash table entry. */
    276 typedef struct KWFSNORMHASHA *PKWFSNORMHASHA;
    277 /**
    278  * Normalized path hash table entry.
    279  *
    280  * Note! This looks like it's duplicating KWFSHASHW/KWFSHASHA/KWFSOBJ, but
    281  *       it also handles paths that not cachable.
    282  */
    283 typedef struct KWFSNORMHASHA
    284 {
    285     /** Next entry with the same hash table slot. */
    286     PKWFSNORMHASHA      pNext;
    287     /** The input path. */
    288     const char         *pszPath;
    289     /** The length of the input path. */
    290     KU16                cchPath;
    291     /** The length of the normalized path. */
    292     KU16                cchNormPath;
    293     /** The hash. */
    294     KU32                uHashPath;
    295     /** The normalized path (variable size). */
    296     char                szNormPath[1];
    297 } KWFSNORMHASHA;
    298 
    299 
    300 typedef struct KWFSTEMPFILESEG *PKWFSTEMPFILESEG;
    301 typedef struct KWFSTEMPFILESEG
    302 {
    303     /** File offset of data. */
    304     KU32                offData;
    305     /** The size of the buffer pbData points to. */
    306     KU32                cbDataAlloc;
    307     /** The segment data. */
    308     KU8                *pbData;
    309 } KWFSTEMPFILESEG;
    310 
    311 typedef struct KWFSTEMPFILE *PKWFSTEMPFILE;
    312 typedef struct KWFSTEMPFILE
    313 {
    314     /** Pointer to the next temporary file for this run. */
    315     PKWFSTEMPFILE       pNext;
    316     /** The UTF-16 path. (Allocated after this structure.)  */
    317     const wchar_t      *pwszPath;
    318     /** The path length. */
    319     KU16                cwcPath;
    320     /** Number of active handles using this file/mapping (<= 2). */
    321     KU8                 cActiveHandles;
    322     /** Number of active mappings (mapped views) (0 or 1). */
    323     KU8                 cMappings;
    324     /** The amount of space allocated in the segments. */
    325     KU32                cbFileAllocated;
    326     /** The current file size. */
    327     KU32                cbFile;
    328     /** The number of segments. */
    329     KU32                cSegs;
    330     /** Segments making up the file. */
    331     PKWFSTEMPFILESEG    paSegs;
    332 } KWFSTEMPFILE;
    333 
    334 
    335 /** Handle type.   */
    336 typedef enum KWHANDLETYPE
    337 {
    338     KWHANDLETYPE_INVALID = 0,
    339     KWHANDLETYPE_FSOBJ_READ_CACHE,
    340     KWHANDLETYPE_TEMP_FILE,
    341     KWHANDLETYPE_TEMP_FILE_MAPPING
    342     //KWHANDLETYPE_CONSOLE_CACHE
    343 } KWHANDLETYPE;
    344 
    345 /** Handle data. */
    346 typedef struct KWHANDLE
    347 {
    348     KWHANDLETYPE        enmType;
    349     /** The current file offset. */
    350     KU32                offFile;
    351     /** Handle access. */
    352     KU32                dwDesiredAccess;
    353     /** The handle. */
    354     HANDLE              hHandle;
    355 
    356     /** Type specific data. */
    357     union
    358     {
    359         /** The file system object.   */
    360         PKWFSOBJ            pFsObj;
    361         /** Temporary file handle or mapping handle. */
    362         PKWFSTEMPFILE       pTempFile;
    363     } u;
    364 } KWHANDLE;
    365 typedef KWHANDLE *PKWHANDLE;
    366 
    367 
    368 typedef enum KWTOOLTYPE
    369 {
    370     KWTOOLTYPE_INVALID = 0,
    371     KWTOOLTYPE_SANDBOXED,
    372     KWTOOLTYPE_WATCOM,
    373     KWTOOLTYPE_EXEC,
    374     KWTOOLTYPE_END
    375 } KWTOOLTYPE;
    376 
    377 typedef enum KWTOOLHINT
    378 {
    379     KWTOOLHINT_INVALID = 0,
    380     KWTOOLHINT_NONE,
    381     KWTOOLHINT_VISUAL_CPP_CL,
    382     KWTOOLHINT_END
    383 } KWTOOLHINT;
    384 
    385 typedef struct KWTOOL *PKWTOOL;
    386 typedef struct KWTOOL
    387 {
    388     /** Pointer to the next in the hash collision chain. */
    389     PKWTOOL             pNext;
    390     /** The normalized path to the program. */
    391     const char         *pszPath;
    392     /** The hash of the program path. */
    393     KU32                uHashPath;
    394     /** The kind of tool. */
    395     KWTOOLTYPE          enmType;
    396     /** UTF-16 version of pszPath. */
    397     wchar_t const      *pwszPath;
    398 
    399     union
    400     {
    401         struct
    402         {
    403             /** The executable. */
    404             PKWMODULE   pExe;
    405             /** List of dynamically loaded modules.
    406              * These will be kept loaded till the tool is destroyed (if we ever do that). */
    407             PKWDYNLOAD  pDynLoadHead;
    408             /** Tool hint (for hacks and such). */
    409             KWTOOLHINT  enmHint;
    410         } Sandboxed;
    411     } u;
    412 } KWTOOL;
    413 
    414 
    415 typedef struct KWSANDBOX *PKWSANDBOX;
    416 typedef struct KWSANDBOX
    417 {
    418     /** The tool currently running in the sandbox. */
    419     PKWTOOL     pTool;
    420     /** Jump buffer. */
    421     jmp_buf     JmpBuf;
    422     /** The thread ID of the main thread (owner of JmpBuf). */
    423     DWORD       idMainThread;
    424     /** Copy of the NT TIB of the main thread. */
    425     NT_TIB      TibMainThread;
    426     /** The exit code in case of longjmp.   */
    427     int         rcExitCode;
    428 
    429     /** The command line.   */
    430     char       *pszCmdLine;
    431     /** The UTF-16 command line. */
    432     wchar_t    *pwszCmdLine;
    433     /** Number of arguments in papszArgs. */
    434     int         cArgs;
    435     /** The argument vector. */
    436     char      **papszArgs;
    437     /** The argument vector. */
    438     wchar_t   **papwszArgs;
    439 
    440     /** The _pgmptr msvcrt variable.  */
    441     char       *pgmptr;
    442     /** The _wpgmptr msvcrt variable. */
    443     wchar_t    *wpgmptr;
    444 
    445     /** The _initenv msvcrt variable. */
    446     char      **initenv;
    447     /** The _winitenv msvcrt variable. */
    448     wchar_t   **winitenv;
    449 
    450     /** The _environ msvcrt variable. */
    451     char      **environ;
    452     /** The _wenviron msvcrt variable. */
    453     wchar_t   **wenviron;
    454 
    455 
    456     /** Handle table. */
    457     PKWHANDLE      *papHandles;
    458     /** Size of the handle table. */
    459     KU32            cHandles;
    460     /** Number of active handles in the table. */
    461     KU32            cActiveHandles;
    462 
    463     /** Head of the list of temporary file. */
    464     PKWFSTEMPFILE   pTempFileHead;
    465 
    466     UNICODE_STRING  SavedCommandLine;
    467 } KWSANDBOX;
    468 
    469 /** Replacement function entry. */
    470 typedef struct KWREPLACEMENTFUNCTION
    471 {
    472     /** The function name. */
    473     const char *pszFunction;
    474     /** The length of the function name. */
    475     KSIZE       cchFunction;
    476     /** The module name (optional). */
    477     const char *pszModule;
    478     /** The replacement function or data address. */
    479     KUPTR       pfnReplacement;
    480 } KWREPLACEMENTFUNCTION;
    481 typedef KWREPLACEMENTFUNCTION const *PCKWREPLACEMENTFUNCTION;
    482 
    483 #if 0
    484 /** Replacement function entry. */
    485 typedef struct KWREPLACEMENTDATA
    486 {
    487     /** The function name. */
    488     const char *pszFunction;
    489     /** The length of the function name. */
    490     KSIZE       cchFunction;
    491     /** The module name (optional). */
    492     const char *pszModule;
    493     /** Function providing the replacement. */
    494     KUPTR     (*pfnMakeReplacement)(PKWMODULE pMod, const char *pchSymbol, KSIZE cchSymbol);
    495 } KWREPLACEMENTDATA;
    496 typedef KWREPLACEMENTDATA const *PCKWREPLACEMENTDATA;
    497 #endif
    498 
    499 
    500 /*********************************************************************************************************************************
    501 *   Global Variables                                                                                                             *
    502 *********************************************************************************************************************************/
    503 /** The sandbox data. */
    504 static KWSANDBOX    g_Sandbox;
    505 
    506 /** Module hash table. */
    507 static PKWMODULE    g_apModules[127];
    508 
    509 /** Tool hash table. */
    510 static PKWTOOL      g_apTools[63];
    511 
    512 /** Special file system root (parent to the drive letters). */
    513 static KWFSOBJ      g_FsRoot =
    514 {
    515     /* .pszName     = */ "",
    516     /* .pwszName    = */ L"",
    517     /* .cchName     = */ 0,
    518     /* .cwcName     = */ 0,
    519     /* .cChildren   = */ 0,
    520     /* .papChildren = */ NULL,
    521     /* .pParent     = */ NULL,
    522     /* .uCacheGen   = */ KFSWOBJ_CACHE_GEN_IGNORE,
    523     /* .fAttribs    = */ FILE_ATTRIBUTE_DIRECTORY,
    524     /* .uLastError  = */ ERROR_PATH_NOT_FOUND,
    525     /* .hCached     = */ INVALID_HANDLE_VALUE,
    526     /* .cbCached    = */ 0,
    527     /* .pbCached    = */ NULL,
    528 };
    529 /** File system hash table for ANSI filename strings. */
    530 static PKWFSHASHA   g_apFsAnsiPaths[1021];
    531 /** File system hash table for UTF-16 filename strings. */
    532 static PKWFSHASHW   g_apFsUtf16Paths[1021];
    533 /** Cached normalized path results. */
    534 static PKWFSNORMHASHA g_apFsNormalizedPathsA[1021];
    535 /** Special file system object returned if the path is invalid. */
    536 static KWFSOBJ      g_FsPathNotFound =
    537 {
    538     /* .pszName     = */ "",
    539     /* .pwszName    = */ L"",
    540     /* .cchName     = */ 0,
    541     /* .cwcName     = */ 0,
    542     /* .cChildren   = */ 0,
    543     /* .papChildren = */ NULL,
    544     /* .pParent     = */ NULL,
    545     /* .uCacheGen   = */ KFSWOBJ_CACHE_GEN_IGNORE,
    546     /* .fAttribs    = */ FILE_ATTRIBUTE_DIRECTORY,
    547     /* .uLastError  = */ ERROR_PATH_NOT_FOUND,
    548     /* .hCached     = */ INVALID_HANDLE_VALUE,
    549     /* .cbCached    = */ 0,
    550     /* .pbCached    = */ NULL,
    551 };
    552 /** The cache generation number, incremented for each sandboxed execution.
    553  * This is used to invalid negative results from parts of the file system. */
    554 static KU32         g_uFsCacheGeneration = 0;
    555 
    556 /** Verbosity level. */
    557 static int          g_cVerbose = 2;
    558 
    559 /** Whether we should restart the worker. */
    560 static KBOOL        g_fRestart = K_FALSE;
    561 
    562 /* Further down. */
    563 extern KWREPLACEMENTFUNCTION const g_aSandboxReplacements[];
    564 extern KU32                  const g_cSandboxReplacements;
    565 
    566 extern KWREPLACEMENTFUNCTION const g_aSandboxNativeReplacements[];
    567 extern KU32                  const g_cSandboxNativeReplacements;
    568 
    569 /** Create a larget BSS blob that with help of /IMAGEBASE:0x10000 should
    570  * cover the default executable link address of 0x400000. */
    571 #pragma section("DefLdBuf", write, execute, read)
    572 __declspec(allocate("DefLdBuf"))
    573 static KU8          g_abDefLdBuf[16*1024*1024];
    574 
     325    /** Pointer to the matching FS object.
     326     * This is NULL for negative path entries? */
     327    PKFSOBJ             pFsObj;
     328} KFSHASHW;
     329#endif
     330
     331
     332/** @name KFSCACHE_F_XXX
     333 * @{ */
     334/** Whether to cache missing directory entries (KFSOBJ_TYPE_MISSING). */
     335#define KFSCACHE_F_MISSING_OBJECTS  KU32_C(0x00000001)
     336/** Whether to cache missing paths. */
     337#define KFSCACHE_F_MISSING_PATHS    KU32_C(0x00000002)
     338/** @} */
     339
     340
     341/** Pointer to a cache.   */
     342typedef struct KFSCACHE *PKFSCACHE;
     343/**
     344 * Directory cache instance.
     345 */
     346typedef struct KFSCACHE
     347{
     348    /** Magic value (KFSCACHE_MAGIC). */
     349    KU32                u32Magic;
     350    /** Cache flags. */
     351    KU32                fFlags;
     352
     353    /** The current cache generation for objects that already exists. */
     354    KU32                uGeneration;
     355    /** The current cache generation for missing objects, negative results, ++. */
     356    KU32                uGenerationMissing;
     357
     358    /** Number of cache objects. */
     359    KSIZE               cObjects;
     360    /** Memory occupied by the cache object structures. */
     361    KSIZE               cbObjects;
     362    /** Number of lookups. */
     363    KSIZE               cLookups;
     364    /** Number of hits in the path hash tables. */
     365    KSIZE               cPathHashHits;
     366    /** Number of hits walking the file system hierarchy. */
     367    KSIZE               cWalkHits;
     368
     369    /** The root directory. */
     370    KFSDIR              RootDir;
     371
     372    /** File system hash table for ANSI filename strings. */
     373    PKFSHASHA           apAnsiPaths[KFSCACHE_CFG_PATH_HASH_TAB_SIZE];
     374    /** Number of paths in the apAnsiPaths hash table. */
     375    KSIZE               cAnsiPaths;
     376    /** Number of collisions in the apAnsiPaths hash table. */
     377    KSIZE               cAnsiPathCollisions;
     378    /** Amount of memory used by the path entries. */
     379    KSIZE               cbAnsiPaths;
     380
     381#ifdef KFSCACHE_CFG_UTF16
     382    /** Number of paths in the apUtf16Paths hash table. */
     383    KSIZE               cUtf16Paths;
     384    /** Number of collisions in the apUtf16Paths hash table. */
     385    KSIZE               cUtf16PathCollisions;
     386    /** Amount of memory used by the UTF-16 path entries. */
     387    KSIZE               cbUtf16Paths;
     388    /** File system hash table for UTF-16 filename strings. */
     389    PKFSHASHW           apUtf16Paths[KFSCACHE_CFG_PATH_HASH_TAB_SIZE];
     390#endif
     391} KFSCACHE;
     392
     393/** Magic value for KFSCACHE::u32Magic (Jon Batiste).  */
     394#define KFSCACHE_MAGIC              KU32_C(0x19861111)
    575395
    576396
     
    578398*   Internal Functions                                                                                                           *
    579399*********************************************************************************************************************************/
    580 static FNKLDRMODGETIMPORT kwLdrModuleGetImportCallback;
    581 static int kwLdrModuleResolveAndLookup(const char *pszName, PKWMODULE pExe, PKWMODULE pImporter, PKWMODULE *ppMod);
    582 static PKWFSOBJ kwFsLookupA(const char *pszPath);
    583 static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle);
    584 
    585 
     400KU32 kFsCacheObjRelease(PKFSCACHE pCache, PKFSOBJ pObj);
     401
     402
     403/**
     404 * Retains a reference to a cache object, internal version.
     405 *
     406 * @returns pObj
     407 * @param   pObj                The object.
     408 */
     409K_INLINE PKFSOBJ kFsCacheObjRetainInternal(PKFSOBJ pObj)
     410{
     411    KU32 cRefs = ++pObj->cRefs;
     412    kHlpAssert(cRefs < 16384);
     413    K_NOREF(cRefs);
     414    return pObj;
     415}
     416
     417
     418#ifndef NDEBUG
    586419
    587420/**
     
    590423 * @param   ...                 Format argument.
    591424 */
    592 static void kwDbgPrintfV(const char *pszFormat, va_list va)
    593 {
    594     if (g_cVerbose >= 2)
     425static void kFsCacheDbgPrintfV(const char *pszFormat, va_list va)
     426{
     427    if (1)
    595428    {
    596429        DWORD const dwSavedErr = GetLastError();
     
    609442 * @param   ...                 Format argument.
    610443 */
    611 static void kwDbgPrintf(const char *pszFormat, ...)
    612 {
    613     if (g_cVerbose >= 2)
     444static void kFsCacheDbgPrintf(const char *pszFormat, ...)
     445{
     446    if (1)
    614447    {
    615448        va_list va;
    616449        va_start(va, pszFormat);
    617         kwDbgPrintfV(pszFormat, va);
     450        kFsCacheDbgPrintfV(pszFormat, va);
    618451        va_end(va);
    619452    }
    620453}
    621454
    622 
    623 /**
    624  * Debugger printing.
    625  * @param   pszFormat           Debug format string.
    626  * @param   ...                 Format argument.
    627  */
    628 static void kwDebuggerPrintfV(const char *pszFormat, va_list va)
    629 {
    630     if (IsDebuggerPresent())
    631     {
    632         DWORD const dwSavedErr = GetLastError();
    633         char szTmp[2048];
    634 
    635         _vsnprintf(szTmp, sizeof(szTmp), pszFormat, va);
    636         OutputDebugStringA(szTmp);
    637 
    638         SetLastError(dwSavedErr);
    639     }
    640 }
    641 
    642 
    643 /**
    644  * Debugger printing.
    645  * @param   pszFormat           Debug format string.
    646  * @param   ...                 Format argument.
    647  */
    648 static void kwDebuggerPrintf(const char *pszFormat, ...)
    649 {
    650     va_list va;
    651     va_start(va, pszFormat);
    652     kwDebuggerPrintfV(pszFormat, va);
    653     va_end(va);
    654 }
    655 
    656 
    657 
    658 /**
    659  * Error printing.
    660  * @param   pszFormat           Message format string.
    661  * @param   ...                 Format argument.
    662  */
    663 static void kwErrPrintfV(const char *pszFormat, va_list va)
    664 {
    665     DWORD const dwSavedErr = GetLastError();
    666 
    667     fprintf(stderr, "kWorker: error: ");
    668     vfprintf(stderr, pszFormat, va);
    669 
    670     SetLastError(dwSavedErr);
    671 }
    672 
    673 
    674 /**
    675  * Error printing.
    676  * @param   pszFormat           Message format string.
    677  * @param   ...                 Format argument.
    678  */
    679 static void kwErrPrintf(const char *pszFormat, ...)
    680 {
    681     va_list va;
    682     va_start(va, pszFormat);
    683     kwErrPrintfV(pszFormat, va);
    684     va_end(va);
    685 }
    686 
    687 
    688 #ifdef K_STRICT
    689 
    690 KHLP_DECL(void) kHlpAssertMsg1(const char *pszExpr, const char *pszFile, unsigned iLine, const char *pszFunction)
    691 {
    692     DWORD const dwSavedErr = GetLastError();
    693 
    694     fprintf(stderr,
    695             "\n"
    696             "!!Assertion failed!!\n"
    697             "Expression: %s\n"
    698             "Function :  %s\n"
    699             "File:       %s\n"
    700             "Line:       %d\n"
    701             ,  pszExpr, pszFunction, pszFile, iLine);
    702 
    703     SetLastError(dwSavedErr);
    704 }
    705 
    706 
    707 KHLP_DECL(void) kHlpAssertMsg2(const char *pszFormat, ...)
    708 {
    709     DWORD const dwSavedErr = GetLastError();
    710     va_list va;
    711 
    712     va_start(va, pszFormat);
    713     fprintf(stderr, pszFormat, va);
    714     va_end(va);
    715 
    716     SetLastError(dwSavedErr);
    717 }
    718 
    719 #endif /* K_STRICT */
     455#endif /* !NDEBUG */
     456
    720457
    721458
     
    726463 * @param   pszString           String to hash.
    727464 */
    728 static KU32 kwStrHash(const char *pszString)
     465static KU32 kFsCacheStrHash(const char *pszString)
    729466{
    730467    /* This algorithm was created for sdbm (a public-domain reimplementation of
     
    753490 * @param   puHash              Where to return the 32-bit string hash.
    754491 */
    755 static KSIZE kwStrHashEx(const char *pszString, KU32 *puHash)
     492static KSIZE kFsCacheStrHashEx(const char *pszString, KU32 *puHash)
    756493{
    757494    const char * const pszStart = pszString;
     
    775512 * @param   puHash              Where to return the 32-bit string hash.
    776513 */
    777 static KSIZE kwUtf16HashEx(const wchar_t *pwszString, KU32 *puHash)
     514static KSIZE kFsCacheUtf16HashEx(const wchar_t *pwszString, KU32 *puHash)
    778515{
    779516    const wchar_t * const pwszStart = pwszString;
     
    789526}
    790527
     528#if 0
    791529
    792530/**
     
    917655     */
    918656    KU32            uHashPath;
    919     KU32            cchPath    = (KU32)kwStrHashEx(pszPath, &uHashPath);
     657    KU32            cchPath    = (KU32)kFsCacheStrHashEx(pszPath, &uHashPath);
    920658    KU32 const      idxHashTab = uHashPath % K_ELEMENTS(g_apFsNormalizedPathsA);
    921     PKWFSNORMHASHA  pHashEntry = g_apFsNormalizedPathsA[idxHashTab];
     659    PKFSNORMHASHA  pHashEntry = g_apFsNormalizedPathsA[idxHashTab];
    922660    if (pHashEntry)
    923661    {
     
    930668                if (cbNormPath > pHashEntry->cchNormPath)
    931669                {
    932                     KWFS_LOG(("kwPathNormalize(%s) - hit\n", pszPath));
     670                    KFSCACHE_LOG(("kwPathNormalize(%s) - hit\n", pszPath));
    933671                    kHlpMemCopy(pszNormPath, pHashEntry->szNormPath, pHashEntry->cchNormPath + 1);
    934672                    return 0;
     
    959697    if (cchNormPath < KU16_MAX && cchPath < KU16_MAX)
    960698    {
    961         pHashEntry = (PKWFSNORMHASHA)kHlpAlloc(sizeof(*pHashEntry) + cchNormPath + 1 + cchPath + 1);
     699        pHashEntry = (PKFSNORMHASHA)kHlpAlloc(sizeof(*pHashEntry) + cchNormPath + 1 + cchPath + 1);
    962700        if (pHashEntry)
    963701        {
     
    1009747        pwszPath++;
    1010748    }
    1011 }
    1012 
    1013 
    1014 
    1015 /**
    1016  * Retains a new reference to the given module
    1017  * @returns pMod
    1018  * @param   pMod                The module to retain.
    1019  */
    1020 static PKWMODULE kwLdrModuleRetain(PKWMODULE pMod)
    1021 {
    1022     kHlpAssert(pMod->cRefs > 0);
    1023     kHlpAssert(pMod->cRefs < 64);
    1024     pMod->cRefs++;
    1025     return pMod;
    1026 }
    1027 
    1028 
    1029 /**
    1030  * Releases a module reference.
    1031  *
    1032  * @param   pMod                The module to release.
    1033  */
    1034 static void kwLdrModuleRelease(PKWMODULE pMod)
    1035 {
    1036     if (--pMod->cRefs == 0)
    1037     {
    1038         /* Unlink it. */
    1039         if (!pMod->fExe)
    1040         {
    1041             PKWMODULE pPrev = NULL;
    1042             unsigned  idx   = pMod->uHashPath % K_ELEMENTS(g_apModules);
    1043             if (g_apModules[idx] == pMod)
    1044                 g_apModules[idx] = pMod->pNext;
    1045             else
    1046             {
    1047                 PKWMODULE pPrev = g_apModules[idx];
    1048                 kHlpAssert(pPrev != NULL);
    1049                 while (pPrev->pNext != pMod)
    1050                 {
    1051                     pPrev = pPrev->pNext;
    1052                     kHlpAssert(pPrev != NULL);
    1053                 }
    1054                 pPrev->pNext = pMod->pNext;
    1055             }
    1056         }
    1057 
    1058         /* Release import modules. */
    1059         if (!pMod->fNative)
    1060         {
    1061             KSIZE idx = pMod->u.Manual.cImpMods;
    1062             while (idx-- > 0)
    1063             {
    1064                 kwLdrModuleRelease(pMod->u.Manual.apImpMods[idx]);
    1065                 pMod->u.Manual.apImpMods[idx] = NULL;
    1066             }
    1067         }
    1068 
    1069         /* Free our resources. */
    1070         kLdrModClose(pMod->pLdrMod);
    1071         pMod->pLdrMod = NULL;
    1072 
    1073         if (!pMod->fNative)
    1074         {
    1075             kHlpPageFree(pMod->u.Manual.pvCopy, pMod->u.Manual.cbImage);
    1076             kHlpPageFree(pMod->u.Manual.pvLoad, pMod->u.Manual.cbImage);
    1077         }
    1078 
    1079         kHlpFree(pMod);
    1080     }
    1081     else
    1082         kHlpAssert(pMod->cRefs < 64);
    1083 }
    1084 
    1085 
    1086 /**
    1087  * Links the module into the module hash table.
    1088  *
    1089  * @returns pMod
    1090  * @param   pMod                The module to link.
    1091  */
    1092 static PKWMODULE kwLdrModuleLink(PKWMODULE pMod)
    1093 {
    1094     unsigned idx = pMod->uHashPath % K_ELEMENTS(g_apModules);
    1095     pMod->pNext = g_apModules[idx];
    1096     g_apModules[idx] = pMod;
    1097     return pMod;
    1098 }
    1099 
    1100 
    1101 /**
    1102  * Replaces imports for this module according to g_aSandboxNativeReplacements.
    1103  *
    1104  * @param   pMod                The natively loaded module to process.
    1105  */
    1106 static void kwLdrModuleDoNativeImportReplacements(PKWMODULE pMod)
    1107 {
    1108     KSIZE const                 cbImage = kLdrModSize(pMod->pLdrMod);
    1109     KU8 const * const           pbImage = (KU8 const *)pMod->hOurMod;
    1110     IMAGE_DOS_HEADER const     *pMzHdr  = (IMAGE_DOS_HEADER const *)pbImage;
    1111     IMAGE_NT_HEADERS const     *pNtHdrs;
    1112     IMAGE_DATA_DIRECTORY const *pDirEnt;
    1113 
    1114     kHlpAssert(pMod->fNative);
    1115 
    1116     /*
    1117      * Locate the export descriptors.
    1118      */
    1119     /* MZ header. */
    1120     if (pMzHdr->e_magic == IMAGE_DOS_SIGNATURE)
    1121     {
    1122         kHlpAssertReturnVoid(pMzHdr->e_lfanew <= cbImage - sizeof(*pNtHdrs));
    1123         pNtHdrs = (IMAGE_NT_HEADERS const *)&pbImage[pMzHdr->e_lfanew];
    1124     }
    1125     else
    1126         pNtHdrs = (IMAGE_NT_HEADERS const *)pbImage;
    1127 
    1128     /* Check PE header. */
    1129     kHlpAssertReturnVoid(pNtHdrs->Signature == IMAGE_NT_SIGNATURE);
    1130     kHlpAssertReturnVoid(pNtHdrs->FileHeader.SizeOfOptionalHeader == sizeof(pNtHdrs->OptionalHeader));
    1131 
    1132     /* Locate the import descriptor array. */
    1133     pDirEnt = (IMAGE_DATA_DIRECTORY const *)&pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
    1134     if (   pDirEnt->Size > 0
    1135         && pDirEnt->VirtualAddress != 0)
    1136     {
    1137         const IMAGE_IMPORT_DESCRIPTOR  *pImpDesc    = (const IMAGE_IMPORT_DESCRIPTOR *)&pbImage[pDirEnt->VirtualAddress];
    1138         KU32                            cLeft       = pDirEnt->Size / sizeof(*pImpDesc);
    1139         MEMORY_BASIC_INFORMATION        ProtInfo    = { NULL, NULL, 0, 0, 0, 0, 0 };
    1140         KU8                            *pbProtRange = NULL;
    1141         SIZE_T                          cbProtRange = 0;
    1142         DWORD                           fOldProt    = 0;
    1143         KU32 const                      cbPage      = 0x1000;
    1144         BOOL                            fRc;
    1145 
    1146 
    1147         kHlpAssertReturnVoid(pDirEnt->VirtualAddress < cbImage);
    1148         kHlpAssertReturnVoid(pDirEnt->Size < cbImage);
    1149         kHlpAssertReturnVoid(pDirEnt->VirtualAddress + pDirEnt->Size <= cbImage);
    1150 
    1151         /*
    1152          * Walk the import descriptor array.
    1153          * Note! This only works if there's a backup thunk array, otherwise we cannot get at the name.
    1154          */
    1155         while (   cLeft-- > 0
    1156                && pImpDesc->Name > 0
    1157                && pImpDesc->FirstThunk > 0)
    1158         {
    1159             KU32                iThunk;
    1160             const char * const  pszImport   = (const char *)&pbImage[pImpDesc->Name];
    1161             PIMAGE_THUNK_DATA   paThunks    = (PIMAGE_THUNK_DATA)&pbImage[pImpDesc->FirstThunk];
    1162             PIMAGE_THUNK_DATA   paOrgThunks = (PIMAGE_THUNK_DATA)&pbImage[pImpDesc->OriginalFirstThunk];
    1163             kHlpAssertReturnVoid(pImpDesc->Name < cbImage);
    1164             kHlpAssertReturnVoid(pImpDesc->FirstThunk < cbImage);
    1165             kHlpAssertReturnVoid(pImpDesc->OriginalFirstThunk < cbImage);
    1166             kHlpAssertReturnVoid(pImpDesc->OriginalFirstThunk != pImpDesc->FirstThunk);
    1167             kHlpAssertReturnVoid(pImpDesc->OriginalFirstThunk);
    1168 
    1169             /* Iterate the thunks. */
    1170             for (iThunk = 0; paOrgThunks[iThunk].u1.Ordinal != 0; iThunk++)
    1171             {
    1172                 KUPTR const off = paOrgThunks[iThunk].u1.Function;
    1173                 kHlpAssertReturnVoid(off < cbImage);
    1174                 if (!IMAGE_SNAP_BY_ORDINAL(off))
    1175                 {
    1176                     IMAGE_IMPORT_BY_NAME const *pName     = (IMAGE_IMPORT_BY_NAME const *)&pbImage[off];
    1177                     KSIZE const                 cchSymbol = kHlpStrLen(pName->Name);
    1178                     KU32                        i         = g_cSandboxNativeReplacements;
    1179                     while (i-- > 0)
    1180                         if (   g_aSandboxNativeReplacements[i].cchFunction == cchSymbol
    1181                             && kHlpMemComp(g_aSandboxNativeReplacements[i].pszFunction, pName->Name, cchSymbol) == 0)
    1182                         {
    1183                             if (   !g_aSandboxNativeReplacements[i].pszModule
    1184                                 || kHlpStrICompAscii(g_aSandboxNativeReplacements[i].pszModule, pszImport) == 0)
    1185                             {
    1186                                 KW_LOG(("%s: replacing %s!%s\n", pMod->pLdrMod->pszName, pszImport, pName->Name));
    1187 
    1188                                 /* The .rdata section is normally read-only, so we need to make it writable first. */
    1189                                 if ((KUPTR)&paThunks[iThunk] - (KUPTR)pbProtRange >= cbPage)
    1190                                 {
    1191                                     /* Restore previous .rdata page. */
    1192                                     if (fOldProt)
    1193                                     {
    1194                                         fRc = VirtualProtect(pbProtRange, cbProtRange, fOldProt, NULL /*pfOldProt*/);
    1195                                         kHlpAssert(fRc);
    1196                                         fOldProt = 0;
    1197                                     }
    1198 
    1199                                     /* Query attributes for the current .rdata page. */
    1200                                     pbProtRange = (KU8 *)((KUPTR)&paThunks[iThunk] & ~(KUPTR)(cbPage - 1));
    1201                                     cbProtRange = VirtualQuery(pbProtRange, &ProtInfo, sizeof(ProtInfo));
    1202                                     kHlpAssert(cbProtRange);
    1203                                     if (cbProtRange)
    1204                                     {
    1205                                         switch (ProtInfo.Protect)
    1206                                         {
    1207                                             case PAGE_READWRITE:
    1208                                             case PAGE_WRITECOPY:
    1209                                             case PAGE_EXECUTE_READWRITE:
    1210                                             case PAGE_EXECUTE_WRITECOPY:
    1211                                                 /* Already writable, nothing to do. */
    1212                                                 break;
    1213 
    1214                                             default:
    1215                                                 kHlpAssertMsgFailed(("%#x\n", ProtInfo.Protect));
    1216                                             case PAGE_READONLY:
    1217                                                 cbProtRange = cbPage;
    1218                                                 fRc = VirtualProtect(pbProtRange, cbProtRange, PAGE_READWRITE, &fOldProt);
    1219                                                 break;
    1220 
    1221                                             case PAGE_EXECUTE:
    1222                                             case PAGE_EXECUTE_READ:
    1223                                                 cbProtRange = cbPage;
    1224                                                 fRc = VirtualProtect(pbProtRange, cbProtRange, PAGE_EXECUTE_READWRITE, &fOldProt);
    1225                                                 break;
    1226                                         }
    1227                                         kHlpAssertStmt(fRc, fOldProt = 0);
    1228                                     }
    1229                                 }
    1230 
    1231                                 paThunks[iThunk].u1.AddressOfData = g_aSandboxNativeReplacements[i].pfnReplacement;
    1232                                 break;
    1233                             }
    1234                         }
    1235                 }
    1236             }
    1237 
    1238 
    1239             /* Next import descriptor. */
    1240             pImpDesc++;
    1241         }
    1242 
    1243 
    1244         if (fOldProt)
    1245         {
    1246             DWORD fIgnore = 0;
    1247             fRc = VirtualProtect(pbProtRange, cbProtRange, fOldProt, &fIgnore);
    1248             kHlpAssertMsg(fRc, ("%u\n", GetLastError())); K_NOREF(fRc);
    1249         }
    1250     }
    1251 
    1252 }
    1253 
    1254 
    1255 /**
    1256  * Creates a module using the native loader.
    1257  *
    1258  * @returns Module w/ 1 reference on success, NULL on failure.
    1259  * @param   pszPath             The normalized path to the module.
    1260  * @param   uHashPath           The module path hash.
    1261  * @param   fDoReplacements     Whether to do import replacements on this
    1262  *                              module.
    1263  */
    1264 static PKWMODULE kwLdrModuleCreateNative(const char *pszPath, KU32 uHashPath, KBOOL fDoReplacements)
    1265 {
    1266     /*
    1267      * Open the module and check the type.
    1268      */
    1269     PKLDRMOD pLdrMod;
    1270     int rc = kLdrModOpenNative(pszPath, &pLdrMod);
    1271     if (rc == 0)
    1272     {
    1273         /*
    1274          * Create the entry.
    1275          */
    1276         KSIZE     cbPath = kHlpStrLen(pszPath) + 1;
    1277         PKWMODULE pMod   = (PKWMODULE)kHlpAllocZ(sizeof(*pMod) + cbPath + 1 + cbPath * 2 * sizeof(wchar_t));
    1278         if (pMod)
    1279         {
    1280             pMod->pszPath       = (char *)kHlpMemCopy(pMod + 1, pszPath, cbPath);
    1281             pMod->pwszPath      = (wchar_t *)(pMod->pszPath + cbPath + (cbPath & 1));
    1282             kwStrToUtf16(pMod->pszPath, (wchar_t *)pMod->pwszPath, cbPath * 2);
    1283             pMod->uHashPath     = uHashPath;
    1284             pMod->cRefs         = 1;
    1285             pMod->offFilename   = (KU16)(kHlpGetFilename(pszPath) - pszPath);
    1286             pMod->fExe          = K_FALSE;
    1287             pMod->fNative       = K_TRUE;
    1288             pMod->pLdrMod       = pLdrMod;
    1289             pMod->hOurMod       = (HMODULE)(KUPTR)pLdrMod->aSegments[0].MapAddress;
    1290 
    1291             if (fDoReplacements)
    1292             {
    1293                 DWORD const dwSavedErr = GetLastError();
    1294                 kwLdrModuleDoNativeImportReplacements(pMod);
    1295                 SetLastError(dwSavedErr);
    1296             }
    1297 
    1298             KW_LOG(("New module: %p LB %#010x %s (native)\n",
    1299                     (KUPTR)pMod->pLdrMod->aSegments[0].MapAddress, kLdrModSize(pMod->pLdrMod), pMod->pszPath));
    1300             return kwLdrModuleLink(pMod);
    1301         }
    1302         //kLdrModClose(pLdrMod);
    1303     }
    1304     return NULL;
    1305 }
    1306 
    1307 
    1308 /**
    1309  * Creates a module using the our own loader.
    1310  *
    1311  * @returns Module w/ 1 reference on success, NULL on failure.
    1312  * @param   pszPath             The normalized path to the module.
    1313  * @param   uHashPath           The module path hash.
    1314  * @param   fExe                K_TRUE if this is an executable image, K_FALSE
    1315  *                              if not.  Executable images does not get entered
    1316  *                              into the global module table.
    1317  * @param   pExeMod             The executable module of the process (for
    1318  *                              resolving imports).  NULL if fExe is set.
    1319  */
    1320 static PKWMODULE kwLdrModuleCreateNonNative(const char *pszPath, KU32 uHashPath, KBOOL fExe, PKWMODULE pExeMod)
    1321 {
    1322     /*
    1323      * Open the module and check the type.
    1324      */
    1325     PKLDRMOD pLdrMod;
    1326     int rc = kLdrModOpen(pszPath, 0 /*fFlags*/, (KCPUARCH)K_ARCH, &pLdrMod);
    1327     if (rc == 0)
    1328     {
    1329         switch (pLdrMod->enmType)
    1330         {
    1331             case KLDRTYPE_EXECUTABLE_FIXED:
    1332             case KLDRTYPE_EXECUTABLE_RELOCATABLE:
    1333             case KLDRTYPE_EXECUTABLE_PIC:
    1334                 if (!fExe)
    1335                     rc = KERR_GENERAL_FAILURE;
    1336                 break;
    1337 
    1338             case KLDRTYPE_SHARED_LIBRARY_RELOCATABLE:
    1339             case KLDRTYPE_SHARED_LIBRARY_PIC:
    1340             case KLDRTYPE_SHARED_LIBRARY_FIXED:
    1341                 if (fExe)
    1342                     rc = KERR_GENERAL_FAILURE;
    1343                 break;
    1344 
    1345             default:
    1346                 rc = KERR_GENERAL_FAILURE;
    1347                 break;
    1348         }
    1349         if (rc == 0)
    1350         {
    1351             KI32 cImports = kLdrModNumberOfImports(pLdrMod, NULL /*pvBits*/);
    1352             if (cImports >= 0)
    1353             {
    1354                 /*
    1355                  * Create the entry.
    1356                  */
    1357                 KSIZE     cbPath = kHlpStrLen(pszPath) + 1;
    1358                 PKWMODULE pMod   = (PKWMODULE)kHlpAllocZ(sizeof(*pMod)
    1359                                                          + sizeof(pMod) * cImports
    1360                                                          + cbPath
    1361                                                          + cbPath * 2 * sizeof(wchar_t));
    1362                 if (pMod)
    1363                 {
    1364                     KBOOL fFixed;
    1365 
    1366                     pMod->cRefs         = 1;
    1367                     pMod->offFilename   = (KU16)(kHlpGetFilename(pszPath) - pszPath);
    1368                     pMod->uHashPath     = uHashPath;
    1369                     pMod->fExe          = fExe;
    1370                     pMod->fNative       = K_FALSE;
    1371                     pMod->pLdrMod       = pLdrMod;
    1372                     pMod->u.Manual.cImpMods = (KU32)cImports;
    1373                     pMod->pszPath       = (char *)kHlpMemCopy(&pMod->u.Manual.apImpMods[cImports + 1], pszPath, cbPath);
    1374                     pMod->pwszPath      = (wchar_t *)(pMod->pszPath + cbPath + (cbPath & 1));
    1375                     kwStrToUtf16(pMod->pszPath, (wchar_t *)pMod->pwszPath, cbPath * 2);
    1376 
    1377                     /*
    1378                      * Figure out where to load it and get memory there.
    1379                      */
    1380                     fFixed = pLdrMod->enmType == KLDRTYPE_EXECUTABLE_FIXED
    1381                           || pLdrMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED;
    1382                     pMod->u.Manual.pvLoad = fFixed ? (void *)(KUPTR)pLdrMod->aSegments[0].LinkAddress : NULL;
    1383                     pMod->u.Manual.cbImage = kLdrModSize(pLdrMod);
    1384                     if (   !fFixed
    1385                         || (KUPTR)pMod->u.Manual.pvLoad - (KUPTR)g_abDefLdBuf >= sizeof(g_abDefLdBuf)
    1386                         || sizeof(g_abDefLdBuf) - (KUPTR)pMod->u.Manual.pvLoad - (KUPTR)g_abDefLdBuf < pMod->u.Manual.cbImage)
    1387                         rc = kHlpPageAlloc(&pMod->u.Manual.pvLoad, pMod->u.Manual.cbImage, KPROT_EXECUTE_READWRITE, fFixed);
    1388                     if (rc == 0)
    1389                     {
    1390                         rc = kHlpPageAlloc(&pMod->u.Manual.pvCopy, pMod->u.Manual.cbImage, KPROT_READWRITE, K_FALSE);
    1391                         if (rc == 0)
    1392                         {
    1393 
    1394                             KI32 iImp;
    1395 
    1396                             /*
    1397                              * Link the module (unless it's an executable image) and process the imports.
    1398                              */
    1399                             pMod->hOurMod = (HMODULE)pMod->u.Manual.pvLoad;
    1400                             if (!fExe)
    1401                                 kwLdrModuleLink(pMod);
    1402                             KW_LOG(("New module: %p LB %#010x %s (kLdr)\n",
    1403                                     pMod->u.Manual.pvLoad, pMod->u.Manual.cbImage, pMod->pszPath));
    1404                             kwDebuggerPrintf("TODO: .reload /f %s=%p\n", pMod->pszPath, pMod->u.Manual.pvLoad);
    1405 
    1406                             for (iImp = 0; iImp < cImports; iImp++)
    1407                             {
    1408                                 char szName[1024];
    1409                                 rc = kLdrModGetImport(pMod->pLdrMod, NULL /*pvBits*/, iImp, szName, sizeof(szName));
    1410                                 if (rc == 0)
    1411                                 {
    1412                                     rc = kwLdrModuleResolveAndLookup(szName, pExeMod, pMod, &pMod->u.Manual.apImpMods[iImp]);
    1413                                     if (rc == 0)
    1414                                         continue;
    1415                                 }
    1416                                 break;
    1417                             }
    1418 
    1419                             if (rc == 0)
    1420                             {
    1421                                 rc = kLdrModGetBits(pLdrMod, pMod->u.Manual.pvCopy, (KUPTR)pMod->u.Manual.pvLoad,
    1422                                                     kwLdrModuleGetImportCallback, pMod);
    1423                                 if (rc == 0)
    1424                                 {
    1425                                     pMod->u.Manual.pvBits = pMod->u.Manual.pvCopy;
    1426                                     pMod->u.Manual.enmState = KWMODSTATE_NEEDS_BITS;
    1427                                     return pMod;
    1428                                 }
    1429                             }
    1430 
    1431                             kwLdrModuleRelease(pMod);
    1432                             return NULL;
    1433                         }
    1434 
    1435                         kHlpPageFree(pMod->u.Manual.pvLoad, pMod->u.Manual.cbImage);
    1436                         kwErrPrintf("Failed to allocate %#x bytes\n", pMod->u.Manual.cbImage);
    1437                     }
    1438                     else if (fFixed)
    1439                         kwErrPrintf("Failed to allocate %#x bytes at %p\n",
    1440                                     pMod->u.Manual.cbImage, (void *)(KUPTR)pLdrMod->aSegments[0].LinkAddress);
    1441                     else
    1442                         kwErrPrintf("Failed to allocate %#x bytes\n", pMod->u.Manual.cbImage);
    1443                 }
    1444             }
    1445         }
    1446         kLdrModClose(pLdrMod);
    1447     }
    1448     else
    1449         kwErrPrintf("kLdrOpen failed with %#x (%d) for %s\n", rc, rc, pszPath);
    1450     return NULL;
    1451 }
    1452 
    1453 
    1454 /** Implements FNKLDRMODGETIMPORT, used by kwLdrModuleCreate. */
    1455 static int kwLdrModuleGetImportCallback(PKLDRMOD pMod, KU32 iImport, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol,
    1456                                         const char *pszVersion, PKLDRADDR puValue, KU32 *pfKind, void *pvUser)
    1457 {
    1458     PKWMODULE pCurMod = (PKWMODULE)pvUser;
    1459     PKWMODULE pImpMod = pCurMod->u.Manual.apImpMods[iImport];
    1460     int rc;
    1461     K_NOREF(pMod);
    1462 
    1463     if (pImpMod->fNative)
    1464         rc = kLdrModQuerySymbol(pImpMod->pLdrMod, NULL /*pvBits*/, KLDRMOD_BASEADDRESS_MAP,
    1465                                 iSymbol, pchSymbol, cchSymbol, pszVersion,
    1466                                 NULL /*pfnGetForwarder*/, NULL /*pvUSer*/,
    1467                                 puValue, pfKind);
    1468     else
    1469         rc = kLdrModQuerySymbol(pImpMod->pLdrMod, pImpMod->u.Manual.pvBits, (KUPTR)pImpMod->u.Manual.pvLoad,
    1470                                 iSymbol, pchSymbol, cchSymbol, pszVersion,
    1471                                 NULL /*pfnGetForwarder*/, NULL /*pvUSer*/,
    1472                                 puValue, pfKind);
    1473     if (rc == 0)
    1474     {
    1475         KU32 i = g_cSandboxReplacements;
    1476         while (i-- > 0)
    1477             if (   g_aSandboxReplacements[i].cchFunction == cchSymbol
    1478                 && kHlpMemComp(g_aSandboxReplacements[i].pszFunction, pchSymbol, cchSymbol) == 0)
    1479             {
    1480                 if (   !g_aSandboxReplacements[i].pszModule
    1481                     || kHlpStrICompAscii(g_aSandboxReplacements[i].pszModule, &pImpMod->pszPath[pImpMod->offFilename]) == 0)
    1482                 {
    1483                     KW_LOG(("replacing %s!%s\n", &pImpMod->pszPath[pImpMod->offFilename], g_aSandboxReplacements[i].pszFunction));
    1484                     *puValue = g_aSandboxReplacements[i].pfnReplacement;
    1485                     break;
    1486                 }
    1487             }
    1488     }
    1489 
    1490     //printf("iImport=%u (%s) %*.*s rc=%d\n", iImport, &pImpMod->pszPath[pImpMod->offFilename], cchSymbol, cchSymbol, pchSymbol, rc);
    1491     return rc;
    1492 
    1493 }
    1494 
    1495 
    1496 /**
    1497  * Gets the main entrypoint for a module.
    1498  *
    1499  * @returns 0 on success, KERR on failure
    1500  * @param   pMod                The module.
    1501  * @param   puAddrMain          Where to return the address.
    1502  */
    1503 static int kwLdrModuleQueryMainEntrypoint(PKWMODULE pMod, KUPTR *puAddrMain)
    1504 {
    1505     KLDRADDR uLdrAddrMain;
    1506     int rc = kLdrModQueryMainEntrypoint(pMod->pLdrMod,  pMod->u.Manual.pvBits, (KUPTR)pMod->u.Manual.pvLoad, &uLdrAddrMain);
    1507     if (rc == 0)
    1508     {
    1509         *puAddrMain = (KUPTR)uLdrAddrMain;
    1510         return 0;
    1511     }
    1512     return rc;
    1513 }
    1514 
    1515 
    1516 /**
    1517  * Whether to apply g_aSandboxNativeReplacements to the imports of this module.
    1518  *
    1519  * @returns K_TRUE/K_FALSE.
    1520  * @param   pszFilename         The filename (no path).
    1521  * @param   enmLocation         The location.
    1522  */
    1523 static KBOOL kwLdrModuleShouldDoNativeReplacements(const char *pszFilename, KWLOCATION enmLocation)
    1524 {
    1525     if (enmLocation != KWLOCATION_SYSTEM32)
    1526         return K_TRUE;
    1527     return kHlpStrNICompAscii(pszFilename, TUPLE("msvc"))   == 0
    1528         || kHlpStrNICompAscii(pszFilename, TUPLE("msdis"))  == 0
    1529         || kHlpStrNICompAscii(pszFilename, TUPLE("mspdb"))  == 0;
    1530 }
    1531 
    1532 
    1533 /**
    1534  * Whether we can load this DLL natively or not.
    1535  *
    1536  * @returns K_TRUE/K_FALSE.
    1537  * @param   pszFilename         The filename (no path).
    1538  * @param   enmLocation         The location.
    1539  */
    1540 static KBOOL kwLdrModuleCanLoadNatively(const char *pszFilename, KWLOCATION enmLocation)
    1541 {
    1542     if (enmLocation == KWLOCATION_SYSTEM32)
    1543         return K_TRUE;
    1544     if (enmLocation == KWLOCATION_UNKNOWN_NATIVE)
    1545         return K_TRUE;
    1546     return kHlpStrNICompAscii(pszFilename, TUPLE("msvc"))   == 0
    1547         || kHlpStrNICompAscii(pszFilename, TUPLE("msdis"))  == 0
    1548         || kHlpStrNICompAscii(pszFilename, TUPLE("mspdb"))  == 0;
    1549749}
    1550750
     
    1566766        && (pszPath[cchPath - 1] == 'l' || pszPath[cchPath - 1] == 'L') )
    1567767    {
    1568         PKWFSOBJ pFsObj = kwFsLookupA(pszPath);
     768        PKFSOBJ pFsObj = kFsCacheLookupA(pszPath);
    1569769        if (pFsObj)
    1570770        {
     
    1587787
    1588788
    1589 /**
    1590  * Worker for kwLdrModuleResolveAndLookup that checks out one possibility.
    1591  *
    1592  * If the file exists, we consult the module hash table before trying to load it
    1593  * off the disk.
    1594  *
    1595  * @returns Pointer to module on success, NULL if not found, ~(KUPTR)0 on
    1596  *          failure.
    1597  * @param   pszPath             The name of the import module.
    1598  * @param   enmLocation         The location we're searching.  This is used in
    1599  *                              the heuristics for determining if we can use the
    1600  *                              native loader or need to sandbox the DLL.
    1601  * @param   pExe                The executable (optional).
    1602  */
    1603 static PKWMODULE kwLdrModuleTryLoadDll(const char *pszPath, KWLOCATION enmLocation, PKWMODULE pExeMod)
    1604 {
    1605     /*
    1606      * Does the file exists and is it a regular file?
    1607      */
    1608     if (kwLdrModuleIsRegularFile(pszPath))
    1609     {
    1610         /*
    1611          * Yes! Normalize it and look it up in the hash table.
    1612          */
    1613         char szNormPath[1024];
    1614         int rc = kwPathNormalize(pszPath, szNormPath, sizeof(szNormPath));
    1615         if (rc == 0)
    1616         {
    1617             const char *pszName;
    1618             KU32 const  uHashPath = kwStrHash(szNormPath);
    1619             unsigned    idxHash   = uHashPath % K_ELEMENTS(g_apModules);
    1620             PKWMODULE   pMod      = g_apModules[idxHash];
    1621             if (pMod)
    1622             {
    1623                 do
    1624                 {
    1625                     if (   pMod->uHashPath == uHashPath
    1626                         && kHlpStrComp(pMod->pszPath, szNormPath) == 0)
    1627                         return kwLdrModuleRetain(pMod);
    1628                     pMod = pMod->pNext;
    1629                 } while (pMod);
    1630             }
    1631 
    1632             /*
    1633              * Not in the hash table, so we have to load it from scratch.
    1634              */
    1635             pszName = kHlpGetFilename(szNormPath);
    1636             if (kwLdrModuleCanLoadNatively(pszName, enmLocation))
    1637                 pMod = kwLdrModuleCreateNative(szNormPath, uHashPath,
    1638                                                kwLdrModuleShouldDoNativeReplacements(pszName, enmLocation));
    1639             else
    1640                 pMod = kwLdrModuleCreateNonNative(szNormPath, uHashPath, K_FALSE /*fExe*/, pExeMod);
    1641             if (pMod)
    1642                 return pMod;
    1643             return (PKWMODULE)~(KUPTR)0;
    1644         }
    1645     }
    1646     return NULL;
    1647 }
    1648 
    1649 
    1650 /**
    1651  * Gets a reference to the module by the given name.
    1652  *
    1653  * We must do the search path thing, as our hash table may multiple DLLs with
    1654  * the same base name due to different tools version and similar.  We'll use a
    1655  * modified search sequence, though.  No point in searching the current
    1656  * directory for instance.
    1657  *
    1658  * @returns 0 on success, KERR on failure.
    1659  * @param   pszName             The name of the import module.
    1660  * @param   pExe                The executable (optional).
    1661  * @param   pImporter           The module doing the importing (optional).
    1662  * @param   ppMod               Where to return the module pointer w/ reference.
    1663  */
    1664 static int kwLdrModuleResolveAndLookup(const char *pszName, PKWMODULE pExe, PKWMODULE pImporter, PKWMODULE *ppMod)
    1665 {
    1666     KSIZE const cchName = kHlpStrLen(pszName);
    1667     char        szPath[1024];
    1668     PKWMODULE   pMod = NULL;
    1669 
    1670 
    1671     /* The import path. */
    1672     if (pMod == NULL && pImporter != NULL)
    1673     {
    1674         if (pImporter->offFilename + cchName >= sizeof(szPath))
    1675             return KERR_BUFFER_OVERFLOW;
    1676         kHlpMemCopy(kHlpMemPCopy(szPath, pImporter->pszPath, pImporter->offFilename), pszName, cchName + 1);
    1677         pMod = kwLdrModuleTryLoadDll(szPath, KWLOCATION_IMPORTER_DIR, pExe);
    1678     }
    1679 
    1680     /* Application directory first. */
    1681     if (pMod == NULL && pExe != NULL && pExe != pImporter)
    1682     {
    1683         if (pExe->offFilename + cchName >= sizeof(szPath))
    1684             return KERR_BUFFER_OVERFLOW;
    1685         kHlpMemCopy(kHlpMemPCopy(szPath, pExe->pszPath, pExe->offFilename), pszName, cchName + 1);
    1686         pMod = kwLdrModuleTryLoadDll(szPath, KWLOCATION_EXE_DIR, pExe);
    1687     }
    1688 
    1689     /* The windows directory. */
    1690     if (pMod == NULL)
    1691     {
    1692         UINT cchDir = GetSystemDirectoryA(szPath, sizeof(szPath));
    1693         if (   cchDir <= 2
    1694             || cchDir + 1 + cchName >= sizeof(szPath))
    1695             return KERR_BUFFER_OVERFLOW;
    1696         szPath[cchDir++] = '\\';
    1697         kHlpMemCopy(&szPath[cchDir], pszName, cchName + 1);
    1698         pMod = kwLdrModuleTryLoadDll(szPath, KWLOCATION_SYSTEM32, pExe);
    1699     }
    1700 
    1701     /* Return. */
    1702     if (pMod != NULL && pMod != (PKWMODULE)~(KUPTR)0)
    1703     {
    1704         *ppMod = pMod;
    1705         return 0;
    1706     }
    1707     *ppMod = NULL;
    1708     return KERR_GENERAL_FAILURE;
    1709 }
    1710 
    1711 
    1712 /**
    1713  * Does module initialization starting at @a pMod.
    1714  *
    1715  * This is initially used on the executable.  Later it is used by the
    1716  * LoadLibrary interceptor.
    1717  *
    1718  * @returns 0 on success, error on failure.
    1719  * @param   pMod                The module to initialize.
    1720  */
    1721 static int kwLdrModuleInitTree(PKWMODULE pMod)
    1722 {
    1723     int rc = 0;
    1724     if (!pMod->fNative)
    1725     {
    1726         /* Need to copy bits? */
    1727         if (pMod->u.Manual.enmState == KWMODSTATE_NEEDS_BITS)
    1728         {
    1729             kHlpMemCopy(pMod->u.Manual.pvLoad, pMod->u.Manual.pvCopy, pMod->u.Manual.cbImage);
    1730             pMod->u.Manual.enmState = KWMODSTATE_NEEDS_INIT;
    1731         }
    1732 
    1733         if (pMod->u.Manual.enmState == KWMODSTATE_NEEDS_INIT)
    1734         {
    1735             /* Must do imports first, but mark our module as being initialized to avoid
    1736                endless recursion should there be a dependency loop. */
    1737             KSIZE iImp;
    1738             pMod->u.Manual.enmState = KWMODSTATE_BEING_INITED;
    1739 
    1740             for (iImp = 0; iImp < pMod->u.Manual.cImpMods; iImp++)
    1741             {
    1742                 rc = kwLdrModuleInitTree(pMod->u.Manual.apImpMods[iImp]);
    1743                 if (rc != 0)
    1744                     return rc;
    1745             }
    1746 
    1747             rc = kLdrModCallInit(pMod->pLdrMod, pMod->u.Manual.pvLoad, (KUPTR)pMod->u.Manual.pvLoad);
    1748             if (rc == 0)
    1749                 pMod->u.Manual.enmState = KWMODSTATE_READY;
    1750             else
    1751                 pMod->u.Manual.enmState = KWMODSTATE_INIT_FAILED;
    1752         }
    1753     }
    1754     return rc;
    1755 }
    1756 
    1757 
    1758 
    1759 
    1760 /**
    1761  * Creates a tool entry and inserts it.
    1762  *
    1763  * @returns Pointer to the tool entry.  NULL on failure.
    1764  * @param   pszTool             The normalized path to the tool.
    1765  * @param   uHashPath           The hash of the tool path.
    1766  * @param   idxHashTab          The hash table index of the tool.
    1767  */
    1768 static PKWTOOL kwToolEntryCreate(const char *pszTool, KU32 uHashPath, unsigned idxHashTab)
    1769 {
    1770     KSIZE   cbTool = kHlpStrLen(pszTool) + 1;
    1771     PKWTOOL pTool  = (PKWTOOL)kHlpAllocZ(sizeof(*pTool) + cbTool + 1 + cbTool * 2 * sizeof(wchar_t));
    1772     if (pTool)
    1773     {
    1774         pTool->pszPath   = (char *)kHlpMemCopy(pTool + 1, pszTool, cbTool);
    1775         pTool->pwszPath  = (wchar_t *)(pTool->pszPath + cbTool + (cbTool & 1));
    1776         kwStrToUtf16(pTool->pszPath, (wchar_t *)pTool->pwszPath, cbTool * 2);
    1777         pTool->uHashPath = uHashPath;
    1778         pTool->enmType   = KWTOOLTYPE_SANDBOXED;
    1779 
    1780         pTool->u.Sandboxed.pExe = kwLdrModuleCreateNonNative(pszTool, uHashPath, K_TRUE /*fExe*/, NULL);
    1781         if (!pTool->u.Sandboxed.pExe)
    1782             pTool->enmType = KWTOOLTYPE_EXEC;
    1783         else if (kHlpStrICompAscii(pTool->u.Sandboxed.pExe->pLdrMod->pszName, "cl.exe") == 0)
    1784             pTool->u.Sandboxed.enmHint = KWTOOLHINT_VISUAL_CPP_CL;
    1785         else
    1786             pTool->u.Sandboxed.enmHint = KWTOOLHINT_NONE;
    1787 
    1788         /* Link the tool. */
    1789         pTool->pNext = g_apTools[idxHashTab];
    1790         g_apTools[idxHashTab] = pTool;
    1791         return pTool;
    1792     }
    1793     return NULL;
    1794 }
    1795 
    1796 
    1797 /**
    1798  * Looks up the given tool, creating a new tool table entry if necessary.
    1799  *
    1800  * @returns Pointer to the tool entry.  NULL on failure.
    1801  * @param   pszExe              The executable for the tool (not normalized).
    1802  */
    1803 static PKWTOOL kwToolLookup(const char *pszExe)
    1804 {
    1805     /*
    1806      * Normalize the path and look up the tool in the g_apTools hash table.
    1807      */
    1808     char szNormPath[4096];
    1809     int rc = kwPathNormalize(pszExe, szNormPath, sizeof(szNormPath));
    1810     if (rc == 0)
    1811     {
    1812         KU32     uHashPath = kwStrHash(szNormPath);
    1813         unsigned idxHash   = uHashPath % K_ELEMENTS(g_apTools);
    1814         PKWTOOL  pTool     = g_apTools[idxHash];
    1815         if (pTool)
    1816         {
    1817             do
    1818             {
    1819                 if (   pTool->uHashPath == uHashPath
    1820                     && kHlpStrComp(pTool->pszPath, szNormPath) == 0)
    1821                     return pTool;
    1822                 pTool = pTool->pNext;
    1823             } while (pTool);
    1824         }
    1825 
    1826         /*
    1827          * Not found, create new entry.
    1828          */
    1829        return kwToolEntryCreate(szNormPath, uHashPath, idxHash);
    1830     }
    1831     return NULL;
    1832 }
    1833 
    1834 
    1835 
    1836 /*
    1837  *
    1838  * File system cache.
    1839  * File system cache.
    1840  * File system cache.
    1841  *
    1842  */
    1843 
    1844 
    1845 #define IS_ALPHA(ch) ( ((ch) >= 'A' && (ch) <= 'Z') || ((ch) >= 'a' && (ch) <= 'z') )
    1846 #define IS_SLASH(ch) ((ch) == '\\' || (ch) == '/')
     789
     790
    1847791
    1848792
     
    1880824    }
    1881825}
     826#endif
    1882827
    1883828
     
    1889834 * @param   cchPath             The length of the path.
    1890835 */
    1891 static KBOOL kwFsHasDotDot(const char *pszPath, KSIZE cchPath)
     836static KBOOL kFsCacheHasDotDot(const char *pszPath, KSIZE cchPath)
    1892837{
    1893838    const char *pchDot = (const char *)kHlpMemChr(pszPath, '.', cchPath);
     
    1917862
    1918863
    1919 static void kwFsCreateHashTabEntryA(PKWFSOBJ pFsObj, const char *pszPath, KU32 cchPath, KU32 uHashPath, KU32 idxHashTab)
    1920 {
    1921     PKWFSHASHA pHashEntry = (PKWFSHASHA)kHlpAlloc(sizeof(*pHashEntry) + cchPath + 1);
     864/**
     865 * Creates an ANSI hash table entry for the given path.
     866 *
     867 * @returns The hash table entry or NULL if out of memory.
     868 * @param   pCache              The hash
     869 * @param   pFsObj              The resulting object.
     870 * @param   pszPath             The path.
     871 * @param   cchPath             The length of the path.
     872 * @param   uHashPath           The hash of the path.
     873 * @param   idxHashTab          The hash table index of the path.
     874 * @param   enmError            The lookup error.
     875 */
     876static PKFSHASHA kFsCacheCreatePathHashTabEntryA(PKFSCACHE pCache, PKFSOBJ pFsObj, const char *pszPath, KU32 cchPath,
     877                                                 KU32 uHashPath, KU32 idxHashTab, KFSLOOKUPERROR enmError)
     878{
     879    PKFSHASHA pHashEntry = (PKFSHASHA)kHlpAlloc(sizeof(*pHashEntry) + cchPath + 1);
    1922880    if (pHashEntry)
    1923881    {
     
    1926884        pHashEntry->pszPath     = (const char *)kHlpMemCopy(pHashEntry + 1, pszPath, cchPath + 1);
    1927885        pHashEntry->pFsObj      = pFsObj;
    1928 
    1929         pHashEntry->pNext = g_apFsAnsiPaths[idxHashTab];
    1930         g_apFsAnsiPaths[idxHashTab] = pHashEntry;
    1931     }
    1932 }
    1933 
    1934 
    1935 /**
    1936  * Refreshes a node that hash expired.
    1937  *
    1938  * This is for files and directories in the output directory tree.  The plan is
    1939  * to invalid negative results for each tool execution, in case a include file
    1940  * or directory has been created since the last time we were active.  Assuming
    1941  * that we'll be stopped together with kmk, there is no need to invalidate
    1942  * positive results.
    1943  *
    1944  * @param   pNode               The FS node.
    1945  */
    1946 static void kwFsRefreshNode(PKWFSOBJ pNode)
    1947 {
    1948     /** @todo implement once we've start inserting uCacheGen nodes. */
    1949     __debugbreak();
     886        pHashEntry->enmError    = enmError;
     887        if (pFsObj)
     888            pHashEntry->uCacheGen = pCache->uGeneration;
     889        else if (enmError != KFSLOOKUPERROR_UNSUPPORTED)
     890            pHashEntry->uCacheGen = pCache->uGenerationMissing;
     891        else
     892            pHashEntry->uCacheGen = KFSWOBJ_CACHE_GEN_IGNORE;
     893
     894        pHashEntry->pNext = pCache->apAnsiPaths[idxHashTab];
     895        pCache->apAnsiPaths[idxHashTab] = pHashEntry;
     896
     897        pCache->cbAnsiPaths += sizeof(*pHashEntry) + cchPath + 1;
     898        pCache->cAnsiPaths++;
     899        if (pHashEntry->pNext)
     900            pCache->cAnsiPathCollisions++;
     901    }
    1950902}
    1951903
     
    1958910 * @param   pChild              The child node.
    1959911 */
    1960 static KBOOL kwFsLinkChild(PKWFSOBJ pParent, PKWFSOBJ pChild)
     912static KBOOL kFsCacheDirAddChild(PKFSCACHE pCache, PKFSDIR pParent, PKFSOBJ pChild, KFSLOOKUPERROR *penmError)
    1961913{
    1962914    if ((pParent->cChildren % 16) == 0)
     
    1965917        if (!pvNew)
    1966918            return K_FALSE;
    1967         pParent->papChildren = (PKWFSOBJ *)pvNew;
     919        pParent->papChildren = (PKFSOBJ *)pvNew;
     920        pCache->cbObjects += 16 * sizeof(pParent->papChildren[0]);
    1968921    }
    1969922    pParent->papChildren[pParent->cChildren++] = pChild;
     
    1973926
    1974927/**
    1975  * Creates a child node for an ANSI path.
    1976  *
    1977  * @returns Pointer to the child tree node on success.
    1978  *          NULL on failure (out of memory).
    1979  * @param   pParent             The parent node.
    1980  * @param   pchPath             The path.
    1981  * @param   offName             The offset of the child name into pchPath.
    1982  * @param   cchName             The length of the child name.
    1983  */
    1984 static PKWFSOBJ kwFsCreateChildA(PKWFSOBJ pParent, const char *pchPath, KU32 offName, KU32 cchName)
    1985 {
    1986     char        szTmp[2048];
    1987     DWORD const dwSavedErr = GetLastError();
    1988     DWORD       dwAttr;
    1989     DWORD       dwErr;
    1990     PKWFSOBJ    pChild;
    1991 
     928 * Creates a new cache object.
     929 *
     930 * @returns Pointer (with 1 reference) to the new object.  The object will not
     931 *          be linked to the parent directory yet.
     932 *
     933 *          NULL if we're out of memory.
     934 *
     935 * @param   pCache          The cache.
     936 * @param   pParent         The parent directory.
     937 * @param   pszName         The ANSI name.
     938 * @param   cchName         The length of the ANSI name.
     939 * @param   pwszName        The UTF-16 name.
     940 * @param   cwcName         The length of the UTF-16 name.
     941 * @param   pszShortName    The ANSI short name, NULL if none.
     942 * @param   cchShortName    The length of the ANSI short name, 0 if none.
     943 * @param   pwszShortName   The UTF-16 short name, NULL if none.
     944 * @param   cwcShortName    The length of the UTF-16 short name, 0 if none.
     945 * @param   bObjType        The objct type.
     946 * @param   penmError       Where to explain failures.
     947 */
     948static PKFSOBJ kFsCacheCreateObject(PKFSCACHE pCache, PKFSDIR pParent,
     949                                    char const *pszName, KU16 cchName, wchar_t const *pwszName, KU16 cwcName,
     950#ifdef KFSCACHE_CFG_SHORT_NAMES
     951                                    char const *pszShortName, KU16 cchShortName, wchar_t const *pwszShortName, KU16 cwcShortName,
     952#endif
     953                                    KU8 bObjType, KFSLOOKUPERROR *penmError)
     954{
    1992955    /*
    1993      * Get attributes.
     956     * Allocate the object.
    1994957     */
    1995     if (pchPath[offName + cchName])
    1996     {
    1997         if (cchName + offName >= sizeof(szTmp))
    1998             return NULL;
    1999         memcpy(szTmp, pchPath, offName + cchName);
    2000         if (offName != 0 || cchName != 2 || pchPath[1] != ':')
    2001             szTmp[offName + cchName] = '\0';
     958    KBOOL const fDirish = bObjType != KFSOBJ_TYPE_FILE && bObjType == KFSOBJ_TYPE_OTHER;
     959    KSIZE const cbObj   = (fDirish ? sizeof(KFSDIR) : sizeof(KFSOBJ))
     960                        + (cwcName + 1) * sizeof(wchar_t)                           + cchName + 1
     961#ifdef KFSCACHE_CFG_SHORT_NAMES
     962                        + (cwcShortName > 0 ? (cwcShortName + 1) * sizeof(wchar_t)  + cchShortName + 1 : 0)
     963#endif
     964                          ;
     965    PKFSOBJ pObj = (PKFSOBJ)kHlpAlloc(cbObj);
     966    if (pObj)
     967    {
     968        KU8 *pbExtra = (KU8 *)(pObj + 1);
     969
     970        pCache->cbObjects += cbObj;
     971        pCache->cObjects++;
     972
     973        /*
     974         * Initialize the object.
     975         */
     976        pObj->u32Magic      = KFSOBJ_MAGIC;
     977        pObj->cRefs         = 1;
     978        pObj->uCacheGen     = bObjType != KFSOBJ_TYPE_MISSING ? pCache->uGeneration : pCache->uGenerationMissing;
     979        pObj->bObjType      = bObjType;
     980        pObj->fHaveStats    = K_FALSE;
     981        pObj->abUnused[0]   = K_FALSE;
     982        pObj->abUnused[1]   = K_FALSE;
     983        pObj->fFlags        = pParent->Obj.fFlags;
     984        pObj->pParent       = pParent;
     985
     986#ifdef KFSCACHE_CFG_UTF16
     987        pObj->cwcParent = pParent->Obj.cwcParent + pParent->Obj.cwcName + !!pParent->Obj.cwcName;
     988        pObj->pwszName  = (wchar_t *)kHlpMemCopy(pbExtra, pwszName, cwcName * sizeof(wchar_t));
     989        pbExtra += cwcName * sizeof(wchar_t);
     990        *pbExtra++ = '\0';
     991        *pbExtra++ = '\0';
     992# ifdef KFSCACHE_CFG_SHORT_NAMES
     993        pObj->cwcShortParent = pParent->Obj.cwcShortParent + pParent->Obj.cwcShortName + !!pParent->Obj.cwcShortName;
     994        if (cwcShortName)
     995        {
     996            pObj->pwszShortName = (wchar_t *)kHlpMemCopy(pbExtra, pwszShortName, cwcShortName * sizeof(wchar_t));
     997            pbExtra += cwcShortName * sizeof(wchar_t);
     998            *pbExtra++ = '\0';
     999            *pbExtra++ = '\0';
     1000        }
    20021001        else
    20031002        {
    2004             /* Change 'E:' to 'E:\\.' so that it's actually absolute. */
    2005             szTmp[2] = '\\';
    2006             szTmp[3] = '.';
    2007             szTmp[4] = '\0';
    2008         }
    2009         pchPath = szTmp;
    2010     }
    2011 
    2012     SetLastError(NO_ERROR);
    2013     dwAttr = GetFileAttributesA(pchPath);
    2014     dwErr  = GetLastError();
    2015 
     1003            pObj->pwszShortName = pObj->pwszName;
     1004            pObj->cwcShortName  = pObj->cwcName;
     1005        }
     1006# endif
     1007#endif
     1008        pObj->cchParent = pParent->Obj.cchParent + pParent->Obj.cchName + !!pParent->Obj.cchName;
     1009        pObj->pszName   = (char *)kHlpMemCopy(pbExtra, pszName, cchName);
     1010        pbExtra += cchName;
     1011        *pbExtra++ = '\0';
     1012# ifdef KFSCACHE_CFG_SHORT_NAMES
     1013        pObj->cchShortParent = pParent->Obj.cchShortParent + pParent->Obj.cchShortName + !!pParent->Obj.cchShortName;
     1014        if (cchShortName)
     1015        {
     1016            pObj->pszShortName = (char *)kHlpMemCopy(pbExtra, pszShortName, cchShortName);
     1017            pbExtra += cchShortName;
     1018            *pbExtra++ = '\0';
     1019        }
     1020        else
     1021        {
     1022            pObj->pszShortName = pObj->pszName;
     1023            pObj->cchShortName = pObj->cchName;
     1024        }
     1025#endif
     1026        kHlpAssert(pbExtra - (KU8 *)pObj == cbObj);
     1027
     1028        /*
     1029         * Type specific initilization.
     1030         */
     1031        if (fDirish)
     1032        {
     1033            PKFSDIR pDirObj = (PKFSDIR)pObj;
     1034            pDirObj->cChildren      = 0;
     1035            pDirObj->papChildren    = NULL;
     1036            pDirObj->cHashTab       = 0;
     1037            pDirObj->paHashTab      = NULL;
     1038            pDirObj->hDir           = INVALID_HANDLE_VALUE;
     1039            pDirObj->uDevNo         = pParent->uDevNo;
     1040            pDirObj->fPopulated     = K_FALSE;
     1041        }
     1042    }
     1043    else
     1044        *penmError = KFSLOOKUPERROR_OUT_OF_MEMORY;
     1045    return pObj;
     1046}
     1047
     1048
     1049/**
     1050 * Creates a new object given wide char names.
     1051 *
     1052 * This function just converts the paths and calls kFsCacheCreateObject.
     1053 *
     1054 *
     1055 * @returns Pointer (with 1 reference) to the new object.  The object will not
     1056 *          be linked to the parent directory yet.
     1057 *
     1058 *          NULL if we're out of memory.
     1059 *
     1060 * @param   pCache          The cache.
     1061 * @param   pParent         The parent directory.
     1062 * @param   pszName         The ANSI name.
     1063 * @param   cchName         The length of the ANSI name.
     1064 * @param   pwszName        The UTF-16 name.
     1065 * @param   cwcName         The length of the UTF-16 name.
     1066 * @param   pwszShortName   The UTF-16 short name, NULL if none.
     1067 * @param   cwcShortName    The length of the UTF-16 short name, 0 if none.
     1068 * @param   bObjType        The objct type.
     1069 * @param   penmError       Where to explain failures.
     1070 */
     1071static PKFSOBJ kFsCacheCreateObjectW(PKFSCACHE pCache, PKFSDIR pParent, wchar_t const *pwszName, KU32 cwcName,
     1072#ifdef KFSCACHE_CFG_SHORT_NAMES
     1073                                     wchar_t const *pwszShortName, KU32 cwcShortName,
     1074#endif
     1075                                     KU8 bObjType, KFSLOOKUPERROR *penmError)
     1076{
     1077    /* Convert names to ANSI first so we know their lengths. */
     1078    char szName[KFSCACHE_CFG_MAX_ANSI_NAME];
     1079    int  cchName = WideCharToMultiByte(CP_ACP, 0, pwszName, cwcName, szName, sizeof(szName) - 1, NULL, NULL);
     1080    if (cchName >= 0)
     1081    {
     1082#ifdef KFSCACHE_CFG_SHORT_NAMES
     1083        char szShortName[12*3 + 1];
     1084        int  cchShortName = 0;
     1085        if (   cwcShortName == 0
     1086            || (cchShortName = WideCharToMultiByte(CP_ACP, 0, pwszShortName, cwcShortName,
     1087                                                   szShortName, sizeof(szShortName) - 1, NULL, NULL)) > 0)
     1088#endif
     1089        {
     1090            return kFsCacheCreateObject(pCache, pParent,
     1091                                        szName, cchName, pwszName, cwcName,
     1092#ifdef KFSCACHE_CFG_SHORT_NAMES
     1093                                        szShortName, cchShortName, pwszShortName, cwcShortName,
     1094#endif
     1095                                        bObjType, penmError);
     1096        }
     1097    }
     1098    *penmError = KFSLOOKUPERROR_ANSI_CONVERSION_ERROR;
     1099    return NULL;
     1100}
     1101
     1102
     1103/**
     1104 * Creates a missing object.
     1105 *
     1106 * This is used for caching negative results.
     1107 *
     1108 * @returns Pointer to the newly created object on success (already linked into
     1109 *          pParent).  No reference.
     1110 *
     1111 *          NULL on failure.
     1112 *
     1113 * @param   pCache              The cache.
     1114 * @param   pParent             The parent directory.
     1115 * @param   pchName             The name.
     1116 * @param   cchName             The length of the name.
     1117 * @param   penmError           Where to return failure explanations.
     1118 */
     1119static PKFSOBJ kFsCacheCreateMissingA(PKFSCACHE pCache, PKFSDIR pParent, const char *pchName, KU32 cchName,
     1120                                      KFSLOOKUPERROR *penmError)
     1121{
    20161122    /*
    2017      * Create the entry.
     1123     * Just convert the name to UTF-16 and call kFsCacheCreateObject to do the job.
    20181124     */
    2019     pChild = (PKWFSOBJ)kHlpAlloc(sizeof(*pChild) + cchName + 1 + (cchName + 1) * sizeof(wchar_t) * 2);
    2020     SetLastError(dwSavedErr);
    2021     if (pChild)
    2022     {
    2023         pChild->pwszName    = (const wchar_t *)(pChild + 1);
    2024         pChild->pszName     = (const char *)kHlpMemCopy((void *)&pChild->pwszName[(cchName + 1) * 2],
    2025                                                         &pchPath[offName], cchName);
    2026         ((char *)pChild->pszName)[cchName] = '\0';
    2027         pChild->cwcName     = (KU16)kwStrToUtf16(pChild->pszName, (wchar_t *)pChild->pwszName, (cchName + 1) * 2);
    2028 
    2029         pChild->cchName     = cchName;
    2030         pChild->cChildren   = 0;
    2031         pChild->papChildren = NULL;
    2032         pChild->pParent     = pParent;
    2033 
    2034         pChild->uCacheGen   = pParent->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE ? KFSWOBJ_CACHE_GEN_IGNORE : g_uFsCacheGeneration;
    2035         pChild->fAttribs    = dwAttr;
    2036         pChild->uLastError  = dwErr;
    2037 
    2038         pChild->hCached     = INVALID_HANDLE_VALUE;
    2039         pChild->cbCached    = 0;
    2040         pChild->pbCached    = NULL;
    2041 
    2042         if (kwFsLinkChild(pParent, pChild))
    2043             return pChild;
    2044 
    2045         kHlpFree(pChild);
    2046     }
     1125    wchar_t wszName[KFSCACHE_CFG_MAX_PATH];
     1126    int cwcName = MultiByteToWideChar(CP_ACP, 0, pchName, cchName, wszName, KFSCACHE_CFG_MAX_UTF16_NAME - 1);
     1127    if (cwcName > 0)
     1128    {
     1129        /** @todo check that it actually doesn't exists before we add it.  We should not
     1130         *        trust the directory enumeration here, or maybe we should?? */
     1131
     1132        PKFSOBJ pMissing = kFsCacheCreateObject(pCache, pParent, pchName, cchName, wszName, cwcName,
     1133#ifdef KFSCACHE_CFG_SHORT_NAMES
     1134                                                NULL, 0, NULL, 0,
     1135#endif
     1136                                                KFSOBJ_TYPE_MISSING, penmError);
     1137        if (pMissing)
     1138        {
     1139            KBOOL fRc = kFsCacheDirAddChild(pCache, pParent, pMissing, penmError);
     1140            kFsCacheObjRelease(pCache, pMissing);
     1141            return fRc ? pMissing : NULL;
     1142        }
     1143        return NULL;
     1144    }
     1145    *penmError = KFSLOOKUPERROR_UTF16_CONVERSION_ERROR;
    20471146    return NULL;
    20481147}
     
    20501149
    20511150/**
     1151 * Does the initial directory populating or refreshes it if it has been
     1152 * invalidated.
     1153 *
     1154 * This assumes the parent directory is opened.
     1155 *
     1156 * @returns K_TRUE on success, K_FALSE on error.
     1157 * @param   pCache              The cache.
     1158 * @param   pDir                The directory.
     1159 * @param   penmError           Where to store K_FALSE explanation.
     1160 */
     1161static KBOOL kFsCachePopuplateOrRefreshDir(PKFSCACHE pCache, PKFSDIR pDir, KFSLOOKUPERROR *penmError)
     1162{
     1163    KBOOL                       fRefreshing  = K_FALSE;
     1164    /** @todo will have to make this more flexible wrt information classes since
     1165     *        older windows versions (XP, w2K) might not correctly support the
     1166     *        ones with file ID on all file systems. */
     1167#ifdef KFSCACHE_CFG_SHORT_NAMES
     1168    MY_FILE_INFORMATION_CLASS   enmInfoClass = MyFileIdBothDirectoryInformation;
     1169#else
     1170    MY_FILE_INFORMATION_CLASS   enmInfoClass = MyFileIdFullDirectoryInformation;
     1171#endif
     1172    MY_NTSTATUS                 rcNt;
     1173    MY_IO_STATUS_BLOCK          Ios;
     1174    union
     1175    {
     1176        /* Include the structures for better alignment. */
     1177        MY_FILE_ID_BOTH_DIR_INFORMATION     WithId;
     1178        MY_FILE_ID_FULL_DIR_INFORMATION     NoId;
     1179        /* Buffer padding. We're using a 56KB buffer here to avoid size troubles with CIFS and such. */
     1180        KU8                                 abBuf[56*1024];
     1181    } uBuf;
     1182
     1183    /*
     1184     * Open the directory.
     1185     */
     1186    if (pDir->hDir == INVALID_HANDLE_VALUE)
     1187    {
     1188        MY_OBJECT_ATTRIBUTES    ObjAttr;
     1189        MY_UNICODE_STRING       UniStr;
     1190
     1191        kHlpAssert(!pDir->fPopulated);
     1192
     1193        Ios.Information = -1;
     1194        Ios.u.Status    = -1;
     1195
     1196        UniStr.Buffer        = (wchar_t *)pDir->Obj.pwszName;
     1197        UniStr.Length        = (USHORT)(pDir->Obj.cwcName * sizeof(wchar_t));
     1198        UniStr.MaximumLength = UniStr.Length + sizeof(wchar_t);
     1199
     1200        kHlpAssertStmtReturn(pDir->Obj.pParent, *penmError = KFSLOOKUPERROR_INTERNAL_ERROR, K_FALSE);
     1201        kHlpAssertStmtReturn(pDir->Obj.pParent->hDir != INVALID_HANDLE_VALUE, *penmError = KFSLOOKUPERROR_INTERNAL_ERROR, K_FALSE);
     1202        MyInitializeObjectAttributes(&ObjAttr, &UniStr, OBJ_CASE_INSENSITIVE, pDir->Obj.pParent->hDir, NULL /*pSecAttr*/);
     1203
     1204        /** @todo FILE_OPEN_REPARSE_POINT? */
     1205        rcNt = g_pfnNtCreateFile(&pDir->hDir,
     1206                                 FILE_READ_DATA | FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
     1207                                 &ObjAttr,
     1208                                 &Ios,
     1209                                 NULL, /*cbFileInitialAlloc */
     1210                                 FILE_ATTRIBUTE_NORMAL,
     1211                                 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
     1212                                 FILE_OPEN,
     1213                                 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
     1214                                 NULL, /*pEaBuffer*/
     1215                                 0);   /*cbEaBuffer*/
     1216        if (MY_NT_SUCCESS(rcNt))
     1217        {  /* likely */ }
     1218        else
     1219        {
     1220            pDir->hDir = INVALID_HANDLE_VALUE;
     1221            *penmError = KFSLOOKUPERROR_DIR_OPEN_ERROR;
     1222            return K_FALSE;
     1223        }
     1224    }
     1225    else if (pDir->fPopulated)
     1226    {
     1227        /** @todo refreshing directories. */
     1228        __debugbreak();
     1229        fRefreshing = K_TRUE;
     1230    }
     1231
     1232
     1233    /*
     1234     * Enumerate the directory content.
     1235     */
     1236    Ios.Information = -1;
     1237    Ios.u.Status    = -1;
     1238    rcNt = g_pfnNtQueryDirectoryFile(pDir->hDir,
     1239                                     NULL,      /* hEvent */
     1240                                     NULL,      /* pfnApcComplete */
     1241                                     NULL,      /* pvApcCompleteCtx */
     1242                                     &Ios,
     1243                                     &uBuf,
     1244                                     sizeof(uBuf),
     1245                                     enmInfoClass,
     1246                                     FALSE,     /* fReturnSingleEntry */
     1247                                     NULL,      /* Filter / restart pos. */
     1248                                     TRUE);     /* fRestartScan */
     1249    while (MY_NT_SUCCESS(rcNt))
     1250    {
     1251        /*
     1252         * Process the entries in the buffer.
     1253         */
     1254        KSIZE offBuf = 0;
     1255        for (;;)
     1256        {
     1257            union
     1258            {
     1259                KU8                             *pb;
     1260#ifdef KFSCACHE_CFG_SHORT_NAMES
     1261                MY_FILE_ID_BOTH_DIR_INFORMATION *pWithId;
     1262                MY_FILE_BOTH_DIR_INFORMATION    *pNoId;
     1263#else
     1264                MY_FILE_ID_FULL_DIR_INFORMATION *pWithId;
     1265                MY_FILE_FULL_DIR_INFORMATION    *pNoId;
     1266#endif
     1267            }           uPtr;
     1268            PKFSOBJ     pCur;
     1269            KU32        offNext;
     1270            KU32        cbMinCur;
     1271            wchar_t    *pwszFilename;
     1272
     1273            /* ASSUME only the FileName member differs between the two structures. */
     1274            uPtr.pb = &uBuf.abBuf[offBuf];
     1275#ifdef KFSCACHE_CFG_SHORT_NAMES
     1276            pwszFilename = enmInfoClass == MyFileIdBothDirectoryInformation
     1277                         ? &uPtr.pWithId->FileName[0] :  &uPtr.pNoId->FileName[0];
     1278#else
     1279            pwszFilename = enmInfoClass == MyFileIdFullDirectoryInformation
     1280                         ? &uPtr.pWithId->FileName[0] :  &uPtr.pNoId->FileName[0];
     1281#endif
     1282            /*
     1283             * Create the entry (not linked yet).
     1284             */
     1285            pCur = kFsCacheCreateObjectW(pCache, pDir, pwszFilename, uPtr.pNoId->FileNameLength / sizeof(wchar_t),
     1286#ifdef KFSCACHE_CFG_SHORT_NAMES
     1287                                         uPtr.pNoId->ShortName, uPtr.pNoId->ShortNameLength / sizeof(wchar_t),
     1288#endif
     1289                                         uPtr.pNoId->FileAttributes & FILE_ATTRIBUTE_DIRECTORY ? KFSOBJ_TYPE_DIR
     1290                                         : uPtr.pNoId->FileAttributes & (FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_REPARSE_POINT)
     1291                                         ? KFSOBJ_TYPE_OTHER : KFSOBJ_TYPE_FILE,
     1292                                         penmError);
     1293            if (!pCur)
     1294                return K_FALSE;
     1295            kHlpAssert(pCur->cRefs == 1);
     1296
     1297#ifdef KFSCACHE_CFG_SHORT_NAMES
     1298            if (enmInfoClass == MyFileIdBothDirectoryInformation)
     1299                birdStatFillFromFileIdBothDirInfo(&pCur->Stats, uPtr.pWithId, pCur->pszName);
     1300            else
     1301                birdStatFillFromFileBothDirInfo(&pCur->Stats, uPtr.pNoId, pCur->pszName);
     1302#else
     1303            if (enmInfoClass == MyFileIdBothDirectoryInformation)
     1304                birdStatFillFromFileIdFullDirInfo(&pCur->Stats, uPtr.pWithId, pCur->pszName);
     1305            else
     1306                birdStatFillFromFileFullDirInfo(&pCur->Stats, uPtr.pNoId, pCur->pszName);
     1307#endif
     1308            pCur->Stats.st_dev = pDir->uDevNo;
     1309
     1310            /*
     1311             * If we're updating we have to check the data.
     1312             */
     1313            if (fRefreshing)
     1314            {
     1315                __debugbreak();
     1316            }
     1317
     1318            /*
     1319             * If we've still got pCur, add it to the directory.
     1320             */
     1321            if (pCur)
     1322            {
     1323                KBOOL fRc = kFsCacheDirAddChild(pCache, pDir, pCur, penmError);
     1324                kFsCacheObjRelease(pCache, pCur);
     1325                if (fRc)
     1326                { /* likely */ }
     1327                else
     1328                    return K_FALSE;
     1329            }
     1330
     1331            /*
     1332             * Advance.
     1333             */
     1334            offNext = uPtr.pNoId->NextEntryOffset;
     1335            if (   offNext >= cbMinCur
     1336                && offNext < sizeof(uBuf))
     1337                offBuf += offNext;
     1338            else
     1339                break;
     1340        }
     1341
     1342        /*
     1343         * Read the next chunk.
     1344         */
     1345        rcNt = g_pfnNtQueryDirectoryFile(pDir->hDir,
     1346                                         NULL,      /* hEvent */
     1347                                         NULL,      /* pfnApcComplete */
     1348                                         NULL,      /* pvApcCompleteCtx */
     1349                                         &Ios,
     1350                                         &uBuf,
     1351                                         sizeof(uBuf),
     1352                                         enmInfoClass,
     1353                                         FALSE,     /* fReturnSingleEntry */
     1354                                         NULL,      /* Filter / restart pos. */
     1355                                         FALSE);    /* fRestartScan */
     1356    }
     1357
     1358    if (rcNt == MY_STATUS_NO_MORE_FILES)
     1359        return K_TRUE;
     1360    kHlpAssertMsgFailed(("%#x\n", rcNt));
     1361    *penmError = KFSLOOKUPERROR_DIR_READ_ERROR;
     1362    return K_TRUE;
     1363}
     1364
     1365
     1366static KBOOL kFsCacheRefreshMissing(PKFSCACHE pCache, PKFSOBJ pMissing, KFSLOOKUPERROR *penmError)
     1367{
     1368    return K_TRUE;
     1369}
     1370
     1371
     1372static KBOOL kFsCacheRefreshMissingIntermediateDir(PKFSCACHE pCache, PKFSOBJ pMissing, KFSLOOKUPERROR *penmError)
     1373{
     1374    return K_TRUE;
     1375}
     1376
     1377
     1378static KBOOL kFsCacheRefreshObj(PKFSCACHE pCache, PKFSOBJ pObj, KFSLOOKUPERROR *penmError)
     1379{
     1380    return K_FALSE;
     1381}
     1382
     1383
     1384/**
     1385 * Refreshes a path hash that has expired.
     1386 *
     1387 * @returns pHash on success, NULL if removed.
     1388 * @param   pCache              The cache.
     1389 * @param   pHashEntry          The path hash.
     1390 * @param   idxHashTab          The hash table entry.
     1391 */
     1392static PKFSHASHA kFsCacheRefreshPathA(PKFSCACHE pCache, PKFSHASHA pHashEntry, KU32 idxHashTab)
     1393{
     1394    /** @todo implement once we've start inserting uCacheGen nodes. */
     1395    __debugbreak();
     1396    K_NOREF(pCache);
     1397    K_NOREF(idxHashTab);
     1398    return pHashEntry;
     1399}
     1400
     1401
     1402/**
    20521403 * Look up a child node, ANSI version.
    20531404 *
    20541405 * @returns Pointer to the child if found, NULL if not.
    2055  * @param   pParent             The parent to search the children of.
     1406 * @param   pCache              The cache.
     1407 * @param   pParent             The parent directory to search.
    20561408 * @param   pchName             The child name to search for (not terminated).
    20571409 * @param   cchName             The length of the child name.
    20581410 */
    2059 static PKWFSOBJ kwFsFindChildA(PKWFSOBJ pParent, const char *pchName, KU32 cchName)
     1411static PKFSOBJ kFsCacheFindChildA(PKFSCACHE pCache, PKFSDIR pParent, const char *pchName, KU32 cchName)
    20601412{
    20611413    /* Check for '.' first. */
    20621414    if (cchName != 1 || *pchName != '.')
    20631415    {
    2064         KU32        cLeft = pParent->cChildren;
    2065         PKWFSOBJ   *ppCur = pParent->papChildren;
     1416        KU32        cLeft;
     1417        PKFSOBJ    *ppCur;
     1418
     1419        if (pParent->paHashTab != NULL)
     1420        {
     1421            /** @todo directory hash table lookup.   */
     1422        }
     1423
     1424        /* Linear search. */
     1425        cLeft = pParent->cChildren;
     1426        ppCur = pParent->papChildren;
    20661427        while (cLeft-- > 0)
    20671428        {
    2068             PKWFSOBJ pCur = *ppCur++;
    2069             if (   pCur->cchName == cchName
    2070                 && _memicmp(pCur->pszName, pchName, cchName) == 0)
     1429            PKFSOBJ pCur = *ppCur++;
     1430            if (   (   pCur->cchName == cchName
     1431                    && _memicmp(pCur->pszName, pchName, cchName) == 0)
     1432#ifdef KFSCACHE_CFG_SHORT_NAMES
     1433                || (   pCur->cchShortName == cchName
     1434                    && pCur->pszShortName != pCur->pszName
     1435                    && _memicmp(pCur->pszName, pchName, cchName) == 0)
     1436#endif
     1437               )
     1438                return pCur;
     1439        }
     1440        return NULL;
     1441    }
     1442    return &pParent->Obj;
     1443}
     1444
     1445
     1446/**
     1447 * Looks up a UNC share, ANSI version.
     1448 *
     1449 * We keep both the server and share in the root directory entry.  This means we
     1450 * have to clean up the entry name before we can insert it.
     1451 *
     1452 * @returns Pointer to the share root directory or an update-to-date missing
     1453 *          node.
     1454 * @param   pCache              The cache.
     1455 * @param   pszPath             The path.
     1456 * @param   poff                Where to return the root dire.
     1457 * @param   penmError           Where to return details as to why the lookup
     1458 *                              failed.
     1459 */
     1460static PKFSOBJ kFswCacheLookupUncShareA(PKFSCACHE pCache, const char *pszPath, KU32 *poff, KFSLOOKUPERROR *penmError)
     1461{
     1462#if 0 /* later */
     1463    KU32 offStartServer;
     1464    KU32 offEndServer;
     1465    KU32 offStartShare;
     1466
     1467    KU32 offEnd = 2;
     1468    while (IS_SLASH(pszPath[offEnd]))
     1469        offEnd++;
     1470
     1471    offStartServer = offEnd;
     1472    while (   (ch = pszPath[offEnd]) != '\0'
     1473           && !IS_SLASH(ch))
     1474        offEnd++;
     1475    offEndServer = offEnd;
     1476
     1477    if (ch != '\0')
     1478    { /* likely */ }
     1479    else
     1480    {
     1481        *penmError = KFSLOOKUPERROR_NOT_FOUND;
     1482        return NULL;
     1483    }
     1484
     1485    while (IS_SLASH(pszPath[offEnd]))
     1486        offEnd++;
     1487    offStartServer = offEnd;
     1488    while (   (ch = pszPath[offEnd]) != '\0'
     1489           && !IS_SLASH(ch))
     1490        offEnd++;
     1491#endif
     1492    *penmError = KFSLOOKUPERROR_UNSUPPORTED;
     1493    return NULL;
     1494}
     1495
     1496
     1497/**
     1498 * Looks up a drive letter.
     1499 *
     1500 * Will enter the drive if necessary.
     1501 *
     1502 * @returns Pointer to the root directory of the drive or an update-to-date
     1503 *          missing node.
     1504 * @param   pCache              The cache.
     1505 * @param   chLetter            The uppercased drive letter.
     1506 * @param   penmError           Where to return details as to why the lookup
     1507 *                              failed.
     1508 */
     1509static PKFSOBJ kFswCacheLookupDrive(PKFSCACHE pCache, char chLetter, KFSLOOKUPERROR *penmError)
     1510{
     1511    KU32 const          uHash = chLetter - 'A';
     1512    KU32                cLeft;
     1513    PKFSOBJ            *ppCur;
     1514
     1515    MY_UNICODE_STRING   NtPath;
     1516    wchar_t             wszTmp[8];
     1517    MY_NTSTATUS         rcNt;
     1518    char                szTmp[4];
     1519
     1520    /*
     1521     * Custom drive letter hashing.
     1522     */
     1523    if (pCache->RootDir.paHashTab)
     1524    {
     1525        /** @todo PKFSOBJHASH pHash = */
     1526    }
     1527
     1528    /*
     1529     * Special cased lookup.
     1530     */
     1531    cLeft = pCache->RootDir.cChildren;
     1532    ppCur = pCache->RootDir.papChildren;
     1533    while (cLeft-- > 0)
     1534    {
     1535        PKFSOBJ pCur = *ppCur++;
     1536        if (   pCur->cchName == 2
     1537            && pCur->pszName[0] == chLetter
     1538            && pCur->pszName[1] == ':')
     1539        {
     1540            if (pCur->bObjType == KFSOBJ_TYPE_DIR)
     1541                return pCur;
     1542            kHlpAssert(pCur->bObjType == KFSOBJ_TYPE_MISSING);
     1543            if (kFsCacheRefreshMissingIntermediateDir(pCache, pCur, penmError))
     1544                return pCur;
     1545            return NULL;
     1546        }
     1547    }
     1548
     1549    /*
     1550     * Need to add it.  We always keep the drive letters open for the benefit
     1551     * of kFsCachePopuplateOrRefreshDir and others.
     1552     */
     1553    wszTmp[0] = szTmp[0] = chLetter;
     1554    wszTmp[1] = szTmp[1] = ':';
     1555    wszTmp[2] = szTmp[2] = '\\';
     1556    wszTmp[3] = '.';
     1557    wszTmp[4] = '\0';
     1558    szTmp[2] = '\0';
     1559
     1560    NtPath.Buffer        = NULL;
     1561    NtPath.Length        = 0;
     1562    NtPath.MaximumLength = 0;
     1563    if (g_pfnRtlDosPathNameToNtPathName_U(wszTmp, &NtPath, NULL, NULL))
     1564    {
     1565        HANDLE hDir;
     1566        rcNt = birdOpenFileUniStr(&NtPath,
     1567                                  FILE_READ_DATA  | FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
     1568                                  FILE_ATTRIBUTE_NORMAL,
     1569                                  FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
     1570                                  FILE_OPEN,
     1571                                  FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
     1572                                  OBJ_CASE_INSENSITIVE,
     1573                                  &hDir);
     1574        birdFreeNtPath(&NtPath);
     1575        if (MY_NT_SUCCESS(rcNt))
     1576        {
     1577            PKFSDIR pDir = (PKFSDIR)kFsCacheCreateObject(pCache, &pCache->RootDir, szTmp, 2, wszTmp, 2,
     1578#ifdef KFSCACHE_CFG_SHORT_NAMES
     1579                                                         NULL, 0, NULL, 0,
     1580#endif
     1581                                                         KFSOBJ_TYPE_DIR, penmError);
     1582            if (pDir)
    20711583            {
    2072                 if (   pCur->uCacheGen != KFSWOBJ_CACHE_GEN_IGNORE
    2073                     && pCur->uCacheGen != g_uFsCacheGeneration)
    2074                     kwFsRefreshNode(pCur);
    2075                 return pCur;
     1584                /*
     1585                 * We need a little bit of extra info for a drive root.  These things are typically
     1586                 * inherited by subdirectories down the tree, so, we do it all here for till that changes.
     1587                 */
     1588                union
     1589                {
     1590                    MY_FILE_FS_VOLUME_INFORMATION       VolInfo;
     1591                    MY_FILE_FS_ATTRIBUTE_INFORMATION    FsAttrInfo;
     1592                    char abPadding[sizeof(MY_FILE_FS_VOLUME_INFORMATION) + 512];
     1593                } uBuf;
     1594                MY_IO_STATUS_BLOCK Ios;
     1595                KBOOL fRc;
     1596
     1597                kHlpAssert(pDir->hDir == INVALID_HANDLE_VALUE);
     1598                pDir->hDir = hDir;
     1599
     1600                /* Get the device number. */
     1601                rcNt = birdQueryVolumeDeviceNumber(hDir, &uBuf.VolInfo, sizeof(uBuf), &pDir->uDevNo);
     1602                kHlpAssertMsg(MY_NT_SUCCESS(rcNt), ("%#x\n", rcNt));
     1603
     1604                /* Get the file system. */
     1605                pDir->Obj.fFlags &= ~(KFSOBJ_F_NTFS | KFSOBJ_F_WORKING_DIR_MTIME);
     1606                Ios.Information = -1;
     1607                Ios.u.Status    = -1;
     1608                rcNt = g_pfnNtQueryVolumeInformationFile(hDir, &Ios, &uBuf.FsAttrInfo, sizeof(uBuf),
     1609                                                         MyFileFsAttributeInformation);
     1610                if (MY_NT_SUCCESS(rcNt))
     1611                    rcNt = Ios.u.Status;
     1612                if (MY_NT_SUCCESS(rcNt))
     1613                {
     1614                    if (   uBuf.FsAttrInfo.FileSystemName[0] == 'N'
     1615                        && uBuf.FsAttrInfo.FileSystemName[1] == 'T'
     1616                        && uBuf.FsAttrInfo.FileSystemName[2] == 'F'
     1617                        && uBuf.FsAttrInfo.FileSystemName[3] == 'S'
     1618                        && uBuf.FsAttrInfo.FileSystemName[4] == '\0')
     1619                    {
     1620                        DWORD dwDriveType = GetDriveTypeW(wszTmp);
     1621                        if (   dwDriveType == DRIVE_FIXED
     1622                            || dwDriveType == DRIVE_RAMDISK)
     1623                            pDir->Obj.fFlags |= KFSOBJ_F_NTFS | KFSOBJ_F_WORKING_DIR_MTIME;
     1624                    }
     1625                }
     1626
     1627                /*
     1628                 * Link the new drive letter into the root dir.
     1629                 */
     1630                fRc = kFsCacheDirAddChild(pCache, &pCache->RootDir, &pDir->Obj, penmError);
     1631                kFsCacheObjRelease(pCache, &pDir->Obj);
     1632                return fRc ? &pDir->Obj : NULL;
    20761633            }
    2077         }
     1634
     1635            g_pfnNtClose(hDir);
     1636            return NULL;
     1637        }
     1638
     1639        /* Assume it doesn't exist if this happens... This may be a little to
     1640           restrictive wrt status code checks. */
     1641        kHlpAssertMsgStmtReturn(   rcNt == MY_STATUS_OBJECT_NAME_NOT_FOUND
     1642                                || rcNt == MY_STATUS_OBJECT_PATH_NOT_FOUND
     1643                                || rcNt == MY_STATUS_OBJECT_PATH_INVALID
     1644                                || rcNt == MY_STATUS_OBJECT_PATH_SYNTAX_BAD,
     1645                                ("%#x\n", rcNt),
     1646                                *penmError = KFSLOOKUPERROR_DIR_OPEN_ERROR,
     1647                                NULL);
     1648    }
     1649    else
     1650    {
     1651        kHlpAssertFailed();
     1652        *penmError = KFSLOOKUPERROR_OUT_OF_MEMORY;
    20781653        return NULL;
    20791654    }
    2080     return pParent;
     1655
     1656    /*
     1657     * Maybe create a missing entry.
     1658     */
     1659    if (pCache->fFlags & KFSCACHE_F_MISSING_OBJECTS)
     1660    {
     1661        PKFSOBJ pMissing = kFsCacheCreateObject(pCache, &pCache->RootDir, szTmp, 2, wszTmp, 2,
     1662#ifdef KFSCACHE_CFG_SHORT_NAMES
     1663                                        NULL, 0, NULL, 0,
     1664#endif
     1665                                        KFSOBJ_TYPE_MISSING, penmError);
     1666        if (pMissing)
     1667        {
     1668            KBOOL fRc = kFsCacheDirAddChild(pCache, &pCache->RootDir, pMissing, penmError);
     1669            kFsCacheObjRelease(pCache, pMissing);
     1670            return fRc ? pMissing : NULL;
     1671        }
     1672    }
     1673    else
     1674    {
     1675        /** @todo this isn't necessary correct for a root spec.   */
     1676        *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND;
     1677    }
     1678    return NULL;
    20811679}
    20821680
     
    20881686 * This will create any missing nodes while walking.
    20891687 *
     1688 * The caller will have to do the path hash table insertion of the result.
     1689 *
    20901690 * @returns Pointer to the tree node corresponding to @a pszPath.
    2091  *          NULL if we ran out of memory.
     1691 *          NULL on lookup failure, see @a penmError for details.
     1692 * @param   pCache              The cache.
    20921693 * @param   pszPath             The path to walk.
    20931694 * @param   cchPath             The length of the path.
    2094  * @param   uHashPath           The hash of the path.
    2095  * @param   idxHashTab          Index into the hash table.
    2096  */
    2097 static PKWFSOBJ kwFsLookupAbsoluteA(const char *pszPath, KU32 cchPath, KU32 uHashPath, KU32 idxHashTab)
    2098 {
    2099     PKWFSOBJ    pParent = &g_FsRoot;
     1695 * @param   penmError           Where to return details as to why the lookup
     1696 *                              failed.
     1697 */
     1698static PKFSOBJ kFsCacheLookupAbsoluteA(PKFSCACHE pCache, const char *pszPath, KU32 cchPath, KFSLOOKUPERROR *penmError)
     1699{
     1700    PKFSDIR     pParent = &pCache->RootDir;
     1701    PKFSOBJ     pChild;
    21001702    KU32        off;
    2101     KWFS_LOG(("kwFsLookupAbsoluteA(%s)\n", pszPath));
    2102 
    2103     kHlpAssert(IS_ALPHA(pszPath[0]));
    2104     kHlpAssert(pszPath[1] == ':');
    2105     kHlpAssert(IS_SLASH(pszPath[2]));
    2106 
    2107     off = 0;
     1703    char        ch;
     1704    KU32        cchSlashes;
     1705    KU32        offEnd;
     1706
     1707    KFSCACHE_LOG(("kFsCacheLookupAbsoluteA(%s)\n", pszPath));
     1708
     1709    /*
     1710     * The root "directory" needs special handling, so we keep it outside the
     1711     * main search loop. (Special: Cannot enumerate it, UNCs, ++.)
     1712     */
     1713    cchSlashes = 0;
     1714    off        = 0;
     1715    if (   pszPath[1] == ':'
     1716        && IS_ALPHA(pszPath[0]))
     1717    {
     1718        /* Drive letter. */
     1719        offEnd = 2;
     1720        kHlpAssert(IS_SLASH(pszPath[2]));
     1721        pChild = kFswCacheLookupDrive(pCache, toupper(pszPath[0]), penmError);
     1722    }
     1723    else if (   IS_SLASH(pszPath[0])
     1724             && IS_SLASH(pszPath[1]) )
     1725        pChild = kFswCacheLookupUncShareA(pCache, pszPath, &offEnd, penmError);
     1726    else
     1727    {
     1728        *penmError = KFSLOOKUPERROR_UNSUPPORTED;
     1729        return NULL;
     1730    }
     1731    if (pChild)
     1732    { /* likely */ }
     1733    else
     1734        return NULL;
     1735
     1736    /* Count slashes trailing the root spec. */
     1737    if (offEnd < cchPath)
     1738    {
     1739        kHlpAssert(IS_SLASH(pszPath[offEnd]));
     1740        do
     1741            cchSlashes++;
     1742        while (IS_SLASH(pszPath[offEnd + cchSlashes]));
     1743    }
     1744
     1745    /* Done already? */
     1746    if (offEnd >= cchPath)
     1747    {
     1748        if (   pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
     1749            || pChild->uCacheGen == (pChild->bObjType != KFSOBJ_TYPE_MISSING ? pCache->uGeneration : pCache->uGenerationMissing)
     1750            || kFsCacheRefreshObj(pCache, pChild, penmError))
     1751            return kFsCacheObjRetainInternal(pChild);
     1752        return NULL;
     1753    }
     1754
     1755    /* Check that we've got a valid result and not a cached negative one. */
     1756    if (pChild->bObjType == KFSOBJ_TYPE_DIR)
     1757    { /* likely */ }
     1758    else
     1759    {
     1760        kHlpAssert(pChild->bObjType == KFSOBJ_TYPE_MISSING);
     1761        kHlpAssert(pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE || pChild->uCacheGen == pCache->uGenerationMissing);
     1762        return pChild;
     1763    }
     1764
     1765    /* Next component. */
     1766    pParent = (PKFSDIR)pChild;
     1767    off     = offEnd + cchSlashes;
     1768
     1769
     1770    /*
     1771     * Walk loop.
     1772     */
    21081773    for (;;)
    21091774    {
    2110         PKWFSOBJ    pChild;
    2111 
    2112         /* Find the end of the component. */
    2113         char        ch;
    2114         KU32        cchSlashes = 0;
    2115         KU32        offEnd = off + 1;
     1775        /*
     1776         * Find the end of the component, counting trailing slashes.
     1777         */
     1778        cchSlashes = 0;
     1779        offEnd     = off + 1;
    21161780        while ((ch = pszPath[offEnd]) != '\0')
    21171781        {
     
    21271791        }
    21281792
    2129         /* Search the current node for the name. */
    2130         pChild = kwFsFindChildA(pParent, &pszPath[off], offEnd - off);
    2131         if (!pChild)
    2132         {
    2133             pChild = kwFsCreateChildA(pParent, pszPath, off, offEnd - off);
    2134             if (!pChild)
    2135                 break;
    2136         }
     1793        /*
     1794         * Do we need to populate or refresh this directory first?
     1795         */
     1796        if (   pParent->fPopulated
     1797            && (   pParent->Obj.uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
     1798                || pParent->Obj.uCacheGen == pCache->uGeneration) )
     1799        { /* likely */ }
     1800        else if (kFsCachePopuplateOrRefreshDir(pCache, pParent, penmError))
     1801        { /* likely */ }
     1802        else
     1803            return NULL;
     1804
     1805        /*
     1806         * Search the current node for the name.
     1807         *
     1808         * If we don't find it, we may insert a missing node depending on
     1809         * the cache configuration.
     1810         */
     1811        pChild = kFsCacheFindChildA(pCache, pParent, &pszPath[off], offEnd - off);
     1812        if (pChild != NULL)
     1813        { /* probably likely */ }
     1814        else
     1815        {
     1816            if (pCache->fFlags & KFSCACHE_F_MISSING_OBJECTS)
     1817                pChild = kFsCacheCreateMissingA(pCache, pParent, &pszPath[off], offEnd - off, penmError);
     1818            if (cchSlashes == 0 || offEnd + cchSlashes >= cchPath)
     1819            {
     1820                if (pChild)
     1821                    return pChild;
     1822                *penmError = KFSLOOKUPERROR_NOT_FOUND;
     1823            }
     1824            else
     1825                *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND;
     1826            return NULL;
     1827        }
     1828
     1829        /* Advance off and check if we're done already. */
    21371830        off = offEnd + cchSlashes;
    21381831        if (   cchSlashes == 0
    21391832            || off >= cchPath)
    21401833        {
    2141             kwFsCreateHashTabEntryA(pChild, pszPath, cchPath, uHashPath, idxHashTab);
     1834            if (   pChild->bObjType != KFSOBJ_TYPE_MISSING
     1835                || pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
     1836                || pChild->uCacheGen == pCache->uGenerationMissing
     1837                || kFsCacheRefreshMissing(pCache, pChild, penmError) )
     1838            { /* likely */ }
     1839            else
     1840                return NULL;
    21421841            return pChild;
    21431842        }
    21441843
    2145         /* Check that it's a directory (won't match INVALID_FILE_ATTRIBUTES). */
    2146         if (!(pChild->fAttribs & FILE_ATTRIBUTE_DIRECTORY))
    2147             return &g_FsPathNotFound;
    2148 
    2149         pParent = pChild;
     1844        /*
     1845         * Check that it's a directory.  If a missing entry, we may have to
     1846         * refresh it and re-examin it.
     1847         */
     1848        if (pChild->bObjType == KFSOBJ_TYPE_DIR)
     1849            pParent = (PKFSDIR)pChild;
     1850        else if (pChild->bObjType != KFSOBJ_TYPE_MISSING)
     1851        {
     1852            *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_DIR;
     1853            return NULL;
     1854        }
     1855        else if (   pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
     1856                 || pChild->uCacheGen == pCache->uGenerationMissing)
     1857        {
     1858            *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND;
     1859            return NULL;
     1860        }
     1861        else if (kFsCacheRefreshMissingIntermediateDir(pCache, pChild, penmError))
     1862            pParent = (PKFSDIR)pChild;
     1863        else
     1864            return NULL;
    21501865    }
    21511866
     
    21601875 * @returns Pointer to object corresponding to @a pszPath on success.
    21611876 *          NULL if this isn't a path we care to cache.
     1877 *
     1878 * @param   pCache              The cache.
    21621879 * @param   pszPath             The path.
    21631880 * @param   cchPath             The length of the path.
    2164  * @param   uHashPath           The hash of the path.
    2165  * @param   idxHashTab          The path table index.
    2166  */
    2167 static PKWFSOBJ kwFsLookupSlowA(const char *pszPath, KU32 cchPath, KU32 uHashPath, KU32 idxHashTab)
    2168 {
    2169     /* Turns out getcwd/_getdcwd uses GetFullPathName internall, so just call it directly here. */
    2170     char szFull[2048];
     1881 * @param   penmError           Where to return details as to why the lookup
     1882 *                              failed.
     1883 */
     1884static PKFSOBJ kFsCacheLookupSlowA(PKFSCACHE pCache, const char *pszPath, KU32 cchPath, KFSLOOKUPERROR *penmError)
     1885{
     1886    /*
     1887     * We just call GetFullPathNameA here to do the job as getcwd and _getdcwd
     1888     * ends up calling it anyway.
     1889     */
     1890    char szFull[KFSCACHE_CFG_MAX_PATH];
    21711891    UINT cchFull = GetFullPathNameA(pszPath, sizeof(szFull), szFull, NULL);
    21721892    if (   cchFull >= 3
    21731893        && cchFull < sizeof(szFull))
    21741894    {
    2175         KWFS_LOG(("kwFsLookupSlowA(%s)\n", pszPath));
    2176         if (   szFull[1] == ':'
    2177             && IS_SLASH(szFull[2])
    2178             && IS_ALPHA(szFull[0]) )
    2179         {
    2180             KU32     uHashPath2  = kwStrHash(szFull);
    2181             PKWFSOBJ pFsObj = kwFsLookupAbsoluteA(szFull, cchFull, uHashPath2, uHashPath2 % K_ELEMENTS(g_apFsAnsiPaths));
    2182             if (pFsObj)
    2183             {
    2184                 kwFsCreateHashTabEntryA(pFsObj, pszPath, cchPath, uHashPath, idxHashTab);
    2185                 return pFsObj;
    2186             }
    2187         }
    2188 
    2189         /* It's worth remembering uncacheable paths in the hash table. */
    2190         kwFsCreateHashTabEntryA(NULL /*pFsObj*/, pszPath, cchPath, uHashPath, idxHashTab);
    2191     }
     1895        PKFSOBJ pFsObj;
     1896        KFSCACHE_LOG(("kFsCacheLookupSlowA(%s)\n", pszPath));
     1897        pFsObj = kFsCacheLookupAbsoluteA(pCache, szFull, cchFull, penmError);
     1898
     1899#if 0 /* No need to do this until it's actually queried. */
     1900        /* Cache the resulting path. */
     1901        if (   pFsObj
     1902            || (pCache->fFlags & KFSCACHE_F_MISSING_PATHS)
     1903            || *penmError == KFSLOOKUPERROR_UNSUPPORTED)
     1904        {
     1905            KU32 uHashPath = kFsCacheStrHash(szFull);
     1906            kFsCacheCreatePathHashTabEntryA(pCache, pFsObj, pszPath, cchPath, uHashPath,
     1907                                            uHashPath % K_ELEMENTS(pCache->apAnsiPaths), *penmError);
     1908        }
     1909#endif
     1910        return pFsObj;
     1911    }
     1912
     1913    /* The path is too long! */
     1914    kHlpAssertMsgFailed(("'%s' -> cchFull=%u\n", pszPath, cchFull));
     1915    *penmError = KFSLOOKUPERROR_PATH_TOO_LONG;
    21921916    return NULL;
    21931917}
     
    21951919
    21961920/**
    2197  * Looks up a KWFSOBJ for the given ANSI path.
     1921 * Looks up a KFSOBJ for the given ANSI path.
    21981922 *
    21991923 * This will first try the hash table.  If not in the hash table, the file
     
    22041928 * point.
    22051929 *
    2206  *
    2207  * @returns Pointer to object corresponding to @a pszPath on success.
     1930 * @returns Reference to object corresponding to @a pszPath on success, this
     1931 *          must be released by kwFsCacheRelease.
    22081932 *          NULL if not a path we care to cache.
     1933 * @param   pCache              The cache.
    22091934 * @param   pszPath             The path to lookup.
    2210  */
    2211 static PKWFSOBJ kwFsLookupA(const char *pszPath)
     1935 * @param   penmError           Where to return details as to why the lookup
     1936 *                              failed.
     1937 */
     1938static PKFSOBJ kFsCacheLookupA(PKFSCACHE pCache, const char *pszPath, KFSLOOKUPERROR *penmError)
    22121939{
    22131940    /*
     
    22151942     */
    22161943    KU32        uHashPath;
    2217     KU32        cchPath    = (KU32)kwStrHashEx(pszPath, &uHashPath);
    2218     KU32        idxHashTab = uHashPath % K_ELEMENTS(g_apFsAnsiPaths);
    2219     PKWFSHASHA  pHashEntry = g_apFsAnsiPaths[idxHashTab];
     1944    KU32        cchPath    = (KU32)kFsCacheStrHashEx(pszPath, &uHashPath);
     1945    KU32        idxHashTab = uHashPath % K_ELEMENTS(pCache->apAnsiPaths);
     1946    PKFSHASHA   pHashEntry = pCache->apAnsiPaths[idxHashTab];
    22201947    if (pHashEntry)
    22211948    {
     
    22261953                && kHlpMemComp(pHashEntry->pszPath, pszPath, cchPath) == 0)
    22271954            {
    2228                 KWFS_LOG(("kwFsLookupA(%s) - hit %p\n", pszPath, pHashEntry->pFsObj));
    2229                 return pHashEntry->pFsObj;
     1955                if (   pHashEntry->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
     1956                    || pHashEntry->uCacheGen == pCache->uGeneration
     1957                    || (pHashEntry = kFsCacheRefreshPathA(pCache, pHashEntry, idxHashTab)) )
     1958                {
     1959                    pCache->cLookups++;
     1960                    pCache->cPathHashHits++;
     1961                    KFSCACHE_LOG(("kFsCacheLookupA(%s) - hit %p\n", pszPath, pHashEntry->pFsObj));
     1962                    *penmError = pHashEntry->enmError;
     1963                    if (pHashEntry->pFsObj)
     1964                        return kFsCacheObjRetainInternal(pHashEntry->pFsObj);
     1965                    return NULL;
     1966                }
     1967                break;
    22301968            }
    22311969            pHashEntry = pHashEntry->pNext;
     
    22371975     */
    22381976    if (   cchPath > 0
    2239         && cchPath < 1024)
    2240     {
     1977        && cchPath < KFSCACHE_CFG_MAX_PATH)
     1978    {
     1979        PKFSOBJ pFsObj;
     1980
    22411981        /* Is absolute without any '..' bits? */
    22421982        if (   cchPath >= 3
    2243             && pszPath[1] == ':'
    2244             && IS_SLASH(pszPath[2])
    2245             && IS_ALPHA(pszPath[0])
    2246             && !kwFsHasDotDot(pszPath, cchPath) )
    2247             return kwFsLookupAbsoluteA(pszPath, cchPath, uHashPath, idxHashTab);
    2248 
    2249         /* Not UNC? */
    2250         if (   cchPath < 2
    2251             || !IS_SLASH(pszPath[0])
    2252             || !IS_SLASH(pszPath[1]) )
    2253             return kwFsLookupSlowA(pszPath, cchPath, uHashPath, idxHashTab);
    2254 
    2255 
    2256         /* It's worth remembering uncacheable paths in the hash table. */
    2257         kwFsCreateHashTabEntryA(NULL /*pFsObj*/, pszPath, cchPath, uHashPath, idxHashTab);
    2258     }
     1983            && (   (   pszPath[1] == ':'    /* Drive letter */
     1984                    && IS_SLASH(pszPath[2])
     1985                    && IS_ALPHA(pszPath[0]) )
     1986                || (   IS_SLASH(pszPath[0]) /* UNC */
     1987                    && IS_SLASH(pszPath[1]) ) )
     1988            && !kFsCacheHasDotDot(pszPath, cchPath) )
     1989            pFsObj = kFsCacheLookupAbsoluteA(pCache, pszPath, cchPath, penmError);
     1990        else
     1991            pFsObj = kFsCacheLookupSlowA(pCache, pszPath, cchPath, penmError);
     1992        if (   pFsObj
     1993            || (   (pCache->fFlags & KFSCACHE_F_MISSING_PATHS)
     1994                && *penmError != KFSLOOKUPERROR_PATH_TOO_LONG)
     1995            || *penmError == KFSLOOKUPERROR_UNSUPPORTED )
     1996            kFsCacheCreatePathHashTabEntryA(pCache, pFsObj, pszPath, cchPath, uHashPath, idxHashTab, *penmError);
     1997
     1998        pCache->cLookups++;
     1999        if (pFsObj)
     2000            pCache->cWalkHits++;
     2001        return pFsObj;
     2002    }
     2003
     2004    *penmError = KFSLOOKUPERROR_PATH_TOO_LONG;
    22592005    return NULL;
    22602006}
    22612007
    22622008
    2263 
    2264 
    2265 /**
    2266  * Parses the argument string passed in as pszSrc.
    2267  *
    2268  * @returns size of the processed arguments.
    2269  * @param   pszSrc  Pointer to the commandline that's to be parsed.
    2270  * @param   pcArgs  Where to return the number of arguments.
    2271  * @param   argv    Pointer to argument vector to put argument pointers in. NULL allowed.
    2272  * @param   pchPool Pointer to memory pchPool to put the arguments into. NULL allowed.
    2273  *
    2274  * @remarks Lifted from startuphacks-win.c
    2275  */
    2276 static int parse_args(const char *pszSrc, int *pcArgs, char **argv, char *pchPool)
    2277 {
    2278     int   bs;
    2279     char  chQuote;
    2280     char *pfFlags;
    2281     int   cbArgs;
    2282     int   cArgs;
    2283 
    2284 #define PUTC(c) do { ++cbArgs; if (pchPool != NULL) *pchPool++ = (c); } while (0)
    2285 #define PUTV    do { ++cArgs;  if (argv != NULL) *argv++ = pchPool; } while (0)
    2286 #define WHITE(c) ((c) == ' ' || (c) == '\t')
    2287 
    2288 #define _ARG_DQUOTE   0x01          /* Argument quoted (")                  */
    2289 #define _ARG_RESPONSE 0x02          /* Argument read from response file     */
    2290 #define _ARG_WILDCARD 0x04          /* Argument expanded from wildcard      */
    2291 #define _ARG_ENV      0x08          /* Argument from environment            */
    2292 #define _ARG_NONZERO  0x80          /* Always set, to avoid end of string   */
    2293 
    2294     cArgs  = 0;
    2295     cbArgs = 0;
    2296 
    2297 #if 0
    2298     /* argv[0] */
    2299     PUTC((char)_ARG_NONZERO);
    2300     PUTV;
    2301     for (;;)
    2302     {
    2303         PUTC(*pszSrc);
    2304         if (*pszSrc == 0)
     2009/**
     2010 * Destroys a cache object which has a zero reference count.
     2011 *
     2012 * @returns 0
     2013 * @param   pCache              The cache.
     2014 * @param   pObj                The object.
     2015 */
     2016KU32 kFsCacheObjDestroy(PKFSCACHE pCache, PKFSOBJ pObj)
     2017{
     2018    kHlpAssert(pObj->cRefs == 0);
     2019    kHlpAssert(pObj->pParent == NULL);
     2020
     2021    switch (pObj->bObjType)
     2022    {
     2023        case KFSOBJ_TYPE_MISSING:
     2024        //case KFSOBJ_TYPE_MISSING | KFSOBJ_TYPE_F_INVALID:
     2025            /* nothing else to do here */
     2026            pCache->cbObjects -= sizeof(*pObj);
    23052027            break;
    2306         ++pszSrc;
    2307     }
    2308     ++pszSrc;
    2309 #endif
    2310 
    2311     for (;;)
    2312     {
    2313         while (WHITE(*pszSrc))
    2314             ++pszSrc;
    2315         if (*pszSrc == 0)
     2028
     2029        case KFSOBJ_TYPE_DIR:
     2030        //case KFSOBJ_TYPE_DIR | KFSOBJ_TYPE_F_INVALID:
     2031        case KFSOBJ_TYPE_FILE:
     2032        //case KFSOBJ_TYPE_FILE | KFSOBJ_TYPE_F_INVALID:
     2033            kHlpAssertFailed();
    23162034            break;
    2317         pfFlags = pchPool;
    2318         PUTC((char)_ARG_NONZERO);
    2319         PUTV;
    2320         bs = 0; chQuote = 0;
    2321         for (;;)
    2322         {
    2323             if (!chQuote ? (*pszSrc == '"' /*|| *pszSrc == '\''*/) : *pszSrc == chQuote)
    2324             {
    2325                 while (bs >= 2)
    2326                 {
    2327                     PUTC('\\');
    2328                     bs -= 2;
    2329                 }
    2330                 if (bs & 1)
    2331                     PUTC(*pszSrc);
    2332                 else
    2333                 {
    2334                     chQuote = chQuote ? 0 : *pszSrc;
    2335                     if (pfFlags != NULL)
    2336                         *pfFlags |= _ARG_DQUOTE;
    2337                 }
    2338                 bs = 0;
    2339             }
    2340             else if (*pszSrc == '\\')
    2341                 ++bs;
    2342             else
    2343             {
    2344                 while (bs != 0)
    2345                 {
    2346                     PUTC('\\');
    2347                     --bs;
    2348                 }
    2349                 if (*pszSrc == 0 || (WHITE(*pszSrc) && !chQuote))
    2350                     break;
    2351                 PUTC(*pszSrc);
    2352             }
    2353             ++pszSrc;
    2354         }
    2355         PUTC(0);
    2356     }
    2357 
    2358     *pcArgs = cArgs;
    2359     return cbArgs;
    2360 }
    2361 
    2362 
    2363 
    2364 
    2365 /*
    2366  *
    2367  * Process and thread related APIs.
    2368  * Process and thread related APIs.
    2369  * Process and thread related APIs.
    2370  *
    2371  */
    2372 
    2373 /** ExitProcess replacement.  */
    2374 static void WINAPI kwSandbox_Kernel32_ExitProcess(UINT uExitCode)
    2375 {
    2376     if (g_Sandbox.idMainThread == GetCurrentThreadId())
    2377     {
    2378         PNT_TIB pTib = (PNT_TIB)NtCurrentTeb();
    2379 
    2380         g_Sandbox.rcExitCode = (int)uExitCode;
    2381 
    2382         /* Before we jump, restore the TIB as we're not interested in any
    2383            exception chain stuff installed by the sandboxed executable. */
    2384         *pTib = g_Sandbox.TibMainThread;
    2385 
    2386         longjmp(g_Sandbox.JmpBuf, 1);
    2387     }
    2388     __debugbreak();
    2389 }
    2390 
    2391 
    2392 /** ExitProcess replacement.  */
    2393 static BOOL WINAPI kwSandbox_Kernel32_TerminateProcess(HANDLE hProcess, UINT uExitCode)
    2394 {
    2395     if (hProcess == GetCurrentProcess())
    2396         kwSandbox_Kernel32_ExitProcess(uExitCode);
    2397     __debugbreak();
    2398     return TerminateProcess(hProcess, uExitCode);
    2399 }
    2400 
    2401 
    2402 /** Normal CRT exit(). */
    2403 static void __cdecl kwSandbox_msvcrt_exit(int rcExitCode)
    2404 {
    2405     KW_LOG(("kwSandbox_msvcrt_exit: %d\n", rcExitCode));
    2406     kwSandbox_Kernel32_ExitProcess(rcExitCode);
    2407 }
    2408 
    2409 
    2410 /** Quick CRT _exit(). */
    2411 static void __cdecl kwSandbox_msvcrt__exit(int rcExitCode)
    2412 {
    2413     /* Quick. */
    2414     KW_LOG(("kwSandbox_msvcrt__exit %d\n", rcExitCode));
    2415     kwSandbox_Kernel32_ExitProcess(rcExitCode);
    2416 }
    2417 
    2418 
    2419 /** Return to caller CRT _cexit(). */
    2420 static void __cdecl kwSandbox_msvcrt__cexit(int rcExitCode)
    2421 {
    2422     KW_LOG(("kwSandbox_msvcrt__cexit: %d\n", rcExitCode));
    2423     kwSandbox_Kernel32_ExitProcess(rcExitCode);
    2424 }
    2425 
    2426 
    2427 /** Quick return to caller CRT _c_exit(). */
    2428 static void __cdecl kwSandbox_msvcrt__c_exit(int rcExitCode)
    2429 {
    2430     KW_LOG(("kwSandbox_msvcrt__c_exit: %d\n", rcExitCode));
    2431     kwSandbox_Kernel32_ExitProcess(rcExitCode);
    2432 }
    2433 
    2434 
    2435 /** Runtime error and exit _amsg_exit(). */
    2436 static void __cdecl kwSandbox_msvcrt__amsg_exit(int iMsgNo)
    2437 {
    2438     KW_LOG(("\nRuntime error #%u!\n", iMsgNo));
    2439     kwSandbox_Kernel32_ExitProcess(255);
    2440 }
    2441 
    2442 
    2443 /** CRT - terminate().  */
    2444 static void __cdecl kwSandbox_msvcrt_terminate(void)
    2445 {
    2446     KW_LOG(("\nRuntime - terminate!\n"));
    2447     kwSandbox_Kernel32_ExitProcess(254);
    2448 }
    2449 
    2450 
    2451 /** The CRT internal __getmainargs() API. */
    2452 static int __cdecl kwSandbox_msvcrt___getmainargs(int *pargc, char ***pargv, char ***penvp,
    2453                                                   int dowildcard, int const *piNewMode)
    2454 {
    2455     *pargc = g_Sandbox.cArgs;
    2456     *pargv = g_Sandbox.papszArgs;
    2457     *penvp = g_Sandbox.environ;
    2458 
    2459     /** @todo startinfo points at a newmode (setmode) value.   */
     2035        default:
     2036            kHlpAssertFailed();
     2037    }
     2038    pCache->cObjects--;
     2039    free(pObj);
    24602040    return 0;
    24612041}
    24622042
    24632043
    2464 /** The CRT internal __wgetmainargs() API. */
    2465 static int __cdecl kwSandbox_msvcrt___wgetmainargs(int *pargc, wchar_t ***pargv, wchar_t ***penvp,
    2466                                                    int dowildcard, int const *piNewMode)
    2467 {
    2468     *pargc = g_Sandbox.cArgs;
    2469     *pargv = g_Sandbox.papwszArgs;
    2470     *penvp = g_Sandbox.wenviron;
    2471 
    2472     /** @todo startinfo points at a newmode (setmode) value.   */
    2473     return 0;
    2474 }
    2475 
    2476 
    2477 
    2478 /** Kernel32 - GetCommandLineA()  */
    2479 static LPCSTR /*LPSTR*/ WINAPI kwSandbox_Kernel32_GetCommandLineA(VOID)
    2480 {
    2481     return g_Sandbox.pszCmdLine;
    2482 }
    2483 
    2484 
    2485 /** Kernel32 - GetCommandLineW()  */
    2486 static LPCWSTR /*LPWSTR*/ WINAPI kwSandbox_Kernel32_GetCommandLineW(VOID)
    2487 {
    2488     return g_Sandbox.pwszCmdLine;
    2489 }
    2490 
    2491 
    2492 /** Kernel32 - GetStartupInfoA()  */
    2493 static VOID WINAPI kwSandbox_Kernel32_GetStartupInfoA(LPSTARTUPINFOA pStartupInfo)
    2494 {
    2495     __debugbreak();
    2496 }
    2497 
    2498 
    2499 /** Kernel32 - GetStartupInfoW()  */
    2500 static VOID WINAPI kwSandbox_Kernel32_GetStartupInfoW(LPSTARTUPINFOW lpStartupInfo)
    2501 {
    2502     __debugbreak();
    2503 }
    2504 
    2505 
    2506 /** CRT - __p___argc().  */
    2507 static int * __cdecl kwSandbox_msvcrt___p___argc(void)
    2508 {
    2509     return &g_Sandbox.cArgs;
    2510 }
    2511 
    2512 
    2513 /** CRT - __p___argv().  */
    2514 static char *** __cdecl kwSandbox_msvcrt___p___argv(void)
    2515 {
    2516     return &g_Sandbox.papszArgs;
    2517 }
    2518 
    2519 
    2520 /** CRT - __p___sargv().  */
    2521 static wchar_t *** __cdecl kwSandbox_msvcrt___p___wargv(void)
    2522 {
    2523     return &g_Sandbox.papwszArgs;
    2524 }
    2525 
    2526 
    2527 /** CRT - __p__acmdln().  */
    2528 static char ** __cdecl kwSandbox_msvcrt___p__acmdln(void)
    2529 {
    2530     return (char **)&g_Sandbox.pszCmdLine;
    2531 }
    2532 
    2533 
    2534 /** CRT - __p__acmdln().  */
    2535 static wchar_t ** __cdecl kwSandbox_msvcrt___p__wcmdln(void)
    2536 {
    2537     return &g_Sandbox.pwszCmdLine;
    2538 }
    2539 
    2540 
    2541 /** CRT - __p__pgmptr().  */
    2542 static char ** __cdecl kwSandbox_msvcrt___p__pgmptr(void)
    2543 {
    2544     return &g_Sandbox.pgmptr;
    2545 }
    2546 
    2547 
    2548 /** CRT - __p__wpgmptr().  */
    2549 static wchar_t ** __cdecl kwSandbox_msvcrt___p__wpgmptr(void)
    2550 {
    2551     return &g_Sandbox.wpgmptr;
    2552 }
    2553 
    2554 
    2555 /** CRT - _get_pgmptr().  */
    2556 static errno_t __cdecl kwSandbox_msvcrt__get_pgmptr(char **ppszValue)
    2557 {
    2558     *ppszValue = g_Sandbox.pgmptr;
    2559     return 0;
    2560 }
    2561 
    2562 
    2563 /** CRT - _get_wpgmptr().  */
    2564 static errno_t __cdecl kwSandbox_msvcrt__get_wpgmptr(wchar_t **ppwszValue)
    2565 {
    2566     *ppwszValue = g_Sandbox.wpgmptr;
    2567     return 0;
    2568 }
    2569 
    2570 /** Just in case. */
    2571 static void kwSandbox_msvcrt__wincmdln(void)
    2572 {
    2573     __debugbreak();
    2574 }
    2575 
    2576 
    2577 /** Just in case. */
    2578 static void kwSandbox_msvcrt__wwincmdln(void)
    2579 {
    2580     __debugbreak();
    2581 }
    2582 
    2583 /** CreateThread interceptor. */
    2584 static HANDLE WINAPI kwSandbox_Kernel32_CreateThread(LPSECURITY_ATTRIBUTES pSecAttr, SIZE_T cbStack,
    2585                                                      PTHREAD_START_ROUTINE pfnThreadProc, PVOID pvUser,
    2586                                                      DWORD fFlags, PDWORD pidThread)
    2587 {
    2588     __debugbreak();
     2044/**
     2045 * Releases a reference to a cache object.
     2046 *
     2047 * @returns New reference count.
     2048 * @param   pCache              The cache.
     2049 * @param   pObj                The object.
     2050 */
     2051KU32 kFsCacheObjRelease(PKFSCACHE pCache, PKFSOBJ pObj)
     2052{
     2053    KU32 cRefs = --pObj->cRefs;
     2054    if (cRefs)
     2055        return cRefs;
     2056    return kFsCacheObjDestroy(pCache, pObj);
     2057}
     2058
     2059
     2060/**
     2061 * Retains a reference to a cahce object.
     2062 *
     2063 * @returns New reference count.
     2064 * @param   pObj                The object.
     2065 */
     2066KU32 kFsCacheObjRetain(PKFSOBJ pObj)
     2067{
     2068    KU32 cRefs = ++pObj->cRefs;
     2069    kHlpAssert(cRefs < 16384);
     2070    return cRefs;
     2071}
     2072
     2073
     2074
     2075PKFSCACHE kFsCacheCreate(KU32 fFlags)
     2076{
     2077    PKFSCACHE pCache;
     2078    birdResolveImports();
     2079
     2080    pCache = (PKFSCACHE)kHlpAllocZ(sizeof(*pCache));
     2081    if (pCache)
     2082    {
     2083        /* Dummy root dir entry. */
     2084        pCache->RootDir.Obj.u32Magic        = KFSOBJ_MAGIC;
     2085        pCache->RootDir.Obj.cRefs           = 1;
     2086        pCache->RootDir.Obj.uCacheGen       = KFSWOBJ_CACHE_GEN_IGNORE;
     2087        pCache->RootDir.Obj.bObjType        = KFSOBJ_TYPE_DIR;
     2088        pCache->RootDir.Obj.fHaveStats      = K_FALSE;
     2089        pCache->RootDir.Obj.pParent         = NULL;
     2090        pCache->RootDir.Obj.pszName         = "";
     2091        pCache->RootDir.Obj.cchName         = 0;
     2092        pCache->RootDir.Obj.cchParent       = 0;
     2093#ifdef KFSCACHE_CFG_UTF16
     2094        pCache->RootDir.Obj.cwcName         = 0;
     2095        pCache->RootDir.Obj.cwcParent       = 0;
     2096        pCache->RootDir.Obj.pwszName        = L"";
     2097#endif
     2098
     2099#ifdef KFSCACHE_CFG_SHORT_NAMES
     2100        pCache->RootDir.Obj.pszShortName    = NULL;
     2101        pCache->RootDir.Obj.cchShortName    = 0;
     2102        pCache->RootDir.Obj.cchShortParent  = 0;
     2103# ifdef KFSCACHE_CFG_UTF16
     2104        pCache->RootDir.Obj.cwcShortName;
     2105        pCache->RootDir.Obj.cwcShortParent;
     2106        pCache->RootDir.Obj.pwszShortName;
     2107# endif
     2108#endif
     2109        pCache->RootDir.cChildren           = 0;
     2110        pCache->RootDir.papChildren         = NULL;
     2111        pCache->RootDir.hDir                = INVALID_HANDLE_VALUE;
     2112        pCache->RootDir.cHashTab            = 251;
     2113        pCache->RootDir.paHashTab           = (PKFSOBJHASH)kHlpAllocZ(  pCache->RootDir.cHashTab
     2114                                                                      * sizeof(pCache->RootDir.paHashTab[0]));
     2115        if (pCache->RootDir.paHashTab)
     2116        {
     2117            /* The cache itself. */
     2118            pCache->u32Magic        = KFSCACHE_MAGIC;
     2119            pCache->fFlags          = fFlags;
     2120            pCache->uGeneration     = 1;
     2121            pCache->cObjects        = 1;
     2122            pCache->cbObjects       = sizeof(pCache->RootDir) + pCache->RootDir.cHashTab * sizeof(pCache->RootDir.paHashTab[0]);
     2123            pCache->cPathHashHits   = 0;
     2124            pCache->cWalkHits       = 0;
     2125            pCache->cAnsiPaths      = 0;
     2126            pCache->cAnsiPathCollisions = 0;
     2127            pCache->cbAnsiPaths     = 0;
     2128#ifdef KFSCACHE_CFG_UTF16
     2129            pCache->cUtf16Paths     = 0;
     2130            pCache->cUtf16PathCollisions = 0;
     2131            pCache->cbUtf16Paths    = 0;
     2132#endif
     2133            return pCache;
     2134        }
     2135
     2136        kHlpFree(pCache);
     2137    }
    25892138    return NULL;
    25902139}
    25912140
    2592 
    2593 /** _beginthread - create a new thread. */
    2594 static uintptr_t __cdecl kwSandbox_msvcrt__beginthread(void (__cdecl *pfnThreadProc)(void *), unsigned cbStack, void *pvUser)
    2595 {
    2596     __debugbreak();
    2597     return 0;
    2598 }
    2599 
    2600 
    2601 /** _beginthreadex - create a new thread. */
    2602 static uintptr_t __cdecl kwSandbox_msvcrt__beginthreadex(void *pvSecAttr, unsigned cbStack,
    2603                                                          unsigned (__stdcall *pfnThreadProc)(void *), void *pvUser,
    2604                                                          unsigned fCreate, unsigned *pidThread)
    2605 {
    2606     __debugbreak();
    2607     return 0;
    2608 }
    2609 
    2610 
    2611 /*
    2612  *
    2613  * Environment related APIs.
    2614  * Environment related APIs.
    2615  * Environment related APIs.
    2616  *
    2617  */
    2618 
    2619 /** Kernel32 - GetEnvironmentVariableA()  */
    2620 static DWORD WINAPI kwSandbox_Kernel32_GetEnvironmentVariableA(LPCSTR pwszVar, LPSTR pszValue, DWORD cbValue)
    2621 {
    2622     __debugbreak();
    2623     return 0;
    2624 }
    2625 
    2626 
    2627 /** Kernel32 - GetEnvironmentVariableW()  */
    2628 static DWORD WINAPI kwSandbox_Kernel32_GetEnvironmentVariableW(LPCWSTR pwszVar, LPWSTR pwszValue, DWORD cbValue)
    2629 {
    2630     KW_LOG(("GetEnvironmentVariableW: '%ls'\n", pwszVar));
    2631     //__debugbreak();
    2632     //SetLastError(ERROR_ENVVAR_NOT_FOUND);
    2633     //return 0;
    2634     return GetEnvironmentVariableW(pwszVar, pwszValue, cbValue);
    2635 }
    2636 
    2637 
    2638 /** Kernel32 - SetEnvironmentVariableA()  */
    2639 static BOOL WINAPI kwSandbox_Kernel32_SetEnvironmentVariableA(LPCSTR pszVar, LPCSTR pszValue)
    2640 {
    2641     __debugbreak();
    2642     return FALSE;
    2643 }
    2644 
    2645 
    2646 /** Kernel32 - SetEnvironmentVariableW()  */
    2647 static BOOL WINAPI kwSandbox_Kernel32_SetEnvironmentVariableW(LPCWSTR pwszVar, LPCWSTR pwszValue)
    2648 {
    2649     KW_LOG(("SetEnvironmentVariableW: '%ls' = '%ls'\n", pwszVar, pwszValue));
    2650     return SetEnvironmentVariableW(pwszVar, pwszValue);
    2651     //__debugbreak();
    2652     //return FALSE;
    2653 }
    2654 
    2655 
    2656 /** Kernel32 - ExpandEnvironmentStringsA()  */
    2657 static DWORD WINAPI kwSandbox_Kernel32_ExpandEnvironmentStringsA(LPCSTR pszSrc, LPSTR pwszDst, DWORD cbDst)
    2658 {
    2659     __debugbreak();
    2660     return 0;
    2661 }
    2662 
    2663 
    2664 /** Kernel32 - ExpandEnvironmentStringsW()  */
    2665 static DWORD WINAPI kwSandbox_Kernel32_ExpandEnvironmentStringsW(LPCWSTR pwszSrc, LPWSTR pwszDst, DWORD cbDst)
    2666 {
    2667     __debugbreak();
    2668     return 0;
    2669 }
    2670 
    2671 
    2672 /** CRT - _putenv(). */
    2673 static int __cdecl kwSandbox_msvcrt__putenv(const char *pszVarEqualValue)
    2674 {
    2675     __debugbreak();
    2676     return 0;
    2677 }
    2678 
    2679 
    2680 /** CRT - _wputenv(). */
    2681 static int __cdecl kwSandbox_msvcrt__wputenv(const wchar_t *pwszVarEqualValue)
    2682 {
    2683     __debugbreak();
    2684     return 0;
    2685 }
    2686 
    2687 
    2688 /** CRT - _putenv_s(). */
    2689 static errno_t __cdecl kwSandbox_msvcrt__putenv_s(const char *pszVar, const char *pszValue)
    2690 {
    2691     __debugbreak();
    2692     return 0;
    2693 }
    2694 
    2695 
    2696 /** CRT - _wputenv_s(). */
    2697 static errno_t __cdecl kwSandbox_msvcrt__wputenv_s(const wchar_t *pwszVar, const wchar_t *pwszValue)
    2698 {
    2699     KW_LOG(("_wputenv_s: '%ls' = '%ls'\n", pwszVar, pwszValue));
    2700     //__debugbreak();
    2701     return SetEnvironmentVariableW(pwszVar, pwszValue) ? 0 : -1;
    2702 }
    2703 
    2704 
    2705 /** CRT - get pointer to the __initenv variable (initial environment).   */
    2706 static char *** __cdecl kwSandbox_msvcrt___p___initenv(void)
    2707 {
    2708     return &g_Sandbox.initenv;
    2709 }
    2710 
    2711 
    2712 /** CRT - get pointer to the __winitenv variable (initial environment).   */
    2713 static wchar_t *** __cdecl kwSandbox_msvcrt___p___winitenv(void)
    2714 {
    2715     return &g_Sandbox.winitenv;
    2716 }
    2717 
    2718 
    2719 /** CRT - get pointer to the _environ variable (current environment).   */
    2720 static char *** __cdecl kwSandbox_msvcrt___p__environ(void)
    2721 {
    2722     return &g_Sandbox.environ;
    2723 }
    2724 
    2725 
    2726 /** CRT - get pointer to the _wenviron variable (current environment).   */
    2727 static wchar_t *** __cdecl kwSandbox_msvcrt___p__wenviron(void)
    2728 {
    2729     return &g_Sandbox.wenviron;
    2730 }
    2731 
    2732 
    2733 /** CRT - get the _environ variable (current environment).
    2734  * @remarks Not documented or prototyped?  */
    2735 static KUPTR /*void*/ __cdecl kwSandbox_msvcrt__get_environ(char ***ppapszEnviron)
    2736 {
    2737     __debugbreak(); /** @todo check the callers expecations! */
    2738     *ppapszEnviron = g_Sandbox.environ;
    2739     return 0;
    2740 }
    2741 
    2742 
    2743 /** CRT - get the _wenviron variable (current environment).
    2744  * @remarks Not documented or prototyped? */
    2745 static KUPTR /*void*/ __cdecl kwSandbox_msvcrt__get_wenviron(wchar_t ***ppapwszEnviron)
    2746 {
    2747     __debugbreak(); /** @todo check the callers expecations! */
    2748     *ppapwszEnviron = g_Sandbox.wenviron;
    2749     return 0;
    2750 }
    2751 
    2752 
    2753 
    2754 /*
    2755  *
    2756  * Loader related APIs
    2757  * Loader related APIs
    2758  * Loader related APIs
    2759  *
    2760  */
    2761 
    2762 
    2763 /** Kernel32 - LoadLibraryExA()   */
    2764 static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryExA(LPCSTR pszFilename, HANDLE hFile, DWORD fFlags)
    2765 {
    2766     PKWDYNLOAD  pDynLoad;
    2767     PKWMODULE   pMod;
    2768     int         rc;
    2769 
    2770     if (   (fFlags & LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE)
    2771         || (hFile != NULL && hFile != INVALID_HANDLE_VALUE) )
    2772     {
    2773         __debugbreak();
    2774         return LoadLibraryExA(pszFilename, hFile, fFlags);
    2775     }
    2776 
    2777     /*
    2778      * Deal with resource / data DLLs.
    2779      */
    2780     if (fFlags & (  DONT_RESOLVE_DLL_REFERENCES
    2781                   | LOAD_LIBRARY_AS_DATAFILE
    2782                   | LOAD_LIBRARY_AS_IMAGE_RESOURCE) )
    2783     {
    2784         HMODULE hmod;
    2785         char    szNormPath[4096];
    2786         KU32    uHashPath;
    2787 
    2788         /* currently, only deal with those that has a path. */
    2789         if (kHlpIsFilenameOnly(pszFilename))
    2790         {
    2791             __debugbreak();
    2792             return LoadLibraryExA(pszFilename, hFile, fFlags);
    2793         }
    2794 
    2795         /* Normalize the path. */
    2796         rc = kwPathNormalize(pszFilename, szNormPath, sizeof(szNormPath));
    2797         if (rc != 0)
    2798         {
    2799             __debugbreak();
    2800             return LoadLibraryExA(pszFilename, hFile, fFlags);
    2801         }
    2802 
    2803         /* Try look it up. */
    2804         uHashPath = kwStrHash(szNormPath);
    2805         for (pDynLoad = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead; pDynLoad != NULL; pDynLoad = pDynLoad->pNext)
    2806             if (   pDynLoad->uHashPath == uHashPath
    2807                 && kHlpStrComp(pDynLoad->pszPath, szNormPath) == 0)
    2808             {
    2809                 if (pDynLoad->pMod == NULL)
    2810                     return pDynLoad->hmod;
    2811                 __debugbreak();
    2812             }
    2813 
    2814         /* Then try load it. */
    2815         hmod = LoadLibraryExA(szNormPath, hFile, fFlags);
    2816         if (hmod)
    2817         {
    2818             KSIZE cbNormPath = kHlpStrLen(szNormPath) + 1;
    2819             pDynLoad = (PKWDYNLOAD)kHlpAlloc(sizeof(*pDynLoad) + cbNormPath + cbNormPath * 2 * sizeof(wchar_t));
    2820             if (pDynLoad)
    2821             {
    2822                 pDynLoad->pszPath           = (char *)kHlpMemCopy(pDynLoad + 1, szNormPath, cbNormPath);
    2823                 pDynLoad->pwszPath          = (wchar_t *)(pDynLoad->pszPath + cbNormPath + (cbNormPath & 1));
    2824                 kwStrToUtf16(pDynLoad->pszPath, (wchar_t *)pDynLoad->pwszPath, cbNormPath * 2);
    2825                 pDynLoad->pszModName        = kHlpGetFilename(pDynLoad->pszPath);
    2826                 pDynLoad->uHashPath         = uHashPath;
    2827                 pDynLoad->pMod              = NULL; /* indicates special  */
    2828                 pDynLoad->hmod              = hmod;
    2829 
    2830                 pDynLoad->pNext = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead;
    2831                 g_Sandbox.pTool->u.Sandboxed.pDynLoadHead = pDynLoad;
    2832             }
    2833             else
    2834                 __debugbreak();
    2835         }
    2836         return hmod;
    2837     }
    2838 
    2839     /*
    2840      * Normal library loading.
    2841      * We start by being very lazy and reusing the code for resolving imports.
    2842      */
    2843     if (!kHlpIsFilenameOnly(pszFilename))
    2844         pMod = kwLdrModuleTryLoadDll(pszFilename, KWLOCATION_UNKNOWN, g_Sandbox.pTool->u.Sandboxed.pExe);
    2845     else
    2846     {
    2847 __debugbreak();
    2848         rc = kwLdrModuleResolveAndLookup(pszFilename, g_Sandbox.pTool->u.Sandboxed.pExe, NULL /*pImporter*/, &pMod);
    2849         if (rc != 0)
    2850             pMod = NULL;
    2851     }
    2852     if (!pMod)
    2853     {
    2854         __debugbreak();
    2855         SetLastError(ERROR_MOD_NOT_FOUND);
    2856         return NULL;
    2857     }
    2858 
    2859     /*
    2860      * Make sure it's initialized.
    2861      */
    2862     rc = kwLdrModuleInitTree(pMod);
    2863     if (rc == 0)
    2864     {
    2865         /*
    2866          * Create an dynamic loading entry for it.
    2867          */
    2868         pDynLoad = (PKWDYNLOAD)kHlpAlloc(sizeof(*pDynLoad));
    2869         if (pDynLoad)
    2870         {
    2871             pDynLoad->pszPath           = pMod->pszPath;
    2872             pDynLoad->pwszPath          = pMod->pwszPath;
    2873             pDynLoad->pszModName        = kHlpGetFilename(pDynLoad->pszPath);
    2874             pDynLoad->uHashPath         = pMod->uHashPath;
    2875             pDynLoad->pMod              = pMod;
    2876             pDynLoad->hmod              = pMod->hOurMod;
    2877 
    2878             pDynLoad->pNext = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead;
    2879             g_Sandbox.pTool->u.Sandboxed.pDynLoadHead = pDynLoad;
    2880 
    2881             return pDynLoad->hmod;
    2882         }
    2883     }
    2884 
    2885     __debugbreak();
    2886     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
    2887     kwLdrModuleRelease(pMod);
    2888     return NULL;
    2889 }
    2890 
    2891 
    2892 /** Kernel32 - LoadLibraryExW()   */
    2893 static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryExW(LPCWSTR pwszFilename, HANDLE hFile, DWORD fFlags)
    2894 {
    2895     char szTmp[4096];
    2896     KSIZE cchTmp = kwUtf16ToStr(pwszFilename, szTmp, sizeof(szTmp));
    2897     if (cchTmp < sizeof(szTmp))
    2898         return kwSandbox_Kernel32_LoadLibraryExA(szTmp, hFile, fFlags);
    2899 
    2900     __debugbreak();
    2901     SetLastError(ERROR_FILENAME_EXCED_RANGE);
    2902     return NULL;
    2903 }
    2904 
    2905 /** Kernel32 - LoadLibraryA()   */
    2906 static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryA(LPCSTR pszFilename)
    2907 {
    2908     return kwSandbox_Kernel32_LoadLibraryExA(pszFilename, NULL /*hFile*/, 0 /*fFlags*/);
    2909 }
    2910 
    2911 
    2912 /** Kernel32 - LoadLibraryW()   */
    2913 static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryW(LPCWSTR pwszFilename)
    2914 {
    2915     char szTmp[4096];
    2916     KSIZE cchTmp = kwUtf16ToStr(pwszFilename, szTmp, sizeof(szTmp));
    2917     if (cchTmp < sizeof(szTmp))
    2918         return kwSandbox_Kernel32_LoadLibraryExA(szTmp, NULL /*hFile*/, 0 /*fFlags*/);
    2919     __debugbreak();
    2920     SetLastError(ERROR_FILENAME_EXCED_RANGE);
    2921     return NULL;
    2922 }
    2923 
    2924 
    2925 /** Kernel32 - FreeLibrary()   */
    2926 static BOOL WINAPI kwSandbox_Kernel32_FreeLibrary(HMODULE hmod)
    2927 {
    2928     /* Ignored, we like to keep everything loaded. */
    2929     return TRUE;
    2930 }
    2931 
    2932 
    2933 /** Kernel32 - GetModuleHandleA()   */
    2934 static HMODULE WINAPI kwSandbox_Kernel32_GetModuleHandleA(LPCSTR pszModule)
    2935 {
    2936     if (pszModule == NULL)
    2937         return (HMODULE)g_Sandbox.pTool->u.Sandboxed.pExe->hOurMod;
    2938     __debugbreak();
    2939     return NULL;
    2940 }
    2941 
    2942 
    2943 /** Kernel32 - GetModuleHandleW()   */
    2944 static HMODULE WINAPI kwSandbox_Kernel32_GetModuleHandleW(LPCWSTR pwszModule)
    2945 {
    2946     if (pwszModule == NULL)
    2947         return (HMODULE)g_Sandbox.pTool->u.Sandboxed.pExe->hOurMod;
    2948     __debugbreak();
    2949     return NULL;
    2950 }
    2951 
    2952 
    2953 static PKWMODULE kwSandboxLocateModuleByHandle(PKWSANDBOX pSandbox, HMODULE hmod)
    2954 {
    2955     PKWDYNLOAD pDynLoad;
    2956 
    2957     /* The executable. */
    2958     if (   hmod == NULL
    2959         || pSandbox->pTool->u.Sandboxed.pExe->hOurMod == hmod)
    2960         return kwLdrModuleRetain(pSandbox->pTool->u.Sandboxed.pExe);
    2961 
    2962     /* Dynamically loaded images. */
    2963     for (pDynLoad = pSandbox->pTool->u.Sandboxed.pDynLoadHead; pDynLoad != NULL; pDynLoad = pDynLoad->pNext)
    2964         if (pDynLoad->hmod == hmod)
    2965         {
    2966             if (pDynLoad->pMod)
    2967                 return kwLdrModuleRetain(pDynLoad->pMod);
    2968             __debugbreak();
    2969             return NULL;
    2970         }
    2971 
    2972     return NULL;
    2973 }
    2974 
    2975 
    2976 /** Used to debug dynamically resolved procedures. */
    2977 static UINT WINAPI kwSandbox_BreakIntoDebugger(void *pv1, void *pv2, void *pv3, void *pv4)
    2978 {
    2979     __debugbreak();
    2980     return -1;
    2981 }
    2982 
    2983 
    2984 /** Kernel32 - GetProcAddress()   */
    2985 static FARPROC WINAPI kwSandbox_Kernel32_GetProcAddress(HMODULE hmod, LPCSTR pszProc)
    2986 {
    2987     /*
    2988      * Try locate the module.
    2989      */
    2990     PKWMODULE pMod = kwSandboxLocateModuleByHandle(&g_Sandbox, hmod);
    2991     if (pMod)
    2992     {
    2993         KLDRADDR uValue;
    2994         int rc = kLdrModQuerySymbol(pMod->pLdrMod,
    2995                                     pMod->fNative ? NULL : pMod->u.Manual.pvBits,
    2996                                     pMod->fNative ? KLDRMOD_BASEADDRESS_MAP : (KUPTR)pMod->u.Manual.pvLoad,
    2997                                     KU32_MAX /*iSymbol*/,
    2998                                     pszProc,
    2999                                     strlen(pszProc),
    3000                                     NULL /*pszVersion*/,
    3001                                     NULL /*pfnGetForwarder*/, NULL /*pvUser*/,
    3002                                     &uValue,
    3003                                     NULL /*pfKind*/);
    3004         if (rc == 0)
    3005         {
    3006             static int s_cDbgGets = 0;
    3007             s_cDbgGets++;
    3008             KW_LOG(("GetProcAddress(%s, %s) -> %p [%d]\n", pMod->pszPath, pszProc, (KUPTR)uValue, s_cDbgGets));
    3009             kwLdrModuleRelease(pMod);
    3010             //if (s_cGets >= 3)
    3011             //    return (FARPROC)kwSandbox_BreakIntoDebugger;
    3012             return (FARPROC)(KUPTR)uValue;
    3013         }
    3014 
    3015         __debugbreak();
    3016         SetLastError(ERROR_PROC_NOT_FOUND);
    3017         kwLdrModuleRelease(pMod);
    3018         return NULL;
    3019     }
    3020 
    3021     __debugbreak();
    3022     return GetProcAddress(hmod, pszProc);
    3023 }
    3024 
    3025 
    3026 /** Kernel32 - GetModuleFileNameA()   */
    3027 static DWORD WINAPI kwSandbox_Kernel32_GetModuleFileNameA(HMODULE hmod, LPSTR pszFilename, DWORD cbFilename)
    3028 {
    3029     PKWMODULE pMod = kwSandboxLocateModuleByHandle(&g_Sandbox, hmod);
    3030     if (pMod != NULL)
    3031     {
    3032         DWORD cbRet = kwStrCopyStyle1(pMod->pszPath, pszFilename, cbFilename);
    3033         kwLdrModuleRelease(pMod);
    3034         return cbRet;
    3035     }
    3036     __debugbreak();
    3037     return 0;
    3038 }
    3039 
    3040 
    3041 /** Kernel32 - GetModuleFileNameW()   */
    3042 static DWORD WINAPI kwSandbox_Kernel32_GetModuleFileNameW(HMODULE hmod, LPWSTR pwszFilename, DWORD cbFilename)
    3043 {
    3044     PKWMODULE pMod = kwSandboxLocateModuleByHandle(&g_Sandbox, hmod);
    3045     if (pMod)
    3046     {
    3047         DWORD cwcRet = kwUtf16CopyStyle1(pMod->pwszPath, pwszFilename, cbFilename);
    3048         kwLdrModuleRelease(pMod);
    3049         return cwcRet;
    3050     }
    3051 
    3052     __debugbreak();
    3053     return 0;
    3054 }
    3055 
    3056 
    3057 
    3058 /*
    3059  *
    3060  * File access APIs (for speeding them up).
    3061  * File access APIs (for speeding them up).
    3062  * File access APIs (for speeding them up).
    3063  *
    3064  */
    3065 
    3066 #ifdef WITH_TEMP_MEMORY_FILES
    3067 
    3068 /**
    3069  * Checks for a cl.exe temporary file.
    3070  *
    3071  * There are quite a bunch of these.  They seems to be passing data between the
    3072  * first and second compiler pass.  Since they're on disk, they get subjected to
    3073  * AV software screening and normal file consistency rules.  So, not necessarily
    3074  * a very efficient way of handling reasonably small amounts of data.
    3075  *
    3076  * We make the files live in virtual memory by intercepting their  opening,
    3077  * writing, reading, closing , mapping, unmapping, and maybe some more stuff.
    3078  *
    3079  * @returns K_TRUE / K_FALSE
    3080  * @param   pwszFilename    The file name being accessed.
    3081  */
    3082 static KBOOL kwFsIsClTempFileW(const wchar_t *pwszFilename)
    3083 {
    3084     wchar_t const *pwszName = kwPathGetFilenameW(pwszFilename);
    3085     if (pwszName)
    3086     {
    3087         /* The name starts with _CL_... */
    3088         if (   pwszName[0] == '_'
    3089             && pwszName[1] == 'C'
    3090             && pwszName[2] == 'L'
    3091             && pwszName[3] == '_' )
    3092         {
    3093             /* ... followed by 8 xdigits and ends with a two letter file type.  Simplify
    3094                this check by just checking that it's alpha numerical ascii from here on. */
    3095             wchar_t wc;
    3096             pwszName += 4;
    3097             while ((wc = *pwszName++) != '\0')
    3098             {
    3099                 if (wc < 127 && iswalnum(wc))
    3100                 { /* likely */ }
    3101                 else
    3102                     return K_FALSE;
    3103             }
    3104             return K_TRUE;
    3105         }
    3106     }
    3107     return K_FALSE;
    3108 }
    3109 
    3110 
    3111 /**
    3112  * Creates a handle to a temporary file.
    3113  *
    3114  * @returns The handle on success.
    3115  *          INVALID_HANDLE_VALUE and SetLastError on failure.
    3116  * @param   pTempFile           The temporary file.
    3117  * @param   dwDesiredAccess     The desired access to the handle.
    3118  * @param   fMapping            Whether this is a mapping (K_TRUE) or file
    3119  *                              (K_FALSE) handle type.
    3120  */
    3121 static HANDLE kwFsTempFileCreateHandle(PKWFSTEMPFILE pTempFile, DWORD dwDesiredAccess, KBOOL fMapping)
    3122 {
    3123     /*
    3124      * Create a handle to the temporary file.
    3125      */
    3126     HANDLE hFile = INVALID_HANDLE_VALUE;
    3127     HANDLE hProcSelf = GetCurrentProcess();
    3128     if (DuplicateHandle(hProcSelf, hProcSelf,
    3129                         hProcSelf, &hFile,
    3130                         SYNCHRONIZE, FALSE,
    3131                         0 /*dwOptions*/))
    3132     {
    3133         PKWHANDLE pHandle = (PKWHANDLE)kHlpAlloc(sizeof(*pHandle));
    3134         if (pHandle)
    3135         {
    3136             pHandle->enmType            = !fMapping ? KWHANDLETYPE_TEMP_FILE : KWHANDLETYPE_TEMP_FILE_MAPPING;
    3137             pHandle->offFile            = 0;
    3138             pHandle->hHandle            = hFile;
    3139             pHandle->dwDesiredAccess    = dwDesiredAccess;
    3140             pHandle->u.pTempFile        = pTempFile;
    3141             if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle))
    3142             {
    3143                 pTempFile->cActiveHandles++;
    3144                 kHlpAssert(pTempFile->cActiveHandles >= 1);
    3145                 kHlpAssert(pTempFile->cActiveHandles <= 2);
    3146                 KWFS_LOG(("kwFsTempFileCreateHandle: Temporary file '%ls' -> %p\n", pTempFile->pwszPath, hFile));
    3147                 return hFile;
    3148             }
    3149 
    3150             kHlpFree(pHandle);
    3151         }
    3152         else
    3153             KWFS_LOG(("kwFsTempFileCreateHandle: Out of memory!\n"));
    3154         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
    3155     }
    3156     else
    3157         KWFS_LOG(("kwFsTempFileCreateHandle: DuplicateHandle failed: err=%u\n", GetLastError()));
    3158     return INVALID_HANDLE_VALUE;
    3159 }
    3160 
    3161 
    3162 static HANDLE kwFsTempFileCreateW(const wchar_t *pwszFilename, DWORD dwDesiredAccess, DWORD dwCreationDisposition)
    3163 {
    3164     HANDLE hFile;
    3165     DWORD  dwErr;
    3166 
    3167     /*
    3168      * Check if we've got an existing temp file.
    3169      * ASSUME exact same path for now.
    3170      */
    3171     KSIZE const   cwcFilename = kwUtf16Len(pwszFilename);
    3172     PKWFSTEMPFILE pTempFile;
    3173     for (pTempFile = g_Sandbox.pTempFileHead; pTempFile != NULL; pTempFile = pTempFile->pNext)
    3174     {
    3175         /* Since the last two chars are usually the only difference, we check them manually before calling memcmp. */
    3176         if (   pTempFile->cwcPath == cwcFilename
    3177             && pTempFile->pwszPath[cwcFilename - 1] == pwszFilename[cwcFilename - 1]
    3178             && pTempFile->pwszPath[cwcFilename - 2] == pwszFilename[cwcFilename - 2]
    3179             && kHlpMemComp(pTempFile->pwszPath, pwszFilename, cwcFilename) == 0)
    3180             break;
    3181     }
    3182 
    3183     /*
    3184      * Create a new temporary file instance if not found.
    3185      */
    3186     if (pTempFile == NULL)
    3187     {
    3188         KSIZE cbFilename;
    3189 
    3190         switch (dwCreationDisposition)
    3191         {
    3192             case CREATE_ALWAYS:
    3193             case OPEN_ALWAYS:
    3194                 dwErr = NO_ERROR;
    3195                 break;
    3196 
    3197             case CREATE_NEW:
    3198                 kHlpAssertFailed();
    3199                 SetLastError(ERROR_ALREADY_EXISTS);
    3200                 return INVALID_HANDLE_VALUE;
    3201 
    3202             case OPEN_EXISTING:
    3203             case TRUNCATE_EXISTING:
    3204                 kHlpAssertFailed();
    3205                 SetLastError(ERROR_FILE_NOT_FOUND);
    3206                 return INVALID_HANDLE_VALUE;
    3207 
    3208             default:
    3209                 kHlpAssertFailed();
    3210                 SetLastError(ERROR_INVALID_PARAMETER);
    3211                 return INVALID_HANDLE_VALUE;
    3212         }
    3213 
    3214         cbFilename = (cwcFilename + 1) * sizeof(wchar_t);
    3215         pTempFile = (PKWFSTEMPFILE)kHlpAlloc(sizeof(*pTempFile) + cbFilename);
    3216         if (pTempFile)
    3217         {
    3218             pTempFile->cwcPath          = (KU16)cwcFilename;
    3219             pTempFile->cbFile           = 0;
    3220             pTempFile->cbFileAllocated  = 0;
    3221             pTempFile->cActiveHandles   = 0;
    3222             pTempFile->cMappings        = 0;
    3223             pTempFile->cSegs            = 0;
    3224             pTempFile->paSegs           = NULL;
    3225             pTempFile->pwszPath         = (wchar_t const *)kHlpMemCopy(pTempFile + 1, pwszFilename, cbFilename);
    3226 
    3227             pTempFile->pNext = g_Sandbox.pTempFileHead;
    3228             g_Sandbox.pTempFileHead = pTempFile;
    3229             KWFS_LOG(("kwFsTempFileCreateW: Created new temporary file '%ls'\n", pwszFilename));
    3230         }
    3231         else
    3232         {
    3233             KWFS_LOG(("kwFsTempFileCreateW: Out of memory!\n"));
    3234             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
    3235             return INVALID_HANDLE_VALUE;
    3236         }
    3237     }
    3238     else
    3239     {
    3240         switch (dwCreationDisposition)
    3241         {
    3242             case OPEN_EXISTING:
    3243                 dwErr = NO_ERROR;
    3244                 break;
    3245             case OPEN_ALWAYS:
    3246                 dwErr = ERROR_ALREADY_EXISTS ;
    3247                 break;
    3248 
    3249             case TRUNCATE_EXISTING:
    3250             case CREATE_ALWAYS:
    3251                 kHlpAssertFailed();
    3252                 pTempFile->cbFile = 0;
    3253                 dwErr = ERROR_ALREADY_EXISTS;
    3254                 break;
    3255 
    3256             case CREATE_NEW:
    3257                 kHlpAssertFailed();
    3258                 SetLastError(ERROR_FILE_EXISTS);
    3259                 return INVALID_HANDLE_VALUE;
    3260 
    3261             default:
    3262                 kHlpAssertFailed();
    3263                 SetLastError(ERROR_INVALID_PARAMETER);
    3264                 return INVALID_HANDLE_VALUE;
    3265         }
    3266     }
    3267 
    3268     /*
    3269      * Create a handle to the temporary file.
    3270      */
    3271     hFile = kwFsTempFileCreateHandle(pTempFile, dwDesiredAccess, K_FALSE /*fMapping*/);
    3272     if (hFile != INVALID_HANDLE_VALUE)
    3273         SetLastError(dwErr);
    3274     return hFile;
    3275 }
    3276 
    3277 #endif /* WITH_TEMP_MEMORY_FILES */
    3278 
    3279 
    3280 /**
    3281  * Checks if the file extension indicates that the file/dir is something we
    3282  * ought to cache.
    3283  *
    3284  * @returns K_TRUE if cachable, K_FALSE if not.
    3285  * @param   pszExt              The kHlpGetExt result.
    3286  * @param   fAttrQuery          Set if it's for an attribute query, clear if for
    3287  *                              file creation.
    3288  */
    3289 static KBOOL kwFsIsCachableExtensionA(const char *pszExt, KBOOL fAttrQuery)
    3290 {
    3291     char const chFirst = *pszExt;
    3292 
    3293     /* C++ header without an extension or a directory. */
    3294     if (chFirst == '\0')
    3295     {
    3296         /** @todo exclude temporary files...  */
    3297         return K_TRUE;
    3298     }
    3299 
    3300     /* C Header: .h */
    3301     if (chFirst == 'h' || chFirst == 'H')
    3302     {
    3303         char        chThird;
    3304         char const  chSecond = pszExt[1];
    3305         if (chSecond == '\0')
    3306             return K_TRUE;
    3307         chThird = pszExt[2];
    3308 
    3309         /* C++ Header: .hpp, .hxx */
    3310         if (   (chSecond == 'p' || chSecond == 'P')
    3311             && (chThird  == 'p' || chThird  == 'P')
    3312             && pszExt[3] == '\0')
    3313             return K_TRUE;
    3314         if (   (chSecond == 'x' || chSecond == 'X')
    3315             && (chThird  == 'x' || chThird  == 'X')
    3316             && pszExt[3] == '\0')
    3317             return K_TRUE;
    3318 
    3319     }
    3320     /* Misc starting with i. */
    3321     else if (chFirst == 'i' || chFirst == 'I')
    3322     {
    3323         char const chSecond = pszExt[1];
    3324         if (chSecond != '\0')
    3325         {
    3326             if (chSecond == 'n' || chSecond == 'N')
    3327             {
    3328                 char const chThird = pszExt[2];
    3329 
    3330                 /* C++ inline header: .inl */
    3331                 if (   (chThird == 'l' || chThird == 'L')
    3332                     && pszExt[3] == '\0')
    3333                     return K_TRUE;
    3334 
    3335                 /* Assembly include file: .inc */
    3336                 if (   (chThird == 'c' || chThird == 'C')
    3337                     && pszExt[3] == '\0')
    3338                     return K_TRUE;
    3339             }
    3340         }
    3341     }
    3342     else if (fAttrQuery)
    3343     {
    3344         /* Dynamic link library: .dll */
    3345         if (chFirst == 'd' || chFirst == 'D')
    3346         {
    3347             char const chSecond = pszExt[1];
    3348             if (chSecond == 'l' || chSecond == 'L')
    3349             {
    3350                 char const chThird = pszExt[2];
    3351                 if (chThird == 'l' || chThird == 'L')
    3352                     return K_TRUE;
    3353             }
    3354         }
    3355         /* Executable file: .exe */
    3356         else if (chFirst == 'e' || chFirst == 'E')
    3357         {
    3358             char const chSecond = pszExt[1];
    3359             if (chSecond == 'x' || chSecond == 'X')
    3360             {
    3361                 char const chThird = pszExt[2];
    3362                 if (chThird == 'e' || chThird == 'e')
    3363                     return K_TRUE;
    3364             }
    3365         }
    3366     }
    3367 
    3368     return K_FALSE;
    3369 }
    3370 
    3371 
    3372 /**
    3373  * Checks if the extension of the given UTF-16 path indicates that the file/dir
    3374  * should be cached.
    3375  *
    3376  * @returns K_TRUE if cachable, K_FALSE if not.
    3377  * @param   pwszPath            The UTF-16 path to examine.
    3378  * @param   fAttrQuery          Set if it's for an attribute query, clear if for
    3379  *                              file creation.
    3380  */
    3381 static KBOOL kwFsIsCachablePathExtensionW(const wchar_t *pwszPath, KBOOL fAttrQuery)
    3382 {
    3383     /*
    3384      * Extract the extension, check that it's in the applicable range, roughly
    3385      * convert it to ASCII/ANSI, and feed it to kwFsIsCachableExtensionA for
    3386      * the actual check.  This avoids a lot of code duplication.
    3387      */
    3388     wchar_t         wc;
    3389     char            szExt[4];
    3390     KSIZE           cwcExt;
    3391     wchar_t const  *pwszExt = kwFsPathGetExtW(pwszPath, &cwcExt);
    3392     switch (cwcExt)
    3393     {
    3394         case 3: if ((wchar_t)(szExt[2] = (char)(wc = pwszExt[2])) == wc) { /*likely*/ } else break;
    3395         case 2: if ((wchar_t)(szExt[1] = (char)(wc = pwszExt[1])) == wc) { /*likely*/ } else break;
    3396         case 1: if ((wchar_t)(szExt[0] = (char)(wc = pwszExt[0])) == wc) { /*likely*/ } else break;
    3397         case 0:
    3398             szExt[cwcExt] = '\0';
    3399             return kwFsIsCachableExtensionA(szExt, fAttrQuery);
    3400     }
    3401     return K_FALSE;
    3402 }
    3403 
    3404 
    3405 static KBOOL kwFsObjCacheFileCommon(PKWFSOBJ pFsObj, HANDLE hFile)
    3406 {
    3407     LARGE_INTEGER cbFile;
    3408     if (GetFileSizeEx(hFile, &cbFile))
    3409     {
    3410         if (   cbFile.QuadPart >= 0
    3411             && cbFile.QuadPart < 16*1024*1024)
    3412         {
    3413             KU32 cbCache = (KU32)cbFile.QuadPart;
    3414             KU8 *pbCache = (KU8 *)kHlpAlloc(cbCache);
    3415             if (pbCache)
    3416             {
    3417                 DWORD cbActually = 0;
    3418                 if (   ReadFile(hFile, pbCache, cbCache, &cbActually, NULL)
    3419                     && cbActually == cbCache)
    3420                 {
    3421                     LARGE_INTEGER offZero;
    3422                     offZero.QuadPart = 0;
    3423                     if (SetFilePointerEx(hFile, offZero, NULL /*poffNew*/, FILE_BEGIN))
    3424                     {
    3425                         pFsObj->hCached  = hFile;
    3426                         pFsObj->cbCached = cbCache;
    3427                         pFsObj->pbCached = pbCache;
    3428                         return K_TRUE;
    3429                     }
    3430 
    3431                     KWFS_LOG(("Failed to seek to start of cached file! err=%u\n", GetLastError()));
    3432                 }
    3433                 else
    3434                     KWFS_LOG(("Failed to read %#x bytes into cache! err=%u cbActually=%#x\n",
    3435                               cbCache, GetLastError(), cbActually));
    3436                 kHlpFree(pbCache);
    3437             }
    3438             else
    3439                 KWFS_LOG(("Failed to allocate %#x bytes for cache!\n", cbCache));
    3440         }
    3441         else
    3442             KWFS_LOG(("File to big to cache! %#llx\n", cbFile.QuadPart));
    3443     }
    3444     else
    3445         KWFS_LOG(("File to get file size! err=%u\n", GetLastError()));
    3446     CloseHandle(hFile);
    3447     return K_FALSE;
    3448 }
    3449 
    3450 
    3451 static KBOOL kwFsObjCacheFileA(PKWFSOBJ pFsObj, const char *pszFilename)
    3452 {
    3453     HANDLE hFile;
    3454     kHlpAssert(pFsObj->hCached == INVALID_HANDLE_VALUE);
    3455 
    3456     hFile = CreateFileA(pszFilename, GENERIC_READ, FILE_SHARE_READ, NULL /*pSecAttrs*/,
    3457                         FILE_OPEN_IF, FILE_ATTRIBUTE_NORMAL, NULL /*hTemplateFile*/);
    3458     if (hFile != INVALID_HANDLE_VALUE)
    3459         return kwFsObjCacheFileCommon(pFsObj, hFile);
    3460     return K_FALSE;
    3461 }
    3462 
    3463 
    3464 static KBOOL kwFsObjCacheFileW(PKWFSOBJ pFsObj, const wchar_t *pwszFilename)
    3465 {
    3466     HANDLE hFile;
    3467     kHlpAssert(pFsObj->hCached == INVALID_HANDLE_VALUE);
    3468 
    3469     hFile = CreateFileW(pwszFilename, GENERIC_READ, FILE_SHARE_READ, NULL /*pSecAttrs*/,
    3470                         FILE_OPEN_IF, FILE_ATTRIBUTE_NORMAL, NULL /*hTemplateFile*/);
    3471     if (hFile != INVALID_HANDLE_VALUE)
    3472         return kwFsObjCacheFileCommon(pFsObj, hFile);
    3473     return K_FALSE;
    3474 }
    3475 
    3476 
    3477 /** Kernel32 - Common code for CreateFileW and CreateFileA.   */
    3478 static KBOOL kwFsObjCacheCreateFile(PKWFSOBJ pFsObj, DWORD dwDesiredAccess, BOOL fInheritHandle,
    3479                                     const char *pszFilename, const wchar_t *pwszFilename, HANDLE *phFile)
    3480 {
    3481     *phFile = INVALID_HANDLE_VALUE;
    3482 
    3483     /*
    3484      * At the moment we only handle existing files.
    3485      */
    3486     if (!(pFsObj->fAttribs & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE))) /* also checks invalid */
    3487     {
    3488         if (   pFsObj->hCached != INVALID_HANDLE_VALUE
    3489             || (pwszFilename != NULL && kwFsObjCacheFileW(pFsObj, pwszFilename))
    3490             || (pszFilename  != NULL && kwFsObjCacheFileA(pFsObj, pszFilename)) )
    3491         {
    3492             HANDLE hProcSelf = GetCurrentProcess();
    3493             if (DuplicateHandle(hProcSelf, pFsObj->hCached,
    3494                                 hProcSelf, phFile,
    3495                                 dwDesiredAccess, fInheritHandle,
    3496                                 0 /*dwOptions*/))
    3497             {
    3498                 /*
    3499                  * Create handle table entry for the duplicate handle.
    3500                  */
    3501                 PKWHANDLE pHandle = (PKWHANDLE)kHlpAlloc(sizeof(*pHandle));
    3502                 if (pHandle)
    3503                 {
    3504                     pHandle->enmType            = KWHANDLETYPE_FSOBJ_READ_CACHE;
    3505                     pHandle->offFile            = 0;
    3506                     pHandle->hHandle            = *phFile;
    3507                     pHandle->dwDesiredAccess    = dwDesiredAccess;
    3508                     pHandle->u.pFsObj           = pFsObj;
    3509                     if (kwSandboxHandleTableEnter(&g_Sandbox, pHandle))
    3510                         return K_TRUE;
    3511 
    3512                     kHlpFree(pHandle);
    3513                 }
    3514                 else
    3515                     KWFS_LOG(("Out of memory for handle!\n"));
    3516 
    3517                 CloseHandle(*phFile);
    3518                 *phFile = INVALID_HANDLE_VALUE;
    3519             }
    3520             else
    3521                 KWFS_LOG(("DuplicateHandle failed! err=%u\n", GetLastError()));
    3522         }
    3523     }
    3524     /** @todo Deal with non-existing files if it becomes necessary (it's not for VS2010). */
    3525 
    3526     /* Do fallback, please. */
    3527     return K_FALSE;
    3528 }
    3529 
    3530 
    3531 /** Kernel32 - CreateFileA */
    3532 static HANDLE WINAPI kwSandbox_Kernel32_CreateFileA(LPCSTR pszFilename, DWORD dwDesiredAccess, DWORD dwShareMode,
    3533                                                     LPSECURITY_ATTRIBUTES pSecAttrs, DWORD dwCreationDisposition,
    3534                                                     DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
    3535 {
    3536     HANDLE hFile;
    3537     if (dwCreationDisposition == FILE_OPEN_IF)
    3538     {
    3539         if (   dwDesiredAccess == GENERIC_READ
    3540             || dwDesiredAccess == FILE_GENERIC_READ)
    3541         {
    3542             if (dwShareMode & FILE_SHARE_READ)
    3543             {
    3544                 if (   !pSecAttrs
    3545                     || (   pSecAttrs->nLength == sizeof(*pSecAttrs)
    3546                         && pSecAttrs->lpSecurityDescriptor == NULL ) )
    3547                 {
    3548                     const char *pszExt = kHlpGetExt(pszFilename);
    3549                     if (kwFsIsCachableExtensionA(pszExt, K_FALSE /*fAttrQuery*/))
    3550                     {
    3551                         PKWFSOBJ pFsObj = kwFsLookupA(pszFilename);
    3552                         if (pFsObj)
    3553                         {
    3554                             if (kwFsObjCacheCreateFile(pFsObj, dwDesiredAccess, pSecAttrs && pSecAttrs->bInheritHandle,
    3555                                                        pszFilename, NULL /*pwszFilename*/, &hFile))
    3556                             {
    3557                                 KWFS_LOG(("CreateFileA(%s) -> %p [cached]\n", pszFilename, hFile));
    3558                                 return hFile;
    3559                             }
    3560                         }
    3561 
    3562                         /* fallback */
    3563                         hFile = CreateFileA(pszFilename, dwDesiredAccess, dwShareMode, pSecAttrs,
    3564                                             dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
    3565                         KWFS_LOG(("CreateFileA(%s) -> %p (err=%u) [fallback]\n", pszFilename, hFile, GetLastError()));
    3566                         return hFile;
    3567                     }
    3568                 }
    3569             }
    3570         }
    3571     }
    3572 
    3573     hFile = CreateFileA(pszFilename, dwDesiredAccess, dwShareMode, pSecAttrs,
    3574                         dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
    3575     KWFS_LOG(("CreateFileA(%s) -> %p\n", pszFilename, hFile));
    3576     return hFile;
    3577 }
    3578 
    3579 
    3580 /** Kernel32 - CreateFileW */
    3581 static HANDLE WINAPI kwSandbox_Kernel32_CreateFileW(LPCWSTR pwszFilename, DWORD dwDesiredAccess, DWORD dwShareMode,
    3582                                                     LPSECURITY_ATTRIBUTES pSecAttrs, DWORD dwCreationDisposition,
    3583                                                     DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
    3584 {
    3585     HANDLE hFile;
    3586 
    3587 #ifdef WITH_TEMP_MEMORY_FILES
    3588     /* First check for temporary files (cl.exe only). */
    3589     if (   g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL
    3590         && !(dwFlagsAndAttributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE | FILE_FLAG_BACKUP_SEMANTICS))
    3591         && !(dwDesiredAccess & (GENERIC_EXECUTE | FILE_EXECUTE))
    3592         && kwFsIsClTempFileW(pwszFilename))
    3593     {
    3594         hFile = kwFsTempFileCreateW(pwszFilename, dwDesiredAccess, dwCreationDisposition);
    3595         KWFS_LOG(("CreateFileW(%ls) -> %p [temp]\n", pwszFilename, hFile));
    3596         return hFile;
    3597     }
    3598 #endif
    3599 
    3600     /* Then check for include files and similar. */
    3601     if (dwCreationDisposition == FILE_OPEN_IF)
    3602     {
    3603         if (   dwDesiredAccess == GENERIC_READ
    3604             || dwDesiredAccess == FILE_GENERIC_READ)
    3605         {
    3606             if (dwShareMode & FILE_SHARE_READ)
    3607             {
    3608                 if (   !pSecAttrs
    3609                     || (   pSecAttrs->nLength == sizeof(*pSecAttrs)
    3610                         && pSecAttrs->lpSecurityDescriptor == NULL ) )
    3611                 {
    3612                     if (kwFsIsCachablePathExtensionW(pwszFilename, K_FALSE /*fAttrQuery*/))
    3613                     {
    3614                         /** @todo rewrite to pure UTF-16. */
    3615                         char szTmp[2048];
    3616                         KSIZE cch = kwUtf16ToStr(pwszFilename, szTmp, sizeof(szTmp));
    3617                         if (cch < sizeof(szTmp))
    3618                             return kwSandbox_Kernel32_CreateFileA(szTmp, dwDesiredAccess, dwShareMode, pSecAttrs,
    3619                                                                   dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
    3620                     }
    3621                 }
    3622                 else
    3623                     KWFS_LOG(("CreateFileW: incompatible security attributes (nLength=%#x pDesc=%p)\n",
    3624                               pSecAttrs->nLength, pSecAttrs->lpSecurityDescriptor));
    3625             }
    3626             else
    3627                 KWFS_LOG(("CreateFileW: incompatible sharing mode %#x\n", dwShareMode));
    3628         }
    3629         else
    3630             KWFS_LOG(("CreateFileW: incompatible desired access %#x\n", dwDesiredAccess));
    3631     }
    3632     else
    3633         KWFS_LOG(("CreateFileW: incompatible disposition %u\n", dwCreationDisposition));
    3634     hFile = CreateFileW(pwszFilename, dwDesiredAccess, dwShareMode, pSecAttrs,
    3635                         dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
    3636     KWFS_LOG(("CreateFileW(%ls) -> %p\n", pwszFilename, hFile));
    3637     return hFile;
    3638 }
    3639 
    3640 
    3641 /** Kernel32 - SetFilePointer */
    3642 static DWORD WINAPI kwSandbox_Kernel32_SetFilePointer(HANDLE hFile, LONG cbMove, PLONG pcbMoveHi, DWORD dwMoveMethod)
    3643 {
    3644     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
    3645     if (idxHandle < g_Sandbox.cHandles)
    3646     {
    3647         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
    3648         if (pHandle != NULL)
    3649         {
    3650             KU32 cbFile;
    3651             KI64 offMove = pcbMoveHi ? ((KI64)*pcbMoveHi << 32) | cbMove : cbMove;
    3652             switch (pHandle->enmType)
    3653             {
    3654                 case KWHANDLETYPE_FSOBJ_READ_CACHE:
    3655                     cbFile = pHandle->u.pFsObj->cbCached;
    3656                     break;
    3657 #ifdef WITH_TEMP_MEMORY_FILES
    3658                 case KWHANDLETYPE_TEMP_FILE:
    3659                     cbFile = pHandle->u.pTempFile->cbFile;
    3660                     break;
    3661                 case KWHANDLETYPE_TEMP_FILE_MAPPING:
    3662 #endif
    3663                 default:
    3664                     kHlpAssertFailed();
    3665                     SetLastError(ERROR_INVALID_FUNCTION);
    3666                     return INVALID_SET_FILE_POINTER;
    3667             }
    3668 
    3669             switch (dwMoveMethod)
    3670             {
    3671                 case FILE_BEGIN:
    3672                     break;
    3673                 case FILE_CURRENT:
    3674                     offMove += pHandle->offFile;
    3675                     break;
    3676                 case FILE_END:
    3677                     offMove += cbFile;
    3678                     break;
    3679                 default:
    3680                     KWFS_LOG(("SetFilePointer(%p) - invalid seek method %u! [cached]\n", hFile));
    3681                     SetLastError(ERROR_INVALID_PARAMETER);
    3682                     return INVALID_SET_FILE_POINTER;
    3683             }
    3684             if (offMove >= 0)
    3685             {
    3686                 if (offMove >= (KSSIZE)cbFile)
    3687                 {
    3688                     /* For read-only files, seeking beyond the end isn't useful to us, so clamp it. */
    3689                     if (pHandle->enmType != KWHANDLETYPE_TEMP_FILE)
    3690                         offMove = (KSSIZE)cbFile;
    3691                     /* For writable files, seeking beyond the end is fine, but check that we've got
    3692                        the type range for the request. */
    3693                     else if (((KU64)offMove & KU32_MAX) != (KU64)offMove)
    3694                     {
    3695                         kHlpAssertMsgFailed(("%#llx\n", offMove));
    3696                         SetLastError(ERROR_SEEK);
    3697                         return INVALID_SET_FILE_POINTER;
    3698                     }
    3699                 }
    3700                 pHandle->offFile = (KU32)offMove;
    3701             }
    3702             else
    3703             {
    3704                 KWFS_LOG(("SetFilePointer(%p) - negative seek! [cached]\n", hFile));
    3705                 SetLastError(ERROR_NEGATIVE_SEEK);
    3706                 return INVALID_SET_FILE_POINTER;
    3707             }
    3708             if (pcbMoveHi)
    3709                 *pcbMoveHi = (KU64)offMove >> 32;
    3710             KWFS_LOG(("SetFilePointer(%p) -> %#llx [cached]\n", hFile, offMove));
    3711             SetLastError(NO_ERROR);
    3712             return (KU32)offMove;
    3713         }
    3714     }
    3715     KWFS_LOG(("SetFilePointer(%p)\n", hFile));
    3716     return SetFilePointer(hFile, cbMove, pcbMoveHi, dwMoveMethod);
    3717 }
    3718 
    3719 
    3720 /** Kernel32 - SetFilePointerEx */
    3721 static BOOL WINAPI kwSandbox_Kernel32_SetFilePointerEx(HANDLE hFile, LARGE_INTEGER offMove, PLARGE_INTEGER poffNew,
    3722                                                        DWORD dwMoveMethod)
    3723 {
    3724     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
    3725     if (idxHandle < g_Sandbox.cHandles)
    3726     {
    3727         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
    3728         if (pHandle != NULL)
    3729         {
    3730             KI64 offMyMove = offMove.QuadPart;
    3731             KU32 cbFile;
    3732             switch (pHandle->enmType)
    3733             {
    3734                 case KWHANDLETYPE_FSOBJ_READ_CACHE:
    3735                     cbFile = pHandle->u.pFsObj->cbCached;
    3736                     break;
    3737 #ifdef WITH_TEMP_MEMORY_FILES
    3738                 case KWHANDLETYPE_TEMP_FILE:
    3739                     cbFile = pHandle->u.pTempFile->cbFile;
    3740                     break;
    3741                 case KWHANDLETYPE_TEMP_FILE_MAPPING:
    3742 #endif
    3743                 default:
    3744                     kHlpAssertFailed();
    3745                     SetLastError(ERROR_INVALID_FUNCTION);
    3746                     return INVALID_SET_FILE_POINTER;
    3747             }
    3748 
    3749             switch (dwMoveMethod)
    3750             {
    3751                 case FILE_BEGIN:
    3752                     break;
    3753                 case FILE_CURRENT:
    3754                     offMyMove += pHandle->offFile;
    3755                     break;
    3756                 case FILE_END:
    3757                     offMyMove += cbFile;
    3758                     break;
    3759                 default:
    3760                     KWFS_LOG(("SetFilePointer(%p) - invalid seek method %u! [cached]\n", hFile));
    3761                     SetLastError(ERROR_INVALID_PARAMETER);
    3762                     return INVALID_SET_FILE_POINTER;
    3763             }
    3764             if (offMyMove >= 0)
    3765             {
    3766                 if (offMyMove >= (KSSIZE)cbFile)
    3767                 {
    3768                     /* For read-only files, seeking beyond the end isn't useful to us, so clamp it. */
    3769                     if (pHandle->enmType != KWHANDLETYPE_TEMP_FILE)
    3770                         offMyMove = (KSSIZE)cbFile;
    3771                     /* For writable files, seeking beyond the end is fine, but check that we've got
    3772                        the type range for the request. */
    3773                     else if (((KU64)offMyMove & KU32_MAX) != (KU64)offMyMove)
    3774                     {
    3775                         kHlpAssertMsgFailed(("%#llx\n", offMyMove));
    3776                         SetLastError(ERROR_SEEK);
    3777                         return INVALID_SET_FILE_POINTER;
    3778                     }
    3779                 }
    3780                 pHandle->offFile = (KU32)offMyMove;
    3781             }
    3782             else
    3783             {
    3784                 KWFS_LOG(("SetFilePointerEx(%p) - negative seek! [cached]\n", hFile));
    3785                 SetLastError(ERROR_NEGATIVE_SEEK);
    3786                 return INVALID_SET_FILE_POINTER;
    3787             }
    3788             if (poffNew)
    3789                 poffNew->QuadPart = offMyMove;
    3790             KWFS_LOG(("SetFilePointerEx(%p) -> TRUE, %#llx [cached]\n", hFile, offMyMove));
    3791             return TRUE;
    3792         }
    3793     }
    3794     KWFS_LOG(("SetFilePointerEx(%p)\n", hFile));
    3795     return SetFilePointerEx(hFile, offMove, poffNew, dwMoveMethod);
    3796 }
    3797 
    3798 
    3799 /** Kernel32 - ReadFile */
    3800 static BOOL WINAPI kwSandbox_Kernel32_ReadFile(HANDLE hFile, LPVOID pvBuffer, DWORD cbToRead, LPDWORD pcbActuallyRead,
    3801                                                LPOVERLAPPED pOverlapped)
    3802 {
    3803     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
    3804     if (idxHandle < g_Sandbox.cHandles)
    3805     {
    3806         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
    3807         if (pHandle != NULL)
    3808         {
    3809             switch (pHandle->enmType)
    3810             {
    3811                 case KWHANDLETYPE_FSOBJ_READ_CACHE:
    3812                 {
    3813                     PKWFSOBJ    pFsObj     = pHandle->u.pFsObj;
    3814                     KU32        cbActually = pFsObj->cbCached - pHandle->offFile;
    3815                     if (cbActually > cbToRead)
    3816                         cbActually = cbToRead;
    3817                     else if (cbActually < cbToRead)
    3818                         ((KU8 *)pvBuffer)[cbActually] = '\0'; // hack hack hack
    3819 
    3820                     kHlpMemCopy(pvBuffer, &pFsObj->pbCached[pHandle->offFile], cbActually);
    3821                     pHandle->offFile += cbActually;
    3822 
    3823                     kHlpAssert(!pOverlapped); kHlpAssert(pcbActuallyRead);
    3824                     *pcbActuallyRead = cbActually;
    3825 
    3826                     KWFS_LOG(("ReadFile(%p,,%#x) -> TRUE, %#x bytes [cached]\n", hFile, cbToRead, cbActually));
    3827                     return TRUE;
    3828                 }
    3829 
    3830 #ifdef WITH_TEMP_MEMORY_FILES
    3831                 case KWHANDLETYPE_TEMP_FILE:
    3832                 {
    3833                     PKWFSTEMPFILE   pTempFile  = pHandle->u.pTempFile;
    3834                     KU32            cbActually;
    3835                     if (pHandle->offFile < pTempFile->cbFile)
    3836                     {
    3837                         cbActually = pTempFile->cbFile - pHandle->offFile;
    3838                         if (cbActually > cbToRead)
    3839                             cbActually = cbToRead;
    3840 
    3841                         /* Copy the data. */
    3842                         if (cbActually > 0)
    3843                         {
    3844                             KU32                    cbLeft;
    3845                             KU32                    offSeg;
    3846                             KWFSTEMPFILESEG const  *paSegs = pTempFile->paSegs;
    3847 
    3848                             /* Locate the segment containing the byte at offFile. */
    3849                             KU32 iSeg   = pTempFile->cSegs - 1;
    3850                             kHlpAssert(pTempFile->cSegs > 0);
    3851                             while (paSegs[iSeg].offData > pHandle->offFile)
    3852                                 iSeg--;
    3853 
    3854                             /* Copy out the data. */
    3855                             cbLeft = cbActually;
    3856                             offSeg = (pHandle->offFile - paSegs[iSeg].offData);
    3857                             for (;;)
    3858                             {
    3859                                 KU32 cbAvail = paSegs[iSeg].cbDataAlloc - offSeg;
    3860                                 if (cbAvail >= cbLeft)
    3861                                 {
    3862                                     kHlpMemCopy(pvBuffer, &paSegs[iSeg].pbData[offSeg], cbLeft);
    3863                                     break;
    3864                                 }
    3865 
    3866                                 pvBuffer = kHlpMemPCopy(pvBuffer, &paSegs[iSeg].pbData[offSeg], cbAvail);
    3867                                 cbLeft  -= cbAvail;
    3868                                 offSeg   = 0;
    3869                                 iSeg++;
    3870                                 kHlpAssert(iSeg < pTempFile->cSegs);
    3871                             }
    3872 
    3873                             /* Update the file offset. */
    3874                             pHandle->offFile += cbActually;
    3875                         }
    3876                     }
    3877                     /* Read does not commit file space, so return zero bytes. */
    3878                     else
    3879                         cbActually = 0;
    3880 
    3881                     kHlpAssert(!pOverlapped); kHlpAssert(pcbActuallyRead);
    3882                     *pcbActuallyRead = cbActually;
    3883 
    3884                     KWFS_LOG(("ReadFile(%p,,%#x) -> TRUE, %#x bytes [temp]\n", hFile, cbToRead, (KU32)cbActually));
    3885                     return TRUE;
    3886                 }
    3887 
    3888                 case KWHANDLETYPE_TEMP_FILE_MAPPING:
    3889 #endif /* WITH_TEMP_MEMORY_FILES */
    3890                 default:
    3891                     kHlpAssertFailed();
    3892                     SetLastError(ERROR_INVALID_FUNCTION);
    3893                     *pcbActuallyRead = 0;
    3894                     return FALSE;
    3895             }
    3896         }
    3897     }
    3898 
    3899     KWFS_LOG(("ReadFile(%p)\n", hFile));
    3900     return ReadFile(hFile, pvBuffer, cbToRead, pcbActuallyRead, pOverlapped);
    3901 }
    3902 
    3903 
    3904 /** Kernel32 - ReadFileEx */
    3905 static BOOL WINAPI kwSandbox_Kernel32_ReadFileEx(HANDLE hFile, LPVOID pvBuffer, DWORD cbToRead, LPOVERLAPPED pOverlapped,
    3906                                                  LPOVERLAPPED_COMPLETION_ROUTINE pfnCompletionRoutine)
    3907 {
    3908     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
    3909     if (idxHandle < g_Sandbox.cHandles)
    3910     {
    3911         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
    3912         if (pHandle != NULL)
    3913         {
    3914             kHlpAssertFailed();
    3915         }
    3916     }
    3917 
    3918     KWFS_LOG(("ReadFile(%p)\n", hFile));
    3919     return ReadFileEx(hFile, pvBuffer, cbToRead, pOverlapped, pfnCompletionRoutine);
    3920 }
    3921 
    3922 #ifdef WITH_TEMP_MEMORY_FILES
    3923 
    3924 static KBOOL kwFsTempFileEnsureSpace(PKWFSTEMPFILE pTempFile, KU32 offFile, KU32 cbNeeded)
    3925 {
    3926     KU32 cbMinFile = offFile + cbNeeded;
    3927     if (cbMinFile >= offFile)
    3928     {
    3929         /* Calc how much space we've already allocated and  */
    3930         if (cbMinFile <= pTempFile->cbFileAllocated)
    3931             return K_TRUE;
    3932 
    3933         /* Grow the file. */
    3934         if (cbMinFile <= KWFS_TEMP_FILE_MAX)
    3935         {
    3936             int  rc;
    3937             KU32 cSegs    = pTempFile->cSegs;
    3938             KU32 cbNewSeg = cbMinFile > 4*1024*1024 ? 256*1024 : 4*1024*1024;
    3939             do
    3940             {
    3941                 /* grow the segment array? */
    3942                 if ((cSegs % 16) == 0)
    3943                 {
    3944                     void *pvNew = kHlpRealloc(pTempFile->paSegs, (cSegs + 16) * sizeof(pTempFile->paSegs[0]));
    3945                     if (!pvNew)
    3946                         return K_FALSE;
    3947                     pTempFile->paSegs = (PKWFSTEMPFILESEG)pvNew;
    3948                 }
    3949 
    3950                 /* Use page alloc here to simplify mapping later. */
    3951                 rc = kHlpPageAlloc((void **)&pTempFile->paSegs[cSegs].pbData, cbNewSeg, KPROT_READWRITE, K_FALSE);
    3952                 if (rc == 0)
    3953                 { /* likely */ }
    3954                 else
    3955                 {
    3956                     cbNewSeg = 64*1024*1024;
    3957                     rc = kHlpPageAlloc((void **)&pTempFile->paSegs[cSegs].pbData, cbNewSeg, KPROT_READWRITE, K_FALSE);
    3958                     if (rc != 0)
    3959                         return K_FALSE;
    3960                 }
    3961                 pTempFile->paSegs[cSegs].offData     = pTempFile->cbFileAllocated;
    3962                 pTempFile->paSegs[cSegs].cbDataAlloc = cbNewSeg;
    3963                 pTempFile->cbFileAllocated          += cbNewSeg;
    3964                 pTempFile->cSegs                     = ++cSegs;
    3965 
    3966             } while (pTempFile->cbFileAllocated < cbMinFile);
    3967 
    3968             return K_TRUE;
    3969         }
    3970     }
    3971 
    3972     kHlpAssertMsgFailed(("Out of bounds offFile=%#x + cbNeeded=%#x = %#x\n", offFile, cbNeeded, offFile + cbNeeded));
    3973     return K_FALSE;
    3974 }
    3975 
    3976 
    3977 /** Kernel32 - WriteFile */
    3978 static BOOL WINAPI kwSandbox_Kernel32_WriteFile(HANDLE hFile, LPCVOID pvBuffer, DWORD cbToWrite, LPDWORD pcbActuallyWritten,
    3979                                                 LPOVERLAPPED pOverlapped)
    3980 {
    3981     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
    3982     if (idxHandle < g_Sandbox.cHandles)
    3983     {
    3984         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
    3985         if (pHandle != NULL)
    3986         {
    3987             switch (pHandle->enmType)
    3988             {
    3989                 case KWHANDLETYPE_TEMP_FILE:
    3990                 {
    3991                     PKWFSTEMPFILE   pTempFile  = pHandle->u.pTempFile;
    3992 
    3993                     kHlpAssert(!pOverlapped);
    3994                     kHlpAssert(pcbActuallyWritten);
    3995 
    3996                     if (kwFsTempFileEnsureSpace(pTempFile, pHandle->offFile, cbToWrite))
    3997                     {
    3998                         KU32                    cbLeft;
    3999                         KU32                    offSeg;
    4000 
    4001                         /* Locate the segment containing the byte at offFile. */
    4002                         KWFSTEMPFILESEG const  *paSegs = pTempFile->paSegs;
    4003                         KU32                    iSeg   = pTempFile->cSegs - 1;
    4004                         kHlpAssert(pTempFile->cSegs > 0);
    4005                         while (paSegs[iSeg].offData > pHandle->offFile)
    4006                             iSeg--;
    4007 
    4008                         /* Copy in the data. */
    4009                         cbLeft = cbToWrite;
    4010                         offSeg = (pHandle->offFile - paSegs[iSeg].offData);
    4011                         for (;;)
    4012                         {
    4013                             KU32 cbAvail = paSegs[iSeg].cbDataAlloc - offSeg;
    4014                             if (cbAvail >= cbLeft)
    4015                             {
    4016                                 kHlpMemCopy(&paSegs[iSeg].pbData[offSeg], pvBuffer, cbLeft);
    4017                                 break;
    4018                             }
    4019 
    4020                             kHlpMemCopy(&paSegs[iSeg].pbData[offSeg], pvBuffer, cbAvail);
    4021                             pvBuffer = (KU8 const *)pvBuffer + cbAvail;
    4022                             cbLeft  -= cbAvail;
    4023                             offSeg   = 0;
    4024                             iSeg++;
    4025                             kHlpAssert(iSeg < pTempFile->cSegs);
    4026                         }
    4027 
    4028                         /* Update the file offset. */
    4029                         pHandle->offFile += cbToWrite;
    4030                         if (pHandle->offFile > pTempFile->cbFile)
    4031                             pTempFile->cbFile = pHandle->offFile;
    4032 
    4033                         *pcbActuallyWritten = cbToWrite;
    4034                         KWFS_LOG(("WriteFile(%p,,%#x) -> TRUE [temp]\n", hFile, cbToWrite));
    4035                         return TRUE;
    4036                     }
    4037 
    4038                     *pcbActuallyWritten = 0;
    4039                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
    4040                     return FALSE;
    4041                 }
    4042 
    4043                 case KWHANDLETYPE_FSOBJ_READ_CACHE:
    4044                     kHlpAssertFailed();
    4045                     SetLastError(ERROR_ACCESS_DENIED);
    4046                     *pcbActuallyWritten = 0;
    4047                     return FALSE;
    4048 
    4049                 default:
    4050                 case KWHANDLETYPE_TEMP_FILE_MAPPING:
    4051                     kHlpAssertFailed();
    4052                     SetLastError(ERROR_INVALID_FUNCTION);
    4053                     *pcbActuallyWritten = 0;
    4054                     return FALSE;
    4055             }
    4056         }
    4057     }
    4058 
    4059     KWFS_LOG(("WriteFile(%p)\n", hFile));
    4060     return WriteFile(hFile, pvBuffer, cbToWrite, pcbActuallyWritten, pOverlapped);
    4061 }
    4062 
    4063 
    4064 /** Kernel32 - WriteFileEx */
    4065 static BOOL WINAPI kwSandbox_Kernel32_WriteFileEx(HANDLE hFile, LPCVOID pvBuffer, DWORD cbToWrite, LPOVERLAPPED pOverlapped,
    4066                                                   LPOVERLAPPED_COMPLETION_ROUTINE pfnCompletionRoutine)
    4067 {
    4068     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
    4069     if (idxHandle < g_Sandbox.cHandles)
    4070     {
    4071         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
    4072         if (pHandle != NULL)
    4073         {
    4074             kHlpAssertFailed();
    4075         }
    4076     }
    4077 
    4078     KWFS_LOG(("WriteFileEx(%p)\n", hFile));
    4079     return WriteFileEx(hFile, pvBuffer, cbToWrite, pOverlapped, pfnCompletionRoutine);
    4080 }
    4081 
    4082 
    4083 /** Kernel32 - SetEndOfFile; */
    4084 static BOOL WINAPI kwSandbox_Kernel32_SetEndOfFile(HANDLE hFile)
    4085 {
    4086     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
    4087     if (idxHandle < g_Sandbox.cHandles)
    4088     {
    4089         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
    4090         if (pHandle != NULL)
    4091         {
    4092             switch (pHandle->enmType)
    4093             {
    4094                 case KWHANDLETYPE_TEMP_FILE:
    4095                 {
    4096                     PKWFSTEMPFILE   pTempFile  = pHandle->u.pTempFile;
    4097                     if (   pHandle->offFile > pTempFile->cbFile
    4098                         && !kwFsTempFileEnsureSpace(pTempFile, pHandle->offFile, 0))
    4099                     {
    4100                         kHlpAssertFailed();
    4101                         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
    4102                         return FALSE;
    4103                     }
    4104 
    4105                     pTempFile->cbFile = pHandle->offFile;
    4106                     KWFS_LOG(("SetEndOfFile(%p) -> TRUE (cbFile=%#x)\n", hFile, pTempFile->cbFile));
    4107                     return TRUE;
    4108                 }
    4109 
    4110                 case KWHANDLETYPE_FSOBJ_READ_CACHE:
    4111                     kHlpAssertFailed();
    4112                     SetLastError(ERROR_ACCESS_DENIED);
    4113                     return FALSE;
    4114 
    4115                 default:
    4116                 case KWHANDLETYPE_TEMP_FILE_MAPPING:
    4117                     kHlpAssertFailed();
    4118                     SetLastError(ERROR_INVALID_FUNCTION);
    4119                     return FALSE;
    4120             }
    4121         }
    4122     }
    4123 
    4124     KWFS_LOG(("SetEndOfFile(%p)\n", hFile));
    4125     return SetEndOfFile(hFile);
    4126 }
    4127 
    4128 
    4129 /** Kernel32 - GetFileType  */
    4130 static BOOL WINAPI kwSandbox_Kernel32_GetFileType(HANDLE hFile)
    4131 {
    4132     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
    4133     if (idxHandle < g_Sandbox.cHandles)
    4134     {
    4135         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
    4136         if (pHandle != NULL)
    4137         {
    4138             switch (pHandle->enmType)
    4139             {
    4140                 case KWHANDLETYPE_FSOBJ_READ_CACHE:
    4141                     KWFS_LOG(("GetFileType(%p) -> FILE_TYPE_DISK [cached]\n", hFile));
    4142                     return FILE_TYPE_DISK;
    4143 
    4144                 case KWHANDLETYPE_TEMP_FILE:
    4145                     KWFS_LOG(("GetFileType(%p) -> FILE_TYPE_DISK [temp]\n", hFile));
    4146                     return FILE_TYPE_DISK;
    4147             }
    4148         }
    4149     }
    4150 
    4151     KWFS_LOG(("GetFileType(%p)\n", hFile));
    4152     return GetFileType(hFile);
    4153 }
    4154 
    4155 
    4156 /** Kernel32 - GetFileSize  */
    4157 static DWORD WINAPI kwSandbox_Kernel32_GetFileSize(HANDLE hFile, LPDWORD pcbHighDword)
    4158 {
    4159     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
    4160     if (idxHandle < g_Sandbox.cHandles)
    4161     {
    4162         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
    4163         if (pHandle != NULL)
    4164         {
    4165             if (pcbHighDword)
    4166                 *pcbHighDword = 0;
    4167             SetLastError(NO_ERROR);
    4168             switch (pHandle->enmType)
    4169             {
    4170                 case KWHANDLETYPE_FSOBJ_READ_CACHE:
    4171                     KWFS_LOG(("GetFileSize(%p) -> %#x [cached]\n", hFile, pHandle->u.pFsObj->cbCached));
    4172                     return pHandle->u.pFsObj->cbCached;
    4173 
    4174                 case KWHANDLETYPE_TEMP_FILE:
    4175                     KWFS_LOG(("GetFileSize(%p) -> %#x [temp]\n", hFile, pHandle->u.pTempFile->cbFile));
    4176                     return pHandle->u.pTempFile->cbFile;
    4177 
    4178                 default:
    4179                     kHlpAssertFailed();
    4180                     SetLastError(ERROR_INVALID_FUNCTION);
    4181                     return INVALID_FILE_SIZE;
    4182             }
    4183         }
    4184     }
    4185 
    4186     KWFS_LOG(("GetFileSize(%p,)\n", hFile));
    4187     return GetFileSize(hFile, pcbHighDword);
    4188 }
    4189 
    4190 
    4191 /** Kernel32 - GetFileSizeEx  */
    4192 static BOOL WINAPI kwSandbox_Kernel32_GetFileSizeEx(HANDLE hFile, PLARGE_INTEGER pcbFile)
    4193 {
    4194     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
    4195     if (idxHandle < g_Sandbox.cHandles)
    4196     {
    4197         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
    4198         if (pHandle != NULL)
    4199         {
    4200             switch (pHandle->enmType)
    4201             {
    4202                 case KWHANDLETYPE_FSOBJ_READ_CACHE:
    4203                     KWFS_LOG(("GetFileSizeEx(%p) -> TRUE, %#x [cached]\n", hFile, pHandle->u.pFsObj->cbCached));
    4204                     pcbFile->QuadPart = pHandle->u.pFsObj->cbCached;
    4205                     return TRUE;
    4206 
    4207                 case KWHANDLETYPE_TEMP_FILE:
    4208                     KWFS_LOG(("GetFileSizeEx(%p) -> TRUE, %#x [temp]\n", hFile, pHandle->u.pTempFile->cbFile));
    4209                     pcbFile->QuadPart = pHandle->u.pTempFile->cbFile;
    4210                     return TRUE;
    4211 
    4212                 default:
    4213                     kHlpAssertFailed();
    4214                     SetLastError(ERROR_INVALID_FUNCTION);
    4215                     return INVALID_FILE_SIZE;
    4216             }
    4217         }
    4218     }
    4219 
    4220     KWFS_LOG(("GetFileSizeEx(%p,)\n", hFile));
    4221     return GetFileSizeEx(hFile, pcbFile);
    4222 }
    4223 
    4224 
    4225 /** Kernel32 - CreateFileMapping  */
    4226 static HANDLE WINAPI kwSandbox_Kernel32_CreateFileMappingW(HANDLE hFile, LPSECURITY_ATTRIBUTES pSecAttrs,
    4227                                                            DWORD fProtect, DWORD dwMaximumSizeHigh,
    4228                                                            DWORD dwMaximumSizeLow, LPCWSTR pwszName)
    4229 {
    4230     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hFile);
    4231     if (idxHandle < g_Sandbox.cHandles)
    4232     {
    4233         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
    4234         if (pHandle != NULL)
    4235         {
    4236             switch (pHandle->enmType)
    4237             {
    4238                 case KWHANDLETYPE_TEMP_FILE:
    4239                 {
    4240                     PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile;
    4241                     if (   (   fProtect == PAGE_READONLY
    4242                             || fProtect == PAGE_EXECUTE_READ)
    4243                         && dwMaximumSizeHigh == 0
    4244                         &&  (   dwMaximumSizeLow == 0
    4245                              || dwMaximumSizeLow == pTempFile->cbFile)
    4246                         && pwszName == NULL)
    4247                     {
    4248                         HANDLE hMapping = kwFsTempFileCreateHandle(pHandle->u.pTempFile, GENERIC_READ, K_TRUE /*fMapping*/);
    4249                         KWFS_LOG(("CreateFileMappingW(%p, %u) -> %p [temp]\n", hFile, fProtect, hMapping));
    4250                         return hMapping;
    4251                     }
    4252                     kHlpAssertMsgFailed(("fProtect=%#x cb=%#x'%08x name=%p\n",
    4253                                          fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName));
    4254                     SetLastError(ERROR_ACCESS_DENIED);
    4255                     return INVALID_HANDLE_VALUE;
    4256                 }
    4257             }
    4258         }
    4259     }
    4260 
    4261     KWFS_LOG(("CreateFileMappingW(%p)\n", hFile));
    4262     return CreateFileMappingW(hFile, pSecAttrs, fProtect, dwMaximumSizeHigh, dwMaximumSizeLow, pwszName);
    4263 }
    4264 
    4265 /** Kernel32 - MapViewOfFile  */
    4266 static HANDLE WINAPI kwSandbox_Kernel32_MapViewOfFile(HANDLE hSection, DWORD dwDesiredAccess,
    4267                                                       DWORD offFileHigh, DWORD offFileLow, SIZE_T cbToMap)
    4268 {
    4269     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hSection);
    4270     if (idxHandle < g_Sandbox.cHandles)
    4271     {
    4272         PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
    4273         if (pHandle != NULL)
    4274         {
    4275             switch (pHandle->enmType)
    4276             {
    4277                 case KWHANDLETYPE_FSOBJ_READ_CACHE:
    4278                 case KWHANDLETYPE_TEMP_FILE:
    4279                     kHlpAssertFailed();
    4280                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
    4281                     return NULL;
    4282 
    4283                 case KWHANDLETYPE_TEMP_FILE_MAPPING:
    4284                 {
    4285                     PKWFSTEMPFILE pTempFile = pHandle->u.pTempFile;
    4286                     if (   dwDesiredAccess == FILE_MAP_READ
    4287                         && offFileHigh == 0
    4288                         && offFileLow  == 0
    4289                         && (cbToMap == 0 || cbToMap == pTempFile->cbFile) )
    4290                     {
    4291                         kHlpAssert(pTempFile->cMappings == 0 || pTempFile->cSegs == 1);
    4292                         if (pTempFile->cSegs != 1)
    4293                         {
    4294                             KU32    iSeg;
    4295                             KU32    cbLeft;
    4296                             KU32    cbAll = pTempFile->cbFile ? (KU32)K_ALIGN_Z(pTempFile->cbFile, 0x2000) : 0x1000;
    4297                             KU8    *pbAll = NULL;
    4298                             int rc = kHlpPageAlloc((void **)&pbAll, cbAll, KPROT_READWRITE, K_FALSE);
    4299                             if (rc != 0)
    4300                             {
    4301                                 kHlpAssertFailed();
    4302                                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
    4303                                 return NULL;
    4304                             }
    4305 
    4306                             cbLeft = pTempFile->cbFile;
    4307                             for (iSeg = 0; iSeg < pTempFile->cSegs && cbLeft > 0; iSeg++)
    4308                             {
    4309                                 KU32 cbToCopy = K_MIN(cbLeft, pTempFile->paSegs[iSeg].cbDataAlloc);
    4310                                 kHlpMemCopy(&pbAll[pTempFile->paSegs[iSeg].offData], pTempFile->paSegs[iSeg].pbData, cbToCopy);
    4311                                 cbLeft -= cbToCopy;
    4312                             }
    4313 
    4314                             for (iSeg = 0; iSeg < pTempFile->cSegs; iSeg++)
    4315                             {
    4316                                 kHlpPageFree(pTempFile->paSegs[iSeg].pbData, pTempFile->paSegs[iSeg].cbDataAlloc);
    4317                                 pTempFile->paSegs[iSeg].pbData = NULL;
    4318                                 pTempFile->paSegs[iSeg].cbDataAlloc = 0;
    4319                             }
    4320 
    4321                             pTempFile->cSegs                 = 1;
    4322                             pTempFile->cbFileAllocated       = cbAll;
    4323                             pTempFile->paSegs[0].cbDataAlloc = cbAll;
    4324                             pTempFile->paSegs[0].pbData      = pbAll;
    4325                             pTempFile->paSegs[0].offData     = 0;
    4326                         }
    4327 
    4328                         pTempFile->cMappings++;
    4329                         kHlpAssert(pTempFile->cMappings == 1);
    4330 
    4331                         KWFS_LOG(("CreateFileMappingW(%p) -> %p [temp]\n", hSection, pTempFile->paSegs[0].pbData));
    4332                         return pTempFile->paSegs[0].pbData;
    4333                     }
    4334 
    4335                     kHlpAssertMsgFailed(("dwDesiredAccess=%#x offFile=%#x'%08x cbToMap=%#x (cbFile=%#x)\n",
    4336                                          dwDesiredAccess, offFileHigh, offFileLow, cbToMap, pTempFile->cbFile));
    4337                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
    4338                     return NULL;
    4339                 }
    4340             }
    4341         }
    4342     }
    4343 
    4344     KWFS_LOG(("MapViewOfFile(%p)\n", hSection));
    4345     return MapViewOfFile(hSection, dwDesiredAccess, offFileHigh, offFileLow, cbToMap);
    4346 }
    4347 /** @todo MapViewOfFileEx */
    4348 
    4349 
    4350 /** Kernel32 - UnmapViewOfFile  */
    4351 static BOOL WINAPI kwSandbox_Kernel32_UnmapViewOfFile(LPCVOID pvBase)
    4352 {
    4353     /* Is this one of our temporary mappings? */
    4354     PKWFSTEMPFILE pCur = g_Sandbox.pTempFileHead;
    4355     while (pCur)
    4356     {
    4357         if (   pCur->cMappings > 0
    4358             && pCur->paSegs[0].pbData == (KU8 *)pvBase)
    4359         {
    4360             pCur->cMappings--;
    4361             KWFS_LOG(("UnmapViewOfFile(%p) -> TRUE [temp]\n", pvBase));
    4362             return TRUE;
    4363         }
    4364         pCur = pCur->pNext;
    4365     }
    4366 
    4367     KWFS_LOG(("UnmapViewOfFile(%p)\n", pvBase));
    4368     return UnmapViewOfFile(pvBase);
    4369 }
    4370 
    4371 /** @todo UnmapViewOfFileEx */
    4372 
    4373 
    4374 #endif /* WITH_TEMP_MEMORY_FILES */
    4375 
    4376 /** Kernel32 - CloseHandle */
    4377 static BOOL WINAPI kwSandbox_Kernel32_CloseHandle(HANDLE hObject)
    4378 {
    4379     BOOL        fRet;
    4380     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(hObject);
    4381     if (   idxHandle < g_Sandbox.cHandles
    4382         && g_Sandbox.papHandles[idxHandle] != NULL)
    4383     {
    4384         fRet = CloseHandle(hObject);
    4385         if (fRet)
    4386         {
    4387             PKWHANDLE pHandle = g_Sandbox.papHandles[idxHandle];
    4388             g_Sandbox.papHandles[idxHandle] = NULL;
    4389             g_Sandbox.cActiveHandles--;
    4390 #ifdef WITH_TEMP_MEMORY_FILES
    4391             if (pHandle->enmType == KWHANDLETYPE_TEMP_FILE)
    4392             {
    4393                 kHlpAssert(pHandle->u.pTempFile->cActiveHandles > 0);
    4394                 pHandle->u.pTempFile->cActiveHandles--;
    4395             }
    4396 #endif
    4397             kHlpFree(pHandle);
    4398             KWFS_LOG(("CloseHandle(%p) -> TRUE [intercepted handle]\n", hObject));
    4399         }
    4400         else
    4401             KWFS_LOG(("CloseHandle(%p) -> FALSE [intercepted handle] err=%u!\n", hObject, GetLastError()));
    4402     }
    4403     else
    4404     {
    4405         KWFS_LOG(("CloseHandle(%p)\n", hObject));
    4406         fRet = CloseHandle(hObject);
    4407     }
    4408     return fRet;
    4409 }
    4410 
    4411 
    4412 /** Kernel32 - GetFileAttributesA. */
    4413 static DWORD WINAPI kwSandbox_Kernel32_GetFileAttributesA(LPCSTR pszFilename)
    4414 {
    4415     DWORD       fRet;
    4416     const char *pszExt = kHlpGetExt(pszFilename);
    4417     if (kwFsIsCachableExtensionA(pszExt, K_TRUE /*fAttrQuery*/))
    4418     {
    4419         PKWFSOBJ pFsObj = kwFsLookupA(pszFilename);
    4420         if (pFsObj)
    4421         {
    4422             if (pFsObj->fAttribs == INVALID_FILE_ATTRIBUTES)
    4423                 SetLastError(pFsObj->uLastError);
    4424             KWFS_LOG(("GetFileAttributesA(%s) -> %#x [cached]\n", pszFilename, pFsObj->fAttribs));
    4425             return pFsObj->fAttribs;
    4426         }
    4427     }
    4428 
    4429     fRet = GetFileAttributesA(pszFilename);
    4430     KWFS_LOG(("GetFileAttributesA(%s) -> %#x\n", pszFilename, fRet));
    4431     return fRet;
    4432 }
    4433 
    4434 
    4435 /** Kernel32 - GetFileAttributesW. */
    4436 static DWORD WINAPI kwSandbox_Kernel32_GetFileAttributesW(LPCWSTR pwszFilename)
    4437 {
    4438     DWORD fRet;
    4439     if (kwFsIsCachablePathExtensionW(pwszFilename, K_TRUE /*fAttrQuery*/))
    4440     {
    4441         /** @todo rewrite to pure UTF-16. */
    4442         char szTmp[2048];
    4443         KSIZE cch = kwUtf16ToStr(pwszFilename, szTmp, sizeof(szTmp));
    4444         if (cch < sizeof(szTmp))
    4445             return kwSandbox_Kernel32_GetFileAttributesA(szTmp);
    4446     }
    4447 
    4448     fRet = GetFileAttributesW(pwszFilename);
    4449     KWFS_LOG(("GetFileAttributesW(%ls) -> %#x\n", pwszFilename, fRet));
    4450     return fRet;
    4451 }
    4452 
    4453 
    4454 /** Kernel32 - GetShortPathNameW - cl1[xx].dll of VS2010 does this to the
    4455  * directory containing each include file.  We cache the result to speed
    4456  * things up a little. */
    4457 static DWORD WINAPI kwSandbox_Kernel32_GetShortPathNameW(LPCWSTR pwszLongPath, LPWSTR pwszShortPath, DWORD cwcShortPath)
    4458 {
    4459     DWORD cwcRet;
    4460     if (kwFsIsCachablePathExtensionW(pwszLongPath, K_TRUE /*fAttrQuery*/))
    4461     {
    4462         /** @todo proper implementation later, for now just copy it over as it. */
    4463         KSIZE cwcLongPath = kwUtf16Len(pwszLongPath);
    4464         cwcRet = kwUtf16CopyStyle1(pwszLongPath, pwszShortPath, cwcShortPath);
    4465         KWFS_LOG(("GetShortPathNameW(%ls) -> '%*.*ls' & %#x [cached]\n",
    4466                   pwszLongPath, K_MIN(cwcShortPath, cwcRet), K_MIN(cwcShortPath, cwcRet), pwszShortPath, cwcRet));
    4467     }
    4468     else
    4469     {
    4470         cwcRet = GetShortPathNameW(pwszLongPath, pwszShortPath, cwcShortPath);
    4471         KWFS_LOG(("GetShortPathNameW(%ls) -> '%*.*ls' & %#x\n",
    4472                   pwszLongPath, K_MIN(cwcShortPath, cwcRet), K_MIN(cwcShortPath, cwcRet), pwszShortPath, cwcRet));
    4473     }
    4474     return cwcRet;
    4475 }
    4476 
    4477 
    4478 
    4479 /**
    4480  * Functions that needs replacing for sandboxed execution.
    4481  */
    4482 KWREPLACEMENTFUNCTION const g_aSandboxReplacements[] =
    4483 {
    4484     /*
    4485      * Kernel32.dll and friends.
    4486      */
    4487     { TUPLE("ExitProcess"),                 NULL,       (KUPTR)kwSandbox_Kernel32_ExitProcess },
    4488     { TUPLE("TerminateProcess"),            NULL,       (KUPTR)kwSandbox_Kernel32_TerminateProcess },
    4489 
    4490     { TUPLE("LoadLibraryA"),                NULL,       (KUPTR)kwSandbox_Kernel32_LoadLibraryA },
    4491     { TUPLE("LoadLibraryW"),                NULL,       (KUPTR)kwSandbox_Kernel32_LoadLibraryW },
    4492     { TUPLE("LoadLibraryExA"),              NULL,       (KUPTR)kwSandbox_Kernel32_LoadLibraryExA },
    4493     { TUPLE("LoadLibraryExW"),              NULL,       (KUPTR)kwSandbox_Kernel32_LoadLibraryExW },
    4494     { TUPLE("FreeLibrary"),                 NULL,       (KUPTR)kwSandbox_Kernel32_FreeLibrary },
    4495     { TUPLE("GetModuleHandleA"),            NULL,       (KUPTR)kwSandbox_Kernel32_GetModuleHandleA },
    4496     { TUPLE("GetModuleHandleW"),            NULL,       (KUPTR)kwSandbox_Kernel32_GetModuleHandleW },
    4497     { TUPLE("GetProcAddress"),              NULL,       (KUPTR)kwSandbox_Kernel32_GetProcAddress },
    4498     { TUPLE("GetModuleFileNameA"),          NULL,       (KUPTR)kwSandbox_Kernel32_GetModuleFileNameA },
    4499     { TUPLE("GetModuleFileNameW"),          NULL,       (KUPTR)kwSandbox_Kernel32_GetModuleFileNameW },
    4500 
    4501     { TUPLE("GetCommandLineA"),             NULL,       (KUPTR)kwSandbox_Kernel32_GetCommandLineA },
    4502     { TUPLE("GetCommandLineW"),             NULL,       (KUPTR)kwSandbox_Kernel32_GetCommandLineW },
    4503     { TUPLE("GetStartupInfoA"),             NULL,       (KUPTR)kwSandbox_Kernel32_GetStartupInfoA },
    4504     { TUPLE("GetStartupInfoW"),             NULL,       (KUPTR)kwSandbox_Kernel32_GetStartupInfoW },
    4505 
    4506     { TUPLE("CreateThread"),                NULL,       (KUPTR)kwSandbox_Kernel32_CreateThread },
    4507 
    4508     { TUPLE("GetEnvironmentVariableA"),     NULL,       (KUPTR)kwSandbox_Kernel32_GetEnvironmentVariableA },
    4509     { TUPLE("GetEnvironmentVariableW"),     NULL,       (KUPTR)kwSandbox_Kernel32_GetEnvironmentVariableW },
    4510     { TUPLE("SetEnvironmentVariableA"),     NULL,       (KUPTR)kwSandbox_Kernel32_SetEnvironmentVariableA },
    4511     { TUPLE("SetEnvironmentVariableW"),     NULL,       (KUPTR)kwSandbox_Kernel32_SetEnvironmentVariableW },
    4512     { TUPLE("ExpandEnvironmentStringsA"),   NULL,       (KUPTR)kwSandbox_Kernel32_ExpandEnvironmentStringsA },
    4513     { TUPLE("ExpandEnvironmentStringsW"),   NULL,       (KUPTR)kwSandbox_Kernel32_ExpandEnvironmentStringsW },
    4514 
    4515     { TUPLE("CreateFileA"),                 NULL,       (KUPTR)kwSandbox_Kernel32_CreateFileA },
    4516     { TUPLE("CreateFileW"),                 NULL,       (KUPTR)kwSandbox_Kernel32_CreateFileW },
    4517     { TUPLE("ReadFile"),                    NULL,       (KUPTR)kwSandbox_Kernel32_ReadFile },
    4518     { TUPLE("ReadFileEx"),                  NULL,       (KUPTR)kwSandbox_Kernel32_ReadFileEx },
    4519 #ifdef WITH_TEMP_MEMORY_FILES
    4520     { TUPLE("WriteFile"),                   NULL,       (KUPTR)kwSandbox_Kernel32_WriteFile },
    4521     { TUPLE("WriteFileEx"),                 NULL,       (KUPTR)kwSandbox_Kernel32_WriteFileEx },
    4522     { TUPLE("SetEndOfFile"),                NULL,       (KUPTR)kwSandbox_Kernel32_SetEndOfFile },
    4523     { TUPLE("GetFileType"),                 NULL,       (KUPTR)kwSandbox_Kernel32_GetFileType },
    4524     { TUPLE("GetFileSize"),                 NULL,       (KUPTR)kwSandbox_Kernel32_GetFileSize },
    4525     { TUPLE("GetFileSizeEx"),               NULL,       (KUPTR)kwSandbox_Kernel32_GetFileSizeEx },
    4526     { TUPLE("CreateFileMappingW"),          NULL,       (KUPTR)kwSandbox_Kernel32_CreateFileMappingW },
    4527     { TUPLE("MapViewOfFile"),               NULL,       (KUPTR)kwSandbox_Kernel32_MapViewOfFile },
    4528     { TUPLE("UnmapViewOfFile"),             NULL,       (KUPTR)kwSandbox_Kernel32_UnmapViewOfFile },
    4529 #endif
    4530     { TUPLE("SetFilePointer"),              NULL,       (KUPTR)kwSandbox_Kernel32_SetFilePointer },
    4531     { TUPLE("SetFilePointerEx"),            NULL,       (KUPTR)kwSandbox_Kernel32_SetFilePointerEx },
    4532     { TUPLE("CloseHandle"),                 NULL,       (KUPTR)kwSandbox_Kernel32_CloseHandle },
    4533     { TUPLE("GetFileAttributesA"),          NULL,       (KUPTR)kwSandbox_Kernel32_GetFileAttributesA },
    4534     { TUPLE("GetFileAttributesW"),          NULL,       (KUPTR)kwSandbox_Kernel32_GetFileAttributesW },
    4535     { TUPLE("GetShortPathNameW"),           NULL,       (KUPTR)kwSandbox_Kernel32_GetShortPathNameW },
    4536 
    4537     /*
    4538      * MS Visual C++ CRTs.
    4539      */
    4540     { TUPLE("exit"),                        NULL,       (KUPTR)kwSandbox_msvcrt_exit },
    4541     { TUPLE("_exit"),                       NULL,       (KUPTR)kwSandbox_msvcrt__exit },
    4542     { TUPLE("_cexit"),                      NULL,       (KUPTR)kwSandbox_msvcrt__cexit },
    4543     { TUPLE("_c_exit"),                     NULL,       (KUPTR)kwSandbox_msvcrt__c_exit },
    4544     { TUPLE("_amsg_exit"),                  NULL,       (KUPTR)kwSandbox_msvcrt__amsg_exit },
    4545     { TUPLE("terminate"),                   NULL,       (KUPTR)kwSandbox_msvcrt_terminate },
    4546 
    4547     { TUPLE("_beginthread"),                NULL,       (KUPTR)kwSandbox_msvcrt__beginthread },
    4548     { TUPLE("_beginthreadex"),              NULL,       (KUPTR)kwSandbox_msvcrt__beginthreadex },
    4549 
    4550     { TUPLE("__argc"),                      NULL,       (KUPTR)&g_Sandbox.cArgs },
    4551     { TUPLE("__argv"),                      NULL,       (KUPTR)&g_Sandbox.papszArgs },
    4552     { TUPLE("__wargv"),                     NULL,       (KUPTR)&g_Sandbox.papwszArgs },
    4553     { TUPLE("__p___argc"),                  NULL,       (KUPTR)kwSandbox_msvcrt___p___argc },
    4554     { TUPLE("__p___argv"),                  NULL,       (KUPTR)kwSandbox_msvcrt___p___argv },
    4555     { TUPLE("__p___wargv"),                 NULL,       (KUPTR)kwSandbox_msvcrt___p___wargv },
    4556     { TUPLE("_acmdln"),                     NULL,       (KUPTR)&g_Sandbox.pszCmdLine },
    4557     { TUPLE("_wcmdln"),                     NULL,       (KUPTR)&g_Sandbox.pwszCmdLine },
    4558     { TUPLE("__p__acmdln"),                 NULL,       (KUPTR)kwSandbox_msvcrt___p__acmdln },
    4559     { TUPLE("__p__wcmdln"),                 NULL,       (KUPTR)kwSandbox_msvcrt___p__wcmdln },
    4560     { TUPLE("_pgmptr"),                     NULL,       (KUPTR)&g_Sandbox.pgmptr  },
    4561     { TUPLE("_wpgmptr"),                    NULL,       (KUPTR)&g_Sandbox.wpgmptr },
    4562     { TUPLE("_get_pgmptr"),                 NULL,       (KUPTR)kwSandbox_msvcrt__get_pgmptr },
    4563     { TUPLE("_get_wpgmptr"),                NULL,       (KUPTR)kwSandbox_msvcrt__get_wpgmptr },
    4564     { TUPLE("__p__pgmptr"),                 NULL,       (KUPTR)kwSandbox_msvcrt___p__pgmptr },
    4565     { TUPLE("__p__wpgmptr"),                NULL,       (KUPTR)kwSandbox_msvcrt___p__wpgmptr },
    4566     { TUPLE("_wincmdln"),                   NULL,       (KUPTR)kwSandbox_msvcrt__wincmdln },
    4567     { TUPLE("_wwincmdln"),                  NULL,       (KUPTR)kwSandbox_msvcrt__wwincmdln },
    4568     { TUPLE("__getmainargs"),               NULL,       (KUPTR)kwSandbox_msvcrt___getmainargs},
    4569     { TUPLE("__wgetmainargs"),              NULL,       (KUPTR)kwSandbox_msvcrt___wgetmainargs},
    4570 
    4571     { TUPLE("_putenv"),                     NULL,       (KUPTR)kwSandbox_msvcrt__putenv},
    4572     { TUPLE("_wputenv"),                    NULL,       (KUPTR)kwSandbox_msvcrt__wputenv},
    4573     { TUPLE("_putenv_s"),                   NULL,       (KUPTR)kwSandbox_msvcrt__putenv_s},
    4574     { TUPLE("_wputenv_s"),                  NULL,       (KUPTR)kwSandbox_msvcrt__wputenv_s},
    4575     { TUPLE("__initenv"),                   NULL,       (KUPTR)&g_Sandbox.initenv },
    4576     { TUPLE("__winitenv"),                  NULL,       (KUPTR)&g_Sandbox.winitenv },
    4577     { TUPLE("__p___initenv"),               NULL,       (KUPTR)kwSandbox_msvcrt___p___initenv},
    4578     { TUPLE("__p___winitenv"),              NULL,       (KUPTR)kwSandbox_msvcrt___p___winitenv},
    4579     { TUPLE("_environ"),                    NULL,       (KUPTR)&g_Sandbox.environ },
    4580     { TUPLE("_wenviron"),                   NULL,       (KUPTR)&g_Sandbox.wenviron },
    4581     { TUPLE("_get_environ"),                NULL,       (KUPTR)kwSandbox_msvcrt__get_environ },
    4582     { TUPLE("_get_wenviron"),               NULL,       (KUPTR)kwSandbox_msvcrt__get_wenviron },
    4583     { TUPLE("__p__environ"),                NULL,       (KUPTR)kwSandbox_msvcrt___p__environ },
    4584     { TUPLE("__p__wenviron"),               NULL,       (KUPTR)kwSandbox_msvcrt___p__wenviron },
    4585 };
    4586 /** Number of entries in g_aReplacements. */
    4587 KU32 const                  g_cSandboxReplacements = K_ELEMENTS(g_aSandboxReplacements);
    4588 
    4589 
    4590 /**
    4591  * Functions that needs replacing in natively loaded DLLs when doing sandboxed
    4592  * execution.
    4593  */
    4594 KWREPLACEMENTFUNCTION const g_aSandboxNativeReplacements[] =
    4595 {
    4596     /*
    4597      * Kernel32.dll and friends.
    4598      */
    4599     { TUPLE("ExitProcess"),                 NULL,       (KUPTR)kwSandbox_Kernel32_ExitProcess },
    4600     { TUPLE("TerminateProcess"),            NULL,       (KUPTR)kwSandbox_Kernel32_TerminateProcess },
    4601 
    4602 #if 0
    4603     { TUPLE("CreateThread"),                NULL,       (KUPTR)kwSandbox_Kernel32_CreateThread },
    4604 #endif
    4605 
    4606     { TUPLE("CreateFileA"),                 NULL,       (KUPTR)kwSandbox_Kernel32_CreateFileA },
    4607     { TUPLE("CreateFileW"),                 NULL,       (KUPTR)kwSandbox_Kernel32_CreateFileW },
    4608     { TUPLE("ReadFile"),                    NULL,       (KUPTR)kwSandbox_Kernel32_ReadFile },
    4609     { TUPLE("ReadFileEx"),                  NULL,       (KUPTR)kwSandbox_Kernel32_ReadFileEx },
    4610 #ifdef WITH_TEMP_MEMORY_FILES
    4611     { TUPLE("WriteFile"),                   NULL,       (KUPTR)kwSandbox_Kernel32_WriteFile },
    4612     { TUPLE("WriteFileEx"),                 NULL,       (KUPTR)kwSandbox_Kernel32_WriteFileEx },
    4613     { TUPLE("SetEndOfFile"),                NULL,       (KUPTR)kwSandbox_Kernel32_SetEndOfFile },
    4614     { TUPLE("GetFileType"),                 NULL,       (KUPTR)kwSandbox_Kernel32_GetFileType },
    4615     { TUPLE("GetFileSize"),                 NULL,       (KUPTR)kwSandbox_Kernel32_GetFileSize },
    4616     { TUPLE("GetFileSizeEx"),               NULL,       (KUPTR)kwSandbox_Kernel32_GetFileSizeEx },
    4617     { TUPLE("CreateFileMappingW"),          NULL,       (KUPTR)kwSandbox_Kernel32_CreateFileMappingW },
    4618     { TUPLE("MapViewOfFile"),               NULL,       (KUPTR)kwSandbox_Kernel32_MapViewOfFile },
    4619     { TUPLE("UnmapViewOfFile"),             NULL,       (KUPTR)kwSandbox_Kernel32_UnmapViewOfFile },
    4620 #endif
    4621     { TUPLE("SetFilePointer"),              NULL,       (KUPTR)kwSandbox_Kernel32_SetFilePointer },
    4622     { TUPLE("SetFilePointerEx"),            NULL,       (KUPTR)kwSandbox_Kernel32_SetFilePointerEx },
    4623     { TUPLE("CloseHandle"),                 NULL,       (KUPTR)kwSandbox_Kernel32_CloseHandle },
    4624     { TUPLE("GetFileAttributesA"),          NULL,       (KUPTR)kwSandbox_Kernel32_GetFileAttributesA },
    4625     { TUPLE("GetFileAttributesW"),          NULL,       (KUPTR)kwSandbox_Kernel32_GetFileAttributesW },
    4626     { TUPLE("GetShortPathNameW"),           NULL,       (KUPTR)kwSandbox_Kernel32_GetShortPathNameW },
    4627 
    4628     /*
    4629      * MS Visual C++ CRTs.
    4630      */
    4631     { TUPLE("exit"),                        NULL,       (KUPTR)kwSandbox_msvcrt_exit },
    4632     { TUPLE("_exit"),                       NULL,       (KUPTR)kwSandbox_msvcrt__exit },
    4633     { TUPLE("_cexit"),                      NULL,       (KUPTR)kwSandbox_msvcrt__cexit },
    4634     { TUPLE("_c_exit"),                     NULL,       (KUPTR)kwSandbox_msvcrt__c_exit },
    4635     { TUPLE("_amsg_exit"),                  NULL,       (KUPTR)kwSandbox_msvcrt__amsg_exit },
    4636     { TUPLE("terminate"),                   NULL,       (KUPTR)kwSandbox_msvcrt_terminate },
    4637 
    4638 #if 0 /* used by mspdbXXX.dll */
    4639     { TUPLE("_beginthread"),                NULL,       (KUPTR)kwSandbox_msvcrt__beginthread },
    4640     { TUPLE("_beginthreadex"),              NULL,       (KUPTR)kwSandbox_msvcrt__beginthreadex },
    4641 #endif
    4642 };
    4643 /** Number of entries in g_aSandboxNativeReplacements. */
    4644 KU32 const                  g_cSandboxNativeReplacements = K_ELEMENTS(g_aSandboxNativeReplacements);
    4645 
    4646 
    4647 /**
    4648  * Used by kwSandboxExec to reset the state of the module tree.
    4649  *
    4650  * This is done recursively.
    4651  *
    4652  * @param   pMod                The root of the tree to consider.
    4653  */
    4654 static void kwSandboxResetModuleState(PKWMODULE pMod)
    4655 {
    4656     if (   !pMod->fNative
    4657         && pMod->u.Manual.enmState != KWMODSTATE_NEEDS_BITS)
    4658     {
    4659         KSIZE iImp;
    4660         pMod->u.Manual.enmState = KWMODSTATE_NEEDS_BITS;
    4661         iImp = pMod->u.Manual.cImpMods;
    4662         while (iImp-- > 0)
    4663             kwSandboxResetModuleState(pMod->u.Manual.apImpMods[iImp]);
    4664     }
    4665 }
    4666 
    4667 static PPEB kwSandboxGetProcessEnvironmentBlock(void)
    4668 {
    4669 #if K_ARCH == K_ARCH_X86_32
    4670     return (PPEB)__readfsdword(0x030 /* offset of ProcessEnvironmentBlock in TEB */);
    4671 #elif K_ARCH == K_ARCH_AMD64
    4672     return (PPEB)__readgsqword(0x060 /* offset of ProcessEnvironmentBlock in TEB */);
    4673 #else
    4674 # error "Port me!"
    4675 #endif
    4676 }
    4677 
    4678 
    4679 /**
    4680  * Enters the given handle into the handle table.
    4681  *
    4682  * @returns K_TRUE on success, K_FALSE on failure.
    4683  * @param   pSandbox            The sandbox.
    4684  * @param   pHandle             The handle.
    4685  */
    4686 static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle)
    4687 {
    4688     KUPTR const idxHandle = KW_HANDLE_TO_INDEX(pHandle->hHandle);
    4689     kHlpAssertReturn(idxHandle < KW_HANDLE_MAX, K_FALSE);
    4690 
    4691     /*
    4692      * Grow handle table.
    4693      */
    4694     if (idxHandle >= pSandbox->cHandles)
    4695     {
    4696         void *pvNew;
    4697         KU32  cHandles = pSandbox->cHandles ? pSandbox->cHandles * 2 : 32;
    4698         while (cHandles <= idxHandle)
    4699             cHandles *= 2;
    4700         pvNew = kHlpRealloc(pSandbox->papHandles, cHandles * sizeof(pSandbox->papHandles[0]));
    4701         if (!pvNew)
    4702         {
    4703             KW_LOG(("Out of memory growing handle table to %u handles\n", cHandles));
    4704             return K_FALSE;
    4705         }
    4706         pSandbox->papHandles = (PKWHANDLE *)pvNew;
    4707         kHlpMemSet(&pSandbox->papHandles[pSandbox->cHandles], 0,
    4708                    (cHandles - pSandbox->cHandles) * sizeof(pSandbox->papHandles[0]));
    4709         pSandbox->cHandles = cHandles;
    4710     }
    4711 
    4712     /*
    4713      * Check that the entry is unused then insert it.
    4714      */
    4715     kHlpAssertReturn(pSandbox->papHandles[idxHandle] == NULL, K_FALSE);
    4716     pSandbox->papHandles[idxHandle] = pHandle;
    4717     pSandbox->cActiveHandles++;
    4718     return K_TRUE;
    4719 }
    4720 
    4721 
    4722 
    4723 static int kwSandboxInit(PKWSANDBOX pSandbox, PKWTOOL pTool,
    4724                          KU32 cArgs, const char **papszArgs, KU32 cbArgs,
    4725                          KU32 cEnvVars, const char **papszEnvVars)
    4726 {
    4727     PPEB pPeb = kwSandboxGetProcessEnvironmentBlock();
    4728     char *psz;
    4729     wchar_t *pwcPool;
    4730     KSIZE cbStrings;
    4731     KSIZE cwc;
    4732     KU32 i;
    4733 
    4734     /* Simple stuff. */
    4735     g_Sandbox.rcExitCode    = 256;
    4736     g_Sandbox.pTool         = pTool;
    4737     g_Sandbox.idMainThread  = GetCurrentThreadId();
    4738     g_Sandbox.TibMainThread = *(PNT_TIB)NtCurrentTeb();
    4739     g_Sandbox.pgmptr        = (char *)pTool->pszPath;
    4740     g_Sandbox.wpgmptr       = (wchar_t *)pTool->pwszPath;
    4741     g_Sandbox.cArgs         = cArgs;
    4742     g_Sandbox.papszArgs     = (char **)papszArgs;
    4743 
    4744     /*
    4745      * Create a command line from the given argv.
    4746      * ASSUME that it's correctly quoted by quote_argv.c already.
    4747      */
    4748     pSandbox->pszCmdLine = psz = (char *)kHlpAlloc(cbArgs + 1);
    4749     if (!psz)
    4750         return KERR_NO_MEMORY;
    4751     psz = kHlpStrPCopy(psz, papszArgs[0]);
    4752     for (i = 1; i < cArgs; i++)
    4753     {
    4754         *psz++ = ' ';
    4755         psz = kHlpStrPCopy(psz, papszArgs[i]);
    4756     }
    4757     kHlpAssert((KSIZE)(&psz[1] - pSandbox->pszCmdLine) == cbArgs);
    4758     psz[0] = '\0';
    4759     psz[1] = '\0';
    4760 
    4761     /*
    4762      * Convert command line and argv to UTF-16.
    4763      * We assume each ANSI char requires a surrogate pair in the UTF-16 variant.
    4764      */
    4765     pSandbox->papwszArgs = (wchar_t **)kHlpAlloc(sizeof(wchar_t *) * (pSandbox->cArgs + 2) + cbArgs * 2 * sizeof(wchar_t));
    4766     if (!pSandbox->papwszArgs)
    4767         return KERR_NO_MEMORY;
    4768     pwcPool = (wchar_t *)&pSandbox->papwszArgs[pSandbox->cArgs + 2];
    4769     for (i = 0; i < cArgs; i++)
    4770     {
    4771         *pwcPool++ = pSandbox->papszArgs[i][-1]; /* flags */
    4772         pSandbox->papwszArgs[i] = pwcPool;
    4773         pwcPool += kwStrToUtf16(pSandbox->papszArgs[i], pwcPool, (strlen(pSandbox->papszArgs[i]) + 1) * 2);
    4774         pwcPool++;
    4775     }
    4776     pSandbox->papwszArgs[pSandbox->cArgs + 0] = NULL;
    4777     pSandbox->papwszArgs[pSandbox->cArgs + 1] = NULL;
    4778 
    4779     /*
    4780      * Convert the commandline string to UTF-16, same pessimistic approach as above.
    4781      */
    4782     cbStrings = (cbArgs + 1) * 2 * sizeof(wchar_t);
    4783     pSandbox->pwszCmdLine = kHlpAlloc(cbStrings);
    4784     if (!pSandbox->pwszCmdLine)
    4785         return KERR_NO_MEMORY;
    4786     cwc = kwStrToUtf16(pSandbox->pszCmdLine, pSandbox->pwszCmdLine, cbStrings / sizeof(wchar_t));
    4787 
    4788     pSandbox->SavedCommandLine = pPeb->ProcessParameters->CommandLine;
    4789     pPeb->ProcessParameters->CommandLine.Buffer = pSandbox->pwszCmdLine;
    4790     pPeb->ProcessParameters->CommandLine.Length = (USHORT)cwc * sizeof(wchar_t);
    4791 
    4792 
    4793     g_uFsCacheGeneration++;
    4794     if (g_uFsCacheGeneration == KFSWOBJ_CACHE_GEN_IGNORE)
    4795         g_uFsCacheGeneration++;
    4796     return 0;
    4797 }
    4798 
    4799 
    4800 static void kwSandboxCleanup(PKWSANDBOX pSandbox)
    4801 {
    4802 #ifdef WITH_TEMP_MEMORY_FILES
    4803     PKWFSTEMPFILE pTempFile;
    4804 #endif
    4805     PPEB pPeb = kwSandboxGetProcessEnvironmentBlock();
    4806     pPeb->ProcessParameters->CommandLine = pSandbox->SavedCommandLine;
    4807     /** @todo lots more to do here!   */
    4808 
    4809 #ifdef WITH_TEMP_MEMORY_FILES
    4810     pTempFile = pSandbox->pTempFileHead;
    4811     pSandbox->pTempFileHead = NULL;
    4812     while (pTempFile)
    4813     {
    4814         PKWFSTEMPFILE pNext = pTempFile->pNext;
    4815         KU32          iSeg  = pTempFile->cSegs;
    4816         while (iSeg-- > 0)
    4817             kHlpPageFree(pTempFile->paSegs[iSeg].pbData, pTempFile->paSegs[iSeg].cbDataAlloc);
    4818         kHlpFree(pTempFile->paSegs);
    4819         pTempFile->pNext = NULL;
    4820         kHlpFree(pTempFile);
    4821 
    4822         pTempFile = pNext;
    4823     }
    4824 #endif
    4825 
    4826 }
    4827 
    4828 
    4829 static int kwSandboxExec(PKWTOOL pTool, KU32 cArgs, const char **papszArgs, KU32 cbArgs,
    4830                          KU32 cEnvVars, const char **papszEnvVars)
    4831 {
    4832     int rcExit = 42;
    4833     int rc;
    4834 
    4835     /*
    4836      * Initialize the sandbox environment.
    4837      */
    4838     rc = kwSandboxInit(&g_Sandbox, pTool, cArgs, papszArgs, cbArgs, cEnvVars, papszEnvVars);
    4839     if (rc == 0)
    4840     {
    4841         /*
    4842          * Do module initialization.
    4843          */
    4844         kwSandboxResetModuleState(pTool->u.Sandboxed.pExe);
    4845         rc = kwLdrModuleInitTree(pTool->u.Sandboxed.pExe);
    4846         if (rc == 0)
    4847         {
    4848             /*
    4849              * Call the main function.
    4850              */
    4851             KUPTR uAddrMain;
    4852             rc = kwLdrModuleQueryMainEntrypoint(pTool->u.Sandboxed.pExe, &uAddrMain);
    4853             if (rc == 0)
    4854             {
    4855                 int (*pfnWin64Entrypoint)(void *pvPeb, void *, void *, void *);
    4856                 *(KUPTR *)&pfnWin64Entrypoint = uAddrMain;
    4857 
    4858                 __try
    4859                 {
    4860                     if (setjmp(g_Sandbox.JmpBuf) == 0)
    4861                     {
    4862 #if K_ARCH == K_ARCH_AMD64
    4863                         *(KU64*)(g_Sandbox.JmpBuf) = 0; /** @todo find other way to prevent longjmp from doing unwind! */
    4864 #else
    4865 # error "Port me!"
    4866 #endif
    4867                         rcExit = pfnWin64Entrypoint(kwSandboxGetProcessEnvironmentBlock(), NULL, NULL, NULL);
    4868                     }
    4869                     else
    4870                         rcExit = g_Sandbox.rcExitCode;
    4871                 }
    4872                 __except (EXCEPTION_EXECUTE_HANDLER)
    4873                 {
    4874                     rcExit = 512;
    4875                 }
    4876 
    4877                 /*
    4878                  * Restore the TIB and later some other stuff.
    4879                  */
    4880                 *(PNT_TIB)NtCurrentTeb() = g_Sandbox.TibMainThread;
    4881             }
    4882             else
    4883                 rcExit = 42 + 5;
    4884         }
    4885         else
    4886             rcExit = 42 + 4;
    4887 
    4888         kwSandboxCleanup(&g_Sandbox);
    4889     }
    4890     else
    4891         rcExit = 42 + 3;
    4892 
    4893     return rcExit;
    4894 }
    4895 
    4896 
    4897 #if 0
    4898 static int kwExecCmdLine(const char *pszExe, const char *pszCmdLine)
    4899 {
    4900     int rc;
    4901     PKWTOOL pTool = kwToolLookup(pszExe);
    4902     if (pTool)
    4903     {
    4904         int rc;
    4905         int rcExitCode;
    4906         switch (pTool->enmType)
    4907         {
    4908             case KWTOOLTYPE_SANDBOXED:
    4909                 KW_LOG(("Sandboxing tool %s\n", pTool->pszPath));
    4910                 rc = kwSandboxExec(pTool, pszCmdLine, &rcExitCode);
    4911                 break;
    4912 
    4913             case KWTOOLTYPE_WATCOM:
    4914                 KW_LOG(("TODO: Watcom style tool %s\n", pTool->pszPath));
    4915                 rc = rcExitCode = 2;
    4916                 break;
    4917 
    4918             case KWTOOLTYPE_EXEC:
    4919                 KW_LOG(("TODO: Direct exec tool %s\n", pTool->pszPath));
    4920                 rc = rcExitCode = 2;
    4921                 break;
    4922 
    4923             default:
    4924                 kHlpAssertFailed();
    4925                 rc = rcExitCode = 2;
    4926                 break;
    4927         }
    4928         KW_LOG(("rcExitCode=%d (rc=%d)\n", rcExitCode, rc));
    4929     }
    4930     else
    4931         rc = 1;
    4932     return rc;
    4933 }
    4934 #endif
    4935 
    4936 
    4937 /**
    4938  * Part 2 of the "JOB" command handler.
    4939  *
    4940  * @returns The exit code of the job.
    4941  * @param   pszExecutable   The executable to execute.
    4942  * @param   pszCwd          The current working directory of the job.
    4943  * @param   cArgs           The number of arguments.
    4944  * @param   papszArgs       The argument vector.
    4945  * @param   cbArgs          The size of the argument strings and terminators.
    4946  * @param   cEnvVars        The number of environment variables.
    4947  * @param   papszEnvVars    The enviornment vector.
    4948  */
    4949 static int kSubmitHandleJobUnpacked(const char *pszExecutable, const char *pszCwd,
    4950                                     KU32 cArgs, const char **papszArgs, KU32 cbArgs,
    4951                                     KU32 cEnvVars, const char **papszEnvVars)
    4952 {
    4953     int rcExit;
    4954     PKWTOOL pTool;
    4955 
    4956     /*
    4957      * Lookup the tool.
    4958      */
    4959     pTool = kwToolLookup(pszExecutable);
    4960     if (pTool)
    4961     {
    4962         /*
    4963          * Change the directory if we're going to execute the job inside
    4964          * this process.  Then invoke the tool type specific handler.
    4965          */
    4966         switch (pTool->enmType)
    4967         {
    4968             case KWTOOLTYPE_SANDBOXED:
    4969             case KWTOOLTYPE_WATCOM:
    4970                 /** @todo cache this   */
    4971                 if (SetCurrentDirectoryA(pszCwd))
    4972                 {
    4973                     if (pTool->enmType == KWTOOLTYPE_SANDBOXED)
    4974                     {
    4975                         KW_LOG(("Sandboxing tool %s\n", pTool->pszPath));
    4976                         rcExit = kwSandboxExec(pTool, cArgs, papszArgs, cbArgs, cEnvVars, papszEnvVars);
    4977                     }
    4978                     else
    4979                     {
    4980                         kwErrPrintf("TODO: Watcom style tool %s\n", pTool->pszPath);
    4981                         rcExit = 42 + 2;
    4982                     }
    4983                 }
    4984                 else
    4985                 {
    4986                     kwErrPrintf("SetCurrentDirectory failed with %u on '%s'\n", GetLastError(), pszCwd);
    4987                     rcExit = 42 + 1;
    4988                 }
    4989                 break;
    4990 
    4991             case KWTOOLTYPE_EXEC:
    4992                 kwErrPrintf("TODO: Direct exec tool %s\n", pTool->pszPath);
    4993                 rcExit = 42 + 2;
    4994                 break;
    4995 
    4996             default:
    4997                 kHlpAssertFailed();
    4998                 kwErrPrintf("Internal tool type corruption!!\n");
    4999                 rcExit = 42 + 2;
    5000                 g_fRestart = K_TRUE;
    5001                 break;
    5002         }
    5003     }
    5004     else
    5005         rcExit = 42 + 1;
    5006     return rcExit;
    5007 }
    5008 
    5009 
    5010 /**
    5011  * Handles a "JOB" command.
    5012  *
    5013  * @returns The exit code of the job.
    5014  * @param   pszMsg              Points to the "JOB" command part of the message.
    5015  * @param   cbMsg               Number of message bytes at @a pszMsg.  There are
    5016  *                              4 more zero bytes after the message body to
    5017  *                              simplify parsing.
    5018  */
    5019 static int kSubmitHandleJob(const char *pszMsg, KSIZE cbMsg)
    5020 {
    5021     int rcExit = 42;
    5022 
    5023     /*
    5024      * Unpack the message.
    5025      */
    5026     const char     *pszExecutable;
    5027     size_t          cbTmp;
    5028 
    5029     pszMsg += sizeof("JOB");
    5030     cbMsg  -= sizeof("JOB");
    5031 
    5032     /* Executable name. */
    5033     pszExecutable = pszMsg;
    5034     cbTmp = strlen(pszMsg) + 1;
    5035     pszMsg += cbTmp;
    5036     if (   cbTmp < cbMsg
    5037         && cbTmp > 2)
    5038     {
    5039         const char *pszCwd;
    5040         cbMsg -= cbTmp;
    5041 
    5042         /* Current working directory. */
    5043         pszCwd = pszMsg;
    5044         cbTmp = strlen(pszMsg) + 1;
    5045         pszMsg += cbTmp;
    5046         if (   cbTmp + sizeof(KU32) < cbMsg
    5047             && cbTmp >= 2)
    5048         {
    5049             KU32    cArgs;
    5050             cbMsg  -= cbTmp;
    5051 
    5052             /* Argument count. */
    5053             kHlpMemCopy(&cArgs, pszMsg, sizeof(cArgs));
    5054             pszMsg += sizeof(cArgs);
    5055             cbMsg  -= sizeof(cArgs);
    5056 
    5057             if (cArgs > 0 && cArgs < 4096)
    5058             {
    5059                 /* The argument vector. */
    5060                 char const **papszArgs = kHlpAlloc((cArgs + 1) * sizeof(papszArgs[0]));
    5061                 if (papszArgs)
    5062                 {
    5063                     KU32 cbArgs;
    5064                     KU32 i;
    5065                     for (i = 0; i < cArgs; i++)
    5066                     {
    5067                         papszArgs[i] = pszMsg + 1; /* First byte is expansion flags for MSC & EMX. */
    5068                         cbTmp = 1 + strlen(pszMsg + 1) + 1;
    5069                         pszMsg += cbTmp;
    5070                         if (cbTmp < cbMsg)
    5071                             cbMsg -= cbTmp;
    5072                         else
    5073                         {
    5074                             cbMsg = 0;
    5075                             break;
    5076                         }
    5077 
    5078                     }
    5079                     papszArgs[cArgs] = 0;
    5080                     cbArgs = (KU32)(pszMsg - papszArgs[0]) - cArgs + 1;
    5081 
    5082                     /* Environment variable count. */
    5083                     if (sizeof(KU32) < cbMsg)
    5084                     {
    5085                         KU32    cEnvVars;
    5086                         kHlpMemCopy(&cEnvVars, pszMsg, sizeof(cEnvVars));
    5087                         pszMsg += sizeof(cEnvVars);
    5088                         cbMsg  -= sizeof(cEnvVars);
    5089 
    5090                         if (cEnvVars >= 0 && cEnvVars < 4096)
    5091                         {
    5092                             /* The argument vector. */
    5093                             char const **papszEnvVars = kHlpAlloc((cEnvVars + 1) * sizeof(papszEnvVars[0]));
    5094                             if (papszEnvVars)
    5095                             {
    5096                                 KU32 i;
    5097                                 for (i = 0; i < cEnvVars; i++)
    5098                                 {
    5099                                     papszEnvVars[i] = pszMsg;
    5100                                     cbTmp = strlen(pszMsg) + 1;
    5101                                     pszMsg += cbTmp;
    5102                                     if (cbTmp < cbMsg)
    5103                                         cbMsg -= cbTmp;
    5104                                     else
    5105                                     {
    5106                                         if (   cbTmp == cbMsg
    5107                                             && i + 1 == cEnvVars)
    5108                                             cbMsg = 0;
    5109                                         else
    5110                                             cbMsg = KSIZE_MAX;
    5111                                         break;
    5112                                     }
    5113                                 }
    5114                                 papszEnvVars[cEnvVars] = 0;
    5115                                 if (cbMsg != KSIZE_MAX)
    5116                                 {
    5117                                     if (cbMsg == 0)
    5118                                     {
    5119                                         /*
    5120                                          * The next step.
    5121                                          */
    5122                                         rcExit = kSubmitHandleJobUnpacked(pszExecutable, pszCwd,
    5123                                                                           cArgs, papszArgs, cbArgs,
    5124                                                                           cEnvVars, papszEnvVars);
    5125                                     }
    5126                                     else
    5127                                         kwErrPrintf("Message has %u bytes unknown trailing bytes\n", cbMsg);
    5128                                 }
    5129                                 else
    5130                                     kwErrPrintf("Detected bogus message unpacking environment variables!\n");
    5131                                 kHlpFree((void *)papszEnvVars);
    5132                             }
    5133                             else
    5134                                 kwErrPrintf("Error allocating papszEnvVars for %u variables\n", cEnvVars);
    5135                         }
    5136                         else
    5137                             kwErrPrintf("Bogus environment variable count: %u (%#x)\n", cEnvVars, cEnvVars);
    5138                     }
    5139                     else
    5140                         kwErrPrintf("Detected bogus message unpacking arguments and environment variable count!\n");
    5141                     kHlpFree((void *)papszArgs);
    5142                 }
    5143                 else
    5144                     kwErrPrintf("Error allocating argv for %u arguments\n", cArgs);
    5145             }
    5146             else
    5147                 kwErrPrintf("Bogus argument count: %u (%#x)\n", cArgs, cArgs);
    5148         }
    5149         else
    5150             kwErrPrintf("Detected bogus message unpacking CWD path and argument count!\n");
    5151     }
    5152     else
    5153         kwErrPrintf("Detected bogus message unpacking executable path!\n");
    5154     return rcExit;
    5155 }
    5156 
    5157 
    5158 /**
    5159  * Wrapper around WriteFile / write that writes the whole @a cbToWrite.
    5160  *
    5161  * @retval  0 on success.
    5162  * @retval  -1 on error (fully bitched).
    5163  *
    5164  * @param   hPipe               The pipe handle.
    5165  * @param   pvBuf               The buffer to write out out.
    5166  * @param   cbToWrite           The number of bytes to write.
    5167  */
    5168 static int kSubmitWriteIt(HANDLE hPipe, const void *pvBuf, KU32 cbToWrite)
    5169 {
    5170     KU8 const  *pbBuf  = (KU8 const *)pvBuf;
    5171     KU32        cbLeft = cbToWrite;
    5172     for (;;)
    5173     {
    5174         DWORD cbActuallyWritten = 0;
    5175         if (WriteFile(hPipe, pbBuf, cbLeft, &cbActuallyWritten, NULL /*pOverlapped*/))
    5176         {
    5177             cbLeft -= cbActuallyWritten;
    5178             if (!cbLeft)
    5179                 return 0;
    5180             pbBuf  += cbActuallyWritten;
    5181         }
    5182         else
    5183         {
    5184             DWORD dwErr = GetLastError();
    5185             if (cbLeft == cbToWrite)
    5186                 kwErrPrintf("WriteFile failed: %u\n", dwErr);
    5187             else
    5188                 kwErrPrintf("WriteFile failed %u byte(s) in: %u\n", cbToWrite - cbLeft, dwErr);
    5189             return -1;
    5190         }
    5191     }
    5192 }
    5193 
    5194 
    5195 /**
    5196  * Wrapper around ReadFile / read that reads the whole @a cbToRead.
    5197  *
    5198  * @retval  0 on success.
    5199  * @retval  1 on shut down (fShutdownOkay must be K_TRUE).
    5200  * @retval  -1 on error (fully bitched).
    5201  * @param   hPipe               The pipe handle.
    5202  * @param   pvBuf               The buffer to read into.
    5203  * @param   cbToRead            The number of bytes to read.
    5204  * @param   fShutdownOkay       Whether connection shutdown while reading the
    5205  *                              first byte is okay or not.
    5206  */
    5207 static int kSubmitReadIt(HANDLE hPipe, void *pvBuf, KU32 cbToRead, KBOOL fMayShutdown)
    5208 {
    5209     KU8 *pbBuf  = (KU8 *)pvBuf;
    5210     KU32 cbLeft = cbToRead;
    5211     for (;;)
    5212     {
    5213         DWORD cbActuallyRead = 0;
    5214         if (ReadFile(hPipe, pbBuf, cbLeft, &cbActuallyRead, NULL /*pOverlapped*/))
    5215         {
    5216             cbLeft -= cbActuallyRead;
    5217             if (!cbLeft)
    5218                 return 0;
    5219             pbBuf  += cbActuallyRead;
    5220         }
    5221         else
    5222         {
    5223             DWORD dwErr = GetLastError();
    5224             if (cbLeft == cbToRead)
    5225             {
    5226                 if (   fMayShutdown
    5227                     && dwErr == ERROR_BROKEN_PIPE)
    5228                     return 1;
    5229                 kwErrPrintf("ReadFile failed: %u\n", dwErr);
    5230             }
    5231             else
    5232                 kwErrPrintf("ReadFile failed %u byte(s) in: %u\n", cbToRead - cbLeft, dwErr);
    5233             return -1;
    5234         }
    5235     }
    5236 }
    5237 
    5238 
    5239 int main(int argc, char **argv)
    5240 {
    5241 #if 1
    5242     KSIZE   cbMsgBuf = 0;
    5243     KU8    *pbMsgBuf = NULL;
    5244     int     i;
    5245     HANDLE  hPipe = INVALID_HANDLE_VALUE;
    5246 
    5247 
    5248     /*
    5249      * Parse arguments.
    5250      */
    5251     for (i = 1; i < argc; i++)
    5252     {
    5253         if (strcmp(argv[i], "--pipe") == 0)
    5254         {
    5255             i++;
    5256             if (i < argc)
    5257             {
    5258                 char *pszEnd = NULL;
    5259                 unsigned __int64 u64Value = _strtoui64(argv[i], &pszEnd, 16);
    5260                 if (   *argv[i]
    5261                     && pszEnd != NULL
    5262                     && *pszEnd == '\0'
    5263                     && u64Value != 0
    5264                     && u64Value != (uintptr_t)INVALID_HANDLE_VALUE
    5265                     && (uintptr_t)u64Value == u64Value)
    5266                     hPipe = (HANDLE)(uintptr_t)u64Value;
    5267                 else
    5268                 {
    5269                     kwErrPrintf("Invalid --pipe argument: %s\n", argv[i]);
    5270                     return 2;
    5271                 }
    5272             }
    5273             else
    5274             {
    5275                 kwErrPrintf("--pipe takes an argument!\n");
    5276                 return 2;
    5277             }
    5278         }
    5279         else if (   strcmp(argv[i], "--help") == 0
    5280                  || strcmp(argv[i], "-h") == 0
    5281                  || strcmp(argv[i], "-?") == 0)
    5282         {
    5283             printf("usage: kWorker --pipe <pipe-handle>\n"
    5284                    "usage: kWorker <--help|-h>\n"
    5285                    "usage: kWorker <--version|-V>\n"
    5286                    "\n"
    5287                    "This is an internal kmk program that is used via the builtin_kSubmit.\n");
    5288             return 0;
    5289         }
    5290         else if (   strcmp(argv[i], "--version") == 0
    5291                  || strcmp(argv[i], "-V") == 0)
    5292             return kbuild_version(argv[0]);
    5293         else
    5294         {
    5295             kwErrPrintf("Unknown argument '%s'\n", argv[i]);
    5296             return 2;
    5297         }
    5298     }
    5299 
    5300     if (hPipe == INVALID_HANDLE_VALUE)
    5301     {
    5302         kwErrPrintf("Missing --pipe <pipe-handle> argument!\n");
    5303         return 2;
    5304     }
    5305 
    5306     /*
    5307      * Serve the pipe.
    5308      */
    5309     for (;;)
    5310     {
    5311         KU32 cbMsg = 0;
    5312         int rc = kSubmitReadIt(hPipe, &cbMsg, sizeof(cbMsg), K_TRUE /*fShutdownOkay*/);
    5313         if (rc == 0)
    5314         {
    5315             /* Make sure the message length is within sane bounds.  */
    5316             if (   cbMsg > 4
    5317                 && cbMsg <= 256*1024*1024)
    5318             {
    5319                 /* Reallocate the message buffer if necessary.  We add 4 zero bytes.  */
    5320                 if (cbMsg + 4 <= cbMsgBuf)
    5321                 { /* likely */ }
    5322                 else
    5323                 {
    5324                     cbMsgBuf = K_ALIGN_Z(cbMsg + 4, 2048);
    5325                     pbMsgBuf = kHlpRealloc(pbMsgBuf, cbMsgBuf);
    5326                     if (!pbMsgBuf)
    5327                     {
    5328                         kwErrPrintf("Failed to allocate %u bytes for a message buffer!\n", cbMsgBuf);
    5329                         return 1;
    5330                     }
    5331                 }
    5332 
    5333                 /* Read the whole message into the buffer, making sure there is are a 4 zero bytes following it. */
    5334                 *(KU32 *)pbMsgBuf = cbMsg;
    5335                 rc = kSubmitReadIt(hPipe, &pbMsgBuf[sizeof(cbMsg)], cbMsg - sizeof(cbMsg), K_FALSE /*fShutdownOkay*/);
    5336                 if (rc == 0)
    5337                 {
    5338                     const char *psz;
    5339 
    5340                     pbMsgBuf[cbMsg]     = '\0';
    5341                     pbMsgBuf[cbMsg + 1] = '\0';
    5342                     pbMsgBuf[cbMsg + 2] = '\0';
    5343                     pbMsgBuf[cbMsg + 3] = '\0';
    5344 
    5345                     /* The first string after the header is the command. */
    5346                     psz = (const char *)&pbMsgBuf[sizeof(cbMsg)];
    5347                     if (strcmp(psz, "JOB") == 0)
    5348                     {
    5349                         struct
    5350                         {
    5351                             KI32 rcExitCode;
    5352                             KU8  bExiting;
    5353                             KU8  abZero[3];
    5354                         } Reply;
    5355                         Reply.rcExitCode = kSubmitHandleJob(psz, cbMsg - sizeof(cbMsg));
    5356                         Reply.bExiting   = g_fRestart;
    5357                         Reply.abZero[0]  = 0;
    5358                         Reply.abZero[1]  = 0;
    5359                         Reply.abZero[2]  = 0;
    5360                         rc = kSubmitWriteIt(hPipe, &Reply, sizeof(Reply));
    5361                         if (   rc == 0
    5362                             && !g_fRestart)
    5363                             continue;
    5364                     }
    5365                     else
    5366                     {
    5367                         kwErrPrintf("Unknown command: '%s'\n", psz);
    5368                         rc = -1;
    5369                     }
    5370                 }
    5371             }
    5372             else
    5373             {
    5374                 kwErrPrintf("Bogus message length: %u (%#x)\n", cbMsg, cbMsg);
    5375                 rc = -1;
    5376             }
    5377         }
    5378         return rc > 0 ? 0 : 1;
    5379     }
    5380 
    5381 #else
    5382     int rc = 0;
    5383     int i;
    5384     argv[2] = "\"E:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/bin/amd64/cl.exe\" -c -c -TP -nologo -Zi -Zi -Zl -GR- -EHsc -GF -Zc:wchar_t- -Oy- -MT -W4 -Wall -wd4065 -wd4996 -wd4127 -wd4706 -wd4201 -wd4214 -wd4510 -wd4512 -wd4610 -wd4514 -wd4820 -wd4365 -wd4987 -wd4710 -wd4061 -wd4986 -wd4191 -wd4574 -wd4917 -wd4711 -wd4611 -wd4571 -wd4324 -wd4505 -wd4263 -wd4264 -wd4738 -wd4242 -wd4244 -WX -RTCsu -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/include -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/atlmfc/include -IE:/vbox/svn/trunk/tools/win.x86/sdk/v7.1/Include -IE:/vbox/svn/trunk/include -IE:/vbox/svn/trunk/out/win.amd64/debug -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/include -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/atlmfc/include -DVBOX -DVBOX_WITH_64_BITS_GUESTS -DVBOX_WITH_REM -DVBOX_WITH_RAW_MODE -DDEBUG -DDEBUG_bird -DDEBUG_USERNAME=bird -DRT_OS_WINDOWS -D__WIN__ -DRT_ARCH_AMD64 -D__AMD64__ -D__WIN64__ -DVBOX_WITH_DEBUGGER -DRT_LOCK_STRICT -DRT_LOCK_STRICT_ORDER -DIN_RING3 -DLOG_DISABLED -DIN_BLD_PROG -D_CRT_SECURE_NO_DEPRECATE -FdE:/vbox/svn/trunk/out/win.amd64/debug/obj/VBoxBs2Linker/VBoxBs2Linker-obj.pdb -FD -FoE:/vbox/svn/trunk/out/win.amd64/debug/obj/VBoxBs2Linker/VBoxBs2Linker.obj E:\\vbox\\svn\\trunk\\src\\VBox\\ValidationKit\\bootsectors\\VBoxBs2Linker.cpp";
    5385 # if 0
    5386     rc = kwExecCmdLine(argv[1], argv[2]);
    5387     rc = kwExecCmdLine(argv[1], argv[2]);
    5388     K_NOREF(i);
    5389 # else
    5390 // Skylake (W10/amd64, only stdandard MS defender):
    5391 //     cmd 1:  48    /1024 = 0x0 (0.046875)        [for /l %i in (1,1,1024) do ...]
    5392 //     kmk 1:  44    /1024 = 0x0 (0.04296875)      [all: ; 1024 x cl.exe]
    5393 //     run 1:  37    /1024 = 0x0 (0.0361328125)    [just process creation gain]
    5394 //     run 2:  34    /1024 = 0x0 (0.033203125)     [get file attribs]
    5395 //     run 3:  32.77 /1024 = 0x0 (0.032001953125)  [read caching of headers]
    5396 //     run 4:  32.67 /1024 = 0x0 (0.031904296875)  [loader tweaking]
    5397 //     run 5:  29.144/1024 = 0x0 (0.0284609375)    [with temp files in memory]
    5398 // Dell (W7/amd64, infected by mcafee):
    5399 //     kmk 1: 285.278/1024 = 0x0 (0.278591796875)
    5400 //     run 1: 134.503/1024 = 0x0 (0.1313505859375) [w/o temp files in memory]
    5401 //     run 2:  78.161/1024 = 0x0 (0.0763291015625) [with temp files in memory]
    5402     g_cVerbose = 0;
    5403     for (i = 0; i < 1024 && rc == 0; i++)
    5404         rc = kwExecCmdLine(argv[1], argv[2]);
    5405 # endif
    5406     return rc;
    5407 
    5408 #endif
    5409 }
    5410 
  • trunk/src/lib/nt/ntstat.c

    r2850 r2851  
    190190 * @param   pBuf                The MY_FILE_ID_FULL_DIR_INFORMATION entry.
    191191 * @param   pszPath             Optionally, the path for X bit checks.
     192 * @remarks Caller sets st_dev.
    192193 */
    193194void birdStatFillFromFileIdFullDirInfo(BirdStat_T *pStat, MY_FILE_ID_FULL_DIR_INFORMATION const *pBuf, const char *pszPath)
     
    216217
    217218
     219/**
     220 * Fills in a stat structure from an MY_FILE_ID_BOTH_DIR_INFORMATION entry.
     221 *
     222 * @param   pStat               The stat structure.
     223 * @param   pBuf                The MY_FILE_ID_BOTH_DIR_INFORMATION entry.
     224 * @param   pszPath             Optionally, the path for X bit checks.
     225 * @remarks Caller sets st_dev.
     226 */
     227void birdStatFillFromFileIdBothDirInfo(BirdStat_T *pStat, MY_FILE_ID_BOTH_DIR_INFORMATION const *pBuf, const char *pszPath)
     228{
     229    pStat->st_mode          = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes, pszPath,
     230                                                 NULL, &pStat->st_dirsymlink);
     231    pStat->st_padding0[0]   = 0;
     232    pStat->st_padding0[1]   = 0;
     233    pStat->st_size          = pBuf->EndOfFile.QuadPart;
     234    birdNtTimeToTimeSpec(pBuf->CreationTime.QuadPart,   &pStat->st_birthtim);
     235    birdNtTimeToTimeSpec(pBuf->ChangeTime.QuadPart,     &pStat->st_ctim);
     236    birdNtTimeToTimeSpec(pBuf->LastWriteTime.QuadPart,  &pStat->st_mtim);
     237    birdNtTimeToTimeSpec(pBuf->LastAccessTime.QuadPart, &pStat->st_atim);
     238    pStat->st_ino           = pBuf->FileId.QuadPart;
     239    pStat->st_nlink         = 1;
     240    pStat->st_rdev          = 0;
     241    pStat->st_uid           = 0;
     242    pStat->st_gid           = 0;
     243    pStat->st_padding1[0]   = 0;
     244    pStat->st_padding1[1]   = 0;
     245    pStat->st_padding1[2]   = 0;
     246    pStat->st_blksize       = 65536;
     247    pStat->st_blocks        = (pBuf->AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
     248                            / BIRD_STAT_BLOCK_SIZE;
     249}
     250
     251
     252/**
     253 * Fills in a stat structure from an MY_FILE_BOTH_DIR_INFORMATION entry.
     254 *
     255 * @param   pStat               The stat structure.
     256 * @param   pBuf                The MY_FILE_BOTH_DIR_INFORMATION entry.
     257 * @param   pszPath             Optionally, the path for X bit checks.
     258 * @remarks Caller sets st_dev.
     259 */
     260void birdStatFillFromFileBothDirInfo(BirdStat_T *pStat, MY_FILE_BOTH_DIR_INFORMATION const *pBuf, const char *pszPath)
     261{
     262    pStat->st_mode          = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes, pszPath,
     263                                                 NULL, &pStat->st_dirsymlink);
     264    pStat->st_padding0[0]   = 0;
     265    pStat->st_padding0[1]   = 0;
     266    pStat->st_size          = pBuf->EndOfFile.QuadPart;
     267    birdNtTimeToTimeSpec(pBuf->CreationTime.QuadPart,   &pStat->st_birthtim);
     268    birdNtTimeToTimeSpec(pBuf->ChangeTime.QuadPart,     &pStat->st_ctim);
     269    birdNtTimeToTimeSpec(pBuf->LastWriteTime.QuadPart,  &pStat->st_mtim);
     270    birdNtTimeToTimeSpec(pBuf->LastAccessTime.QuadPart, &pStat->st_atim);
     271    pStat->st_ino           = 0;
     272    pStat->st_nlink         = 1;
     273    pStat->st_rdev          = 0;
     274    pStat->st_uid           = 0;
     275    pStat->st_gid           = 0;
     276    pStat->st_padding1[0]   = 0;
     277    pStat->st_padding1[1]   = 0;
     278    pStat->st_padding1[2]   = 0;
     279    pStat->st_blksize       = 65536;
     280    pStat->st_blocks        = (pBuf->AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
     281                            / BIRD_STAT_BLOCK_SIZE;
     282}
     283
     284
    218285int birdStatHandle(HANDLE hFile, BirdStat_T *pStat, const char *pszPath)
    219286{
     
    359426
    360427
     428/**
     429 * Generates a device number from the volume information.
     430 *
     431 * @returns Device number.
     432 * @param   pVolInfo            Volume information.
     433 */
     434unsigned __int64 birdVolumeInfoToDeviceNumber(const MY_FILE_FS_VOLUME_INFORMATION *pVolInfo)
     435{
     436    return pVolInfo->VolumeSerialNumber
     437         | (pVolInfo->VolumeCreationTime.QuadPart << 32);
     438}
     439
     440
     441/**
     442 * Quries the volume information and generates a device number from it.
     443 *
     444 * @returns NT status code.
     445 * @param   hFile               The file/dir/whatever to query the volume info
     446 *                              and device number for.
     447 * @param   pVolInfo            User provided buffer for volume information.
     448 * @param   cbVolInfo           The size of the buffer.
     449 * @param   puDevNo             Where to return the device number.  This is set
     450 *                              to zero on failure.
     451 */
     452MY_NTSTATUS birdQueryVolumeDeviceNumber(HANDLE hFile, MY_FILE_FS_VOLUME_INFORMATION *pVolInfo, size_t cbVolInfo,
     453                                        unsigned __int64 *puDevNo)
     454{
     455    MY_IO_STATUS_BLOCK  Ios;
     456    MY_NTSTATUS         rcNt;
     457
     458    Ios.u.Status    = -1;
     459    Ios.Information = -1;
     460
     461    pVolInfo->VolumeSerialNumber = 0;
     462    pVolInfo->VolumeCreationTime.QuadPart = 0;
     463
     464    rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pVolInfo, (LONG)cbVolInfo, MyFileFsVolumeInformation);
     465    if (MY_NT_SUCCESS(rcNt))
     466    {
     467        *puDevNo = birdVolumeInfoToDeviceNumber(pVolInfo);
     468        return Ios.u.Status;
     469    }
     470    *puDevNo = 0;
     471    return rcNt;
     472}
     473
     474
    361475static int birdStatInternal(const char *pszPath, BirdStat_T *pStat, int fFollow)
    362476{
     
    429543
    430544                    /* Get the serial number, reusing the buffer from above. */
    431                     rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pBuf, cbBuf, MyFileFsVolumeInformation);
     545                    rcNt = birdQueryVolumeDeviceNumber(hFile, (MY_FILE_FS_VOLUME_INFORMATION *)pBuf, cbBuf, &pStat->st_dev);
    432546                    if (MY_NT_SUCCESS(rcNt))
    433                         rcNt = Ios.u.Status;
    434                     if (MY_NT_SUCCESS(rcNt))
    435                     {
    436                         MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo = (MY_FILE_FS_VOLUME_INFORMATION const *)pBuf;
    437                         pStat->st_dev       = pVolInfo->VolumeSerialNumber
    438                                             | (pVolInfo->VolumeCreationTime.QuadPart << 32);
    439547                        rc = 0;
    440                     }
    441548                    else
    442                     {
    443                         pStat->st_dev       = 0;
    444549                        rc = birdSetErrnoFromNt(rcNt);
    445                     }
    446550                }
    447551
  • trunk/src/lib/nt/ntstat.h

    r2850 r2851  
    8282#ifdef ___nt_ntstuff_h
    8383void birdStatFillFromFileIdFullDirInfo(BirdStat_T *pStat, MY_FILE_ID_FULL_DIR_INFORMATION const *pBuf, const char *pszPath);
     84void birdStatFillFromFileIdBothDirInfo(BirdStat_T *pStat, MY_FILE_ID_BOTH_DIR_INFORMATION const *pBuf, const char *pszPath);
     85void birdStatFillFromFileBothDirInfo(BirdStat_T *pStat, MY_FILE_BOTH_DIR_INFORMATION const *pBuf, const char *pszPath);
     86MY_NTSTATUS birdQueryVolumeDeviceNumber(HANDLE hFile, MY_FILE_FS_VOLUME_INFORMATION *pVolInfo, size_t cbVolInfo,
     87                                        unsigned __int64 *puDevNo);
     88unsigned __int64 birdVolumeInfoToDeviceNumber(MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo);
    8489#endif
    8590
  • trunk/src/lib/nt/ntstuff.h

    r2713 r2851  
    199199/** The sizeof(MY_FILE_NAMES_INFORMATION) without the FileName. */
    200200#define MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION  ( (size_t)&((MY_FILE_ID_FULL_DIR_INFORMATION *)0)->FileName )
     201
     202typedef struct MY_FILE_BOTH_DIR_INFORMATION
     203{
     204    ULONG           NextEntryOffset;
     205    ULONG           FileIndex;
     206    LARGE_INTEGER   CreationTime;
     207    LARGE_INTEGER   LastAccessTime;
     208    LARGE_INTEGER   LastWriteTime;
     209    LARGE_INTEGER   ChangeTime;
     210    LARGE_INTEGER   EndOfFile;
     211    LARGE_INTEGER   AllocationSize;
     212    ULONG           FileAttributes;
     213    ULONG           FileNameLength;
     214    ULONG           EaSize;
     215    CCHAR           ShortNameLength;
     216    WCHAR           ShortName[12];
     217    WCHAR           FileName[1];
     218} MY_FILE_BOTH_DIR_INFORMATION;
     219/** The sizeof(MY_FILE_BOTH_DIR_INFORMATION) without the FileName. */
     220#define MIN_SIZEOF_MY_FILE_BOTH_DIR_INFORMATION  ( (size_t)&((MY_FILE_BOTH_DIR_INFORMATION *)0)->FileName )
     221
     222
     223typedef struct MY_FILE_ID_BOTH_DIR_INFORMATION
     224{
     225    ULONG           NextEntryOffset;
     226    ULONG           FileIndex;
     227    LARGE_INTEGER   CreationTime;
     228    LARGE_INTEGER   LastAccessTime;
     229    LARGE_INTEGER   LastWriteTime;
     230    LARGE_INTEGER   ChangeTime;
     231    LARGE_INTEGER   EndOfFile;
     232    LARGE_INTEGER   AllocationSize;
     233    ULONG           FileAttributes;
     234    ULONG           FileNameLength;
     235    ULONG           EaSize;
     236    CCHAR           ShortNameLength;
     237    WCHAR           ShortName[12];
     238    LARGE_INTEGER   FileId;
     239    WCHAR           FileName[1];
     240} MY_FILE_ID_BOTH_DIR_INFORMATION;
     241/** The sizeof(MY_FILE_NAMES_INFORMATION) without the FileName. */
     242#define MIN_SIZEOF_MY_FILE_ID_BOTH_DIR_INFORMATION  ( (size_t)&((MY_FILE_ID_BOTH_DIR_INFORMATION *)0)->FileName )
    201243
    202244
     
    277319} MY_FILE_FS_VOLUME_INFORMATION;
    278320
     321typedef struct _MY_FILE_FS_ATTRIBUTE_INFORMATION
     322{
     323    ULONG           FileSystemAttributes;
     324    LONG            MaximumComponentNameLength;
     325    ULONG           FileSystemNameLength;
     326    WCHAR           FileSystemName[1];
     327} MY_FILE_FS_ATTRIBUTE_INFORMATION;
     328
    279329typedef enum MY_FSINFOCLASS
    280330{
     
    358408#define MY_NT_FAILURE(a_ntRc)               ((MY_NTSTATUS)(a_ntRc) <  0)
    359409#define MY_STATUS_NO_MORE_FILES             ((MY_NTSTATUS)0x80000006)
     410#define MY_STATUS_OBJECT_NAME_INVALID       ((MY_NTSTATUS)0xc0000033)
     411#define MY_STATUS_OBJECT_NAME_NOT_FOUND     ((MY_NTSTATUS)0xc0000034)
     412#define MY_STATUS_OBJECT_PATH_INVALID       ((MY_NTSTATUS)0xc0000039)
     413#define MY_STATUS_OBJECT_PATH_NOT_FOUND     ((MY_NTSTATUS)0xc000003a)
     414#define MY_STATUS_OBJECT_PATH_SYNTAX_BAD    ((MY_NTSTATUS)0xc000003b)
    360415/** @}  */
    361416
  • trunk/src/lib/quote_argv.c

    r2838 r2851  
    77 * Copyright (c) 2007-2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
    88 *
    9  * This file is part of kBuild.
    10  *
    11  * kBuild is free software; you can redistribute it and/or modify
    12  * it under the terms of the GNU General Public License as published by
    13  * the Free Software Foundation; either version 3 of the License, or
    14  * (at your option) any later version.
    15  *
    16  * kBuild is distributed in the hope that it will be useful,
    17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    19  * GNU General Public License for more details.
    20  *
    21  * You should have received a copy of the GNU General Public License
    22  * along with kBuild.  If not, see <http://www.gnu.org/licenses/>
    23  *
    24  */
     9 * Permission is hereby granted, free of charge, to any person obtaining a
     10 * copy of this software and associated documentation files (the "Software"),
     11 * to deal in the Software without restriction, including without limitation
     12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     13 * and/or sell copies of the Software, and to permit persons to whom the
     14 * Software is furnished to do so, subject to the following conditions:
     15 *
     16 * The above copyright notice and this permission notice shall be included
     17 * in all copies or substantial portions of the Software.
     18 *
     19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     25 * IN THE SOFTWARE.
     26 *
     27 * Alternatively, the content of this file may be used under the terms of the
     28 * GPL version 2 or later, or LGPL version 2.1 or later.
     29 */
     30
    2531
    2632/*******************************************************************************
  • trunk/src/lib/quote_argv.h

    r2838 r2851  
    55
    66/*
    7  * Copyright (c) 2010 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
     7 * Copyright (c) 2007-2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
    88 *
    9  * This file is part of kBuild.
     9 * Permission is hereby granted, free of charge, to any person obtaining a
     10 * copy of this software and associated documentation files (the "Software"),
     11 * to deal in the Software without restriction, including without limitation
     12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     13 * and/or sell copies of the Software, and to permit persons to whom the
     14 * Software is furnished to do so, subject to the following conditions:
    1015 *
    11  * kBuild is free software; you can redistribute it and/or modify
    12  * it under the terms of the GNU General Public License as published by
    13  * the Free Software Foundation; either version 3 of the License, or
    14  * (at your option) any later version.
     16 * The above copyright notice and this permission notice shall be included
     17 * in all copies or substantial portions of the Software.
    1518 *
    16  * kBuild is distributed in the hope that it will be useful,
    17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    19  * GNU General Public License for more details.
     19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     25 * IN THE SOFTWARE.
    2026 *
    21  * You should have received a copy of the GNU General Public License
    22  * along with kBuild.  If not, see <http://www.gnu.org/licenses/>
    23  *
     27 * Alternatively, the content of this file may be used under the terms of the
     28 * GPL version 2 or later, or LGPL version 2.1 or later.
    2429 */
    2530
  • trunk/src/lib/quoted_spawn.c

    r2413 r2851  
    55
    66/*
    7  * Copyright (c) 2010 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
    8  *
    9  * This file is part of kBuild.
    10  *
    11  * kBuild is free software; you can redistribute it and/or modify
    12  * it under the terms of the GNU General Public License as published by
    13  * the Free Software Foundation; either version 3 of the License, or
    14  * (at your option) any later version.
    15  *
    16  * kBuild is distributed in the hope that it will be useful,
    17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    19  * GNU General Public License for more details.
    20  *
    21  * You should have received a copy of the GNU General Public License
    22  * along with kBuild.  If not, see <http://www.gnu.org/licenses/>
    23  *
    24  */
     7 * Copyright (c) 2010-2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
     8 *
     9 * Permission is hereby granted, free of charge, to any person obtaining a
     10 * copy of this software and associated documentation files (the "Software"),
     11 * to deal in the Software without restriction, including without limitation
     12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     13 * and/or sell copies of the Software, and to permit persons to whom the
     14 * Software is furnished to do so, subject to the following conditions:
     15 *
     16 * The above copyright notice and this permission notice shall be included
     17 * in all copies or substantial portions of the Software.
     18 *
     19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     25 * IN THE SOFTWARE.
     26 *
     27 * Alternatively, the content of this file may be used under the terms of the
     28 * GPL version 2 or later, or LGPL version 2.1 or later.
     29 */
     30
    2531
    2632/*******************************************************************************
  • trunk/src/lib/quoted_spawn.h

    r2413 r2851  
    55
    66/*
    7  * Copyright (c) 2010 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
     7 * Copyright (c) 2010-2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
    88 *
    9  * This file is part of kBuild.
     9 * Permission is hereby granted, free of charge, to any person obtaining a
     10 * copy of this software and associated documentation files (the "Software"),
     11 * to deal in the Software without restriction, including without limitation
     12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     13 * and/or sell copies of the Software, and to permit persons to whom the
     14 * Software is furnished to do so, subject to the following conditions:
    1015 *
    11  * kBuild is free software; you can redistribute it and/or modify
    12  * it under the terms of the GNU General Public License as published by
    13  * the Free Software Foundation; either version 3 of the License, or
    14  * (at your option) any later version.
     16 * The above copyright notice and this permission notice shall be included
     17 * in all copies or substantial portions of the Software.
    1518 *
    16  * kBuild is distributed in the hope that it will be useful,
    17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    19  * GNU General Public License for more details.
     19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     25 * IN THE SOFTWARE.
    2026 *
    21  * You should have received a copy of the GNU General Public License
    22  * along with kBuild.  If not, see <http://www.gnu.org/licenses/>
    23  *
     27 * Alternatively, the content of this file may be used under the terms of the
     28 * GPL version 2 or later, or LGPL version 2.1 or later.
    2429 */
    2530
  • trunk/src/lib/restartable-syscall-wrappers.c

    r2507 r2851  
    1313
    1414/*
    15  * Copyright (c) 2011 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
    16  *
    17  * This file is part of kBuild.
    18  *
    19  * kBuild is free software; you can redistribute it and/or modify
    20  * it under the terms of the GNU General Public License as published by
    21  * the Free Software Foundation; either version 3 of the License, or
    22  * (at your option) any later version.
    23  *
    24  * kBuild is distributed in the hope that it will be useful,
    25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    27  * GNU General Public License for more details.
    28  *
    29  * You should have received a copy of the GNU General Public License
    30  * along with kBuild.  If not, see <http://www.gnu.org/licenses/>
    31  *
     15 * Copyright (c) 2011-2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
     16 *
     17 * Permission is hereby granted, free of charge, to any person obtaining a
     18 * copy of this software and associated documentation files (the "Software"),
     19 * to deal in the Software without restriction, including without limitation
     20 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     21 * and/or sell copies of the Software, and to permit persons to whom the
     22 * Software is furnished to do so, subject to the following conditions:
     23 *
     24 * The above copyright notice and this permission notice shall be included
     25 * in all copies or substantial portions of the Software.
     26 *
     27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     28 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     29 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     30 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     31 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     32 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     33 * IN THE SOFTWARE.
     34 *
     35 * Alternatively, the content of this file may be used under the terms of the
     36 * GPL version 2 or later, or LGPL version 2.1 or later.
    3237 */
    3338
  • trunk/src/lib/wrapper.c

    r2413 r2851  
    55
    66/*
    7  * Copyright (c) 2007-2010 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
     7 * Copyright (c) 2007-2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
    88 *
    9  * This file is part of kBuild.
     9 * Permission is hereby granted, free of charge, to any person obtaining a
     10 * copy of this software and associated documentation files (the "Software"),
     11 * to deal in the Software without restriction, including without limitation
     12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     13 * and/or sell copies of the Software, and to permit persons to whom the
     14 * Software is furnished to do so, subject to the following conditions:
    1015 *
    11  * kBuild is free software; you can redistribute it and/or modify
    12  * it under the terms of the GNU General Public License as published by
    13  * the Free Software Foundation; either version 3 of the License, or
    14  * (at your option) any later version.
     16 * The above copyright notice and this permission notice shall be included
     17 * in all copies or substantial portions of the Software.
    1518 *
    16  * kBuild is distributed in the hope that it will be useful,
    17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    19  * GNU General Public License for more details.
     19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     25 * IN THE SOFTWARE.
    2026 *
    21  * You should have received a copy of the GNU General Public License
    22  * along with kBuild.  If not, see <http://www.gnu.org/licenses/>
    23  *
     27 * Alternatively, the content of this file may be used under the terms of the
     28 * GPL version 2 or later, or LGPL version 2.1 or later.
    2429 */
     30
    2531
    2632/*******************************************************************************
     
    3541# include <unistd.h>
    3642#endif
     43
    3744
    3845int main(int argc, char **argv, char **envp)
     
    8996    return pszRetVal ? atol(pszRetVal) : 1;
    9097}
     98
Note: See TracChangeset for help on using the changeset viewer.