Changeset 2853 for trunk/src/lib/nt/ntdircache.c
- Timestamp:
- Aug 31, 2016, 10:56:48 PM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/lib/nt/ntdircache.c
r2852 r2853 49 49 //#include <winternl.h> 50 50 51 52 53 /********************************************************************************************************************************* 54 * Defined Constants And Macros * 55 *********************************************************************************************************************************/ 56 /** @def KFSCACHE_CFG_UTF16 57 * Whether to compile in the UTF-16 names support. */ 58 #define KFSCACHE_CFG_UTF16 1 59 /** @def KFSCACHE_CFG_SHORT_NAMES 60 * Whether to compile in the short name support. */ 61 #define KFSCACHE_CFG_SHORT_NAMES 1 62 /** @def KFSCACHE_CFG_PATH_HASH_TAB_SIZE 63 * Size of the path hash table. */ 64 #define KFSCACHE_CFG_PATH_HASH_TAB_SIZE 16381 65 /** The max length paths we consider. */ 66 #define KFSCACHE_CFG_MAX_PATH 1024 67 /** The max ANSI name length. */ 68 #define KFSCACHE_CFG_MAX_ANSI_NAME (256*3 + 16) 69 /** The max UTF-16 name length. */ 70 #define KFSCACHE_CFG_MAX_UTF16_NAME (256*2 + 16) 71 72 73 74 /** Special KFSOBJ::uCacheGen number indicating that it does not apply. */ 75 #define KFSWOBJ_CACHE_GEN_IGNORE KU32_MAX 76 77 /** @def KW_LOG 78 * Generic logging. 79 * @param a Argument list for kFsCacheDbgPrintf */ 80 #ifndef NDEBUG 81 # define KFSCACHE_LOG(a) kFsCacheDbgPrintf a 82 #else 83 # define KFSCACHE_LOG(a) do { } while (0) 84 #endif 85 86 87 /** @name KFSOBJ_TYPE_XXX - KFSOBJ::bObjType 88 * @{ */ 89 /** Directory, type KFSDIR. */ 90 #define KFSOBJ_TYPE_DIR KU8_C(0x01) 91 /** Regular file - type KFSOBJ. */ 92 #define KFSOBJ_TYPE_FILE KU8_C(0x02) 93 /** Other file - type KFSOBJ. */ 94 #define KFSOBJ_TYPE_OTHER KU8_C(0x03) 95 /** Caching of a negative result - type KFSOBJ. 96 * @remarks We will allocate enough space for the largest cache node, so this 97 * can metamorph into any other object should it actually turn up. */ 98 #define KFSOBJ_TYPE_MISSING KU8_C(0x04) 99 ///** Invalidated entry flag. */ 100 //#define KFSOBJ_TYPE_F_INVALID KU8_C(0x20) 101 /** @} */ 102 103 /** @name KFSOBJ_F_XXX - KFSOBJ::fFlags 104 * @{ */ 105 /** Whether the file system update the modified timestamp of directories 106 * when something is removed from it or added to it. 107 * @remarks They say NTFS is the only windows filesystem doing this. */ 108 #define KFSOBJ_F_WORKING_DIR_MTIME KU32_C(0x00000001) 109 /** NTFS file system volume. */ 110 #define KFSOBJ_F_NTFS KU32_C(0x80000000) 111 /** @} */ 112 113 114 #define IS_ALPHA(ch) ( ((ch) >= 'A' && (ch) <= 'Z') || ((ch) >= 'a' && (ch) <= 'z') ) 115 #define IS_SLASH(ch) ((ch) == '\\' || (ch) == '/') 116 117 118 /********************************************************************************************************************************* 119 * Structures and Typedefs * 120 *********************************************************************************************************************************/ 121 /** Pointer to a core object. */ 122 typedef struct KFSOBJ *PKFSOBJ; 123 /** Pointer to a directory object. */ 124 typedef struct KFSDIR *PKFSDIR; 125 /** Pointer to a directory hash table entry. */ 126 typedef struct KFSOBJHASH *PKFSOBJHASH; 127 128 129 /** 130 * Directory hash table entry. 131 * 132 * There can be two of these per directory entry when the short name differs 133 * from the long name. 134 */ 135 typedef struct KFSOBJHASH 136 { 137 /** Pointer to the next entry with the same hash. */ 138 PKFSOBJHASH pNext; 139 /** Pointer to the object. */ 140 PKFSOBJ pObj; 141 } KFSOBJHASH; 142 143 144 /** 145 * Base cache node. 146 */ 147 typedef struct KFSOBJ 148 { 149 /** Magic value (KFSOBJ_MAGIC). */ 150 KU32 u32Magic; 151 /** Number of references. */ 152 KU32 volatile cRefs; 153 /** The cache generation, see KFSWOBJ_CACHE_GEN_IGNORE. */ 154 KU32 uCacheGen; 155 /** The object type, KFSOBJ_TYPE_XXX. */ 156 KU8 bObjType; 157 /** Set if the Stats member is valid, clear if not. */ 158 KBOOL fHaveStats; 159 /** Unused flags. */ 160 KBOOL abUnused[2]; 161 /** Flags, KFSOBJ_F_XXX. */ 162 KU32 fFlags; 163 164 /** Pointer to the parent (directory). 165 * This is only NULL for a root. */ 166 PKFSDIR pParent; 167 168 /** The directory name. (Allocated after the structure.) */ 169 const char *pszName; 170 /** The length of pszName. */ 171 KU16 cchName; 172 /** The length of the parent path (up to where pszName starts). 173 * @note This is valuable when constructing an absolute path to this node by 174 * means of the parent pointer (no need for recursion). */ 175 KU16 cchParent; 176 #ifdef KFSCACHE_CFG_UTF16 177 /** The length of pwszName (in wchar_t's). */ 178 KU16 cwcName; 179 /** The length of the parent UTF-16 path (in wchar_t's). 180 * @note This is valuable when constructing an absolute path to this node by 181 * means of the parent pointer (no need for recursion). */ 182 KU16 cwcParent; 183 /** The UTF-16 object name. (Allocated after the structure.) */ 184 const wchar_t *pwszName; 185 #endif 186 187 #ifdef KFSCACHE_CFG_SHORT_NAMES 188 /** The short object name. (Allocated after the structure, could be same 189 * as pszName.) */ 190 const char *pszShortName; 191 /** The length of pszShortName. */ 192 KU16 cchShortName; 193 /** The length of the short parent path (up to where pszShortName starts). */ 194 KU16 cchShortParent; 195 # ifdef KFSCACHE_CFG_UTF16 196 /** The length of pwszShortName (in wchar_t's). */ 197 KU16 cwcShortName; 198 /** The length of the short parent UTF-16 path (in wchar_t's). */ 199 KU16 cwcShortParent; 200 /** The UTF-16 short object name. (Allocated after the structure, possibly 201 * same as pwszName.) */ 202 const wchar_t *pwszShortName; 203 # endif 204 #endif 205 206 /** Stats - only valid when fHaveStats is set. */ 207 BirdStat_T Stats; 208 } KFSOBJ; 209 210 /** The magic for a KFSOBJ structure (Thelonious Sphere Monk). */ 211 #define KFSOBJ_MAGIC KU32_C(0x19171010) 212 213 214 /** 215 * Directory node in the cache. 216 */ 217 typedef struct KFSDIR 218 { 219 /** The core object information. */ 220 KFSOBJ Obj; 221 222 /** Child objects. */ 223 PKFSOBJ *papChildren; 224 /** The number of child objects. */ 225 KU32 cChildren; 226 227 /** The size of the hash table. 228 * @remarks The hash table is optional and only used when there are a lot of 229 * entries in the directory. */ 230 KU32 cHashTab; 231 /** Pointer to the hash table. 232 * @todo this isn't quite there yet, structure wise. sigh. */ 233 PKFSOBJHASH paHashTab; 234 235 /** Handle to the directory (we generally keep it open). */ 236 HANDLE hDir; 237 /** The device number we queried/inherited when opening it. */ 238 KU64 uDevNo; 239 240 /** Set if populated. */ 241 KBOOL fPopulated; 242 } KFSDIR; 243 244 245 /** 246 * Lookup errors. 247 */ 248 typedef enum KFSLOOKUPERROR 249 { 250 /** Lookup was a success. */ 251 KFSLOOKUPERROR_SUCCESS = 0, 252 /** A path component was not found. */ 253 KFSLOOKUPERROR_PATH_COMP_NOT_FOUND, 254 /** A path component is not a directory. */ 255 KFSLOOKUPERROR_PATH_COMP_NOT_DIR, 256 /** The final path entry is not a directory (trailing slash). */ 257 KFSLOOKUPERROR_NOT_DIR, 258 /** Not found. */ 259 KFSLOOKUPERROR_NOT_FOUND, 260 /** The path is too long. */ 261 KFSLOOKUPERROR_PATH_TOO_LONG, 262 /** Unsupported path type. */ 263 KFSLOOKUPERROR_UNSUPPORTED, 264 /** We're out of memory. */ 265 KFSLOOKUPERROR_OUT_OF_MEMORY, 266 267 /** Error opening directory. */ 268 KFSLOOKUPERROR_DIR_OPEN_ERROR, 269 /** Error reading directory. */ 270 KFSLOOKUPERROR_DIR_READ_ERROR, 271 /** UTF-16 to ANSI conversion error. */ 272 KFSLOOKUPERROR_ANSI_CONVERSION_ERROR, 273 /** ANSI to UTF-16 conversion error. */ 274 KFSLOOKUPERROR_UTF16_CONVERSION_ERROR, 275 /** Internal error. */ 276 KFSLOOKUPERROR_INTERNAL_ERROR 277 } KFSLOOKUPERROR; 278 279 280 /** Pointer to an ANSI path hash table entry. */ 281 typedef struct KFSHASHA *PKFSHASHA; 282 /** 283 * ANSI file system path hash table entry. 284 * The path hash table allows us to skip parsing and walking a path. 285 */ 286 typedef struct KFSHASHA 287 { 288 /** Next entry with the same hash table slot. */ 289 PKFSHASHA pNext; 290 /** Path hash value. */ 291 KU32 uHashPath; 292 /** The path length. */ 293 KU32 cchPath; 294 /** The cache generation ID. */ 295 KU32 uCacheGen; 296 /** The lookup error (when pFsObj is NULL). */ 297 KFSLOOKUPERROR enmError; 298 /** The path. (Allocated after the structure.) */ 299 const char *pszPath; 300 /** Pointer to the matching FS object. 301 * This is NULL for negative path entries? */ 302 PKFSOBJ pFsObj; 303 } KFSHASHA; 304 305 306 #ifdef KFSCACHE_CFG_UTF16 307 /** Pointer to an UTF-16 path hash table entry. */ 308 typedef struct KFSHASHW *PKFSHASHW; 309 /** 310 * UTF-16 file system path hash table entry. The path hash table allows us 311 * to skip parsing and walking a path. 312 */ 313 typedef struct KFSHASHW 314 { 315 /** Next entry with the same hash table slot. */ 316 PKFSHASHW pNext; 317 /** Path hash value. */ 318 KU32 uHashPath; 319 /** The path length (in wchar_t units). */ 320 KU32 cwcPath; 321 /** The cache generation ID. */ 322 KU32 uCacheGen; 323 /** The lookup error (when pFsObj is NULL). */ 324 KFSLOOKUPERROR enmError; 325 /** The path. (Allocated after the structure.) */ 326 const wchar_t *pwszPath; 327 /** Pointer to the matching FS object. 328 * This is NULL for negative path entries? */ 329 PKFSOBJ pFsObj; 330 } KFSHASHW; 331 #endif 332 333 334 /** @name KFSCACHE_F_XXX 335 * @{ */ 336 /** Whether to cache missing directory entries (KFSOBJ_TYPE_MISSING). */ 337 #define KFSCACHE_F_MISSING_OBJECTS KU32_C(0x00000001) 338 /** Whether to cache missing paths. */ 339 #define KFSCACHE_F_MISSING_PATHS KU32_C(0x00000002) 340 /** @} */ 341 342 343 /** Pointer to a cache. */ 344 typedef struct KFSCACHE *PKFSCACHE; 345 /** 346 * Directory cache instance. 347 */ 348 typedef struct KFSCACHE 349 { 350 /** Magic value (KFSCACHE_MAGIC). */ 351 KU32 u32Magic; 352 /** Cache flags. */ 353 KU32 fFlags; 354 355 /** The current cache generation for objects that already exists. */ 356 KU32 uGeneration; 357 /** The current cache generation for missing objects, negative results, ++. */ 358 KU32 uGenerationMissing; 359 360 /** Number of cache objects. */ 361 KSIZE cObjects; 362 /** Memory occupied by the cache object structures. */ 363 KSIZE cbObjects; 364 /** Number of lookups. */ 365 KSIZE cLookups; 366 /** Number of hits in the path hash tables. */ 367 KSIZE cPathHashHits; 368 /** Number of hits walking the file system hierarchy. */ 369 KSIZE cWalkHits; 370 371 /** The root directory. */ 372 KFSDIR RootDir; 373 374 /** File system hash table for ANSI filename strings. */ 375 PKFSHASHA apAnsiPaths[KFSCACHE_CFG_PATH_HASH_TAB_SIZE]; 376 /** Number of paths in the apAnsiPaths hash table. */ 377 KSIZE cAnsiPaths; 378 /** Number of collisions in the apAnsiPaths hash table. */ 379 KSIZE cAnsiPathCollisions; 380 /** Amount of memory used by the path entries. */ 381 KSIZE cbAnsiPaths; 382 383 #ifdef KFSCACHE_CFG_UTF16 384 /** Number of paths in the apUtf16Paths hash table. */ 385 KSIZE cUtf16Paths; 386 /** Number of collisions in the apUtf16Paths hash table. */ 387 KSIZE cUtf16PathCollisions; 388 /** Amount of memory used by the UTF-16 path entries. */ 389 KSIZE cbUtf16Paths; 390 /** File system hash table for UTF-16 filename strings. */ 391 PKFSHASHW apUtf16Paths[KFSCACHE_CFG_PATH_HASH_TAB_SIZE]; 392 #endif 393 } KFSCACHE; 394 395 /** Magic value for KFSCACHE::u32Magic (Jon Batiste). */ 396 #define KFSCACHE_MAGIC KU32_C(0x19861111) 397 398 399 /********************************************************************************************************************************* 400 * Internal Functions * 401 *********************************************************************************************************************************/ 402 KU32 kFsCacheObjRelease(PKFSCACHE pCache, PKFSOBJ pObj); 51 #include "kFsCache.h" 52 53 54 403 55 404 56 … … 425 77 * @param ... Format argument. 426 78 */ 427 staticvoid kFsCacheDbgPrintfV(const char *pszFormat, va_list va)79 void kFsCacheDbgPrintfV(const char *pszFormat, va_list va) 428 80 { 429 81 if (1) … … 444 96 * @param ... Format argument. 445 97 */ 446 staticvoid kFsCacheDbgPrintf(const char *pszFormat, ...)98 void kFsCacheDbgPrintf(const char *pszFormat, ...) 447 99 { 448 100 if (1) … … 927 579 pHashEntry->uCacheGen = pCache->uGenerationMissing; 928 580 else 929 pHashEntry->uCacheGen = KFS WOBJ_CACHE_GEN_IGNORE;581 pHashEntry->uCacheGen = KFSOBJ_CACHE_GEN_IGNORE; 930 582 931 583 pHashEntry->pNext = pCache->apAnsiPaths[idxHashTab]; … … 969 621 pHashEntry->uCacheGen = pCache->uGenerationMissing; 970 622 else 971 pHashEntry->uCacheGen = KFS WOBJ_CACHE_GEN_IGNORE;623 pHashEntry->uCacheGen = KFSOBJ_CACHE_GEN_IGNORE; 972 624 973 625 pHashEntry->pNext = pCache->apUtf16Paths[idxHashTab]; … … 1026 678 * @param penmError Where to explain failures. 1027 679 */ 1028 staticPKFSOBJ kFsCacheCreateObject(PKFSCACHE pCache, PKFSDIR pParent,1029 680 PKFSOBJ kFsCacheCreateObject(PKFSCACHE pCache, PKFSDIR pParent, 681 char const *pszName, KU16 cchName, wchar_t const *pwszName, KU16 cwcName, 1030 682 #ifdef KFSCACHE_CFG_SHORT_NAMES 1031 1032 #endif 1033 683 char const *pszShortName, KU16 cchShortName, wchar_t const *pwszShortName, KU16 cwcShortName, 684 #endif 685 KU8 bObjType, KFSLOOKUPERROR *penmError) 1034 686 { 1035 687 /* … … 1149 801 * @param penmError Where to explain failures. 1150 802 */ 1151 staticPKFSOBJ kFsCacheCreateObjectW(PKFSCACHE pCache, PKFSDIR pParent, wchar_t const *pwszName, KU32 cwcName,803 PKFSOBJ kFsCacheCreateObjectW(PKFSCACHE pCache, PKFSDIR pParent, wchar_t const *pwszName, KU32 cwcName, 1152 804 #ifdef KFSCACHE_CFG_SHORT_NAMES 1153 1154 #endif 1155 805 wchar_t const *pwszShortName, KU32 cwcShortName, 806 #endif 807 KU8 bObjType, KFSLOOKUPERROR *penmError) 1156 808 { 1157 809 /* Convert names to ANSI first so we know their lengths. */ … … 2006 1658 if (offEnd >= cchPath) 2007 1659 { 2008 if ( pChild->uCacheGen == KFS WOBJ_CACHE_GEN_IGNORE1660 if ( pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE 2009 1661 || pChild->uCacheGen == (pChild->bObjType != KFSOBJ_TYPE_MISSING ? pCache->uGeneration : pCache->uGenerationMissing) 2010 1662 || kFsCacheRefreshObj(pCache, pChild, penmError)) … … 2019 1671 { 2020 1672 kHlpAssert(pChild->bObjType == KFSOBJ_TYPE_MISSING); 2021 kHlpAssert(pChild->uCacheGen == KFS WOBJ_CACHE_GEN_IGNORE || pChild->uCacheGen == pCache->uGenerationMissing);1673 kHlpAssert(pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE || pChild->uCacheGen == pCache->uGenerationMissing); 2022 1674 return pChild; 2023 1675 } … … 2056 1708 */ 2057 1709 if ( pParent->fPopulated 2058 && ( pParent->Obj.uCacheGen == KFS WOBJ_CACHE_GEN_IGNORE1710 && ( pParent->Obj.uCacheGen == KFSOBJ_CACHE_GEN_IGNORE 2059 1711 || pParent->Obj.uCacheGen == pCache->uGeneration) ) 2060 1712 { /* likely */ } … … 2094 1746 { 2095 1747 if ( pChild->bObjType != KFSOBJ_TYPE_MISSING 2096 || pChild->uCacheGen == KFS WOBJ_CACHE_GEN_IGNORE1748 || pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE 2097 1749 || pChild->uCacheGen == pCache->uGenerationMissing 2098 1750 || kFsCacheRefreshMissing(pCache, pChild, penmError) ) … … 2114 1766 return NULL; 2115 1767 } 2116 else if ( pChild->uCacheGen == KFS WOBJ_CACHE_GEN_IGNORE1768 else if ( pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE 2117 1769 || pChild->uCacheGen == pCache->uGenerationMissing) 2118 1770 { … … 2194 1846 if (offEnd >= cwcPath) 2195 1847 { 2196 if ( pChild->uCacheGen == KFS WOBJ_CACHE_GEN_IGNORE1848 if ( pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE 2197 1849 || pChild->uCacheGen == (pChild->bObjType != KFSOBJ_TYPE_MISSING ? pCache->uGeneration : pCache->uGenerationMissing) 2198 1850 || kFsCacheRefreshObj(pCache, pChild, penmError)) … … 2207 1859 { 2208 1860 kHlpAssert(pChild->bObjType == KFSOBJ_TYPE_MISSING); 2209 kHlpAssert(pChild->uCacheGen == KFS WOBJ_CACHE_GEN_IGNORE || pChild->uCacheGen == pCache->uGenerationMissing);1861 kHlpAssert(pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE || pChild->uCacheGen == pCache->uGenerationMissing); 2210 1862 return pChild; 2211 1863 } … … 2244 1896 */ 2245 1897 if ( pParent->fPopulated 2246 && ( pParent->Obj.uCacheGen == KFS WOBJ_CACHE_GEN_IGNORE1898 && ( pParent->Obj.uCacheGen == KFSOBJ_CACHE_GEN_IGNORE 2247 1899 || pParent->Obj.uCacheGen == pCache->uGeneration) ) 2248 1900 { /* likely */ } … … 2282 1934 { 2283 1935 if ( pChild->bObjType != KFSOBJ_TYPE_MISSING 2284 || pChild->uCacheGen == KFS WOBJ_CACHE_GEN_IGNORE1936 || pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE 2285 1937 || pChild->uCacheGen == pCache->uGenerationMissing 2286 1938 || kFsCacheRefreshMissing(pCache, pChild, penmError) ) … … 2302 1954 return NULL; 2303 1955 } 2304 else if ( pChild->uCacheGen == KFS WOBJ_CACHE_GEN_IGNORE1956 else if ( pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE 2305 1957 || pChild->uCacheGen == pCache->uGenerationMissing) 2306 1958 { … … 2487 2139 && kHlpMemComp(pHashEntry->pszPath, pszPath, cchPath) == 0) 2488 2140 { 2489 if ( pHashEntry->uCacheGen == KFS WOBJ_CACHE_GEN_IGNORE2141 if ( pHashEntry->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE 2490 2142 || pHashEntry->uCacheGen == pCache->uGeneration 2491 2143 || (pHashEntry = kFsCacheRefreshPathA(pCache, pHashEntry, idxHashTab)) ) … … 2576 2228 && kHlpMemComp(pHashEntry->pwszPath, pwszPath, cwcPath) == 0) 2577 2229 { 2578 if ( pHashEntry->uCacheGen == KFS WOBJ_CACHE_GEN_IGNORE2230 if ( pHashEntry->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE 2579 2231 || pHashEntry->uCacheGen == pCache->uGeneration 2580 2232 || (pHashEntry = kFsCacheRefreshPathW(pCache, pHashEntry, idxHashTab)) ) … … 2707 2359 pCache->RootDir.Obj.u32Magic = KFSOBJ_MAGIC; 2708 2360 pCache->RootDir.Obj.cRefs = 1; 2709 pCache->RootDir.Obj.uCacheGen = KFS WOBJ_CACHE_GEN_IGNORE;2361 pCache->RootDir.Obj.uCacheGen = KFSOBJ_CACHE_GEN_IGNORE; 2710 2362 pCache->RootDir.Obj.bObjType = KFSOBJ_TYPE_DIR; 2711 2363 pCache->RootDir.Obj.fHaveStats = K_FALSE;
Note:
See TracChangeset
for help on using the changeset viewer.