Changeset 2851
- Timestamp:
- Aug 31, 2016, 7:30:52 PM (9 years ago)
- Location:
- trunk/src/lib
- Files:
-
- 1 deleted
- 16 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/lib
- Property svn:externals set to
-
trunk/src/lib/Makefile.kmk
r2849 r2851 49 49 nt/nthlpfs.c \ 50 50 nt/ntdir.c \ 51 nt/ntdircache.c \ 51 52 nt/ntstat.c \ 52 53 nt/ntunlink.c -
trunk/src/lib/kDep.c
r2413 r2851 5 5 6 6 /* 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 25 31 26 32 /******************************************************************************* -
trunk/src/lib/kDep.h
r2413 r2851 5 5 6 6 /* 7 * Copyright (c) 2004-201 0knut st. osmundsen <bird-kBuild-spamx@anduin.net>7 * Copyright (c) 2004-2013 knut st. osmundsen <bird-kBuild-spamx@anduin.net> 8 8 * 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: 10 15 * 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. 15 18 * 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. 20 26 * 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. 24 29 */ 30 25 31 26 32 #ifndef ___kDep_h -
trunk/src/lib/kbuild_version.c
r2844 r2851 5 5 6 6 /* 7 * Copyright (c) 2007-201 6knut st. osmundsen <bird-kBuild-spamx@anduin.net>7 * Copyright (c) 2007-2013 knut st. osmundsen <bird-kBuild-spamx@anduin.net> 8 8 * 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: 10 15 * 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. 15 18 * 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. 20 26 * 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. 24 29 */ 25 30 -
trunk/src/lib/kbuild_version.h
r2844 r2851 5 5 6 6 /* 7 * Copyright (c) 2007-201 6knut st. osmundsen <bird-kBuild-spamx@anduin.net>7 * Copyright (c) 2007-2013 knut st. osmundsen <bird-kBuild-spamx@anduin.net> 8 8 * 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: 10 15 * 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. 15 18 * 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. 20 26 * 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. 24 29 */ 25 30 -
trunk/src/lib/mytypes.h
r2442 r2851 5 5 6 6 /* 7 * Copyright (c) 2007-201 0knut st. osmundsen <bird-kBuild-spamx@anduin.net>7 * Copyright (c) 2007-2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net> 8 8 * 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: 10 15 * 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. 15 18 * 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. 20 26 * 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. 24 29 */ 25 30 26 #ifndef ___mytypes_h__ 27 #define ___mytypes_h__ 31 #ifndef ___mytypes_h___ 32 #define ___mytypes_h___ 28 33 29 34 #include <stdlib.h> -
trunk/src/lib/nt/ntdircache.c
r2850 r2851 1 1 /* $Id$ */ 2 2 /** @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. 7 4 */ 8 5 … … 10 7 * Copyright (c) 2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net> 11 8 * 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. 27 29 */ 28 30 … … 32 34 *********************************************************************************************************************************/ 33 35 #include <k/kHlp.h> 34 #include <k/kLdr.h> 36 37 #include "nthlp.h" 38 #include "ntstat.h" 35 39 36 40 #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> 48 48 49 49 … … 52 52 * Defined Constants And Macros * 53 53 *********************************************************************************************************************************/ 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 59 74 60 75 /** @def KW_LOG 61 76 * Generic logging. 62 * @param a Argument list for k wDbgPrintf */77 * @param a Argument list for kFsCacheDbgPrintf */ 63 78 #ifndef NDEBUG 64 # define K W_LOG(a) kwDbgPrintf a79 # define KFSCACHE_LOG(a) kFsCacheDbgPrintf a 65 80 #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) == '/') 97 114 98 115 … … 100 117 * Structures and Typedefs * 101 118 *********************************************************************************************************************************/ 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. */ 120 typedef struct KFSOBJ *PKFSOBJ; 121 /** Pointer to a directory object. */ 122 typedef struct KFSDIR *PKFSDIR; 123 /** Pointer to a directory hash table entry. */ 124 typedef 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 */ 133 typedef 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 */ 145 typedef struct KFSOBJ 146 { 147 /** Magic value (KFSOBJ_MAGIC). */ 148 KU32 u32Magic; 131 149 /** 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.) */ 200 167 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; 201 181 /** The UTF-16 object name. (Allocated after the structure.) */ 202 182 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 */ 215 typedef struct KFSDIR 216 { 217 /** The core object information. */ 218 KFSOBJ Obj; 219 220 /** Child objects. */ 221 PKFSOBJ *papChildren; 208 222 /** The number of child objects. */ 209 223 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 */ 246 typedef 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; 230 276 231 277 232 278 /** Pointer to an ANSI path hash table entry. */ 233 typedef struct K WFSHASHA *PKWFSHASHA;279 typedef struct KFSHASHA *PKFSHASHA; 234 280 /** 235 281 * ANSI file system path hash table entry. 236 282 * The path hash table allows us to skip parsing and walking a path. 237 283 */ 238 typedef struct K WFSHASHA284 typedef struct KFSHASHA 239 285 { 240 286 /** Next entry with the same hash table slot. */ 241 PK WFSHASHApNext;287 PKFSHASHA pNext; 242 288 /** Path hash value. */ 243 289 KU32 uHashPath; 244 290 /** The path length. */ 245 291 KU32 cchPath; 292 /** The cache generation ID. */ 293 KU32 uCacheGen; 294 /** The lookup error (when pFsObj is NULL). */ 295 KFSLOOKUPERROR enmError; 246 296 /** The path. (Allocated after the structure.) */ 247 297 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 253 305 /** Pointer to an UTF-16 path hash table entry. */ 254 typedef struct K WFSHASHW *PKWFSHASHW;306 typedef struct KFSHASHW *PKFSHASHW; 255 307 /** 256 308 * UTF-16 file system path hash table entry. The path hash table allows us 257 309 * to skip parsing and walking a path. 258 310 */ 259 typedef struct K WFSHASHW311 typedef struct KFSHASHW 260 312 { 261 313 /** Next entry with the same hash table slot. */ 262 PK WFSHASHWpNext;314 PKFSHASHW pNext; 263 315 /** Path hash value. */ 264 316 KU32 uHashPath; 265 317 /** The path length (in wchar_t units). */ 266 318 KU32 cwcPath; 319 /** The cache generation ID. */ 320 KU32 uCacheGen; 321 /** The lookup error (when pFsObj is NULL). */ 322 KFSLOOKUPERROR enmError; 267 323 /** The path. (Allocated after the structure.) */ 268 324 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. */ 342 typedef struct KFSCACHE *PKFSCACHE; 343 /** 344 * Directory cache instance. 345 */ 346 typedef 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) 575 395 576 396 … … 578 398 * Internal Functions * 579 399 *********************************************************************************************************************************/ 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 400 KU32 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 */ 409 K_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 586 419 587 420 /** … … 590 423 * @param ... Format argument. 591 424 */ 592 static void k wDbgPrintfV(const char *pszFormat, va_list va)593 { 594 if ( g_cVerbose >= 2)425 static void kFsCacheDbgPrintfV(const char *pszFormat, va_list va) 426 { 427 if (1) 595 428 { 596 429 DWORD const dwSavedErr = GetLastError(); … … 609 442 * @param ... Format argument. 610 443 */ 611 static void k wDbgPrintf(const char *pszFormat, ...)612 { 613 if ( g_cVerbose >= 2)444 static void kFsCacheDbgPrintf(const char *pszFormat, ...) 445 { 446 if (1) 614 447 { 615 448 va_list va; 616 449 va_start(va, pszFormat); 617 k wDbgPrintfV(pszFormat, va);450 kFsCacheDbgPrintfV(pszFormat, va); 618 451 va_end(va); 619 452 } 620 453 } 621 454 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 720 457 721 458 … … 726 463 * @param pszString String to hash. 727 464 */ 728 static KU32 k wStrHash(const char *pszString)465 static KU32 kFsCacheStrHash(const char *pszString) 729 466 { 730 467 /* This algorithm was created for sdbm (a public-domain reimplementation of … … 753 490 * @param puHash Where to return the 32-bit string hash. 754 491 */ 755 static KSIZE k wStrHashEx(const char *pszString, KU32 *puHash)492 static KSIZE kFsCacheStrHashEx(const char *pszString, KU32 *puHash) 756 493 { 757 494 const char * const pszStart = pszString; … … 775 512 * @param puHash Where to return the 32-bit string hash. 776 513 */ 777 static KSIZE k wUtf16HashEx(const wchar_t *pwszString, KU32 *puHash)514 static KSIZE kFsCacheUtf16HashEx(const wchar_t *pwszString, KU32 *puHash) 778 515 { 779 516 const wchar_t * const pwszStart = pwszString; … … 789 526 } 790 527 528 #if 0 791 529 792 530 /** … … 917 655 */ 918 656 KU32 uHashPath; 919 KU32 cchPath = (KU32)k wStrHashEx(pszPath, &uHashPath);657 KU32 cchPath = (KU32)kFsCacheStrHashEx(pszPath, &uHashPath); 920 658 KU32 const idxHashTab = uHashPath % K_ELEMENTS(g_apFsNormalizedPathsA); 921 PK WFSNORMHASHA pHashEntry = g_apFsNormalizedPathsA[idxHashTab];659 PKFSNORMHASHA pHashEntry = g_apFsNormalizedPathsA[idxHashTab]; 922 660 if (pHashEntry) 923 661 { … … 930 668 if (cbNormPath > pHashEntry->cchNormPath) 931 669 { 932 K WFS_LOG(("kwPathNormalize(%s) - hit\n", pszPath));670 KFSCACHE_LOG(("kwPathNormalize(%s) - hit\n", pszPath)); 933 671 kHlpMemCopy(pszNormPath, pHashEntry->szNormPath, pHashEntry->cchNormPath + 1); 934 672 return 0; … … 959 697 if (cchNormPath < KU16_MAX && cchPath < KU16_MAX) 960 698 { 961 pHashEntry = (PK WFSNORMHASHA)kHlpAlloc(sizeof(*pHashEntry) + cchNormPath + 1 + cchPath + 1);699 pHashEntry = (PKFSNORMHASHA)kHlpAlloc(sizeof(*pHashEntry) + cchNormPath + 1 + cchPath + 1); 962 700 if (pHashEntry) 963 701 { … … 1009 747 pwszPath++; 1010 748 } 1011 }1012 1013 1014 1015 /**1016 * Retains a new reference to the given module1017 * @returns pMod1018 * @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 else1046 {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 else1082 kHlpAssert(pMod->cRefs < 64);1083 }1084 1085 1086 /**1087 * Links the module into the module hash table.1088 *1089 * @returns pMod1090 * @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 else1126 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 > 01135 && 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-- > 01156 && pImpDesc->Name > 01157 && 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 == cchSymbol1181 && kHlpMemComp(g_aSandboxNativeReplacements[i].pszFunction, pName->Name, cchSymbol) == 0)1182 {1183 if ( !g_aSandboxNativeReplacements[i].pszModule1184 || 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 this1262 * 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_FALSE1315 * if not. Executable images does not get entered1316 * into the global module table.1317 * @param pExeMod The executable module of the process (for1318 * 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) * cImports1360 + cbPath1361 + 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_FIXED1381 || 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 ( !fFixed1385 || (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 else1442 kwErrPrintf("Failed to allocate %#x bytes\n", pMod->u.Manual.cbImage);1443 }1444 }1445 }1446 kLdrModClose(pLdrMod);1447 }1448 else1449 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 else1469 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 == cchSymbol1478 && kHlpMemComp(g_aSandboxReplacements[i].pszFunction, pchSymbol, cchSymbol) == 0)1479 {1480 if ( !g_aSandboxReplacements[i].pszModule1481 || 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 failure1500 * @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")) == 01528 || kHlpStrNICompAscii(pszFilename, TUPLE("msdis")) == 01529 || 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")) == 01547 || kHlpStrNICompAscii(pszFilename, TUPLE("msdis")) == 01548 || kHlpStrNICompAscii(pszFilename, TUPLE("mspdb")) == 0;1549 749 } 1550 750 … … 1566 766 && (pszPath[cchPath - 1] == 'l' || pszPath[cchPath - 1] == 'L') ) 1567 767 { 1568 PK WFSOBJ pFsObj = kwFsLookupA(pszPath);768 PKFSOBJ pFsObj = kFsCacheLookupA(pszPath); 1569 769 if (pFsObj) 1570 770 { … … 1587 787 1588 788 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 1847 791 1848 792 … … 1880 824 } 1881 825 } 826 #endif 1882 827 1883 828 … … 1889 834 * @param cchPath The length of the path. 1890 835 */ 1891 static KBOOL k wFsHasDotDot(const char *pszPath, KSIZE cchPath)836 static KBOOL kFsCacheHasDotDot(const char *pszPath, KSIZE cchPath) 1892 837 { 1893 838 const char *pchDot = (const char *)kHlpMemChr(pszPath, '.', cchPath); … … 1917 862 1918 863 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 */ 876 static 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); 1922 880 if (pHashEntry) 1923 881 { … … 1926 884 pHashEntry->pszPath = (const char *)kHlpMemCopy(pHashEntry + 1, pszPath, cchPath + 1); 1927 885 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 } 1950 902 } 1951 903 … … 1958 910 * @param pChild The child node. 1959 911 */ 1960 static KBOOL k wFsLinkChild(PKWFSOBJ pParent, PKWFSOBJ pChild)912 static KBOOL kFsCacheDirAddChild(PKFSCACHE pCache, PKFSDIR pParent, PKFSOBJ pChild, KFSLOOKUPERROR *penmError) 1961 913 { 1962 914 if ((pParent->cChildren % 16) == 0) … … 1965 917 if (!pvNew) 1966 918 return K_FALSE; 1967 pParent->papChildren = (PKWFSOBJ *)pvNew; 919 pParent->papChildren = (PKFSOBJ *)pvNew; 920 pCache->cbObjects += 16 * sizeof(pParent->papChildren[0]); 1968 921 } 1969 922 pParent->papChildren[pParent->cChildren++] = pChild; … … 1973 926 1974 927 /** 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 */ 948 static 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 { 1992 955 /* 1993 * Get attributes.956 * Allocate the object. 1994 957 */ 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 } 2002 1001 else 2003 1002 { 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 */ 1071 static 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 */ 1119 static PKFSOBJ kFsCacheCreateMissingA(PKFSCACHE pCache, PKFSDIR pParent, const char *pchName, KU32 cchName, 1120 KFSLOOKUPERROR *penmError) 1121 { 2016 1122 /* 2017 * Create the entry.1123 * Just convert the name to UTF-16 and call kFsCacheCreateObject to do the job. 2018 1124 */ 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; 2047 1146 return NULL; 2048 1147 } … … 2050 1149 2051 1150 /** 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 */ 1161 static 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 1366 static KBOOL kFsCacheRefreshMissing(PKFSCACHE pCache, PKFSOBJ pMissing, KFSLOOKUPERROR *penmError) 1367 { 1368 return K_TRUE; 1369 } 1370 1371 1372 static KBOOL kFsCacheRefreshMissingIntermediateDir(PKFSCACHE pCache, PKFSOBJ pMissing, KFSLOOKUPERROR *penmError) 1373 { 1374 return K_TRUE; 1375 } 1376 1377 1378 static 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 */ 1392 static 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 /** 2052 1403 * Look up a child node, ANSI version. 2053 1404 * 2054 1405 * @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. 2056 1408 * @param pchName The child name to search for (not terminated). 2057 1409 * @param cchName The length of the child name. 2058 1410 */ 2059 static PK WFSOBJ kwFsFindChildA(PKWFSOBJpParent, const char *pchName, KU32 cchName)1411 static PKFSOBJ kFsCacheFindChildA(PKFSCACHE pCache, PKFSDIR pParent, const char *pchName, KU32 cchName) 2060 1412 { 2061 1413 /* Check for '.' first. */ 2062 1414 if (cchName != 1 || *pchName != '.') 2063 1415 { 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; 2066 1427 while (cLeft-- > 0) 2067 1428 { 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 */ 1460 static 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 */ 1509 static 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) 2071 1583 { 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; 2076 1633 } 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; 2078 1653 return NULL; 2079 1654 } 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; 2081 1679 } 2082 1680 … … 2088 1686 * This will create any missing nodes while walking. 2089 1687 * 1688 * The caller will have to do the path hash table insertion of the result. 1689 * 2090 1690 * @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. 2092 1693 * @param pszPath The path to walk. 2093 1694 * @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 */ 1698 static PKFSOBJ kFsCacheLookupAbsoluteA(PKFSCACHE pCache, const char *pszPath, KU32 cchPath, KFSLOOKUPERROR *penmError) 1699 { 1700 PKFSDIR pParent = &pCache->RootDir; 1701 PKFSOBJ pChild; 2100 1702 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 */ 2108 1773 for (;;) 2109 1774 { 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; 2116 1780 while ((ch = pszPath[offEnd]) != '\0') 2117 1781 { … … 2127 1791 } 2128 1792 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. */ 2137 1830 off = offEnd + cchSlashes; 2138 1831 if ( cchSlashes == 0 2139 1832 || off >= cchPath) 2140 1833 { 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; 2142 1841 return pChild; 2143 1842 } 2144 1843 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; 2150 1865 } 2151 1866 … … 2160 1875 * @returns Pointer to object corresponding to @a pszPath on success. 2161 1876 * NULL if this isn't a path we care to cache. 1877 * 1878 * @param pCache The cache. 2162 1879 * @param pszPath The path. 2163 1880 * @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 */ 1884 static 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]; 2171 1891 UINT cchFull = GetFullPathNameA(pszPath, sizeof(szFull), szFull, NULL); 2172 1892 if ( cchFull >= 3 2173 1893 && cchFull < sizeof(szFull)) 2174 1894 { 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; 2192 1916 return NULL; 2193 1917 } … … 2195 1919 2196 1920 /** 2197 * Looks up a K WFSOBJ for the given ANSI path.1921 * Looks up a KFSOBJ for the given ANSI path. 2198 1922 * 2199 1923 * This will first try the hash table. If not in the hash table, the file … … 2204 1928 * point. 2205 1929 * 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. 2208 1932 * NULL if not a path we care to cache. 1933 * @param pCache The cache. 2209 1934 * @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 */ 1938 static PKFSOBJ kFsCacheLookupA(PKFSCACHE pCache, const char *pszPath, KFSLOOKUPERROR *penmError) 2212 1939 { 2213 1940 /* … … 2215 1942 */ 2216 1943 KU32 uHashPath; 2217 KU32 cchPath = (KU32)k wStrHashEx(pszPath, &uHashPath);2218 KU32 idxHashTab = uHashPath % K_ELEMENTS( g_apFsAnsiPaths);2219 PK WFSHASHA 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]; 2220 1947 if (pHashEntry) 2221 1948 { … … 2226 1953 && kHlpMemComp(pHashEntry->pszPath, pszPath, cchPath) == 0) 2227 1954 { 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; 2230 1968 } 2231 1969 pHashEntry = pHashEntry->pNext; … … 2237 1975 */ 2238 1976 if ( cchPath > 0 2239 && cchPath < 1024) 2240 { 1977 && cchPath < KFSCACHE_CFG_MAX_PATH) 1978 { 1979 PKFSOBJ pFsObj; 1980 2241 1981 /* Is absolute without any '..' bits? */ 2242 1982 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; 2259 2005 return NULL; 2260 2006 } 2261 2007 2262 2008 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 */ 2016 KU32 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); 2305 2027 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(); 2316 2034 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); 2460 2040 return 0; 2461 2041 } 2462 2042 2463 2043 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 */ 2051 KU32 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 */ 2066 KU32 kFsCacheObjRetain(PKFSOBJ pObj) 2067 { 2068 KU32 cRefs = ++pObj->cRefs; 2069 kHlpAssert(cRefs < 16384); 2070 return cRefs; 2071 } 2072 2073 2074 2075 PKFSCACHE 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 } 2589 2138 return NULL; 2590 2139 } 2591 2140 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 APIs2757 * Loader related APIs2758 * Loader related APIs2759 *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_REFERENCES2781 | LOAD_LIBRARY_AS_DATAFILE2782 | 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 == uHashPath2807 && 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 else2834 __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 else2846 {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 == NULL2959 || 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_FILES3067 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 the3072 * first and second compiler pass. Since they're on disk, they get subjected to3073 * AV software screening and normal file consistency rules. So, not necessarily3074 * 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_FALSE3080 * @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. Simplify3094 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 else3102 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 file3119 * (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 else3153 KWFS_LOG(("kwFsTempFileCreateHandle: Out of memory!\n"));3154 SetLastError(ERROR_NOT_ENOUGH_MEMORY);3155 }3156 else3157 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 == cwcFilename3177 && 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 else3232 {3233 KWFS_LOG(("kwFsTempFileCreateW: Out of memory!\n"));3234 SetLastError(ERROR_NOT_ENOUGH_MEMORY);3235 return INVALID_HANDLE_VALUE;3236 }3237 }3238 else3239 {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 we3282 * 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 for3287 * 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/dir3374 * 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 for3379 * 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, roughly3385 * convert it to ASCII/ANSI, and feed it to kwFsIsCachableExtensionA for3386 * 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 >= 03411 && 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 else3434 KWFS_LOG(("Failed to read %#x bytes into cache! err=%u cbActually=%#x\n",3435 cbCache, GetLastError(), cbActually));3436 kHlpFree(pbCache);3437 }3438 else3439 KWFS_LOG(("Failed to allocate %#x bytes for cache!\n", cbCache));3440 }3441 else3442 KWFS_LOG(("File to big to cache! %#llx\n", cbFile.QuadPart));3443 }3444 else3445 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_VALUE3489 || (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 else3515 KWFS_LOG(("Out of memory for handle!\n"));3516 3517 CloseHandle(*phFile);3518 *phFile = INVALID_HANDLE_VALUE;3519 }3520 else3521 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_READ3540 || dwDesiredAccess == FILE_GENERIC_READ)3541 {3542 if (dwShareMode & FILE_SHARE_READ)3543 {3544 if ( !pSecAttrs3545 || ( 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_FILES3588 /* First check for temporary files (cl.exe only). */3589 if ( g_Sandbox.pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL3590 && !(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 #endif3599 3600 /* Then check for include files and similar. */3601 if (dwCreationDisposition == FILE_OPEN_IF)3602 {3603 if ( dwDesiredAccess == GENERIC_READ3604 || dwDesiredAccess == FILE_GENERIC_READ)3605 {3606 if (dwShareMode & FILE_SHARE_READ)3607 {3608 if ( !pSecAttrs3609 || ( 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 else3623 KWFS_LOG(("CreateFileW: incompatible security attributes (nLength=%#x pDesc=%p)\n",3624 pSecAttrs->nLength, pSecAttrs->lpSecurityDescriptor));3625 }3626 else3627 KWFS_LOG(("CreateFileW: incompatible sharing mode %#x\n", dwShareMode));3628 }3629 else3630 KWFS_LOG(("CreateFileW: incompatible desired access %#x\n", dwDesiredAccess));3631 }3632 else3633 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_FILES3658 case KWHANDLETYPE_TEMP_FILE:3659 cbFile = pHandle->u.pTempFile->cbFile;3660 break;3661 case KWHANDLETYPE_TEMP_FILE_MAPPING:3662 #endif3663 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 got3692 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 else3703 {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_FILES3738 case KWHANDLETYPE_TEMP_FILE:3739 cbFile = pHandle->u.pTempFile->cbFile;3740 break;3741 case KWHANDLETYPE_TEMP_FILE_MAPPING:3742 #endif3743 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 got3772 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 else3783 {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 hack3819 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_FILES3831 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 else3879 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_FILES3923 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 do3940 {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 else3955 {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->cbFile4098 && !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_READONLY4242 || fProtect == PAGE_EXECUTE_READ)4243 && dwMaximumSizeHigh == 04244 && ( dwMaximumSizeLow == 04245 || 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_READ4287 && offFileHigh == 04288 && offFileLow == 04289 && (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 > 04358 && 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.cHandles4382 && 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_FILES4391 if (pHandle->enmType == KWHANDLETYPE_TEMP_FILE)4392 {4393 kHlpAssert(pHandle->u.pTempFile->cActiveHandles > 0);4394 pHandle->u.pTempFile->cActiveHandles--;4395 }4396 #endif4397 kHlpFree(pHandle);4398 KWFS_LOG(("CloseHandle(%p) -> TRUE [intercepted handle]\n", hObject));4399 }4400 else4401 KWFS_LOG(("CloseHandle(%p) -> FALSE [intercepted handle] err=%u!\n", hObject, GetLastError()));4402 }4403 else4404 {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 the4455 * directory containing each include file. We cache the result to speed4456 * 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 else4469 {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_FILES4520 { 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 #endif4530 { 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 sandboxed4592 * 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 04603 { TUPLE("CreateThread"), NULL, (KUPTR)kwSandbox_Kernel32_CreateThread },4604 #endif4605 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_FILES4611 { 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 #endif4621 { 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 #endif4642 };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->fNative4657 && 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_324670 return (PPEB)__readfsdword(0x030 /* offset of ProcessEnvironmentBlock in TEB */);4671 #elif K_ARCH == K_ARCH_AMD644672 return (PPEB)__readgsqword(0x060 /* offset of ProcessEnvironmentBlock in TEB */);4673 #else4674 # error "Port me!"4675 #endif4676 }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_FILES4803 PKWFSTEMPFILE pTempFile;4804 #endif4805 PPEB pPeb = kwSandboxGetProcessEnvironmentBlock();4806 pPeb->ProcessParameters->CommandLine = pSandbox->SavedCommandLine;4807 /** @todo lots more to do here! */4808 4809 #ifdef WITH_TEMP_MEMORY_FILES4810 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 #endif4825 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 __try4859 {4860 if (setjmp(g_Sandbox.JmpBuf) == 0)4861 {4862 #if K_ARCH == K_ARCH_AMD644863 *(KU64*)(g_Sandbox.JmpBuf) = 0; /** @todo find other way to prevent longjmp from doing unwind! */4864 #else4865 # error "Port me!"4866 #endif4867 rcExit = pfnWin64Entrypoint(kwSandboxGetProcessEnvironmentBlock(), NULL, NULL, NULL);4868 }4869 else4870 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 else4883 rcExit = 42 + 5;4884 }4885 else4886 rcExit = 42 + 4;4887 4888 kwSandboxCleanup(&g_Sandbox);4889 }4890 else4891 rcExit = 42 + 3;4892 4893 return rcExit;4894 }4895 4896 4897 #if 04898 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 else4931 rc = 1;4932 return rc;4933 }4934 #endif4935 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 inside4964 * 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 else4979 {4980 kwErrPrintf("TODO: Watcom style tool %s\n", pTool->pszPath);4981 rcExit = 42 + 2;4982 }4983 }4984 else4985 {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 else5005 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 are5016 * 4 more zero bytes after the message body to5017 * 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 < cbMsg5037 && 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) < cbMsg5047 && 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 else5073 {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 else5105 {5106 if ( cbTmp == cbMsg5107 && i + 1 == cEnvVars)5108 cbMsg = 0;5109 else5110 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 else5127 kwErrPrintf("Message has %u bytes unknown trailing bytes\n", cbMsg);5128 }5129 else5130 kwErrPrintf("Detected bogus message unpacking environment variables!\n");5131 kHlpFree((void *)papszEnvVars);5132 }5133 else5134 kwErrPrintf("Error allocating papszEnvVars for %u variables\n", cEnvVars);5135 }5136 else5137 kwErrPrintf("Bogus environment variable count: %u (%#x)\n", cEnvVars, cEnvVars);5138 }5139 else5140 kwErrPrintf("Detected bogus message unpacking arguments and environment variable count!\n");5141 kHlpFree((void *)papszArgs);5142 }5143 else5144 kwErrPrintf("Error allocating argv for %u arguments\n", cArgs);5145 }5146 else5147 kwErrPrintf("Bogus argument count: %u (%#x)\n", cArgs, cArgs);5148 }5149 else5150 kwErrPrintf("Detected bogus message unpacking CWD path and argument count!\n");5151 }5152 else5153 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 else5183 {5184 DWORD dwErr = GetLastError();5185 if (cbLeft == cbToWrite)5186 kwErrPrintf("WriteFile failed: %u\n", dwErr);5187 else5188 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 the5205 * 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 else5222 {5223 DWORD dwErr = GetLastError();5224 if (cbLeft == cbToRead)5225 {5226 if ( fMayShutdown5227 && dwErr == ERROR_BROKEN_PIPE)5228 return 1;5229 kwErrPrintf("ReadFile failed: %u\n", dwErr);5230 }5231 else5232 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 15242 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 != NULL5262 && *pszEnd == '\0'5263 && u64Value != 05264 && u64Value != (uintptr_t)INVALID_HANDLE_VALUE5265 && (uintptr_t)u64Value == u64Value)5266 hPipe = (HANDLE)(uintptr_t)u64Value;5267 else5268 {5269 kwErrPrintf("Invalid --pipe argument: %s\n", argv[i]);5270 return 2;5271 }5272 }5273 else5274 {5275 kwErrPrintf("--pipe takes an argument!\n");5276 return 2;5277 }5278 }5279 else if ( strcmp(argv[i], "--help") == 05280 || strcmp(argv[i], "-h") == 05281 || 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") == 05291 || strcmp(argv[i], "-V") == 0)5292 return kbuild_version(argv[0]);5293 else5294 {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 > 45317 && 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 else5323 {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 struct5350 {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 == 05362 && !g_fRestart)5363 continue;5364 }5365 else5366 {5367 kwErrPrintf("Unknown command: '%s'\n", psz);5368 rc = -1;5369 }5370 }5371 }5372 else5373 {5374 kwErrPrintf("Bogus message length: %u (%#x)\n", cbMsg, cbMsg);5375 rc = -1;5376 }5377 }5378 return rc > 0 ? 0 : 1;5379 }5380 5381 #else5382 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 05386 rc = kwExecCmdLine(argv[1], argv[2]);5387 rc = kwExecCmdLine(argv[1], argv[2]);5388 K_NOREF(i);5389 # else5390 // 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 # endif5406 return rc;5407 5408 #endif5409 }5410 -
trunk/src/lib/nt/ntstat.c
r2850 r2851 190 190 * @param pBuf The MY_FILE_ID_FULL_DIR_INFORMATION entry. 191 191 * @param pszPath Optionally, the path for X bit checks. 192 * @remarks Caller sets st_dev. 192 193 */ 193 194 void birdStatFillFromFileIdFullDirInfo(BirdStat_T *pStat, MY_FILE_ID_FULL_DIR_INFORMATION const *pBuf, const char *pszPath) … … 216 217 217 218 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 */ 227 void 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 */ 260 void 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 218 285 int birdStatHandle(HANDLE hFile, BirdStat_T *pStat, const char *pszPath) 219 286 { … … 359 426 360 427 428 /** 429 * Generates a device number from the volume information. 430 * 431 * @returns Device number. 432 * @param pVolInfo Volume information. 433 */ 434 unsigned __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 */ 452 MY_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 361 475 static int birdStatInternal(const char *pszPath, BirdStat_T *pStat, int fFollow) 362 476 { … … 429 543 430 544 /* 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); 432 546 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->VolumeSerialNumber438 | (pVolInfo->VolumeCreationTime.QuadPart << 32);439 547 rc = 0; 440 }441 548 else 442 {443 pStat->st_dev = 0;444 549 rc = birdSetErrnoFromNt(rcNt); 445 }446 550 } 447 551 -
trunk/src/lib/nt/ntstat.h
r2850 r2851 82 82 #ifdef ___nt_ntstuff_h 83 83 void birdStatFillFromFileIdFullDirInfo(BirdStat_T *pStat, MY_FILE_ID_FULL_DIR_INFORMATION const *pBuf, const char *pszPath); 84 void birdStatFillFromFileIdBothDirInfo(BirdStat_T *pStat, MY_FILE_ID_BOTH_DIR_INFORMATION const *pBuf, const char *pszPath); 85 void birdStatFillFromFileBothDirInfo(BirdStat_T *pStat, MY_FILE_BOTH_DIR_INFORMATION const *pBuf, const char *pszPath); 86 MY_NTSTATUS birdQueryVolumeDeviceNumber(HANDLE hFile, MY_FILE_FS_VOLUME_INFORMATION *pVolInfo, size_t cbVolInfo, 87 unsigned __int64 *puDevNo); 88 unsigned __int64 birdVolumeInfoToDeviceNumber(MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo); 84 89 #endif 85 90 -
trunk/src/lib/nt/ntstuff.h
r2713 r2851 199 199 /** The sizeof(MY_FILE_NAMES_INFORMATION) without the FileName. */ 200 200 #define MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION ( (size_t)&((MY_FILE_ID_FULL_DIR_INFORMATION *)0)->FileName ) 201 202 typedef 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 223 typedef 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 ) 201 243 202 244 … … 277 319 } MY_FILE_FS_VOLUME_INFORMATION; 278 320 321 typedef 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 279 329 typedef enum MY_FSINFOCLASS 280 330 { … … 358 408 #define MY_NT_FAILURE(a_ntRc) ((MY_NTSTATUS)(a_ntRc) < 0) 359 409 #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) 360 415 /** @} */ 361 416 -
trunk/src/lib/quote_argv.c
r2838 r2851 7 7 * Copyright (c) 2007-2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net> 8 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 */ 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 25 31 26 32 /******************************************************************************* -
trunk/src/lib/quote_argv.h
r2838 r2851 5 5 6 6 /* 7 * Copyright (c) 20 10knut st. osmundsen <bird-kBuild-spamx@anduin.net>7 * Copyright (c) 2007-2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net> 8 8 * 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: 10 15 * 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. 15 18 * 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. 20 26 * 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. 24 29 */ 25 30 -
trunk/src/lib/quoted_spawn.c
r2413 r2851 5 5 6 6 /* 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 25 31 26 32 /******************************************************************************* -
trunk/src/lib/quoted_spawn.h
r2413 r2851 5 5 6 6 /* 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> 8 8 * 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: 10 15 * 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. 15 18 * 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. 20 26 * 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. 24 29 */ 25 30 -
trunk/src/lib/restartable-syscall-wrappers.c
r2507 r2851 13 13 14 14 /* 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. 32 37 */ 33 38 -
trunk/src/lib/wrapper.c
r2413 r2851 5 5 6 6 /* 7 * Copyright (c) 2007-201 0knut st. osmundsen <bird-kBuild-spamx@anduin.net>7 * Copyright (c) 2007-2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net> 8 8 * 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: 10 15 * 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. 15 18 * 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. 20 26 * 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. 24 29 */ 30 25 31 26 32 /******************************************************************************* … … 35 41 # include <unistd.h> 36 42 #endif 43 37 44 38 45 int main(int argc, char **argv, char **envp) … … 89 96 return pszRetVal ? atol(pszRetVal) : 1; 90 97 } 98
Note:
See TracChangeset
for help on using the changeset viewer.