Changeset 2853 for trunk/src/lib/nt


Ignore:
Timestamp:
Aug 31, 2016, 10:56:48 PM (9 years ago)
Author:
bird
Message:

updates

Location:
trunk/src/lib/nt
Files:
1 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/lib/nt/kFsCache.h

    r2852 r2853  
    11/* $Id$ */
    22/** @file
    3  * ntdircache.c - NT directory content cache.
     3 * kFsCache.c - NT directory content cache.
    44 */
    55
     
    2929 */
    3030
    31 
    32 /*********************************************************************************************************************************
    33 *   Header Files                                                                                                                 *
    34 *********************************************************************************************************************************/
     31#ifndef ___lib_nt_kFsCache_h___
     32#define ___lib_nt_kFsCache_h___
     33
     34
    3535#include <k/kHlp.h>
    36 
    37 #include "nthlp.h"
    3836#include "ntstat.h"
    39 
    40 #include <stdio.h>
    41 #include <mbstring.h>
    42 #include <wchar.h>
    43 //#include <intrin.h>
    44 //#include <setjmp.h>
    45 //#include <ctype.h>
    46 
    47 
    48 //#include <Windows.h>
    49 //#include <winternl.h>
    50 
    51 
    52 
    53 /*********************************************************************************************************************************
    54 *   Defined Constants And Macros                                                                                                 *
    55 *********************************************************************************************************************************/
     37#ifndef NDEBUG
     38# include <stdarg.h>
     39#endif
     40
     41
    5642/** @def KFSCACHE_CFG_UTF16
    5743 * Whether to compile in the UTF-16 names support. */
     
    7359
    7460/** Special KFSOBJ::uCacheGen number indicating that it does not apply. */
    75 #define KFSWOBJ_CACHE_GEN_IGNORE            KU32_MAX
    76 
    77 /** @def KW_LOG
    78  * Generic logging.
    79  * @param a     Argument list for kFsCacheDbgPrintf  */
    80 #ifndef NDEBUG
    81 # define KFSCACHE_LOG(a) kFsCacheDbgPrintf a
    82 #else
    83 # define KFSCACHE_LOG(a) do { } while (0)
    84 #endif
     61#define KFSOBJ_CACHE_GEN_IGNORE             KU32_MAX
    8562
    8663
     
    11693
    11794
    118 /*********************************************************************************************************************************
    119 *   Structures and Typedefs                                                                                                      *
    120 *********************************************************************************************************************************/
     95
     96
    12197/** Pointer to a core object.  */
    12298typedef struct KFSOBJ *PKFSOBJ;
     
    151127    /** Number of references. */
    152128    KU32 volatile       cRefs;
    153     /** The cache generation, see KFSWOBJ_CACHE_GEN_IGNORE. */
     129    /** The cache generation, see KFSOBJ_CACHE_GEN_IGNORE. */
    154130    KU32                uCacheGen;
    155131    /** The object type, KFSOBJ_TYPE_XXX.   */
     
    397373
    398374
    399 /*********************************************************************************************************************************
    400 *   Internal Functions                                                                                                           *
    401 *********************************************************************************************************************************/
    402 KU32 kFsCacheObjRelease(PKFSCACHE pCache, PKFSOBJ pObj);
    403 
    404 
    405 /**
    406  * Retains a reference to a cache object, internal version.
    407  *
    408  * @returns pObj
    409  * @param   pObj                The object.
    410  */
    411 K_INLINE PKFSOBJ kFsCacheObjRetainInternal(PKFSOBJ pObj)
    412 {
    413     KU32 cRefs = ++pObj->cRefs;
    414     kHlpAssert(cRefs < 16384);
    415     K_NOREF(cRefs);
    416     return pObj;
    417 }
    418 
    419 
    420 #ifndef NDEBUG
    421 
    422 /**
    423  * Debug printing.
    424  * @param   pszFormat           Debug format string.
    425  * @param   ...                 Format argument.
    426  */
    427 static void kFsCacheDbgPrintfV(const char *pszFormat, va_list va)
    428 {
    429     if (1)
    430     {
    431         DWORD const dwSavedErr = GetLastError();
    432 
    433         fprintf(stderr, "debug: ");
    434         vfprintf(stderr, pszFormat, va);
    435 
    436         SetLastError(dwSavedErr);
    437     }
    438 }
    439 
    440 
    441 /**
    442  * Debug printing.
    443  * @param   pszFormat           Debug format string.
    444  * @param   ...                 Format argument.
    445  */
    446 static void kFsCacheDbgPrintf(const char *pszFormat, ...)
    447 {
    448     if (1)
    449     {
    450         va_list va;
    451         va_start(va, pszFormat);
    452         kFsCacheDbgPrintfV(pszFormat, va);
    453         va_end(va);
    454     }
    455 }
    456 
    457 #endif /* !NDEBUG */
    458 
    459 
    460 
    461 /**
    462  * Hashes a string.
    463  *
    464  * @returns 32-bit string hash.
    465  * @param   pszString           String to hash.
    466  */
    467 static KU32 kFsCacheStrHash(const char *pszString)
    468 {
    469     /* This algorithm was created for sdbm (a public-domain reimplementation of
    470        ndbm) database library. it was found to do well in scrambling bits,
    471        causing better distribution of the keys and fewer splits. it also happens
    472        to be a good general hashing function with good distribution. the actual
    473        function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
    474        is the faster version used in gawk. [there is even a faster, duff-device
    475        version] the magic constant 65599 was picked out of thin air while
    476        experimenting with different constants, and turns out to be a prime.
    477        this is one of the algorithms used in berkeley db (see sleepycat) and
    478        elsewhere. */
    479     KU32 uHash = 0;
    480     KU32 uChar;
    481     while ((uChar = (unsigned char)*pszString++) != 0)
    482         uHash = uChar + (uHash << 6) + (uHash << 16) - uHash;
    483     return uHash;
    484 }
    485 
    486 
    487 /**
    488  * Hashes a string.
    489  *
    490  * @returns The string length.
    491  * @param   pszString           String to hash.
    492  * @param   puHash              Where to return the 32-bit string hash.
    493  */
    494 static KSIZE kFsCacheStrHashEx(const char *pszString, KU32 *puHash)
    495 {
    496     const char * const pszStart = pszString;
    497     KU32 uHash = 0;
    498     KU32 uChar;
    499     while ((uChar = (unsigned char)*pszString) != 0)
    500     {
    501         uHash = uChar + (uHash << 6) + (uHash << 16) - uHash;
    502         pszString++;
    503     }
    504     *puHash = uHash;
    505     return pszString - pszStart;
    506 }
    507 
    508 
    509 /**
    510  * Hashes a string.
    511  *
    512  * @returns The string length in wchar_t units.
    513  * @param   pwszString          String to hash.
    514  * @param   puHash              Where to return the 32-bit string hash.
    515  */
    516 static KSIZE kFsCacheUtf16HashEx(const wchar_t *pwszString, KU32 *puHash)
    517 {
    518     const wchar_t * const pwszStart = pwszString;
    519     KU32 uHash = 0;
    520     KU32 uChar;
    521     while ((uChar = *pwszString) != 0)
    522     {
    523         uHash = uChar + (uHash << 6) + (uHash << 16) - uHash;
    524         pwszString++;
    525     }
    526     *puHash = uHash;
    527     return pwszString - pwszStart;
    528 }
    529 
    530 #if 0
    531 
    532 /**
    533  * Converts the given string to unicode.
    534  *
    535  * @returns Length of the resulting string in wchar_t's.
    536  * @param   pszSrc              The source string.
    537  * @param   pwszDst             The destination buffer.
    538  * @param   cwcDst              The size of the destination buffer in wchar_t's.
    539  */
    540 static KSIZE kwStrToUtf16(const char *pszSrc, wchar_t *pwszDst, KSIZE cwcDst)
    541 {
    542     /* Just to the quick ASCII stuff for now. correct ansi code page stuff later some time.  */
    543     KSIZE offDst = 0;
    544     while (offDst < cwcDst)
    545     {
    546         char ch = *pszSrc++;
    547         pwszDst[offDst++] = ch;
    548         if (!ch)
    549             return offDst - 1;
    550         kHlpAssert((unsigned)ch < 127);
    551     }
    552 
    553     pwszDst[offDst - 1] = '\0';
    554     return offDst;
    555 }
    556 
    557 
    558 /**
    559  * Converts the given UTF-16 to a normal string.
    560  *
    561  * @returns Length of the resulting string.
    562  * @param   pwszSrc             The source UTF-16 string.
    563  * @param   pszDst              The destination buffer.
    564  * @param   cbDst               The size of the destination buffer in bytes.
    565  */
    566 static KSIZE kwUtf16ToStr(const wchar_t *pwszSrc, char *pszDst, KSIZE cbDst)
    567 {
    568     /* Just to the quick ASCII stuff for now. correct ansi code page stuff later some time.  */
    569     KSIZE offDst = 0;
    570     while (offDst < cbDst)
    571     {
    572         wchar_t wc = *pwszSrc++;
    573         pszDst[offDst++] = (char)wc;
    574         if (!wc)
    575             return offDst - 1;
    576         kHlpAssert((unsigned)wc < 127);
    577     }
    578 
    579     pszDst[offDst - 1] = '\0';
    580     return offDst;
    581 }
    582 
    583 
    584 
    585 /** UTF-16 string length.  */
    586 static KSIZE kwUtf16Len(wchar_t const *pwsz)
    587 {
    588     KSIZE cwc = 0;
    589     while (*pwsz != '\0')
    590         cwc++, pwsz++;
    591     return cwc;
    592 }
    593 
    594 /**
    595  * Copy out the UTF-16 string following the convension of GetModuleFileName
    596  */
    597 static DWORD kwUtf16CopyStyle1(wchar_t const *pwszSrc, wchar_t *pwszDst, KSIZE cwcDst)
    598 {
    599     KSIZE cwcSrc = kwUtf16Len(pwszSrc);
    600     if (cwcSrc + 1 <= cwcDst)
    601     {
    602         kHlpMemCopy(pwszDst, pwszSrc, (cwcSrc + 1) * sizeof(wchar_t));
    603         return (DWORD)cwcSrc;
    604     }
    605     if (cwcDst > 0)
    606     {
    607         KSIZE cwcDstTmp = cwcDst - 1;
    608         pwszDst[cwcDstTmp] = '\0';
    609         if (cwcDstTmp > 0)
    610             kHlpMemCopy(pwszDst, pwszSrc, cwcDstTmp);
    611     }
    612     SetLastError(ERROR_INSUFFICIENT_BUFFER);
    613     return (DWORD)cwcDst;
    614 }
    615 
    616 
    617 /**
    618  * Copy out the ANSI string following the convension of GetModuleFileName
    619  */
    620 static DWORD kwStrCopyStyle1(char const *pszSrc, char *pszDst, KSIZE cbDst)
    621 {
    622     KSIZE cchSrc = kHlpStrLen(pszSrc);
    623     if (cchSrc + 1 <= cbDst)
    624     {
    625         kHlpMemCopy(pszDst, pszSrc, cchSrc + 1);
    626         return (DWORD)cchSrc;
    627     }
    628     if (cbDst > 0)
    629     {
    630         KSIZE cbDstTmp = cbDst - 1;
    631         pszDst[cbDstTmp] = '\0';
    632         if (cbDstTmp > 0)
    633             kHlpMemCopy(pszDst, pszSrc, cbDstTmp);
    634     }
    635     SetLastError(ERROR_INSUFFICIENT_BUFFER);
    636     return (DWORD)cbDst;
    637 }
    638 
    639 
    640 /**
    641  * Normalizes the path so we get a consistent hash.
    642  *
    643  * @returns status code.
    644  * @param   pszPath             The path.
    645  * @param   pszNormPath         The output buffer.
    646  * @param   cbNormPath          The size of the output buffer.
    647  */
    648 static int kwPathNormalize(const char *pszPath, char *pszNormPath, KSIZE cbNormPath)
    649 {
    650     char           *pchSlash;
    651     KSIZE           cchNormPath;
    652 
    653     /*
    654      * We hash these to speed stuff up (nt_fullpath isn't cheap and we're
    655      * gonna have many repeat queries and assume nobody do case changes to
    656      * anything essential while kmk is running).
    657      */
    658     KU32            uHashPath;
    659     KU32            cchPath    = (KU32)kFsCacheStrHashEx(pszPath, &uHashPath);
    660     KU32 const      idxHashTab = uHashPath % K_ELEMENTS(g_apFsNormalizedPathsA);
    661     PKFSNORMHASHA  pHashEntry = g_apFsNormalizedPathsA[idxHashTab];
    662     if (pHashEntry)
    663     {
    664         do
    665         {
    666             if (   pHashEntry->uHashPath == uHashPath
    667                 && pHashEntry->cchPath   == cchPath
    668                 && kHlpMemComp(pHashEntry->pszPath, pszPath, cchPath) == 0)
    669             {
    670                 if (cbNormPath > pHashEntry->cchNormPath)
    671                 {
    672                     KFSCACHE_LOG(("kwPathNormalize(%s) - hit\n", pszPath));
    673                     kHlpMemCopy(pszNormPath, pHashEntry->szNormPath, pHashEntry->cchNormPath + 1);
    674                     return 0;
    675                 }
    676                 return KERR_BUFFER_OVERFLOW;
    677             }
    678             pHashEntry = pHashEntry->pNext;
    679         } while (pHashEntry);
    680     }
    681 
    682     /*
    683      * Do it the slow way.
    684      */
    685     nt_fullpath(pszPath, pszNormPath, cbNormPath);
    686     /** @todo nt_fullpath overflow handling?!?!?   */
    687 
    688     pchSlash = kHlpStrChr(pszNormPath, '/');
    689     while (pchSlash)
    690     {
    691         *pchSlash = '\\';
    692         pchSlash = kHlpStrChr(pchSlash + 1, '/');
    693     }
    694 
    695     /*
    696      * Create a new hash table entry (ignore failures).
    697      */
    698     cchNormPath = kHlpStrLen(pszNormPath);
    699     if (cchNormPath < KU16_MAX && cchPath < KU16_MAX)
    700     {
    701         pHashEntry = (PKFSNORMHASHA)kHlpAlloc(sizeof(*pHashEntry) + cchNormPath + 1 + cchPath + 1);
    702         if (pHashEntry)
    703         {
    704             pHashEntry->cchNormPath = (KU16)cchNormPath;
    705             pHashEntry->cchPath     = (KU16)cchPath;
    706             pHashEntry->uHashPath   = uHashPath;
    707             pHashEntry->pszPath     = (char *)kHlpMemCopy(&pHashEntry->szNormPath[cchNormPath + 1], pszPath, cchPath + 1);
    708             kHlpMemCopy(pHashEntry->szNormPath, pszNormPath, cchNormPath + 1);
    709 
    710             pHashEntry->pNext = g_apFsNormalizedPathsA[idxHashTab];
    711             g_apFsNormalizedPathsA[idxHashTab] = pHashEntry;
    712         }
    713     }
    714 
    715     return 0;
    716 }
    717 
    718 
    719 /**
    720  * Get the pointer to the filename part of the path.
    721  *
    722  * @returns Pointer to where the filename starts within the string pointed to by pszFilename.
    723  * @returns Pointer to the terminator char if no filename.
    724  * @param   pszPath     The path to parse.
    725  */
    726 static wchar_t *kwPathGetFilenameW(const wchar_t *pwszPath)
    727 {
    728     const wchar_t *pwszLast = NULL;
    729     for (;;)
    730     {
    731         wchar_t wc = *pwszPath;
    732 #if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS
    733         if (wc == '/' || wc == '\\' || wc == ':')
    734         {
    735             while ((wc = *++pwszPath) == '/' || wc == '\\' || wc == ':')
    736                 /* nothing */;
    737             pwszLast = pwszPath;
    738         }
     375/** @def KW_LOG
     376 * Generic logging.
     377 * @param a     Argument list for kFsCacheDbgPrintf  */
     378#ifdef NDEBUG
     379# define KFSCACHE_LOG(a) do { } while (0)
    739380#else
    740         if (wc == '/')
    741         {
    742             while ((wc = *++pszFilename) == '/')
    743                 /* betsuni */;
    744             pwszLast = pwszPath;
    745         }
    746 #endif
    747         if (!wc)
    748             return (wchar_t *)(pwszLast ? pwszLast : pwszPath);
    749         pwszPath++;
    750     }
    751 }
    752 
    753 
    754 /**
    755  * Check if the path leads to a regular file (that exists).
    756  *
    757  * @returns K_TRUE / K_FALSE
    758  * @param   pszPath             Path to the file to check out.
    759  */
    760 static KBOOL kwLdrModuleIsRegularFile(const char *pszPath)
    761 {
    762     /* For stuff with .DLL extensions, we can use the GetFileAttribute cache to speed this up! */
    763     KSIZE cchPath = kHlpStrLen(pszPath);
    764     if (   cchPath > 3
    765         && pszPath[cchPath - 4] == '.'
    766         && (pszPath[cchPath - 3] == 'd' || pszPath[cchPath - 3] == 'D')
    767         && (pszPath[cchPath - 2] == 'l' || pszPath[cchPath - 2] == 'L')
    768         && (pszPath[cchPath - 1] == 'l' || pszPath[cchPath - 1] == 'L') )
    769     {
    770         PKFSOBJ pFsObj = kFsCacheLookupA(pszPath);
    771         if (pFsObj)
    772         {
    773             if (!(pFsObj->fAttribs & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE))) /* also checks invalid */
    774                 return K_TRUE;
    775         }
    776     }
    777     else
    778     {
    779         BirdStat_T Stat;
    780         int rc = birdStatFollowLink(pszPath, &Stat);
    781         if (rc == 0)
    782         {
    783             if (S_ISREG(Stat.st_mode))
    784                 return K_TRUE;
    785         }
    786     }
    787     return K_FALSE;
    788 }
    789 
    790 
    791 
    792 
    793 
    794 
    795 /**
    796  * Helper for getting the extension of a UTF-16 path.
    797  *
    798  * @returns Pointer to the extension or the terminator.
    799  * @param   pwszPath        The path.
    800  * @param   pcwcExt         Where to return the length of the extension.
    801  */
    802 static wchar_t const *kwFsPathGetExtW(wchar_t const *pwszPath, KSIZE *pcwcExt)
    803 {
    804     wchar_t const *pwszName = pwszPath;
    805     wchar_t const *pwszExt  = NULL;
    806     for (;;)
    807     {
    808         wchar_t const wc = *pwszPath++;
    809         if (wc == '.')
    810             pwszExt = pwszPath;
    811         else if (wc == '/' || wc == '\\' || wc == ':')
    812         {
    813             pwszName = pwszPath;
    814             pwszExt = NULL;
    815         }
    816         else if (wc == '\0')
    817         {
    818             if (pwszExt)
    819             {
    820                 *pcwcExt = pwszPath - pwszExt - 1;
    821                 return pwszExt;
    822             }
    823             *pcwcExt = 0;
    824             return pwszPath - 1;
    825         }
    826     }
    827 }
    828 #endif
    829 
    830 
    831 /**
    832  * Looks for '..' in the path.
    833  *
    834  * @returns K_TRUE if '..' component found, K_FALSE if not.
    835  * @param   pszPath             The path.
    836  * @param   cchPath             The length of the path.
    837  */
    838 static KBOOL kFsCacheHasDotDotA(const char *pszPath, KSIZE cchPath)
    839 {
    840     const char *pchDot = (const char *)kHlpMemChr(pszPath, '.', cchPath);
    841     while (pchDot)
    842     {
    843         if (pchDot[1] != '.')
    844             pchDot = (const char *)kHlpMemChr(pchDot + 1, '.', &pszPath[cchPath] - pchDot - 1);
    845         else
    846         {
    847             char ch;
    848             if (   (ch = pchDot[2]) == '\0'
    849                 && IS_SLASH(ch))
    850             {
    851                 if (pchDot == pszPath)
    852                     return K_TRUE;
    853                 ch = pchDot[-1];
    854                 if (   IS_SLASH(ch)
    855                     || ch == ':')
    856                     return K_TRUE;
    857             }
    858             pchDot = (const char *)kHlpMemChr(pchDot + 2, '.', &pszPath[cchPath] - pchDot - 2);
    859         }
    860     }
    861 
    862     return K_FALSE;
    863 }
    864 
    865 
    866 /**
    867  * Looks for '..' in the path.
    868  *
    869  * @returns K_TRUE if '..' component found, K_FALSE if not.
    870  * @param   pwszPath            The path.
    871  * @param   cwcPath             The length of the path (in wchar_t's).
    872  */
    873 static KBOOL kFsCacheHasDotDotW(const wchar_t *pwszPath, KSIZE cwcPath)
    874 {
    875     const wchar_t *pwcDot = wmemchr(pwszPath, '.', cwcPath);
    876     while (pwcDot)
    877     {
    878         if (pwcDot[1] != '.')
    879             pwcDot = wmemchr(pwcDot + 1, '.', &pwszPath[cwcPath] - pwcDot - 1);
    880         else
    881         {
    882             wchar_t wch;
    883             if (   (wch = pwcDot[2]) == '\0'
    884                 && IS_SLASH(wch))
    885             {
    886                 if (pwcDot == pwszPath)
    887                     return K_TRUE;
    888                 wch = pwcDot[-1];
    889                 if (   IS_SLASH(wch)
    890                     || wch == ':')
    891                     return K_TRUE;
    892             }
    893             pwcDot = wmemchr(pwcDot + 2, '.', &pwszPath[cwcPath] - pwcDot - 2);
    894         }
    895     }
    896 
    897     return K_FALSE;
    898 }
    899 
    900 
    901 /**
    902  * Creates an ANSI hash table entry for the given path.
    903  *
    904  * @returns The hash table entry or NULL if out of memory.
    905  * @param   pCache              The hash
    906  * @param   pFsObj              The resulting object.
    907  * @param   pszPath             The path.
    908  * @param   cchPath             The length of the path.
    909  * @param   uHashPath           The hash of the path.
    910  * @param   idxHashTab          The hash table index of the path.
    911  * @param   enmError            The lookup error.
    912  */
    913 static PKFSHASHA kFsCacheCreatePathHashTabEntryA(PKFSCACHE pCache, PKFSOBJ pFsObj, const char *pszPath, KU32 cchPath,
    914                                                  KU32 uHashPath, KU32 idxHashTab, KFSLOOKUPERROR enmError)
    915 {
    916     PKFSHASHA pHashEntry = (PKFSHASHA)kHlpAlloc(sizeof(*pHashEntry) + cchPath + 1);
    917     if (pHashEntry)
    918     {
    919         pHashEntry->uHashPath   = uHashPath;
    920         pHashEntry->cchPath     = cchPath;
    921         pHashEntry->pszPath     = (const char *)kHlpMemCopy(pHashEntry + 1, pszPath, cchPath + 1);
    922         pHashEntry->pFsObj      = pFsObj;
    923         pHashEntry->enmError    = enmError;
    924         if (pFsObj)
    925             pHashEntry->uCacheGen = pCache->uGeneration;
    926         else if (enmError != KFSLOOKUPERROR_UNSUPPORTED)
    927             pHashEntry->uCacheGen = pCache->uGenerationMissing;
    928         else
    929             pHashEntry->uCacheGen = KFSWOBJ_CACHE_GEN_IGNORE;
    930 
    931         pHashEntry->pNext = pCache->apAnsiPaths[idxHashTab];
    932         pCache->apAnsiPaths[idxHashTab] = pHashEntry;
    933 
    934         pCache->cbAnsiPaths += sizeof(*pHashEntry) + cchPath + 1;
    935         pCache->cAnsiPaths++;
    936         if (pHashEntry->pNext)
    937             pCache->cAnsiPathCollisions++;
    938     }
    939     return pHashEntry;
    940 }
    941 
    942 
    943 /**
    944  * Creates an UTF-16 hash table entry for the given path.
    945  *
    946  * @returns The hash table entry or NULL if out of memory.
    947  * @param   pCache              The hash
    948  * @param   pFsObj              The resulting object.
    949  * @param   pwszPath            The path.
    950  * @param   cwcPath             The length of the path (in wchar_t's).
    951  * @param   uHashPath           The hash of the path.
    952  * @param   idxHashTab          The hash table index of the path.
    953  * @param   enmError            The lookup error.
    954  */
    955 static PKFSHASHW kFsCacheCreatePathHashTabEntryW(PKFSCACHE pCache, PKFSOBJ pFsObj, const wchar_t *pwszPath, KU32 cwcPath,
    956                                                  KU32 uHashPath, KU32 idxHashTab, KFSLOOKUPERROR enmError)
    957 {
    958     PKFSHASHW pHashEntry = (PKFSHASHW)kHlpAlloc(sizeof(*pHashEntry) + (cwcPath + 1) * sizeof(wchar_t));
    959     if (pHashEntry)
    960     {
    961         pHashEntry->uHashPath   = uHashPath;
    962         pHashEntry->cwcPath     = cwcPath;
    963         pHashEntry->pwszPath    = (const wchar_t *)kHlpMemCopy(pHashEntry + 1, pwszPath, (cwcPath + 1) * sizeof(wchar_t));
    964         pHashEntry->pFsObj      = pFsObj;
    965         pHashEntry->enmError    = enmError;
    966         if (pFsObj)
    967             pHashEntry->uCacheGen = pCache->uGeneration;
    968         else if (enmError != KFSLOOKUPERROR_UNSUPPORTED)
    969             pHashEntry->uCacheGen = pCache->uGenerationMissing;
    970         else
    971             pHashEntry->uCacheGen = KFSWOBJ_CACHE_GEN_IGNORE;
    972 
    973         pHashEntry->pNext = pCache->apUtf16Paths[idxHashTab];
    974         pCache->apUtf16Paths[idxHashTab] = pHashEntry;
    975 
    976         pCache->cbUtf16Paths += sizeof(*pHashEntry) + (cwcPath + 1) * sizeof(wchar_t);
    977         pCache->cUtf16Paths++;
    978         if (pHashEntry->pNext)
    979             pCache->cAnsiPathCollisions++;
    980     }
    981     return pHashEntry;
    982 }
    983 
    984 
    985 /**
    986  * Links the child in under the parent.
    987  *
    988  * @returns K_TRUE on success, K_FALSE if out of memory.
    989  * @param   pParent             The parent node.
    990  * @param   pChild              The child node.
    991  */
    992 static KBOOL kFsCacheDirAddChild(PKFSCACHE pCache, PKFSDIR pParent, PKFSOBJ pChild, KFSLOOKUPERROR *penmError)
    993 {
    994     if ((pParent->cChildren % 16) == 0)
    995     {
    996         void *pvNew = kHlpRealloc(pParent->papChildren, (pParent->cChildren + 16) * sizeof(pParent->papChildren[0]));
    997         if (!pvNew)
    998             return K_FALSE;
    999         pParent->papChildren = (PKFSOBJ *)pvNew;
    1000         pCache->cbObjects += 16 * sizeof(pParent->papChildren[0]);
    1001     }
    1002     pParent->papChildren[pParent->cChildren++] = pChild;
    1003     return K_TRUE;
    1004 }
    1005 
    1006 
    1007 /**
    1008  * Creates a new cache object.
    1009  *
    1010  * @returns Pointer (with 1 reference) to the new object.  The object will not
    1011  *          be linked to the parent directory yet.
    1012  *
    1013  *          NULL if we're out of memory.
    1014  *
    1015  * @param   pCache          The cache.
    1016  * @param   pParent         The parent directory.
    1017  * @param   pszName         The ANSI name.
    1018  * @param   cchName         The length of the ANSI name.
    1019  * @param   pwszName        The UTF-16 name.
    1020  * @param   cwcName         The length of the UTF-16 name.
    1021  * @param   pszShortName    The ANSI short name, NULL if none.
    1022  * @param   cchShortName    The length of the ANSI short name, 0 if none.
    1023  * @param   pwszShortName   The UTF-16 short name, NULL if none.
    1024  * @param   cwcShortName    The length of the UTF-16 short name, 0 if none.
    1025  * @param   bObjType        The objct type.
    1026  * @param   penmError       Where to explain failures.
    1027  */
    1028 static PKFSOBJ kFsCacheCreateObject(PKFSCACHE pCache, PKFSDIR pParent,
    1029                                     char const *pszName, KU16 cchName, wchar_t const *pwszName, KU16 cwcName,
     381# define KFSCACHE_LOG(a) kFsCacheDbgPrintf a
     382void        kFsCacheDbgPrintfV(const char *pszFormat, va_list va);
     383void        kFsCacheDbgPrintf(const char *pszFormat, ...);
     384#endif
     385
     386
     387KBOOL       kFsCacheDirAddChild(PKFSCACHE pCache, PKFSDIR pParent, PKFSOBJ pChild, KFSLOOKUPERROR *penmError);
     388PKFSOBJ     kFsCacheCreateObject(PKFSCACHE pCache, PKFSDIR pParent,
     389                                 char const *pszName, KU16 cchName, wchar_t const *pwszName, KU16 cwcName,
    1030390#ifdef KFSCACHE_CFG_SHORT_NAMES
    1031                                     char const *pszShortName, KU16 cchShortName, wchar_t const *pwszShortName, KU16 cwcShortName,
    1032 #endif
    1033                                     KU8 bObjType, KFSLOOKUPERROR *penmError)
    1034 {
    1035     /*
    1036      * Allocate the object.
    1037      */
    1038     KBOOL const fDirish = bObjType != KFSOBJ_TYPE_FILE && bObjType == KFSOBJ_TYPE_OTHER;
    1039     KSIZE const cbObj   = (fDirish ? sizeof(KFSDIR) : sizeof(KFSOBJ))
    1040                         + (cwcName + 1) * sizeof(wchar_t)                           + cchName + 1
     391                                 char const *pszShortName, KU16 cchShortName, wchar_t const *pwszShortName, KU16 cwcShortName,
     392#endif
     393                                 KU8 bObjType, KFSLOOKUPERROR *penmError);
     394PKFSOBJ     kFsCacheCreateObjectW(PKFSCACHE pCache, PKFSDIR pParent, wchar_t const *pwszName, KU32 cwcName,
    1041395#ifdef KFSCACHE_CFG_SHORT_NAMES
    1042                         + (cwcShortName > 0 ? (cwcShortName + 1) * sizeof(wchar_t)  + cchShortName + 1 : 0)
    1043 #endif
    1044                           ;
    1045     PKFSOBJ pObj = (PKFSOBJ)kHlpAlloc(cbObj);
    1046     if (pObj)
    1047     {
    1048         KU8 *pbExtra = (KU8 *)(pObj + 1);
    1049 
    1050         pCache->cbObjects += cbObj;
    1051         pCache->cObjects++;
    1052 
    1053         /*
    1054          * Initialize the object.
    1055          */
    1056         pObj->u32Magic      = KFSOBJ_MAGIC;
    1057         pObj->cRefs         = 1;
    1058         pObj->uCacheGen     = bObjType != KFSOBJ_TYPE_MISSING ? pCache->uGeneration : pCache->uGenerationMissing;
    1059         pObj->bObjType      = bObjType;
    1060         pObj->fHaveStats    = K_FALSE;
    1061         pObj->abUnused[0]   = K_FALSE;
    1062         pObj->abUnused[1]   = K_FALSE;
    1063         pObj->fFlags        = pParent->Obj.fFlags;
    1064         pObj->pParent       = pParent;
    1065 
    1066 #ifdef KFSCACHE_CFG_UTF16
    1067         pObj->cwcParent = pParent->Obj.cwcParent + pParent->Obj.cwcName + !!pParent->Obj.cwcName;
    1068         pObj->pwszName  = (wchar_t *)kHlpMemCopy(pbExtra, pwszName, cwcName * sizeof(wchar_t));
    1069         pbExtra += cwcName * sizeof(wchar_t);
    1070         *pbExtra++ = '\0';
    1071         *pbExtra++ = '\0';
    1072 # ifdef KFSCACHE_CFG_SHORT_NAMES
    1073         pObj->cwcShortParent = pParent->Obj.cwcShortParent + pParent->Obj.cwcShortName + !!pParent->Obj.cwcShortName;
    1074         if (cwcShortName)
    1075         {
    1076             pObj->pwszShortName = (wchar_t *)kHlpMemCopy(pbExtra, pwszShortName, cwcShortName * sizeof(wchar_t));
    1077             pbExtra += cwcShortName * sizeof(wchar_t);
    1078             *pbExtra++ = '\0';
    1079             *pbExtra++ = '\0';
    1080         }
    1081         else
    1082         {
    1083             pObj->pwszShortName = pObj->pwszName;
    1084             pObj->cwcShortName  = pObj->cwcName;
    1085         }
    1086 # endif
    1087 #endif
    1088         pObj->cchParent = pParent->Obj.cchParent + pParent->Obj.cchName + !!pParent->Obj.cchName;
    1089         pObj->pszName   = (char *)kHlpMemCopy(pbExtra, pszName, cchName);
    1090         pbExtra += cchName;
    1091         *pbExtra++ = '\0';
    1092 # ifdef KFSCACHE_CFG_SHORT_NAMES
    1093         pObj->cchShortParent = pParent->Obj.cchShortParent + pParent->Obj.cchShortName + !!pParent->Obj.cchShortName;
    1094         if (cchShortName)
    1095         {
    1096             pObj->pszShortName = (char *)kHlpMemCopy(pbExtra, pszShortName, cchShortName);
    1097             pbExtra += cchShortName;
    1098             *pbExtra++ = '\0';
    1099         }
    1100         else
    1101         {
    1102             pObj->pszShortName = pObj->pszName;
    1103             pObj->cchShortName = pObj->cchName;
    1104         }
    1105 #endif
    1106         kHlpAssert(pbExtra - (KU8 *)pObj == cbObj);
    1107 
    1108         /*
    1109          * Type specific initilization.
    1110          */
    1111         if (fDirish)
    1112         {
    1113             PKFSDIR pDirObj = (PKFSDIR)pObj;
    1114             pDirObj->cChildren      = 0;
    1115             pDirObj->papChildren    = NULL;
    1116             pDirObj->cHashTab       = 0;
    1117             pDirObj->paHashTab      = NULL;
    1118             pDirObj->hDir           = INVALID_HANDLE_VALUE;
    1119             pDirObj->uDevNo         = pParent->uDevNo;
    1120             pDirObj->fPopulated     = K_FALSE;
    1121         }
    1122     }
    1123     else
    1124         *penmError = KFSLOOKUPERROR_OUT_OF_MEMORY;
    1125     return pObj;
    1126 }
    1127 
    1128 
    1129 /**
    1130  * Creates a new object given wide char names.
    1131  *
    1132  * This function just converts the paths and calls kFsCacheCreateObject.
    1133  *
    1134  *
    1135  * @returns Pointer (with 1 reference) to the new object.  The object will not
    1136  *          be linked to the parent directory yet.
    1137  *
    1138  *          NULL if we're out of memory.
    1139  *
    1140  * @param   pCache          The cache.
    1141  * @param   pParent         The parent directory.
    1142  * @param   pszName         The ANSI name.
    1143  * @param   cchName         The length of the ANSI name.
    1144  * @param   pwszName        The UTF-16 name.
    1145  * @param   cwcName         The length of the UTF-16 name.
    1146  * @param   pwszShortName   The UTF-16 short name, NULL if none.
    1147  * @param   cwcShortName    The length of the UTF-16 short name, 0 if none.
    1148  * @param   bObjType        The objct type.
    1149  * @param   penmError       Where to explain failures.
    1150  */
    1151 static PKFSOBJ kFsCacheCreateObjectW(PKFSCACHE pCache, PKFSDIR pParent, wchar_t const *pwszName, KU32 cwcName,
    1152 #ifdef KFSCACHE_CFG_SHORT_NAMES
    1153                                      wchar_t const *pwszShortName, KU32 cwcShortName,
    1154 #endif
    1155                                      KU8 bObjType, KFSLOOKUPERROR *penmError)
    1156 {
    1157     /* Convert names to ANSI first so we know their lengths. */
    1158     char szName[KFSCACHE_CFG_MAX_ANSI_NAME];
    1159     int  cchName = WideCharToMultiByte(CP_ACP, 0, pwszName, cwcName, szName, sizeof(szName) - 1, NULL, NULL);
    1160     if (cchName >= 0)
    1161     {
    1162 #ifdef KFSCACHE_CFG_SHORT_NAMES
    1163         char szShortName[12*3 + 1];
    1164         int  cchShortName = 0;
    1165         if (   cwcShortName == 0
    1166             || (cchShortName = WideCharToMultiByte(CP_ACP, 0, pwszShortName, cwcShortName,
    1167                                                    szShortName, sizeof(szShortName) - 1, NULL, NULL)) > 0)
    1168 #endif
    1169         {
    1170             return kFsCacheCreateObject(pCache, pParent,
    1171                                         szName, cchName, pwszName, cwcName,
    1172 #ifdef KFSCACHE_CFG_SHORT_NAMES
    1173                                         szShortName, cchShortName, pwszShortName, cwcShortName,
    1174 #endif
    1175                                         bObjType, penmError);
    1176         }
    1177     }
    1178     *penmError = KFSLOOKUPERROR_ANSI_CONVERSION_ERROR;
    1179     return NULL;
    1180 }
    1181 
    1182 
    1183 /**
    1184  * Creates a missing object.
    1185  *
    1186  * This is used for caching negative results.
    1187  *
    1188  * @returns Pointer to the newly created object on success (already linked into
    1189  *          pParent).  No reference.
    1190  *
    1191  *          NULL on failure.
    1192  *
    1193  * @param   pCache              The cache.
    1194  * @param   pParent             The parent directory.
    1195  * @param   pchName             The name.
    1196  * @param   cchName             The length of the name.
    1197  * @param   penmError           Where to return failure explanations.
    1198  */
    1199 static PKFSOBJ kFsCacheCreateMissingA(PKFSCACHE pCache, PKFSDIR pParent, const char *pchName, KU32 cchName,
    1200                                       KFSLOOKUPERROR *penmError)
    1201 {
    1202     /*
    1203      * Just convert the name to UTF-16 and call kFsCacheCreateObject to do the job.
    1204      */
    1205     wchar_t wszName[KFSCACHE_CFG_MAX_PATH];
    1206     int cwcName = MultiByteToWideChar(CP_ACP, 0, pchName, cchName, wszName, KFSCACHE_CFG_MAX_UTF16_NAME - 1);
    1207     if (cwcName > 0)
    1208     {
    1209         /** @todo check that it actually doesn't exists before we add it.  We should not
    1210          *        trust the directory enumeration here, or maybe we should?? */
    1211 
    1212         PKFSOBJ pMissing = kFsCacheCreateObject(pCache, pParent, pchName, cchName, wszName, cwcName,
    1213 #ifdef KFSCACHE_CFG_SHORT_NAMES
    1214                                                 NULL, 0, NULL, 0,
    1215 #endif
    1216                                                 KFSOBJ_TYPE_MISSING, penmError);
    1217         if (pMissing)
    1218         {
    1219             KBOOL fRc = kFsCacheDirAddChild(pCache, pParent, pMissing, penmError);
    1220             kFsCacheObjRelease(pCache, pMissing);
    1221             return fRc ? pMissing : NULL;
    1222         }
    1223         return NULL;
    1224     }
    1225     *penmError = KFSLOOKUPERROR_UTF16_CONVERSION_ERROR;
    1226     return NULL;
    1227 }
    1228 
    1229 
    1230 /**
    1231  * Creates a missing object, UTF-16 version.
    1232  *
    1233  * This is used for caching negative results.
    1234  *
    1235  * @returns Pointer to the newly created object on success (already linked into
    1236  *          pParent).  No reference.
    1237  *
    1238  *          NULL on failure.
    1239  *
    1240  * @param   pCache              The cache.
    1241  * @param   pParent             The parent directory.
    1242  * @param   pwcName             The name.
    1243  * @param   cwcName             The length of the name.
    1244  * @param   penmError           Where to return failure explanations.
    1245  */
    1246 static PKFSOBJ kFsCacheCreateMissingW(PKFSCACHE pCache, PKFSDIR pParent, const wchar_t *pwcName, KU32 cwcName,
    1247                                       KFSLOOKUPERROR *penmError)
    1248 {
    1249     /** @todo check that it actually doesn't exists before we add it.  We should not
    1250      *        trust the directory enumeration here, or maybe we should?? */
    1251     PKFSOBJ pMissing = kFsCacheCreateObjectW(pCache, pParent, pwcName, cwcName,
    1252 #ifdef KFSCACHE_CFG_SHORT_NAMES
    1253                                              NULL, 0,
    1254 #endif
    1255                                              KFSOBJ_TYPE_MISSING, penmError);
    1256     if (pMissing)
    1257     {
    1258         KBOOL fRc = kFsCacheDirAddChild(pCache, pParent, pMissing, penmError);
    1259         kFsCacheObjRelease(pCache, pMissing);
    1260         return fRc ? pMissing : NULL;
    1261     }
    1262     return NULL;
    1263 }
    1264 
    1265 
    1266 /**
    1267  * Does the initial directory populating or refreshes it if it has been
    1268  * invalidated.
    1269  *
    1270  * This assumes the parent directory is opened.
    1271  *
    1272  * @returns K_TRUE on success, K_FALSE on error.
    1273  * @param   pCache              The cache.
    1274  * @param   pDir                The directory.
    1275  * @param   penmError           Where to store K_FALSE explanation.
    1276  */
    1277 static KBOOL kFsCachePopuplateOrRefreshDir(PKFSCACHE pCache, PKFSDIR pDir, KFSLOOKUPERROR *penmError)
    1278 {
    1279     KBOOL                       fRefreshing  = K_FALSE;
    1280     /** @todo will have to make this more flexible wrt information classes since
    1281      *        older windows versions (XP, w2K) might not correctly support the
    1282      *        ones with file ID on all file systems. */
    1283 #ifdef KFSCACHE_CFG_SHORT_NAMES
    1284     MY_FILE_INFORMATION_CLASS const enmInfoClassWithId = MyFileIdBothDirectoryInformation;
    1285     MY_FILE_INFORMATION_CLASS       enmInfoClass = MyFileIdBothDirectoryInformation;
    1286 #else
    1287     MY_FILE_INFORMATION_CLASS const enmInfoClassWithId = MyFileIdFullDirectoryInformation;
    1288     MY_FILE_INFORMATION_CLASS       enmInfoClass = MyFileIdFullDirectoryInformation;
    1289 #endif
    1290     MY_NTSTATUS                 rcNt;
    1291     MY_IO_STATUS_BLOCK          Ios;
    1292     union
    1293     {
    1294         /* Include the structures for better alignment. */
    1295         MY_FILE_ID_BOTH_DIR_INFORMATION     WithId;
    1296         MY_FILE_ID_FULL_DIR_INFORMATION     NoId;
    1297         /* Buffer padding. We're using a 56KB buffer here to avoid size troubles with CIFS and such. */
    1298         KU8                                 abBuf[56*1024];
    1299     } uBuf;
    1300 
    1301     /*
    1302      * Open the directory.
    1303      */
    1304     if (pDir->hDir == INVALID_HANDLE_VALUE)
    1305     {
    1306         MY_OBJECT_ATTRIBUTES    ObjAttr;
    1307         MY_UNICODE_STRING       UniStr;
    1308 
    1309         kHlpAssert(!pDir->fPopulated);
    1310 
    1311         Ios.Information = -1;
    1312         Ios.u.Status    = -1;
    1313 
    1314         UniStr.Buffer        = (wchar_t *)pDir->Obj.pwszName;
    1315         UniStr.Length        = (USHORT)(pDir->Obj.cwcName * sizeof(wchar_t));
    1316         UniStr.MaximumLength = UniStr.Length + sizeof(wchar_t);
    1317 
    1318         kHlpAssertStmtReturn(pDir->Obj.pParent, *penmError = KFSLOOKUPERROR_INTERNAL_ERROR, K_FALSE);
    1319         kHlpAssertStmtReturn(pDir->Obj.pParent->hDir != INVALID_HANDLE_VALUE, *penmError = KFSLOOKUPERROR_INTERNAL_ERROR, K_FALSE);
    1320         MyInitializeObjectAttributes(&ObjAttr, &UniStr, OBJ_CASE_INSENSITIVE, pDir->Obj.pParent->hDir, NULL /*pSecAttr*/);
    1321 
    1322         /** @todo FILE_OPEN_REPARSE_POINT? */
    1323         rcNt = g_pfnNtCreateFile(&pDir->hDir,
    1324                                  FILE_READ_DATA | FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
    1325                                  &ObjAttr,
    1326                                  &Ios,
    1327                                  NULL, /*cbFileInitialAlloc */
    1328                                  FILE_ATTRIBUTE_NORMAL,
    1329                                  FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
    1330                                  FILE_OPEN,
    1331                                  FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
    1332                                  NULL, /*pEaBuffer*/
    1333                                  0);   /*cbEaBuffer*/
    1334         if (MY_NT_SUCCESS(rcNt))
    1335         {  /* likely */ }
    1336         else
    1337         {
    1338             pDir->hDir = INVALID_HANDLE_VALUE;
    1339             *penmError = KFSLOOKUPERROR_DIR_OPEN_ERROR;
    1340             return K_FALSE;
    1341         }
    1342     }
    1343     else if (pDir->fPopulated)
    1344     {
    1345         /** @todo refreshing directories. */
    1346         __debugbreak();
    1347         fRefreshing = K_TRUE;
    1348     }
    1349 
    1350 
    1351     /*
    1352      * Enumerate the directory content.
    1353      */
    1354     Ios.Information = -1;
    1355     Ios.u.Status    = -1;
    1356     rcNt = g_pfnNtQueryDirectoryFile(pDir->hDir,
    1357                                      NULL,      /* hEvent */
    1358                                      NULL,      /* pfnApcComplete */
    1359                                      NULL,      /* pvApcCompleteCtx */
    1360                                      &Ios,
    1361                                      &uBuf,
    1362                                      sizeof(uBuf),
    1363                                      enmInfoClass,
    1364                                      FALSE,     /* fReturnSingleEntry */
    1365                                      NULL,      /* Filter / restart pos. */
    1366                                      TRUE);     /* fRestartScan */
    1367     while (MY_NT_SUCCESS(rcNt))
    1368     {
    1369         /*
    1370          * Process the entries in the buffer.
    1371          */
    1372         KSIZE offBuf = 0;
    1373         for (;;)
    1374         {
    1375             union
    1376             {
    1377                 KU8                             *pb;
    1378 #ifdef KFSCACHE_CFG_SHORT_NAMES
    1379                 MY_FILE_ID_BOTH_DIR_INFORMATION *pWithId;
    1380                 MY_FILE_BOTH_DIR_INFORMATION    *pNoId;
    1381 #else
    1382                 MY_FILE_ID_FULL_DIR_INFORMATION *pWithId;
    1383                 MY_FILE_FULL_DIR_INFORMATION    *pNoId;
    1384 #endif
    1385             }           uPtr;
    1386             PKFSOBJ     pCur;
    1387             KU32        offNext;
    1388             KU32        cbMinCur;
    1389             wchar_t    *pwszFilename;
    1390 
    1391             /* ASSUME only the FileName member differs between the two structures. */
    1392             uPtr.pb = &uBuf.abBuf[offBuf];
    1393             if (enmInfoClass == enmInfoClassWithId)
    1394             {
    1395                 pwszFilename = &uPtr.pWithId->FileName[0];
    1396                 cbMinCur  = (KU32)((uintptr_t)&uPtr.pWithId->FileName[0] - (uintptr_t)uPtr.pWithId);
    1397                 cbMinCur += uPtr.pNoId->FileNameLength;
    1398             }
    1399             else
    1400             {
    1401                 pwszFilename = &uPtr.pNoId->FileName[0];
    1402                 cbMinCur  = (KU32)((uintptr_t)&uPtr.pNoId->FileName[0] - (uintptr_t)uPtr.pNoId);
    1403                 cbMinCur += uPtr.pNoId->FileNameLength;
    1404             }
    1405 
    1406             /*
    1407              * Create the entry (not linked yet).
    1408              */
    1409             pCur = kFsCacheCreateObjectW(pCache, pDir, pwszFilename, uPtr.pNoId->FileNameLength / sizeof(wchar_t),
    1410 #ifdef KFSCACHE_CFG_SHORT_NAMES
    1411                                          uPtr.pNoId->ShortName, uPtr.pNoId->ShortNameLength / sizeof(wchar_t),
    1412 #endif
    1413                                          uPtr.pNoId->FileAttributes & FILE_ATTRIBUTE_DIRECTORY ? KFSOBJ_TYPE_DIR
    1414                                          : uPtr.pNoId->FileAttributes & (FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_REPARSE_POINT)
    1415                                          ? KFSOBJ_TYPE_OTHER : KFSOBJ_TYPE_FILE,
    1416                                          penmError);
    1417             if (!pCur)
    1418                 return K_FALSE;
    1419             kHlpAssert(pCur->cRefs == 1);
    1420 
    1421 #ifdef KFSCACHE_CFG_SHORT_NAMES
    1422             if (enmInfoClass == enmInfoClassWithId)
    1423                 birdStatFillFromFileIdBothDirInfo(&pCur->Stats, uPtr.pWithId, pCur->pszName);
    1424             else
    1425                 birdStatFillFromFileBothDirInfo(&pCur->Stats, uPtr.pNoId, pCur->pszName);
    1426 #else
    1427             if (enmInfoClass == enmInfoClassWithId)
    1428                 birdStatFillFromFileIdFullDirInfo(&pCur->Stats, uPtr.pWithId, pCur->pszName);
    1429             else
    1430                 birdStatFillFromFileFullDirInfo(&pCur->Stats, uPtr.pNoId, pCur->pszName);
    1431 #endif
    1432             pCur->Stats.st_dev = pDir->uDevNo;
    1433 
    1434             /*
    1435              * If we're updating we have to check the data.
    1436              */
    1437             if (fRefreshing)
    1438             {
    1439                 __debugbreak();
    1440             }
    1441 
    1442             /*
    1443              * If we've still got pCur, add it to the directory.
    1444              */
    1445             if (pCur)
    1446             {
    1447                 KBOOL fRc = kFsCacheDirAddChild(pCache, pDir, pCur, penmError);
    1448                 kFsCacheObjRelease(pCache, pCur);
    1449                 if (fRc)
    1450                 { /* likely */ }
    1451                 else
    1452                     return K_FALSE;
    1453             }
    1454 
    1455             /*
    1456              * Advance.
    1457              */
    1458             offNext = uPtr.pNoId->NextEntryOffset;
    1459             if (   offNext >= cbMinCur
    1460                 && offNext < sizeof(uBuf))
    1461                 offBuf += offNext;
    1462             else
    1463                 break;
    1464         }
    1465 
    1466         /*
    1467          * Read the next chunk.
    1468          */
    1469         rcNt = g_pfnNtQueryDirectoryFile(pDir->hDir,
    1470                                          NULL,      /* hEvent */
    1471                                          NULL,      /* pfnApcComplete */
    1472                                          NULL,      /* pvApcCompleteCtx */
    1473                                          &Ios,
    1474                                          &uBuf,
    1475                                          sizeof(uBuf),
    1476                                          enmInfoClass,
    1477                                          FALSE,     /* fReturnSingleEntry */
    1478                                          NULL,      /* Filter / restart pos. */
    1479                                          FALSE);    /* fRestartScan */
    1480     }
    1481 
    1482     if (rcNt == MY_STATUS_NO_MORE_FILES)
    1483         return K_TRUE;
    1484     kHlpAssertMsgFailed(("%#x\n", rcNt));
    1485     *penmError = KFSLOOKUPERROR_DIR_READ_ERROR;
    1486     return K_TRUE;
    1487 }
    1488 
    1489 
    1490 static KBOOL kFsCacheRefreshMissing(PKFSCACHE pCache, PKFSOBJ pMissing, KFSLOOKUPERROR *penmError)
    1491 {
    1492     return K_TRUE;
    1493 }
    1494 
    1495 
    1496 static KBOOL kFsCacheRefreshMissingIntermediateDir(PKFSCACHE pCache, PKFSOBJ pMissing, KFSLOOKUPERROR *penmError)
    1497 {
    1498     return K_TRUE;
    1499 }
    1500 
    1501 
    1502 static KBOOL kFsCacheRefreshObj(PKFSCACHE pCache, PKFSOBJ pObj, KFSLOOKUPERROR *penmError)
    1503 {
    1504     return K_FALSE;
    1505 }
    1506 
    1507 
    1508 
    1509 /**
    1510  * Looks up a drive letter.
    1511  *
    1512  * Will enter the drive if necessary.
    1513  *
    1514  * @returns Pointer to the root directory of the drive or an update-to-date
    1515  *          missing node.
    1516  * @param   pCache              The cache.
    1517  * @param   chLetter            The uppercased drive letter.
    1518  * @param   penmError           Where to return details as to why the lookup
    1519  *                              failed.
    1520  */
    1521 static PKFSOBJ kFswCacheLookupDrive(PKFSCACHE pCache, char chLetter, KFSLOOKUPERROR *penmError)
    1522 {
    1523     KU32 const          uHash = chLetter - 'A';
    1524     KU32                cLeft;
    1525     PKFSOBJ            *ppCur;
    1526 
    1527     MY_UNICODE_STRING   NtPath;
    1528     wchar_t             wszTmp[8];
    1529     MY_NTSTATUS         rcNt;
    1530     char                szTmp[4];
    1531 
    1532     /*
    1533      * Custom drive letter hashing.
    1534      */
    1535     if (pCache->RootDir.paHashTab)
    1536     {
    1537         /** @todo PKFSOBJHASH pHash = */
    1538     }
    1539 
    1540     /*
    1541      * Special cased lookup.
    1542      */
    1543     cLeft = pCache->RootDir.cChildren;
    1544     ppCur = pCache->RootDir.papChildren;
    1545     while (cLeft-- > 0)
    1546     {
    1547         PKFSOBJ pCur = *ppCur++;
    1548         if (   pCur->cchName == 2
    1549             && pCur->pszName[0] == chLetter
    1550             && pCur->pszName[1] == ':')
    1551         {
    1552             if (pCur->bObjType == KFSOBJ_TYPE_DIR)
    1553                 return pCur;
    1554             kHlpAssert(pCur->bObjType == KFSOBJ_TYPE_MISSING);
    1555             if (kFsCacheRefreshMissingIntermediateDir(pCache, pCur, penmError))
    1556                 return pCur;
    1557             return NULL;
    1558         }
    1559     }
    1560 
    1561     /*
    1562      * Need to add it.  We always keep the drive letters open for the benefit
    1563      * of kFsCachePopuplateOrRefreshDir and others.
    1564      */
    1565     wszTmp[0] = szTmp[0] = chLetter;
    1566     wszTmp[1] = szTmp[1] = ':';
    1567     wszTmp[2] = szTmp[2] = '\\';
    1568     wszTmp[3] = '.';
    1569     wszTmp[4] = '\0';
    1570     szTmp[2] = '\0';
    1571 
    1572     NtPath.Buffer        = NULL;
    1573     NtPath.Length        = 0;
    1574     NtPath.MaximumLength = 0;
    1575     if (g_pfnRtlDosPathNameToNtPathName_U(wszTmp, &NtPath, NULL, NULL))
    1576     {
    1577         HANDLE hDir;
    1578         rcNt = birdOpenFileUniStr(&NtPath,
    1579                                   FILE_READ_DATA  | FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
    1580                                   FILE_ATTRIBUTE_NORMAL,
    1581                                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
    1582                                   FILE_OPEN,
    1583                                   FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
    1584                                   OBJ_CASE_INSENSITIVE,
    1585                                   &hDir);
    1586         birdFreeNtPath(&NtPath);
    1587         if (MY_NT_SUCCESS(rcNt))
    1588         {
    1589             PKFSDIR pDir = (PKFSDIR)kFsCacheCreateObject(pCache, &pCache->RootDir, szTmp, 2, wszTmp, 2,
    1590 #ifdef KFSCACHE_CFG_SHORT_NAMES
    1591                                                          NULL, 0, NULL, 0,
    1592 #endif
    1593                                                          KFSOBJ_TYPE_DIR, penmError);
    1594             if (pDir)
    1595             {
    1596                 /*
    1597                  * We need a little bit of extra info for a drive root.  These things are typically
    1598                  * inherited by subdirectories down the tree, so, we do it all here for till that changes.
    1599                  */
    1600                 union
    1601                 {
    1602                     MY_FILE_FS_VOLUME_INFORMATION       VolInfo;
    1603                     MY_FILE_FS_ATTRIBUTE_INFORMATION    FsAttrInfo;
    1604                     char abPadding[sizeof(MY_FILE_FS_VOLUME_INFORMATION) + 512];
    1605                 } uBuf;
    1606                 MY_IO_STATUS_BLOCK Ios;
    1607                 KBOOL fRc;
    1608 
    1609                 kHlpAssert(pDir->hDir == INVALID_HANDLE_VALUE);
    1610                 pDir->hDir = hDir;
    1611 
    1612                 /* Get the device number. */
    1613                 rcNt = birdQueryVolumeDeviceNumber(hDir, &uBuf.VolInfo, sizeof(uBuf), &pDir->uDevNo);
    1614                 kHlpAssertMsg(MY_NT_SUCCESS(rcNt), ("%#x\n", rcNt));
    1615 
    1616                 /* Get the file system. */
    1617                 pDir->Obj.fFlags &= ~(KFSOBJ_F_NTFS | KFSOBJ_F_WORKING_DIR_MTIME);
    1618                 Ios.Information = -1;
    1619                 Ios.u.Status    = -1;
    1620                 rcNt = g_pfnNtQueryVolumeInformationFile(hDir, &Ios, &uBuf.FsAttrInfo, sizeof(uBuf),
    1621                                                          MyFileFsAttributeInformation);
    1622                 if (MY_NT_SUCCESS(rcNt))
    1623                     rcNt = Ios.u.Status;
    1624                 if (MY_NT_SUCCESS(rcNt))
    1625                 {
    1626                     if (   uBuf.FsAttrInfo.FileSystemName[0] == 'N'
    1627                         && uBuf.FsAttrInfo.FileSystemName[1] == 'T'
    1628                         && uBuf.FsAttrInfo.FileSystemName[2] == 'F'
    1629                         && uBuf.FsAttrInfo.FileSystemName[3] == 'S'
    1630                         && uBuf.FsAttrInfo.FileSystemName[4] == '\0')
    1631                     {
    1632                         DWORD dwDriveType = GetDriveTypeW(wszTmp);
    1633                         if (   dwDriveType == DRIVE_FIXED
    1634                             || dwDriveType == DRIVE_RAMDISK)
    1635                             pDir->Obj.fFlags |= KFSOBJ_F_NTFS | KFSOBJ_F_WORKING_DIR_MTIME;
    1636                     }
    1637                 }
    1638 
    1639                 /*
    1640                  * Link the new drive letter into the root dir.
    1641                  */
    1642                 fRc = kFsCacheDirAddChild(pCache, &pCache->RootDir, &pDir->Obj, penmError);
    1643                 kFsCacheObjRelease(pCache, &pDir->Obj);
    1644                 return fRc ? &pDir->Obj : NULL;
    1645             }
    1646 
    1647             g_pfnNtClose(hDir);
    1648             return NULL;
    1649         }
    1650 
    1651         /* Assume it doesn't exist if this happens... This may be a little to
    1652            restrictive wrt status code checks. */
    1653         kHlpAssertMsgStmtReturn(   rcNt == MY_STATUS_OBJECT_NAME_NOT_FOUND
    1654                                 || rcNt == MY_STATUS_OBJECT_PATH_NOT_FOUND
    1655                                 || rcNt == MY_STATUS_OBJECT_PATH_INVALID
    1656                                 || rcNt == MY_STATUS_OBJECT_PATH_SYNTAX_BAD,
    1657                                 ("%#x\n", rcNt),
    1658                                 *penmError = KFSLOOKUPERROR_DIR_OPEN_ERROR,
    1659                                 NULL);
    1660     }
    1661     else
    1662     {
    1663         kHlpAssertFailed();
    1664         *penmError = KFSLOOKUPERROR_OUT_OF_MEMORY;
    1665         return NULL;
    1666     }
    1667 
    1668     /*
    1669      * Maybe create a missing entry.
    1670      */
    1671     if (pCache->fFlags & KFSCACHE_F_MISSING_OBJECTS)
    1672     {
    1673         PKFSOBJ pMissing = kFsCacheCreateObject(pCache, &pCache->RootDir, szTmp, 2, wszTmp, 2,
    1674 #ifdef KFSCACHE_CFG_SHORT_NAMES
    1675                                         NULL, 0, NULL, 0,
    1676 #endif
    1677                                         KFSOBJ_TYPE_MISSING, penmError);
    1678         if (pMissing)
    1679         {
    1680             KBOOL fRc = kFsCacheDirAddChild(pCache, &pCache->RootDir, pMissing, penmError);
    1681             kFsCacheObjRelease(pCache, pMissing);
    1682             return fRc ? pMissing : NULL;
    1683         }
    1684     }
    1685     else
    1686     {
    1687         /** @todo this isn't necessary correct for a root spec.   */
    1688         *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND;
    1689     }
    1690     return NULL;
    1691 }
    1692 
    1693 
    1694 /**
    1695  * Look up a child node, ANSI version.
    1696  *
    1697  * @returns Pointer to the child if found, NULL if not.
    1698  * @param   pCache              The cache.
    1699  * @param   pParent             The parent directory to search.
    1700  * @param   pchName             The child name to search for (not terminated).
    1701  * @param   cchName             The length of the child name.
    1702  */
    1703 static PKFSOBJ kFsCacheFindChildA(PKFSCACHE pCache, PKFSDIR pParent, const char *pchName, KU32 cchName)
    1704 {
    1705     /* Check for '.' first. */
    1706     if (cchName != 1 || *pchName != '.')
    1707     {
    1708         KU32        cLeft;
    1709         PKFSOBJ    *ppCur;
    1710 
    1711         if (pParent->paHashTab != NULL)
    1712         {
    1713             /** @todo directory hash table lookup.   */
    1714         }
    1715 
    1716         /* Linear search. */
    1717         cLeft = pParent->cChildren;
    1718         ppCur = pParent->papChildren;
    1719         while (cLeft-- > 0)
    1720         {
    1721             PKFSOBJ pCur = *ppCur++;
    1722             if (   (   pCur->cchName == cchName
    1723                     && _mbsnicmp(pCur->pszName, pchName, cchName) == 0)
    1724 #ifdef KFSCACHE_CFG_SHORT_NAMES
    1725                 || (   pCur->cchShortName == cchName
    1726                     && pCur->pszShortName != pCur->pszName
    1727                     && _mbsnicmp(pCur->pszShortName, pchName, cchName) == 0)
    1728 #endif
    1729                )
    1730                 return pCur;
    1731         }
    1732         return NULL;
    1733     }
    1734     return &pParent->Obj;
    1735 }
    1736 
    1737 
    1738 /**
    1739  * For use when kFsCacheIAreEqualW hit's something non-trivial.
    1740  *
    1741  * @returns K_TRUE if equal, K_FALSE if different.
    1742  * @param   pwcName1            The first string.
    1743  * @param   pwcName2            The second string.
    1744  * @param   cwcName             The length of the two strings (in wchar_t's).
    1745  */
    1746 KBOOL kFsCacheIAreEqualSlowW(const wchar_t *pwcName1, const wchar_t *pwcName2, KU16 cwcName)
    1747 {
    1748     MY_UNICODE_STRING UniStr1 = { cwcName * sizeof(wchar_t), cwcName * sizeof(wchar_t), (wchar_t *)pwcName1 };
    1749     MY_UNICODE_STRING UniStr2 = { cwcName * sizeof(wchar_t), cwcName * sizeof(wchar_t), (wchar_t *)pwcName2 };
    1750     return g_pfnRtlEqualUnicodeString(&UniStr1, &UniStr2, TRUE /*fCaseInsensitive*/);
    1751 }
    1752 
    1753 
    1754 /**
    1755  * Compares two UTF-16 strings in a case-insensitive fashion.
    1756  *
    1757  * You would think we should be using _wscnicmp here instead, however it is
    1758  * locale dependent and defaults to ASCII upper/lower handling setlocale hasn't
    1759  * been called.
    1760  *
    1761  * @returns K_TRUE if equal, K_FALSE if different.
    1762  * @param   pwcName1            The first string.
    1763  * @param   pwcName2            The second string.
    1764  * @param   cwcName             The length of the two strings (in wchar_t's).
    1765  */
    1766 K_INLINE KBOOL kFsCacheIAreEqualW(const wchar_t *pwcName1, const wchar_t *pwcName2, KU32 cwcName)
    1767 {
    1768     while (cwcName > 0)
    1769     {
    1770         wchar_t wc1 = *pwcName1;
    1771         wchar_t wc2 = *pwcName2;
    1772         if (wc1 == wc2)
    1773         { /* not unlikely */ }
    1774         else if (  (KU16)wc1 < (KU16)0xc0 /* U+00C0 is the first upper/lower letter after 'z'. */
    1775                 && (KU16)wc2 < (KU16)0xc0)
    1776         {
    1777             /* ASCII upper case. */
    1778             if ((KU16)wc1 - (KU16)0x61 < (KU16)26)
    1779                 wc1 &= ~(wchar_t)0x20;
    1780             if ((KU16)wc2 - (KU16)0x61 < (KU16)26)
    1781                 wc2 &= ~(wchar_t)0x20;
    1782             if (wc1 != wc2)
    1783                 return K_FALSE;
    1784         }
    1785         else
    1786             return kFsCacheIAreEqualSlowW(pwcName1, pwcName2, (KU16)cwcName);
    1787 
    1788         pwcName2++;
    1789         pwcName1++;
    1790         cwcName--;
    1791     }
    1792 
    1793     return K_TRUE;
    1794 }
    1795 
    1796 
    1797 /**
    1798  * Look up a child node, UTF-16 version.
    1799  *
    1800  * @returns Pointer to the child if found, NULL if not.
    1801  * @param   pCache              The cache.
    1802  * @param   pParent             The parent directory to search.
    1803  * @param   pwcName             The child name to search for (not terminated).
    1804  * @param   cwcName             The length of the child name (in wchar_t's).
    1805  */
    1806 static PKFSOBJ kFsCacheFindChildW(PKFSCACHE pCache, PKFSDIR pParent, const wchar_t *pwcName, KU32 cwcName)
    1807 {
    1808     /* Check for '.' first. */
    1809     if (cwcName != 1 || *pwcName != '.')
    1810     {
    1811         KU32        cLeft;
    1812         PKFSOBJ    *ppCur;
    1813 
    1814         if (pParent->paHashTab != NULL)
    1815         {
    1816             /** @todo directory hash table lookup.   */
    1817         }
    1818 
    1819         /* Linear search. */
    1820         cLeft = pParent->cChildren;
    1821         ppCur = pParent->papChildren;
    1822         while (cLeft-- > 0)
    1823         {
    1824             PKFSOBJ pCur = *ppCur++;
    1825             if (   (   pCur->cwcName == cwcName
    1826                     && kFsCacheIAreEqualW(pCur->pwszName, pwcName, cwcName))
    1827 #ifdef KFSCACHE_CFG_SHORT_NAMES
    1828                 || (   pCur->cwcShortName == cwcName
    1829                     && pCur->pwszShortName != pCur->pwszName
    1830                     && kFsCacheIAreEqualW(pCur->pwszShortName, pwcName, cwcName))
    1831 #endif
    1832                )
    1833                 return pCur;
    1834         }
    1835         return NULL;
    1836     }
    1837     return &pParent->Obj;
    1838 }
    1839 
    1840 
    1841 /**
    1842  * Looks up a UNC share, ANSI version.
    1843  *
    1844  * We keep both the server and share in the root directory entry.  This means we
    1845  * have to clean up the entry name before we can insert it.
    1846  *
    1847  * @returns Pointer to the share root directory or an update-to-date missing
    1848  *          node.
    1849  * @param   pCache              The cache.
    1850  * @param   pszPath             The path.
    1851  * @param   poff                Where to return the root dire.
    1852  * @param   penmError           Where to return details as to why the lookup
    1853  *                              failed.
    1854  */
    1855 static PKFSOBJ kFswCacheLookupUncShareA(PKFSCACHE pCache, const char *pszPath, KU32 *poff, KFSLOOKUPERROR *penmError)
    1856 {
    1857 #if 0 /* later */
    1858     KU32 offStartServer;
    1859     KU32 offEndServer;
    1860     KU32 offStartShare;
    1861 
    1862     KU32 offEnd = 2;
    1863     while (IS_SLASH(pszPath[offEnd]))
    1864         offEnd++;
    1865 
    1866     offStartServer = offEnd;
    1867     while (   (ch = pszPath[offEnd]) != '\0'
    1868            && !IS_SLASH(ch))
    1869         offEnd++;
    1870     offEndServer = offEnd;
    1871 
    1872     if (ch != '\0')
    1873     { /* likely */ }
    1874     else
    1875     {
    1876         *penmError = KFSLOOKUPERROR_NOT_FOUND;
    1877         return NULL;
    1878     }
    1879 
    1880     while (IS_SLASH(pszPath[offEnd]))
    1881         offEnd++;
    1882     offStartServer = offEnd;
    1883     while (   (ch = pszPath[offEnd]) != '\0'
    1884            && !IS_SLASH(ch))
    1885         offEnd++;
    1886 #endif
    1887     *penmError = KFSLOOKUPERROR_UNSUPPORTED;
    1888     return NULL;
    1889 }
    1890 
    1891 
    1892 /**
    1893  * Looks up a UNC share, UTF-16 version.
    1894  *
    1895  * We keep both the server and share in the root directory entry.  This means we
    1896  * have to clean up the entry name before we can insert it.
    1897  *
    1898  * @returns Pointer to the share root directory or an update-to-date missing
    1899  *          node.
    1900  * @param   pCache              The cache.
    1901  * @param   pwszPath            The path.
    1902  * @param   poff                Where to return the root dire.
    1903  * @param   penmError           Where to return details as to why the lookup
    1904  *                              failed.
    1905  */
    1906 static PKFSOBJ kFswCacheLookupUncShareW(PKFSCACHE pCache, const wchar_t *pwszPath, KU32 *poff, KFSLOOKUPERROR *penmError)
    1907 {
    1908 #if 0 /* later */
    1909     KU32 offStartServer;
    1910     KU32 offEndServer;
    1911     KU32 offStartShare;
    1912 
    1913     KU32 offEnd = 2;
    1914     while (IS_SLASH(pwszPath[offEnd]))
    1915         offEnd++;
    1916 
    1917     offStartServer = offEnd;
    1918     while (   (ch = pwszPath[offEnd]) != '\0'
    1919            && !IS_SLASH(ch))
    1920         offEnd++;
    1921     offEndServer = offEnd;
    1922 
    1923     if (ch != '\0')
    1924     { /* likely */ }
    1925     else
    1926     {
    1927         *penmError = KFSLOOKUPERROR_NOT_FOUND;
    1928         return NULL;
    1929     }
    1930 
    1931     while (IS_SLASH(pwszPath[offEnd]))
    1932         offEnd++;
    1933     offStartServer = offEnd;
    1934     while (   (ch = pwszPath[offEnd]) != '\0'
    1935            && !IS_SLASH(ch))
    1936         offEnd++;
    1937 #endif
    1938     *penmError = KFSLOOKUPERROR_UNSUPPORTED;
    1939     return NULL;
    1940 }
    1941 
    1942 
    1943 /**
    1944  * Walk the file system tree for the given absolute path, entering it into the
    1945  * hash table.
    1946  *
    1947  * This will create any missing nodes while walking.
    1948  *
    1949  * The caller will have to do the path hash table insertion of the result.
    1950  *
    1951  * @returns Pointer to the tree node corresponding to @a pszPath.
    1952  *          NULL on lookup failure, see @a penmError for details.
    1953  * @param   pCache              The cache.
    1954  * @param   pszPath             The path to walk.
    1955  * @param   cchPath             The length of the path.
    1956  * @param   penmError           Where to return details as to why the lookup
    1957  *                              failed.
    1958  */
    1959 static PKFSOBJ kFsCacheLookupAbsoluteA(PKFSCACHE pCache, const char *pszPath, KU32 cchPath, KFSLOOKUPERROR *penmError)
    1960 {
    1961     PKFSDIR     pParent = &pCache->RootDir;
    1962     PKFSOBJ     pChild;
    1963     KU32        off;
    1964     KU32        cchSlashes;
    1965     KU32        offEnd;
    1966 
    1967     KFSCACHE_LOG(("kFsCacheLookupAbsoluteA(%s)\n", pszPath));
    1968 
    1969     /*
    1970      * The root "directory" needs special handling, so we keep it outside the
    1971      * main search loop. (Special: Cannot enumerate it, UNCs, ++.)
    1972      */
    1973     cchSlashes = 0;
    1974     off        = 0;
    1975     if (   pszPath[1] == ':'
    1976         && IS_ALPHA(pszPath[0]))
    1977     {
    1978         /* Drive letter. */
    1979         offEnd = 2;
    1980         kHlpAssert(IS_SLASH(pszPath[2]));
    1981         pChild = kFswCacheLookupDrive(pCache, toupper(pszPath[0]), penmError);
    1982     }
    1983     else if (   IS_SLASH(pszPath[0])
    1984              && IS_SLASH(pszPath[1]) )
    1985         pChild = kFswCacheLookupUncShareA(pCache, pszPath, &offEnd, penmError);
    1986     else
    1987     {
    1988         *penmError = KFSLOOKUPERROR_UNSUPPORTED;
    1989         return NULL;
    1990     }
    1991     if (pChild)
    1992     { /* likely */ }
    1993     else
    1994         return NULL;
    1995 
    1996     /* Count slashes trailing the root spec. */
    1997     if (offEnd < cchPath)
    1998     {
    1999         kHlpAssert(IS_SLASH(pszPath[offEnd]));
    2000         do
    2001             cchSlashes++;
    2002         while (IS_SLASH(pszPath[offEnd + cchSlashes]));
    2003     }
    2004 
    2005     /* Done already? */
    2006     if (offEnd >= cchPath)
    2007     {
    2008         if (   pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
    2009             || pChild->uCacheGen == (pChild->bObjType != KFSOBJ_TYPE_MISSING ? pCache->uGeneration : pCache->uGenerationMissing)
    2010             || kFsCacheRefreshObj(pCache, pChild, penmError))
    2011             return kFsCacheObjRetainInternal(pChild);
    2012         return NULL;
    2013     }
    2014 
    2015     /* Check that we've got a valid result and not a cached negative one. */
    2016     if (pChild->bObjType == KFSOBJ_TYPE_DIR)
    2017     { /* likely */ }
    2018     else
    2019     {
    2020         kHlpAssert(pChild->bObjType == KFSOBJ_TYPE_MISSING);
    2021         kHlpAssert(pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE || pChild->uCacheGen == pCache->uGenerationMissing);
    2022         return pChild;
    2023     }
    2024 
    2025     /* Next component. */
    2026     pParent = (PKFSDIR)pChild;
    2027     off     = offEnd + cchSlashes;
    2028 
    2029 
    2030     /*
    2031      * Walk loop.
    2032      */
    2033     for (;;)
    2034     {
    2035         /*
    2036          * Find the end of the component, counting trailing slashes.
    2037          */
    2038         char ch;
    2039         cchSlashes = 0;
    2040         offEnd     = off + 1;
    2041         while ((ch = pszPath[offEnd]) != '\0')
    2042         {
    2043             if (!IS_SLASH(ch))
    2044                 offEnd++;
    2045             else
    2046             {
    2047                 do
    2048                     cchSlashes++;
    2049                 while (IS_SLASH(pszPath[offEnd + cchSlashes]));
    2050                 break;
    2051             }
    2052         }
    2053 
    2054         /*
    2055          * Do we need to populate or refresh this directory first?
    2056          */
    2057         if (   pParent->fPopulated
    2058             && (   pParent->Obj.uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
    2059                 || pParent->Obj.uCacheGen == pCache->uGeneration) )
    2060         { /* likely */ }
    2061         else if (kFsCachePopuplateOrRefreshDir(pCache, pParent, penmError))
    2062         { /* likely */ }
    2063         else
    2064             return NULL;
    2065 
    2066         /*
    2067          * Search the current node for the name.
    2068          *
    2069          * If we don't find it, we may insert a missing node depending on
    2070          * the cache configuration.
    2071          */
    2072         pChild = kFsCacheFindChildA(pCache, pParent, &pszPath[off], offEnd - off);
    2073         if (pChild != NULL)
    2074         { /* probably likely */ }
    2075         else
    2076         {
    2077             if (pCache->fFlags & KFSCACHE_F_MISSING_OBJECTS)
    2078                 pChild = kFsCacheCreateMissingA(pCache, pParent, &pszPath[off], offEnd - off, penmError);
    2079             if (cchSlashes == 0 || offEnd + cchSlashes >= cchPath)
    2080             {
    2081                 if (pChild)
    2082                     return pChild;
    2083                 *penmError = KFSLOOKUPERROR_NOT_FOUND;
    2084             }
    2085             else
    2086                 *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND;
    2087             return NULL;
    2088         }
    2089 
    2090         /* Advance off and check if we're done already. */
    2091         off = offEnd + cchSlashes;
    2092         if (   cchSlashes == 0
    2093             || off >= cchPath)
    2094         {
    2095             if (   pChild->bObjType != KFSOBJ_TYPE_MISSING
    2096                 || pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
    2097                 || pChild->uCacheGen == pCache->uGenerationMissing
    2098                 || kFsCacheRefreshMissing(pCache, pChild, penmError) )
    2099             { /* likely */ }
    2100             else
    2101                 return NULL;
    2102             return pChild;
    2103         }
    2104 
    2105         /*
    2106          * Check that it's a directory.  If a missing entry, we may have to
    2107          * refresh it and re-examin it.
    2108          */
    2109         if (pChild->bObjType == KFSOBJ_TYPE_DIR)
    2110             pParent = (PKFSDIR)pChild;
    2111         else if (pChild->bObjType != KFSOBJ_TYPE_MISSING)
    2112         {
    2113             *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_DIR;
    2114             return NULL;
    2115         }
    2116         else if (   pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
    2117                  || pChild->uCacheGen == pCache->uGenerationMissing)
    2118         {
    2119             *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND;
    2120             return NULL;
    2121         }
    2122         else if (kFsCacheRefreshMissingIntermediateDir(pCache, pChild, penmError))
    2123             pParent = (PKFSDIR)pChild;
    2124         else
    2125             return NULL;
    2126     }
    2127 
    2128     return NULL;
    2129 }
    2130 
    2131 
    2132 /**
    2133  * Walk the file system tree for the given absolute path, UTF-16 version.
    2134  *
    2135  * This will create any missing nodes while walking.
    2136  *
    2137  * The caller will have to do the path hash table insertion of the result.
    2138  *
    2139  * @returns Pointer to the tree node corresponding to @a pszPath.
    2140  *          NULL on lookup failure, see @a penmError for details.
    2141  * @param   pCache              The cache.
    2142  * @param   pwszPath            The path to walk.
    2143  * @param   cwcPath             The length of the path (in wchar_t's).
    2144  * @param   penmError           Where to return details as to why the lookup
    2145  *                              failed.
    2146  */
    2147 static PKFSOBJ kFsCacheLookupAbsoluteW(PKFSCACHE pCache, const wchar_t *pwszPath, KU32 cwcPath, KFSLOOKUPERROR *penmError)
    2148 {
    2149     PKFSDIR     pParent = &pCache->RootDir;
    2150     PKFSOBJ     pChild;
    2151     KU32        off;
    2152     KU32        cwcSlashes;
    2153     KU32        offEnd;
    2154 
    2155     KFSCACHE_LOG(("kFsCacheLookupAbsoluteW(%ls)\n", pwszPath));
    2156 
    2157     /*
    2158      * The root "directory" needs special handling, so we keep it outside the
    2159      * main search loop. (Special: Cannot enumerate it, UNCs, ++.)
    2160      */
    2161     cwcSlashes = 0;
    2162     off        = 0;
    2163     if (   pwszPath[1] == ':'
    2164         && IS_ALPHA(pwszPath[0]))
    2165     {
    2166         /* Drive letter. */
    2167         offEnd = 2;
    2168         kHlpAssert(IS_SLASH(pwszPath[2]));
    2169         pChild = kFswCacheLookupDrive(pCache, toupper(pwszPath[0]), penmError);
    2170     }
    2171     else if (   IS_SLASH(pwszPath[0])
    2172              && IS_SLASH(pwszPath[1]) )
    2173         pChild = kFswCacheLookupUncShareW(pCache, pwszPath, &offEnd, penmError);
    2174     else
    2175     {
    2176         *penmError = KFSLOOKUPERROR_UNSUPPORTED;
    2177         return NULL;
    2178     }
    2179     if (pChild)
    2180     { /* likely */ }
    2181     else
    2182         return NULL;
    2183 
    2184     /* Count slashes trailing the root spec. */
    2185     if (offEnd < cwcPath)
    2186     {
    2187         kHlpAssert(IS_SLASH(pwszPath[offEnd]));
    2188         do
    2189             cwcSlashes++;
    2190         while (IS_SLASH(pwszPath[offEnd + cwcSlashes]));
    2191     }
    2192 
    2193     /* Done already? */
    2194     if (offEnd >= cwcPath)
    2195     {
    2196         if (   pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
    2197             || pChild->uCacheGen == (pChild->bObjType != KFSOBJ_TYPE_MISSING ? pCache->uGeneration : pCache->uGenerationMissing)
    2198             || kFsCacheRefreshObj(pCache, pChild, penmError))
    2199             return kFsCacheObjRetainInternal(pChild);
    2200         return NULL;
    2201     }
    2202 
    2203     /* Check that we've got a valid result and not a cached negative one. */
    2204     if (pChild->bObjType == KFSOBJ_TYPE_DIR)
    2205     { /* likely */ }
    2206     else
    2207     {
    2208         kHlpAssert(pChild->bObjType == KFSOBJ_TYPE_MISSING);
    2209         kHlpAssert(pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE || pChild->uCacheGen == pCache->uGenerationMissing);
    2210         return pChild;
    2211     }
    2212 
    2213     /* Next component. */
    2214     pParent = (PKFSDIR)pChild;
    2215     off     = offEnd + cwcSlashes;
    2216 
    2217 
    2218     /*
    2219      * Walk loop.
    2220      */
    2221     for (;;)
    2222     {
    2223         /*
    2224          * Find the end of the component, counting trailing slashes.
    2225          */
    2226         wchar_t wc;
    2227         cwcSlashes = 0;
    2228         offEnd     = off + 1;
    2229         while ((wc = pwszPath[offEnd]) != '\0')
    2230         {
    2231             if (!IS_SLASH(wc))
    2232                 offEnd++;
    2233             else
    2234             {
    2235                 do
    2236                     cwcSlashes++;
    2237                 while (IS_SLASH(pwszPath[offEnd + cwcSlashes]));
    2238                 break;
    2239             }
    2240         }
    2241 
    2242         /*
    2243          * Do we need to populate or refresh this directory first?
    2244          */
    2245         if (   pParent->fPopulated
    2246             && (   pParent->Obj.uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
    2247                 || pParent->Obj.uCacheGen == pCache->uGeneration) )
    2248         { /* likely */ }
    2249         else if (kFsCachePopuplateOrRefreshDir(pCache, pParent, penmError))
    2250         { /* likely */ }
    2251         else
    2252             return NULL;
    2253 
    2254         /*
    2255          * Search the current node for the name.
    2256          *
    2257          * If we don't find it, we may insert a missing node depending on
    2258          * the cache configuration.
    2259          */
    2260         pChild = kFsCacheFindChildW(pCache, pParent, &pwszPath[off], offEnd - off);
    2261         if (pChild != NULL)
    2262         { /* probably likely */ }
    2263         else
    2264         {
    2265             if (pCache->fFlags & KFSCACHE_F_MISSING_OBJECTS)
    2266                 pChild = kFsCacheCreateMissingW(pCache, pParent, &pwszPath[off], offEnd - off, penmError);
    2267             if (cwcSlashes == 0 || offEnd + cwcSlashes >= cwcPath)
    2268             {
    2269                 if (pChild)
    2270                     return pChild;
    2271                 *penmError = KFSLOOKUPERROR_NOT_FOUND;
    2272             }
    2273             else
    2274                 *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND;
    2275             return NULL;
    2276         }
    2277 
    2278         /* Advance off and check if we're done already. */
    2279         off = offEnd + cwcSlashes;
    2280         if (   cwcSlashes == 0
    2281             || off >= cwcPath)
    2282         {
    2283             if (   pChild->bObjType != KFSOBJ_TYPE_MISSING
    2284                 || pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
    2285                 || pChild->uCacheGen == pCache->uGenerationMissing
    2286                 || kFsCacheRefreshMissing(pCache, pChild, penmError) )
    2287             { /* likely */ }
    2288             else
    2289                 return NULL;
    2290             return pChild;
    2291         }
    2292 
    2293         /*
    2294          * Check that it's a directory.  If a missing entry, we may have to
    2295          * refresh it and re-examin it.
    2296          */
    2297         if (pChild->bObjType == KFSOBJ_TYPE_DIR)
    2298             pParent = (PKFSDIR)pChild;
    2299         else if (pChild->bObjType != KFSOBJ_TYPE_MISSING)
    2300         {
    2301             *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_DIR;
    2302             return NULL;
    2303         }
    2304         else if (   pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
    2305                  || pChild->uCacheGen == pCache->uGenerationMissing)
    2306         {
    2307             *penmError = KFSLOOKUPERROR_PATH_COMP_NOT_FOUND;
    2308             return NULL;
    2309         }
    2310         else if (kFsCacheRefreshMissingIntermediateDir(pCache, pChild, penmError))
    2311             pParent = (PKFSDIR)pChild;
    2312         else
    2313             return NULL;
    2314     }
    2315 
    2316     return NULL;
    2317 }
    2318 
    2319 
    2320 /**
    2321  * This deals with paths that are relative and paths that contains '..'
    2322  * elements, ANSI version.
    2323  *
    2324  * @returns Pointer to object corresponding to @a pszPath on success.
    2325  *          NULL if this isn't a path we care to cache.
    2326  *
    2327  * @param   pCache              The cache.
    2328  * @param   pszPath             The path.
    2329  * @param   cchPath             The length of the path.
    2330  * @param   penmError           Where to return details as to why the lookup
    2331  *                              failed.
    2332  */
    2333 static PKFSOBJ kFsCacheLookupSlowA(PKFSCACHE pCache, const char *pszPath, KU32 cchPath, KFSLOOKUPERROR *penmError)
    2334 {
    2335     /*
    2336      * We just call GetFullPathNameA here to do the job as getcwd and _getdcwd
    2337      * ends up calling it anyway.
    2338      */
    2339     char szFull[KFSCACHE_CFG_MAX_PATH];
    2340     UINT cchFull = GetFullPathNameA(pszPath, sizeof(szFull), szFull, NULL);
    2341     if (   cchFull >= 3
    2342         && cchFull < sizeof(szFull))
    2343     {
    2344         PKFSOBJ pFsObj;
    2345         KFSCACHE_LOG(("kFsCacheLookupSlowA(%s)\n", pszPath));
    2346         pFsObj = kFsCacheLookupAbsoluteA(pCache, szFull, cchFull, penmError);
    2347 
    2348 #if 0 /* No need to do this until it's actually queried. */
    2349         /* Cache the resulting path. */
    2350         if (   pFsObj
    2351             || (pCache->fFlags & KFSCACHE_F_MISSING_PATHS)
    2352             || *penmError == KFSLOOKUPERROR_UNSUPPORTED)
    2353         {
    2354             KU32 uHashPath = kFsCacheStrHash(szFull);
    2355             kFsCacheCreatePathHashTabEntryA(pCache, pFsObj, pszPath, cchPath, uHashPath,
    2356                                             uHashPath % K_ELEMENTS(pCache->apAnsiPaths), *penmError);
    2357         }
    2358 #endif
    2359         return pFsObj;
    2360     }
    2361 
    2362     /* The path is too long! */
    2363     kHlpAssertMsgFailed(("'%s' -> cchFull=%u\n", pszPath, cchFull));
    2364     *penmError = KFSLOOKUPERROR_PATH_TOO_LONG;
    2365     return NULL;
    2366 }
    2367 
    2368 
    2369 /**
    2370  * This deals with paths that are relative and paths that contains '..'
    2371  * elements, UTF-16 version.
    2372  *
    2373  * @returns Pointer to object corresponding to @a pszPath on success.
    2374  *          NULL if this isn't a path we care to cache.
    2375  *
    2376  * @param   pCache              The cache.
    2377  * @param   pwszPath            The path.
    2378  * @param   cwcPath             The length of the path (in wchar_t's).
    2379  * @param   penmError           Where to return details as to why the lookup
    2380  *                              failed.
    2381  */
    2382 static PKFSOBJ kFsCacheLookupSlowW(PKFSCACHE pCache, const wchar_t *pwszPath, KU32 wcwPath, KFSLOOKUPERROR *penmError)
    2383 {
    2384     /*
    2385      * We just call GetFullPathNameA here to do the job as getcwd and _getdcwd
    2386      * ends up calling it anyway.
    2387      */
    2388     wchar_t wszFull[KFSCACHE_CFG_MAX_PATH];
    2389     UINT cwcFull = GetFullPathNameW(pwszPath, KFSCACHE_CFG_MAX_PATH, wszFull, NULL);
    2390     if (   cwcFull >= 3
    2391         && cwcFull < KFSCACHE_CFG_MAX_PATH)
    2392     {
    2393         PKFSOBJ pFsObj;
    2394         KFSCACHE_LOG(("kFsCacheLookupSlowA(%ls)\n", pwszPath));
    2395         pFsObj = kFsCacheLookupAbsoluteW(pCache, wszFull, cwcFull, penmError);
    2396 
    2397 #if 0 /* No need to do this until it's actually queried. */
    2398         /* Cache the resulting path. */
    2399         if (   pFsObj
    2400             || (pCache->fFlags & KFSCACHE_F_MISSING_PATHS)
    2401             || *penmError == KFSLOOKUPERROR_UNSUPPORTED)
    2402         {
    2403             KU32 uHashPath = kFsCacheStrHash(szFull);
    2404             kFsCacheCreatePathHashTabEntryA(pCache, pFsObj, pszPath, cchPath, uHashPath,
    2405                                             uHashPath % K_ELEMENTS(pCache->apAnsiPaths), *penmError);
    2406         }
    2407 #endif
    2408         return pFsObj;
    2409     }
    2410 
    2411     /* The path is too long! */
    2412     kHlpAssertMsgFailed(("'%ls' -> cwcFull=%u\n", pwszPath, cwcFull));
    2413     *penmError = KFSLOOKUPERROR_PATH_TOO_LONG;
    2414     return NULL;
    2415 }
    2416 
    2417 
    2418 /**
    2419  * Refreshes a path hash that has expired, ANSI version.
    2420  *
    2421  * @returns pHash on success, NULL if removed.
    2422  * @param   pCache              The cache.
    2423  * @param   pHashEntry          The path hash.
    2424  * @param   idxHashTab          The hash table entry.
    2425  */
    2426 static PKFSHASHA kFsCacheRefreshPathA(PKFSCACHE pCache, PKFSHASHA pHashEntry, KU32 idxHashTab)
    2427 {
    2428     /** @todo implement once we've start inserting uCacheGen nodes. */
    2429     __debugbreak();
    2430     K_NOREF(pCache);
    2431     K_NOREF(idxHashTab);
    2432     return pHashEntry;
    2433 }
    2434 
    2435 
    2436 /**
    2437  * Refreshes a path hash that has expired, UTF-16 version.
    2438  *
    2439  * @returns pHash on success, NULL if removed.
    2440  * @param   pCache              The cache.
    2441  * @param   pHashEntry          The path hash.
    2442  * @param   idxHashTab          The hash table entry.
    2443  */
    2444 static PKFSHASHW kFsCacheRefreshPathW(PKFSCACHE pCache, PKFSHASHW pHashEntry, KU32 idxHashTab)
    2445 {
    2446     /** @todo implement once we've start inserting uCacheGen nodes. */
    2447     __debugbreak();
    2448     K_NOREF(pCache);
    2449     K_NOREF(idxHashTab);
    2450     return pHashEntry;
    2451 }
    2452 
    2453 
    2454 /**
    2455  * Looks up a KFSOBJ for the given ANSI path.
    2456  *
    2457  * This will first try the hash table.  If not in the hash table, the file
    2458  * system cache tree is walked, missing bits filled in and finally a hash table
    2459  * entry is created.
    2460  *
    2461  * Only drive letter paths are cachable.  We don't do any UNC paths at this
    2462  * point.
    2463  *
    2464  * @returns Reference to object corresponding to @a pszPath on success, this
    2465  *          must be released by kwFsCacheRelease.
    2466  *          NULL if not a path we care to cache.
    2467  * @param   pCache              The cache.
    2468  * @param   pszPath             The path to lookup.
    2469  * @param   penmError           Where to return details as to why the lookup
    2470  *                              failed.
    2471  */
    2472 PKFSOBJ kFsCacheLookupA(PKFSCACHE pCache, const char *pszPath, KFSLOOKUPERROR *penmError)
    2473 {
    2474     /*
    2475      * Do hash table lookup of the path.
    2476      */
    2477     KU32        uHashPath;
    2478     KU32        cchPath    = (KU32)kFsCacheStrHashEx(pszPath, &uHashPath);
    2479     KU32        idxHashTab = uHashPath % K_ELEMENTS(pCache->apAnsiPaths);
    2480     PKFSHASHA   pHashEntry = pCache->apAnsiPaths[idxHashTab];
    2481     if (pHashEntry)
    2482     {
    2483         do
    2484         {
    2485             if (   pHashEntry->uHashPath == uHashPath
    2486                 && pHashEntry->cchPath   == cchPath
    2487                 && kHlpMemComp(pHashEntry->pszPath, pszPath, cchPath) == 0)
    2488             {
    2489                 if (   pHashEntry->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
    2490                     || pHashEntry->uCacheGen == pCache->uGeneration
    2491                     || (pHashEntry = kFsCacheRefreshPathA(pCache, pHashEntry, idxHashTab)) )
    2492                 {
    2493                     pCache->cLookups++;
    2494                     pCache->cPathHashHits++;
    2495                     KFSCACHE_LOG(("kFsCacheLookupA(%s) - hit %p\n", pszPath, pHashEntry->pFsObj));
    2496                     *penmError = pHashEntry->enmError;
    2497                     if (pHashEntry->pFsObj)
    2498                         return kFsCacheObjRetainInternal(pHashEntry->pFsObj);
    2499                     return NULL;
    2500                 }
    2501                 break;
    2502             }
    2503             pHashEntry = pHashEntry->pNext;
    2504         } while (pHashEntry);
    2505     }
    2506 
    2507     /*
    2508      * Create an entry for it by walking the file system cache and filling in the blanks.
    2509      */
    2510     if (   cchPath > 0
    2511         && cchPath < KFSCACHE_CFG_MAX_PATH)
    2512     {
    2513         PKFSOBJ pFsObj;
    2514 
    2515         /* Is absolute without any '..' bits? */
    2516         if (   cchPath >= 3
    2517             && (   (   pszPath[1] == ':'    /* Drive letter */
    2518                     && IS_SLASH(pszPath[2])
    2519                     && IS_ALPHA(pszPath[0]) )
    2520                 || (   IS_SLASH(pszPath[0]) /* UNC */
    2521                     && IS_SLASH(pszPath[1]) ) )
    2522             && !kFsCacheHasDotDotA(pszPath, cchPath) )
    2523             pFsObj = kFsCacheLookupAbsoluteA(pCache, pszPath, cchPath, penmError);
    2524         else
    2525             pFsObj = kFsCacheLookupSlowA(pCache, pszPath, cchPath, penmError);
    2526         if (   pFsObj
    2527             || (   (pCache->fFlags & KFSCACHE_F_MISSING_PATHS)
    2528                 && *penmError != KFSLOOKUPERROR_PATH_TOO_LONG)
    2529             || *penmError == KFSLOOKUPERROR_UNSUPPORTED )
    2530             kFsCacheCreatePathHashTabEntryA(pCache, pFsObj, pszPath, cchPath, uHashPath, idxHashTab, *penmError);
    2531 
    2532         pCache->cLookups++;
    2533         if (pFsObj)
    2534             pCache->cWalkHits++;
    2535         return pFsObj;
    2536     }
    2537 
    2538     *penmError = KFSLOOKUPERROR_PATH_TOO_LONG;
    2539     return NULL;
    2540 }
    2541 
    2542 
    2543 /**
    2544  * Looks up a KFSOBJ for the given UTF-16 path.
    2545  *
    2546  * This will first try the hash table.  If not in the hash table, the file
    2547  * system cache tree is walked, missing bits filled in and finally a hash table
    2548  * entry is created.
    2549  *
    2550  * Only drive letter paths are cachable.  We don't do any UNC paths at this
    2551  * point.
    2552  *
    2553  * @returns Reference to object corresponding to @a pszPath on success, this
    2554  *          must be released by kwFsCacheRelease.
    2555  *          NULL if not a path we care to cache.
    2556  * @param   pCache              The cache.
    2557  * @param   pwszPath            The path to lookup.
    2558  * @param   penmError           Where to return details as to why the lookup
    2559  *                              failed.
    2560  */
    2561 PKFSOBJ kFsCacheLookupW(PKFSCACHE pCache, const wchar_t *pwszPath, KFSLOOKUPERROR *penmError)
    2562 {
    2563     /*
    2564      * Do hash table lookup of the path.
    2565      */
    2566     KU32        uHashPath;
    2567     KU32        cwcPath    = (KU32)kFsCacheUtf16HashEx(pwszPath, &uHashPath);
    2568     KU32        idxHashTab = uHashPath % K_ELEMENTS(pCache->apAnsiPaths);
    2569     PKFSHASHW   pHashEntry = pCache->apUtf16Paths[idxHashTab];
    2570     if (pHashEntry)
    2571     {
    2572         do
    2573         {
    2574             if (   pHashEntry->uHashPath == uHashPath
    2575                 && pHashEntry->cwcPath   == cwcPath
    2576                 && kHlpMemComp(pHashEntry->pwszPath, pwszPath, cwcPath) == 0)
    2577             {
    2578                 if (   pHashEntry->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
    2579                     || pHashEntry->uCacheGen == pCache->uGeneration
    2580                     || (pHashEntry = kFsCacheRefreshPathW(pCache, pHashEntry, idxHashTab)) )
    2581                 {
    2582                     pCache->cLookups++;
    2583                     pCache->cPathHashHits++;
    2584                     KFSCACHE_LOG(("kFsCacheLookupW(%ls) - hit %p\n", pwszPath, pHashEntry->pFsObj));
    2585                     *penmError = pHashEntry->enmError;
    2586                     if (pHashEntry->pFsObj)
    2587                         return kFsCacheObjRetainInternal(pHashEntry->pFsObj);
    2588                     return NULL;
    2589                 }
    2590                 break;
    2591             }
    2592             pHashEntry = pHashEntry->pNext;
    2593         } while (pHashEntry);
    2594     }
    2595 
    2596     /*
    2597      * Create an entry for it by walking the file system cache and filling in the blanks.
    2598      */
    2599     if (   cwcPath > 0
    2600         && cwcPath < KFSCACHE_CFG_MAX_PATH)
    2601     {
    2602         PKFSOBJ pFsObj;
    2603 
    2604         /* Is absolute without any '..' bits? */
    2605         if (   cwcPath >= 3
    2606             && (   (   pwszPath[1] == ':'    /* Drive letter */
    2607                     && IS_SLASH(pwszPath[2])
    2608                     && IS_ALPHA(pwszPath[0]) )
    2609                 || (   IS_SLASH(pwszPath[0]) /* UNC */
    2610                     && IS_SLASH(pwszPath[1]) ) )
    2611             && !kFsCacheHasDotDotW(pwszPath, cwcPath) )
    2612             pFsObj = kFsCacheLookupAbsoluteW(pCache, pwszPath, cwcPath, penmError);
    2613         else
    2614             pFsObj = kFsCacheLookupSlowW(pCache, pwszPath, cwcPath, penmError);
    2615         if (   pFsObj
    2616             || (   (pCache->fFlags & KFSCACHE_F_MISSING_PATHS)
    2617                 && *penmError != KFSLOOKUPERROR_PATH_TOO_LONG)
    2618             || *penmError == KFSLOOKUPERROR_UNSUPPORTED )
    2619             kFsCacheCreatePathHashTabEntryW(pCache, pFsObj, pwszPath, cwcPath, uHashPath, idxHashTab, *penmError);
    2620 
    2621         pCache->cLookups++;
    2622         if (pFsObj)
    2623             pCache->cWalkHits++;
    2624         return pFsObj;
    2625     }
    2626 
    2627     *penmError = KFSLOOKUPERROR_PATH_TOO_LONG;
    2628     return NULL;
    2629 }
    2630 
    2631 
    2632 /**
    2633  * Destroys a cache object which has a zero reference count.
    2634  *
    2635  * @returns 0
    2636  * @param   pCache              The cache.
    2637  * @param   pObj                The object.
    2638  */
    2639 KU32 kFsCacheObjDestroy(PKFSCACHE pCache, PKFSOBJ pObj)
    2640 {
    2641     kHlpAssert(pObj->cRefs == 0);
    2642     kHlpAssert(pObj->pParent == NULL);
    2643 
    2644     switch (pObj->bObjType)
    2645     {
    2646         case KFSOBJ_TYPE_MISSING:
    2647         //case KFSOBJ_TYPE_MISSING | KFSOBJ_TYPE_F_INVALID:
    2648             /* nothing else to do here */
    2649             pCache->cbObjects -= sizeof(*pObj);
    2650             break;
    2651 
    2652         case KFSOBJ_TYPE_DIR:
    2653         //case KFSOBJ_TYPE_DIR | KFSOBJ_TYPE_F_INVALID:
    2654         case KFSOBJ_TYPE_FILE:
    2655         //case KFSOBJ_TYPE_FILE | KFSOBJ_TYPE_F_INVALID:
    2656             kHlpAssertFailed();
    2657             break;
    2658         default:
    2659             kHlpAssertFailed();
    2660     }
    2661     pCache->cObjects--;
    2662     free(pObj);
    2663     return 0;
    2664 }
    2665 
    2666 
    2667 /**
    2668  * Releases a reference to a cache object.
    2669  *
    2670  * @returns New reference count.
    2671  * @param   pCache              The cache.
    2672  * @param   pObj                The object.
    2673  */
    2674 KU32 kFsCacheObjRelease(PKFSCACHE pCache, PKFSOBJ pObj)
    2675 {
    2676     KU32 cRefs = --pObj->cRefs;
    2677     if (cRefs)
    2678         return cRefs;
    2679     return kFsCacheObjDestroy(pCache, pObj);
    2680 }
    2681 
    2682 
    2683 /**
    2684  * Retains a reference to a cahce object.
    2685  *
    2686  * @returns New reference count.
    2687  * @param   pObj                The object.
    2688  */
    2689 KU32 kFsCacheObjRetain(PKFSOBJ pObj)
    2690 {
    2691     KU32 cRefs = ++pObj->cRefs;
    2692     kHlpAssert(cRefs < 16384);
    2693     return cRefs;
    2694 }
    2695 
    2696 
    2697 
    2698 PKFSCACHE kFsCacheCreate(KU32 fFlags)
    2699 {
    2700     PKFSCACHE pCache;
    2701     birdResolveImports();
    2702 
    2703     pCache = (PKFSCACHE)kHlpAllocZ(sizeof(*pCache));
    2704     if (pCache)
    2705     {
    2706         /* Dummy root dir entry. */
    2707         pCache->RootDir.Obj.u32Magic        = KFSOBJ_MAGIC;
    2708         pCache->RootDir.Obj.cRefs           = 1;
    2709         pCache->RootDir.Obj.uCacheGen       = KFSWOBJ_CACHE_GEN_IGNORE;
    2710         pCache->RootDir.Obj.bObjType        = KFSOBJ_TYPE_DIR;
    2711         pCache->RootDir.Obj.fHaveStats      = K_FALSE;
    2712         pCache->RootDir.Obj.pParent         = NULL;
    2713         pCache->RootDir.Obj.pszName         = "";
    2714         pCache->RootDir.Obj.cchName         = 0;
    2715         pCache->RootDir.Obj.cchParent       = 0;
    2716 #ifdef KFSCACHE_CFG_UTF16
    2717         pCache->RootDir.Obj.cwcName         = 0;
    2718         pCache->RootDir.Obj.cwcParent       = 0;
    2719         pCache->RootDir.Obj.pwszName        = L"";
    2720 #endif
    2721 
    2722 #ifdef KFSCACHE_CFG_SHORT_NAMES
    2723         pCache->RootDir.Obj.pszShortName    = NULL;
    2724         pCache->RootDir.Obj.cchShortName    = 0;
    2725         pCache->RootDir.Obj.cchShortParent  = 0;
    2726 # ifdef KFSCACHE_CFG_UTF16
    2727         pCache->RootDir.Obj.cwcShortName;
    2728         pCache->RootDir.Obj.cwcShortParent;
    2729         pCache->RootDir.Obj.pwszShortName;
    2730 # endif
    2731 #endif
    2732         pCache->RootDir.cChildren           = 0;
    2733         pCache->RootDir.papChildren         = NULL;
    2734         pCache->RootDir.hDir                = INVALID_HANDLE_VALUE;
    2735         pCache->RootDir.cHashTab            = 251;
    2736         pCache->RootDir.paHashTab           = (PKFSOBJHASH)kHlpAllocZ(  pCache->RootDir.cHashTab
    2737                                                                       * sizeof(pCache->RootDir.paHashTab[0]));
    2738         if (pCache->RootDir.paHashTab)
    2739         {
    2740             /* The cache itself. */
    2741             pCache->u32Magic        = KFSCACHE_MAGIC;
    2742             pCache->fFlags          = fFlags;
    2743             pCache->uGeneration     = 1;
    2744             pCache->cObjects        = 1;
    2745             pCache->cbObjects       = sizeof(pCache->RootDir) + pCache->RootDir.cHashTab * sizeof(pCache->RootDir.paHashTab[0]);
    2746             pCache->cPathHashHits   = 0;
    2747             pCache->cWalkHits       = 0;
    2748             pCache->cAnsiPaths      = 0;
    2749             pCache->cAnsiPathCollisions = 0;
    2750             pCache->cbAnsiPaths     = 0;
    2751 #ifdef KFSCACHE_CFG_UTF16
    2752             pCache->cUtf16Paths     = 0;
    2753             pCache->cUtf16PathCollisions = 0;
    2754             pCache->cbUtf16Paths    = 0;
    2755 #endif
    2756             return pCache;
    2757         }
    2758 
    2759         kHlpFree(pCache);
    2760     }
    2761     return NULL;
    2762 }
    2763 
     396                                  wchar_t const *pwszShortName, KU32 cwcShortName,
     397#endif
     398                                  KU8 bObjType, KFSLOOKUPERROR *penmError);
     399PKFSOBJ     kFsCacheLookupA(PKFSCACHE pCache, const char *pszPath, KFSLOOKUPERROR *penmError);
     400PKFSOBJ     kFsCacheLookupW(PKFSCACHE pCache, const wchar_t *pwszPath, KFSLOOKUPERROR *penmError);
     401
     402KU32        kFsCacheObjRelease(PKFSCACHE pCache, PKFSOBJ pObj);
     403KU32        kFsCacheObjRetain(PKFSOBJ pObj);
     404
     405PKFSCACHE   kFsCacheCreate(KU32 fFlags);
     406void        kFsCacheDestroy(PKFSCACHE);
     407
     408#endif
  • trunk/src/lib/nt/ntdircache.c

    r2852 r2853  
    4949//#include <winternl.h>
    5050
    51 
    52 
    53 /*********************************************************************************************************************************
    54 *   Defined Constants And Macros                                                                                                 *
    55 *********************************************************************************************************************************/
    56 /** @def KFSCACHE_CFG_UTF16
    57  * Whether to compile in the UTF-16 names support. */
    58 #define KFSCACHE_CFG_UTF16                  1
    59 /** @def KFSCACHE_CFG_SHORT_NAMES
    60  * Whether to compile in the short name support. */
    61 #define KFSCACHE_CFG_SHORT_NAMES            1
    62 /** @def KFSCACHE_CFG_PATH_HASH_TAB_SIZE
    63  * Size of the path hash table. */
    64 #define KFSCACHE_CFG_PATH_HASH_TAB_SIZE     16381
    65 /** The max length paths we consider. */
    66 #define KFSCACHE_CFG_MAX_PATH               1024
    67 /** The max ANSI name length. */
    68 #define KFSCACHE_CFG_MAX_ANSI_NAME          (256*3 + 16)
    69 /** The max UTF-16 name length. */
    70 #define KFSCACHE_CFG_MAX_UTF16_NAME         (256*2 + 16)
    71 
    72 
    73 
    74 /** Special KFSOBJ::uCacheGen number indicating that it does not apply. */
    75 #define KFSWOBJ_CACHE_GEN_IGNORE            KU32_MAX
    76 
    77 /** @def KW_LOG
    78  * Generic logging.
    79  * @param a     Argument list for kFsCacheDbgPrintf  */
    80 #ifndef NDEBUG
    81 # define KFSCACHE_LOG(a) kFsCacheDbgPrintf a
    82 #else
    83 # define KFSCACHE_LOG(a) do { } while (0)
    84 #endif
    85 
    86 
    87 /** @name KFSOBJ_TYPE_XXX - KFSOBJ::bObjType
    88  * @{  */
    89 /** Directory, type KFSDIR. */
    90 #define KFSOBJ_TYPE_DIR         KU8_C(0x01)
    91 /** Regular file - type KFSOBJ. */
    92 #define KFSOBJ_TYPE_FILE        KU8_C(0x02)
    93 /** Other file - type KFSOBJ. */
    94 #define KFSOBJ_TYPE_OTHER       KU8_C(0x03)
    95 /** Caching of a negative result - type KFSOBJ.
    96  * @remarks We will allocate enough space for the largest cache node, so this
    97  *          can metamorph into any other object should it actually turn up.  */
    98 #define KFSOBJ_TYPE_MISSING     KU8_C(0x04)
    99 ///** Invalidated entry flag. */
    100 //#define KFSOBJ_TYPE_F_INVALID   KU8_C(0x20)
    101 /** @} */
    102 
    103 /** @name KFSOBJ_F_XXX - KFSOBJ::fFlags
    104  * @{ */
    105 /** Whether the file system update the modified timestamp of directories
    106  * when something is removed from it or added to it.
    107  * @remarks They say NTFS is the only windows filesystem doing this.  */
    108 #define KFSOBJ_F_WORKING_DIR_MTIME      KU32_C(0x00000001)
    109 /** NTFS file system volume. */
    110 #define KFSOBJ_F_NTFS                   KU32_C(0x80000000)
    111 /** @} */
    112 
    113 
    114 #define IS_ALPHA(ch) ( ((ch) >= 'A' && (ch) <= 'Z') || ((ch) >= 'a' && (ch) <= 'z') )
    115 #define IS_SLASH(ch) ((ch) == '\\' || (ch) == '/')
    116 
    117 
    118 /*********************************************************************************************************************************
    119 *   Structures and Typedefs                                                                                                      *
    120 *********************************************************************************************************************************/
    121 /** Pointer to a core object.  */
    122 typedef struct KFSOBJ *PKFSOBJ;
    123 /** Pointer to a directory object.  */
    124 typedef struct KFSDIR *PKFSDIR;
    125 /** Pointer to a directory hash table entry. */
    126 typedef struct KFSOBJHASH *PKFSOBJHASH;
    127 
    128 
    129 /**
    130  * Directory hash table entry.
    131  *
    132  * There can be two of these per directory entry when the short name differs
    133  * from the long name.
    134  */
    135 typedef struct KFSOBJHASH
    136 {
    137     /** Pointer to the next entry with the same hash. */
    138     PKFSOBJHASH         pNext;
    139     /** Pointer to the object. */
    140     PKFSOBJ             pObj;
    141 } KFSOBJHASH;
    142 
    143 
    144 /**
    145  * Base cache node.
    146  */
    147 typedef struct KFSOBJ
    148 {
    149     /** Magic value (KFSOBJ_MAGIC). */
    150     KU32                u32Magic;
    151     /** Number of references. */
    152     KU32 volatile       cRefs;
    153     /** The cache generation, see KFSWOBJ_CACHE_GEN_IGNORE. */
    154     KU32                uCacheGen;
    155     /** The object type, KFSOBJ_TYPE_XXX.   */
    156     KU8                 bObjType;
    157     /** Set if the Stats member is valid, clear if not. */
    158     KBOOL               fHaveStats;
    159     /** Unused flags. */
    160     KBOOL               abUnused[2];
    161     /** Flags, KFSOBJ_F_XXX. */
    162     KU32                fFlags;
    163 
    164     /** Pointer to the parent (directory).
    165      * This is only NULL for a root. */
    166     PKFSDIR             pParent;
    167 
    168     /** The directory name.  (Allocated after the structure.) */
    169     const char         *pszName;
    170     /** The length of pszName. */
    171     KU16                cchName;
    172     /** The length of the parent path (up to where pszName starts).
    173      * @note This is valuable when constructing an absolute path to this node by
    174      *       means of the parent pointer (no need for recursion). */
    175     KU16                cchParent;
    176 #ifdef KFSCACHE_CFG_UTF16
    177     /** The length of pwszName (in wchar_t's). */
    178     KU16                cwcName;
    179     /** The length of the parent UTF-16 path (in wchar_t's).
    180      * @note This is valuable when constructing an absolute path to this node by
    181      *       means of the parent pointer (no need for recursion). */
    182     KU16                cwcParent;
    183     /** The UTF-16 object name.  (Allocated after the structure.) */
    184     const wchar_t      *pwszName;
    185 #endif
    186 
    187 #ifdef KFSCACHE_CFG_SHORT_NAMES
    188     /** The short object name.  (Allocated after the structure, could be same
    189      *  as pszName.) */
    190     const char         *pszShortName;
    191     /** The length of pszShortName. */
    192     KU16                cchShortName;
    193     /** The length of the short parent path (up to where pszShortName starts). */
    194     KU16                cchShortParent;
    195 # ifdef KFSCACHE_CFG_UTF16
    196     /** The length of pwszShortName (in wchar_t's). */
    197     KU16                cwcShortName;
    198     /** The length of the short parent UTF-16 path (in wchar_t's). */
    199     KU16                cwcShortParent;
    200     /** The UTF-16 short object name.  (Allocated after the structure, possibly
    201      *  same as pwszName.) */
    202     const wchar_t      *pwszShortName;
    203 # endif
    204 #endif
    205 
    206     /** Stats - only valid when fHaveStats is set. */
    207     BirdStat_T          Stats;
    208 } KFSOBJ;
    209 
    210 /** The magic for a KFSOBJ structure (Thelonious Sphere Monk). */
    211 #define KFSOBJ_MAGIC                KU32_C(0x19171010)
    212 
    213 
    214 /**
    215  * Directory node in the cache.
    216  */
    217 typedef struct KFSDIR
    218 {
    219     /** The core object information. */
    220     KFSOBJ             Obj;
    221 
    222     /** Child objects. */
    223     PKFSOBJ            *papChildren;
    224     /** The number of child objects. */
    225     KU32                cChildren;
    226 
    227     /** The size of the hash table.
    228      * @remarks The hash table is optional and only used when there are a lot of
    229      *          entries in the directory. */
    230     KU32                cHashTab;
    231     /** Pointer to the hash table.
    232      * @todo this isn't quite there yet, structure wise. sigh.  */
    233     PKFSOBJHASH         paHashTab;
    234 
    235     /** Handle to the directory (we generally keep it open). */
    236     HANDLE              hDir;
    237     /** The device number we queried/inherited when opening it. */
    238     KU64                uDevNo;
    239 
    240     /** Set if populated. */
    241     KBOOL               fPopulated;
    242 } KFSDIR;
    243 
    244 
    245 /**
    246  * Lookup errors.
    247  */
    248 typedef enum KFSLOOKUPERROR
    249 {
    250     /** Lookup was a success. */
    251     KFSLOOKUPERROR_SUCCESS = 0,
    252     /** A path component was not found. */
    253     KFSLOOKUPERROR_PATH_COMP_NOT_FOUND,
    254     /** A path component is not a directory. */
    255     KFSLOOKUPERROR_PATH_COMP_NOT_DIR,
    256     /** The final path entry is not a directory (trailing slash). */
    257     KFSLOOKUPERROR_NOT_DIR,
    258     /** Not found. */
    259     KFSLOOKUPERROR_NOT_FOUND,
    260     /** The path is too long. */
    261     KFSLOOKUPERROR_PATH_TOO_LONG,
    262     /** Unsupported path type. */
    263     KFSLOOKUPERROR_UNSUPPORTED,
    264     /** We're out of memory. */
    265     KFSLOOKUPERROR_OUT_OF_MEMORY,
    266 
    267     /** Error opening directory. */
    268     KFSLOOKUPERROR_DIR_OPEN_ERROR,
    269     /** Error reading directory. */
    270     KFSLOOKUPERROR_DIR_READ_ERROR,
    271     /** UTF-16 to ANSI conversion error. */
    272     KFSLOOKUPERROR_ANSI_CONVERSION_ERROR,
    273     /** ANSI to UTF-16 conversion error. */
    274     KFSLOOKUPERROR_UTF16_CONVERSION_ERROR,
    275     /** Internal error. */
    276     KFSLOOKUPERROR_INTERNAL_ERROR
    277 } KFSLOOKUPERROR;
    278 
    279 
    280 /** Pointer to an ANSI path hash table entry. */
    281 typedef struct KFSHASHA *PKFSHASHA;
    282 /**
    283  * ANSI file system path hash table entry.
    284  * The path hash table allows us to skip parsing and walking a path.
    285  */
    286 typedef struct KFSHASHA
    287 {
    288     /** Next entry with the same hash table slot. */
    289     PKFSHASHA           pNext;
    290     /** Path hash value. */
    291     KU32                uHashPath;
    292     /** The path length. */
    293     KU32                cchPath;
    294     /** The cache generation ID. */
    295     KU32                uCacheGen;
    296     /** The lookup error (when pFsObj is NULL). */
    297     KFSLOOKUPERROR      enmError;
    298     /** The path.  (Allocated after the structure.) */
    299     const char         *pszPath;
    300     /** Pointer to the matching FS object.
    301      * This is NULL for negative path entries? */
    302     PKFSOBJ             pFsObj;
    303 } KFSHASHA;
    304 
    305 
    306 #ifdef KFSCACHE_CFG_UTF16
    307 /** Pointer to an UTF-16 path hash table entry. */
    308 typedef struct KFSHASHW *PKFSHASHW;
    309 /**
    310  * UTF-16 file system path hash table entry. The path hash table allows us
    311  * to skip parsing and walking a path.
    312  */
    313 typedef struct KFSHASHW
    314 {
    315     /** Next entry with the same hash table slot. */
    316     PKFSHASHW           pNext;
    317     /** Path hash value. */
    318     KU32                uHashPath;
    319     /** The path length (in wchar_t units). */
    320     KU32                cwcPath;
    321     /** The cache generation ID. */
    322     KU32                uCacheGen;
    323     /** The lookup error (when pFsObj is NULL). */
    324     KFSLOOKUPERROR      enmError;
    325     /** The path.  (Allocated after the structure.) */
    326     const wchar_t      *pwszPath;
    327     /** Pointer to the matching FS object.
    328      * This is NULL for negative path entries? */
    329     PKFSOBJ             pFsObj;
    330 } KFSHASHW;
    331 #endif
    332 
    333 
    334 /** @name KFSCACHE_F_XXX
    335  * @{ */
    336 /** Whether to cache missing directory entries (KFSOBJ_TYPE_MISSING). */
    337 #define KFSCACHE_F_MISSING_OBJECTS  KU32_C(0x00000001)
    338 /** Whether to cache missing paths. */
    339 #define KFSCACHE_F_MISSING_PATHS    KU32_C(0x00000002)
    340 /** @} */
    341 
    342 
    343 /** Pointer to a cache.   */
    344 typedef struct KFSCACHE *PKFSCACHE;
    345 /**
    346  * Directory cache instance.
    347  */
    348 typedef struct KFSCACHE
    349 {
    350     /** Magic value (KFSCACHE_MAGIC). */
    351     KU32                u32Magic;
    352     /** Cache flags. */
    353     KU32                fFlags;
    354 
    355     /** The current cache generation for objects that already exists. */
    356     KU32                uGeneration;
    357     /** The current cache generation for missing objects, negative results, ++. */
    358     KU32                uGenerationMissing;
    359 
    360     /** Number of cache objects. */
    361     KSIZE               cObjects;
    362     /** Memory occupied by the cache object structures. */
    363     KSIZE               cbObjects;
    364     /** Number of lookups. */
    365     KSIZE               cLookups;
    366     /** Number of hits in the path hash tables. */
    367     KSIZE               cPathHashHits;
    368     /** Number of hits walking the file system hierarchy. */
    369     KSIZE               cWalkHits;
    370 
    371     /** The root directory. */
    372     KFSDIR              RootDir;
    373 
    374     /** File system hash table for ANSI filename strings. */
    375     PKFSHASHA           apAnsiPaths[KFSCACHE_CFG_PATH_HASH_TAB_SIZE];
    376     /** Number of paths in the apAnsiPaths hash table. */
    377     KSIZE               cAnsiPaths;
    378     /** Number of collisions in the apAnsiPaths hash table. */
    379     KSIZE               cAnsiPathCollisions;
    380     /** Amount of memory used by the path entries. */
    381     KSIZE               cbAnsiPaths;
    382 
    383 #ifdef KFSCACHE_CFG_UTF16
    384     /** Number of paths in the apUtf16Paths hash table. */
    385     KSIZE               cUtf16Paths;
    386     /** Number of collisions in the apUtf16Paths hash table. */
    387     KSIZE               cUtf16PathCollisions;
    388     /** Amount of memory used by the UTF-16 path entries. */
    389     KSIZE               cbUtf16Paths;
    390     /** File system hash table for UTF-16 filename strings. */
    391     PKFSHASHW           apUtf16Paths[KFSCACHE_CFG_PATH_HASH_TAB_SIZE];
    392 #endif
    393 } KFSCACHE;
    394 
    395 /** Magic value for KFSCACHE::u32Magic (Jon Batiste).  */
    396 #define KFSCACHE_MAGIC              KU32_C(0x19861111)
    397 
    398 
    399 /*********************************************************************************************************************************
    400 *   Internal Functions                                                                                                           *
    401 *********************************************************************************************************************************/
    402 KU32 kFsCacheObjRelease(PKFSCACHE pCache, PKFSOBJ pObj);
     51#include "kFsCache.h"
     52
     53
     54
    40355
    40456
     
    42577 * @param   ...                 Format argument.
    42678 */
    427 static void kFsCacheDbgPrintfV(const char *pszFormat, va_list va)
     79void kFsCacheDbgPrintfV(const char *pszFormat, va_list va)
    42880{
    42981    if (1)
     
    44496 * @param   ...                 Format argument.
    44597 */
    446 static void kFsCacheDbgPrintf(const char *pszFormat, ...)
     98void kFsCacheDbgPrintf(const char *pszFormat, ...)
    44799{
    448100    if (1)
     
    927579            pHashEntry->uCacheGen = pCache->uGenerationMissing;
    928580        else
    929             pHashEntry->uCacheGen = KFSWOBJ_CACHE_GEN_IGNORE;
     581            pHashEntry->uCacheGen = KFSOBJ_CACHE_GEN_IGNORE;
    930582
    931583        pHashEntry->pNext = pCache->apAnsiPaths[idxHashTab];
     
    969621            pHashEntry->uCacheGen = pCache->uGenerationMissing;
    970622        else
    971             pHashEntry->uCacheGen = KFSWOBJ_CACHE_GEN_IGNORE;
     623            pHashEntry->uCacheGen = KFSOBJ_CACHE_GEN_IGNORE;
    972624
    973625        pHashEntry->pNext = pCache->apUtf16Paths[idxHashTab];
     
    1026678 * @param   penmError       Where to explain failures.
    1027679 */
    1028 static PKFSOBJ kFsCacheCreateObject(PKFSCACHE pCache, PKFSDIR pParent,
    1029                                     char const *pszName, KU16 cchName, wchar_t const *pwszName, KU16 cwcName,
     680PKFSOBJ kFsCacheCreateObject(PKFSCACHE pCache, PKFSDIR pParent,
     681                             char const *pszName, KU16 cchName, wchar_t const *pwszName, KU16 cwcName,
    1030682#ifdef KFSCACHE_CFG_SHORT_NAMES
    1031                                     char const *pszShortName, KU16 cchShortName, wchar_t const *pwszShortName, KU16 cwcShortName,
    1032 #endif
    1033                                     KU8 bObjType, KFSLOOKUPERROR *penmError)
     683                             char const *pszShortName, KU16 cchShortName, wchar_t const *pwszShortName, KU16 cwcShortName,
     684#endif
     685                             KU8 bObjType, KFSLOOKUPERROR *penmError)
    1034686{
    1035687    /*
     
    1149801 * @param   penmError       Where to explain failures.
    1150802 */
    1151 static PKFSOBJ kFsCacheCreateObjectW(PKFSCACHE pCache, PKFSDIR pParent, wchar_t const *pwszName, KU32 cwcName,
     803PKFSOBJ kFsCacheCreateObjectW(PKFSCACHE pCache, PKFSDIR pParent, wchar_t const *pwszName, KU32 cwcName,
    1152804#ifdef KFSCACHE_CFG_SHORT_NAMES
    1153                                      wchar_t const *pwszShortName, KU32 cwcShortName,
    1154 #endif
    1155                                      KU8 bObjType, KFSLOOKUPERROR *penmError)
     805                              wchar_t const *pwszShortName, KU32 cwcShortName,
     806#endif
     807                              KU8 bObjType, KFSLOOKUPERROR *penmError)
    1156808{
    1157809    /* Convert names to ANSI first so we know their lengths. */
     
    20061658    if (offEnd >= cchPath)
    20071659    {
    2008         if (   pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
     1660        if (   pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
    20091661            || pChild->uCacheGen == (pChild->bObjType != KFSOBJ_TYPE_MISSING ? pCache->uGeneration : pCache->uGenerationMissing)
    20101662            || kFsCacheRefreshObj(pCache, pChild, penmError))
     
    20191671    {
    20201672        kHlpAssert(pChild->bObjType == KFSOBJ_TYPE_MISSING);
    2021         kHlpAssert(pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE || pChild->uCacheGen == pCache->uGenerationMissing);
     1673        kHlpAssert(pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE || pChild->uCacheGen == pCache->uGenerationMissing);
    20221674        return pChild;
    20231675    }
     
    20561708         */
    20571709        if (   pParent->fPopulated
    2058             && (   pParent->Obj.uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
     1710            && (   pParent->Obj.uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
    20591711                || pParent->Obj.uCacheGen == pCache->uGeneration) )
    20601712        { /* likely */ }
     
    20941746        {
    20951747            if (   pChild->bObjType != KFSOBJ_TYPE_MISSING
    2096                 || pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
     1748                || pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
    20971749                || pChild->uCacheGen == pCache->uGenerationMissing
    20981750                || kFsCacheRefreshMissing(pCache, pChild, penmError) )
     
    21141766            return NULL;
    21151767        }
    2116         else if (   pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
     1768        else if (   pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
    21171769                 || pChild->uCacheGen == pCache->uGenerationMissing)
    21181770        {
     
    21941846    if (offEnd >= cwcPath)
    21951847    {
    2196         if (   pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
     1848        if (   pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
    21971849            || pChild->uCacheGen == (pChild->bObjType != KFSOBJ_TYPE_MISSING ? pCache->uGeneration : pCache->uGenerationMissing)
    21981850            || kFsCacheRefreshObj(pCache, pChild, penmError))
     
    22071859    {
    22081860        kHlpAssert(pChild->bObjType == KFSOBJ_TYPE_MISSING);
    2209         kHlpAssert(pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE || pChild->uCacheGen == pCache->uGenerationMissing);
     1861        kHlpAssert(pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE || pChild->uCacheGen == pCache->uGenerationMissing);
    22101862        return pChild;
    22111863    }
     
    22441896         */
    22451897        if (   pParent->fPopulated
    2246             && (   pParent->Obj.uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
     1898            && (   pParent->Obj.uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
    22471899                || pParent->Obj.uCacheGen == pCache->uGeneration) )
    22481900        { /* likely */ }
     
    22821934        {
    22831935            if (   pChild->bObjType != KFSOBJ_TYPE_MISSING
    2284                 || pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
     1936                || pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
    22851937                || pChild->uCacheGen == pCache->uGenerationMissing
    22861938                || kFsCacheRefreshMissing(pCache, pChild, penmError) )
     
    23021954            return NULL;
    23031955        }
    2304         else if (   pChild->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
     1956        else if (   pChild->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
    23051957                 || pChild->uCacheGen == pCache->uGenerationMissing)
    23061958        {
     
    24872139                && kHlpMemComp(pHashEntry->pszPath, pszPath, cchPath) == 0)
    24882140            {
    2489                 if (   pHashEntry->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
     2141                if (   pHashEntry->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
    24902142                    || pHashEntry->uCacheGen == pCache->uGeneration
    24912143                    || (pHashEntry = kFsCacheRefreshPathA(pCache, pHashEntry, idxHashTab)) )
     
    25762228                && kHlpMemComp(pHashEntry->pwszPath, pwszPath, cwcPath) == 0)
    25772229            {
    2578                 if (   pHashEntry->uCacheGen == KFSWOBJ_CACHE_GEN_IGNORE
     2230                if (   pHashEntry->uCacheGen == KFSOBJ_CACHE_GEN_IGNORE
    25792231                    || pHashEntry->uCacheGen == pCache->uGeneration
    25802232                    || (pHashEntry = kFsCacheRefreshPathW(pCache, pHashEntry, idxHashTab)) )
     
    27072359        pCache->RootDir.Obj.u32Magic        = KFSOBJ_MAGIC;
    27082360        pCache->RootDir.Obj.cRefs           = 1;
    2709         pCache->RootDir.Obj.uCacheGen       = KFSWOBJ_CACHE_GEN_IGNORE;
     2361        pCache->RootDir.Obj.uCacheGen       = KFSOBJ_CACHE_GEN_IGNORE;
    27102362        pCache->RootDir.Obj.bObjType        = KFSOBJ_TYPE_DIR;
    27112363        pCache->RootDir.Obj.fHaveStats      = K_FALSE;
Note: See TracChangeset for help on using the changeset viewer.