[2831] | 1 | /* $Id: kFsCache.c 3381 2020-06-12 11:36:10Z bird $ */
|
---|
| 2 | /** @file
|
---|
[2851] | 3 | * ntdircache.c - NT directory content cache.
|
---|
[2831] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
| 7 | * Copyright (c) 2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
|
---|
| 8 | *
|
---|
[2851] | 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:
|
---|
[2831] | 15 | *
|
---|
[2851] | 16 | * The above copyright notice and this permission notice shall be included
|
---|
| 17 | * in all copies or substantial portions of the Software.
|
---|
[2831] | 18 | *
|
---|
[2851] | 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.
|
---|
[2831] | 26 | *
|
---|
[2851] | 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.
|
---|
[2831] | 29 | */
|
---|
| 30 |
|
---|
| 31 |
|
---|
| 32 | /*********************************************************************************************************************************
|
---|
| 33 | * Header Files *
|
---|
| 34 | *********************************************************************************************************************************/
|
---|
| 35 | #include <k/kHlp.h>
|
---|
| 36 |
|
---|
[2851] | 37 | #include "nthlp.h"
|
---|
| 38 | #include "ntstat.h"
|
---|
| 39 |
|
---|
[2831] | 40 | #include <stdio.h>
|
---|
[2852] | 41 | #include <mbstring.h>
|
---|
| 42 | #include <wchar.h>
|
---|
[2930] | 43 | #ifdef _MSC_VER
|
---|
| 44 | # include <intrin.h>
|
---|
| 45 | #endif
|
---|
[2851] | 46 | //#include <setjmp.h>
|
---|
| 47 | //#include <ctype.h>
|
---|
[2831] | 48 |
|
---|
[2844] | 49 |
|
---|
[2851] | 50 | //#include <Windows.h>
|
---|
| 51 | //#include <winternl.h>
|
---|
[2831] | 52 |
|
---|
[2853] | 53 | #include "kFsCache.h"
|
---|
[2831] | 54 |
|
---|
[2844] | 55 |
|
---|
[2862] | 56 | /*********************************************************************************************************************************
|
---|
| 57 | * Defined Constants And Macros *
|
---|
| 58 | *********************************************************************************************************************************/
|
---|
| 59 | /** @def KFSCACHE_LOG2
|
---|
| 60 | * More logging. */
|
---|
| 61 | #if 0
|
---|
| 62 | # define KFSCACHE_LOG2(a) KFSCACHE_LOG(a)
|
---|
| 63 | #else
|
---|
| 64 | # define KFSCACHE_LOG2(a) do { } while (0)
|
---|
| 65 | #endif
|
---|
[2833] | 66 |
|
---|
[3381] | 67 | /** The minimum time between a directory last populated time and its
|
---|
| 68 | * modification time for the cache to consider it up-to-date.
|
---|
| 69 | *
|
---|
| 70 | * This helps work around races between us reading a directory and someone else
|
---|
| 71 | * adding / removing files and directories to /from it. Given that the
|
---|
| 72 | * effective time resolution typically is around 2000Hz these days, unless you
|
---|
| 73 | * use the new *TimePrecise API variants, there is plenty of room for a race
|
---|
| 74 | * here.
|
---|
| 75 | *
|
---|
| 76 | * The current value is 20ms in NT time units (100ns each), which translates
|
---|
| 77 | * to a 50Hz time update frequency. */
|
---|
| 78 | #define KFSCACHE_MIN_LAST_POPULATED_VS_WRITE (20*1000*10)
|
---|
[2833] | 79 |
|
---|
[3381] | 80 |
|
---|
[2863] | 81 | /*********************************************************************************************************************************
|
---|
| 82 | * Structures and Typedefs *
|
---|
| 83 | *********************************************************************************************************************************/
|
---|
| 84 | /**
|
---|
| 85 | * Used by the code re-populating a directory.
|
---|
| 86 | */
|
---|
| 87 | typedef struct KFSDIRREPOP
|
---|
| 88 | {
|
---|
| 89 | /** The old papChildren array. */
|
---|
| 90 | PKFSOBJ *papOldChildren;
|
---|
| 91 | /** Number of children in the array. */
|
---|
| 92 | KU32 cOldChildren;
|
---|
| 93 | /** The index into papOldChildren we expect to find the next entry. */
|
---|
| 94 | KU32 iNextOldChild;
|
---|
| 95 | /** Add this to iNextOldChild . */
|
---|
| 96 | KI32 cNextOldChildInc;
|
---|
| 97 | /** Pointer to the cache (name changes). */
|
---|
| 98 | PKFSCACHE pCache;
|
---|
| 99 | } KFSDIRREPOP;
|
---|
| 100 | /** Pointer to directory re-population data. */
|
---|
| 101 | typedef KFSDIRREPOP *PKFSDIRREPOP;
|
---|
[2851] | 102 |
|
---|
[2862] | 103 |
|
---|
[2863] | 104 |
|
---|
[2948] | 105 | /*********************************************************************************************************************************
|
---|
| 106 | * Internal Functions *
|
---|
| 107 | *********************************************************************************************************************************/
|
---|
| 108 | static KBOOL kFsCacheRefreshObj(PKFSCACHE pCache, PKFSOBJ pObj, KFSLOOKUPERROR *penmError);
|
---|
[2863] | 109 |
|
---|
[2948] | 110 |
|
---|
[2851] | 111 | /**
|
---|
| 112 | * Retains a reference to a cache object, internal version.
|
---|
| 113 | *
|
---|
| 114 | * @returns pObj
|
---|
| 115 | * @param pObj The object.
|
---|
| 116 | */
|
---|
| 117 | K_INLINE PKFSOBJ kFsCacheObjRetainInternal(PKFSOBJ pObj)
|
---|
[2833] | 118 | {
|
---|
[2851] | 119 | KU32 cRefs = ++pObj->cRefs;
|
---|
| 120 | kHlpAssert(cRefs < 16384);
|
---|
| 121 | K_NOREF(cRefs);
|
---|
| 122 | return pObj;
|
---|
| 123 | }
|
---|
[2833] | 124 |
|
---|
[2832] | 125 |
|
---|
[2851] | 126 | #ifndef NDEBUG
|
---|
[2844] | 127 |
|
---|
[2831] | 128 | /**
|
---|
[2832] | 129 | * Debug printing.
|
---|
| 130 | * @param pszFormat Debug format string.
|
---|
| 131 | * @param ... Format argument.
|
---|
| 132 | */
|
---|
[2853] | 133 | void kFsCacheDbgPrintfV(const char *pszFormat, va_list va)
|
---|
[2832] | 134 | {
|
---|
[2851] | 135 | if (1)
|
---|
[2832] | 136 | {
|
---|
[2833] | 137 | DWORD const dwSavedErr = GetLastError();
|
---|
| 138 |
|
---|
[2832] | 139 | fprintf(stderr, "debug: ");
|
---|
| 140 | vfprintf(stderr, pszFormat, va);
|
---|
[2833] | 141 |
|
---|
| 142 | SetLastError(dwSavedErr);
|
---|
[2832] | 143 | }
|
---|
| 144 | }
|
---|
| 145 |
|
---|
| 146 |
|
---|
| 147 | /**
|
---|
| 148 | * Debug printing.
|
---|
| 149 | * @param pszFormat Debug format string.
|
---|
| 150 | * @param ... Format argument.
|
---|
| 151 | */
|
---|
[2853] | 152 | void kFsCacheDbgPrintf(const char *pszFormat, ...)
|
---|
[2832] | 153 | {
|
---|
[2851] | 154 | if (1)
|
---|
[2832] | 155 | {
|
---|
| 156 | va_list va;
|
---|
| 157 | va_start(va, pszFormat);
|
---|
[2851] | 158 | kFsCacheDbgPrintfV(pszFormat, va);
|
---|
[2832] | 159 | va_end(va);
|
---|
| 160 | }
|
---|
| 161 | }
|
---|
| 162 |
|
---|
[2851] | 163 | #endif /* !NDEBUG */
|
---|
[2832] | 164 |
|
---|
[2833] | 165 |
|
---|
| 166 |
|
---|
[2832] | 167 | /**
|
---|
[2831] | 168 | * Hashes a string.
|
---|
| 169 | *
|
---|
| 170 | * @returns 32-bit string hash.
|
---|
| 171 | * @param pszString String to hash.
|
---|
| 172 | */
|
---|
[2851] | 173 | static KU32 kFsCacheStrHash(const char *pszString)
|
---|
[2831] | 174 | {
|
---|
| 175 | /* This algorithm was created for sdbm (a public-domain reimplementation of
|
---|
| 176 | ndbm) database library. it was found to do well in scrambling bits,
|
---|
| 177 | causing better distribution of the keys and fewer splits. it also happens
|
---|
| 178 | to be a good general hashing function with good distribution. the actual
|
---|
| 179 | function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
|
---|
| 180 | is the faster version used in gawk. [there is even a faster, duff-device
|
---|
| 181 | version] the magic constant 65599 was picked out of thin air while
|
---|
| 182 | experimenting with different constants, and turns out to be a prime.
|
---|
| 183 | this is one of the algorithms used in berkeley db (see sleepycat) and
|
---|
| 184 | elsewhere. */
|
---|
| 185 | KU32 uHash = 0;
|
---|
| 186 | KU32 uChar;
|
---|
| 187 | while ((uChar = (unsigned char)*pszString++) != 0)
|
---|
| 188 | uHash = uChar + (uHash << 6) + (uHash << 16) - uHash;
|
---|
| 189 | return uHash;
|
---|
| 190 | }
|
---|
| 191 |
|
---|
| 192 |
|
---|
[2833] | 193 | /**
|
---|
| 194 | * Hashes a string.
|
---|
| 195 | *
|
---|
| 196 | * @returns The string length.
|
---|
| 197 | * @param pszString String to hash.
|
---|
| 198 | * @param puHash Where to return the 32-bit string hash.
|
---|
| 199 | */
|
---|
[2851] | 200 | static KSIZE kFsCacheStrHashEx(const char *pszString, KU32 *puHash)
|
---|
[2833] | 201 | {
|
---|
| 202 | const char * const pszStart = pszString;
|
---|
| 203 | KU32 uHash = 0;
|
---|
| 204 | KU32 uChar;
|
---|
| 205 | while ((uChar = (unsigned char)*pszString) != 0)
|
---|
| 206 | {
|
---|
| 207 | uHash = uChar + (uHash << 6) + (uHash << 16) - uHash;
|
---|
| 208 | pszString++;
|
---|
| 209 | }
|
---|
| 210 | *puHash = uHash;
|
---|
| 211 | return pszString - pszStart;
|
---|
| 212 | }
|
---|
[2831] | 213 |
|
---|
[2833] | 214 |
|
---|
[2832] | 215 | /**
|
---|
[2861] | 216 | * Hashes a substring.
|
---|
[2833] | 217 | *
|
---|
[2861] | 218 | * @returns 32-bit substring hash.
|
---|
| 219 | * @param pchString Pointer to the substring (not terminated).
|
---|
| 220 | * @param cchString The length of the substring.
|
---|
| 221 | */
|
---|
[2930] | 222 | static KU32 kFsCacheStrHashN(const char *pchString, KSIZE cchString)
|
---|
[2861] | 223 | {
|
---|
| 224 | KU32 uHash = 0;
|
---|
| 225 | while (cchString-- > 0)
|
---|
| 226 | {
|
---|
[2930] | 227 | KU32 uChar = (unsigned char)*pchString++;
|
---|
[2861] | 228 | uHash = uChar + (uHash << 6) + (uHash << 16) - uHash;
|
---|
| 229 | }
|
---|
| 230 | return uHash;
|
---|
| 231 | }
|
---|
| 232 |
|
---|
| 233 |
|
---|
| 234 | /**
|
---|
| 235 | * Hashes a UTF-16 string.
|
---|
| 236 | *
|
---|
[2833] | 237 | * @returns The string length in wchar_t units.
|
---|
| 238 | * @param pwszString String to hash.
|
---|
| 239 | * @param puHash Where to return the 32-bit string hash.
|
---|
| 240 | */
|
---|
[2851] | 241 | static KSIZE kFsCacheUtf16HashEx(const wchar_t *pwszString, KU32 *puHash)
|
---|
[2833] | 242 | {
|
---|
| 243 | const wchar_t * const pwszStart = pwszString;
|
---|
| 244 | KU32 uHash = 0;
|
---|
| 245 | KU32 uChar;
|
---|
| 246 | while ((uChar = *pwszString) != 0)
|
---|
| 247 | {
|
---|
| 248 | uHash = uChar + (uHash << 6) + (uHash << 16) - uHash;
|
---|
| 249 | pwszString++;
|
---|
| 250 | }
|
---|
| 251 | *puHash = uHash;
|
---|
| 252 | return pwszString - pwszStart;
|
---|
| 253 | }
|
---|
| 254 |
|
---|
[2861] | 255 |
|
---|
| 256 | /**
|
---|
| 257 | * Hashes a UTF-16 substring.
|
---|
| 258 | *
|
---|
| 259 | * @returns 32-bit substring hash.
|
---|
| 260 | * @param pwcString Pointer to the substring (not terminated).
|
---|
| 261 | * @param cchString The length of the substring (in wchar_t's).
|
---|
| 262 | */
|
---|
| 263 | static KU32 kFsCacheUtf16HashN(const wchar_t *pwcString, KSIZE cwcString)
|
---|
| 264 | {
|
---|
| 265 | KU32 uHash = 0;
|
---|
| 266 | while (cwcString-- > 0)
|
---|
| 267 | {
|
---|
| 268 | KU32 uChar = *pwcString++;
|
---|
| 269 | uHash = uChar + (uHash << 6) + (uHash << 16) - uHash;
|
---|
| 270 | }
|
---|
| 271 | return uHash;
|
---|
| 272 | }
|
---|
| 273 |
|
---|
[2833] | 274 |
|
---|
| 275 | /**
|
---|
[2863] | 276 | * For use when kFsCacheIAreEqualW hit's something non-trivial.
|
---|
| 277 | *
|
---|
| 278 | * @returns K_TRUE if equal, K_FALSE if different.
|
---|
| 279 | * @param pwcName1 The first string.
|
---|
| 280 | * @param pwcName2 The second string.
|
---|
| 281 | * @param cwcName The length of the two strings (in wchar_t's).
|
---|
| 282 | */
|
---|
| 283 | KBOOL kFsCacheIAreEqualSlowW(const wchar_t *pwcName1, const wchar_t *pwcName2, KU16 cwcName)
|
---|
| 284 | {
|
---|
| 285 | MY_UNICODE_STRING UniStr1 = { cwcName * sizeof(wchar_t), cwcName * sizeof(wchar_t), (wchar_t *)pwcName1 };
|
---|
| 286 | MY_UNICODE_STRING UniStr2 = { cwcName * sizeof(wchar_t), cwcName * sizeof(wchar_t), (wchar_t *)pwcName2 };
|
---|
| 287 | return g_pfnRtlEqualUnicodeString(&UniStr1, &UniStr2, TRUE /*fCaseInsensitive*/);
|
---|
| 288 | }
|
---|
| 289 |
|
---|
| 290 |
|
---|
| 291 | /**
|
---|
| 292 | * Compares two UTF-16 strings in a case-insensitive fashion.
|
---|
| 293 | *
|
---|
| 294 | * You would think we should be using _wscnicmp here instead, however it is
|
---|
| 295 | * locale dependent and defaults to ASCII upper/lower handling setlocale hasn't
|
---|
| 296 | * been called.
|
---|
| 297 | *
|
---|
| 298 | * @returns K_TRUE if equal, K_FALSE if different.
|
---|
| 299 | * @param pwcName1 The first string.
|
---|
| 300 | * @param pwcName2 The second string.
|
---|
| 301 | * @param cwcName The length of the two strings (in wchar_t's).
|
---|
| 302 | */
|
---|
| 303 | K_INLINE KBOOL kFsCacheIAreEqualW(const wchar_t *pwcName1, const wchar_t *pwcName2, KU32 cwcName)
|
---|
| 304 | {
|
---|
| 305 | while (cwcName > 0)
|
---|
| 306 | {
|
---|
| 307 | wchar_t wc1 = *pwcName1;
|
---|
| 308 | wchar_t wc2 = *pwcName2;
|
---|
| 309 | if (wc1 == wc2)
|
---|
| 310 | { /* not unlikely */ }
|
---|
| 311 | else if ( (KU16)wc1 < (KU16)0xc0 /* U+00C0 is the first upper/lower letter after 'z'. */
|
---|
| 312 | && (KU16)wc2 < (KU16)0xc0)
|
---|
| 313 | {
|
---|
| 314 | /* ASCII upper case. */
|
---|
| 315 | if ((KU16)wc1 - (KU16)0x61 < (KU16)26)
|
---|
| 316 | wc1 &= ~(wchar_t)0x20;
|
---|
| 317 | if ((KU16)wc2 - (KU16)0x61 < (KU16)26)
|
---|
| 318 | wc2 &= ~(wchar_t)0x20;
|
---|
| 319 | if (wc1 != wc2)
|
---|
| 320 | return K_FALSE;
|
---|
| 321 | }
|
---|
| 322 | else
|
---|
| 323 | return kFsCacheIAreEqualSlowW(pwcName1, pwcName2, (KU16)cwcName);
|
---|
| 324 |
|
---|
| 325 | pwcName2++;
|
---|
| 326 | pwcName1++;
|
---|
| 327 | cwcName--;
|
---|
| 328 | }
|
---|
| 329 |
|
---|
| 330 | return K_TRUE;
|
---|
| 331 | }
|
---|
| 332 |
|
---|
| 333 |
|
---|
| 334 | /**
|
---|
[2833] | 335 | * Looks for '..' in the path.
|
---|
| 336 | *
|
---|
| 337 | * @returns K_TRUE if '..' component found, K_FALSE if not.
|
---|
| 338 | * @param pszPath The path.
|
---|
| 339 | * @param cchPath The length of the path.
|
---|
| 340 | */
|
---|
[2852] | 341 | static KBOOL kFsCacheHasDotDotA(const char *pszPath, KSIZE cchPath)
|
---|
[2833] | 342 | {
|
---|
| 343 | const char *pchDot = (const char *)kHlpMemChr(pszPath, '.', cchPath);
|
---|
| 344 | while (pchDot)
|
---|
| 345 | {
|
---|
| 346 | if (pchDot[1] != '.')
|
---|
[2857] | 347 | {
|
---|
| 348 | pchDot++;
|
---|
| 349 | pchDot = (const char *)kHlpMemChr(pchDot, '.', &pszPath[cchPath] - pchDot);
|
---|
| 350 | }
|
---|
[2833] | 351 | else
|
---|
| 352 | {
|
---|
| 353 | char ch;
|
---|
[2857] | 354 | if ( (ch = pchDot[2]) != '\0'
|
---|
[2833] | 355 | && IS_SLASH(ch))
|
---|
| 356 | {
|
---|
| 357 | if (pchDot == pszPath)
|
---|
| 358 | return K_TRUE;
|
---|
| 359 | ch = pchDot[-1];
|
---|
| 360 | if ( IS_SLASH(ch)
|
---|
| 361 | || ch == ':')
|
---|
| 362 | return K_TRUE;
|
---|
| 363 | }
|
---|
| 364 | pchDot = (const char *)kHlpMemChr(pchDot + 2, '.', &pszPath[cchPath] - pchDot - 2);
|
---|
| 365 | }
|
---|
| 366 | }
|
---|
| 367 |
|
---|
| 368 | return K_FALSE;
|
---|
| 369 | }
|
---|
| 370 |
|
---|
| 371 |
|
---|
[2851] | 372 | /**
|
---|
[2852] | 373 | * Looks for '..' in the path.
|
---|
| 374 | *
|
---|
| 375 | * @returns K_TRUE if '..' component found, K_FALSE if not.
|
---|
| 376 | * @param pwszPath The path.
|
---|
| 377 | * @param cwcPath The length of the path (in wchar_t's).
|
---|
| 378 | */
|
---|
| 379 | static KBOOL kFsCacheHasDotDotW(const wchar_t *pwszPath, KSIZE cwcPath)
|
---|
| 380 | {
|
---|
| 381 | const wchar_t *pwcDot = wmemchr(pwszPath, '.', cwcPath);
|
---|
| 382 | while (pwcDot)
|
---|
| 383 | {
|
---|
| 384 | if (pwcDot[1] != '.')
|
---|
[2857] | 385 | {
|
---|
| 386 | pwcDot++;
|
---|
| 387 | pwcDot = wmemchr(pwcDot, '.', &pwszPath[cwcPath] - pwcDot);
|
---|
| 388 | }
|
---|
[2852] | 389 | else
|
---|
| 390 | {
|
---|
| 391 | wchar_t wch;
|
---|
[2857] | 392 | if ( (wch = pwcDot[2]) != '\0'
|
---|
[2852] | 393 | && IS_SLASH(wch))
|
---|
| 394 | {
|
---|
| 395 | if (pwcDot == pwszPath)
|
---|
| 396 | return K_TRUE;
|
---|
| 397 | wch = pwcDot[-1];
|
---|
| 398 | if ( IS_SLASH(wch)
|
---|
| 399 | || wch == ':')
|
---|
| 400 | return K_TRUE;
|
---|
| 401 | }
|
---|
| 402 | pwcDot = wmemchr(pwcDot + 2, '.', &pwszPath[cwcPath] - pwcDot - 2);
|
---|
| 403 | }
|
---|
| 404 | }
|
---|
| 405 |
|
---|
| 406 | return K_FALSE;
|
---|
| 407 | }
|
---|
| 408 |
|
---|
| 409 |
|
---|
| 410 | /**
|
---|
[2851] | 411 | * Creates an ANSI hash table entry for the given path.
|
---|
| 412 | *
|
---|
| 413 | * @returns The hash table entry or NULL if out of memory.
|
---|
| 414 | * @param pCache The hash
|
---|
| 415 | * @param pFsObj The resulting object.
|
---|
| 416 | * @param pszPath The path.
|
---|
| 417 | * @param cchPath The length of the path.
|
---|
| 418 | * @param uHashPath The hash of the path.
|
---|
[2859] | 419 | * @param fAbsolute Whether it can be refreshed using an absolute
|
---|
| 420 | * lookup or requires the slow treatment.
|
---|
[2868] | 421 | * @parma idxMissingGen The missing generation index.
|
---|
[2851] | 422 | * @param idxHashTab The hash table index of the path.
|
---|
| 423 | * @param enmError The lookup error.
|
---|
| 424 | */
|
---|
| 425 | static PKFSHASHA kFsCacheCreatePathHashTabEntryA(PKFSCACHE pCache, PKFSOBJ pFsObj, const char *pszPath, KU32 cchPath,
|
---|
[2868] | 426 | KU32 uHashPath, KU32 idxHashTab, BOOL fAbsolute, KU32 idxMissingGen,
|
---|
| 427 | KFSLOOKUPERROR enmError)
|
---|
[2833] | 428 | {
|
---|
[2851] | 429 | PKFSHASHA pHashEntry = (PKFSHASHA)kHlpAlloc(sizeof(*pHashEntry) + cchPath + 1);
|
---|
[2833] | 430 | if (pHashEntry)
|
---|
| 431 | {
|
---|
[2868] | 432 | pHashEntry->uHashPath = uHashPath;
|
---|
| 433 | pHashEntry->cchPath = (KU16)cchPath;
|
---|
| 434 | pHashEntry->fAbsolute = fAbsolute;
|
---|
| 435 | pHashEntry->idxMissingGen = (KU8)idxMissingGen;
|
---|
| 436 | pHashEntry->enmError = enmError;
|
---|
| 437 | pHashEntry->pszPath = (const char *)kHlpMemCopy(pHashEntry + 1, pszPath, cchPath + 1);
|
---|
[2851] | 438 | if (pFsObj)
|
---|
[2879] | 439 | {
|
---|
| 440 | pHashEntry->pFsObj = kFsCacheObjRetainInternal(pFsObj);
|
---|
| 441 | pHashEntry->uCacheGen = pFsObj->bObjType != KFSOBJ_TYPE_MISSING
|
---|
| 442 | ? pCache->auGenerations[ pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
|
---|
| 443 | : pCache->auGenerationsMissing[pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN];
|
---|
[3362] | 444 | pFsObj->cPathHashRefs += 1; // for debugging
|
---|
[2879] | 445 | }
|
---|
[2851] | 446 | else
|
---|
[2879] | 447 | {
|
---|
| 448 | pHashEntry->pFsObj = NULL;
|
---|
| 449 | if (enmError != KFSLOOKUPERROR_UNSUPPORTED)
|
---|
| 450 | pHashEntry->uCacheGen = pCache->auGenerationsMissing[idxMissingGen];
|
---|
| 451 | else
|
---|
| 452 | pHashEntry->uCacheGen = KFSOBJ_CACHE_GEN_IGNORE;
|
---|
| 453 | }
|
---|
[2833] | 454 |
|
---|
[2851] | 455 | pHashEntry->pNext = pCache->apAnsiPaths[idxHashTab];
|
---|
| 456 | pCache->apAnsiPaths[idxHashTab] = pHashEntry;
|
---|
| 457 |
|
---|
| 458 | pCache->cbAnsiPaths += sizeof(*pHashEntry) + cchPath + 1;
|
---|
| 459 | pCache->cAnsiPaths++;
|
---|
| 460 | if (pHashEntry->pNext)
|
---|
| 461 | pCache->cAnsiPathCollisions++;
|
---|
[2833] | 462 | }
|
---|
[2852] | 463 | return pHashEntry;
|
---|
[2833] | 464 | }
|
---|
| 465 |
|
---|
| 466 |
|
---|
| 467 | /**
|
---|
[2852] | 468 | * Creates an UTF-16 hash table entry for the given path.
|
---|
| 469 | *
|
---|
| 470 | * @returns The hash table entry or NULL if out of memory.
|
---|
| 471 | * @param pCache The hash
|
---|
| 472 | * @param pFsObj The resulting object.
|
---|
| 473 | * @param pwszPath The path.
|
---|
| 474 | * @param cwcPath The length of the path (in wchar_t's).
|
---|
| 475 | * @param uHashPath The hash of the path.
|
---|
[2859] | 476 | * @param fAbsolute Whether it can be refreshed using an absolute
|
---|
| 477 | * lookup or requires the slow treatment.
|
---|
[2868] | 478 | * @parma idxMissingGen The missing generation index.
|
---|
[2852] | 479 | * @param idxHashTab The hash table index of the path.
|
---|
| 480 | * @param enmError The lookup error.
|
---|
| 481 | */
|
---|
| 482 | static PKFSHASHW kFsCacheCreatePathHashTabEntryW(PKFSCACHE pCache, PKFSOBJ pFsObj, const wchar_t *pwszPath, KU32 cwcPath,
|
---|
[2868] | 483 | KU32 uHashPath, KU32 idxHashTab, BOOL fAbsolute, KU32 idxMissingGen,
|
---|
| 484 | KFSLOOKUPERROR enmError)
|
---|
[2852] | 485 | {
|
---|
| 486 | PKFSHASHW pHashEntry = (PKFSHASHW)kHlpAlloc(sizeof(*pHashEntry) + (cwcPath + 1) * sizeof(wchar_t));
|
---|
| 487 | if (pHashEntry)
|
---|
| 488 | {
|
---|
[2868] | 489 | pHashEntry->uHashPath = uHashPath;
|
---|
| 490 | pHashEntry->cwcPath = cwcPath;
|
---|
| 491 | pHashEntry->fAbsolute = fAbsolute;
|
---|
| 492 | pHashEntry->idxMissingGen = (KU8)idxMissingGen;
|
---|
| 493 | pHashEntry->enmError = enmError;
|
---|
| 494 | pHashEntry->pwszPath = (const wchar_t *)kHlpMemCopy(pHashEntry + 1, pwszPath, (cwcPath + 1) * sizeof(wchar_t));
|
---|
[2852] | 495 | if (pFsObj)
|
---|
[2879] | 496 | {
|
---|
| 497 | pHashEntry->pFsObj = kFsCacheObjRetainInternal(pFsObj);
|
---|
| 498 | pHashEntry->uCacheGen = pFsObj->bObjType != KFSOBJ_TYPE_MISSING
|
---|
| 499 | ? pCache->auGenerations[ pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
|
---|
| 500 | : pCache->auGenerationsMissing[pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN];
|
---|
[3362] | 501 | pFsObj->cPathHashRefs += 1; // for debugging
|
---|
[2879] | 502 | }
|
---|
[2852] | 503 | else
|
---|
[2879] | 504 | {
|
---|
| 505 | pHashEntry->pFsObj = NULL;
|
---|
| 506 | if (enmError != KFSLOOKUPERROR_UNSUPPORTED)
|
---|
| 507 | pHashEntry->uCacheGen = pCache->auGenerationsMissing[idxMissingGen];
|
---|
| 508 | else
|
---|
| 509 | pHashEntry->uCacheGen = KFSOBJ_CACHE_GEN_IGNORE;
|
---|
| 510 | }
|
---|
[2852] | 511 |
|
---|
| 512 | pHashEntry->pNext = pCache->apUtf16Paths[idxHashTab];
|
---|
| 513 | pCache->apUtf16Paths[idxHashTab] = pHashEntry;
|
---|
| 514 |
|
---|
| 515 | pCache->cbUtf16Paths += sizeof(*pHashEntry) + (cwcPath + 1) * sizeof(wchar_t);
|
---|
| 516 | pCache->cUtf16Paths++;
|
---|
| 517 | if (pHashEntry->pNext)
|
---|
| 518 | pCache->cAnsiPathCollisions++;
|
---|
| 519 | }
|
---|
| 520 | return pHashEntry;
|
---|
| 521 | }
|
---|
| 522 |
|
---|
| 523 |
|
---|
| 524 | /**
|
---|
[2833] | 525 | * Links the child in under the parent.
|
---|
| 526 | *
|
---|
| 527 | * @returns K_TRUE on success, K_FALSE if out of memory.
|
---|
| 528 | * @param pParent The parent node.
|
---|
| 529 | * @param pChild The child node.
|
---|
| 530 | */
|
---|
[2851] | 531 | static KBOOL kFsCacheDirAddChild(PKFSCACHE pCache, PKFSDIR pParent, PKFSOBJ pChild, KFSLOOKUPERROR *penmError)
|
---|
[2833] | 532 | {
|
---|
[2863] | 533 | if (pParent->cChildren >= pParent->cChildrenAllocated)
|
---|
[2833] | 534 | {
|
---|
[2863] | 535 | void *pvNew = kHlpRealloc(pParent->papChildren, (pParent->cChildrenAllocated + 16) * sizeof(pParent->papChildren[0]));
|
---|
[2833] | 536 | if (!pvNew)
|
---|
| 537 | return K_FALSE;
|
---|
[2851] | 538 | pParent->papChildren = (PKFSOBJ *)pvNew;
|
---|
[2863] | 539 | pParent->cChildrenAllocated += 16;
|
---|
[2851] | 540 | pCache->cbObjects += 16 * sizeof(pParent->papChildren[0]);
|
---|
[2833] | 541 | }
|
---|
[2856] | 542 | pParent->papChildren[pParent->cChildren++] = kFsCacheObjRetainInternal(pChild);
|
---|
[2833] | 543 | return K_TRUE;
|
---|
| 544 | }
|
---|
| 545 |
|
---|
| 546 |
|
---|
| 547 | /**
|
---|
[2851] | 548 | * Creates a new cache object.
|
---|
[2833] | 549 | *
|
---|
[2851] | 550 | * @returns Pointer (with 1 reference) to the new object. The object will not
|
---|
| 551 | * be linked to the parent directory yet.
|
---|
| 552 | *
|
---|
| 553 | * NULL if we're out of memory.
|
---|
| 554 | *
|
---|
| 555 | * @param pCache The cache.
|
---|
| 556 | * @param pParent The parent directory.
|
---|
| 557 | * @param pszName The ANSI name.
|
---|
| 558 | * @param cchName The length of the ANSI name.
|
---|
| 559 | * @param pwszName The UTF-16 name.
|
---|
| 560 | * @param cwcName The length of the UTF-16 name.
|
---|
| 561 | * @param pszShortName The ANSI short name, NULL if none.
|
---|
| 562 | * @param cchShortName The length of the ANSI short name, 0 if none.
|
---|
| 563 | * @param pwszShortName The UTF-16 short name, NULL if none.
|
---|
| 564 | * @param cwcShortName The length of the UTF-16 short name, 0 if none.
|
---|
| 565 | * @param bObjType The objct type.
|
---|
| 566 | * @param penmError Where to explain failures.
|
---|
[2833] | 567 | */
|
---|
[2853] | 568 | PKFSOBJ kFsCacheCreateObject(PKFSCACHE pCache, PKFSDIR pParent,
|
---|
| 569 | char const *pszName, KU16 cchName, wchar_t const *pwszName, KU16 cwcName,
|
---|
[2851] | 570 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
[2853] | 571 | char const *pszShortName, KU16 cchShortName, wchar_t const *pwszShortName, KU16 cwcShortName,
|
---|
[2851] | 572 | #endif
|
---|
[2853] | 573 | KU8 bObjType, KFSLOOKUPERROR *penmError)
|
---|
[2833] | 574 | {
|
---|
| 575 | /*
|
---|
[2851] | 576 | * Allocate the object.
|
---|
[2833] | 577 | */
|
---|
[2856] | 578 | KBOOL const fDirish = bObjType != KFSOBJ_TYPE_FILE && bObjType != KFSOBJ_TYPE_OTHER;
|
---|
| 579 | KSIZE const cbObj = fDirish ? sizeof(KFSDIR) : sizeof(KFSOBJ);
|
---|
| 580 | KSIZE const cbNames = (cwcName + 1) * sizeof(wchar_t) + cchName + 1
|
---|
[2851] | 581 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 582 | + (cwcShortName > 0 ? (cwcShortName + 1) * sizeof(wchar_t) + cchShortName + 1 : 0)
|
---|
| 583 | #endif
|
---|
| 584 | ;
|
---|
[2855] | 585 | PKFSOBJ pObj;
|
---|
| 586 | kHlpAssert(pCache->u32Magic == KFSCACHE_MAGIC);
|
---|
| 587 |
|
---|
[2856] | 588 | pObj = (PKFSOBJ)kHlpAlloc(cbObj + cbNames);
|
---|
[2851] | 589 | if (pObj)
|
---|
[2833] | 590 | {
|
---|
[2856] | 591 | KU8 *pbExtra = (KU8 *)pObj + cbObj;
|
---|
[2833] | 592 |
|
---|
[3184] | 593 | KFSCACHE_LOCK(pCache); /** @todo reduce the amount of work done holding the lock */
|
---|
| 594 |
|
---|
[2856] | 595 | pCache->cbObjects += cbObj + cbNames;
|
---|
[2851] | 596 | pCache->cObjects++;
|
---|
[2833] | 597 |
|
---|
[2851] | 598 | /*
|
---|
| 599 | * Initialize the object.
|
---|
| 600 | */
|
---|
| 601 | pObj->u32Magic = KFSOBJ_MAGIC;
|
---|
| 602 | pObj->cRefs = 1;
|
---|
[2868] | 603 | pObj->uCacheGen = bObjType != KFSOBJ_TYPE_MISSING
|
---|
| 604 | ? pCache->auGenerations[pParent->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
|
---|
| 605 | : pCache->auGenerationsMissing[pParent->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN];
|
---|
[2851] | 606 | pObj->bObjType = bObjType;
|
---|
| 607 | pObj->fHaveStats = K_FALSE;
|
---|
[3362] | 608 | pObj->cPathHashRefs = 0;
|
---|
| 609 | pObj->idxUserDataLock = KU8_MAX;
|
---|
[2868] | 610 | pObj->fFlags = pParent->Obj.fFlags & KFSOBJ_F_INHERITED_MASK;
|
---|
[2851] | 611 | pObj->pParent = pParent;
|
---|
[2930] | 612 | pObj->uNameHash = 0;
|
---|
| 613 | pObj->pNextNameHash = NULL;
|
---|
[2967] | 614 | pObj->pNameAlloc = NULL;
|
---|
[2855] | 615 | pObj->pUserDataHead = NULL;
|
---|
[2833] | 616 |
|
---|
[2851] | 617 | #ifdef KFSCACHE_CFG_UTF16
|
---|
| 618 | pObj->cwcParent = pParent->Obj.cwcParent + pParent->Obj.cwcName + !!pParent->Obj.cwcName;
|
---|
| 619 | pObj->pwszName = (wchar_t *)kHlpMemCopy(pbExtra, pwszName, cwcName * sizeof(wchar_t));
|
---|
[2856] | 620 | pObj->cwcName = cwcName;
|
---|
[2851] | 621 | pbExtra += cwcName * sizeof(wchar_t);
|
---|
| 622 | *pbExtra++ = '\0';
|
---|
| 623 | *pbExtra++ = '\0';
|
---|
| 624 | # ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 625 | pObj->cwcShortParent = pParent->Obj.cwcShortParent + pParent->Obj.cwcShortName + !!pParent->Obj.cwcShortName;
|
---|
| 626 | if (cwcShortName)
|
---|
[2833] | 627 | {
|
---|
[2851] | 628 | pObj->pwszShortName = (wchar_t *)kHlpMemCopy(pbExtra, pwszShortName, cwcShortName * sizeof(wchar_t));
|
---|
[2856] | 629 | pObj->cwcShortName = cwcShortName;
|
---|
[2851] | 630 | pbExtra += cwcShortName * sizeof(wchar_t);
|
---|
| 631 | *pbExtra++ = '\0';
|
---|
| 632 | *pbExtra++ = '\0';
|
---|
[2833] | 633 | }
|
---|
[2851] | 634 | else
|
---|
[2833] | 635 | {
|
---|
[2851] | 636 | pObj->pwszShortName = pObj->pwszName;
|
---|
[2856] | 637 | pObj->cwcShortName = cwcName;
|
---|
[2833] | 638 | }
|
---|
[2851] | 639 | # endif
|
---|
| 640 | #endif
|
---|
| 641 | pObj->cchParent = pParent->Obj.cchParent + pParent->Obj.cchName + !!pParent->Obj.cchName;
|
---|
| 642 | pObj->pszName = (char *)kHlpMemCopy(pbExtra, pszName, cchName);
|
---|
[2856] | 643 | pObj->cchName = cchName;
|
---|
[2851] | 644 | pbExtra += cchName;
|
---|
| 645 | *pbExtra++ = '\0';
|
---|
| 646 | # ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 647 | pObj->cchShortParent = pParent->Obj.cchShortParent + pParent->Obj.cchShortName + !!pParent->Obj.cchShortName;
|
---|
| 648 | if (cchShortName)
|
---|
[2833] | 649 | {
|
---|
[2851] | 650 | pObj->pszShortName = (char *)kHlpMemCopy(pbExtra, pszShortName, cchShortName);
|
---|
[2856] | 651 | pObj->cchShortName = cchShortName;
|
---|
[2851] | 652 | pbExtra += cchShortName;
|
---|
| 653 | *pbExtra++ = '\0';
|
---|
[2833] | 654 | }
|
---|
[2851] | 655 | else
|
---|
[2833] | 656 | {
|
---|
[2851] | 657 | pObj->pszShortName = pObj->pszName;
|
---|
[2856] | 658 | pObj->cchShortName = cchName;
|
---|
[2833] | 659 | }
|
---|
[2851] | 660 | #endif
|
---|
| 661 | kHlpAssert(pbExtra - (KU8 *)pObj == cbObj);
|
---|
[2833] | 662 |
|
---|
[2851] | 663 | /*
|
---|
[2930] | 664 | * Type specific initialization.
|
---|
[2851] | 665 | */
|
---|
| 666 | if (fDirish)
|
---|
| 667 | {
|
---|
| 668 | PKFSDIR pDirObj = (PKFSDIR)pObj;
|
---|
[2863] | 669 | pDirObj->cChildren = 0;
|
---|
| 670 | pDirObj->cChildrenAllocated = 0;
|
---|
| 671 | pDirObj->papChildren = NULL;
|
---|
[2930] | 672 | pDirObj->fHashTabMask = 0;
|
---|
| 673 | pDirObj->papHashTab = NULL;
|
---|
[2863] | 674 | pDirObj->hDir = INVALID_HANDLE_VALUE;
|
---|
| 675 | pDirObj->uDevNo = pParent->uDevNo;
|
---|
| 676 | pDirObj->iLastWrite = 0;
|
---|
[3381] | 677 | pDirObj->iLastPopulated = 0;
|
---|
[2863] | 678 | pDirObj->fPopulated = K_FALSE;
|
---|
[2851] | 679 | }
|
---|
[3184] | 680 |
|
---|
| 681 | KFSCACHE_UNLOCK(pCache);
|
---|
[2833] | 682 | }
|
---|
[2851] | 683 | else
|
---|
| 684 | *penmError = KFSLOOKUPERROR_OUT_OF_MEMORY;
|
---|
| 685 | return pObj;
|
---|
[2833] | 686 | }
|
---|
| 687 |
|
---|
| 688 |
|
---|
| 689 | /**
|
---|
[2851] | 690 | * Creates a new object given wide char names.
|
---|
[2833] | 691 | *
|
---|
[2851] | 692 | * This function just converts the paths and calls kFsCacheCreateObject.
|
---|
| 693 | *
|
---|
| 694 | *
|
---|
| 695 | * @returns Pointer (with 1 reference) to the new object. The object will not
|
---|
| 696 | * be linked to the parent directory yet.
|
---|
| 697 | *
|
---|
| 698 | * NULL if we're out of memory.
|
---|
| 699 | *
|
---|
| 700 | * @param pCache The cache.
|
---|
| 701 | * @param pParent The parent directory.
|
---|
| 702 | * @param pszName The ANSI name.
|
---|
| 703 | * @param cchName The length of the ANSI name.
|
---|
| 704 | * @param pwszName The UTF-16 name.
|
---|
| 705 | * @param cwcName The length of the UTF-16 name.
|
---|
| 706 | * @param pwszShortName The UTF-16 short name, NULL if none.
|
---|
| 707 | * @param cwcShortName The length of the UTF-16 short name, 0 if none.
|
---|
| 708 | * @param bObjType The objct type.
|
---|
| 709 | * @param penmError Where to explain failures.
|
---|
[2833] | 710 | */
|
---|
[2853] | 711 | PKFSOBJ kFsCacheCreateObjectW(PKFSCACHE pCache, PKFSDIR pParent, wchar_t const *pwszName, KU32 cwcName,
|
---|
[2851] | 712 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
[2853] | 713 | wchar_t const *pwszShortName, KU32 cwcShortName,
|
---|
[2851] | 714 | #endif
|
---|
[2853] | 715 | KU8 bObjType, KFSLOOKUPERROR *penmError)
|
---|
[2833] | 716 | {
|
---|
[2851] | 717 | /* Convert names to ANSI first so we know their lengths. */
|
---|
| 718 | char szName[KFSCACHE_CFG_MAX_ANSI_NAME];
|
---|
| 719 | int cchName = WideCharToMultiByte(CP_ACP, 0, pwszName, cwcName, szName, sizeof(szName) - 1, NULL, NULL);
|
---|
| 720 | if (cchName >= 0)
|
---|
[2833] | 721 | {
|
---|
[2851] | 722 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 723 | char szShortName[12*3 + 1];
|
---|
| 724 | int cchShortName = 0;
|
---|
| 725 | if ( cwcShortName == 0
|
---|
| 726 | || (cchShortName = WideCharToMultiByte(CP_ACP, 0, pwszShortName, cwcShortName,
|
---|
| 727 | szShortName, sizeof(szShortName) - 1, NULL, NULL)) > 0)
|
---|
| 728 | #endif
|
---|
[2833] | 729 | {
|
---|
[3184] | 730 | /* No locking needed here, kFsCacheCreateObject takes care of that. */
|
---|
[2851] | 731 | return kFsCacheCreateObject(pCache, pParent,
|
---|
| 732 | szName, cchName, pwszName, cwcName,
|
---|
| 733 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 734 | szShortName, cchShortName, pwszShortName, cwcShortName,
|
---|
| 735 | #endif
|
---|
| 736 | bObjType, penmError);
|
---|
[2833] | 737 | }
|
---|
| 738 | }
|
---|
[2851] | 739 | *penmError = KFSLOOKUPERROR_ANSI_CONVERSION_ERROR;
|
---|
[2833] | 740 | return NULL;
|
---|
| 741 | }
|
---|
| 742 |
|
---|
| 743 |
|
---|
| 744 | /**
|
---|
[2851] | 745 | * Creates a missing object.
|
---|
[2833] | 746 | *
|
---|
[2851] | 747 | * This is used for caching negative results.
|
---|
[2833] | 748 | *
|
---|
[2851] | 749 | * @returns Pointer to the newly created object on success (already linked into
|
---|
| 750 | * pParent). No reference.
|
---|
[2833] | 751 | *
|
---|
[2851] | 752 | * NULL on failure.
|
---|
[2833] | 753 | *
|
---|
[2851] | 754 | * @param pCache The cache.
|
---|
| 755 | * @param pParent The parent directory.
|
---|
| 756 | * @param pchName The name.
|
---|
| 757 | * @param cchName The length of the name.
|
---|
| 758 | * @param penmError Where to return failure explanations.
|
---|
[2833] | 759 | */
|
---|
[2851] | 760 | static PKFSOBJ kFsCacheCreateMissingA(PKFSCACHE pCache, PKFSDIR pParent, const char *pchName, KU32 cchName,
|
---|
| 761 | KFSLOOKUPERROR *penmError)
|
---|
[2833] | 762 | {
|
---|
| 763 | /*
|
---|
[2851] | 764 | * Just convert the name to UTF-16 and call kFsCacheCreateObject to do the job.
|
---|
[2833] | 765 | */
|
---|
[2851] | 766 | wchar_t wszName[KFSCACHE_CFG_MAX_PATH];
|
---|
| 767 | int cwcName = MultiByteToWideChar(CP_ACP, 0, pchName, cchName, wszName, KFSCACHE_CFG_MAX_UTF16_NAME - 1);
|
---|
| 768 | if (cwcName > 0)
|
---|
[2833] | 769 | {
|
---|
[2851] | 770 | /** @todo check that it actually doesn't exists before we add it. We should not
|
---|
| 771 | * trust the directory enumeration here, or maybe we should?? */
|
---|
| 772 |
|
---|
| 773 | PKFSOBJ pMissing = kFsCacheCreateObject(pCache, pParent, pchName, cchName, wszName, cwcName,
|
---|
| 774 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 775 | NULL, 0, NULL, 0,
|
---|
| 776 | #endif
|
---|
| 777 | KFSOBJ_TYPE_MISSING, penmError);
|
---|
| 778 | if (pMissing)
|
---|
[2833] | 779 | {
|
---|
[2851] | 780 | KBOOL fRc = kFsCacheDirAddChild(pCache, pParent, pMissing, penmError);
|
---|
| 781 | kFsCacheObjRelease(pCache, pMissing);
|
---|
| 782 | return fRc ? pMissing : NULL;
|
---|
| 783 | }
|
---|
| 784 | return NULL;
|
---|
[2833] | 785 | }
|
---|
[2851] | 786 | *penmError = KFSLOOKUPERROR_UTF16_CONVERSION_ERROR;
|
---|
[2833] | 787 | return NULL;
|
---|
| 788 | }
|
---|
| 789 |
|
---|
| 790 |
|
---|
| 791 | /**
|
---|
[2852] | 792 | * Creates a missing object, UTF-16 version.
|
---|
| 793 | *
|
---|
| 794 | * This is used for caching negative results.
|
---|
| 795 | *
|
---|
| 796 | * @returns Pointer to the newly created object on success (already linked into
|
---|
| 797 | * pParent). No reference.
|
---|
| 798 | *
|
---|
| 799 | * NULL on failure.
|
---|
| 800 | *
|
---|
| 801 | * @param pCache The cache.
|
---|
| 802 | * @param pParent The parent directory.
|
---|
| 803 | * @param pwcName The name.
|
---|
| 804 | * @param cwcName The length of the name.
|
---|
| 805 | * @param penmError Where to return failure explanations.
|
---|
| 806 | */
|
---|
| 807 | static PKFSOBJ kFsCacheCreateMissingW(PKFSCACHE pCache, PKFSDIR pParent, const wchar_t *pwcName, KU32 cwcName,
|
---|
| 808 | KFSLOOKUPERROR *penmError)
|
---|
| 809 | {
|
---|
| 810 | /** @todo check that it actually doesn't exists before we add it. We should not
|
---|
| 811 | * trust the directory enumeration here, or maybe we should?? */
|
---|
| 812 | PKFSOBJ pMissing = kFsCacheCreateObjectW(pCache, pParent, pwcName, cwcName,
|
---|
| 813 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 814 | NULL, 0,
|
---|
| 815 | #endif
|
---|
| 816 | KFSOBJ_TYPE_MISSING, penmError);
|
---|
| 817 | if (pMissing)
|
---|
| 818 | {
|
---|
| 819 | KBOOL fRc = kFsCacheDirAddChild(pCache, pParent, pMissing, penmError);
|
---|
| 820 | kFsCacheObjRelease(pCache, pMissing);
|
---|
| 821 | return fRc ? pMissing : NULL;
|
---|
| 822 | }
|
---|
| 823 | return NULL;
|
---|
| 824 | }
|
---|
| 825 |
|
---|
[2967] | 826 |
|
---|
[2863] | 827 | /**
|
---|
[2967] | 828 | * Does the growing of names.
|
---|
| 829 | *
|
---|
| 830 | * @returns pCur
|
---|
| 831 | * @param pCache The cache.
|
---|
| 832 | * @param pCur The object.
|
---|
| 833 | * @param pchName The name (not necessarily terminated).
|
---|
| 834 | * @param cchName Name length.
|
---|
| 835 | * @param pwcName The UTF-16 name (not necessarily terminated).
|
---|
| 836 | * @param cwcName The length of the UTF-16 name in wchar_t's.
|
---|
| 837 | * @param pchShortName The short name.
|
---|
| 838 | * @param cchShortName The length of the short name. This is 0 if no short
|
---|
| 839 | * name.
|
---|
| 840 | * @param pwcShortName The short UTF-16 name.
|
---|
| 841 | * @param cwcShortName The length of the short UTF-16 name. This is 0 if
|
---|
| 842 | * no short name.
|
---|
| 843 | */
|
---|
| 844 | static PKFSOBJ kFsCacheRefreshGrowNames(PKFSCACHE pCache, PKFSOBJ pCur,
|
---|
| 845 | const char *pchName, KU32 cchName,
|
---|
| 846 | wchar_t const *pwcName, KU32 cwcName
|
---|
| 847 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 848 | , const char *pchShortName, KU32 cchShortName,
|
---|
| 849 | wchar_t const *pwcShortName, KU32 cwcShortName
|
---|
| 850 | #endif
|
---|
| 851 | )
|
---|
| 852 | {
|
---|
| 853 | PKFSOBJNAMEALLOC pNameAlloc;
|
---|
| 854 | char *pch;
|
---|
| 855 | KU32 cbNeeded;
|
---|
| 856 |
|
---|
| 857 | pCache->cNameGrowths++;
|
---|
| 858 |
|
---|
| 859 | /*
|
---|
| 860 | * Figure out our requirements.
|
---|
| 861 | */
|
---|
| 862 | cbNeeded = sizeof(KU32) + cchName + 1;
|
---|
| 863 | #ifdef KFSCACHE_CFG_UTF16
|
---|
| 864 | cbNeeded += (cwcName + 1) * sizeof(wchar_t);
|
---|
| 865 | #endif
|
---|
| 866 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 867 | cbNeeded += cchShortName + !!cchShortName;
|
---|
| 868 | # ifdef KFSCACHE_CFG_UTF16
|
---|
| 869 | cbNeeded += (cwcShortName + !!cwcShortName) * sizeof(wchar_t);
|
---|
| 870 | # endif
|
---|
| 871 | #endif
|
---|
| 872 | cbNeeded = K_ALIGN_Z(cbNeeded, 8); /* Memory will likely be 8 or 16 byte aligned, so we might just claim it. */
|
---|
| 873 |
|
---|
| 874 | /*
|
---|
| 875 | * Allocate memory.
|
---|
| 876 | */
|
---|
| 877 | pNameAlloc = pCur->pNameAlloc;
|
---|
| 878 | if (!pNameAlloc)
|
---|
| 879 | {
|
---|
| 880 | pNameAlloc = (PKFSOBJNAMEALLOC)kHlpAlloc(cbNeeded);
|
---|
| 881 | if (!pNameAlloc)
|
---|
| 882 | return pCur;
|
---|
| 883 | pCache->cbObjects += cbNeeded;
|
---|
| 884 | pCur->pNameAlloc = pNameAlloc;
|
---|
| 885 | pNameAlloc->cb = cbNeeded;
|
---|
| 886 | }
|
---|
| 887 | else if (pNameAlloc->cb < cbNeeded)
|
---|
| 888 | {
|
---|
| 889 | pNameAlloc = (PKFSOBJNAMEALLOC)kHlpRealloc(pNameAlloc, cbNeeded);
|
---|
| 890 | if (!pNameAlloc)
|
---|
| 891 | return pCur;
|
---|
| 892 | pCache->cbObjects += cbNeeded - pNameAlloc->cb;
|
---|
| 893 | pCur->pNameAlloc = pNameAlloc;
|
---|
| 894 | pNameAlloc->cb = cbNeeded;
|
---|
| 895 | }
|
---|
| 896 |
|
---|
| 897 | /*
|
---|
| 898 | * Copy out the new names, starting with the wide char ones to avoid misaligning them.
|
---|
| 899 | */
|
---|
| 900 | pch = &pNameAlloc->abSpace[0];
|
---|
| 901 |
|
---|
| 902 | #ifdef KFSCACHE_CFG_UTF16
|
---|
| 903 | pCur->pwszName = (wchar_t *)pch;
|
---|
| 904 | pCur->cwcName = cwcName;
|
---|
| 905 | pch = kHlpMemPCopy(pch, pwcName, cwcName * sizeof(wchar_t));
|
---|
| 906 | *pch++ = '\0';
|
---|
| 907 | *pch++ = '\0';
|
---|
| 908 |
|
---|
| 909 | # ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 910 | if (cwcShortName == 0)
|
---|
| 911 | {
|
---|
| 912 | pCur->pwszShortName = pCur->pwszName;
|
---|
| 913 | pCur->cwcShortName = pCur->cwcName;
|
---|
| 914 | }
|
---|
| 915 | else
|
---|
| 916 | {
|
---|
| 917 | pCur->pwszShortName = (wchar_t *)pch;
|
---|
| 918 | pCur->cwcShortName = cwcShortName;
|
---|
| 919 | pch = kHlpMemPCopy(pch, pwcShortName, cwcShortName * sizeof(wchar_t));
|
---|
| 920 | *pch++ = '\0';
|
---|
| 921 | *pch++ = '\0';
|
---|
| 922 | }
|
---|
| 923 | # endif
|
---|
| 924 | #endif
|
---|
| 925 |
|
---|
| 926 | pCur->pszName = pch;
|
---|
| 927 | pCur->cchName = cchName;
|
---|
[3379] | 928 | pch = kHlpMemPCopy(pch, pchName, cchName);
|
---|
[2967] | 929 | *pch++ = '\0';
|
---|
| 930 |
|
---|
| 931 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 932 | if (cchShortName == 0)
|
---|
| 933 | {
|
---|
| 934 | pCur->pszShortName = pCur->pszName;
|
---|
| 935 | pCur->cchShortName = pCur->cchName;
|
---|
| 936 | }
|
---|
| 937 | else
|
---|
| 938 | {
|
---|
| 939 | pCur->pszShortName = pch;
|
---|
| 940 | pCur->cchShortName = cchShortName;
|
---|
| 941 | pch = kHlpMemPCopy(pch, pchShortName, cchShortName);
|
---|
| 942 | *pch++ = '\0';
|
---|
| 943 | }
|
---|
| 944 | #endif
|
---|
| 945 |
|
---|
| 946 | return pCur;
|
---|
| 947 | }
|
---|
| 948 |
|
---|
| 949 |
|
---|
| 950 | /**
|
---|
[2863] | 951 | * Worker for kFsCacheDirFindOldChild that refreshes the file ID value on an
|
---|
| 952 | * object found by name.
|
---|
| 953 | *
|
---|
[2967] | 954 | * @returns pCur.
|
---|
[2863] | 955 | * @param pDirRePop Repopulation data.
|
---|
| 956 | * @param pCur The object to check the names of.
|
---|
| 957 | * @param idFile The file ID.
|
---|
| 958 | */
|
---|
| 959 | static PKFSOBJ kFsCacheDirRefreshOldChildFileId(PKFSDIRREPOP pDirRePop, PKFSOBJ pCur, KI64 idFile)
|
---|
| 960 | {
|
---|
| 961 | KFSCACHE_LOG(("Refreshing %s/%s/ - %s changed file ID from %#llx -> %#llx...\n",
|
---|
| 962 | pCur->pParent->Obj.pParent->Obj.pszName, pCur->pParent->Obj.pszName, pCur->pszName,
|
---|
| 963 | pCur->Stats.st_ino, idFile));
|
---|
| 964 | pCur->Stats.st_ino = idFile;
|
---|
| 965 | /** @todo inform user data items... */
|
---|
| 966 | return pCur;
|
---|
| 967 | }
|
---|
[2852] | 968 |
|
---|
[2863] | 969 |
|
---|
[2852] | 970 | /**
|
---|
[2863] | 971 | * Worker for kFsCacheDirFindOldChild that checks the names after an old object
|
---|
| 972 | * has been found the file ID.
|
---|
| 973 | *
|
---|
[2967] | 974 | * @returns pCur.
|
---|
[2863] | 975 | * @param pDirRePop Repopulation data.
|
---|
| 976 | * @param pCur The object to check the names of.
|
---|
| 977 | * @param pwcName The file name.
|
---|
| 978 | * @param cwcName The length of the filename (in wchar_t's).
|
---|
| 979 | * @param pwcShortName The short name, if present.
|
---|
| 980 | * @param cwcShortName The length of the short name (in wchar_t's).
|
---|
| 981 | */
|
---|
| 982 | static PKFSOBJ kFsCacheDirRefreshOldChildName(PKFSDIRREPOP pDirRePop, PKFSOBJ pCur, wchar_t const *pwcName, KU32 cwcName
|
---|
| 983 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 984 | , wchar_t const *pwcShortName, KU32 cwcShortName
|
---|
| 985 | #endif
|
---|
| 986 | )
|
---|
| 987 | {
|
---|
[2967] | 988 | char szName[KFSCACHE_CFG_MAX_ANSI_NAME];
|
---|
| 989 | int cchName;
|
---|
| 990 |
|
---|
| 991 | pDirRePop->pCache->cNameChanges++;
|
---|
| 992 |
|
---|
[2866] | 993 | /*
|
---|
| 994 | * Convert the names to ANSI first, that way we know all the lengths.
|
---|
| 995 | */
|
---|
[2967] | 996 | cchName = WideCharToMultiByte(CP_ACP, 0, pwcName, cwcName, szName, sizeof(szName) - 1, NULL, NULL);
|
---|
[2866] | 997 | if (cchName >= 0)
|
---|
| 998 | {
|
---|
| 999 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 1000 | char szShortName[12*3 + 1];
|
---|
| 1001 | int cchShortName = 0;
|
---|
| 1002 | if ( cwcShortName == 0
|
---|
| 1003 | || (cchShortName = WideCharToMultiByte(CP_ACP, 0, pwcShortName, cwcShortName,
|
---|
| 1004 | szShortName, sizeof(szShortName) - 1, NULL, NULL)) > 0)
|
---|
| 1005 | #endif
|
---|
| 1006 | {
|
---|
| 1007 | /*
|
---|
| 1008 | * Shortening is easy for non-directory objects, for
|
---|
| 1009 | * directory object we're only good when the length doesn't change
|
---|
| 1010 | * on any of the components (cchParent et al).
|
---|
| 1011 | *
|
---|
| 1012 | * This deals with your typical xxxx.ext.tmp -> xxxx.ext renames.
|
---|
| 1013 | */
|
---|
| 1014 | if ( cchName <= pCur->cchName
|
---|
| 1015 | #ifdef KFSCACHE_CFG_UTF16
|
---|
| 1016 | && cwcName <= pCur->cwcName
|
---|
| 1017 | #endif
|
---|
| 1018 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 1019 | && ( cchShortName == 0
|
---|
| 1020 | || ( cchShortName <= pCur->cchShortName
|
---|
| 1021 | && pCur->pszShortName != pCur->pszName
|
---|
| 1022 | # ifdef KFSCACHE_CFG_UTF16
|
---|
| 1023 | && cwcShortName <= pCur->cwcShortName
|
---|
| 1024 | && pCur->pwszShortName != pCur->pwszName
|
---|
| 1025 | # endif
|
---|
| 1026 | )
|
---|
| 1027 | )
|
---|
| 1028 | #endif
|
---|
| 1029 | )
|
---|
| 1030 | {
|
---|
| 1031 | if ( pCur->bObjType != KFSOBJ_TYPE_DIR
|
---|
| 1032 | || ( cchName == pCur->cchName
|
---|
| 1033 | #ifdef KFSCACHE_CFG_UTF16
|
---|
| 1034 | && cwcName == pCur->cwcName
|
---|
| 1035 | #endif
|
---|
| 1036 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 1037 | && ( cchShortName == 0
|
---|
| 1038 | || ( cchShortName == pCur->cchShortName
|
---|
| 1039 | # ifdef KFSCACHE_CFG_UTF16
|
---|
| 1040 | && cwcShortName == pCur->cwcShortName
|
---|
| 1041 | )
|
---|
| 1042 | # endif
|
---|
| 1043 | )
|
---|
| 1044 | #endif
|
---|
| 1045 | )
|
---|
| 1046 | )
|
---|
| 1047 | {
|
---|
| 1048 | KFSCACHE_LOG(("Refreshing %ls - name changed to '%*.*ls'\n", pCur->pwszName, cwcName, cwcName, pwcName));
|
---|
| 1049 | *(char *)kHlpMemPCopy((void *)pCur->pszName, szName, cchName) = '\0';
|
---|
| 1050 | pCur->cchName = cchName;
|
---|
| 1051 | #ifdef KFSCACHE_CFG_UTF16
|
---|
| 1052 | *(wchar_t *)kHlpMemPCopy((void *)pCur->pwszName, pwcName, cwcName * sizeof(wchar_t)) = '\0';
|
---|
| 1053 | pCur->cwcName = cwcName;
|
---|
| 1054 | #endif
|
---|
| 1055 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 1056 | *(char *)kHlpMemPCopy((void *)pCur->pszShortName, szShortName, cchShortName) = '\0';
|
---|
| 1057 | pCur->cchShortName = cchShortName;
|
---|
| 1058 | # ifdef KFSCACHE_CFG_UTF16
|
---|
| 1059 | *(wchar_t *)kHlpMemPCopy((void *)pCur->pwszShortName, pwcShortName, cwcShortName * sizeof(wchar_t)) = '\0';
|
---|
| 1060 | pCur->cwcShortName = cwcShortName;
|
---|
| 1061 | # endif
|
---|
| 1062 | #endif
|
---|
| 1063 | return pCur;
|
---|
| 1064 | }
|
---|
| 1065 | }
|
---|
[2967] | 1066 |
|
---|
| 1067 | return kFsCacheRefreshGrowNames(pDirRePop->pCache, pCur, szName, cchName, pwcName, cwcName,
|
---|
| 1068 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 1069 | szShortName, cchShortName, pwcShortName, cwcShortName
|
---|
| 1070 | #endif
|
---|
| 1071 | );
|
---|
[2866] | 1072 | }
|
---|
| 1073 | }
|
---|
| 1074 |
|
---|
[2967] | 1075 | fprintf(stderr, "kFsCacheDirRefreshOldChildName: WideCharToMultiByte error\n");
|
---|
[2863] | 1076 | return pCur;
|
---|
| 1077 | }
|
---|
| 1078 |
|
---|
| 1079 |
|
---|
| 1080 | /**
|
---|
| 1081 | * Worker for kFsCacheDirFindOldChild that checks the names after an old object
|
---|
[2967] | 1082 | * has been found by the file ID.
|
---|
[2863] | 1083 | *
|
---|
[2967] | 1084 | * @returns pCur.
|
---|
[2863] | 1085 | * @param pDirRePop Repopulation data.
|
---|
| 1086 | * @param pCur The object to check the names of.
|
---|
| 1087 | * @param pwcName The file name.
|
---|
| 1088 | * @param cwcName The length of the filename (in wchar_t's).
|
---|
| 1089 | * @param pwcShortName The short name, if present.
|
---|
| 1090 | * @param cwcShortName The length of the short name (in wchar_t's).
|
---|
| 1091 | */
|
---|
| 1092 | K_INLINE PKFSOBJ kFsCacheDirCheckOldChildName(PKFSDIRREPOP pDirRePop, PKFSOBJ pCur, wchar_t const *pwcName, KU32 cwcName
|
---|
| 1093 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 1094 | , wchar_t const *pwcShortName, KU32 cwcShortName
|
---|
| 1095 | #endif
|
---|
| 1096 | )
|
---|
| 1097 | {
|
---|
| 1098 | if ( pCur->cwcName == cwcName
|
---|
| 1099 | && kHlpMemComp(pCur->pwszName, pwcName, cwcName * sizeof(wchar_t)) == 0)
|
---|
| 1100 | {
|
---|
| 1101 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 1102 | if (cwcShortName == 0
|
---|
| 1103 | ? pCur->pwszShortName == pCur->pwszName
|
---|
| 1104 | || ( pCur->cwcShortName == cwcName
|
---|
| 1105 | && kHlpMemComp(pCur->pwszShortName, pCur->pwszName, cwcName * sizeof(wchar_t)) == 0)
|
---|
| 1106 | : pCur->cwcShortName == cwcShortName
|
---|
| 1107 | && kHlpMemComp(pCur->pwszShortName, pwcShortName, cwcShortName * sizeof(wchar_t)) == 0 )
|
---|
| 1108 | #endif
|
---|
| 1109 | {
|
---|
| 1110 | return pCur;
|
---|
| 1111 | }
|
---|
| 1112 | }
|
---|
| 1113 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 1114 | return kFsCacheDirRefreshOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName);
|
---|
| 1115 | #else
|
---|
| 1116 | return kFsCacheDirRefreshOldChildName(pDirRePop, pCur, pwcName, cwcName);
|
---|
| 1117 | #endif
|
---|
| 1118 | }
|
---|
| 1119 |
|
---|
| 1120 |
|
---|
| 1121 | /**
|
---|
| 1122 | * Worker for kFsCachePopuplateOrRefreshDir that locates an old child object
|
---|
| 1123 | * while re-populating a directory.
|
---|
| 1124 | *
|
---|
| 1125 | * @returns Pointer to the existing object if found, NULL if not.
|
---|
| 1126 | * @param pDirRePop Repopulation data.
|
---|
| 1127 | * @param idFile The file ID, 0 if none.
|
---|
| 1128 | * @param pwcName The file name.
|
---|
| 1129 | * @param cwcName The length of the filename (in wchar_t's).
|
---|
| 1130 | * @param pwcShortName The short name, if present.
|
---|
| 1131 | * @param cwcShortName The length of the short name (in wchar_t's).
|
---|
| 1132 | */
|
---|
| 1133 | static PKFSOBJ kFsCacheDirFindOldChildSlow(PKFSDIRREPOP pDirRePop, KI64 idFile, wchar_t const *pwcName, KU32 cwcName
|
---|
| 1134 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 1135 | , wchar_t const *pwcShortName, KU32 cwcShortName
|
---|
| 1136 | #endif
|
---|
| 1137 | )
|
---|
| 1138 | {
|
---|
| 1139 | KU32 cOldChildren = pDirRePop->cOldChildren;
|
---|
| 1140 | KU32 const iNextOldChild = K_MIN(pDirRePop->iNextOldChild, cOldChildren - 1);
|
---|
| 1141 | KU32 iCur;
|
---|
| 1142 | KI32 cInc;
|
---|
| 1143 | KI32 cDirLefts;
|
---|
| 1144 |
|
---|
| 1145 | kHlpAssertReturn(cOldChildren > 0, NULL);
|
---|
| 1146 |
|
---|
| 1147 | /*
|
---|
| 1148 | * Search by file ID first, if we've got one.
|
---|
| 1149 | * ASSUMES that KU32 wraps around when -1 is added to 0.
|
---|
| 1150 | */
|
---|
| 1151 | if ( idFile != 0
|
---|
| 1152 | && idFile != KI64_MAX
|
---|
| 1153 | && idFile != KI64_MIN)
|
---|
| 1154 | {
|
---|
| 1155 | cInc = pDirRePop->cNextOldChildInc;
|
---|
| 1156 | kHlpAssert(cInc == -1 || cInc == 1);
|
---|
| 1157 | for (cDirLefts = 2; cDirLefts > 0; cDirLefts--)
|
---|
| 1158 | {
|
---|
| 1159 | for (iCur = iNextOldChild; iCur < cOldChildren; iCur += cInc)
|
---|
| 1160 | {
|
---|
| 1161 | PKFSOBJ pCur = pDirRePop->papOldChildren[iCur];
|
---|
| 1162 | if (pCur->Stats.st_ino == idFile)
|
---|
| 1163 | {
|
---|
| 1164 | /* Remove it and check the name. */
|
---|
| 1165 | pDirRePop->cOldChildren = --cOldChildren;
|
---|
| 1166 | if (iCur < cOldChildren)
|
---|
| 1167 | pDirRePop->papOldChildren[iCur] = pDirRePop->papOldChildren[cOldChildren];
|
---|
| 1168 | else
|
---|
| 1169 | cInc = -1;
|
---|
| 1170 | pDirRePop->cNextOldChildInc = cInc;
|
---|
| 1171 | pDirRePop->iNextOldChild = iCur + cInc;
|
---|
| 1172 |
|
---|
| 1173 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 1174 | return kFsCacheDirCheckOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName);
|
---|
| 1175 | #else
|
---|
| 1176 | return kFsCacheDirCheckOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName);
|
---|
| 1177 | #endif
|
---|
| 1178 | }
|
---|
| 1179 | }
|
---|
| 1180 | cInc = -cInc;
|
---|
| 1181 | }
|
---|
| 1182 | }
|
---|
| 1183 |
|
---|
| 1184 | /*
|
---|
| 1185 | * Search by name.
|
---|
| 1186 | * ASSUMES that KU32 wraps around when -1 is added to 0.
|
---|
| 1187 | */
|
---|
| 1188 | cInc = pDirRePop->cNextOldChildInc;
|
---|
| 1189 | kHlpAssert(cInc == -1 || cInc == 1);
|
---|
| 1190 | for (cDirLefts = 2; cDirLefts > 0; cDirLefts--)
|
---|
| 1191 | {
|
---|
| 1192 | for (iCur = iNextOldChild; iCur < cOldChildren; iCur += cInc)
|
---|
| 1193 | {
|
---|
| 1194 | PKFSOBJ pCur = pDirRePop->papOldChildren[iCur];
|
---|
| 1195 | if ( ( pCur->cwcName == cwcName
|
---|
| 1196 | && kFsCacheIAreEqualW(pCur->pwszName, pwcName, cwcName))
|
---|
| 1197 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 1198 | || ( pCur->cwcShortName == cwcName
|
---|
| 1199 | && pCur->pwszShortName != pCur->pwszName
|
---|
| 1200 | && kFsCacheIAreEqualW(pCur->pwszShortName, pwcName, cwcName))
|
---|
| 1201 | #endif
|
---|
| 1202 | )
|
---|
| 1203 | {
|
---|
| 1204 | /* Do this first so the compiler can share the rest with the above file ID return. */
|
---|
| 1205 | if (pCur->Stats.st_ino == idFile)
|
---|
| 1206 | { /* likely */ }
|
---|
| 1207 | else
|
---|
| 1208 | pCur = kFsCacheDirRefreshOldChildFileId(pDirRePop, pCur, idFile);
|
---|
| 1209 |
|
---|
| 1210 | /* Remove it and check the name. */
|
---|
| 1211 | pDirRePop->cOldChildren = --cOldChildren;
|
---|
| 1212 | if (iCur < cOldChildren)
|
---|
| 1213 | pDirRePop->papOldChildren[iCur] = pDirRePop->papOldChildren[cOldChildren];
|
---|
| 1214 | else
|
---|
| 1215 | cInc = -1;
|
---|
| 1216 | pDirRePop->cNextOldChildInc = cInc;
|
---|
| 1217 | pDirRePop->iNextOldChild = iCur + cInc;
|
---|
| 1218 |
|
---|
| 1219 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 1220 | return kFsCacheDirCheckOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName);
|
---|
| 1221 | #else
|
---|
| 1222 | return kFsCacheDirCheckOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName);
|
---|
| 1223 | #endif
|
---|
| 1224 | }
|
---|
| 1225 | }
|
---|
| 1226 | cInc = -cInc;
|
---|
| 1227 | }
|
---|
| 1228 |
|
---|
| 1229 | return NULL;
|
---|
| 1230 | }
|
---|
| 1231 |
|
---|
| 1232 |
|
---|
| 1233 |
|
---|
| 1234 | /**
|
---|
| 1235 | * Worker for kFsCachePopuplateOrRefreshDir that locates an old child object
|
---|
| 1236 | * while re-populating a directory.
|
---|
| 1237 | *
|
---|
| 1238 | * @returns Pointer to the existing object if found, NULL if not.
|
---|
| 1239 | * @param pDirRePop Repopulation data.
|
---|
| 1240 | * @param idFile The file ID, 0 if none.
|
---|
| 1241 | * @param pwcName The file name.
|
---|
| 1242 | * @param cwcName The length of the filename (in wchar_t's).
|
---|
| 1243 | * @param pwcShortName The short name, if present.
|
---|
| 1244 | * @param cwcShortName The length of the short name (in wchar_t's).
|
---|
| 1245 | */
|
---|
| 1246 | K_INLINE PKFSOBJ kFsCacheDirFindOldChild(PKFSDIRREPOP pDirRePop, KI64 idFile, wchar_t const *pwcName, KU32 cwcName
|
---|
| 1247 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 1248 | , wchar_t const *pwcShortName, KU32 cwcShortName
|
---|
| 1249 | #endif
|
---|
| 1250 | )
|
---|
| 1251 | {
|
---|
| 1252 | /*
|
---|
| 1253 | * We only check the iNextOldChild element here, hoping that the compiler
|
---|
| 1254 | * will actually inline this code, letting the slow version of the function
|
---|
| 1255 | * do the rest.
|
---|
| 1256 | */
|
---|
| 1257 | KU32 cOldChildren = pDirRePop->cOldChildren;
|
---|
| 1258 | if (cOldChildren > 0)
|
---|
| 1259 | {
|
---|
[2944] | 1260 | KU32 const iNextOldChild = K_MIN(pDirRePop->iNextOldChild, cOldChildren - 1);
|
---|
[2863] | 1261 | PKFSOBJ pCur = pDirRePop->papOldChildren[iNextOldChild];
|
---|
| 1262 |
|
---|
| 1263 | if ( pCur->Stats.st_ino == idFile
|
---|
| 1264 | && idFile != 0
|
---|
| 1265 | && idFile != KI64_MAX
|
---|
| 1266 | && idFile != KI64_MIN)
|
---|
| 1267 | pCur = kFsCacheDirCheckOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName);
|
---|
| 1268 | else if ( pCur->cwcName == cwcName
|
---|
| 1269 | && kHlpMemComp(pCur->pwszName, pwcName, cwcName * sizeof(wchar_t)) == 0)
|
---|
| 1270 | {
|
---|
| 1271 | if (pCur->Stats.st_ino == idFile)
|
---|
| 1272 | { /* likely */ }
|
---|
| 1273 | else
|
---|
| 1274 | pCur = kFsCacheDirRefreshOldChildFileId(pDirRePop, pCur, idFile);
|
---|
| 1275 |
|
---|
| 1276 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 1277 | if (cwcShortName == 0
|
---|
| 1278 | ? pCur->pwszShortName == pCur->pwszName
|
---|
| 1279 | || ( pCur->cwcShortName == cwcName
|
---|
| 1280 | && kHlpMemComp(pCur->pwszShortName, pCur->pwszName, cwcName * sizeof(wchar_t)) == 0)
|
---|
| 1281 | : pCur->cwcShortName == cwcShortName
|
---|
| 1282 | && kHlpMemComp(pCur->pwszShortName, pwcShortName, cwcShortName * sizeof(wchar_t)) == 0 )
|
---|
| 1283 | { /* likely */ }
|
---|
| 1284 | else
|
---|
| 1285 | pCur = kFsCacheDirRefreshOldChildName(pDirRePop, pCur, pwcName, cwcName, pwcShortName, cwcShortName);
|
---|
| 1286 | #endif
|
---|
| 1287 | }
|
---|
| 1288 | else
|
---|
| 1289 | pCur = NULL;
|
---|
| 1290 | if (pCur)
|
---|
| 1291 | {
|
---|
| 1292 | /*
|
---|
| 1293 | * Got a match. Remove the child from the array, replacing it with
|
---|
| 1294 | * the last element. (This means we're reversing the second half of
|
---|
| 1295 | * the elements, which is why we need cNextOldChildInc.)
|
---|
| 1296 | */
|
---|
| 1297 | pDirRePop->cOldChildren = --cOldChildren;
|
---|
| 1298 | if (iNextOldChild < cOldChildren)
|
---|
| 1299 | pDirRePop->papOldChildren[iNextOldChild] = pDirRePop->papOldChildren[cOldChildren];
|
---|
| 1300 | pDirRePop->iNextOldChild = iNextOldChild + pDirRePop->cNextOldChildInc;
|
---|
| 1301 | return pCur;
|
---|
| 1302 | }
|
---|
| 1303 |
|
---|
| 1304 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 1305 | return kFsCacheDirFindOldChildSlow(pDirRePop, idFile, pwcName, cwcName, pwcShortName, cwcShortName);
|
---|
| 1306 | #else
|
---|
| 1307 | return kFsCacheDirFindOldChildSlow(pDirRePop, idFile, pwcName, cwcName);
|
---|
| 1308 | #endif
|
---|
| 1309 | }
|
---|
| 1310 |
|
---|
| 1311 | return NULL;
|
---|
| 1312 | }
|
---|
| 1313 |
|
---|
| 1314 |
|
---|
| 1315 |
|
---|
| 1316 | /**
|
---|
[2851] | 1317 | * Does the initial directory populating or refreshes it if it has been
|
---|
| 1318 | * invalidated.
|
---|
[2832] | 1319 | *
|
---|
[2851] | 1320 | * This assumes the parent directory is opened.
|
---|
[2832] | 1321 | *
|
---|
[2851] | 1322 | * @returns K_TRUE on success, K_FALSE on error.
|
---|
| 1323 | * @param pCache The cache.
|
---|
| 1324 | * @param pDir The directory.
|
---|
| 1325 | * @param penmError Where to store K_FALSE explanation.
|
---|
[2832] | 1326 | */
|
---|
[2851] | 1327 | static KBOOL kFsCachePopuplateOrRefreshDir(PKFSCACHE pCache, PKFSDIR pDir, KFSLOOKUPERROR *penmError)
|
---|
[2832] | 1328 | {
|
---|
[2863] | 1329 | KBOOL fRefreshing = K_FALSE;
|
---|
| 1330 | KFSDIRREPOP DirRePop = { NULL, 0, 0, 0, NULL };
|
---|
| 1331 | MY_UNICODE_STRING UniStrStar = { 1 * sizeof(wchar_t), 2 * sizeof(wchar_t), L"*" };
|
---|
[3381] | 1332 | FILETIME Now;
|
---|
[2863] | 1333 |
|
---|
| 1334 | /** @todo May have to make this more flexible wrt information classes since
|
---|
[2851] | 1335 | * older windows versions (XP, w2K) might not correctly support the
|
---|
| 1336 | * ones with file ID on all file systems. */
|
---|
| 1337 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
[2852] | 1338 | MY_FILE_INFORMATION_CLASS const enmInfoClassWithId = MyFileIdBothDirectoryInformation;
|
---|
| 1339 | MY_FILE_INFORMATION_CLASS enmInfoClass = MyFileIdBothDirectoryInformation;
|
---|
[2851] | 1340 | #else
|
---|
[2852] | 1341 | MY_FILE_INFORMATION_CLASS const enmInfoClassWithId = MyFileIdFullDirectoryInformation;
|
---|
| 1342 | MY_FILE_INFORMATION_CLASS enmInfoClass = MyFileIdFullDirectoryInformation;
|
---|
[2851] | 1343 | #endif
|
---|
| 1344 | MY_NTSTATUS rcNt;
|
---|
| 1345 | MY_IO_STATUS_BLOCK Ios;
|
---|
| 1346 | union
|
---|
[2832] | 1347 | {
|
---|
[2851] | 1348 | /* Include the structures for better alignment. */
|
---|
| 1349 | MY_FILE_ID_BOTH_DIR_INFORMATION WithId;
|
---|
| 1350 | MY_FILE_ID_FULL_DIR_INFORMATION NoId;
|
---|
[3005] | 1351 | /** Buffer padding. We're using a 56KB buffer here to avoid size troubles
|
---|
| 1352 | * with CIFS and such that starts at 64KB. */
|
---|
[2851] | 1353 | KU8 abBuf[56*1024];
|
---|
| 1354 | } uBuf;
|
---|
[2832] | 1355 |
|
---|
[2863] | 1356 |
|
---|
[2851] | 1357 | /*
|
---|
| 1358 | * Open the directory.
|
---|
| 1359 | */
|
---|
| 1360 | if (pDir->hDir == INVALID_HANDLE_VALUE)
|
---|
[2832] | 1361 | {
|
---|
[2851] | 1362 | MY_OBJECT_ATTRIBUTES ObjAttr;
|
---|
| 1363 | MY_UNICODE_STRING UniStr;
|
---|
[2832] | 1364 |
|
---|
[2851] | 1365 | kHlpAssert(!pDir->fPopulated);
|
---|
[2832] | 1366 |
|
---|
[2851] | 1367 | Ios.Information = -1;
|
---|
| 1368 | Ios.u.Status = -1;
|
---|
[2832] | 1369 |
|
---|
[2851] | 1370 | UniStr.Buffer = (wchar_t *)pDir->Obj.pwszName;
|
---|
| 1371 | UniStr.Length = (USHORT)(pDir->Obj.cwcName * sizeof(wchar_t));
|
---|
| 1372 | UniStr.MaximumLength = UniStr.Length + sizeof(wchar_t);
|
---|
[2832] | 1373 |
|
---|
[2851] | 1374 | kHlpAssertStmtReturn(pDir->Obj.pParent, *penmError = KFSLOOKUPERROR_INTERNAL_ERROR, K_FALSE);
|
---|
| 1375 | kHlpAssertStmtReturn(pDir->Obj.pParent->hDir != INVALID_HANDLE_VALUE, *penmError = KFSLOOKUPERROR_INTERNAL_ERROR, K_FALSE);
|
---|
| 1376 | MyInitializeObjectAttributes(&ObjAttr, &UniStr, OBJ_CASE_INSENSITIVE, pDir->Obj.pParent->hDir, NULL /*pSecAttr*/);
|
---|
[2832] | 1377 |
|
---|
[2851] | 1378 | /** @todo FILE_OPEN_REPARSE_POINT? */
|
---|
| 1379 | rcNt = g_pfnNtCreateFile(&pDir->hDir,
|
---|
| 1380 | FILE_READ_DATA | FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
|
---|
| 1381 | &ObjAttr,
|
---|
| 1382 | &Ios,
|
---|
| 1383 | NULL, /*cbFileInitialAlloc */
|
---|
| 1384 | FILE_ATTRIBUTE_NORMAL,
|
---|
| 1385 | FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
---|
| 1386 | FILE_OPEN,
|
---|
| 1387 | FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
|
---|
| 1388 | NULL, /*pEaBuffer*/
|
---|
| 1389 | 0); /*cbEaBuffer*/
|
---|
| 1390 | if (MY_NT_SUCCESS(rcNt))
|
---|
| 1391 | { /* likely */ }
|
---|
| 1392 | else
|
---|
| 1393 | {
|
---|
| 1394 | pDir->hDir = INVALID_HANDLE_VALUE;
|
---|
| 1395 | *penmError = KFSLOOKUPERROR_DIR_OPEN_ERROR;
|
---|
| 1396 | return K_FALSE;
|
---|
| 1397 | }
|
---|
[2831] | 1398 | }
|
---|
[2863] | 1399 | /*
|
---|
| 1400 | * When re-populating, we replace papChildren in the directory and pick
|
---|
| 1401 | * from the old one as we go along.
|
---|
| 1402 | */
|
---|
[2851] | 1403 | else if (pDir->fPopulated)
|
---|
[2832] | 1404 | {
|
---|
[2948] | 1405 | KU32 cAllocated;
|
---|
| 1406 | void *pvNew;
|
---|
| 1407 |
|
---|
| 1408 | /* Make sure we really need to do this first. */
|
---|
| 1409 | if (!pDir->fNeedRePopulating)
|
---|
| 1410 | {
|
---|
| 1411 | if ( pDir->Obj.uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
|
---|
| 1412 | || pDir->Obj.uCacheGen == pCache->auGenerations[pDir->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN])
|
---|
| 1413 | return K_TRUE;
|
---|
| 1414 | if ( kFsCacheRefreshObj(pCache, &pDir->Obj, penmError)
|
---|
| 1415 | && !pDir->fNeedRePopulating)
|
---|
| 1416 | return K_TRUE;
|
---|
| 1417 | }
|
---|
| 1418 |
|
---|
| 1419 | /* Yes we do need to. */
|
---|
| 1420 | cAllocated = K_ALIGN_Z(pDir->cChildren, 16);
|
---|
| 1421 | pvNew = kHlpAlloc(sizeof(pDir->papChildren[0]) * cAllocated);
|
---|
[2863] | 1422 | if (pvNew)
|
---|
| 1423 | {
|
---|
| 1424 | DirRePop.papOldChildren = pDir->papChildren;
|
---|
| 1425 | DirRePop.cOldChildren = pDir->cChildren;
|
---|
| 1426 | DirRePop.iNextOldChild = 0;
|
---|
| 1427 | DirRePop.cNextOldChildInc = 1;
|
---|
| 1428 | DirRePop.pCache = pCache;
|
---|
| 1429 |
|
---|
| 1430 | pDir->cChildren = 0;
|
---|
| 1431 | pDir->cChildrenAllocated = cAllocated;
|
---|
| 1432 | pDir->papChildren = (PKFSOBJ *)pvNew;
|
---|
| 1433 | }
|
---|
| 1434 | else
|
---|
| 1435 | {
|
---|
| 1436 | *penmError = KFSLOOKUPERROR_OUT_OF_MEMORY;
|
---|
| 1437 | return K_FALSE;
|
---|
| 1438 | }
|
---|
| 1439 |
|
---|
[2851] | 1440 | fRefreshing = K_TRUE;
|
---|
[2832] | 1441 | }
|
---|
[2862] | 1442 | if (!fRefreshing)
|
---|
| 1443 | KFSCACHE_LOG(("Populating %s...\n", pDir->Obj.pszName));
|
---|
| 1444 | else
|
---|
| 1445 | KFSCACHE_LOG(("Refreshing %s...\n", pDir->Obj.pszName));
|
---|
[2832] | 1446 |
|
---|
| 1447 | /*
|
---|
[2851] | 1448 | * Enumerate the directory content.
|
---|
[2863] | 1449 | *
|
---|
| 1450 | * Note! The "*" filter is necessary because kFsCacheRefreshObj may have
|
---|
| 1451 | * previously quried a single file name and just passing NULL would
|
---|
| 1452 | * restart that single file name query.
|
---|
[2832] | 1453 | */
|
---|
[3381] | 1454 | GetSystemTimeAsFileTime(&Now);
|
---|
| 1455 | pDir->iLastPopulated = ((KI64)Now.dwHighDateTime << 32) | Now.dwLowDateTime;
|
---|
[2851] | 1456 | Ios.Information = -1;
|
---|
| 1457 | Ios.u.Status = -1;
|
---|
| 1458 | rcNt = g_pfnNtQueryDirectoryFile(pDir->hDir,
|
---|
| 1459 | NULL, /* hEvent */
|
---|
| 1460 | NULL, /* pfnApcComplete */
|
---|
| 1461 | NULL, /* pvApcCompleteCtx */
|
---|
| 1462 | &Ios,
|
---|
| 1463 | &uBuf,
|
---|
| 1464 | sizeof(uBuf),
|
---|
| 1465 | enmInfoClass,
|
---|
| 1466 | FALSE, /* fReturnSingleEntry */
|
---|
[2863] | 1467 | &UniStrStar, /* Filter / restart pos. */
|
---|
[2851] | 1468 | TRUE); /* fRestartScan */
|
---|
| 1469 | while (MY_NT_SUCCESS(rcNt))
|
---|
[2832] | 1470 | {
|
---|
[2851] | 1471 | /*
|
---|
| 1472 | * Process the entries in the buffer.
|
---|
| 1473 | */
|
---|
| 1474 | KSIZE offBuf = 0;
|
---|
| 1475 | for (;;)
|
---|
[2832] | 1476 | {
|
---|
[2851] | 1477 | union
|
---|
| 1478 | {
|
---|
| 1479 | KU8 *pb;
|
---|
| 1480 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 1481 | MY_FILE_ID_BOTH_DIR_INFORMATION *pWithId;
|
---|
| 1482 | MY_FILE_BOTH_DIR_INFORMATION *pNoId;
|
---|
| 1483 | #else
|
---|
| 1484 | MY_FILE_ID_FULL_DIR_INFORMATION *pWithId;
|
---|
| 1485 | MY_FILE_FULL_DIR_INFORMATION *pNoId;
|
---|
| 1486 | #endif
|
---|
| 1487 | } uPtr;
|
---|
| 1488 | PKFSOBJ pCur;
|
---|
| 1489 | KU32 offNext;
|
---|
| 1490 | KU32 cbMinCur;
|
---|
[2863] | 1491 | wchar_t *pwchFilename;
|
---|
[2832] | 1492 |
|
---|
[2851] | 1493 | /* ASSUME only the FileName member differs between the two structures. */
|
---|
| 1494 | uPtr.pb = &uBuf.abBuf[offBuf];
|
---|
[2852] | 1495 | if (enmInfoClass == enmInfoClassWithId)
|
---|
| 1496 | {
|
---|
[2863] | 1497 | pwchFilename = &uPtr.pWithId->FileName[0];
|
---|
[2852] | 1498 | cbMinCur = (KU32)((uintptr_t)&uPtr.pWithId->FileName[0] - (uintptr_t)uPtr.pWithId);
|
---|
| 1499 | cbMinCur += uPtr.pNoId->FileNameLength;
|
---|
| 1500 | }
|
---|
| 1501 | else
|
---|
| 1502 | {
|
---|
[2863] | 1503 | pwchFilename = &uPtr.pNoId->FileName[0];
|
---|
[2852] | 1504 | cbMinCur = (KU32)((uintptr_t)&uPtr.pNoId->FileName[0] - (uintptr_t)uPtr.pNoId);
|
---|
| 1505 | cbMinCur += uPtr.pNoId->FileNameLength;
|
---|
| 1506 | }
|
---|
| 1507 |
|
---|
[2859] | 1508 | /* We need to skip the '.' and '..' entries. */
|
---|
[2863] | 1509 | if ( *pwchFilename != '.'
|
---|
[2859] | 1510 | || uPtr.pNoId->FileNameLength > 4
|
---|
| 1511 | || !( uPtr.pNoId->FileNameLength == 2
|
---|
| 1512 | || ( uPtr.pNoId->FileNameLength == 4
|
---|
[2863] | 1513 | && pwchFilename[1] == '.') )
|
---|
[2859] | 1514 | )
|
---|
| 1515 | {
|
---|
[2863] | 1516 | KBOOL fRc;
|
---|
| 1517 | KU8 const bObjType = uPtr.pNoId->FileAttributes & FILE_ATTRIBUTE_DIRECTORY ? KFSOBJ_TYPE_DIR
|
---|
| 1518 | : uPtr.pNoId->FileAttributes & (FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_REPARSE_POINT)
|
---|
| 1519 | ? KFSOBJ_TYPE_OTHER : KFSOBJ_TYPE_FILE;
|
---|
| 1520 |
|
---|
[2859] | 1521 | /*
|
---|
[2863] | 1522 | * If refreshing, we must first see if this directory entry already
|
---|
| 1523 | * exists.
|
---|
[2859] | 1524 | */
|
---|
[2863] | 1525 | if (!fRefreshing)
|
---|
| 1526 | pCur = NULL;
|
---|
| 1527 | else
|
---|
| 1528 | {
|
---|
| 1529 | pCur = kFsCacheDirFindOldChild(&DirRePop,
|
---|
| 1530 | enmInfoClass == enmInfoClassWithId ? uPtr.pWithId->FileId.QuadPart : 0,
|
---|
| 1531 | pwchFilename, uPtr.pWithId->FileNameLength / sizeof(wchar_t)
|
---|
[2851] | 1532 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
[2863] | 1533 | , uPtr.pWithId->ShortName, uPtr.pWithId->ShortNameLength / sizeof(wchar_t)
|
---|
[2851] | 1534 | #endif
|
---|
[2863] | 1535 | );
|
---|
| 1536 | if (pCur)
|
---|
| 1537 | {
|
---|
| 1538 | if (pCur->bObjType == bObjType)
|
---|
| 1539 | {
|
---|
| 1540 | if (pCur->bObjType == KFSOBJ_TYPE_DIR)
|
---|
| 1541 | {
|
---|
| 1542 | PKFSDIR pCurDir = (PKFSDIR)pCur;
|
---|
| 1543 | if ( !pCurDir->fPopulated
|
---|
| 1544 | || ( pCurDir->iLastWrite == uPtr.pWithId->LastWriteTime.QuadPart
|
---|
[3381] | 1545 | && (pCur->fFlags & KFSOBJ_F_WORKING_DIR_MTIME)
|
---|
| 1546 | && pCurDir->iLastPopulated - pCurDir->iLastWrite
|
---|
| 1547 | >= KFSCACHE_MIN_LAST_POPULATED_VS_WRITE ))
|
---|
[2863] | 1548 | { /* kind of likely */ }
|
---|
| 1549 | else
|
---|
| 1550 | {
|
---|
| 1551 | KFSCACHE_LOG(("Refreshing %s/%s/ - %s/ needs re-populating...\n",
|
---|
| 1552 | pDir->Obj.pParent->Obj.pszName, pDir->Obj.pszName, pCur->pszName));
|
---|
| 1553 | pCurDir->fNeedRePopulating = K_TRUE;
|
---|
| 1554 | }
|
---|
| 1555 | }
|
---|
[3379] | 1556 | if (pCur->uCacheGen != KFSOBJ_CACHE_GEN_IGNORE)
|
---|
| 1557 | pCur->uCacheGen = pCache->auGenerations[pCur->fFlags & KFSOBJ_F_USE_CUSTOM_GEN];
|
---|
[2863] | 1558 | }
|
---|
| 1559 | else if (pCur->bObjType == KFSOBJ_TYPE_MISSING)
|
---|
| 1560 | {
|
---|
| 1561 | KFSCACHE_LOG(("Refreshing %s/%s/ - %s appeared as %u, was missing.\n",
|
---|
| 1562 | pDir->Obj.pParent->Obj.pszName, pDir->Obj.pszName, pCur->pszName, bObjType));
|
---|
| 1563 | pCur->bObjType = bObjType;
|
---|
[3379] | 1564 | if (pCur->uCacheGen != KFSOBJ_CACHE_GEN_IGNORE)
|
---|
| 1565 | pCur->uCacheGen = pCache->auGenerations[pCur->fFlags & KFSOBJ_F_USE_CUSTOM_GEN];
|
---|
[2863] | 1566 | }
|
---|
| 1567 | else
|
---|
| 1568 | {
|
---|
| 1569 | KFSCACHE_LOG(("Refreshing %s/%s/ - %s changed type from %u to %u! Dropping old object.\n",
|
---|
| 1570 | pDir->Obj.pParent->Obj.pszName, pDir->Obj.pszName, pCur->pszName,
|
---|
| 1571 | pCur->bObjType, bObjType));
|
---|
| 1572 | kFsCacheObjRelease(pCache, pCur);
|
---|
| 1573 | pCur = NULL;
|
---|
| 1574 | }
|
---|
| 1575 | }
|
---|
| 1576 | else
|
---|
| 1577 | KFSCACHE_LOG(("Refreshing %s/%s/ - %*.*ls added.\n", pDir->Obj.pParent->Obj.pszName, pDir->Obj.pszName,
|
---|
| 1578 | uPtr.pNoId->FileNameLength / sizeof(wchar_t), uPtr.pNoId->FileNameLength / sizeof(wchar_t),
|
---|
| 1579 | pwchFilename));
|
---|
| 1580 | }
|
---|
| 1581 |
|
---|
[2859] | 1582 | if (!pCur)
|
---|
[2863] | 1583 | {
|
---|
| 1584 | /*
|
---|
| 1585 | * Create the entry (not linked yet).
|
---|
| 1586 | */
|
---|
| 1587 | pCur = kFsCacheCreateObjectW(pCache, pDir, pwchFilename, uPtr.pNoId->FileNameLength / sizeof(wchar_t),
|
---|
| 1588 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 1589 | uPtr.pNoId->ShortName, uPtr.pNoId->ShortNameLength / sizeof(wchar_t),
|
---|
| 1590 | #endif
|
---|
| 1591 | bObjType, penmError);
|
---|
| 1592 | if (!pCur)
|
---|
| 1593 | return K_FALSE;
|
---|
| 1594 | kHlpAssert(pCur->cRefs == 1);
|
---|
| 1595 | }
|
---|
[2832] | 1596 |
|
---|
[2851] | 1597 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
[2859] | 1598 | if (enmInfoClass == enmInfoClassWithId)
|
---|
[3007] | 1599 | birdStatFillFromFileIdBothDirInfo(&pCur->Stats, uPtr.pWithId);
|
---|
[2859] | 1600 | else
|
---|
[3007] | 1601 | birdStatFillFromFileBothDirInfo(&pCur->Stats, uPtr.pNoId);
|
---|
[2851] | 1602 | #else
|
---|
[2859] | 1603 | if (enmInfoClass == enmInfoClassWithId)
|
---|
[3007] | 1604 | birdStatFillFromFileIdFullDirInfo(&pCur->Stats, uPtr.pWithId);
|
---|
[2859] | 1605 | else
|
---|
[3007] | 1606 | birdStatFillFromFileFullDirInfo(&pCur->Stats, uPtr.pNoId);
|
---|
[2851] | 1607 | #endif
|
---|
[2859] | 1608 | pCur->Stats.st_dev = pDir->uDevNo;
|
---|
| 1609 | pCur->fHaveStats = K_TRUE;
|
---|
[2851] | 1610 |
|
---|
[2859] | 1611 | /*
|
---|
[2863] | 1612 | * Add the entry to the directory.
|
---|
[2859] | 1613 | */
|
---|
[2863] | 1614 | fRc = kFsCacheDirAddChild(pCache, pDir, pCur, penmError);
|
---|
| 1615 | kFsCacheObjRelease(pCache, pCur);
|
---|
| 1616 | if (fRc)
|
---|
| 1617 | { /* likely */ }
|
---|
| 1618 | else
|
---|
[2859] | 1619 | {
|
---|
[2863] | 1620 | rcNt = STATUS_NO_MEMORY;
|
---|
| 1621 | break;
|
---|
[2859] | 1622 | }
|
---|
[2832] | 1623 | }
|
---|
[2851] | 1624 | /*
|
---|
[2859] | 1625 | * When seeing '.' we update the directory info.
|
---|
[2851] | 1626 | */
|
---|
[2859] | 1627 | else if (uPtr.pNoId->FileNameLength == 2)
|
---|
[2832] | 1628 | {
|
---|
[2859] | 1629 | pDir->iLastWrite = uPtr.pNoId->LastWriteTime.QuadPart;
|
---|
| 1630 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 1631 | if (enmInfoClass == enmInfoClassWithId)
|
---|
[3007] | 1632 | birdStatFillFromFileIdBothDirInfo(&pDir->Obj.Stats, uPtr.pWithId);
|
---|
[2851] | 1633 | else
|
---|
[3007] | 1634 | birdStatFillFromFileBothDirInfo(&pDir->Obj.Stats, uPtr.pNoId);
|
---|
[2859] | 1635 | #else
|
---|
| 1636 | if (enmInfoClass == enmInfoClassWithId)
|
---|
[3007] | 1637 | birdStatFillFromFileIdFullDirInfo(&pDir->Obj.Stats, uPtr.pWithId);
|
---|
[2859] | 1638 | else
|
---|
[3007] | 1639 | birdStatFillFromFileFullDirInfo(&pDir->Obj.Stats, uPtr.pNoId);
|
---|
[2859] | 1640 | #endif
|
---|
[2851] | 1641 | }
|
---|
[2832] | 1642 |
|
---|
[2851] | 1643 | /*
|
---|
| 1644 | * Advance.
|
---|
| 1645 | */
|
---|
| 1646 | offNext = uPtr.pNoId->NextEntryOffset;
|
---|
| 1647 | if ( offNext >= cbMinCur
|
---|
| 1648 | && offNext < sizeof(uBuf))
|
---|
| 1649 | offBuf += offNext;
|
---|
[2832] | 1650 | else
|
---|
[2851] | 1651 | break;
|
---|
[2832] | 1652 | }
|
---|
| 1653 |
|
---|
| 1654 | /*
|
---|
[2851] | 1655 | * Read the next chunk.
|
---|
[2832] | 1656 | */
|
---|
[2851] | 1657 | rcNt = g_pfnNtQueryDirectoryFile(pDir->hDir,
|
---|
| 1658 | NULL, /* hEvent */
|
---|
| 1659 | NULL, /* pfnApcComplete */
|
---|
| 1660 | NULL, /* pvApcCompleteCtx */
|
---|
| 1661 | &Ios,
|
---|
| 1662 | &uBuf,
|
---|
| 1663 | sizeof(uBuf),
|
---|
| 1664 | enmInfoClass,
|
---|
| 1665 | FALSE, /* fReturnSingleEntry */
|
---|
[2863] | 1666 | &UniStrStar, /* Filter / restart pos. */
|
---|
[2851] | 1667 | FALSE); /* fRestartScan */
|
---|
[2832] | 1668 | }
|
---|
| 1669 |
|
---|
[2851] | 1670 | if (rcNt == MY_STATUS_NO_MORE_FILES)
|
---|
[2856] | 1671 | {
|
---|
| 1672 | /*
|
---|
[2863] | 1673 | * If refreshing, add missing children objects and ditch the rest.
|
---|
| 1674 | * We ignore errors while adding missing children (lazy bird).
|
---|
| 1675 | */
|
---|
| 1676 | if (!fRefreshing)
|
---|
| 1677 | { /* more likely */ }
|
---|
| 1678 | else
|
---|
| 1679 | {
|
---|
| 1680 | while (DirRePop.cOldChildren > 0)
|
---|
| 1681 | {
|
---|
| 1682 | KFSLOOKUPERROR enmErrorIgn;
|
---|
| 1683 | PKFSOBJ pOldChild = DirRePop.papOldChildren[--DirRePop.cOldChildren];
|
---|
| 1684 | if (pOldChild->bObjType == KFSOBJ_TYPE_MISSING)
|
---|
| 1685 | kFsCacheDirAddChild(pCache, pDir, pOldChild, &enmErrorIgn);
|
---|
| 1686 | else
|
---|
| 1687 | {
|
---|
| 1688 | KFSCACHE_LOG(("Refreshing %s/%s/ - %s was removed.\n",
|
---|
| 1689 | pDir->Obj.pParent->Obj.pszName, pDir->Obj.pszName, pOldChild->pszName));
|
---|
| 1690 | kHlpAssert(pOldChild->bObjType != KFSOBJ_TYPE_DIR);
|
---|
[2930] | 1691 | /* Remove from hash table. */
|
---|
| 1692 | if (pOldChild->uNameHash != 0)
|
---|
| 1693 | {
|
---|
| 1694 | KU32 idx = pOldChild->uNameHash & pDir->fHashTabMask;
|
---|
| 1695 | PKFSOBJ pPrev = pDir->papHashTab[idx];
|
---|
| 1696 | if (pPrev == pOldChild)
|
---|
| 1697 | pDir->papHashTab[idx] = pOldChild->pNextNameHash;
|
---|
| 1698 | else
|
---|
| 1699 | {
|
---|
| 1700 | while (pPrev && pPrev->pNextNameHash != pOldChild)
|
---|
| 1701 | pPrev = pPrev->pNextNameHash;
|
---|
| 1702 | kHlpAssert(pPrev);
|
---|
| 1703 | if (pPrev)
|
---|
| 1704 | pPrev->pNextNameHash = pOldChild->pNextNameHash;
|
---|
| 1705 | }
|
---|
| 1706 | pOldChild->uNameHash = 0;
|
---|
| 1707 | }
|
---|
[2863] | 1708 | }
|
---|
| 1709 | kFsCacheObjRelease(pCache, pOldChild);
|
---|
| 1710 | }
|
---|
| 1711 | kHlpFree(DirRePop.papOldChildren);
|
---|
| 1712 | }
|
---|
| 1713 |
|
---|
| 1714 | /*
|
---|
[2856] | 1715 | * Mark the directory as fully populated and up to date.
|
---|
| 1716 | */
|
---|
[2863] | 1717 | pDir->fPopulated = K_TRUE;
|
---|
| 1718 | pDir->fNeedRePopulating = K_FALSE;
|
---|
[2856] | 1719 | if (pDir->Obj.uCacheGen != KFSOBJ_CACHE_GEN_IGNORE)
|
---|
[2868] | 1720 | pDir->Obj.uCacheGen = pCache->auGenerations[pDir->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN];
|
---|
[2851] | 1721 | return K_TRUE;
|
---|
[2856] | 1722 | }
|
---|
| 1723 |
|
---|
[2863] | 1724 | /*
|
---|
| 1725 | * If we failed during refresh, add back remaining old children.
|
---|
| 1726 | */
|
---|
| 1727 | if (!fRefreshing)
|
---|
| 1728 | {
|
---|
| 1729 | while (DirRePop.cOldChildren > 0)
|
---|
| 1730 | {
|
---|
| 1731 | KFSLOOKUPERROR enmErrorIgn;
|
---|
| 1732 | PKFSOBJ pOldChild = DirRePop.papOldChildren[--DirRePop.cOldChildren];
|
---|
| 1733 | kFsCacheDirAddChild(pCache, pDir, pOldChild, &enmErrorIgn);
|
---|
| 1734 | kFsCacheObjRelease(pCache, pOldChild);
|
---|
| 1735 | }
|
---|
| 1736 | kHlpFree(DirRePop.papOldChildren);
|
---|
| 1737 | }
|
---|
| 1738 |
|
---|
[2851] | 1739 | kHlpAssertMsgFailed(("%#x\n", rcNt));
|
---|
| 1740 | *penmError = KFSLOOKUPERROR_DIR_READ_ERROR;
|
---|
| 1741 | return K_TRUE;
|
---|
[2832] | 1742 | }
|
---|
| 1743 |
|
---|
| 1744 |
|
---|
[2857] | 1745 | /**
|
---|
| 1746 | * Does the initial directory populating or refreshes it if it has been
|
---|
| 1747 | * invalidated.
|
---|
| 1748 | *
|
---|
| 1749 | * This assumes the parent directory is opened.
|
---|
| 1750 | *
|
---|
| 1751 | * @returns K_TRUE on success, K_FALSE on error.
|
---|
| 1752 | * @param pCache The cache.
|
---|
| 1753 | * @param pDir The directory.
|
---|
| 1754 | * @param penmError Where to store K_FALSE explanation. Optional.
|
---|
| 1755 | */
|
---|
| 1756 | KBOOL kFsCacheDirEnsurePopuplated(PKFSCACHE pCache, PKFSDIR pDir, KFSLOOKUPERROR *penmError)
|
---|
| 1757 | {
|
---|
| 1758 | KFSLOOKUPERROR enmIgnored;
|
---|
[3184] | 1759 | KBOOL fRet;
|
---|
| 1760 | KFSCACHE_LOCK(pCache);
|
---|
[2857] | 1761 | if ( pDir->fPopulated
|
---|
[2864] | 1762 | && !pDir->fNeedRePopulating
|
---|
[2857] | 1763 | && ( pDir->Obj.uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
|
---|
[2868] | 1764 | || pDir->Obj.uCacheGen == pCache->auGenerations[pDir->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN]) )
|
---|
[3184] | 1765 | fRet = K_TRUE;
|
---|
| 1766 | else
|
---|
| 1767 | fRet = kFsCachePopuplateOrRefreshDir(pCache, pDir, penmError ? penmError : &enmIgnored);
|
---|
| 1768 | KFSCACHE_UNLOCK(pCache);
|
---|
| 1769 | return fRet;
|
---|
[2857] | 1770 | }
|
---|
| 1771 |
|
---|
| 1772 |
|
---|
[2859] | 1773 | /**
|
---|
| 1774 | * Checks whether the modified timestamp differs on this directory.
|
---|
| 1775 | *
|
---|
| 1776 | * @returns K_TRUE if possibly modified, K_FALSE if definitely not modified.
|
---|
| 1777 | * @param pDir The directory..
|
---|
| 1778 | */
|
---|
| 1779 | static KBOOL kFsCacheDirIsModified(PKFSDIR pDir)
|
---|
| 1780 | {
|
---|
| 1781 | if ( pDir->hDir != INVALID_HANDLE_VALUE
|
---|
| 1782 | && (pDir->Obj.fFlags & KFSOBJ_F_WORKING_DIR_MTIME) )
|
---|
| 1783 | {
|
---|
[2948] | 1784 | if (!pDir->fNeedRePopulating)
|
---|
| 1785 | {
|
---|
| 1786 | MY_IO_STATUS_BLOCK Ios;
|
---|
| 1787 | MY_FILE_BASIC_INFORMATION BasicInfo;
|
---|
| 1788 | MY_NTSTATUS rcNt;
|
---|
[2859] | 1789 |
|
---|
[2948] | 1790 | Ios.Information = -1;
|
---|
| 1791 | Ios.u.Status = -1;
|
---|
[2859] | 1792 |
|
---|
[2948] | 1793 | rcNt = g_pfnNtQueryInformationFile(pDir->hDir, &Ios, &BasicInfo, sizeof(BasicInfo), MyFileBasicInformation);
|
---|
| 1794 | if (MY_NT_SUCCESS(rcNt))
|
---|
| 1795 | {
|
---|
[3381] | 1796 | if ( BasicInfo.LastWriteTime.QuadPart != pDir->iLastWrite
|
---|
| 1797 | || pDir->iLastPopulated - pDir->iLastWrite < KFSCACHE_MIN_LAST_POPULATED_VS_WRITE)
|
---|
[2948] | 1798 | {
|
---|
| 1799 | pDir->fNeedRePopulating = K_TRUE;
|
---|
| 1800 | return K_TRUE;
|
---|
| 1801 | }
|
---|
| 1802 | return K_FALSE;
|
---|
| 1803 | }
|
---|
| 1804 | }
|
---|
[2859] | 1805 | }
|
---|
[2862] | 1806 | /* The cache root never changes. */
|
---|
| 1807 | else if (!pDir->Obj.pParent)
|
---|
| 1808 | return K_FALSE;
|
---|
[2859] | 1809 |
|
---|
| 1810 | return K_TRUE;
|
---|
| 1811 | }
|
---|
| 1812 |
|
---|
| 1813 |
|
---|
[2851] | 1814 | static KBOOL kFsCacheRefreshMissing(PKFSCACHE pCache, PKFSOBJ pMissing, KFSLOOKUPERROR *penmError)
|
---|
[2832] | 1815 | {
|
---|
[2859] | 1816 | /*
|
---|
| 1817 | * If we can, we start by checking whether the parent directory
|
---|
| 1818 | * has been modified. If it has, we need to check if this entry
|
---|
| 1819 | * was added or not, most likely it wasn't added.
|
---|
| 1820 | */
|
---|
| 1821 | if (!kFsCacheDirIsModified(pMissing->pParent))
|
---|
[2862] | 1822 | {
|
---|
| 1823 | KFSCACHE_LOG(("Parent of missing not written to %s/%s\n", pMissing->pParent->Obj.pszName, pMissing->pszName));
|
---|
[2868] | 1824 | pMissing->uCacheGen = pCache->auGenerationsMissing[pMissing->fFlags & KFSOBJ_F_USE_CUSTOM_GEN];
|
---|
[2862] | 1825 | }
|
---|
[2859] | 1826 | else
|
---|
| 1827 | {
|
---|
| 1828 | MY_UNICODE_STRING UniStr;
|
---|
| 1829 | MY_OBJECT_ATTRIBUTES ObjAttr;
|
---|
| 1830 | MY_FILE_BASIC_INFORMATION BasicInfo;
|
---|
| 1831 | MY_NTSTATUS rcNt;
|
---|
| 1832 |
|
---|
| 1833 | UniStr.Buffer = (wchar_t *)pMissing->pwszName;
|
---|
| 1834 | UniStr.Length = (USHORT)(pMissing->cwcName * sizeof(wchar_t));
|
---|
| 1835 | UniStr.MaximumLength = UniStr.Length + sizeof(wchar_t);
|
---|
| 1836 |
|
---|
| 1837 | kHlpAssert(pMissing->pParent->hDir != INVALID_HANDLE_VALUE);
|
---|
| 1838 | MyInitializeObjectAttributes(&ObjAttr, &UniStr, OBJ_CASE_INSENSITIVE, pMissing->pParent->hDir, NULL /*pSecAttr*/);
|
---|
| 1839 |
|
---|
| 1840 | rcNt = g_pfnNtQueryAttributesFile(&ObjAttr, &BasicInfo);
|
---|
| 1841 | if (!MY_NT_SUCCESS(rcNt))
|
---|
| 1842 | {
|
---|
| 1843 | /*
|
---|
| 1844 | * Probably more likely that a missing node stays missing.
|
---|
| 1845 | */
|
---|
[2868] | 1846 | pMissing->uCacheGen = pCache->auGenerationsMissing[pMissing->fFlags & KFSOBJ_F_USE_CUSTOM_GEN];
|
---|
[2862] | 1847 | KFSCACHE_LOG(("Still missing %s/%s\n", pMissing->pParent->Obj.pszName, pMissing->pszName));
|
---|
[2859] | 1848 | }
|
---|
| 1849 | else
|
---|
| 1850 | {
|
---|
| 1851 | /*
|
---|
| 1852 | * We must metamorphose this node. This is tedious business
|
---|
| 1853 | * because we need to check the file name casing. We might
|
---|
| 1854 | * just as well update the parent directory...
|
---|
| 1855 | */
|
---|
[2864] | 1856 | KU8 const bObjType = BasicInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY ? KFSOBJ_TYPE_DIR
|
---|
| 1857 | : BasicInfo.FileAttributes & (FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_REPARSE_POINT)
|
---|
| 1858 | ? KFSOBJ_TYPE_OTHER : KFSOBJ_TYPE_FILE;
|
---|
| 1859 |
|
---|
| 1860 | KFSCACHE_LOG(("Birth of %s/%s as %d with attribs %#x...\n",
|
---|
| 1861 | pMissing->pParent->Obj.pszName, pMissing->pszName, bObjType, BasicInfo.FileAttributes));
|
---|
| 1862 | pMissing->bObjType = bObjType;
|
---|
[3379] | 1863 | /* (auGenerations[] - 1): make sure it's not considered up to date */
|
---|
| 1864 | pMissing->uCacheGen = pCache->auGenerations[pMissing->fFlags & KFSOBJ_F_USE_CUSTOM_GEN] - 1;
|
---|
| 1865 | /* Trigger parent directory repopulation. */
|
---|
| 1866 | if (pMissing->pParent->fPopulated)
|
---|
| 1867 | pMissing->pParent->fNeedRePopulating = K_TRUE;
|
---|
[2864] | 1868 | /**
|
---|
| 1869 | * @todo refresh missing object names when it appears.
|
---|
| 1870 | */
|
---|
[2859] | 1871 | }
|
---|
| 1872 | }
|
---|
| 1873 |
|
---|
[2851] | 1874 | return K_TRUE;
|
---|
[2832] | 1875 | }
|
---|
| 1876 |
|
---|
| 1877 |
|
---|
[2851] | 1878 | static KBOOL kFsCacheRefreshMissingIntermediateDir(PKFSCACHE pCache, PKFSOBJ pMissing, KFSLOOKUPERROR *penmError)
|
---|
[2832] | 1879 | {
|
---|
[2859] | 1880 | if (kFsCacheRefreshMissing(pCache, pMissing, penmError))
|
---|
| 1881 | {
|
---|
| 1882 | if ( pMissing->bObjType == KFSOBJ_TYPE_DIR
|
---|
| 1883 | || pMissing->bObjType == KFSOBJ_TYPE_MISSING)
|
---|
| 1884 | return K_TRUE;
|
---|
| 1885 | *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_DIR;
|
---|
| 1886 | }
|
---|
| 1887 |
|
---|
| 1888 | return K_FALSE;
|
---|
[2832] | 1889 | }
|
---|
| 1890 |
|
---|
| 1891 |
|
---|
[2863] | 1892 | /**
|
---|
| 1893 | * Generic object refresh.
|
---|
| 1894 | *
|
---|
| 1895 | * This does not refresh the content of directories.
|
---|
| 1896 | *
|
---|
| 1897 | * @returns K_TRUE on success. K_FALSE and *penmError on failure.
|
---|
| 1898 | * @param pCache The cache.
|
---|
| 1899 | * @param pObj The object.
|
---|
| 1900 | * @param penmError Where to return error info.
|
---|
| 1901 | */
|
---|
[2851] | 1902 | static KBOOL kFsCacheRefreshObj(PKFSCACHE pCache, PKFSOBJ pObj, KFSLOOKUPERROR *penmError)
|
---|
[2832] | 1903 | {
|
---|
[2862] | 1904 | KBOOL fRc;
|
---|
| 1905 |
|
---|
| 1906 | /*
|
---|
| 1907 | * Since we generally assume nothing goes away in this cache, we only really
|
---|
| 1908 | * have a hard time with negative entries. So, missing stuff goes to
|
---|
| 1909 | * complicated land.
|
---|
| 1910 | */
|
---|
[2859] | 1911 | if (pObj->bObjType == KFSOBJ_TYPE_MISSING)
|
---|
[2862] | 1912 | fRc = kFsCacheRefreshMissing(pCache, pObj, penmError);
|
---|
| 1913 | else
|
---|
| 1914 | {
|
---|
| 1915 | /*
|
---|
| 1916 | * This object is supposed to exist, so all we need to do is query essential
|
---|
| 1917 | * stats again. Since we've already got handles on directories, there are
|
---|
| 1918 | * two ways to go about this.
|
---|
| 1919 | */
|
---|
| 1920 | union
|
---|
| 1921 | {
|
---|
| 1922 | MY_FILE_NETWORK_OPEN_INFORMATION FullInfo;
|
---|
| 1923 | MY_FILE_STANDARD_INFORMATION StdInfo;
|
---|
| 1924 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 1925 | MY_FILE_ID_BOTH_DIR_INFORMATION WithId;
|
---|
| 1926 | //MY_FILE_BOTH_DIR_INFORMATION NoId;
|
---|
| 1927 | #else
|
---|
| 1928 | MY_FILE_ID_FULL_DIR_INFORMATION WithId;
|
---|
| 1929 | //MY_FILE_FULL_DIR_INFORMATION NoId;
|
---|
| 1930 | #endif
|
---|
| 1931 | KU8 abPadding[ sizeof(wchar_t) * KFSCACHE_CFG_MAX_UTF16_NAME
|
---|
| 1932 | + sizeof(MY_FILE_ID_BOTH_DIR_INFORMATION)];
|
---|
| 1933 | } uBuf;
|
---|
| 1934 | MY_IO_STATUS_BLOCK Ios;
|
---|
| 1935 | MY_NTSTATUS rcNt;
|
---|
| 1936 | if ( pObj->bObjType != KFSOBJ_TYPE_DIR
|
---|
| 1937 | || ((PKFSDIR)pObj)->hDir == INVALID_HANDLE_VALUE)
|
---|
| 1938 | {
|
---|
[2872] | 1939 | #if 1
|
---|
| 1940 | /* This always works and doesn't mess up NtQueryDirectoryFile. */
|
---|
[2862] | 1941 | MY_UNICODE_STRING UniStr;
|
---|
| 1942 | MY_OBJECT_ATTRIBUTES ObjAttr;
|
---|
[2859] | 1943 |
|
---|
[2862] | 1944 | UniStr.Buffer = (wchar_t *)pObj->pwszName;
|
---|
| 1945 | UniStr.Length = (USHORT)(pObj->cwcName * sizeof(wchar_t));
|
---|
| 1946 | UniStr.MaximumLength = UniStr.Length + sizeof(wchar_t);
|
---|
| 1947 |
|
---|
| 1948 | kHlpAssert(pObj->pParent->hDir != INVALID_HANDLE_VALUE);
|
---|
| 1949 | MyInitializeObjectAttributes(&ObjAttr, &UniStr, OBJ_CASE_INSENSITIVE, pObj->pParent->hDir, NULL /*pSecAttr*/);
|
---|
| 1950 |
|
---|
| 1951 | rcNt = g_pfnNtQueryFullAttributesFile(&ObjAttr, &uBuf.FullInfo);
|
---|
| 1952 | if (MY_NT_SUCCESS(rcNt))
|
---|
| 1953 | {
|
---|
| 1954 | pObj->Stats.st_size = uBuf.FullInfo.EndOfFile.QuadPart;
|
---|
| 1955 | birdNtTimeToTimeSpec(uBuf.FullInfo.CreationTime.QuadPart, &pObj->Stats.st_birthtim);
|
---|
| 1956 | birdNtTimeToTimeSpec(uBuf.FullInfo.ChangeTime.QuadPart, &pObj->Stats.st_ctim);
|
---|
| 1957 | birdNtTimeToTimeSpec(uBuf.FullInfo.LastWriteTime.QuadPart, &pObj->Stats.st_mtim);
|
---|
| 1958 | birdNtTimeToTimeSpec(uBuf.FullInfo.LastAccessTime.QuadPart, &pObj->Stats.st_atim);
|
---|
| 1959 | pObj->Stats.st_attribs = uBuf.FullInfo.FileAttributes;
|
---|
| 1960 | pObj->Stats.st_blksize = 65536;
|
---|
| 1961 | pObj->Stats.st_blocks = (uBuf.FullInfo.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
|
---|
| 1962 | / BIRD_STAT_BLOCK_SIZE;
|
---|
| 1963 | }
|
---|
| 1964 | #else
|
---|
[2863] | 1965 | /* This alternative lets us keep the inode number up to date and
|
---|
[2872] | 1966 | detect name case changes.
|
---|
| 1967 | Update: This doesn't work on windows 7, it ignores the UniStr
|
---|
| 1968 | and continue with the "*" search. So, we're using the
|
---|
| 1969 | above query instead for the time being. */
|
---|
[2862] | 1970 | MY_UNICODE_STRING UniStr;
|
---|
| 1971 | # ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 1972 | MY_FILE_INFORMATION_CLASS enmInfoClass = MyFileIdBothDirectoryInformation;
|
---|
| 1973 | # else
|
---|
| 1974 | MY_FILE_INFORMATION_CLASS enmInfoClass = MyFileIdFullDirectoryInformation;
|
---|
| 1975 | # endif
|
---|
| 1976 |
|
---|
| 1977 | UniStr.Buffer = (wchar_t *)pObj->pwszName;
|
---|
| 1978 | UniStr.Length = (USHORT)(pObj->cwcName * sizeof(wchar_t));
|
---|
| 1979 | UniStr.MaximumLength = UniStr.Length + sizeof(wchar_t);
|
---|
| 1980 |
|
---|
| 1981 | kHlpAssert(pObj->pParent->hDir != INVALID_HANDLE_VALUE);
|
---|
| 1982 |
|
---|
| 1983 | Ios.Information = -1;
|
---|
| 1984 | Ios.u.Status = -1;
|
---|
| 1985 | rcNt = g_pfnNtQueryDirectoryFile(pObj->pParent->hDir,
|
---|
| 1986 | NULL, /* hEvent */
|
---|
| 1987 | NULL, /* pfnApcComplete */
|
---|
| 1988 | NULL, /* pvApcCompleteCtx */
|
---|
| 1989 | &Ios,
|
---|
| 1990 | &uBuf,
|
---|
| 1991 | sizeof(uBuf),
|
---|
| 1992 | enmInfoClass,
|
---|
| 1993 | TRUE, /* fReturnSingleEntry */
|
---|
| 1994 | &UniStr, /* Filter / restart pos. */
|
---|
| 1995 | TRUE); /* fRestartScan */
|
---|
| 1996 |
|
---|
| 1997 | if (MY_NT_SUCCESS(rcNt))
|
---|
| 1998 | {
|
---|
| 1999 | if (pObj->Stats.st_ino == uBuf.WithId.FileId.QuadPart)
|
---|
| 2000 | KFSCACHE_LOG(("Refreshing %s/%s, no ID change...\n", pObj->pParent->Obj.pszName, pObj->pszName));
|
---|
| 2001 | else if ( pObj->cwcName == uBuf.WithId.FileNameLength / sizeof(wchar_t)
|
---|
| 2002 | # ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 2003 | && ( uBuf.WithId.ShortNameLength == 0
|
---|
| 2004 | ? pObj->pwszName == pObj->pwszShortName
|
---|
| 2005 | || ( pObj->cwcName == pObj->cwcShortName
|
---|
| 2006 | && memcmp(pObj->pwszName, pObj->pwszShortName, pObj->cwcName * sizeof(wchar_t)) == 0)
|
---|
| 2007 | : pObj->cwcShortName == uBuf.WithId.ShortNameLength / sizeof(wchar_t)
|
---|
| 2008 | && memcmp(pObj->pwszShortName, uBuf.WithId.ShortName, uBuf.WithId.ShortNameLength) == 0
|
---|
| 2009 | )
|
---|
| 2010 | # endif
|
---|
| 2011 | && memcmp(pObj->pwszName, uBuf.WithId.FileName, uBuf.WithId.FileNameLength) == 0
|
---|
| 2012 | )
|
---|
| 2013 | {
|
---|
| 2014 | KFSCACHE_LOG(("Refreshing %s/%s, ID changed %#llx -> %#llx...\n",
|
---|
| 2015 | pObj->pParent->Obj.pszName, pObj->pszName, pObj->Stats.st_ino, uBuf.WithId.FileId.QuadPart));
|
---|
| 2016 | pObj->Stats.st_ino = uBuf.WithId.FileId.QuadPart;
|
---|
| 2017 | }
|
---|
| 2018 | else
|
---|
| 2019 | {
|
---|
| 2020 | KFSCACHE_LOG(("Refreshing %s/%s, ID changed %#llx -> %#llx and names too...\n",
|
---|
| 2021 | pObj->pParent->Obj.pszName, pObj->pszName, pObj->Stats.st_ino, uBuf.WithId.FileId.QuadPart));
|
---|
[2866] | 2022 | fprintf(stderr, "kFsCacheRefreshObj - ID + name change not implemented!!\n");
|
---|
[2969] | 2023 | fflush(stderr);
|
---|
[2862] | 2024 | __debugbreak();
|
---|
| 2025 | pObj->Stats.st_ino = uBuf.WithId.FileId.QuadPart;
|
---|
| 2026 | /** @todo implement as needed. */
|
---|
| 2027 | }
|
---|
| 2028 |
|
---|
| 2029 | pObj->Stats.st_size = uBuf.WithId.EndOfFile.QuadPart;
|
---|
| 2030 | birdNtTimeToTimeSpec(uBuf.WithId.CreationTime.QuadPart, &pObj->Stats.st_birthtim);
|
---|
| 2031 | birdNtTimeToTimeSpec(uBuf.WithId.ChangeTime.QuadPart, &pObj->Stats.st_ctim);
|
---|
| 2032 | birdNtTimeToTimeSpec(uBuf.WithId.LastWriteTime.QuadPart, &pObj->Stats.st_mtim);
|
---|
| 2033 | birdNtTimeToTimeSpec(uBuf.WithId.LastAccessTime.QuadPart, &pObj->Stats.st_atim);
|
---|
| 2034 | pObj->Stats.st_attribs = uBuf.WithId.FileAttributes;
|
---|
| 2035 | pObj->Stats.st_blksize = 65536;
|
---|
| 2036 | pObj->Stats.st_blocks = (uBuf.WithId.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
|
---|
| 2037 | / BIRD_STAT_BLOCK_SIZE;
|
---|
| 2038 | }
|
---|
| 2039 | #endif
|
---|
[2863] | 2040 | if (MY_NT_SUCCESS(rcNt))
|
---|
| 2041 | {
|
---|
[2868] | 2042 | pObj->uCacheGen = pCache->auGenerations[pObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN];
|
---|
[2863] | 2043 | fRc = K_TRUE;
|
---|
| 2044 | }
|
---|
| 2045 | else
|
---|
| 2046 | {
|
---|
| 2047 | /* ouch! */
|
---|
| 2048 | kHlpAssertMsgFailed(("%#x\n", rcNt));
|
---|
[2866] | 2049 | fprintf(stderr, "kFsCacheRefreshObj - rcNt=%#x on non-dir - not implemented!\n", rcNt);
|
---|
[2863] | 2050 | __debugbreak();
|
---|
| 2051 | fRc = K_FALSE;
|
---|
| 2052 | }
|
---|
[2862] | 2053 | }
|
---|
| 2054 | else
|
---|
| 2055 | {
|
---|
| 2056 | /*
|
---|
| 2057 | * An open directory. Query information via the handle, the
|
---|
| 2058 | * file ID shouldn't have been able to change, so we can use
|
---|
| 2059 | * NtQueryInformationFile. Right...
|
---|
| 2060 | */
|
---|
| 2061 | PKFSDIR pDir = (PKFSDIR)pObj;
|
---|
| 2062 | Ios.Information = -1;
|
---|
| 2063 | Ios.u.Status = -1;
|
---|
| 2064 | rcNt = g_pfnNtQueryInformationFile(pDir->hDir, &Ios, &uBuf.FullInfo, sizeof(uBuf.FullInfo),
|
---|
| 2065 | MyFileNetworkOpenInformation);
|
---|
| 2066 | if (MY_NT_SUCCESS(rcNt))
|
---|
| 2067 | rcNt = Ios.u.Status;
|
---|
| 2068 | if (MY_NT_SUCCESS(rcNt))
|
---|
| 2069 | {
|
---|
| 2070 | pObj->Stats.st_size = uBuf.FullInfo.EndOfFile.QuadPart;
|
---|
| 2071 | birdNtTimeToTimeSpec(uBuf.FullInfo.CreationTime.QuadPart, &pObj->Stats.st_birthtim);
|
---|
| 2072 | birdNtTimeToTimeSpec(uBuf.FullInfo.ChangeTime.QuadPart, &pObj->Stats.st_ctim);
|
---|
| 2073 | birdNtTimeToTimeSpec(uBuf.FullInfo.LastWriteTime.QuadPart, &pObj->Stats.st_mtim);
|
---|
| 2074 | birdNtTimeToTimeSpec(uBuf.FullInfo.LastAccessTime.QuadPart, &pObj->Stats.st_atim);
|
---|
| 2075 | pObj->Stats.st_attribs = uBuf.FullInfo.FileAttributes;
|
---|
| 2076 | pObj->Stats.st_blksize = 65536;
|
---|
| 2077 | pObj->Stats.st_blocks = (uBuf.FullInfo.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
|
---|
| 2078 | / BIRD_STAT_BLOCK_SIZE;
|
---|
| 2079 |
|
---|
[2863] | 2080 | if ( pDir->iLastWrite == uBuf.FullInfo.LastWriteTime.QuadPart
|
---|
[3381] | 2081 | && (pObj->fFlags & KFSOBJ_F_WORKING_DIR_MTIME)
|
---|
| 2082 | && pDir->iLastPopulated - pDir->iLastWrite >= KFSCACHE_MIN_LAST_POPULATED_VS_WRITE)
|
---|
[2862] | 2083 | KFSCACHE_LOG(("Refreshing %s/%s/ - no re-populating necessary.\n",
|
---|
| 2084 | pObj->pParent->Obj.pszName, pObj->pszName));
|
---|
| 2085 | else
|
---|
| 2086 | {
|
---|
| 2087 | KFSCACHE_LOG(("Refreshing %s/%s/ - needs re-populating...\n",
|
---|
| 2088 | pObj->pParent->Obj.pszName, pObj->pszName));
|
---|
| 2089 | pDir->fNeedRePopulating = K_TRUE;
|
---|
| 2090 | #if 0
|
---|
| 2091 | /* Refresh the link count. */
|
---|
| 2092 | rcNt = g_pfnNtQueryInformationFile(pDir->hDir, &Ios, &StdInfo, sizeof(StdInfo), FileStandardInformation);
|
---|
| 2093 | if (MY_NT_SUCCESS(rcNt))
|
---|
| 2094 | rcNt = Ios.s.Status;
|
---|
| 2095 | if (MY_NT_SUCCESS(rcNt))
|
---|
| 2096 | pObj->Stats.st_nlink = StdInfo.NumberOfLinks;
|
---|
| 2097 | #endif
|
---|
| 2098 | }
|
---|
| 2099 | }
|
---|
[2863] | 2100 | if (MY_NT_SUCCESS(rcNt))
|
---|
| 2101 | {
|
---|
[2868] | 2102 | pObj->uCacheGen = pCache->auGenerations[pObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN];
|
---|
[2863] | 2103 | fRc = K_TRUE;
|
---|
| 2104 | }
|
---|
| 2105 | else
|
---|
| 2106 | {
|
---|
| 2107 | /* ouch! */
|
---|
| 2108 | kHlpAssertMsgFailed(("%#x\n", rcNt));
|
---|
[2866] | 2109 | fprintf(stderr, "kFsCacheRefreshObj - rcNt=%#x on dir - not implemented!\n", rcNt);
|
---|
[2969] | 2110 | fflush(stderr);
|
---|
[2863] | 2111 | __debugbreak();
|
---|
| 2112 | fRc = K_FALSE;
|
---|
| 2113 | }
|
---|
[2862] | 2114 | }
|
---|
| 2115 | }
|
---|
| 2116 |
|
---|
| 2117 | return fRc;
|
---|
[2832] | 2118 | }
|
---|
| 2119 |
|
---|
| 2120 |
|
---|
[2836] | 2121 |
|
---|
| 2122 | /**
|
---|
[2851] | 2123 | * Looks up a drive letter.
|
---|
[2833] | 2124 | *
|
---|
[2851] | 2125 | * Will enter the drive if necessary.
|
---|
| 2126 | *
|
---|
| 2127 | * @returns Pointer to the root directory of the drive or an update-to-date
|
---|
| 2128 | * missing node.
|
---|
| 2129 | * @param pCache The cache.
|
---|
| 2130 | * @param chLetter The uppercased drive letter.
|
---|
[2912] | 2131 | * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX.
|
---|
[2851] | 2132 | * @param penmError Where to return details as to why the lookup
|
---|
| 2133 | * failed.
|
---|
[2833] | 2134 | */
|
---|
[2930] | 2135 | static PKFSOBJ kFsCacheLookupDrive(PKFSCACHE pCache, char chLetter, KU32 fFlags, KFSLOOKUPERROR *penmError)
|
---|
[2833] | 2136 | {
|
---|
[2930] | 2137 | KU32 const uNameHash = chLetter - 'A';
|
---|
| 2138 | PKFSOBJ pCur = pCache->RootDir.papHashTab[uNameHash];
|
---|
| 2139 |
|
---|
[2851] | 2140 | KU32 cLeft;
|
---|
| 2141 | PKFSOBJ *ppCur;
|
---|
| 2142 | MY_UNICODE_STRING NtPath;
|
---|
| 2143 | wchar_t wszTmp[8];
|
---|
| 2144 | char szTmp[4];
|
---|
| 2145 |
|
---|
[2833] | 2146 | /*
|
---|
[2851] | 2147 | * Custom drive letter hashing.
|
---|
[2833] | 2148 | */
|
---|
[2930] | 2149 | kHlpAssert((uNameHash & pCache->RootDir.fHashTabMask) == uNameHash);
|
---|
| 2150 | while (pCur)
|
---|
[2833] | 2151 | {
|
---|
[2930] | 2152 | if ( pCur->uNameHash == uNameHash
|
---|
| 2153 | && pCur->cchName == 2
|
---|
| 2154 | && pCur->pszName[0] == chLetter
|
---|
| 2155 | && pCur->pszName[1] == ':')
|
---|
| 2156 | {
|
---|
| 2157 | if (pCur->bObjType == KFSOBJ_TYPE_DIR)
|
---|
| 2158 | return pCur;
|
---|
| 2159 | if ( (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH)
|
---|
| 2160 | || kFsCacheRefreshMissingIntermediateDir(pCache, pCur, penmError))
|
---|
| 2161 | return pCur;
|
---|
| 2162 | return NULL;
|
---|
| 2163 | }
|
---|
| 2164 | pCur = pCur->pNextNameHash;
|
---|
[2833] | 2165 | }
|
---|
| 2166 |
|
---|
[2851] | 2167 | /*
|
---|
[2930] | 2168 | * Make 100% sure it's not there.
|
---|
[2851] | 2169 | */
|
---|
| 2170 | cLeft = pCache->RootDir.cChildren;
|
---|
| 2171 | ppCur = pCache->RootDir.papChildren;
|
---|
| 2172 | while (cLeft-- > 0)
|
---|
[2834] | 2173 | {
|
---|
[2930] | 2174 | pCur = *ppCur++;
|
---|
[2851] | 2175 | if ( pCur->cchName == 2
|
---|
| 2176 | && pCur->pszName[0] == chLetter
|
---|
| 2177 | && pCur->pszName[1] == ':')
|
---|
[2834] | 2178 | {
|
---|
[2851] | 2179 | if (pCur->bObjType == KFSOBJ_TYPE_DIR)
|
---|
| 2180 | return pCur;
|
---|
| 2181 | kHlpAssert(pCur->bObjType == KFSOBJ_TYPE_MISSING);
|
---|
[2912] | 2182 | if ( (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH)
|
---|
| 2183 | || kFsCacheRefreshMissingIntermediateDir(pCache, pCur, penmError))
|
---|
[2851] | 2184 | return pCur;
|
---|
| 2185 | return NULL;
|
---|
[2834] | 2186 | }
|
---|
| 2187 | }
|
---|
| 2188 |
|
---|
[2912] | 2189 | if (fFlags & KFSCACHE_LOOKUP_F_NO_INSERT)
|
---|
| 2190 | {
|
---|
| 2191 | *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND; /* close enough */
|
---|
| 2192 | return NULL;
|
---|
| 2193 | }
|
---|
| 2194 |
|
---|
[2834] | 2195 | /*
|
---|
[2851] | 2196 | * Need to add it. We always keep the drive letters open for the benefit
|
---|
| 2197 | * of kFsCachePopuplateOrRefreshDir and others.
|
---|
[2834] | 2198 | */
|
---|
[2851] | 2199 | wszTmp[0] = szTmp[0] = chLetter;
|
---|
| 2200 | wszTmp[1] = szTmp[1] = ':';
|
---|
| 2201 | wszTmp[2] = szTmp[2] = '\\';
|
---|
| 2202 | wszTmp[3] = '.';
|
---|
| 2203 | wszTmp[4] = '\0';
|
---|
| 2204 | szTmp[2] = '\0';
|
---|
| 2205 |
|
---|
| 2206 | NtPath.Buffer = NULL;
|
---|
| 2207 | NtPath.Length = 0;
|
---|
| 2208 | NtPath.MaximumLength = 0;
|
---|
| 2209 | if (g_pfnRtlDosPathNameToNtPathName_U(wszTmp, &NtPath, NULL, NULL))
|
---|
[2834] | 2210 | {
|
---|
[2859] | 2211 | HANDLE hDir;
|
---|
| 2212 | MY_NTSTATUS rcNt;
|
---|
[2985] | 2213 | rcNt = birdOpenFileUniStr(NULL /*hRoot*/,
|
---|
| 2214 | &NtPath,
|
---|
[2851] | 2215 | FILE_READ_DATA | FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
|
---|
| 2216 | FILE_ATTRIBUTE_NORMAL,
|
---|
| 2217 | FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
---|
| 2218 | FILE_OPEN,
|
---|
| 2219 | FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
|
---|
| 2220 | OBJ_CASE_INSENSITIVE,
|
---|
| 2221 | &hDir);
|
---|
| 2222 | birdFreeNtPath(&NtPath);
|
---|
| 2223 | if (MY_NT_SUCCESS(rcNt))
|
---|
[2834] | 2224 | {
|
---|
[2851] | 2225 | PKFSDIR pDir = (PKFSDIR)kFsCacheCreateObject(pCache, &pCache->RootDir, szTmp, 2, wszTmp, 2,
|
---|
| 2226 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 2227 | NULL, 0, NULL, 0,
|
---|
| 2228 | #endif
|
---|
| 2229 | KFSOBJ_TYPE_DIR, penmError);
|
---|
| 2230 | if (pDir)
|
---|
[2834] | 2231 | {
|
---|
| 2232 | /*
|
---|
[2851] | 2233 | * We need a little bit of extra info for a drive root. These things are typically
|
---|
| 2234 | * inherited by subdirectories down the tree, so, we do it all here for till that changes.
|
---|
[2834] | 2235 | */
|
---|
[2851] | 2236 | union
|
---|
[2834] | 2237 | {
|
---|
[2851] | 2238 | MY_FILE_FS_VOLUME_INFORMATION VolInfo;
|
---|
| 2239 | MY_FILE_FS_ATTRIBUTE_INFORMATION FsAttrInfo;
|
---|
| 2240 | char abPadding[sizeof(MY_FILE_FS_VOLUME_INFORMATION) + 512];
|
---|
| 2241 | } uBuf;
|
---|
| 2242 | MY_IO_STATUS_BLOCK Ios;
|
---|
| 2243 | KBOOL fRc;
|
---|
[2834] | 2244 |
|
---|
[2851] | 2245 | kHlpAssert(pDir->hDir == INVALID_HANDLE_VALUE);
|
---|
| 2246 | pDir->hDir = hDir;
|
---|
[2834] | 2247 |
|
---|
[2856] | 2248 | if (birdStatHandle(hDir, &pDir->Obj.Stats, pDir->Obj.pszName) == 0)
|
---|
| 2249 | {
|
---|
| 2250 | pDir->Obj.fHaveStats = K_TRUE;
|
---|
| 2251 | pDir->uDevNo = pDir->Obj.Stats.st_dev;
|
---|
| 2252 | }
|
---|
| 2253 | else
|
---|
| 2254 | {
|
---|
| 2255 | /* Just in case. */
|
---|
| 2256 | pDir->Obj.fHaveStats = K_FALSE;
|
---|
| 2257 | rcNt = birdQueryVolumeDeviceNumber(hDir, &uBuf.VolInfo, sizeof(uBuf), &pDir->uDevNo);
|
---|
| 2258 | kHlpAssertMsg(MY_NT_SUCCESS(rcNt), ("%#x\n", rcNt));
|
---|
| 2259 | }
|
---|
[2834] | 2260 |
|
---|
[2851] | 2261 | /* Get the file system. */
|
---|
| 2262 | pDir->Obj.fFlags &= ~(KFSOBJ_F_NTFS | KFSOBJ_F_WORKING_DIR_MTIME);
|
---|
| 2263 | Ios.Information = -1;
|
---|
| 2264 | Ios.u.Status = -1;
|
---|
| 2265 | rcNt = g_pfnNtQueryVolumeInformationFile(hDir, &Ios, &uBuf.FsAttrInfo, sizeof(uBuf),
|
---|
| 2266 | MyFileFsAttributeInformation);
|
---|
| 2267 | if (MY_NT_SUCCESS(rcNt))
|
---|
| 2268 | rcNt = Ios.u.Status;
|
---|
| 2269 | if (MY_NT_SUCCESS(rcNt))
|
---|
[2833] | 2270 | {
|
---|
[2851] | 2271 | if ( uBuf.FsAttrInfo.FileSystemName[0] == 'N'
|
---|
| 2272 | && uBuf.FsAttrInfo.FileSystemName[1] == 'T'
|
---|
| 2273 | && uBuf.FsAttrInfo.FileSystemName[2] == 'F'
|
---|
| 2274 | && uBuf.FsAttrInfo.FileSystemName[3] == 'S'
|
---|
| 2275 | && uBuf.FsAttrInfo.FileSystemName[4] == '\0')
|
---|
[2833] | 2276 | {
|
---|
[2851] | 2277 | DWORD dwDriveType = GetDriveTypeW(wszTmp);
|
---|
| 2278 | if ( dwDriveType == DRIVE_FIXED
|
---|
| 2279 | || dwDriveType == DRIVE_RAMDISK)
|
---|
| 2280 | pDir->Obj.fFlags |= KFSOBJ_F_NTFS | KFSOBJ_F_WORKING_DIR_MTIME;
|
---|
[2833] | 2281 | }
|
---|
| 2282 | }
|
---|
[2851] | 2283 |
|
---|
| 2284 | /*
|
---|
| 2285 | * Link the new drive letter into the root dir.
|
---|
| 2286 | */
|
---|
| 2287 | fRc = kFsCacheDirAddChild(pCache, &pCache->RootDir, &pDir->Obj, penmError);
|
---|
| 2288 | kFsCacheObjRelease(pCache, &pDir->Obj);
|
---|
[2930] | 2289 | if (fRc)
|
---|
| 2290 | {
|
---|
| 2291 | pDir->Obj.pNextNameHash = pCache->RootDir.papHashTab[uNameHash];
|
---|
| 2292 | pCache->RootDir.papHashTab[uNameHash] = &pDir->Obj;
|
---|
| 2293 | return &pDir->Obj;
|
---|
| 2294 | }
|
---|
| 2295 | return NULL;
|
---|
[2833] | 2296 | }
|
---|
[2851] | 2297 |
|
---|
| 2298 | g_pfnNtClose(hDir);
|
---|
| 2299 | return NULL;
|
---|
[2833] | 2300 | }
|
---|
| 2301 |
|
---|
[2851] | 2302 | /* Assume it doesn't exist if this happens... This may be a little to
|
---|
| 2303 | restrictive wrt status code checks. */
|
---|
| 2304 | kHlpAssertMsgStmtReturn( rcNt == MY_STATUS_OBJECT_NAME_NOT_FOUND
|
---|
| 2305 | || rcNt == MY_STATUS_OBJECT_PATH_NOT_FOUND
|
---|
| 2306 | || rcNt == MY_STATUS_OBJECT_PATH_INVALID
|
---|
| 2307 | || rcNt == MY_STATUS_OBJECT_PATH_SYNTAX_BAD,
|
---|
| 2308 | ("%#x\n", rcNt),
|
---|
| 2309 | *penmError = KFSLOOKUPERROR_DIR_OPEN_ERROR,
|
---|
| 2310 | NULL);
|
---|
[2836] | 2311 | }
|
---|
[2834] | 2312 | else
|
---|
[2835] | 2313 | {
|
---|
[2851] | 2314 | kHlpAssertFailed();
|
---|
| 2315 | *penmError = KFSLOOKUPERROR_OUT_OF_MEMORY;
|
---|
| 2316 | return NULL;
|
---|
[2835] | 2317 | }
|
---|
[2833] | 2318 |
|
---|
[2851] | 2319 | /*
|
---|
| 2320 | * Maybe create a missing entry.
|
---|
| 2321 | */
|
---|
| 2322 | if (pCache->fFlags & KFSCACHE_F_MISSING_OBJECTS)
|
---|
[2835] | 2323 | {
|
---|
[2851] | 2324 | PKFSOBJ pMissing = kFsCacheCreateObject(pCache, &pCache->RootDir, szTmp, 2, wszTmp, 2,
|
---|
| 2325 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 2326 | NULL, 0, NULL, 0,
|
---|
[2836] | 2327 | #endif
|
---|
[2851] | 2328 | KFSOBJ_TYPE_MISSING, penmError);
|
---|
| 2329 | if (pMissing)
|
---|
[2835] | 2330 | {
|
---|
[2851] | 2331 | KBOOL fRc = kFsCacheDirAddChild(pCache, &pCache->RootDir, pMissing, penmError);
|
---|
| 2332 | kFsCacheObjRelease(pCache, pMissing);
|
---|
| 2333 | return fRc ? pMissing : NULL;
|
---|
[2835] | 2334 | }
|
---|
| 2335 | }
|
---|
[2851] | 2336 | else
|
---|
[2835] | 2337 | {
|
---|
[2851] | 2338 | /** @todo this isn't necessary correct for a root spec. */
|
---|
| 2339 | *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND;
|
---|
[2835] | 2340 | }
|
---|
[2851] | 2341 | return NULL;
|
---|
[2835] | 2342 | }
|
---|
| 2343 |
|
---|
| 2344 |
|
---|
[2851] | 2345 | /**
|
---|
[2930] | 2346 | * Slow path that allocates the child hash table and enters the given one.
|
---|
| 2347 | *
|
---|
| 2348 | * Allocation fialures are ignored.
|
---|
| 2349 | *
|
---|
| 2350 | * @param pCache The cache (for stats).
|
---|
| 2351 | * @param pDir The directory.
|
---|
| 2352 | * @param uNameHash The name hash to enter @a pChild under.
|
---|
| 2353 | * @param pChild The child to enter into the hash table.
|
---|
| 2354 | */
|
---|
| 2355 | static void kFsCacheDirAllocHashTabAndEnterChild(PKFSCACHE pCache, PKFSDIR pDir, KU32 uNameHash, PKFSOBJ pChild)
|
---|
| 2356 | {
|
---|
| 2357 | if (uNameHash != 0) /* paranoia ^ 4! */
|
---|
| 2358 | {
|
---|
| 2359 | /*
|
---|
| 2360 | * Double the current number of children and round up to a multiple of
|
---|
| 2361 | * two so we can avoid division.
|
---|
| 2362 | */
|
---|
| 2363 | KU32 cbHashTab;
|
---|
| 2364 | KU32 cEntries;
|
---|
| 2365 | kHlpAssert(pDir->cChildren > 0);
|
---|
| 2366 | if (pDir->cChildren <= KU32_MAX / 4)
|
---|
| 2367 | {
|
---|
| 2368 | #if defined(_MSC_VER) && 1
|
---|
| 2369 | KU32 cEntriesRaw = pDir->cChildren * 2;
|
---|
| 2370 | KU32 cEntriesShift;
|
---|
| 2371 | kHlpAssert(sizeof(cEntries) == (unsigned long));
|
---|
| 2372 | if (_BitScanReverse(&cEntriesShift, cEntriesRaw))
|
---|
| 2373 | {
|
---|
| 2374 | if ( K_BIT32(cEntriesShift) < cEntriesRaw
|
---|
| 2375 | && cEntriesShift < 31U)
|
---|
| 2376 | cEntriesShift++;
|
---|
| 2377 | cEntries = K_BIT32(cEntriesShift);
|
---|
| 2378 | }
|
---|
| 2379 | else
|
---|
| 2380 | {
|
---|
| 2381 | kHlpAssertFailed();
|
---|
| 2382 | cEntries = KU32_MAX / 2 + 1;
|
---|
| 2383 | }
|
---|
| 2384 | #else
|
---|
| 2385 | cEntries = pDir->cChildren * 2 - 1;
|
---|
| 2386 | cEntries |= cEntries >> 1;
|
---|
| 2387 | cEntries |= cEntries >> 2;
|
---|
| 2388 | cEntries |= cEntries >> 4;
|
---|
| 2389 | cEntries |= cEntries >> 8;
|
---|
| 2390 | cEntries |= cEntries >> 16;
|
---|
| 2391 | cEntries++;
|
---|
| 2392 | #endif
|
---|
| 2393 | }
|
---|
| 2394 | else
|
---|
| 2395 | cEntries = KU32_MAX / 2 + 1;
|
---|
| 2396 | kHlpAssert((cEntries & (cEntries - 1)) == 0);
|
---|
| 2397 |
|
---|
| 2398 | cbHashTab = cEntries * sizeof(pDir->papHashTab[0]);
|
---|
| 2399 | pDir->papHashTab = (PKFSOBJ *)kHlpAllocZ(cbHashTab);
|
---|
| 2400 | if (pDir->papHashTab)
|
---|
| 2401 | {
|
---|
| 2402 | KU32 idx;
|
---|
| 2403 | pDir->fHashTabMask = cEntries - 1;
|
---|
| 2404 | pCache->cbObjects += cbHashTab;
|
---|
| 2405 | pCache->cChildHashTabs++;
|
---|
| 2406 | pCache->cChildHashEntriesTotal += cEntries;
|
---|
| 2407 |
|
---|
| 2408 | /*
|
---|
| 2409 | * Insert it.
|
---|
| 2410 | */
|
---|
| 2411 | pChild->uNameHash = uNameHash;
|
---|
| 2412 | idx = uNameHash & (pDir->fHashTabMask);
|
---|
| 2413 | pChild->pNextNameHash = pDir->papHashTab[idx];
|
---|
| 2414 | pDir->papHashTab[idx] = pChild;
|
---|
| 2415 | pCache->cChildHashed++;
|
---|
| 2416 | }
|
---|
| 2417 | }
|
---|
| 2418 | }
|
---|
| 2419 |
|
---|
| 2420 |
|
---|
| 2421 | /**
|
---|
[2852] | 2422 | * Look up a child node, ANSI version.
|
---|
| 2423 | *
|
---|
| 2424 | * @returns Pointer to the child if found, NULL if not.
|
---|
| 2425 | * @param pCache The cache.
|
---|
| 2426 | * @param pParent The parent directory to search.
|
---|
| 2427 | * @param pchName The child name to search for (not terminated).
|
---|
| 2428 | * @param cchName The length of the child name.
|
---|
| 2429 | */
|
---|
| 2430 | static PKFSOBJ kFsCacheFindChildA(PKFSCACHE pCache, PKFSDIR pParent, const char *pchName, KU32 cchName)
|
---|
| 2431 | {
|
---|
[2930] | 2432 | /*
|
---|
| 2433 | * Check for '.' first ('..' won't appear).
|
---|
| 2434 | */
|
---|
[2852] | 2435 | if (cchName != 1 || *pchName != '.')
|
---|
| 2436 | {
|
---|
[2930] | 2437 | PKFSOBJ *ppCur;
|
---|
[2852] | 2438 | KU32 cLeft;
|
---|
[2930] | 2439 | KU32 uNameHash;
|
---|
[2852] | 2440 |
|
---|
[2930] | 2441 | /*
|
---|
| 2442 | * Do hash table lookup.
|
---|
| 2443 | *
|
---|
| 2444 | * This caches previous lookups, which should be useful when looking up
|
---|
| 2445 | * intermediate directories at least.
|
---|
| 2446 | */
|
---|
| 2447 | if (pParent->papHashTab != NULL)
|
---|
[2852] | 2448 | {
|
---|
[2930] | 2449 | PKFSOBJ pCur;
|
---|
| 2450 | uNameHash = kFsCacheStrHashN(pchName, cchName);
|
---|
| 2451 | pCur = pParent->papHashTab[uNameHash & pParent->fHashTabMask];
|
---|
| 2452 | while (pCur)
|
---|
| 2453 | {
|
---|
| 2454 | if ( pCur->uNameHash == uNameHash
|
---|
| 2455 | && ( ( pCur->cchName == cchName
|
---|
| 2456 | && _mbsnicmp(pCur->pszName, pchName, cchName) == 0)
|
---|
| 2457 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 2458 | || ( pCur->cchShortName == cchName
|
---|
| 2459 | && pCur->pszShortName != pCur->pszName
|
---|
| 2460 | && _mbsnicmp(pCur->pszShortName, pchName, cchName) == 0)
|
---|
| 2461 | #endif
|
---|
| 2462 | )
|
---|
| 2463 | )
|
---|
| 2464 | {
|
---|
| 2465 | pCache->cChildHashHits++;
|
---|
| 2466 | pCache->cChildSearches++;
|
---|
| 2467 | return pCur;
|
---|
| 2468 | }
|
---|
| 2469 | pCur = pCur->pNextNameHash;
|
---|
| 2470 | }
|
---|
[2852] | 2471 | }
|
---|
[2930] | 2472 | else
|
---|
| 2473 | uNameHash = 0;
|
---|
[2852] | 2474 |
|
---|
[2930] | 2475 | /*
|
---|
| 2476 | * Do linear search.
|
---|
| 2477 | */
|
---|
[2852] | 2478 | cLeft = pParent->cChildren;
|
---|
| 2479 | ppCur = pParent->papChildren;
|
---|
| 2480 | while (cLeft-- > 0)
|
---|
| 2481 | {
|
---|
| 2482 | PKFSOBJ pCur = *ppCur++;
|
---|
| 2483 | if ( ( pCur->cchName == cchName
|
---|
| 2484 | && _mbsnicmp(pCur->pszName, pchName, cchName) == 0)
|
---|
| 2485 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 2486 | || ( pCur->cchShortName == cchName
|
---|
| 2487 | && pCur->pszShortName != pCur->pszName
|
---|
| 2488 | && _mbsnicmp(pCur->pszShortName, pchName, cchName) == 0)
|
---|
| 2489 | #endif
|
---|
| 2490 | )
|
---|
[2930] | 2491 | {
|
---|
| 2492 | /*
|
---|
| 2493 | * Consider entering it into the parent hash table.
|
---|
| 2494 | * Note! We hash the input, not the name we found.
|
---|
| 2495 | */
|
---|
| 2496 | if ( pCur->uNameHash == 0
|
---|
| 2497 | && pParent->cChildren >= 2)
|
---|
| 2498 | {
|
---|
| 2499 | if (pParent->papHashTab)
|
---|
| 2500 | {
|
---|
| 2501 | if (uNameHash != 0)
|
---|
| 2502 | {
|
---|
| 2503 | KU32 idxNameHash = uNameHash & pParent->fHashTabMask;
|
---|
| 2504 | pCur->uNameHash = uNameHash;
|
---|
| 2505 | pCur->pNextNameHash = pParent->papHashTab[idxNameHash];
|
---|
| 2506 | pParent->papHashTab[idxNameHash] = pCur;
|
---|
| 2507 | if (pCur->pNextNameHash)
|
---|
| 2508 | pCache->cChildHashCollisions++;
|
---|
| 2509 | pCache->cChildHashed++;
|
---|
| 2510 | }
|
---|
| 2511 | }
|
---|
| 2512 | else
|
---|
| 2513 | kFsCacheDirAllocHashTabAndEnterChild(pCache, pParent, kFsCacheStrHashN(pchName, cchName), pCur);
|
---|
| 2514 | }
|
---|
| 2515 |
|
---|
| 2516 | pCache->cChildSearches++;
|
---|
[2852] | 2517 | return pCur;
|
---|
[2930] | 2518 | }
|
---|
[2852] | 2519 | }
|
---|
[2930] | 2520 |
|
---|
| 2521 | pCache->cChildSearches++;
|
---|
[2852] | 2522 | return NULL;
|
---|
| 2523 | }
|
---|
| 2524 | return &pParent->Obj;
|
---|
| 2525 | }
|
---|
| 2526 |
|
---|
| 2527 |
|
---|
| 2528 | /**
|
---|
| 2529 | * Look up a child node, UTF-16 version.
|
---|
| 2530 | *
|
---|
| 2531 | * @returns Pointer to the child if found, NULL if not.
|
---|
| 2532 | * @param pCache The cache.
|
---|
| 2533 | * @param pParent The parent directory to search.
|
---|
| 2534 | * @param pwcName The child name to search for (not terminated).
|
---|
| 2535 | * @param cwcName The length of the child name (in wchar_t's).
|
---|
| 2536 | */
|
---|
| 2537 | static PKFSOBJ kFsCacheFindChildW(PKFSCACHE pCache, PKFSDIR pParent, const wchar_t *pwcName, KU32 cwcName)
|
---|
| 2538 | {
|
---|
[2930] | 2539 | /*
|
---|
| 2540 | * Check for '.' first ('..' won't appear).
|
---|
| 2541 | */
|
---|
[2852] | 2542 | if (cwcName != 1 || *pwcName != '.')
|
---|
| 2543 | {
|
---|
[2930] | 2544 | PKFSOBJ *ppCur;
|
---|
[2852] | 2545 | KU32 cLeft;
|
---|
[2930] | 2546 | KU32 uNameHash;
|
---|
[2852] | 2547 |
|
---|
[2930] | 2548 | /*
|
---|
| 2549 | * Do hash table lookup.
|
---|
| 2550 | *
|
---|
| 2551 | * This caches previous lookups, which should be useful when looking up
|
---|
| 2552 | * intermediate directories at least.
|
---|
| 2553 | */
|
---|
| 2554 | if (pParent->papHashTab != NULL)
|
---|
[2852] | 2555 | {
|
---|
[2930] | 2556 | PKFSOBJ pCur;
|
---|
| 2557 | uNameHash = kFsCacheUtf16HashN(pwcName, cwcName);
|
---|
| 2558 | pCur = pParent->papHashTab[uNameHash & pParent->fHashTabMask];
|
---|
| 2559 | while (pCur)
|
---|
| 2560 | {
|
---|
| 2561 | if ( pCur->uNameHash == uNameHash
|
---|
| 2562 | && ( ( pCur->cwcName == cwcName
|
---|
| 2563 | && kFsCacheIAreEqualW(pCur->pwszName, pwcName, cwcName))
|
---|
| 2564 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 2565 | || ( pCur->cwcShortName == cwcName
|
---|
| 2566 | && pCur->pwszShortName != pCur->pwszName
|
---|
| 2567 | && kFsCacheIAreEqualW(pCur->pwszShortName, pwcName, cwcName))
|
---|
| 2568 | #endif
|
---|
| 2569 | )
|
---|
| 2570 | )
|
---|
| 2571 | {
|
---|
| 2572 | pCache->cChildHashHits++;
|
---|
| 2573 | pCache->cChildSearches++;
|
---|
| 2574 | return pCur;
|
---|
| 2575 | }
|
---|
| 2576 | pCur = pCur->pNextNameHash;
|
---|
| 2577 | }
|
---|
[2852] | 2578 | }
|
---|
[2930] | 2579 | else
|
---|
| 2580 | uNameHash = 0;
|
---|
[2852] | 2581 |
|
---|
[2930] | 2582 | /*
|
---|
| 2583 | * Do linear search.
|
---|
| 2584 | */
|
---|
[2852] | 2585 | cLeft = pParent->cChildren;
|
---|
| 2586 | ppCur = pParent->papChildren;
|
---|
| 2587 | while (cLeft-- > 0)
|
---|
| 2588 | {
|
---|
| 2589 | PKFSOBJ pCur = *ppCur++;
|
---|
| 2590 | if ( ( pCur->cwcName == cwcName
|
---|
| 2591 | && kFsCacheIAreEqualW(pCur->pwszName, pwcName, cwcName))
|
---|
| 2592 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 2593 | || ( pCur->cwcShortName == cwcName
|
---|
| 2594 | && pCur->pwszShortName != pCur->pwszName
|
---|
| 2595 | && kFsCacheIAreEqualW(pCur->pwszShortName, pwcName, cwcName))
|
---|
| 2596 | #endif
|
---|
| 2597 | )
|
---|
[2930] | 2598 | {
|
---|
| 2599 | /*
|
---|
| 2600 | * Consider entering it into the parent hash table.
|
---|
| 2601 | * Note! We hash the input, not the name we found.
|
---|
| 2602 | */
|
---|
| 2603 | if ( pCur->uNameHash == 0
|
---|
| 2604 | && pParent->cChildren >= 4)
|
---|
| 2605 | {
|
---|
| 2606 | if (pParent->papHashTab)
|
---|
| 2607 | {
|
---|
| 2608 | if (uNameHash != 0)
|
---|
| 2609 | {
|
---|
| 2610 | KU32 idxNameHash = uNameHash & pParent->fHashTabMask;
|
---|
| 2611 | pCur->uNameHash = uNameHash;
|
---|
| 2612 | pCur->pNextNameHash = pParent->papHashTab[idxNameHash];
|
---|
| 2613 | pParent->papHashTab[idxNameHash] = pCur;
|
---|
| 2614 | if (pCur->pNextNameHash)
|
---|
| 2615 | pCache->cChildHashCollisions++;
|
---|
| 2616 | pCache->cChildHashed++;
|
---|
| 2617 | }
|
---|
| 2618 | }
|
---|
| 2619 | else
|
---|
| 2620 | kFsCacheDirAllocHashTabAndEnterChild(pCache, pParent, kFsCacheUtf16HashN(pwcName, cwcName), pCur);
|
---|
| 2621 | }
|
---|
| 2622 |
|
---|
| 2623 | pCache->cChildSearches++;
|
---|
[2852] | 2624 | return pCur;
|
---|
[2930] | 2625 | }
|
---|
[2852] | 2626 | }
|
---|
[2930] | 2627 | pCache->cChildSearches++;
|
---|
[2852] | 2628 | return NULL;
|
---|
| 2629 | }
|
---|
| 2630 | return &pParent->Obj;
|
---|
| 2631 | }
|
---|
| 2632 |
|
---|
| 2633 |
|
---|
| 2634 | /**
|
---|
| 2635 | * Looks up a UNC share, ANSI version.
|
---|
| 2636 | *
|
---|
| 2637 | * We keep both the server and share in the root directory entry. This means we
|
---|
| 2638 | * have to clean up the entry name before we can insert it.
|
---|
| 2639 | *
|
---|
| 2640 | * @returns Pointer to the share root directory or an update-to-date missing
|
---|
| 2641 | * node.
|
---|
| 2642 | * @param pCache The cache.
|
---|
| 2643 | * @param pszPath The path.
|
---|
[2912] | 2644 | * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX.
|
---|
[2852] | 2645 | * @param poff Where to return the root dire.
|
---|
| 2646 | * @param penmError Where to return details as to why the lookup
|
---|
| 2647 | * failed.
|
---|
| 2648 | */
|
---|
[2930] | 2649 | static PKFSOBJ kFsCacheLookupUncShareA(PKFSCACHE pCache, const char *pszPath, KU32 fFlags,
|
---|
| 2650 | KU32 *poff, KFSLOOKUPERROR *penmError)
|
---|
[2852] | 2651 | {
|
---|
[2940] | 2652 | /*
|
---|
| 2653 | * Special case: Long path prefix w/ drive letter following it.
|
---|
| 2654 | * Note! Must've been converted from wide char to ANSI.
|
---|
| 2655 | */
|
---|
| 2656 | if ( IS_SLASH(pszPath[0])
|
---|
| 2657 | && IS_SLASH(pszPath[1])
|
---|
| 2658 | && pszPath[2] == '?'
|
---|
| 2659 | && IS_SLASH(pszPath[3])
|
---|
| 2660 | && IS_ALPHA(pszPath[4])
|
---|
| 2661 | && pszPath[5] == ':'
|
---|
| 2662 | && IS_SLASH(pszPath[6]) )
|
---|
| 2663 | {
|
---|
| 2664 | *poff = 4 + 2;
|
---|
| 2665 | return kFsCacheLookupDrive(pCache, pszPath[4], fFlags, penmError);
|
---|
| 2666 | }
|
---|
| 2667 |
|
---|
[2852] | 2668 | #if 0 /* later */
|
---|
| 2669 | KU32 offStartServer;
|
---|
| 2670 | KU32 offEndServer;
|
---|
| 2671 | KU32 offStartShare;
|
---|
| 2672 |
|
---|
| 2673 | KU32 offEnd = 2;
|
---|
| 2674 | while (IS_SLASH(pszPath[offEnd]))
|
---|
| 2675 | offEnd++;
|
---|
| 2676 |
|
---|
| 2677 | offStartServer = offEnd;
|
---|
| 2678 | while ( (ch = pszPath[offEnd]) != '\0'
|
---|
| 2679 | && !IS_SLASH(ch))
|
---|
| 2680 | offEnd++;
|
---|
| 2681 | offEndServer = offEnd;
|
---|
| 2682 |
|
---|
| 2683 | if (ch != '\0')
|
---|
| 2684 | { /* likely */ }
|
---|
| 2685 | else
|
---|
| 2686 | {
|
---|
| 2687 | *penmError = KFSLOOKUPERROR_NOT_FOUND;
|
---|
| 2688 | return NULL;
|
---|
| 2689 | }
|
---|
| 2690 |
|
---|
| 2691 | while (IS_SLASH(pszPath[offEnd]))
|
---|
| 2692 | offEnd++;
|
---|
| 2693 | offStartServer = offEnd;
|
---|
| 2694 | while ( (ch = pszPath[offEnd]) != '\0'
|
---|
| 2695 | && !IS_SLASH(ch))
|
---|
| 2696 | offEnd++;
|
---|
| 2697 | #endif
|
---|
| 2698 | *penmError = KFSLOOKUPERROR_UNSUPPORTED;
|
---|
| 2699 | return NULL;
|
---|
| 2700 | }
|
---|
| 2701 |
|
---|
| 2702 |
|
---|
| 2703 | /**
|
---|
| 2704 | * Looks up a UNC share, UTF-16 version.
|
---|
| 2705 | *
|
---|
| 2706 | * We keep both the server and share in the root directory entry. This means we
|
---|
| 2707 | * have to clean up the entry name before we can insert it.
|
---|
| 2708 | *
|
---|
| 2709 | * @returns Pointer to the share root directory or an update-to-date missing
|
---|
| 2710 | * node.
|
---|
| 2711 | * @param pCache The cache.
|
---|
| 2712 | * @param pwszPath The path.
|
---|
[2912] | 2713 | * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX.
|
---|
[2940] | 2714 | * @param poff Where to return the root dir.
|
---|
[2852] | 2715 | * @param penmError Where to return details as to why the lookup
|
---|
| 2716 | * failed.
|
---|
| 2717 | */
|
---|
[2930] | 2718 | static PKFSOBJ kFsCacheLookupUncShareW(PKFSCACHE pCache, const wchar_t *pwszPath, KU32 fFlags,
|
---|
| 2719 | KU32 *poff, KFSLOOKUPERROR *penmError)
|
---|
[2852] | 2720 | {
|
---|
[2940] | 2721 | /*
|
---|
| 2722 | * Special case: Long path prefix w/ drive letter following it.
|
---|
| 2723 | */
|
---|
| 2724 | if ( IS_SLASH(pwszPath[0])
|
---|
| 2725 | && IS_SLASH(pwszPath[1])
|
---|
| 2726 | && pwszPath[2] == '?'
|
---|
| 2727 | && IS_SLASH(pwszPath[3])
|
---|
| 2728 | && IS_ALPHA(pwszPath[4])
|
---|
| 2729 | && pwszPath[5] == ':'
|
---|
| 2730 | && IS_SLASH(pwszPath[6]) )
|
---|
| 2731 | {
|
---|
| 2732 | *poff = 4 + 2;
|
---|
| 2733 | return kFsCacheLookupDrive(pCache, (char)pwszPath[4], fFlags, penmError);
|
---|
| 2734 | }
|
---|
| 2735 |
|
---|
| 2736 |
|
---|
[2852] | 2737 | #if 0 /* later */
|
---|
| 2738 | KU32 offStartServer;
|
---|
| 2739 | KU32 offEndServer;
|
---|
| 2740 | KU32 offStartShare;
|
---|
| 2741 |
|
---|
| 2742 | KU32 offEnd = 2;
|
---|
| 2743 | while (IS_SLASH(pwszPath[offEnd]))
|
---|
| 2744 | offEnd++;
|
---|
| 2745 |
|
---|
| 2746 | offStartServer = offEnd;
|
---|
| 2747 | while ( (ch = pwszPath[offEnd]) != '\0'
|
---|
| 2748 | && !IS_SLASH(ch))
|
---|
| 2749 | offEnd++;
|
---|
| 2750 | offEndServer = offEnd;
|
---|
| 2751 |
|
---|
| 2752 | if (ch != '\0')
|
---|
| 2753 | { /* likely */ }
|
---|
| 2754 | else
|
---|
| 2755 | {
|
---|
| 2756 | *penmError = KFSLOOKUPERROR_NOT_FOUND;
|
---|
| 2757 | return NULL;
|
---|
| 2758 | }
|
---|
| 2759 |
|
---|
| 2760 | while (IS_SLASH(pwszPath[offEnd]))
|
---|
| 2761 | offEnd++;
|
---|
| 2762 | offStartServer = offEnd;
|
---|
| 2763 | while ( (ch = pwszPath[offEnd]) != '\0'
|
---|
| 2764 | && !IS_SLASH(ch))
|
---|
| 2765 | offEnd++;
|
---|
| 2766 | #endif
|
---|
| 2767 | *penmError = KFSLOOKUPERROR_UNSUPPORTED;
|
---|
| 2768 | return NULL;
|
---|
| 2769 | }
|
---|
| 2770 |
|
---|
| 2771 |
|
---|
| 2772 | /**
|
---|
[2856] | 2773 | * Walks an full path relative to the given directory, ANSI version.
|
---|
[2851] | 2774 | *
|
---|
| 2775 | * This will create any missing nodes while walking.
|
---|
| 2776 | *
|
---|
| 2777 | * The caller will have to do the path hash table insertion of the result.
|
---|
| 2778 | *
|
---|
| 2779 | * @returns Pointer to the tree node corresponding to @a pszPath.
|
---|
| 2780 | * NULL on lookup failure, see @a penmError for details.
|
---|
| 2781 | * @param pCache The cache.
|
---|
[2856] | 2782 | * @param pParent The directory to start the lookup in.
|
---|
[2851] | 2783 | * @param pszPath The path to walk.
|
---|
| 2784 | * @param cchPath The length of the path.
|
---|
[2912] | 2785 | * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX.
|
---|
[2851] | 2786 | * @param penmError Where to return details as to why the lookup
|
---|
| 2787 | * failed.
|
---|
[2868] | 2788 | * @param ppLastAncestor Where to return the last parent element found
|
---|
[3082] | 2789 | * (referenced) in case of error like an path/file
|
---|
| 2790 | * not found problem. Optional.
|
---|
[2851] | 2791 | */
|
---|
[2912] | 2792 | PKFSOBJ kFsCacheLookupRelativeToDirA(PKFSCACHE pCache, PKFSDIR pParent, const char *pszPath, KU32 cchPath, KU32 fFlags,
|
---|
[2868] | 2793 | KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor)
|
---|
[2836] | 2794 | {
|
---|
[2851] | 2795 | /*
|
---|
| 2796 | * Walk loop.
|
---|
| 2797 | */
|
---|
[2856] | 2798 | KU32 off = 0;
|
---|
[2868] | 2799 | if (ppLastAncestor)
|
---|
| 2800 | *ppLastAncestor = NULL;
|
---|
[3184] | 2801 | KFSCACHE_LOCK(pCache);
|
---|
[2851] | 2802 | for (;;)
|
---|
[2836] | 2803 | {
|
---|
[2856] | 2804 | PKFSOBJ pChild;
|
---|
| 2805 |
|
---|
[2851] | 2806 | /*
|
---|
| 2807 | * Find the end of the component, counting trailing slashes.
|
---|
| 2808 | */
|
---|
[2856] | 2809 | char ch;
|
---|
| 2810 | KU32 cchSlashes = 0;
|
---|
| 2811 | KU32 offEnd = off + 1;
|
---|
[2851] | 2812 | while ((ch = pszPath[offEnd]) != '\0')
|
---|
[2836] | 2813 | {
|
---|
[2851] | 2814 | if (!IS_SLASH(ch))
|
---|
| 2815 | offEnd++;
|
---|
| 2816 | else
|
---|
[2836] | 2817 | {
|
---|
[2851] | 2818 | do
|
---|
| 2819 | cchSlashes++;
|
---|
| 2820 | while (IS_SLASH(pszPath[offEnd + cchSlashes]));
|
---|
| 2821 | break;
|
---|
[2836] | 2822 | }
|
---|
| 2823 | }
|
---|
| 2824 |
|
---|
[2851] | 2825 | /*
|
---|
| 2826 | * Do we need to populate or refresh this directory first?
|
---|
| 2827 | */
|
---|
[2912] | 2828 | if ( !pParent->fNeedRePopulating
|
---|
| 2829 | && pParent->fPopulated
|
---|
[2853] | 2830 | && ( pParent->Obj.uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
|
---|
[2868] | 2831 | || pParent->Obj.uCacheGen == pCache->auGenerations[pParent->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN]) )
|
---|
[2851] | 2832 | { /* likely */ }
|
---|
[3379] | 2833 | else if ( (fFlags & (KFSCACHE_LOOKUP_F_NO_INSERT | KFSCACHE_LOOKUP_F_NO_REFRESH))
|
---|
[2912] | 2834 | || kFsCachePopuplateOrRefreshDir(pCache, pParent, penmError))
|
---|
[2851] | 2835 | { /* likely */ }
|
---|
| 2836 | else
|
---|
[3082] | 2837 | {
|
---|
| 2838 | if (ppLastAncestor)
|
---|
| 2839 | *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj);
|
---|
[3184] | 2840 | KFSCACHE_UNLOCK(pCache);
|
---|
[2851] | 2841 | return NULL;
|
---|
[3082] | 2842 | }
|
---|
[2836] | 2843 |
|
---|
[2851] | 2844 | /*
|
---|
| 2845 | * Search the current node for the name.
|
---|
| 2846 | *
|
---|
| 2847 | * If we don't find it, we may insert a missing node depending on
|
---|
| 2848 | * the cache configuration.
|
---|
| 2849 | */
|
---|
| 2850 | pChild = kFsCacheFindChildA(pCache, pParent, &pszPath[off], offEnd - off);
|
---|
| 2851 | if (pChild != NULL)
|
---|
| 2852 | { /* probably likely */ }
|
---|
| 2853 | else
|
---|
[2836] | 2854 | {
|
---|
[2912] | 2855 | if ( (pCache->fFlags & KFSCACHE_F_MISSING_OBJECTS)
|
---|
| 2856 | && !(fFlags & KFSCACHE_LOOKUP_F_NO_INSERT))
|
---|
[2851] | 2857 | pChild = kFsCacheCreateMissingA(pCache, pParent, &pszPath[off], offEnd - off, penmError);
|
---|
| 2858 | if (cchSlashes == 0 || offEnd + cchSlashes >= cchPath)
|
---|
[2836] | 2859 | {
|
---|
[2851] | 2860 | if (pChild)
|
---|
[3184] | 2861 | {
|
---|
| 2862 | kFsCacheObjRetainInternal(pChild);
|
---|
| 2863 | KFSCACHE_UNLOCK(pCache);
|
---|
| 2864 | return pChild;
|
---|
| 2865 | }
|
---|
[2851] | 2866 | *penmError = KFSLOOKUPERROR_NOT_FOUND;
|
---|
[2836] | 2867 | }
|
---|
[2851] | 2868 | else
|
---|
| 2869 | *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND;
|
---|
[2868] | 2870 | if (ppLastAncestor)
|
---|
| 2871 | *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj);
|
---|
[3184] | 2872 | KFSCACHE_UNLOCK(pCache);
|
---|
[2851] | 2873 | return NULL;
|
---|
[2836] | 2874 | }
|
---|
| 2875 |
|
---|
[2851] | 2876 | /* Advance off and check if we're done already. */
|
---|
| 2877 | off = offEnd + cchSlashes;
|
---|
| 2878 | if ( cchSlashes == 0
|
---|
| 2879 | || off >= cchPath)
|
---|
[2836] | 2880 | {
|
---|
[2851] | 2881 | if ( pChild->bObjType != KFSOBJ_TYPE_MISSING
|
---|
[2853] | 2882 | || pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
|
---|
[2868] | 2883 | || pChild->uCacheGen == pCache->auGenerationsMissing[pChild->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
|
---|
[2912] | 2884 | || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH)
|
---|
[2851] | 2885 | || kFsCacheRefreshMissing(pCache, pChild, penmError) )
|
---|
| 2886 | { /* likely */ }
|
---|
| 2887 | else
|
---|
[3082] | 2888 | {
|
---|
| 2889 | if (ppLastAncestor)
|
---|
| 2890 | *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj);
|
---|
[3184] | 2891 | KFSCACHE_UNLOCK(pCache);
|
---|
[2851] | 2892 | return NULL;
|
---|
[3082] | 2893 | }
|
---|
[3184] | 2894 | kFsCacheObjRetainInternal(pChild);
|
---|
| 2895 | KFSCACHE_UNLOCK(pCache);
|
---|
| 2896 | return pChild;
|
---|
[2836] | 2897 | }
|
---|
| 2898 |
|
---|
[2851] | 2899 | /*
|
---|
| 2900 | * Check that it's a directory. If a missing entry, we may have to
|
---|
| 2901 | * refresh it and re-examin it.
|
---|
| 2902 | */
|
---|
| 2903 | if (pChild->bObjType == KFSOBJ_TYPE_DIR)
|
---|
| 2904 | pParent = (PKFSDIR)pChild;
|
---|
| 2905 | else if (pChild->bObjType != KFSOBJ_TYPE_MISSING)
|
---|
[2836] | 2906 | {
|
---|
[2851] | 2907 | *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_DIR;
|
---|
[2868] | 2908 | if (ppLastAncestor)
|
---|
| 2909 | *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj);
|
---|
[3184] | 2910 | KFSCACHE_UNLOCK(pCache);
|
---|
[2851] | 2911 | return NULL;
|
---|
[2836] | 2912 | }
|
---|
[2853] | 2913 | else if ( pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
|
---|
[2912] | 2914 | || pChild->uCacheGen == pCache->auGenerationsMissing[pChild->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
|
---|
| 2915 | || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH))
|
---|
[2834] | 2916 | {
|
---|
[2851] | 2917 | *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND;
|
---|
[2868] | 2918 | if (ppLastAncestor)
|
---|
| 2919 | *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj);
|
---|
[3184] | 2920 | KFSCACHE_UNLOCK(pCache);
|
---|
[2851] | 2921 | return NULL;
|
---|
[2834] | 2922 | }
|
---|
[2851] | 2923 | else if (kFsCacheRefreshMissingIntermediateDir(pCache, pChild, penmError))
|
---|
| 2924 | pParent = (PKFSDIR)pChild;
|
---|
[2834] | 2925 | else
|
---|
[2868] | 2926 | {
|
---|
| 2927 | if (ppLastAncestor)
|
---|
| 2928 | *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj);
|
---|
[3184] | 2929 | KFSCACHE_UNLOCK(pCache);
|
---|
[2851] | 2930 | return NULL;
|
---|
[2868] | 2931 | }
|
---|
[2834] | 2932 | }
|
---|
[2833] | 2933 |
|
---|
[3082] | 2934 | /* not reached */
|
---|
[3184] | 2935 | KFSCACHE_UNLOCK(pCache);
|
---|
[2851] | 2936 | return NULL;
|
---|
[2833] | 2937 | }
|
---|
| 2938 |
|
---|
| 2939 |
|
---|
| 2940 | /**
|
---|
[2856] | 2941 | * Walks an full path relative to the given directory, UTF-16 version.
|
---|
[2852] | 2942 | *
|
---|
| 2943 | * This will create any missing nodes while walking.
|
---|
| 2944 | *
|
---|
| 2945 | * The caller will have to do the path hash table insertion of the result.
|
---|
| 2946 | *
|
---|
| 2947 | * @returns Pointer to the tree node corresponding to @a pszPath.
|
---|
| 2948 | * NULL on lookup failure, see @a penmError for details.
|
---|
| 2949 | * @param pCache The cache.
|
---|
[2856] | 2950 | * @param pParent The directory to start the lookup in.
|
---|
| 2951 | * @param pszPath The path to walk. No dot-dot bits allowed!
|
---|
| 2952 | * @param cchPath The length of the path.
|
---|
[2912] | 2953 | * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX.
|
---|
[2852] | 2954 | * @param penmError Where to return details as to why the lookup
|
---|
| 2955 | * failed.
|
---|
[2868] | 2956 | * @param ppLastAncestor Where to return the last parent element found
|
---|
[3082] | 2957 | * (referenced) in case of error like an path/file
|
---|
| 2958 | * not found problem. Optional.
|
---|
[2852] | 2959 | */
|
---|
[2912] | 2960 | PKFSOBJ kFsCacheLookupRelativeToDirW(PKFSCACHE pCache, PKFSDIR pParent, const wchar_t *pwszPath, KU32 cwcPath, KU32 fFlags,
|
---|
[2868] | 2961 | KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor)
|
---|
[2852] | 2962 | {
|
---|
| 2963 | /*
|
---|
| 2964 | * Walk loop.
|
---|
| 2965 | */
|
---|
[2856] | 2966 | KU32 off = 0;
|
---|
[2868] | 2967 | if (ppLastAncestor)
|
---|
| 2968 | *ppLastAncestor = NULL;
|
---|
[3184] | 2969 | KFSCACHE_LOCK(pCache);
|
---|
[2852] | 2970 | for (;;)
|
---|
| 2971 | {
|
---|
[2856] | 2972 | PKFSOBJ pChild;
|
---|
| 2973 |
|
---|
[2852] | 2974 | /*
|
---|
| 2975 | * Find the end of the component, counting trailing slashes.
|
---|
| 2976 | */
|
---|
| 2977 | wchar_t wc;
|
---|
[2856] | 2978 | KU32 cwcSlashes = 0;
|
---|
| 2979 | KU32 offEnd = off + 1;
|
---|
[2852] | 2980 | while ((wc = pwszPath[offEnd]) != '\0')
|
---|
| 2981 | {
|
---|
| 2982 | if (!IS_SLASH(wc))
|
---|
| 2983 | offEnd++;
|
---|
| 2984 | else
|
---|
| 2985 | {
|
---|
| 2986 | do
|
---|
| 2987 | cwcSlashes++;
|
---|
| 2988 | while (IS_SLASH(pwszPath[offEnd + cwcSlashes]));
|
---|
| 2989 | break;
|
---|
| 2990 | }
|
---|
| 2991 | }
|
---|
| 2992 |
|
---|
| 2993 | /*
|
---|
| 2994 | * Do we need to populate or refresh this directory first?
|
---|
| 2995 | */
|
---|
[2912] | 2996 | if ( !pParent->fNeedRePopulating
|
---|
| 2997 | && pParent->fPopulated
|
---|
[2853] | 2998 | && ( pParent->Obj.uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
|
---|
[2868] | 2999 | || pParent->Obj.uCacheGen == pCache->auGenerations[pParent->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN]) )
|
---|
[2852] | 3000 | { /* likely */ }
|
---|
[3379] | 3001 | else if ( (fFlags & (KFSCACHE_LOOKUP_F_NO_INSERT | KFSCACHE_LOOKUP_F_NO_REFRESH))
|
---|
[2912] | 3002 | || kFsCachePopuplateOrRefreshDir(pCache, pParent, penmError))
|
---|
[2852] | 3003 | { /* likely */ }
|
---|
| 3004 | else
|
---|
[3082] | 3005 | {
|
---|
| 3006 | if (ppLastAncestor)
|
---|
| 3007 | *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj);
|
---|
[3184] | 3008 | KFSCACHE_UNLOCK(pCache);
|
---|
[2852] | 3009 | return NULL;
|
---|
[3082] | 3010 | }
|
---|
[2852] | 3011 |
|
---|
| 3012 | /*
|
---|
| 3013 | * Search the current node for the name.
|
---|
| 3014 | *
|
---|
| 3015 | * If we don't find it, we may insert a missing node depending on
|
---|
| 3016 | * the cache configuration.
|
---|
| 3017 | */
|
---|
| 3018 | pChild = kFsCacheFindChildW(pCache, pParent, &pwszPath[off], offEnd - off);
|
---|
| 3019 | if (pChild != NULL)
|
---|
| 3020 | { /* probably likely */ }
|
---|
| 3021 | else
|
---|
| 3022 | {
|
---|
[2912] | 3023 | if ( (pCache->fFlags & KFSCACHE_F_MISSING_OBJECTS)
|
---|
| 3024 | && !(fFlags & KFSCACHE_LOOKUP_F_NO_INSERT))
|
---|
[2852] | 3025 | pChild = kFsCacheCreateMissingW(pCache, pParent, &pwszPath[off], offEnd - off, penmError);
|
---|
| 3026 | if (cwcSlashes == 0 || offEnd + cwcSlashes >= cwcPath)
|
---|
| 3027 | {
|
---|
| 3028 | if (pChild)
|
---|
[3184] | 3029 | {
|
---|
| 3030 | kFsCacheObjRetainInternal(pChild);
|
---|
| 3031 | KFSCACHE_UNLOCK(pCache);
|
---|
| 3032 | return pChild;
|
---|
| 3033 | }
|
---|
[2852] | 3034 | *penmError = KFSLOOKUPERROR_NOT_FOUND;
|
---|
| 3035 | }
|
---|
| 3036 | else
|
---|
| 3037 | *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND;
|
---|
[2868] | 3038 | if (ppLastAncestor)
|
---|
| 3039 | *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj);
|
---|
[3184] | 3040 | KFSCACHE_UNLOCK(pCache);
|
---|
[2852] | 3041 | return NULL;
|
---|
| 3042 | }
|
---|
| 3043 |
|
---|
| 3044 | /* Advance off and check if we're done already. */
|
---|
| 3045 | off = offEnd + cwcSlashes;
|
---|
| 3046 | if ( cwcSlashes == 0
|
---|
| 3047 | || off >= cwcPath)
|
---|
| 3048 | {
|
---|
| 3049 | if ( pChild->bObjType != KFSOBJ_TYPE_MISSING
|
---|
[2853] | 3050 | || pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
|
---|
[2868] | 3051 | || pChild->uCacheGen == pCache->auGenerationsMissing[pChild->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
|
---|
[2912] | 3052 | || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH)
|
---|
[2852] | 3053 | || kFsCacheRefreshMissing(pCache, pChild, penmError) )
|
---|
| 3054 | { /* likely */ }
|
---|
| 3055 | else
|
---|
[3082] | 3056 | {
|
---|
| 3057 | if (ppLastAncestor)
|
---|
| 3058 | *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj);
|
---|
[3184] | 3059 | KFSCACHE_UNLOCK(pCache);
|
---|
[2852] | 3060 | return NULL;
|
---|
[3082] | 3061 | }
|
---|
[3184] | 3062 | kFsCacheObjRetainInternal(pChild);
|
---|
| 3063 | KFSCACHE_UNLOCK(pCache);
|
---|
| 3064 | return pChild;
|
---|
[2852] | 3065 | }
|
---|
| 3066 |
|
---|
| 3067 | /*
|
---|
| 3068 | * Check that it's a directory. If a missing entry, we may have to
|
---|
| 3069 | * refresh it and re-examin it.
|
---|
| 3070 | */
|
---|
| 3071 | if (pChild->bObjType == KFSOBJ_TYPE_DIR)
|
---|
| 3072 | pParent = (PKFSDIR)pChild;
|
---|
| 3073 | else if (pChild->bObjType != KFSOBJ_TYPE_MISSING)
|
---|
| 3074 | {
|
---|
| 3075 | *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_DIR;
|
---|
[2868] | 3076 | if (ppLastAncestor)
|
---|
| 3077 | *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj);
|
---|
[3184] | 3078 | KFSCACHE_UNLOCK(pCache);
|
---|
[2852] | 3079 | return NULL;
|
---|
| 3080 | }
|
---|
[2853] | 3081 | else if ( pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
|
---|
[2912] | 3082 | || pChild->uCacheGen == pCache->auGenerationsMissing[pChild->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
|
---|
| 3083 | || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH) )
|
---|
| 3084 |
|
---|
[2852] | 3085 | {
|
---|
| 3086 | *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND;
|
---|
[2868] | 3087 | if (ppLastAncestor)
|
---|
| 3088 | *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj);
|
---|
[3184] | 3089 | KFSCACHE_UNLOCK(pCache);
|
---|
[2852] | 3090 | return NULL;
|
---|
| 3091 | }
|
---|
| 3092 | else if (kFsCacheRefreshMissingIntermediateDir(pCache, pChild, penmError))
|
---|
| 3093 | pParent = (PKFSDIR)pChild;
|
---|
| 3094 | else
|
---|
[2868] | 3095 | {
|
---|
| 3096 | if (ppLastAncestor)
|
---|
| 3097 | *ppLastAncestor = kFsCacheObjRetainInternal(&pParent->Obj);
|
---|
[3184] | 3098 | KFSCACHE_UNLOCK(pCache);
|
---|
[2852] | 3099 | return NULL;
|
---|
[2868] | 3100 | }
|
---|
[2852] | 3101 | }
|
---|
| 3102 |
|
---|
[3184] | 3103 | KFSCACHE_UNLOCK(pCache);
|
---|
[2852] | 3104 | return NULL;
|
---|
| 3105 | }
|
---|
| 3106 |
|
---|
[2856] | 3107 | /**
|
---|
| 3108 | * Walk the file system tree for the given absolute path, entering it into the
|
---|
| 3109 | * hash table.
|
---|
| 3110 | *
|
---|
| 3111 | * This will create any missing nodes while walking.
|
---|
| 3112 | *
|
---|
| 3113 | * The caller will have to do the path hash table insertion of the result.
|
---|
| 3114 | *
|
---|
| 3115 | * @returns Pointer to the tree node corresponding to @a pszPath.
|
---|
| 3116 | * NULL on lookup failure, see @a penmError for details.
|
---|
| 3117 | * @param pCache The cache.
|
---|
| 3118 | * @param pszPath The path to walk. No dot-dot bits allowed!
|
---|
| 3119 | * @param cchPath The length of the path.
|
---|
[2912] | 3120 | * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX.
|
---|
[2856] | 3121 | * @param penmError Where to return details as to why the lookup
|
---|
| 3122 | * failed.
|
---|
[2868] | 3123 | * @param ppLastAncestor Where to return the last parent element found
|
---|
| 3124 | * (referenced) in case of error an path/file not
|
---|
| 3125 | * found problem. Optional.
|
---|
[2856] | 3126 | */
|
---|
[2912] | 3127 | static PKFSOBJ kFsCacheLookupAbsoluteA(PKFSCACHE pCache, const char *pszPath, KU32 cchPath, KU32 fFlags,
|
---|
[2868] | 3128 | KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor)
|
---|
[2856] | 3129 | {
|
---|
[2868] | 3130 | PKFSOBJ pRoot;
|
---|
[2856] | 3131 | KU32 cchSlashes;
|
---|
| 3132 | KU32 offEnd;
|
---|
[2852] | 3133 |
|
---|
[2862] | 3134 | KFSCACHE_LOG2(("kFsCacheLookupAbsoluteA(%s)\n", pszPath));
|
---|
[2856] | 3135 |
|
---|
| 3136 | /*
|
---|
| 3137 | * The root "directory" needs special handling, so we keep it outside the
|
---|
| 3138 | * main search loop. (Special: Cannot enumerate it, UNCs, ++.)
|
---|
| 3139 | */
|
---|
| 3140 | cchSlashes = 0;
|
---|
| 3141 | if ( pszPath[1] == ':'
|
---|
| 3142 | && IS_ALPHA(pszPath[0]))
|
---|
| 3143 | {
|
---|
| 3144 | /* Drive letter. */
|
---|
| 3145 | offEnd = 2;
|
---|
| 3146 | kHlpAssert(IS_SLASH(pszPath[2]));
|
---|
[2930] | 3147 | pRoot = kFsCacheLookupDrive(pCache, toupper(pszPath[0]), fFlags, penmError);
|
---|
[2856] | 3148 | }
|
---|
| 3149 | else if ( IS_SLASH(pszPath[0])
|
---|
| 3150 | && IS_SLASH(pszPath[1]) )
|
---|
[2930] | 3151 | pRoot = kFsCacheLookupUncShareA(pCache, pszPath, fFlags, &offEnd, penmError);
|
---|
[2856] | 3152 | else
|
---|
| 3153 | {
|
---|
| 3154 | *penmError = KFSLOOKUPERROR_UNSUPPORTED;
|
---|
| 3155 | return NULL;
|
---|
| 3156 | }
|
---|
[2868] | 3157 | if (pRoot)
|
---|
[2856] | 3158 | { /* likely */ }
|
---|
| 3159 | else
|
---|
| 3160 | return NULL;
|
---|
| 3161 |
|
---|
| 3162 | /* Count slashes trailing the root spec. */
|
---|
| 3163 | if (offEnd < cchPath)
|
---|
| 3164 | {
|
---|
| 3165 | kHlpAssert(IS_SLASH(pszPath[offEnd]));
|
---|
| 3166 | do
|
---|
| 3167 | cchSlashes++;
|
---|
| 3168 | while (IS_SLASH(pszPath[offEnd + cchSlashes]));
|
---|
| 3169 | }
|
---|
| 3170 |
|
---|
| 3171 | /* Done already? */
|
---|
| 3172 | if (offEnd >= cchPath)
|
---|
| 3173 | {
|
---|
[2868] | 3174 | if ( pRoot->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
|
---|
| 3175 | || pRoot->uCacheGen == ( pRoot->bObjType != KFSOBJ_TYPE_MISSING
|
---|
| 3176 | ? pCache->auGenerations[ pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
|
---|
| 3177 | : pCache->auGenerationsMissing[pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN])
|
---|
[2912] | 3178 | || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH)
|
---|
[2868] | 3179 | || kFsCacheRefreshObj(pCache, pRoot, penmError))
|
---|
| 3180 | return kFsCacheObjRetainInternal(pRoot);
|
---|
[3082] | 3181 | if (ppLastAncestor)
|
---|
| 3182 | *ppLastAncestor = kFsCacheObjRetainInternal(pRoot);
|
---|
[2856] | 3183 | return NULL;
|
---|
| 3184 | }
|
---|
| 3185 |
|
---|
| 3186 | /* Check that we've got a valid result and not a cached negative one. */
|
---|
[2868] | 3187 | if (pRoot->bObjType == KFSOBJ_TYPE_DIR)
|
---|
[2856] | 3188 | { /* likely */ }
|
---|
| 3189 | else
|
---|
| 3190 | {
|
---|
[2868] | 3191 | kHlpAssert(pRoot->bObjType == KFSOBJ_TYPE_MISSING);
|
---|
| 3192 | kHlpAssert( pRoot->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
|
---|
| 3193 | || pRoot->uCacheGen == pCache->auGenerationsMissing[pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]);
|
---|
| 3194 | return pRoot;
|
---|
[2856] | 3195 | }
|
---|
| 3196 |
|
---|
| 3197 | /*
|
---|
| 3198 | * Now that we've found a valid root directory, lookup the
|
---|
| 3199 | * remainder of the path starting with it.
|
---|
| 3200 | */
|
---|
[2868] | 3201 | return kFsCacheLookupRelativeToDirA(pCache, (PKFSDIR)pRoot, &pszPath[offEnd + cchSlashes],
|
---|
[2912] | 3202 | cchPath - offEnd - cchSlashes, fFlags, penmError, ppLastAncestor);
|
---|
[2856] | 3203 | }
|
---|
| 3204 |
|
---|
| 3205 |
|
---|
[2852] | 3206 | /**
|
---|
[2856] | 3207 | * Walk the file system tree for the given absolute path, UTF-16 version.
|
---|
| 3208 | *
|
---|
| 3209 | * This will create any missing nodes while walking.
|
---|
| 3210 | *
|
---|
| 3211 | * The caller will have to do the path hash table insertion of the result.
|
---|
| 3212 | *
|
---|
| 3213 | * @returns Pointer to the tree node corresponding to @a pszPath.
|
---|
| 3214 | * NULL on lookup failure, see @a penmError for details.
|
---|
| 3215 | * @param pCache The cache.
|
---|
| 3216 | * @param pwszPath The path to walk.
|
---|
| 3217 | * @param cwcPath The length of the path (in wchar_t's).
|
---|
[2912] | 3218 | * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX.
|
---|
[2856] | 3219 | * @param penmError Where to return details as to why the lookup
|
---|
| 3220 | * failed.
|
---|
[2868] | 3221 | * @param ppLastAncestor Where to return the last parent element found
|
---|
| 3222 | * (referenced) in case of error an path/file not
|
---|
| 3223 | * found problem. Optional.
|
---|
[2856] | 3224 | */
|
---|
[2912] | 3225 | static PKFSOBJ kFsCacheLookupAbsoluteW(PKFSCACHE pCache, const wchar_t *pwszPath, KU32 cwcPath, KU32 fFlags,
|
---|
[2868] | 3226 | KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor)
|
---|
[2856] | 3227 | {
|
---|
| 3228 | PKFSDIR pParent = &pCache->RootDir;
|
---|
[2868] | 3229 | PKFSOBJ pRoot;
|
---|
[2856] | 3230 | KU32 off;
|
---|
| 3231 | KU32 cwcSlashes;
|
---|
| 3232 | KU32 offEnd;
|
---|
| 3233 |
|
---|
[2862] | 3234 | KFSCACHE_LOG2(("kFsCacheLookupAbsoluteW(%ls)\n", pwszPath));
|
---|
[2856] | 3235 |
|
---|
| 3236 | /*
|
---|
| 3237 | * The root "directory" needs special handling, so we keep it outside the
|
---|
| 3238 | * main search loop. (Special: Cannot enumerate it, UNCs, ++.)
|
---|
| 3239 | */
|
---|
| 3240 | cwcSlashes = 0;
|
---|
| 3241 | off = 0;
|
---|
| 3242 | if ( pwszPath[1] == ':'
|
---|
| 3243 | && IS_ALPHA(pwszPath[0]))
|
---|
| 3244 | {
|
---|
| 3245 | /* Drive letter. */
|
---|
| 3246 | offEnd = 2;
|
---|
| 3247 | kHlpAssert(IS_SLASH(pwszPath[2]));
|
---|
[2930] | 3248 | pRoot = kFsCacheLookupDrive(pCache, toupper(pwszPath[0]), fFlags, penmError);
|
---|
[2856] | 3249 | }
|
---|
| 3250 | else if ( IS_SLASH(pwszPath[0])
|
---|
| 3251 | && IS_SLASH(pwszPath[1]) )
|
---|
[2930] | 3252 | pRoot = kFsCacheLookupUncShareW(pCache, pwszPath, fFlags, &offEnd, penmError);
|
---|
[2856] | 3253 | else
|
---|
| 3254 | {
|
---|
| 3255 | *penmError = KFSLOOKUPERROR_UNSUPPORTED;
|
---|
| 3256 | return NULL;
|
---|
| 3257 | }
|
---|
[2868] | 3258 | if (pRoot)
|
---|
[2856] | 3259 | { /* likely */ }
|
---|
| 3260 | else
|
---|
| 3261 | return NULL;
|
---|
| 3262 |
|
---|
| 3263 | /* Count slashes trailing the root spec. */
|
---|
| 3264 | if (offEnd < cwcPath)
|
---|
| 3265 | {
|
---|
| 3266 | kHlpAssert(IS_SLASH(pwszPath[offEnd]));
|
---|
| 3267 | do
|
---|
| 3268 | cwcSlashes++;
|
---|
| 3269 | while (IS_SLASH(pwszPath[offEnd + cwcSlashes]));
|
---|
| 3270 | }
|
---|
| 3271 |
|
---|
| 3272 | /* Done already? */
|
---|
| 3273 | if (offEnd >= cwcPath)
|
---|
| 3274 | {
|
---|
[2868] | 3275 | if ( pRoot->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
|
---|
| 3276 | || pRoot->uCacheGen == (pRoot->bObjType != KFSOBJ_TYPE_MISSING
|
---|
| 3277 | ? pCache->auGenerations[ pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
|
---|
| 3278 | : pCache->auGenerationsMissing[pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN])
|
---|
[2912] | 3279 | || (fFlags & KFSCACHE_LOOKUP_F_NO_REFRESH)
|
---|
[2868] | 3280 | || kFsCacheRefreshObj(pCache, pRoot, penmError))
|
---|
| 3281 | return kFsCacheObjRetainInternal(pRoot);
|
---|
[3082] | 3282 | if (ppLastAncestor)
|
---|
| 3283 | *ppLastAncestor = kFsCacheObjRetainInternal(pRoot);
|
---|
[2856] | 3284 | return NULL;
|
---|
| 3285 | }
|
---|
| 3286 |
|
---|
| 3287 | /* Check that we've got a valid result and not a cached negative one. */
|
---|
[2868] | 3288 | if (pRoot->bObjType == KFSOBJ_TYPE_DIR)
|
---|
[2856] | 3289 | { /* likely */ }
|
---|
| 3290 | else
|
---|
| 3291 | {
|
---|
[2868] | 3292 | kHlpAssert(pRoot->bObjType == KFSOBJ_TYPE_MISSING);
|
---|
| 3293 | kHlpAssert( pRoot->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
|
---|
| 3294 | || pRoot->uCacheGen == pCache->auGenerationsMissing[pRoot->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]);
|
---|
| 3295 | return pRoot;
|
---|
[2856] | 3296 | }
|
---|
| 3297 |
|
---|
| 3298 | /*
|
---|
| 3299 | * Now that we've found a valid root directory, lookup the
|
---|
| 3300 | * remainder of the path starting with it.
|
---|
| 3301 | */
|
---|
[2868] | 3302 | return kFsCacheLookupRelativeToDirW(pCache, (PKFSDIR)pRoot, &pwszPath[offEnd + cwcSlashes],
|
---|
[2912] | 3303 | cwcPath - offEnd - cwcSlashes, fFlags, penmError, ppLastAncestor);
|
---|
[2856] | 3304 | }
|
---|
| 3305 |
|
---|
| 3306 |
|
---|
| 3307 | /**
|
---|
[2851] | 3308 | * This deals with paths that are relative and paths that contains '..'
|
---|
[2852] | 3309 | * elements, ANSI version.
|
---|
[2831] | 3310 | *
|
---|
[2851] | 3311 | * @returns Pointer to object corresponding to @a pszPath on success.
|
---|
| 3312 | * NULL if this isn't a path we care to cache.
|
---|
[2831] | 3313 | *
|
---|
[2851] | 3314 | * @param pCache The cache.
|
---|
| 3315 | * @param pszPath The path.
|
---|
| 3316 | * @param cchPath The length of the path.
|
---|
[2912] | 3317 | * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX.
|
---|
[2851] | 3318 | * @param penmError Where to return details as to why the lookup
|
---|
| 3319 | * failed.
|
---|
[2868] | 3320 | * @param ppLastAncestor Where to return the last parent element found
|
---|
| 3321 | * (referenced) in case of error an path/file not
|
---|
| 3322 | * found problem. Optional.
|
---|
[2831] | 3323 | */
|
---|
[2912] | 3324 | static PKFSOBJ kFsCacheLookupSlowA(PKFSCACHE pCache, const char *pszPath, KU32 cchPath, KU32 fFlags,
|
---|
[2868] | 3325 | KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor)
|
---|
[2831] | 3326 | {
|
---|
[2834] | 3327 | /*
|
---|
[2851] | 3328 | * We just call GetFullPathNameA here to do the job as getcwd and _getdcwd
|
---|
| 3329 | * ends up calling it anyway.
|
---|
[2834] | 3330 | */
|
---|
[2851] | 3331 | char szFull[KFSCACHE_CFG_MAX_PATH];
|
---|
| 3332 | UINT cchFull = GetFullPathNameA(pszPath, sizeof(szFull), szFull, NULL);
|
---|
| 3333 | if ( cchFull >= 3
|
---|
| 3334 | && cchFull < sizeof(szFull))
|
---|
[2834] | 3335 | {
|
---|
[2862] | 3336 | KFSCACHE_LOG2(("kFsCacheLookupSlowA(%s)\n", pszPath));
|
---|
[2912] | 3337 | return kFsCacheLookupAbsoluteA(pCache, szFull, cchFull, fFlags, penmError, ppLastAncestor);
|
---|
[2836] | 3338 | }
|
---|
| 3339 |
|
---|
[2851] | 3340 | /* The path is too long! */
|
---|
| 3341 | kHlpAssertMsgFailed(("'%s' -> cchFull=%u\n", pszPath, cchFull));
|
---|
[3372] | 3342 | *penmError = cchFull >= 3 ? KFSLOOKUPERROR_PATH_TOO_LONG : KFSLOOKUPERROR_PATH_TOO_SHORT;
|
---|
[2851] | 3343 | return NULL;
|
---|
[2831] | 3344 | }
|
---|
| 3345 |
|
---|
| 3346 |
|
---|
[2851] | 3347 | /**
|
---|
[2852] | 3348 | * This deals with paths that are relative and paths that contains '..'
|
---|
| 3349 | * elements, UTF-16 version.
|
---|
| 3350 | *
|
---|
| 3351 | * @returns Pointer to object corresponding to @a pszPath on success.
|
---|
| 3352 | * NULL if this isn't a path we care to cache.
|
---|
| 3353 | *
|
---|
| 3354 | * @param pCache The cache.
|
---|
| 3355 | * @param pwszPath The path.
|
---|
| 3356 | * @param cwcPath The length of the path (in wchar_t's).
|
---|
[2912] | 3357 | * @param fFlags Lookup flags, KFSCACHE_LOOKUP_F_XXX.
|
---|
[2852] | 3358 | * @param penmError Where to return details as to why the lookup
|
---|
| 3359 | * failed.
|
---|
[2868] | 3360 | * @param ppLastAncestor Where to return the last parent element found
|
---|
| 3361 | * (referenced) in case of error an path/file not
|
---|
| 3362 | * found problem. Optional.
|
---|
[2852] | 3363 | */
|
---|
[2912] | 3364 | static PKFSOBJ kFsCacheLookupSlowW(PKFSCACHE pCache, const wchar_t *pwszPath, KU32 wcwPath, KU32 fFlags,
|
---|
[2868] | 3365 | KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor)
|
---|
[2852] | 3366 | {
|
---|
| 3367 | /*
|
---|
| 3368 | * We just call GetFullPathNameA here to do the job as getcwd and _getdcwd
|
---|
| 3369 | * ends up calling it anyway.
|
---|
| 3370 | */
|
---|
| 3371 | wchar_t wszFull[KFSCACHE_CFG_MAX_PATH];
|
---|
| 3372 | UINT cwcFull = GetFullPathNameW(pwszPath, KFSCACHE_CFG_MAX_PATH, wszFull, NULL);
|
---|
| 3373 | if ( cwcFull >= 3
|
---|
| 3374 | && cwcFull < KFSCACHE_CFG_MAX_PATH)
|
---|
| 3375 | {
|
---|
[2862] | 3376 | KFSCACHE_LOG2(("kFsCacheLookupSlowA(%ls)\n", pwszPath));
|
---|
[2912] | 3377 | return kFsCacheLookupAbsoluteW(pCache, wszFull, cwcFull, fFlags, penmError, ppLastAncestor);
|
---|
[2852] | 3378 | }
|
---|
| 3379 |
|
---|
| 3380 | /* The path is too long! */
|
---|
| 3381 | kHlpAssertMsgFailed(("'%ls' -> cwcFull=%u\n", pwszPath, cwcFull));
|
---|
[3372] | 3382 | *penmError = cwcFull >= 3 ? KFSLOOKUPERROR_PATH_TOO_LONG : KFSLOOKUPERROR_PATH_TOO_SHORT;
|
---|
[2852] | 3383 | return NULL;
|
---|
| 3384 | }
|
---|
| 3385 |
|
---|
| 3386 |
|
---|
| 3387 | /**
|
---|
| 3388 | * Refreshes a path hash that has expired, ANSI version.
|
---|
| 3389 | *
|
---|
| 3390 | * @returns pHash on success, NULL if removed.
|
---|
| 3391 | * @param pCache The cache.
|
---|
| 3392 | * @param pHashEntry The path hash.
|
---|
| 3393 | * @param idxHashTab The hash table entry.
|
---|
| 3394 | */
|
---|
| 3395 | static PKFSHASHA kFsCacheRefreshPathA(PKFSCACHE pCache, PKFSHASHA pHashEntry, KU32 idxHashTab)
|
---|
| 3396 | {
|
---|
[2868] | 3397 | PKFSOBJ pLastAncestor = NULL;
|
---|
[2859] | 3398 | if (!pHashEntry->pFsObj)
|
---|
| 3399 | {
|
---|
| 3400 | if (pHashEntry->fAbsolute)
|
---|
[2912] | 3401 | pHashEntry->pFsObj = kFsCacheLookupAbsoluteA(pCache, pHashEntry->pszPath, pHashEntry->cchPath, 0 /*fFlags*/,
|
---|
[2868] | 3402 | &pHashEntry->enmError, &pLastAncestor);
|
---|
[2859] | 3403 | else
|
---|
[2912] | 3404 | pHashEntry->pFsObj = kFsCacheLookupSlowA(pCache, pHashEntry->pszPath, pHashEntry->cchPath, 0 /*fFlags*/,
|
---|
[2868] | 3405 | &pHashEntry->enmError, &pLastAncestor);
|
---|
[2859] | 3406 | }
|
---|
| 3407 | else
|
---|
| 3408 | {
|
---|
[2862] | 3409 | KU8 bOldType = pHashEntry->pFsObj->bObjType;
|
---|
| 3410 | KFSLOOKUPERROR enmError;
|
---|
[2859] | 3411 | if (kFsCacheRefreshObj(pCache, pHashEntry->pFsObj, &enmError))
|
---|
| 3412 | {
|
---|
[2862] | 3413 | if (pHashEntry->pFsObj->bObjType == bOldType)
|
---|
| 3414 | { }
|
---|
| 3415 | else
|
---|
| 3416 | {
|
---|
[3362] | 3417 | pHashEntry->pFsObj->cPathHashRefs -= 1;
|
---|
[2862] | 3418 | kFsCacheObjRelease(pCache, pHashEntry->pFsObj);
|
---|
| 3419 | if (pHashEntry->fAbsolute)
|
---|
[2912] | 3420 | pHashEntry->pFsObj = kFsCacheLookupAbsoluteA(pCache, pHashEntry->pszPath, pHashEntry->cchPath, 0 /*fFlags*/,
|
---|
[2868] | 3421 | &pHashEntry->enmError, &pLastAncestor);
|
---|
[2862] | 3422 | else
|
---|
[2912] | 3423 | pHashEntry->pFsObj = kFsCacheLookupSlowA(pCache, pHashEntry->pszPath, pHashEntry->cchPath, 0 /*fFlags*/,
|
---|
[2868] | 3424 | &pHashEntry->enmError, &pLastAncestor);
|
---|
[2862] | 3425 | }
|
---|
[2859] | 3426 | }
|
---|
[2862] | 3427 | else
|
---|
| 3428 | {
|
---|
[2866] | 3429 | fprintf(stderr, "kFsCacheRefreshPathA - refresh failure handling not implemented!\n");
|
---|
[2862] | 3430 | __debugbreak();
|
---|
| 3431 | /** @todo just remove this entry. */
|
---|
| 3432 | return NULL;
|
---|
| 3433 | }
|
---|
[2859] | 3434 | }
|
---|
[2868] | 3435 |
|
---|
| 3436 | if (pLastAncestor && !pHashEntry->pFsObj)
|
---|
| 3437 | pHashEntry->idxMissingGen = pLastAncestor->fFlags & KFSOBJ_F_USE_CUSTOM_GEN;
|
---|
| 3438 | pHashEntry->uCacheGen = !pHashEntry->pFsObj
|
---|
| 3439 | ? pCache->auGenerationsMissing[pHashEntry->idxMissingGen]
|
---|
| 3440 | : pHashEntry->pFsObj->bObjType == KFSOBJ_TYPE_MISSING
|
---|
| 3441 | ? pCache->auGenerationsMissing[pHashEntry->pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
|
---|
| 3442 | : pCache->auGenerations[ pHashEntry->pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN];
|
---|
| 3443 | if (pLastAncestor)
|
---|
| 3444 | kFsCacheObjRelease(pCache, pLastAncestor);
|
---|
[2852] | 3445 | return pHashEntry;
|
---|
| 3446 | }
|
---|
| 3447 |
|
---|
| 3448 |
|
---|
| 3449 | /**
|
---|
| 3450 | * Refreshes a path hash that has expired, UTF-16 version.
|
---|
| 3451 | *
|
---|
| 3452 | * @returns pHash on success, NULL if removed.
|
---|
| 3453 | * @param pCache The cache.
|
---|
| 3454 | * @param pHashEntry The path hash.
|
---|
| 3455 | * @param idxHashTab The hash table entry.
|
---|
| 3456 | */
|
---|
| 3457 | static PKFSHASHW kFsCacheRefreshPathW(PKFSCACHE pCache, PKFSHASHW pHashEntry, KU32 idxHashTab)
|
---|
| 3458 | {
|
---|
[2868] | 3459 | PKFSOBJ pLastAncestor = NULL;
|
---|
[2859] | 3460 | if (!pHashEntry->pFsObj)
|
---|
| 3461 | {
|
---|
| 3462 | if (pHashEntry->fAbsolute)
|
---|
[2912] | 3463 | pHashEntry->pFsObj = kFsCacheLookupAbsoluteW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath, 0 /*fFlags*/,
|
---|
[2868] | 3464 | &pHashEntry->enmError, &pLastAncestor);
|
---|
[2859] | 3465 | else
|
---|
[2912] | 3466 | pHashEntry->pFsObj = kFsCacheLookupSlowW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath, 0 /*fFlags*/,
|
---|
[2868] | 3467 | &pHashEntry->enmError, &pLastAncestor);
|
---|
[2859] | 3468 | }
|
---|
| 3469 | else
|
---|
| 3470 | {
|
---|
[2862] | 3471 | KU8 bOldType = pHashEntry->pFsObj->bObjType;
|
---|
| 3472 | KFSLOOKUPERROR enmError;
|
---|
[2859] | 3473 | if (kFsCacheRefreshObj(pCache, pHashEntry->pFsObj, &enmError))
|
---|
| 3474 | {
|
---|
[2862] | 3475 | if (pHashEntry->pFsObj->bObjType == bOldType)
|
---|
| 3476 | { }
|
---|
| 3477 | else
|
---|
| 3478 | {
|
---|
[3362] | 3479 | pHashEntry->pFsObj->cPathHashRefs -= 1;
|
---|
[2862] | 3480 | kFsCacheObjRelease(pCache, pHashEntry->pFsObj);
|
---|
| 3481 | if (pHashEntry->fAbsolute)
|
---|
[2912] | 3482 | pHashEntry->pFsObj = kFsCacheLookupAbsoluteW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath, 0 /*fFlags*/,
|
---|
[2868] | 3483 | &pHashEntry->enmError, &pLastAncestor);
|
---|
[2862] | 3484 | else
|
---|
[2912] | 3485 | pHashEntry->pFsObj = kFsCacheLookupSlowW(pCache, pHashEntry->pwszPath, pHashEntry->cwcPath, 0 /*fFlags*/,
|
---|
[2868] | 3486 | &pHashEntry->enmError, &pLastAncestor);
|
---|
[2862] | 3487 | }
|
---|
[2859] | 3488 | }
|
---|
[2862] | 3489 | else
|
---|
| 3490 | {
|
---|
[2866] | 3491 | fprintf(stderr, "kFsCacheRefreshPathW - refresh failure handling not implemented!\n");
|
---|
[2969] | 3492 | fflush(stderr);
|
---|
[2862] | 3493 | __debugbreak();
|
---|
| 3494 | /** @todo just remove this entry. */
|
---|
| 3495 | return NULL;
|
---|
| 3496 | }
|
---|
[2859] | 3497 | }
|
---|
[2868] | 3498 | if (pLastAncestor && !pHashEntry->pFsObj)
|
---|
| 3499 | pHashEntry->idxMissingGen = pLastAncestor->fFlags & KFSOBJ_F_USE_CUSTOM_GEN;
|
---|
| 3500 | pHashEntry->uCacheGen = !pHashEntry->pFsObj
|
---|
| 3501 | ? pCache->auGenerationsMissing[pHashEntry->idxMissingGen]
|
---|
| 3502 | : pHashEntry->pFsObj->bObjType == KFSOBJ_TYPE_MISSING
|
---|
| 3503 | ? pCache->auGenerationsMissing[pHashEntry->pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
|
---|
| 3504 | : pCache->auGenerations[ pHashEntry->pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN];
|
---|
| 3505 | if (pLastAncestor)
|
---|
| 3506 | kFsCacheObjRelease(pCache, pLastAncestor);
|
---|
[2852] | 3507 | return pHashEntry;
|
---|
| 3508 | }
|
---|
| 3509 |
|
---|
| 3510 |
|
---|
| 3511 | /**
|
---|
[2861] | 3512 | * Internal lookup worker that looks up a KFSOBJ for the given ANSI path with
|
---|
| 3513 | * length and hash.
|
---|
[2851] | 3514 | *
|
---|
| 3515 | * This will first try the hash table. If not in the hash table, the file
|
---|
| 3516 | * system cache tree is walked, missing bits filled in and finally a hash table
|
---|
| 3517 | * entry is created.
|
---|
| 3518 | *
|
---|
| 3519 | * Only drive letter paths are cachable. We don't do any UNC paths at this
|
---|
| 3520 | * point.
|
---|
| 3521 | *
|
---|
| 3522 | * @returns Reference to object corresponding to @a pszPath on success, this
|
---|
[2858] | 3523 | * must be released by kFsCacheObjRelease.
|
---|
[2851] | 3524 | * NULL if not a path we care to cache.
|
---|
| 3525 | * @param pCache The cache.
|
---|
[2861] | 3526 | * @param pchPath The path to lookup.
|
---|
| 3527 | * @param cchPath The path length.
|
---|
| 3528 | * @param uHashPath The hash of the path.
|
---|
[2851] | 3529 | * @param penmError Where to return details as to why the lookup
|
---|
| 3530 | * failed.
|
---|
| 3531 | */
|
---|
[2861] | 3532 | static PKFSOBJ kFsCacheLookupHashedA(PKFSCACHE pCache, const char *pchPath, KU32 cchPath, KU32 uHashPath,
|
---|
| 3533 | KFSLOOKUPERROR *penmError)
|
---|
[2831] | 3534 | {
|
---|
| 3535 | /*
|
---|
[2851] | 3536 | * Do hash table lookup of the path.
|
---|
[2831] | 3537 | */
|
---|
[2851] | 3538 | KU32 idxHashTab = uHashPath % K_ELEMENTS(pCache->apAnsiPaths);
|
---|
| 3539 | PKFSHASHA pHashEntry = pCache->apAnsiPaths[idxHashTab];
|
---|
[2855] | 3540 | kHlpAssert(pCache->u32Magic == KFSCACHE_MAGIC);
|
---|
[2851] | 3541 | if (pHashEntry)
|
---|
[2831] | 3542 | {
|
---|
[2851] | 3543 | do
|
---|
[2831] | 3544 | {
|
---|
[2851] | 3545 | if ( pHashEntry->uHashPath == uHashPath
|
---|
| 3546 | && pHashEntry->cchPath == cchPath
|
---|
[2861] | 3547 | && kHlpMemComp(pHashEntry->pszPath, pchPath, cchPath) == 0)
|
---|
[2832] | 3548 | {
|
---|
[2868] | 3549 | PKFSOBJ pFsObj;
|
---|
[2853] | 3550 | if ( pHashEntry->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
|
---|
[2868] | 3551 | || pHashEntry->uCacheGen == ( (pFsObj = pHashEntry->pFsObj) != NULL
|
---|
| 3552 | ? pFsObj->bObjType != KFSOBJ_TYPE_MISSING
|
---|
| 3553 | ? pCache->auGenerations[ pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
|
---|
| 3554 | : pCache->auGenerationsMissing[pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
|
---|
| 3555 | : pCache->auGenerationsMissing[pHashEntry->idxMissingGen])
|
---|
[2851] | 3556 | || (pHashEntry = kFsCacheRefreshPathA(pCache, pHashEntry, idxHashTab)) )
|
---|
[2831] | 3557 | {
|
---|
[2851] | 3558 | pCache->cLookups++;
|
---|
| 3559 | pCache->cPathHashHits++;
|
---|
[2862] | 3560 | KFSCACHE_LOG2(("kFsCacheLookupA(%*.*s) - hit %p\n", cchPath, cchPath, pchPath, pHashEntry->pFsObj));
|
---|
[2851] | 3561 | *penmError = pHashEntry->enmError;
|
---|
| 3562 | if (pHashEntry->pFsObj)
|
---|
| 3563 | return kFsCacheObjRetainInternal(pHashEntry->pFsObj);
|
---|
| 3564 | return NULL;
|
---|
[2831] | 3565 | }
|
---|
[2851] | 3566 | break;
|
---|
[2832] | 3567 | }
|
---|
[2851] | 3568 | pHashEntry = pHashEntry->pNext;
|
---|
| 3569 | } while (pHashEntry);
|
---|
[2831] | 3570 | }
|
---|
[2832] | 3571 |
|
---|
[2844] | 3572 | /*
|
---|
[2851] | 3573 | * Create an entry for it by walking the file system cache and filling in the blanks.
|
---|
[2844] | 3574 | */
|
---|
[2851] | 3575 | if ( cchPath > 0
|
---|
| 3576 | && cchPath < KFSCACHE_CFG_MAX_PATH)
|
---|
[2844] | 3577 | {
|
---|
[2851] | 3578 | PKFSOBJ pFsObj;
|
---|
[2859] | 3579 | KBOOL fAbsolute;
|
---|
[2868] | 3580 | PKFSOBJ pLastAncestor = NULL;
|
---|
[2844] | 3581 |
|
---|
[2851] | 3582 | /* Is absolute without any '..' bits? */
|
---|
| 3583 | if ( cchPath >= 3
|
---|
[2861] | 3584 | && ( ( pchPath[1] == ':' /* Drive letter */
|
---|
| 3585 | && IS_SLASH(pchPath[2])
|
---|
| 3586 | && IS_ALPHA(pchPath[0]) )
|
---|
| 3587 | || ( IS_SLASH(pchPath[0]) /* UNC */
|
---|
| 3588 | && IS_SLASH(pchPath[1]) ) )
|
---|
| 3589 | && !kFsCacheHasDotDotA(pchPath, cchPath) )
|
---|
[2859] | 3590 | {
|
---|
[2912] | 3591 | pFsObj = kFsCacheLookupAbsoluteA(pCache, pchPath, cchPath, 0 /*fFlags*/, penmError, &pLastAncestor);
|
---|
[2859] | 3592 | fAbsolute = K_TRUE;
|
---|
| 3593 | }
|
---|
[2851] | 3594 | else
|
---|
[2859] | 3595 | {
|
---|
[2912] | 3596 | pFsObj = kFsCacheLookupSlowA(pCache, pchPath, cchPath, 0 /*fFlags*/, penmError, &pLastAncestor);
|
---|
[2859] | 3597 | fAbsolute = K_FALSE;
|
---|
| 3598 | }
|
---|
[2851] | 3599 | if ( pFsObj
|
---|
| 3600 | || ( (pCache->fFlags & KFSCACHE_F_MISSING_PATHS)
|
---|
| 3601 | && *penmError != KFSLOOKUPERROR_PATH_TOO_LONG)
|
---|
| 3602 | || *penmError == KFSLOOKUPERROR_UNSUPPORTED )
|
---|
[2868] | 3603 | kFsCacheCreatePathHashTabEntryA(pCache, pFsObj, pchPath, cchPath, uHashPath, idxHashTab, fAbsolute,
|
---|
[3082] | 3604 | pLastAncestor ? pLastAncestor->fFlags & KFSOBJ_F_USE_CUSTOM_GEN : 0, *penmError);
|
---|
[2868] | 3605 | if (pLastAncestor)
|
---|
| 3606 | kFsCacheObjRelease(pCache, pLastAncestor);
|
---|
[2844] | 3607 |
|
---|
[2851] | 3608 | pCache->cLookups++;
|
---|
| 3609 | if (pFsObj)
|
---|
| 3610 | pCache->cWalkHits++;
|
---|
| 3611 | return pFsObj;
|
---|
[2844] | 3612 | }
|
---|
[2851] | 3613 |
|
---|
[3372] | 3614 | *penmError = cchPath > 0 ? KFSLOOKUPERROR_PATH_TOO_LONG : KFSLOOKUPERROR_PATH_TOO_SHORT;
|
---|
[2851] | 3615 | return NULL;
|
---|
[2844] | 3616 | }
|
---|
| 3617 |
|
---|
| 3618 |
|
---|
| 3619 | /**
|
---|
[2861] | 3620 | * Internal lookup worker that looks up a KFSOBJ for the given UTF-16 path with
|
---|
| 3621 | * length and hash.
|
---|
[2852] | 3622 | *
|
---|
| 3623 | * This will first try the hash table. If not in the hash table, the file
|
---|
| 3624 | * system cache tree is walked, missing bits filled in and finally a hash table
|
---|
| 3625 | * entry is created.
|
---|
| 3626 | *
|
---|
| 3627 | * Only drive letter paths are cachable. We don't do any UNC paths at this
|
---|
| 3628 | * point.
|
---|
| 3629 | *
|
---|
[2861] | 3630 | * @returns Reference to object corresponding to @a pwcPath on success, this
|
---|
[2858] | 3631 | * must be released by kFsCacheObjRelease.
|
---|
[2852] | 3632 | * NULL if not a path we care to cache.
|
---|
| 3633 | * @param pCache The cache.
|
---|
[2861] | 3634 | * @param pwcPath The path to lookup.
|
---|
| 3635 | * @param cwcPath The length of the path (in wchar_t's).
|
---|
| 3636 | * @param uHashPath The hash of the path.
|
---|
[2852] | 3637 | * @param penmError Where to return details as to why the lookup
|
---|
| 3638 | * failed.
|
---|
| 3639 | */
|
---|
[2861] | 3640 | static PKFSOBJ kFsCacheLookupHashedW(PKFSCACHE pCache, const wchar_t *pwcPath, KU32 cwcPath, KU32 uHashPath,
|
---|
| 3641 | KFSLOOKUPERROR *penmError)
|
---|
[2852] | 3642 | {
|
---|
| 3643 | /*
|
---|
| 3644 | * Do hash table lookup of the path.
|
---|
| 3645 | */
|
---|
| 3646 | KU32 idxHashTab = uHashPath % K_ELEMENTS(pCache->apAnsiPaths);
|
---|
| 3647 | PKFSHASHW pHashEntry = pCache->apUtf16Paths[idxHashTab];
|
---|
[2855] | 3648 | kHlpAssert(pCache->u32Magic == KFSCACHE_MAGIC);
|
---|
[2852] | 3649 | if (pHashEntry)
|
---|
| 3650 | {
|
---|
| 3651 | do
|
---|
| 3652 | {
|
---|
| 3653 | if ( pHashEntry->uHashPath == uHashPath
|
---|
| 3654 | && pHashEntry->cwcPath == cwcPath
|
---|
[2861] | 3655 | && kHlpMemComp(pHashEntry->pwszPath, pwcPath, cwcPath) == 0)
|
---|
[2852] | 3656 | {
|
---|
[2868] | 3657 | PKFSOBJ pFsObj;
|
---|
[2853] | 3658 | if ( pHashEntry->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
|
---|
[2868] | 3659 | || pHashEntry->uCacheGen == ((pFsObj = pHashEntry->pFsObj) != NULL
|
---|
| 3660 | ? pFsObj->bObjType != KFSOBJ_TYPE_MISSING
|
---|
| 3661 | ? pCache->auGenerations[ pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
|
---|
| 3662 | : pCache->auGenerationsMissing[pFsObj->fFlags & KFSOBJ_F_USE_CUSTOM_GEN]
|
---|
| 3663 | : pCache->auGenerationsMissing[pHashEntry->idxMissingGen])
|
---|
[2852] | 3664 | || (pHashEntry = kFsCacheRefreshPathW(pCache, pHashEntry, idxHashTab)) )
|
---|
| 3665 | {
|
---|
| 3666 | pCache->cLookups++;
|
---|
| 3667 | pCache->cPathHashHits++;
|
---|
[2862] | 3668 | KFSCACHE_LOG2(("kFsCacheLookupW(%*.*ls) - hit %p\n", cwcPath, cwcPath, pwcPath, pHashEntry->pFsObj));
|
---|
[2852] | 3669 | *penmError = pHashEntry->enmError;
|
---|
| 3670 | if (pHashEntry->pFsObj)
|
---|
| 3671 | return kFsCacheObjRetainInternal(pHashEntry->pFsObj);
|
---|
| 3672 | return NULL;
|
---|
| 3673 | }
|
---|
| 3674 | break;
|
---|
| 3675 | }
|
---|
| 3676 | pHashEntry = pHashEntry->pNext;
|
---|
| 3677 | } while (pHashEntry);
|
---|
| 3678 | }
|
---|
| 3679 |
|
---|
| 3680 | /*
|
---|
| 3681 | * Create an entry for it by walking the file system cache and filling in the blanks.
|
---|
| 3682 | */
|
---|
| 3683 | if ( cwcPath > 0
|
---|
| 3684 | && cwcPath < KFSCACHE_CFG_MAX_PATH)
|
---|
| 3685 | {
|
---|
| 3686 | PKFSOBJ pFsObj;
|
---|
[2859] | 3687 | KBOOL fAbsolute;
|
---|
[2868] | 3688 | PKFSOBJ pLastAncestor = NULL;
|
---|
[2852] | 3689 |
|
---|
| 3690 | /* Is absolute without any '..' bits? */
|
---|
| 3691 | if ( cwcPath >= 3
|
---|
[2861] | 3692 | && ( ( pwcPath[1] == ':' /* Drive letter */
|
---|
| 3693 | && IS_SLASH(pwcPath[2])
|
---|
| 3694 | && IS_ALPHA(pwcPath[0]) )
|
---|
| 3695 | || ( IS_SLASH(pwcPath[0]) /* UNC */
|
---|
| 3696 | && IS_SLASH(pwcPath[1]) ) )
|
---|
| 3697 | && !kFsCacheHasDotDotW(pwcPath, cwcPath) )
|
---|
[2859] | 3698 | {
|
---|
[2912] | 3699 | pFsObj = kFsCacheLookupAbsoluteW(pCache, pwcPath, cwcPath, 0 /*fFlags*/, penmError, &pLastAncestor);
|
---|
[2859] | 3700 | fAbsolute = K_TRUE;
|
---|
| 3701 | }
|
---|
[2852] | 3702 | else
|
---|
[2859] | 3703 | {
|
---|
[2912] | 3704 | pFsObj = kFsCacheLookupSlowW(pCache, pwcPath, cwcPath, 0 /*fFlags*/, penmError, &pLastAncestor);
|
---|
[2859] | 3705 | fAbsolute = K_FALSE;
|
---|
| 3706 | }
|
---|
[2852] | 3707 | if ( pFsObj
|
---|
| 3708 | || ( (pCache->fFlags & KFSCACHE_F_MISSING_PATHS)
|
---|
| 3709 | && *penmError != KFSLOOKUPERROR_PATH_TOO_LONG)
|
---|
| 3710 | || *penmError == KFSLOOKUPERROR_UNSUPPORTED )
|
---|
[2868] | 3711 | kFsCacheCreatePathHashTabEntryW(pCache, pFsObj, pwcPath, cwcPath, uHashPath, idxHashTab, fAbsolute,
|
---|
[3082] | 3712 | pLastAncestor ? pLastAncestor->fFlags & KFSOBJ_F_USE_CUSTOM_GEN : 0, *penmError);
|
---|
[2868] | 3713 | if (pLastAncestor)
|
---|
| 3714 | kFsCacheObjRelease(pCache, pLastAncestor);
|
---|
[2852] | 3715 |
|
---|
| 3716 | pCache->cLookups++;
|
---|
| 3717 | if (pFsObj)
|
---|
| 3718 | pCache->cWalkHits++;
|
---|
| 3719 | return pFsObj;
|
---|
| 3720 | }
|
---|
| 3721 |
|
---|
[3372] | 3722 | *penmError = cwcPath > 0 ? KFSLOOKUPERROR_PATH_TOO_LONG : KFSLOOKUPERROR_PATH_TOO_SHORT;
|
---|
[2852] | 3723 | return NULL;
|
---|
| 3724 | }
|
---|
| 3725 |
|
---|
| 3726 |
|
---|
[2861] | 3727 |
|
---|
[2852] | 3728 | /**
|
---|
[2861] | 3729 | * Looks up a KFSOBJ for the given ANSI path.
|
---|
| 3730 | *
|
---|
| 3731 | * This will first try the hash table. If not in the hash table, the file
|
---|
| 3732 | * system cache tree is walked, missing bits filled in and finally a hash table
|
---|
| 3733 | * entry is created.
|
---|
| 3734 | *
|
---|
| 3735 | * Only drive letter paths are cachable. We don't do any UNC paths at this
|
---|
| 3736 | * point.
|
---|
| 3737 | *
|
---|
| 3738 | * @returns Reference to object corresponding to @a pszPath on success, this
|
---|
| 3739 | * must be released by kFsCacheObjRelease.
|
---|
| 3740 | * NULL if not a path we care to cache.
|
---|
| 3741 | * @param pCache The cache.
|
---|
| 3742 | * @param pszPath The path to lookup.
|
---|
| 3743 | * @param penmError Where to return details as to why the lookup
|
---|
| 3744 | * failed.
|
---|
| 3745 | */
|
---|
| 3746 | PKFSOBJ kFsCacheLookupA(PKFSCACHE pCache, const char *pszPath, KFSLOOKUPERROR *penmError)
|
---|
| 3747 | {
|
---|
[3184] | 3748 | KU32 uHashPath;
|
---|
| 3749 | KU32 cchPath = (KU32)kFsCacheStrHashEx(pszPath, &uHashPath);
|
---|
| 3750 | PKFSOBJ pObj;
|
---|
| 3751 | KFSCACHE_LOCK(pCache);
|
---|
| 3752 | pObj = kFsCacheLookupHashedA(pCache, pszPath, cchPath, uHashPath, penmError);
|
---|
| 3753 | KFSCACHE_UNLOCK(pCache);
|
---|
| 3754 | return pObj;
|
---|
[2861] | 3755 | }
|
---|
| 3756 |
|
---|
| 3757 |
|
---|
| 3758 | /**
|
---|
| 3759 | * Looks up a KFSOBJ for the given UTF-16 path.
|
---|
| 3760 | *
|
---|
| 3761 | * This will first try the hash table. If not in the hash table, the file
|
---|
| 3762 | * system cache tree is walked, missing bits filled in and finally a hash table
|
---|
| 3763 | * entry is created.
|
---|
| 3764 | *
|
---|
| 3765 | * Only drive letter paths are cachable. We don't do any UNC paths at this
|
---|
| 3766 | * point.
|
---|
| 3767 | *
|
---|
| 3768 | * @returns Reference to object corresponding to @a pwszPath on success, this
|
---|
| 3769 | * must be released by kFsCacheObjRelease.
|
---|
| 3770 | * NULL if not a path we care to cache.
|
---|
| 3771 | * @param pCache The cache.
|
---|
| 3772 | * @param pwszPath The path to lookup.
|
---|
| 3773 | * @param penmError Where to return details as to why the lookup
|
---|
| 3774 | * failed.
|
---|
| 3775 | */
|
---|
| 3776 | PKFSOBJ kFsCacheLookupW(PKFSCACHE pCache, const wchar_t *pwszPath, KFSLOOKUPERROR *penmError)
|
---|
| 3777 | {
|
---|
[3184] | 3778 | KU32 uHashPath;
|
---|
| 3779 | KU32 cwcPath = (KU32)kFsCacheUtf16HashEx(pwszPath, &uHashPath);
|
---|
| 3780 | PKFSOBJ pObj;
|
---|
| 3781 | KFSCACHE_LOCK(pCache);
|
---|
| 3782 | pObj = kFsCacheLookupHashedW(pCache, pwszPath, cwcPath, uHashPath, penmError);
|
---|
| 3783 | KFSCACHE_UNLOCK(pCache);
|
---|
| 3784 | return pObj;
|
---|
[2861] | 3785 | }
|
---|
| 3786 |
|
---|
| 3787 |
|
---|
| 3788 | /**
|
---|
| 3789 | * Looks up a KFSOBJ for the given ANSI path.
|
---|
| 3790 | *
|
---|
| 3791 | * This will first try the hash table. If not in the hash table, the file
|
---|
| 3792 | * system cache tree is walked, missing bits filled in and finally a hash table
|
---|
| 3793 | * entry is created.
|
---|
| 3794 | *
|
---|
| 3795 | * Only drive letter paths are cachable. We don't do any UNC paths at this
|
---|
| 3796 | * point.
|
---|
| 3797 | *
|
---|
| 3798 | * @returns Reference to object corresponding to @a pchPath on success, this
|
---|
| 3799 | * must be released by kFsCacheObjRelease.
|
---|
| 3800 | * NULL if not a path we care to cache.
|
---|
| 3801 | * @param pCache The cache.
|
---|
| 3802 | * @param pchPath The path to lookup (does not need to be nul
|
---|
| 3803 | * terminated).
|
---|
| 3804 | * @param cchPath The path length.
|
---|
| 3805 | * @param penmError Where to return details as to why the lookup
|
---|
| 3806 | * failed.
|
---|
| 3807 | */
|
---|
| 3808 | PKFSOBJ kFsCacheLookupWithLengthA(PKFSCACHE pCache, const char *pchPath, KSIZE cchPath, KFSLOOKUPERROR *penmError)
|
---|
| 3809 | {
|
---|
[3184] | 3810 | KU32 uHashPath = kFsCacheStrHashN(pchPath, cchPath);
|
---|
| 3811 | PKFSOBJ pObj;
|
---|
| 3812 | KFSCACHE_LOCK(pCache);
|
---|
| 3813 | pObj = kFsCacheLookupHashedA(pCache, pchPath, (KU32)cchPath, uHashPath, penmError);
|
---|
| 3814 | KFSCACHE_UNLOCK(pCache);
|
---|
| 3815 | return pObj;
|
---|
[2861] | 3816 | }
|
---|
| 3817 |
|
---|
| 3818 |
|
---|
| 3819 | /**
|
---|
| 3820 | * Looks up a KFSOBJ for the given UTF-16 path.
|
---|
| 3821 | *
|
---|
| 3822 | * This will first try the hash table. If not in the hash table, the file
|
---|
| 3823 | * system cache tree is walked, missing bits filled in and finally a hash table
|
---|
| 3824 | * entry is created.
|
---|
| 3825 | *
|
---|
| 3826 | * Only drive letter paths are cachable. We don't do any UNC paths at this
|
---|
| 3827 | * point.
|
---|
| 3828 | *
|
---|
| 3829 | * @returns Reference to object corresponding to @a pwchPath on success, this
|
---|
| 3830 | * must be released by kFsCacheObjRelease.
|
---|
| 3831 | * NULL if not a path we care to cache.
|
---|
| 3832 | * @param pCache The cache.
|
---|
| 3833 | * @param pwcPath The path to lookup (does not need to be nul
|
---|
| 3834 | * terminated).
|
---|
| 3835 | * @param cwcPath The path length (in wchar_t's).
|
---|
| 3836 | * @param penmError Where to return details as to why the lookup
|
---|
| 3837 | * failed.
|
---|
| 3838 | */
|
---|
| 3839 | PKFSOBJ kFsCacheLookupWithLengthW(PKFSCACHE pCache, const wchar_t *pwcPath, KSIZE cwcPath, KFSLOOKUPERROR *penmError)
|
---|
| 3840 | {
|
---|
[3184] | 3841 | KU32 uHashPath = kFsCacheUtf16HashN(pwcPath, cwcPath);
|
---|
| 3842 | PKFSOBJ pObj;
|
---|
| 3843 | KFSCACHE_LOCK(pCache);
|
---|
| 3844 | pObj = kFsCacheLookupHashedW(pCache, pwcPath, (KU32)cwcPath, uHashPath, penmError);
|
---|
| 3845 | KFSCACHE_UNLOCK(pCache);
|
---|
| 3846 | return pObj;
|
---|
[2861] | 3847 | }
|
---|
| 3848 |
|
---|
| 3849 |
|
---|
| 3850 | /**
|
---|
[2858] | 3851 | * Wrapper around kFsCacheLookupA that drops KFSOBJ_TYPE_MISSING and returns
|
---|
| 3852 | * KFSLOOKUPERROR_NOT_FOUND instead.
|
---|
| 3853 | *
|
---|
| 3854 | * @returns Reference to object corresponding to @a pszPath on success, this
|
---|
| 3855 | * must be released by kFsCacheObjRelease.
|
---|
| 3856 | * NULL if not a path we care to cache.
|
---|
| 3857 | * @param pCache The cache.
|
---|
| 3858 | * @param pszPath The path to lookup.
|
---|
| 3859 | * @param penmError Where to return details as to why the lookup
|
---|
| 3860 | * failed.
|
---|
| 3861 | */
|
---|
| 3862 | PKFSOBJ kFsCacheLookupNoMissingA(PKFSCACHE pCache, const char *pszPath, KFSLOOKUPERROR *penmError)
|
---|
| 3863 | {
|
---|
[3184] | 3864 | PKFSOBJ pObj;
|
---|
| 3865 | KFSCACHE_LOCK(pCache); /* probably not necessary */
|
---|
| 3866 | pObj = kFsCacheLookupA(pCache, pszPath, penmError);
|
---|
[2858] | 3867 | if (pObj)
|
---|
| 3868 | {
|
---|
| 3869 | if (pObj->bObjType != KFSOBJ_TYPE_MISSING)
|
---|
[3184] | 3870 | {
|
---|
| 3871 | KFSCACHE_UNLOCK(pCache);
|
---|
[2858] | 3872 | return pObj;
|
---|
[3184] | 3873 | }
|
---|
[2858] | 3874 |
|
---|
| 3875 | kFsCacheObjRelease(pCache, pObj);
|
---|
| 3876 | *penmError = KFSLOOKUPERROR_NOT_FOUND;
|
---|
| 3877 | }
|
---|
[3184] | 3878 | KFSCACHE_UNLOCK(pCache);
|
---|
[2858] | 3879 | return NULL;
|
---|
| 3880 | }
|
---|
| 3881 |
|
---|
| 3882 |
|
---|
| 3883 | /**
|
---|
| 3884 | * Wrapper around kFsCacheLookupW that drops KFSOBJ_TYPE_MISSING and returns
|
---|
| 3885 | * KFSLOOKUPERROR_NOT_FOUND instead.
|
---|
| 3886 | *
|
---|
| 3887 | * @returns Reference to object corresponding to @a pszPath on success, this
|
---|
| 3888 | * must be released by kFsCacheObjRelease.
|
---|
| 3889 | * NULL if not a path we care to cache.
|
---|
| 3890 | * @param pCache The cache.
|
---|
| 3891 | * @param pwszPath The path to lookup.
|
---|
| 3892 | * @param penmError Where to return details as to why the lookup
|
---|
| 3893 | * failed.
|
---|
| 3894 | */
|
---|
| 3895 | PKFSOBJ kFsCacheLookupNoMissingW(PKFSCACHE pCache, const wchar_t *pwszPath, KFSLOOKUPERROR *penmError)
|
---|
| 3896 | {
|
---|
[3184] | 3897 | PKFSOBJ pObj;
|
---|
| 3898 | KFSCACHE_LOCK(pCache); /* probably not necessary */
|
---|
| 3899 | pObj = kFsCacheLookupW(pCache, pwszPath, penmError);
|
---|
[2858] | 3900 | if (pObj)
|
---|
| 3901 | {
|
---|
| 3902 | if (pObj->bObjType != KFSOBJ_TYPE_MISSING)
|
---|
[3184] | 3903 | {
|
---|
| 3904 | KFSCACHE_UNLOCK(pCache);
|
---|
[2858] | 3905 | return pObj;
|
---|
[3184] | 3906 | }
|
---|
[2858] | 3907 |
|
---|
| 3908 | kFsCacheObjRelease(pCache, pObj);
|
---|
| 3909 | *penmError = KFSLOOKUPERROR_NOT_FOUND;
|
---|
| 3910 | }
|
---|
[3184] | 3911 | KFSCACHE_UNLOCK(pCache);
|
---|
[2858] | 3912 | return NULL;
|
---|
| 3913 | }
|
---|
| 3914 |
|
---|
| 3915 |
|
---|
| 3916 | /**
|
---|
[2851] | 3917 | * Destroys a cache object which has a zero reference count.
|
---|
[2844] | 3918 | *
|
---|
[2851] | 3919 | * @returns 0
|
---|
| 3920 | * @param pCache The cache.
|
---|
| 3921 | * @param pObj The object.
|
---|
[2944] | 3922 | * @param pszWhere Where it was released from.
|
---|
[2844] | 3923 | */
|
---|
[2944] | 3924 | KU32 kFsCacheObjDestroy(PKFSCACHE pCache, PKFSOBJ pObj, const char *pszWhere)
|
---|
[2844] | 3925 | {
|
---|
[2851] | 3926 | kHlpAssert(pObj->cRefs == 0);
|
---|
| 3927 | kHlpAssert(pObj->pParent == NULL);
|
---|
[2855] | 3928 | kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC);
|
---|
[3184] | 3929 | KFSCACHE_LOCK(pCache);
|
---|
[2844] | 3930 |
|
---|
[2944] | 3931 | KFSCACHE_LOG(("Destroying %s/%s, type=%d, pObj=%p, pszWhere=%s\n",
|
---|
| 3932 | pObj->pParent ? pObj->pParent->Obj.pszName : "", pObj->pszName, pObj->bObjType, pObj, pszWhere));
|
---|
[3362] | 3933 | if (pObj->cPathHashRefs != 0)
|
---|
[2879] | 3934 | {
|
---|
| 3935 | fprintf(stderr, "Destroying %s/%s, type=%d, path hash entries: %d!\n", pObj->pParent ? pObj->pParent->Obj.pszName : "",
|
---|
[3362] | 3936 | pObj->pszName, pObj->bObjType, pObj->cPathHashRefs);
|
---|
[2969] | 3937 | fflush(stderr);
|
---|
[2879] | 3938 | __debugbreak();
|
---|
| 3939 | }
|
---|
[2863] | 3940 |
|
---|
[2855] | 3941 | /*
|
---|
| 3942 | * Invalidate the structure.
|
---|
| 3943 | */
|
---|
| 3944 | pObj->u32Magic = ~KFSOBJ_MAGIC;
|
---|
| 3945 |
|
---|
| 3946 | /*
|
---|
| 3947 | * Destroy any user data first.
|
---|
| 3948 | */
|
---|
| 3949 | while (pObj->pUserDataHead != NULL)
|
---|
| 3950 | {
|
---|
| 3951 | PKFSUSERDATA pUserData = pObj->pUserDataHead;
|
---|
| 3952 | pObj->pUserDataHead = pUserData->pNext;
|
---|
[2856] | 3953 | if (pUserData->pfnDestructor)
|
---|
| 3954 | pUserData->pfnDestructor(pCache, pObj, pUserData);
|
---|
[2855] | 3955 | kHlpFree(pUserData);
|
---|
| 3956 | }
|
---|
| 3957 |
|
---|
| 3958 | /*
|
---|
| 3959 | * Do type specific destruction
|
---|
| 3960 | */
|
---|
[2851] | 3961 | switch (pObj->bObjType)
|
---|
[2844] | 3962 | {
|
---|
[2851] | 3963 | case KFSOBJ_TYPE_MISSING:
|
---|
| 3964 | /* nothing else to do here */
|
---|
[2855] | 3965 | pCache->cbObjects -= sizeof(KFSDIR);
|
---|
[2851] | 3966 | break;
|
---|
[2844] | 3967 |
|
---|
[2851] | 3968 | case KFSOBJ_TYPE_DIR:
|
---|
[2855] | 3969 | {
|
---|
| 3970 | PKFSDIR pDir = (PKFSDIR)pObj;
|
---|
| 3971 | KU32 cChildren = pDir->cChildren;
|
---|
| 3972 | pCache->cbObjects -= sizeof(*pDir)
|
---|
| 3973 | + K_ALIGN_Z(cChildren, 16) * sizeof(pDir->papChildren)
|
---|
[2930] | 3974 | + (pDir->fHashTabMask + !!pDir->fHashTabMask) * sizeof(pDir->papHashTab[0]);
|
---|
[2855] | 3975 |
|
---|
| 3976 | pDir->cChildren = 0;
|
---|
| 3977 | while (cChildren-- > 0)
|
---|
| 3978 | kFsCacheObjRelease(pCache, pDir->papChildren[cChildren]);
|
---|
| 3979 | kHlpFree(pDir->papChildren);
|
---|
| 3980 | pDir->papChildren = NULL;
|
---|
| 3981 |
|
---|
[2930] | 3982 | kHlpFree(pDir->papHashTab);
|
---|
| 3983 | pDir->papHashTab = NULL;
|
---|
[2855] | 3984 | break;
|
---|
| 3985 | }
|
---|
| 3986 |
|
---|
[2851] | 3987 | case KFSOBJ_TYPE_FILE:
|
---|
[2855] | 3988 | case KFSOBJ_TYPE_OTHER:
|
---|
| 3989 | pCache->cbObjects -= sizeof(*pObj);
|
---|
[2851] | 3990 | break;
|
---|
[2855] | 3991 |
|
---|
[2851] | 3992 | default:
|
---|
[3184] | 3993 | KFSCACHE_UNLOCK(pCache);
|
---|
[2855] | 3994 | return 0;
|
---|
[2844] | 3995 | }
|
---|
[2855] | 3996 |
|
---|
| 3997 | /*
|
---|
| 3998 | * Common bits.
|
---|
| 3999 | */
|
---|
| 4000 | pCache->cbObjects -= pObj->cchName + 1;
|
---|
| 4001 | #ifdef KFSCACHE_CFG_UTF16
|
---|
| 4002 | pCache->cbObjects -= (pObj->cwcName + 1) * sizeof(wchar_t);
|
---|
| 4003 | #endif
|
---|
| 4004 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 4005 | if (pObj->pszName != pObj->pszShortName)
|
---|
| 4006 | {
|
---|
| 4007 | pCache->cbObjects -= pObj->cchShortName + 1;
|
---|
| 4008 | # ifdef KFSCACHE_CFG_UTF16
|
---|
| 4009 | pCache->cbObjects -= (pObj->cwcShortName + 1) * sizeof(wchar_t);
|
---|
| 4010 | # endif
|
---|
| 4011 | }
|
---|
| 4012 | #endif
|
---|
[2851] | 4013 | pCache->cObjects--;
|
---|
[2855] | 4014 |
|
---|
[2967] | 4015 | if (pObj->pNameAlloc)
|
---|
| 4016 | {
|
---|
| 4017 | pCache->cbObjects -= pObj->pNameAlloc->cb;
|
---|
| 4018 | kHlpFree(pObj->pNameAlloc);
|
---|
| 4019 | }
|
---|
| 4020 |
|
---|
[3184] | 4021 | KFSCACHE_UNLOCK(pCache);
|
---|
| 4022 |
|
---|
[2855] | 4023 | kHlpFree(pObj);
|
---|
[2851] | 4024 | return 0;
|
---|
[2844] | 4025 | }
|
---|
| 4026 |
|
---|
| 4027 |
|
---|
| 4028 | /**
|
---|
[2851] | 4029 | * Releases a reference to a cache object.
|
---|
[2844] | 4030 | *
|
---|
[2851] | 4031 | * @returns New reference count.
|
---|
| 4032 | * @param pCache The cache.
|
---|
| 4033 | * @param pObj The object.
|
---|
[2844] | 4034 | */
|
---|
[2944] | 4035 | #undef kFsCacheObjRelease
|
---|
[2851] | 4036 | KU32 kFsCacheObjRelease(PKFSCACHE pCache, PKFSOBJ pObj)
|
---|
[2844] | 4037 | {
|
---|
[2858] | 4038 | if (pObj)
|
---|
| 4039 | {
|
---|
| 4040 | KU32 cRefs;
|
---|
| 4041 | kHlpAssert(pCache->u32Magic == KFSCACHE_MAGIC);
|
---|
| 4042 | kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC);
|
---|
[2855] | 4043 |
|
---|
[3184] | 4044 | cRefs = _InterlockedDecrement(&pObj->cRefs);
|
---|
[2858] | 4045 | if (cRefs)
|
---|
| 4046 | return cRefs;
|
---|
[2944] | 4047 | return kFsCacheObjDestroy(pCache, pObj, "kFsCacheObjRelease");
|
---|
[2858] | 4048 | }
|
---|
| 4049 | return 0;
|
---|
[2844] | 4050 | }
|
---|
| 4051 |
|
---|
| 4052 |
|
---|
| 4053 | /**
|
---|
[2944] | 4054 | * Debug version of kFsCacheObjRelease
|
---|
| 4055 | *
|
---|
| 4056 | * @returns New reference count.
|
---|
| 4057 | * @param pCache The cache.
|
---|
| 4058 | * @param pObj The object.
|
---|
| 4059 | * @param pszWhere Where it's invoked from.
|
---|
| 4060 | */
|
---|
| 4061 | KU32 kFsCacheObjReleaseTagged(PKFSCACHE pCache, PKFSOBJ pObj, const char *pszWhere)
|
---|
| 4062 | {
|
---|
| 4063 | if (pObj)
|
---|
| 4064 | {
|
---|
| 4065 | KU32 cRefs;
|
---|
| 4066 | kHlpAssert(pCache->u32Magic == KFSCACHE_MAGIC);
|
---|
| 4067 | kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC);
|
---|
| 4068 |
|
---|
[3184] | 4069 | cRefs = _InterlockedDecrement(&pObj->cRefs);
|
---|
[2944] | 4070 | if (cRefs)
|
---|
| 4071 | return cRefs;
|
---|
| 4072 | return kFsCacheObjDestroy(pCache, pObj, pszWhere);
|
---|
| 4073 | }
|
---|
| 4074 | return 0;
|
---|
| 4075 | }
|
---|
| 4076 |
|
---|
| 4077 |
|
---|
| 4078 | /**
|
---|
[2851] | 4079 | * Retains a reference to a cahce object.
|
---|
[2844] | 4080 | *
|
---|
[2851] | 4081 | * @returns New reference count.
|
---|
| 4082 | * @param pObj The object.
|
---|
[2844] | 4083 | */
|
---|
[2851] | 4084 | KU32 kFsCacheObjRetain(PKFSOBJ pObj)
|
---|
[2844] | 4085 | {
|
---|
[2855] | 4086 | KU32 cRefs;
|
---|
| 4087 | kHlpAssert(pCache->u32Magic == KFSCACHE_MAGIC);
|
---|
| 4088 | kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC);
|
---|
| 4089 |
|
---|
[3184] | 4090 | cRefs = _InterlockedIncrement(&pObj->cRefs);
|
---|
[2851] | 4091 | kHlpAssert(cRefs < 16384);
|
---|
| 4092 | return cRefs;
|
---|
[2844] | 4093 | }
|
---|
| 4094 |
|
---|
| 4095 |
|
---|
[2856] | 4096 | /**
|
---|
| 4097 | * Associates an item of user data with the given object.
|
---|
| 4098 | *
|
---|
| 4099 | * If the data needs cleaning up before being free, set the
|
---|
| 4100 | * PKFSUSERDATA::pfnDestructor member of the returned structure.
|
---|
| 4101 | *
|
---|
| 4102 | * @returns Pointer to the user data on success.
|
---|
| 4103 | * NULL if out of memory or key already in use.
|
---|
| 4104 | *
|
---|
| 4105 | * @param pCache The cache.
|
---|
| 4106 | * @param pObj The object.
|
---|
| 4107 | * @param uKey The user data key.
|
---|
| 4108 | * @param cbUserData The size of the user data.
|
---|
| 4109 | */
|
---|
| 4110 | PKFSUSERDATA kFsCacheObjAddUserData(PKFSCACHE pCache, PKFSOBJ pObj, KUPTR uKey, KSIZE cbUserData)
|
---|
| 4111 | {
|
---|
| 4112 | kHlpAssert(cbUserData >= sizeof(*pNew));
|
---|
[3362] | 4113 | KFSCACHE_OBJUSERDATA_LOCK(pCache, pObj);
|
---|
[3184] | 4114 |
|
---|
[2856] | 4115 | if (kFsCacheObjGetUserData(pCache, pObj, uKey) == NULL)
|
---|
| 4116 | {
|
---|
| 4117 | PKFSUSERDATA pNew = (PKFSUSERDATA)kHlpAllocZ(cbUserData);
|
---|
| 4118 | if (pNew)
|
---|
| 4119 | {
|
---|
| 4120 | pNew->uKey = uKey;
|
---|
| 4121 | pNew->pfnDestructor = NULL;
|
---|
| 4122 | pNew->pNext = pObj->pUserDataHead;
|
---|
| 4123 | pObj->pUserDataHead = pNew;
|
---|
[3362] | 4124 | KFSCACHE_OBJUSERDATA_UNLOCK(pCache, pObj);
|
---|
[2856] | 4125 | return pNew;
|
---|
| 4126 | }
|
---|
| 4127 | }
|
---|
[2851] | 4128 |
|
---|
[3362] | 4129 | KFSCACHE_OBJUSERDATA_UNLOCK(pCache, pObj);
|
---|
[2856] | 4130 | return NULL;
|
---|
| 4131 | }
|
---|
| 4132 |
|
---|
| 4133 |
|
---|
| 4134 | /**
|
---|
| 4135 | * Retrieves an item of user data associated with the given object.
|
---|
| 4136 | *
|
---|
| 4137 | * @returns Pointer to the associated user data if found, otherwise NULL.
|
---|
| 4138 | * @param pCache The cache.
|
---|
| 4139 | * @param pObj The object.
|
---|
| 4140 | * @param uKey The user data key.
|
---|
| 4141 | */
|
---|
| 4142 | PKFSUSERDATA kFsCacheObjGetUserData(PKFSCACHE pCache, PKFSOBJ pObj, KUPTR uKey)
|
---|
| 4143 | {
|
---|
| 4144 | PKFSUSERDATA pCur;
|
---|
| 4145 |
|
---|
| 4146 | kHlpAssert(pCache->u32Magic == KFSCACHE_MAGIC);
|
---|
| 4147 | kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC);
|
---|
[3362] | 4148 | KFSCACHE_OBJUSERDATA_LOCK(pCache, pObj);
|
---|
[2856] | 4149 |
|
---|
| 4150 | for (pCur = pObj->pUserDataHead; pCur; pCur = pCur->pNext)
|
---|
| 4151 | if (pCur->uKey == uKey)
|
---|
[3184] | 4152 | {
|
---|
[3362] | 4153 | KFSCACHE_OBJUSERDATA_UNLOCK(pCache, pObj);
|
---|
[2856] | 4154 | return pCur;
|
---|
[3184] | 4155 | }
|
---|
| 4156 |
|
---|
[3362] | 4157 | KFSCACHE_OBJUSERDATA_UNLOCK(pCache, pObj);
|
---|
[2856] | 4158 | return NULL;
|
---|
| 4159 | }
|
---|
| 4160 |
|
---|
| 4161 |
|
---|
[2858] | 4162 | /**
|
---|
[3362] | 4163 | * Determins the idxUserDataLock value.
|
---|
| 4164 | *
|
---|
| 4165 | * Called by KFSCACHE_OBJUSERDATA_LOCK when idxUserDataLock is set to KU8_MAX.
|
---|
| 4166 | *
|
---|
| 4167 | * @returns The proper idxUserDataLock value.
|
---|
| 4168 | * @param pCache The cache.
|
---|
| 4169 | * @param pObj The object.
|
---|
| 4170 | */
|
---|
| 4171 | KU8 kFsCacheObjGetUserDataLockIndex(PKFSCACHE pCache, PKFSOBJ pObj)
|
---|
| 4172 | {
|
---|
| 4173 | KU8 idxUserDataLock = pObj->idxUserDataLock;
|
---|
| 4174 | if (idxUserDataLock == KU8_MAX)
|
---|
| 4175 | {
|
---|
| 4176 | KFSCACHE_LOCK(pCache);
|
---|
| 4177 | idxUserDataLock = pObj->idxUserDataLock;
|
---|
| 4178 | if (idxUserDataLock == KU8_MAX)
|
---|
| 4179 | {
|
---|
| 4180 | idxUserDataLock = pCache->idxUserDataNext++;
|
---|
| 4181 | idxUserDataLock %= K_ELEMENTS(pCache->auUserDataLocks);
|
---|
| 4182 | pObj->idxUserDataLock = idxUserDataLock;
|
---|
| 4183 | }
|
---|
| 4184 | KFSCACHE_UNLOCK(pCache);
|
---|
| 4185 | }
|
---|
| 4186 | return idxUserDataLock;
|
---|
| 4187 | }
|
---|
| 4188 |
|
---|
| 4189 | /**
|
---|
[2858] | 4190 | * Gets the full path to @a pObj, ANSI version.
|
---|
| 4191 | *
|
---|
| 4192 | * @returns K_TRUE on success, K_FALSE on buffer overflow (nothing stored).
|
---|
| 4193 | * @param pObj The object to get the full path to.
|
---|
| 4194 | * @param pszPath Where to return the path
|
---|
| 4195 | * @param cbPath The size of the output buffer.
|
---|
| 4196 | * @param chSlash The slash to use.
|
---|
| 4197 | */
|
---|
| 4198 | KBOOL kFsCacheObjGetFullPathA(PKFSOBJ pObj, char *pszPath, KSIZE cbPath, char chSlash)
|
---|
| 4199 | {
|
---|
[3184] | 4200 | /** @todo No way of to do locking here w/o pCache parameter; need to verify
|
---|
| 4201 | * that we're only access static data! */
|
---|
[2858] | 4202 | KSIZE off = pObj->cchParent;
|
---|
| 4203 | kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC);
|
---|
| 4204 | if (off > 0)
|
---|
| 4205 | {
|
---|
| 4206 | KSIZE offEnd = off + pObj->cchName;
|
---|
| 4207 | if (offEnd < cbPath)
|
---|
| 4208 | {
|
---|
| 4209 | PKFSDIR pAncestor;
|
---|
[2856] | 4210 |
|
---|
[2858] | 4211 | pszPath[off + pObj->cchName] = '\0';
|
---|
| 4212 | memcpy(&pszPath[off], pObj->pszName, pObj->cchName);
|
---|
| 4213 |
|
---|
| 4214 | for (pAncestor = pObj->pParent; off > 0; pAncestor = pAncestor->Obj.pParent)
|
---|
| 4215 | {
|
---|
| 4216 | kHlpAssert(off > 1);
|
---|
| 4217 | kHlpAssert(pAncestor != NULL);
|
---|
| 4218 | kHlpAssert(pAncestor->Obj.cchName > 0);
|
---|
| 4219 | pszPath[--off] = chSlash;
|
---|
| 4220 | off -= pAncestor->Obj.cchName;
|
---|
| 4221 | kHlpAssert(pAncestor->Obj.cchParent == off);
|
---|
| 4222 | memcpy(&pszPath[off], pAncestor->Obj.pszName, pAncestor->Obj.cchName);
|
---|
| 4223 | }
|
---|
| 4224 | return K_TRUE;
|
---|
| 4225 | }
|
---|
| 4226 | }
|
---|
| 4227 | else
|
---|
| 4228 | {
|
---|
| 4229 | KBOOL const fDriveLetter = pObj->cchName == 2 && pObj->pszName[2] == ':';
|
---|
| 4230 | off = pObj->cchName;
|
---|
| 4231 | if (off + fDriveLetter < cbPath)
|
---|
| 4232 | {
|
---|
| 4233 | memcpy(pszPath, pObj->pszName, off);
|
---|
| 4234 | if (fDriveLetter)
|
---|
| 4235 | pszPath[off++] = chSlash;
|
---|
| 4236 | pszPath[off] = '\0';
|
---|
| 4237 | return K_TRUE;
|
---|
| 4238 | }
|
---|
| 4239 | }
|
---|
| 4240 |
|
---|
| 4241 | return K_FALSE;
|
---|
| 4242 | }
|
---|
| 4243 |
|
---|
| 4244 |
|
---|
| 4245 | /**
|
---|
| 4246 | * Gets the full path to @a pObj, UTF-16 version.
|
---|
| 4247 | *
|
---|
| 4248 | * @returns K_TRUE on success, K_FALSE on buffer overflow (nothing stored).
|
---|
| 4249 | * @param pObj The object to get the full path to.
|
---|
| 4250 | * @param pszPath Where to return the path
|
---|
| 4251 | * @param cbPath The size of the output buffer.
|
---|
| 4252 | * @param wcSlash The slash to use.
|
---|
| 4253 | */
|
---|
| 4254 | KBOOL kFsCacheObjGetFullPathW(PKFSOBJ pObj, wchar_t *pwszPath, KSIZE cwcPath, wchar_t wcSlash)
|
---|
| 4255 | {
|
---|
[3184] | 4256 | /** @todo No way of to do locking here w/o pCache parameter; need to verify
|
---|
| 4257 | * that we're only access static data! */
|
---|
[2858] | 4258 | KSIZE off = pObj->cwcParent;
|
---|
| 4259 | kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC);
|
---|
| 4260 | if (off > 0)
|
---|
| 4261 | {
|
---|
| 4262 | KSIZE offEnd = off + pObj->cwcName;
|
---|
| 4263 | if (offEnd < cwcPath)
|
---|
| 4264 | {
|
---|
| 4265 | PKFSDIR pAncestor;
|
---|
| 4266 |
|
---|
| 4267 | pwszPath[off + pObj->cwcName] = '\0';
|
---|
| 4268 | memcpy(&pwszPath[off], pObj->pwszName, pObj->cwcName * sizeof(wchar_t));
|
---|
| 4269 |
|
---|
| 4270 | for (pAncestor = pObj->pParent; off > 0; pAncestor = pAncestor->Obj.pParent)
|
---|
| 4271 | {
|
---|
| 4272 | kHlpAssert(off > 1);
|
---|
| 4273 | kHlpAssert(pAncestor != NULL);
|
---|
| 4274 | kHlpAssert(pAncestor->Obj.cwcName > 0);
|
---|
| 4275 | pwszPath[--off] = wcSlash;
|
---|
| 4276 | off -= pAncestor->Obj.cwcName;
|
---|
| 4277 | kHlpAssert(pAncestor->Obj.cwcParent == off);
|
---|
| 4278 | memcpy(&pwszPath[off], pAncestor->Obj.pwszName, pAncestor->Obj.cwcName * sizeof(wchar_t));
|
---|
| 4279 | }
|
---|
| 4280 | return K_TRUE;
|
---|
| 4281 | }
|
---|
| 4282 | }
|
---|
| 4283 | else
|
---|
| 4284 | {
|
---|
| 4285 | KBOOL const fDriveLetter = pObj->cchName == 2 && pObj->pszName[2] == ':';
|
---|
| 4286 | off = pObj->cwcName;
|
---|
| 4287 | if (off + fDriveLetter < cwcPath)
|
---|
| 4288 | {
|
---|
| 4289 | memcpy(pwszPath, pObj->pwszName, off * sizeof(wchar_t));
|
---|
| 4290 | if (fDriveLetter)
|
---|
| 4291 | pwszPath[off++] = wcSlash;
|
---|
| 4292 | pwszPath[off] = '\0';
|
---|
| 4293 | return K_TRUE;
|
---|
| 4294 | }
|
---|
| 4295 | }
|
---|
| 4296 |
|
---|
| 4297 | return K_FALSE;
|
---|
| 4298 | }
|
---|
| 4299 |
|
---|
| 4300 |
|
---|
| 4301 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 4302 |
|
---|
| 4303 | /**
|
---|
| 4304 | * Gets the full short path to @a pObj, ANSI version.
|
---|
| 4305 | *
|
---|
| 4306 | * @returns K_TRUE on success, K_FALSE on buffer overflow (nothing stored).
|
---|
| 4307 | * @param pObj The object to get the full path to.
|
---|
| 4308 | * @param pszPath Where to return the path
|
---|
| 4309 | * @param cbPath The size of the output buffer.
|
---|
| 4310 | * @param chSlash The slash to use.
|
---|
| 4311 | */
|
---|
| 4312 | KBOOL kFsCacheObjGetFullShortPathA(PKFSOBJ pObj, char *pszPath, KSIZE cbPath, char chSlash)
|
---|
| 4313 | {
|
---|
[3184] | 4314 | /** @todo No way of to do locking here w/o pCache parameter; need to verify
|
---|
| 4315 | * that we're only access static data! */
|
---|
[2858] | 4316 | KSIZE off = pObj->cchShortParent;
|
---|
| 4317 | kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC);
|
---|
| 4318 | if (off > 0)
|
---|
| 4319 | {
|
---|
| 4320 | KSIZE offEnd = off + pObj->cchShortName;
|
---|
| 4321 | if (offEnd < cbPath)
|
---|
| 4322 | {
|
---|
| 4323 | PKFSDIR pAncestor;
|
---|
| 4324 |
|
---|
| 4325 | pszPath[off + pObj->cchShortName] = '\0';
|
---|
| 4326 | memcpy(&pszPath[off], pObj->pszShortName, pObj->cchShortName);
|
---|
| 4327 |
|
---|
| 4328 | for (pAncestor = pObj->pParent; off > 0; pAncestor = pAncestor->Obj.pParent)
|
---|
| 4329 | {
|
---|
| 4330 | kHlpAssert(off > 1);
|
---|
| 4331 | kHlpAssert(pAncestor != NULL);
|
---|
| 4332 | kHlpAssert(pAncestor->Obj.cchShortName > 0);
|
---|
| 4333 | pszPath[--off] = chSlash;
|
---|
| 4334 | off -= pAncestor->Obj.cchShortName;
|
---|
| 4335 | kHlpAssert(pAncestor->Obj.cchShortParent == off);
|
---|
| 4336 | memcpy(&pszPath[off], pAncestor->Obj.pszShortName, pAncestor->Obj.cchShortName);
|
---|
| 4337 | }
|
---|
| 4338 | return K_TRUE;
|
---|
| 4339 | }
|
---|
| 4340 | }
|
---|
| 4341 | else
|
---|
| 4342 | {
|
---|
| 4343 | KBOOL const fDriveLetter = pObj->cchShortName == 2 && pObj->pszShortName[2] == ':';
|
---|
| 4344 | off = pObj->cchShortName;
|
---|
| 4345 | if (off + fDriveLetter < cbPath)
|
---|
| 4346 | {
|
---|
| 4347 | memcpy(pszPath, pObj->pszShortName, off);
|
---|
| 4348 | if (fDriveLetter)
|
---|
| 4349 | pszPath[off++] = chSlash;
|
---|
| 4350 | pszPath[off] = '\0';
|
---|
| 4351 | return K_TRUE;
|
---|
| 4352 | }
|
---|
| 4353 | }
|
---|
| 4354 |
|
---|
| 4355 | return K_FALSE;
|
---|
| 4356 | }
|
---|
| 4357 |
|
---|
| 4358 |
|
---|
| 4359 | /**
|
---|
| 4360 | * Gets the full short path to @a pObj, UTF-16 version.
|
---|
| 4361 | *
|
---|
| 4362 | * @returns K_TRUE on success, K_FALSE on buffer overflow (nothing stored).
|
---|
| 4363 | * @param pObj The object to get the full path to.
|
---|
| 4364 | * @param pszPath Where to return the path
|
---|
| 4365 | * @param cbPath The size of the output buffer.
|
---|
| 4366 | * @param wcSlash The slash to use.
|
---|
| 4367 | */
|
---|
| 4368 | KBOOL kFsCacheObjGetFullShortPathW(PKFSOBJ pObj, wchar_t *pwszPath, KSIZE cwcPath, wchar_t wcSlash)
|
---|
| 4369 | {
|
---|
[3184] | 4370 | /** @todo No way of to do locking here w/o pCache parameter; need to verify
|
---|
| 4371 | * that we're only access static data! */
|
---|
[2858] | 4372 | KSIZE off = pObj->cwcShortParent;
|
---|
| 4373 | kHlpAssert(pObj->u32Magic == KFSOBJ_MAGIC);
|
---|
| 4374 | if (off > 0)
|
---|
| 4375 | {
|
---|
| 4376 | KSIZE offEnd = off + pObj->cwcShortName;
|
---|
| 4377 | if (offEnd < cwcPath)
|
---|
| 4378 | {
|
---|
| 4379 | PKFSDIR pAncestor;
|
---|
| 4380 |
|
---|
| 4381 | pwszPath[off + pObj->cwcShortName] = '\0';
|
---|
| 4382 | memcpy(&pwszPath[off], pObj->pwszShortName, pObj->cwcShortName * sizeof(wchar_t));
|
---|
| 4383 |
|
---|
| 4384 | for (pAncestor = pObj->pParent; off > 0; pAncestor = pAncestor->Obj.pParent)
|
---|
| 4385 | {
|
---|
| 4386 | kHlpAssert(off > 1);
|
---|
| 4387 | kHlpAssert(pAncestor != NULL);
|
---|
| 4388 | kHlpAssert(pAncestor->Obj.cwcShortName > 0);
|
---|
| 4389 | pwszPath[--off] = wcSlash;
|
---|
| 4390 | off -= pAncestor->Obj.cwcShortName;
|
---|
| 4391 | kHlpAssert(pAncestor->Obj.cwcShortParent == off);
|
---|
| 4392 | memcpy(&pwszPath[off], pAncestor->Obj.pwszShortName, pAncestor->Obj.cwcShortName * sizeof(wchar_t));
|
---|
| 4393 | }
|
---|
| 4394 | return K_TRUE;
|
---|
| 4395 | }
|
---|
| 4396 | }
|
---|
| 4397 | else
|
---|
| 4398 | {
|
---|
| 4399 | KBOOL const fDriveLetter = pObj->cchShortName == 2 && pObj->pszShortName[2] == ':';
|
---|
| 4400 | off = pObj->cwcShortName;
|
---|
| 4401 | if (off + fDriveLetter < cwcPath)
|
---|
| 4402 | {
|
---|
| 4403 | memcpy(pwszPath, pObj->pwszShortName, off * sizeof(wchar_t));
|
---|
| 4404 | if (fDriveLetter)
|
---|
| 4405 | pwszPath[off++] = wcSlash;
|
---|
| 4406 | pwszPath[off] = '\0';
|
---|
| 4407 | return K_TRUE;
|
---|
| 4408 | }
|
---|
| 4409 | }
|
---|
| 4410 |
|
---|
| 4411 | return K_FALSE;
|
---|
| 4412 | }
|
---|
| 4413 |
|
---|
| 4414 | #endif /* KFSCACHE_CFG_SHORT_NAMES */
|
---|
| 4415 |
|
---|
| 4416 |
|
---|
[2861] | 4417 |
|
---|
[2859] | 4418 | /**
|
---|
[2861] | 4419 | * Read the specified bits from the files into the given buffer, simple version.
|
---|
| 4420 | *
|
---|
| 4421 | * @returns K_TRUE on success (all requested bytes read),
|
---|
| 4422 | * K_FALSE on any kind of failure.
|
---|
| 4423 | *
|
---|
| 4424 | * @param pCache The cache.
|
---|
| 4425 | * @param pFileObj The file object.
|
---|
| 4426 | * @param offStart Where to start reading.
|
---|
| 4427 | * @param pvBuf Where to store what we read.
|
---|
| 4428 | * @param cbToRead How much to read (exact).
|
---|
| 4429 | */
|
---|
| 4430 | KBOOL kFsCacheFileSimpleOpenReadClose(PKFSCACHE pCache, PKFSOBJ pFileObj, KU64 offStart, void *pvBuf, KSIZE cbToRead)
|
---|
| 4431 | {
|
---|
| 4432 | /*
|
---|
| 4433 | * Open the file relative to the parent directory.
|
---|
| 4434 | */
|
---|
| 4435 | MY_NTSTATUS rcNt;
|
---|
| 4436 | HANDLE hFile;
|
---|
| 4437 | MY_IO_STATUS_BLOCK Ios;
|
---|
| 4438 | MY_OBJECT_ATTRIBUTES ObjAttr;
|
---|
| 4439 | MY_UNICODE_STRING UniStr;
|
---|
| 4440 |
|
---|
| 4441 | kHlpAssertReturn(pFileObj->bObjType == KFSOBJ_TYPE_FILE, K_FALSE);
|
---|
| 4442 | kHlpAssert(pFileObj->pParent);
|
---|
| 4443 | kHlpAssertReturn(pFileObj->pParent->hDir != INVALID_HANDLE_VALUE, K_FALSE);
|
---|
| 4444 | kHlpAssertReturn(offStart == 0, K_FALSE); /** @todo when needed */
|
---|
| 4445 |
|
---|
| 4446 | Ios.Information = -1;
|
---|
| 4447 | Ios.u.Status = -1;
|
---|
| 4448 |
|
---|
| 4449 | UniStr.Buffer = (wchar_t *)pFileObj->pwszName;
|
---|
| 4450 | UniStr.Length = (USHORT)(pFileObj->cwcName * sizeof(wchar_t));
|
---|
| 4451 | UniStr.MaximumLength = UniStr.Length + sizeof(wchar_t);
|
---|
| 4452 |
|
---|
[3184] | 4453 | /** @todo potential race against kFsCacheInvalidateDeletedDirectoryA */
|
---|
[2861] | 4454 | MyInitializeObjectAttributes(&ObjAttr, &UniStr, OBJ_CASE_INSENSITIVE, pFileObj->pParent->hDir, NULL /*pSecAttr*/);
|
---|
| 4455 |
|
---|
| 4456 | rcNt = g_pfnNtCreateFile(&hFile,
|
---|
| 4457 | GENERIC_READ | SYNCHRONIZE,
|
---|
| 4458 | &ObjAttr,
|
---|
| 4459 | &Ios,
|
---|
| 4460 | NULL, /*cbFileInitialAlloc */
|
---|
| 4461 | FILE_ATTRIBUTE_NORMAL,
|
---|
| 4462 | FILE_SHARE_READ,
|
---|
| 4463 | FILE_OPEN,
|
---|
| 4464 | FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
|
---|
| 4465 | NULL, /*pEaBuffer*/
|
---|
| 4466 | 0); /*cbEaBuffer*/
|
---|
| 4467 | if (MY_NT_SUCCESS(rcNt))
|
---|
| 4468 | {
|
---|
| 4469 | LARGE_INTEGER offFile;
|
---|
| 4470 | offFile.QuadPart = offStart;
|
---|
| 4471 |
|
---|
| 4472 | Ios.Information = -1;
|
---|
| 4473 | Ios.u.Status = -1;
|
---|
| 4474 | rcNt = g_pfnNtReadFile(hFile, NULL /*hEvent*/, NULL /*pfnApcComplete*/, NULL /*pvApcCtx*/, &Ios,
|
---|
| 4475 | pvBuf, (KU32)cbToRead, !offStart ? &offFile : NULL, NULL /*puKey*/);
|
---|
| 4476 | if (MY_NT_SUCCESS(rcNt))
|
---|
| 4477 | rcNt = Ios.u.Status;
|
---|
| 4478 | if (MY_NT_SUCCESS(rcNt))
|
---|
| 4479 | {
|
---|
| 4480 | if (Ios.Information == cbToRead)
|
---|
| 4481 | {
|
---|
| 4482 | g_pfnNtClose(hFile);
|
---|
| 4483 | return K_TRUE;
|
---|
| 4484 | }
|
---|
| 4485 | KFSCACHE_LOG(("Error reading %#x bytes from '%ls': Information=%p\n", pFileObj->pwszName, Ios.Information));
|
---|
| 4486 | }
|
---|
| 4487 | else
|
---|
| 4488 | KFSCACHE_LOG(("Error reading %#x bytes from '%ls': %#x\n", pFileObj->pwszName, rcNt));
|
---|
| 4489 | g_pfnNtClose(hFile);
|
---|
| 4490 | }
|
---|
| 4491 | else
|
---|
| 4492 | KFSCACHE_LOG(("Error opening '%ls' for caching: %#x\n", pFileObj->pwszName, rcNt));
|
---|
| 4493 | return K_FALSE;
|
---|
| 4494 | }
|
---|
| 4495 |
|
---|
| 4496 |
|
---|
| 4497 | /**
|
---|
[2859] | 4498 | * Invalidate all cache entries of missing files.
|
---|
| 4499 | *
|
---|
| 4500 | * @param pCache The cache.
|
---|
| 4501 | */
|
---|
| 4502 | void kFsCacheInvalidateMissing(PKFSCACHE pCache)
|
---|
| 4503 | {
|
---|
| 4504 | kHlpAssert(pCache->u32Magic == KFSOBJ_MAGIC);
|
---|
[3184] | 4505 | KFSCACHE_LOCK(pCache);
|
---|
| 4506 |
|
---|
[2868] | 4507 | pCache->auGenerationsMissing[0]++;
|
---|
[2859] | 4508 | kHlpAssert(pCache->uGenerationMissing < KU32_MAX);
|
---|
[3184] | 4509 |
|
---|
[2868] | 4510 | KFSCACHE_LOG(("Invalidate missing %#x\n", pCache->auGenerationsMissing[0]));
|
---|
[3184] | 4511 | KFSCACHE_UNLOCK(pCache);
|
---|
[2859] | 4512 | }
|
---|
[2858] | 4513 |
|
---|
[2859] | 4514 |
|
---|
[3359] | 4515 | /**
|
---|
| 4516 | * Recursively close directories.
|
---|
| 4517 | */
|
---|
| 4518 | static void kFsCacheCloseDirs(PKFSOBJ *papChildren, KU32 cChildren)
|
---|
| 4519 | {
|
---|
| 4520 | while (cChildren-- > 0)
|
---|
| 4521 | {
|
---|
| 4522 | PKFSDIR pDir = (PKFSDIR)papChildren[cChildren];
|
---|
| 4523 | if (pDir && pDir->Obj.bObjType == KFSOBJ_TYPE_DIR)
|
---|
| 4524 | {
|
---|
| 4525 | if (pDir->hDir != INVALID_HANDLE_VALUE)
|
---|
| 4526 | {
|
---|
| 4527 | g_pfnNtClose(pDir->hDir);
|
---|
| 4528 | pDir->hDir = INVALID_HANDLE_VALUE;
|
---|
| 4529 | }
|
---|
| 4530 | kFsCacheCloseDirs(pDir->papChildren, pDir->cChildren);
|
---|
| 4531 | }
|
---|
| 4532 | }
|
---|
| 4533 | }
|
---|
| 4534 |
|
---|
| 4535 |
|
---|
[2859] | 4536 | /**
|
---|
[3359] | 4537 | * Worker for kFsCacheInvalidateAll and kFsCacheInvalidateAllAndCloseDirs
|
---|
[2859] | 4538 | */
|
---|
[3359] | 4539 | static void kFsCacheInvalidateAllWorker(PKFSCACHE pCache, KBOOL fCloseDirs, KBOOL fIncludingRoot)
|
---|
[2859] | 4540 | {
|
---|
| 4541 | kHlpAssert(pCache->u32Magic == KFSOBJ_MAGIC);
|
---|
[3184] | 4542 | KFSCACHE_LOCK(pCache);
|
---|
[2862] | 4543 |
|
---|
[2868] | 4544 | pCache->auGenerationsMissing[0]++;
|
---|
| 4545 | kHlpAssert(pCache->auGenerationsMissing[0] < KU32_MAX);
|
---|
| 4546 | pCache->auGenerationsMissing[1]++;
|
---|
| 4547 | kHlpAssert(pCache->auGenerationsMissing[1] < KU32_MAX);
|
---|
| 4548 |
|
---|
| 4549 | pCache->auGenerations[0]++;
|
---|
| 4550 | kHlpAssert(pCache->auGenerations[0] < KU32_MAX);
|
---|
| 4551 | pCache->auGenerations[1]++;
|
---|
| 4552 | kHlpAssert(pCache->auGenerations[1] < KU32_MAX);
|
---|
| 4553 |
|
---|
[3359] | 4554 | if (fCloseDirs)
|
---|
| 4555 | {
|
---|
| 4556 | kFsCacheCloseDirs(pCache->RootDir.papChildren, pCache->RootDir.cChildren);
|
---|
| 4557 | if (fCloseDirs && pCache->RootDir.hDir != INVALID_HANDLE_VALUE)
|
---|
| 4558 | {
|
---|
| 4559 | g_pfnNtClose(pCache->RootDir.hDir);
|
---|
| 4560 | pCache->RootDir.hDir = INVALID_HANDLE_VALUE;
|
---|
| 4561 | }
|
---|
| 4562 | }
|
---|
| 4563 |
|
---|
[2868] | 4564 | KFSCACHE_LOG(("Invalidate all - default: %#x/%#x, custom: %#x/%#x\n",
|
---|
| 4565 | pCache->auGenerationsMissing[0], pCache->auGenerations[0],
|
---|
| 4566 | pCache->auGenerationsMissing[1], pCache->auGenerations[1]));
|
---|
[3184] | 4567 | KFSCACHE_UNLOCK(pCache);
|
---|
[2859] | 4568 | }
|
---|
| 4569 |
|
---|
| 4570 |
|
---|
[2868] | 4571 | /**
|
---|
[3359] | 4572 | * Invalidate all cache entries (regular, custom & missing).
|
---|
| 4573 | *
|
---|
| 4574 | * @param pCache The cache.
|
---|
| 4575 | */
|
---|
| 4576 | void kFsCacheInvalidateAll(PKFSCACHE pCache)
|
---|
| 4577 | {
|
---|
| 4578 | kHlpAssert(pCache->u32Magic == KFSOBJ_MAGIC);
|
---|
| 4579 | kFsCacheInvalidateAllWorker(pCache, K_FALSE, K_FALSE);
|
---|
| 4580 | }
|
---|
| 4581 |
|
---|
| 4582 |
|
---|
| 4583 | /**
|
---|
| 4584 | * Invalidate all cache entries (regular, custom & missing) and close all the
|
---|
| 4585 | * directory handles.
|
---|
| 4586 | *
|
---|
| 4587 | * @param pCache The cache.
|
---|
| 4588 | * @param fIncludingRoot Close the root directory handle too.
|
---|
| 4589 | */
|
---|
| 4590 | void kFsCacheInvalidateAllAndCloseDirs(PKFSCACHE pCache, KBOOL fIncludingRoot)
|
---|
| 4591 | {
|
---|
| 4592 | kHlpAssert(pCache->u32Magic == KFSOBJ_MAGIC);
|
---|
| 4593 | kFsCacheInvalidateAllWorker(pCache, K_TRUE, fIncludingRoot);
|
---|
| 4594 | }
|
---|
| 4595 |
|
---|
| 4596 |
|
---|
| 4597 | /**
|
---|
[2868] | 4598 | * Invalidate all cache entries with custom generation handling set.
|
---|
| 4599 | *
|
---|
| 4600 | * @see kFsCacheSetupCustomRevisionForTree, KFSOBJ_F_USE_CUSTOM_GEN
|
---|
| 4601 | * @param pCache The cache.
|
---|
| 4602 | */
|
---|
| 4603 | void kFsCacheInvalidateCustomMissing(PKFSCACHE pCache)
|
---|
| 4604 | {
|
---|
| 4605 | kHlpAssert(pCache->u32Magic == KFSOBJ_MAGIC);
|
---|
[3184] | 4606 | KFSCACHE_LOCK(pCache);
|
---|
| 4607 |
|
---|
[2868] | 4608 | pCache->auGenerationsMissing[1]++;
|
---|
| 4609 | kHlpAssert(pCache->auGenerationsMissing[1] < KU32_MAX);
|
---|
[3184] | 4610 |
|
---|
[2868] | 4611 | KFSCACHE_LOG(("Invalidate missing custom %#x\n", pCache->auGenerationsMissing[1]));
|
---|
[3184] | 4612 | KFSCACHE_UNLOCK(pCache);
|
---|
[2868] | 4613 | }
|
---|
[2859] | 4614 |
|
---|
[2868] | 4615 |
|
---|
| 4616 | /**
|
---|
| 4617 | * Invalidate all cache entries with custom generation handling set, both
|
---|
| 4618 | * missing and regular present entries.
|
---|
| 4619 | *
|
---|
| 4620 | * @see kFsCacheSetupCustomRevisionForTree, KFSOBJ_F_USE_CUSTOM_GEN
|
---|
| 4621 | * @param pCache The cache.
|
---|
| 4622 | */
|
---|
| 4623 | void kFsCacheInvalidateCustomBoth(PKFSCACHE pCache)
|
---|
| 4624 | {
|
---|
| 4625 | kHlpAssert(pCache->u32Magic == KFSOBJ_MAGIC);
|
---|
[3184] | 4626 | KFSCACHE_LOCK(pCache);
|
---|
| 4627 |
|
---|
[2868] | 4628 | pCache->auGenerations[1]++;
|
---|
| 4629 | kHlpAssert(pCache->auGenerations[1] < KU32_MAX);
|
---|
| 4630 | pCache->auGenerationsMissing[1]++;
|
---|
| 4631 | kHlpAssert(pCache->auGenerationsMissing[1] < KU32_MAX);
|
---|
[3184] | 4632 |
|
---|
[2868] | 4633 | KFSCACHE_LOG(("Invalidate both custom %#x/%#x\n", pCache->auGenerationsMissing[1], pCache->auGenerations[1]));
|
---|
[3184] | 4634 | KFSCACHE_UNLOCK(pCache);
|
---|
[2868] | 4635 | }
|
---|
| 4636 |
|
---|
| 4637 |
|
---|
| 4638 |
|
---|
| 4639 | /**
|
---|
| 4640 | * Applies the given flags to all the objects in a tree.
|
---|
| 4641 | *
|
---|
| 4642 | * @param pRoot Where to start applying the flag changes.
|
---|
| 4643 | * @param fAndMask The AND mask.
|
---|
| 4644 | * @param fOrMask The OR mask.
|
---|
| 4645 | */
|
---|
| 4646 | static void kFsCacheApplyFlagsToTree(PKFSDIR pRoot, KU32 fAndMask, KU32 fOrMask)
|
---|
| 4647 | {
|
---|
| 4648 | PKFSOBJ *ppCur = ((PKFSDIR)pRoot)->papChildren;
|
---|
| 4649 | KU32 cLeft = ((PKFSDIR)pRoot)->cChildren;
|
---|
| 4650 | while (cLeft-- > 0)
|
---|
| 4651 | {
|
---|
| 4652 | PKFSOBJ pCur = *ppCur++;
|
---|
| 4653 | if (pCur->bObjType != KFSOBJ_TYPE_DIR)
|
---|
| 4654 | pCur->fFlags = (fAndMask & pCur->fFlags) | fOrMask;
|
---|
| 4655 | else
|
---|
| 4656 | kFsCacheApplyFlagsToTree((PKFSDIR)pCur, fAndMask, fOrMask);
|
---|
| 4657 | }
|
---|
| 4658 |
|
---|
| 4659 | pRoot->Obj.fFlags = (fAndMask & pRoot->Obj.fFlags) | fOrMask;
|
---|
| 4660 | }
|
---|
| 4661 |
|
---|
| 4662 |
|
---|
| 4663 | /**
|
---|
| 4664 | * Sets up using custom revisioning for the specified directory tree or file.
|
---|
| 4665 | *
|
---|
| 4666 | * There are some restrictions of the current implementation:
|
---|
| 4667 | * - If the root of the sub-tree is ever deleted from the cache (i.e.
|
---|
| 4668 | * deleted in real life and reflected in the cache), the setting is lost.
|
---|
| 4669 | * - It is not automatically applied to the lookup paths caches.
|
---|
| 4670 | *
|
---|
| 4671 | * @returns K_TRUE on success, K_FALSE on failure.
|
---|
| 4672 | * @param pCache The cache.
|
---|
| 4673 | * @param pRoot The root of the subtree. A non-directory is
|
---|
| 4674 | * fine, like a missing node.
|
---|
| 4675 | */
|
---|
| 4676 | KBOOL kFsCacheSetupCustomRevisionForTree(PKFSCACHE pCache, PKFSOBJ pRoot)
|
---|
| 4677 | {
|
---|
| 4678 | if (pRoot)
|
---|
| 4679 | {
|
---|
[3184] | 4680 | KFSCACHE_LOCK(pCache);
|
---|
[2868] | 4681 | if (pRoot->bObjType == KFSOBJ_TYPE_DIR)
|
---|
| 4682 | kFsCacheApplyFlagsToTree((PKFSDIR)pRoot, KU32_MAX, KFSOBJ_F_USE_CUSTOM_GEN);
|
---|
| 4683 | else
|
---|
| 4684 | pRoot->fFlags |= KFSOBJ_F_USE_CUSTOM_GEN;
|
---|
[3184] | 4685 | KFSCACHE_UNLOCK(pCache);
|
---|
[2868] | 4686 | return K_TRUE;
|
---|
| 4687 | }
|
---|
| 4688 | return K_FALSE;
|
---|
| 4689 | }
|
---|
| 4690 |
|
---|
| 4691 |
|
---|
[2912] | 4692 | /**
|
---|
| 4693 | * Invalidates a deleted directory, ANSI version.
|
---|
| 4694 | *
|
---|
| 4695 | * @returns K_TRUE if found and is a non-root directory. Otherwise K_FALSE.
|
---|
| 4696 | * @param pCache The cache.
|
---|
| 4697 | * @param pszDir The directory.
|
---|
| 4698 | */
|
---|
| 4699 | KBOOL kFsCacheInvalidateDeletedDirectoryA(PKFSCACHE pCache, const char *pszDir)
|
---|
| 4700 | {
|
---|
| 4701 | KU32 cchDir = (KU32)kHlpStrLen(pszDir);
|
---|
| 4702 | KFSLOOKUPERROR enmError;
|
---|
| 4703 | PKFSOBJ pFsObj;
|
---|
| 4704 |
|
---|
[3184] | 4705 | KFSCACHE_LOCK(pCache);
|
---|
| 4706 |
|
---|
[2912] | 4707 | /* Is absolute without any '..' bits? */
|
---|
| 4708 | if ( cchDir >= 3
|
---|
| 4709 | && ( ( pszDir[1] == ':' /* Drive letter */
|
---|
| 4710 | && IS_SLASH(pszDir[2])
|
---|
| 4711 | && IS_ALPHA(pszDir[0]) )
|
---|
| 4712 | || ( IS_SLASH(pszDir[0]) /* UNC */
|
---|
| 4713 | && IS_SLASH(pszDir[1]) ) )
|
---|
| 4714 | && !kFsCacheHasDotDotA(pszDir, cchDir) )
|
---|
| 4715 | pFsObj = kFsCacheLookupAbsoluteA(pCache, pszDir, cchDir, KFSCACHE_LOOKUP_F_NO_INSERT | KFSCACHE_LOOKUP_F_NO_REFRESH,
|
---|
| 4716 | &enmError, NULL);
|
---|
| 4717 | else
|
---|
| 4718 | pFsObj = kFsCacheLookupSlowA(pCache, pszDir, cchDir, KFSCACHE_LOOKUP_F_NO_INSERT | KFSCACHE_LOOKUP_F_NO_REFRESH,
|
---|
| 4719 | &enmError, NULL);
|
---|
| 4720 | if (pFsObj)
|
---|
| 4721 | {
|
---|
| 4722 | /* Is directory? */
|
---|
| 4723 | if (pFsObj->bObjType == KFSOBJ_TYPE_DIR)
|
---|
| 4724 | {
|
---|
| 4725 | if (pFsObj->pParent != &pCache->RootDir)
|
---|
| 4726 | {
|
---|
| 4727 | PKFSDIR pDir = (PKFSDIR)pFsObj;
|
---|
| 4728 | KFSCACHE_LOG(("kFsCacheInvalidateDeletedDirectoryA: %s hDir=%p\n", pszDir, pDir->hDir));
|
---|
| 4729 | if (pDir->hDir != INVALID_HANDLE_VALUE)
|
---|
| 4730 | {
|
---|
| 4731 | g_pfnNtClose(pDir->hDir);
|
---|
| 4732 | pDir->hDir = INVALID_HANDLE_VALUE;
|
---|
| 4733 | }
|
---|
| 4734 | pDir->fNeedRePopulating = K_TRUE;
|
---|
| 4735 | pDir->Obj.uCacheGen = pCache->auGenerations[pDir->Obj.fFlags & KFSOBJ_F_USE_CUSTOM_GEN] - 1;
|
---|
[3184] | 4736 | kFsCacheObjRelease(pCache, &pDir->Obj);
|
---|
| 4737 | KFSCACHE_UNLOCK(pCache);
|
---|
[2912] | 4738 | return K_TRUE;
|
---|
| 4739 | }
|
---|
| 4740 | KFSCACHE_LOG(("kFsCacheInvalidateDeletedDirectoryA: Trying to invalidate a root directory was deleted! %s\n", pszDir));
|
---|
| 4741 | }
|
---|
| 4742 | else
|
---|
| 4743 | KFSCACHE_LOG(("kFsCacheInvalidateDeletedDirectoryA: Trying to invalidate a non-directory: bObjType=%d %s\n",
|
---|
| 4744 | pFsObj->bObjType, pszDir));
|
---|
[3184] | 4745 | kFsCacheObjRelease(pCache, pFsObj);
|
---|
[2912] | 4746 | }
|
---|
| 4747 | else
|
---|
| 4748 | KFSCACHE_LOG(("kFsCacheInvalidateDeletedDirectoryA: '%s' was not found\n", pszDir));
|
---|
[3184] | 4749 | KFSCACHE_UNLOCK(pCache);
|
---|
[2912] | 4750 | return K_FALSE;
|
---|
| 4751 | }
|
---|
| 4752 |
|
---|
| 4753 |
|
---|
[2851] | 4754 | PKFSCACHE kFsCacheCreate(KU32 fFlags)
|
---|
[2831] | 4755 | {
|
---|
[2851] | 4756 | PKFSCACHE pCache;
|
---|
| 4757 | birdResolveImports();
|
---|
[2844] | 4758 |
|
---|
[2851] | 4759 | pCache = (PKFSCACHE)kHlpAllocZ(sizeof(*pCache));
|
---|
| 4760 | if (pCache)
|
---|
| 4761 | {
|
---|
| 4762 | /* Dummy root dir entry. */
|
---|
| 4763 | pCache->RootDir.Obj.u32Magic = KFSOBJ_MAGIC;
|
---|
| 4764 | pCache->RootDir.Obj.cRefs = 1;
|
---|
[2853] | 4765 | pCache->RootDir.Obj.uCacheGen = KFSOBJ_CACHE_GEN_IGNORE;
|
---|
[2851] | 4766 | pCache->RootDir.Obj.bObjType = KFSOBJ_TYPE_DIR;
|
---|
| 4767 | pCache->RootDir.Obj.fHaveStats = K_FALSE;
|
---|
| 4768 | pCache->RootDir.Obj.pParent = NULL;
|
---|
| 4769 | pCache->RootDir.Obj.pszName = "";
|
---|
| 4770 | pCache->RootDir.Obj.cchName = 0;
|
---|
| 4771 | pCache->RootDir.Obj.cchParent = 0;
|
---|
| 4772 | #ifdef KFSCACHE_CFG_UTF16
|
---|
| 4773 | pCache->RootDir.Obj.cwcName = 0;
|
---|
| 4774 | pCache->RootDir.Obj.cwcParent = 0;
|
---|
| 4775 | pCache->RootDir.Obj.pwszName = L"";
|
---|
| 4776 | #endif
|
---|
[2846] | 4777 |
|
---|
[2851] | 4778 | #ifdef KFSCACHE_CFG_SHORT_NAMES
|
---|
| 4779 | pCache->RootDir.Obj.pszShortName = NULL;
|
---|
| 4780 | pCache->RootDir.Obj.cchShortName = 0;
|
---|
| 4781 | pCache->RootDir.Obj.cchShortParent = 0;
|
---|
| 4782 | # ifdef KFSCACHE_CFG_UTF16
|
---|
| 4783 | pCache->RootDir.Obj.cwcShortName;
|
---|
| 4784 | pCache->RootDir.Obj.cwcShortParent;
|
---|
| 4785 | pCache->RootDir.Obj.pwszShortName;
|
---|
| 4786 | # endif
|
---|
| 4787 | #endif
|
---|
| 4788 | pCache->RootDir.cChildren = 0;
|
---|
[2863] | 4789 | pCache->RootDir.cChildrenAllocated = 0;
|
---|
[2851] | 4790 | pCache->RootDir.papChildren = NULL;
|
---|
| 4791 | pCache->RootDir.hDir = INVALID_HANDLE_VALUE;
|
---|
[2930] | 4792 | pCache->RootDir.fHashTabMask = 255; /* 256: 26 drive letters and 102 UNCs before we're half ways. */
|
---|
| 4793 | pCache->RootDir.papHashTab = (PKFSOBJ *)kHlpAllocZ(256 * sizeof(pCache->RootDir.papHashTab[0]));
|
---|
| 4794 | if (pCache->RootDir.papHashTab)
|
---|
[2844] | 4795 | {
|
---|
[2851] | 4796 | /* The cache itself. */
|
---|
[2930] | 4797 | pCache->u32Magic = KFSCACHE_MAGIC;
|
---|
| 4798 | pCache->fFlags = fFlags;
|
---|
[2868] | 4799 | pCache->auGenerations[0] = KU32_MAX / 4;
|
---|
| 4800 | pCache->auGenerations[1] = KU32_MAX / 32;
|
---|
| 4801 | pCache->auGenerationsMissing[0] = KU32_MAX / 256;
|
---|
| 4802 | pCache->auGenerationsMissing[1] = 1;
|
---|
[2930] | 4803 | pCache->cObjects = 1;
|
---|
| 4804 | pCache->cbObjects = sizeof(pCache->RootDir)
|
---|
| 4805 | + (pCache->RootDir.fHashTabMask + 1) * sizeof(pCache->RootDir.papHashTab[0]);
|
---|
| 4806 | pCache->cPathHashHits = 0;
|
---|
| 4807 | pCache->cWalkHits = 0;
|
---|
| 4808 | pCache->cChildSearches = 0;
|
---|
| 4809 | pCache->cChildHashHits = 0;
|
---|
| 4810 | pCache->cChildHashed = 0;
|
---|
| 4811 | pCache->cChildHashTabs = 1;
|
---|
| 4812 | pCache->cChildHashEntriesTotal = pCache->RootDir.fHashTabMask + 1;
|
---|
| 4813 | pCache->cChildHashCollisions = 0;
|
---|
[2967] | 4814 | pCache->cNameChanges = 0;
|
---|
| 4815 | pCache->cNameGrowths = 0;
|
---|
[2930] | 4816 | pCache->cAnsiPaths = 0;
|
---|
| 4817 | pCache->cAnsiPathCollisions = 0;
|
---|
| 4818 | pCache->cbAnsiPaths = 0;
|
---|
[2851] | 4819 | #ifdef KFSCACHE_CFG_UTF16
|
---|
[2930] | 4820 | pCache->cUtf16Paths = 0;
|
---|
| 4821 | pCache->cUtf16PathCollisions = 0;
|
---|
| 4822 | pCache->cbUtf16Paths = 0;
|
---|
[2851] | 4823 | #endif
|
---|
[3184] | 4824 |
|
---|
| 4825 | #ifdef KFSCACHE_CFG_LOCKING
|
---|
[3362] | 4826 | {
|
---|
| 4827 | KSIZE idx = K_ELEMENTS(pCache->auUserDataLocks);
|
---|
| 4828 | while (idx-- > 0)
|
---|
| 4829 | InitializeCriticalSection(&pCache->auUserDataLocks[idx].CritSect);
|
---|
| 4830 | InitializeCriticalSection(&pCache->u.CritSect);
|
---|
| 4831 | }
|
---|
[3184] | 4832 | #endif
|
---|
[2851] | 4833 | return pCache;
|
---|
[2844] | 4834 | }
|
---|
| 4835 |
|
---|
[2851] | 4836 | kHlpFree(pCache);
|
---|
[2844] | 4837 | }
|
---|
[2851] | 4838 | return NULL;
|
---|
[2831] | 4839 | }
|
---|
| 4840 |
|
---|