1 /* $Id: kFsCache.h 2967 2016-09-26 18:14:13Z bird $ */
2 /** @file
3  * kFsCache.c - NT directory content cache.
4  */
5 
6 /*
7  * Copyright (c) 2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a
10  * copy of this software and associated documentation files (the "Software"),
11  * to deal in the Software without restriction, including without limitation
12  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13  * and/or sell copies of the Software, and to permit persons to whom the
14  * Software is furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included
17  * in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25  * IN THE SOFTWARE.
26  *
27  * Alternatively, the content of this file may be used under the terms of the
28  * GPL version 2 or later, or LGPL version 2.1 or later.
29  */
30 
31 #ifndef ___lib_nt_kFsCache_h___
32 #define ___lib_nt_kFsCache_h___
33 
34 
35 #include <k/kHlp.h>
36 #include "ntstat.h"
37 #ifndef NDEBUG
38 # include <stdarg.h>
39 #endif
40 
41 
42 /** @def KFSCACHE_CFG_UTF16
43  * Whether to compile in the UTF-16 names support. */
44 #define KFSCACHE_CFG_UTF16                  1
45 /** @def KFSCACHE_CFG_SHORT_NAMES
46  * Whether to compile in the short name support. */
47 #define KFSCACHE_CFG_SHORT_NAMES            1
48 /** @def KFSCACHE_CFG_PATH_HASH_TAB_SIZE
49  * Size of the path hash table. */
50 #define KFSCACHE_CFG_PATH_HASH_TAB_SIZE     99991
51 /** The max length paths we consider. */
52 #define KFSCACHE_CFG_MAX_PATH               1024
53 /** The max ANSI name length. */
54 #define KFSCACHE_CFG_MAX_ANSI_NAME          (256*3 + 16)
55 /** The max UTF-16 name length. */
56 #define KFSCACHE_CFG_MAX_UTF16_NAME         (256*2 + 16)
57 
58 
59 
60 /** Special KFSOBJ::uCacheGen number indicating that it does not apply. */
61 #define KFSOBJ_CACHE_GEN_IGNORE             KU32_MAX
62 
63 
64 /** @name KFSOBJ_TYPE_XXX - KFSOBJ::bObjType
65  * @{  */
66 /** Directory, type KFSDIR. */
67 #define KFSOBJ_TYPE_DIR         KU8_C(0x01)
68 /** Regular file - type KFSOBJ. */
69 #define KFSOBJ_TYPE_FILE        KU8_C(0x02)
70 /** Other file - type KFSOBJ. */
71 #define KFSOBJ_TYPE_OTHER       KU8_C(0x03)
72 /** Caching of a negative result - type KFSOBJ.
73  * @remarks We will allocate enough space for the largest cache node, so this
74  *          can metamorph into any other object should it actually turn up.  */
75 #define KFSOBJ_TYPE_MISSING     KU8_C(0x04)
76 ///** Invalidated entry flag. */
77 //#define KFSOBJ_TYPE_F_INVALID   KU8_C(0x20)
78 /** @} */
79 
80 /** @name KFSOBJ_F_XXX - KFSOBJ::fFlags
81  * @{ */
82  /** Use custom generation.
83   * @remarks This is given the value 1, as we use it as an index into
84   *          KFSCACHE::auGenerations, 0 being the default. */
85 #define KFSOBJ_F_USE_CUSTOM_GEN         KU32_C(0x00000001)
86 
87 /** Whether the file system update the modified timestamp of directories
88  * when something is removed from it or added to it.
89  * @remarks They say NTFS is the only windows filesystem doing this.  */
90 #define KFSOBJ_F_WORKING_DIR_MTIME      KU32_C(0x00000002)
91 /** NTFS file system volume. */
92 #define KFSOBJ_F_NTFS                   KU32_C(0x80000000)
93 /** Flags that are automatically inherited. */
94 #define KFSOBJ_F_INHERITED_MASK         KU32_C(0xffffffff)
95 /** @} */
96 
97 
98 #define IS_ALPHA(ch) ( ((ch) >= 'A' && (ch) <= 'Z') || ((ch) >= 'a' && (ch) <= 'z') )
99 #define IS_SLASH(ch) ((ch) == '\\' || (ch) == '/')
100 
101 
102 
103 
104 /** Pointer to a cache. */
105 typedef struct KFSCACHE *PKFSCACHE;
106 /** Pointer to a core object.  */
107 typedef struct KFSOBJ *PKFSOBJ;
108 /** Pointer to a directory object.  */
109 typedef struct KFSDIR *PKFSDIR;
110 /** Pointer to a directory hash table entry. */
111 typedef struct KFSOBJHASH *PKFSOBJHASH;
112 
113 
114 
115 /** Pointer to a user data item. */
116 typedef struct KFSUSERDATA *PKFSUSERDATA;
117 /**
118  * User data item associated with a cache node.
119  */
120 typedef struct KFSUSERDATA
121 {
122     /** Pointer to the next piece of user data. */
123     PKFSUSERDATA    pNext;
124     /** The key identifying this user. */
125     KUPTR           uKey;
126     /** The destructor. */
127     void (*pfnDestructor)(PKFSCACHE pCache, PKFSOBJ pObj, PKFSUSERDATA pData);
128 } KFSUSERDATA;
129 
130 
131 /**
132  * Storage for name strings for the unlikely event that they should grow in
133  * length after the KFSOBJ was created.
134  */
135 typedef struct KFSOBJNAMEALLOC
136 {
137     /** Size of the allocation. */
138     KU32        cb;
139     /** The space for names. */
140     char        abSpace[1];
141 } KFSOBJNAMEALLOC;
142 /** Name growth allocation. */
143 typedef KFSOBJNAMEALLOC *PKFSOBJNAMEALLOC;
144 
145 
146 /**
147  * Base cache node.
148  */
149 typedef struct KFSOBJ
150 {
151     /** Magic value (KFSOBJ_MAGIC). */
152     KU32                u32Magic;
153     /** Number of references. */
154     KU32 volatile       cRefs;
155     /** The cache generation, see KFSOBJ_CACHE_GEN_IGNORE. */
156     KU32                uCacheGen;
157     /** The object type, KFSOBJ_TYPE_XXX.   */
158     KU8                 bObjType;
159     /** Set if the Stats member is valid, clear if not. */
160     KBOOL               fHaveStats;
161     /** Unused flags. */
162     KBOOL               abUnused[2];
163     /** Flags, KFSOBJ_F_XXX. */
164     KU32                fFlags;
165 
166     /** Hash value of the name inserted into the parent hash table.
167      * This is 0 if not inserted.  Names are only hashed and inserted as they are
168      * first found thru linear searching of its siblings, and which name it is
169      * dependens on the lookup function (W or A) and whether the normal name or
170      * short name seems to have matched.
171      *
172      * @note It was ruled out as too much work to hash and track all four names,
173      *       so instead this minimalist approach was choosen in stead. */
174     KU32                uNameHash;
175     /** Pointer to the next child with the same name hash value. */
176     PKFSOBJ             pNextNameHash;
177     /** Pointer to the parent (directory).
178      * This is only NULL for a root. */
179     PKFSDIR             pParent;
180 
181     /** The directory name.  (Allocated after the structure.) */
182     const char         *pszName;
183     /** The length of pszName. */
184     KU16                cchName;
185     /** The length of the parent path (up to where pszName starts).
186      * @note This is valuable when constructing an absolute path to this node by
187      *       means of the parent pointer (no need for recursion). */
188     KU16                cchParent;
189 #ifdef KFSCACHE_CFG_UTF16
190     /** The length of pwszName (in wchar_t's). */
191     KU16                cwcName;
192     /** The length of the parent UTF-16 path (in wchar_t's).
193      * @note This is valuable when constructing an absolute path to this node by
194      *       means of the parent pointer (no need for recursion). */
195     KU16                cwcParent;
196     /** The UTF-16 object name.  (Allocated after the structure.) */
197     const wchar_t      *pwszName;
198 #endif
199 
200 #ifdef KFSCACHE_CFG_SHORT_NAMES
201     /** The short object name.  (Allocated after the structure, could be same
202      *  as pszName.) */
203     const char         *pszShortName;
204     /** The length of pszShortName. */
205     KU16                cchShortName;
206     /** The length of the short parent path (up to where pszShortName starts). */
207     KU16                cchShortParent;
208 # ifdef KFSCACHE_CFG_UTF16
209     /** The length of pwszShortName (in wchar_t's). */
210     KU16                cwcShortName;
211     /** The length of the short parent UTF-16 path (in wchar_t's). */
212     KU16                cwcShortParent;
213     /** The UTF-16 short object name.  (Allocated after the structure, possibly
214      *  same as pwszName.) */
215     const wchar_t      *pwszShortName;
216 # endif
217 #endif
218 
219     /** Allocation for handling name length increases. */
220     PKFSOBJNAMEALLOC    pNameAlloc;
221 
222     /** Pointer to the first user data item */
223     PKFSUSERDATA        pUserDataHead;
224 
225     /** Stats - only valid when fHaveStats is set. */
226     BirdStat_T          Stats;
227 } KFSOBJ;
228 
229 /** The magic for a KFSOBJ structure (Thelonious Sphere Monk). */
230 #define KFSOBJ_MAGIC                KU32_C(0x19171010)
231 
232 
233 /**
234  * Directory node in the cache.
235  */
236 typedef struct KFSDIR
237 {
238     /** The core object information. */
239     KFSOBJ             Obj;
240 
241     /** Child objects. */
242     PKFSOBJ            *papChildren;
243     /** The number of child objects. */
244     KU32                cChildren;
245     /** The allocated size of papChildren. */
246     KU32                cChildrenAllocated;
247 
248     /** Pointer to the child hash table. */
249     PKFSOBJ            *papHashTab;
250     /** The mask shift of the hash table.
251      * Hash table size is a power of two, this is the size minus one.
252      *
253      * @remarks The hash table is optional and populated by lookup hits.  The
254      *          assumption being that a lookup is repeated and will choose a good
255      *          name to hash on.  We've got up to 4 different hashes, so this
256      *          was the easy way out. */
257     KU32                fHashTabMask;
258 
259     /** Handle to the directory (we generally keep it open). */
260 #ifndef DECLARE_HANDLE
261     KUPTR               hDir;
262 #else
263     HANDLE              hDir;
264 #endif
265     /** The device number we queried/inherited when opening it. */
266     KU64                uDevNo;
267 
268     /** The last write time sampled the last time the directory was refreshed.
269      * @remarks May differ from st_mtim because it will be updated when the
270      *          parent directory is refreshed. */
271     KI64                iLastWrite;
272 
273     /** Set if populated. */
274     KBOOL               fPopulated;
275     /** Set if it needs re-populated. */
276     KBOOL               fNeedRePopulating;
277 } KFSDIR;
278 
279 
280 /**
281  * Lookup errors.
282  */
283 typedef enum KFSLOOKUPERROR
284 {
285     /** Lookup was a success. */
286     KFSLOOKUPERROR_SUCCESS = 0,
287     /** A path component was not found. */
288     KFSLOOKUPERROR_PATH_COMP_NOT_FOUND,
289     /** A path component is not a directory. */
290     KFSLOOKUPERROR_PATH_COMP_NOT_DIR,
291     /** The final path entry is not a directory (trailing slash). */
292     KFSLOOKUPERROR_NOT_DIR,
293     /** Not found. */
294     KFSLOOKUPERROR_NOT_FOUND,
295     /** The path is too long. */
296     KFSLOOKUPERROR_PATH_TOO_LONG,
297     /** Unsupported path type. */
298     KFSLOOKUPERROR_UNSUPPORTED,
299     /** We're out of memory. */
300     KFSLOOKUPERROR_OUT_OF_MEMORY,
301 
302     /** Error opening directory. */
303     KFSLOOKUPERROR_DIR_OPEN_ERROR,
304     /** Error reading directory. */
305     KFSLOOKUPERROR_DIR_READ_ERROR,
306     /** UTF-16 to ANSI conversion error. */
307     KFSLOOKUPERROR_ANSI_CONVERSION_ERROR,
308     /** ANSI to UTF-16 conversion error. */
309     KFSLOOKUPERROR_UTF16_CONVERSION_ERROR,
310     /** Internal error. */
311     KFSLOOKUPERROR_INTERNAL_ERROR
312 } KFSLOOKUPERROR;
313 
314 
315 /** Pointer to an ANSI path hash table entry. */
316 typedef struct KFSHASHA *PKFSHASHA;
317 /**
318  * ANSI file system path hash table entry.
319  * The path hash table allows us to skip parsing and walking a path.
320  */
321 typedef struct KFSHASHA
322 {
323     /** Next entry with the same hash table slot. */
324     PKFSHASHA           pNext;
325     /** Path hash value. */
326     KU32                uHashPath;
327     /** The path length. */
328     KU16                cchPath;
329     /** Set if aboslute path.   */
330     KBOOL               fAbsolute;
331     /** Index into KFSCACHE:auGenerationsMissing when pFsObj is NULL. */
332     KU8                 idxMissingGen;
333     /** The cache generation ID. */
334     KU32                uCacheGen;
335     /** The lookup error (when pFsObj is NULL). */
336     KFSLOOKUPERROR      enmError;
337     /** The path.  (Allocated after the structure.) */
338     const char         *pszPath;
339     /** Pointer to the matching FS object.
340      * This is NULL for negative path entries? */
341     PKFSOBJ             pFsObj;
342 } KFSHASHA;
343 
344 
345 #ifdef KFSCACHE_CFG_UTF16
346 /** Pointer to an UTF-16 path hash table entry. */
347 typedef struct KFSHASHW *PKFSHASHW;
348 /**
349  * UTF-16 file system path hash table entry. The path hash table allows us
350  * to skip parsing and walking a path.
351  */
352 typedef struct KFSHASHW
353 {
354     /** Next entry with the same hash table slot. */
355     PKFSHASHW           pNext;
356     /** Path hash value. */
357     KU32                uHashPath;
358     /** The path length (in wchar_t units). */
359     KU16                cwcPath;
360     /** Set if aboslute path.   */
361     KBOOL               fAbsolute;
362     /** Index into KFSCACHE:auGenerationsMissing when pFsObj is NULL. */
363     KU8                 idxMissingGen;
364     /** The cache generation ID. */
365     KU32                uCacheGen;
366     /** The lookup error (when pFsObj is NULL). */
367     KFSLOOKUPERROR      enmError;
368     /** The path.  (Allocated after the structure.) */
369     const wchar_t      *pwszPath;
370     /** Pointer to the matching FS object.
371      * This is NULL for negative path entries? */
372     PKFSOBJ             pFsObj;
373 } KFSHASHW;
374 #endif
375 
376 
377 /** @name KFSCACHE_F_XXX
378  * @{ */
379 /** Whether to cache missing directory entries (KFSOBJ_TYPE_MISSING). */
380 #define KFSCACHE_F_MISSING_OBJECTS  KU32_C(0x00000001)
381 /** Whether to cache missing paths. */
382 #define KFSCACHE_F_MISSING_PATHS    KU32_C(0x00000002)
383 /** @} */
384 
385 
386 /**
387  * Directory cache instance.
388  */
389 typedef struct KFSCACHE
390 {
391     /** Magic value (KFSCACHE_MAGIC). */
392     KU32                u32Magic;
393     /** Cache flags. */
394     KU32                fFlags;
395 
396     /** The default and custom cache generations for stuff that exists, indexed by
397      *  KFSOBJ_F_USE_CUSTOM_GEN.
398      *
399      * The custom generation can be used to invalidate parts of the file system that
400      * are known to be volatile without triggering refreshing of the more static
401      * parts.  Like the 'out' directory in a kBuild setup or a 'TEMP' directory are
402      * expected to change and you need to invalidate the caching of these frequently
403      * to stay on top of things.  Whereas the sources, headers, compilers, sdk,
404      * ddks, windows directory and such generally doesn't change all that often.
405      */
406     KU32                auGenerations[2];
407     /** The current cache generation for missing objects, negative results, ++.
408      * This comes with a custom variant too.  Indexed by KFSOBJ_F_USE_CUSTOM_GEN. */
409     KU32                auGenerationsMissing[2];
410 
411     /** Number of cache objects. */
412     KSIZE               cObjects;
413     /** Memory occupied by the cache object structures. */
414     KSIZE               cbObjects;
415     /** Number of lookups. */
416     KSIZE               cLookups;
417     /** Number of hits in the path hash tables. */
418     KSIZE               cPathHashHits;
419     /** Number of hits walking the file system hierarchy. */
420     KSIZE               cWalkHits;
421     /** Number of child searches. */
422     KSIZE               cChildSearches;
423     /** Number of cChildLookups resolved thru hash table hits. */
424     KSIZE               cChildHashHits;
425     /** The number of child hash tables. */
426     KSIZE               cChildHashTabs;
427     /** The sum of all child hash table sizes. */
428     KSIZE               cChildHashEntriesTotal;
429     /** Number of children inserted into the hash tables. */
430     KSIZE               cChildHashed;
431     /** Number of collisions in the child hash tables. */
432     KSIZE               cChildHashCollisions;
433     /** Number times a object name changed. */
434     KSIZE               cNameChanges;
435     /** Number times a object name grew and needed KFSOBJNAMEALLOC.
436      *  (Subset of cNameChanges) */
437     KSIZE               cNameGrowths;
438 
439     /** The root directory. */
440     KFSDIR              RootDir;
441 
442     /** File system hash table for ANSI filename strings. */
443     PKFSHASHA           apAnsiPaths[KFSCACHE_CFG_PATH_HASH_TAB_SIZE];
444     /** Number of paths in the apAnsiPaths hash table. */
445     KSIZE               cAnsiPaths;
446     /** Number of collisions in the apAnsiPaths hash table. */
447     KSIZE               cAnsiPathCollisions;
448     /** Amount of memory used by the path entries. */
449     KSIZE               cbAnsiPaths;
450 
451 #ifdef KFSCACHE_CFG_UTF16
452     /** Number of paths in the apUtf16Paths hash table. */
453     KSIZE               cUtf16Paths;
454     /** Number of collisions in the apUtf16Paths hash table. */
455     KSIZE               cUtf16PathCollisions;
456     /** Amount of memory used by the UTF-16 path entries. */
457     KSIZE               cbUtf16Paths;
458     /** File system hash table for UTF-16 filename strings. */
459     PKFSHASHW           apUtf16Paths[KFSCACHE_CFG_PATH_HASH_TAB_SIZE];
460 #endif
461 } KFSCACHE;
462 
463 /** Magic value for KFSCACHE::u32Magic (Jon Batiste).  */
464 #define KFSCACHE_MAGIC              KU32_C(0x19861111)
465 
466 
467 /** @def KW_LOG
468  * Generic logging.
469  * @param a     Argument list for kFsCacheDbgPrintf  */
470 #ifdef NDEBUG
471 # define KFSCACHE_LOG(a) do { } while (0)
472 #else
473 # define KFSCACHE_LOG(a) kFsCacheDbgPrintf a
474 void        kFsCacheDbgPrintfV(const char *pszFormat, va_list va);
475 void        kFsCacheDbgPrintf(const char *pszFormat, ...);
476 #endif
477 
478 
479 KBOOL       kFsCacheDirEnsurePopuplated(PKFSCACHE pCache, PKFSDIR pDir, KFSLOOKUPERROR *penmError);
480 KBOOL       kFsCacheDirAddChild(PKFSCACHE pCache, PKFSDIR pParent, PKFSOBJ pChild, KFSLOOKUPERROR *penmError);
481 PKFSOBJ     kFsCacheCreateObject(PKFSCACHE pCache, PKFSDIR pParent,
482                                  char const *pszName, KU16 cchName, wchar_t const *pwszName, KU16 cwcName,
483 #ifdef KFSCACHE_CFG_SHORT_NAMES
484                                  char const *pszShortName, KU16 cchShortName, wchar_t const *pwszShortName, KU16 cwcShortName,
485 #endif
486                                  KU8 bObjType, KFSLOOKUPERROR *penmError);
487 PKFSOBJ     kFsCacheCreateObjectW(PKFSCACHE pCache, PKFSDIR pParent, wchar_t const *pwszName, KU32 cwcName,
488 #ifdef KFSCACHE_CFG_SHORT_NAMES
489                                   wchar_t const *pwszShortName, KU32 cwcShortName,
490 #endif
491                                   KU8 bObjType, KFSLOOKUPERROR *penmError);
492 PKFSOBJ     kFsCacheLookupA(PKFSCACHE pCache, const char *pszPath, KFSLOOKUPERROR *penmError);
493 PKFSOBJ     kFsCacheLookupW(PKFSCACHE pCache, const wchar_t *pwszPath, KFSLOOKUPERROR *penmError);
494 PKFSOBJ     kFsCacheLookupRelativeToDirA(PKFSCACHE pCache, PKFSDIR pParent, const char *pszPath, KU32 cchPath, KU32 fFlags,
495                                          KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor);
496 PKFSOBJ     kFsCacheLookupRelativeToDirW(PKFSCACHE pCache, PKFSDIR pParent, const wchar_t *pwszPath, KU32 cwcPath, KU32 fFlags,
497                                          KFSLOOKUPERROR *penmError, PKFSOBJ *ppLastAncestor);
498 PKFSOBJ     kFsCacheLookupWithLengthA(PKFSCACHE pCache, const char *pchPath, KSIZE cchPath, KFSLOOKUPERROR *penmError);
499 PKFSOBJ     kFsCacheLookupWithLengthW(PKFSCACHE pCache, const wchar_t *pwcPath, KSIZE cwcPath, KFSLOOKUPERROR *penmError);
500 PKFSOBJ     kFsCacheLookupNoMissingA(PKFSCACHE pCache, const char *pszPath, KFSLOOKUPERROR *penmError);
501 PKFSOBJ     kFsCacheLookupNoMissingW(PKFSCACHE pCache, const wchar_t *pwszPath, KFSLOOKUPERROR *penmError);
502 
503 /** @name KFSCACHE_LOOKUP_F_XXX - lookup flags
504  * @{ */
505 /** No inserting new cache entries.
506  * This effectively prevent directories from being repopulated too.  */
507 #define KFSCACHE_LOOKUP_F_NO_INSERT     KU32_C(1)
508 /** No refreshing cache entries. */
509 #define KFSCACHE_LOOKUP_F_NO_REFRESH    KU32_C(2)
510 /** @} */
511 
512 KU32        kFsCacheObjRelease(PKFSCACHE pCache, PKFSOBJ pObj);
513 KU32        kFsCacheObjReleaseTagged(PKFSCACHE pCache, PKFSOBJ pObj, const char *pszWhere);
514 #ifndef NDEBUG /* enable to debug object release. */
515 # define kFsCacheObjRelease(a_pCache, a_pObj) kFsCacheObjReleaseTagged(a_pCache, a_pObj, __FUNCTION__)
516 #endif
517 KU32        kFsCacheObjRetain(PKFSOBJ pObj);
518 PKFSUSERDATA kFsCacheObjAddUserData(PKFSCACHE pCache, PKFSOBJ pObj, KUPTR uKey, KSIZE cbUserData);
519 PKFSUSERDATA kFsCacheObjGetUserData(PKFSCACHE pCache, PKFSOBJ pObj, KUPTR uKey);
520 KBOOL       kFsCacheObjGetFullPathA(PKFSOBJ pObj, char *pszPath, KSIZE cbPath, char chSlash);
521 KBOOL       kFsCacheObjGetFullPathW(PKFSOBJ pObj, wchar_t *pwszPath, KSIZE cwcPath, wchar_t wcSlash);
522 KBOOL       kFsCacheObjGetFullShortPathA(PKFSOBJ pObj, char *pszPath, KSIZE cbPath, char chSlash);
523 KBOOL       kFsCacheObjGetFullShortPathW(PKFSOBJ pObj, wchar_t *pwszPath, KSIZE cwcPath, wchar_t wcSlash);
524 
525 KBOOL       kFsCacheFileSimpleOpenReadClose(PKFSCACHE pCache, PKFSOBJ pFileObj, KU64 offStart, void *pvBuf, KSIZE cbToRead);
526 
527 PKFSCACHE   kFsCacheCreate(KU32 fFlags);
528 void        kFsCacheDestroy(PKFSCACHE);
529 void        kFsCacheInvalidateMissing(PKFSCACHE pCache);
530 void        kFsCacheInvalidateAll(PKFSCACHE pCache);
531 void        kFsCacheInvalidateCustomMissing(PKFSCACHE pCache);
532 void        kFsCacheInvalidateCustomBoth(PKFSCACHE pCache);
533 KBOOL       kFsCacheSetupCustomRevisionForTree(PKFSCACHE pCache, PKFSOBJ pRoot);
534 KBOOL       kFsCacheInvalidateDeletedDirectoryA(PKFSCACHE pCache, const char *pszDir);
535 
536 #endif
537