VirtualBox

source: kBuild/trunk/src/kmk/dir-nt-bird.c@ 3068

Last change on this file since 3068 was 3024, checked in by bird, 8 years ago

dir-nt-bird.c / dir_glob_readir: Try avoid names with spaces in them.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 23.1 KB
Line 
1/* $Id: dir-nt-bird.c 3024 2017-01-07 17:46:13Z bird $ */
2/** @file
3 * Reimplementation of dir.c for NT using kFsCache.
4 *
5 * This should perform better on NT, especially on machines "infected"
6 * by antivirus programs.
7 */
8
9/*
10 * Copyright (c) 2016 knut st. osmundsen <[email protected]>
11 *
12 * This file is part of kBuild.
13 *
14 * kBuild is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
18 *
19 * kBuild is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with kBuild. If not, see <http://www.gnu.org/licenses/>
26 *
27 */
28
29
30/*********************************************************************************************************************************
31* Header Files *
32*********************************************************************************************************************************/
33#include "nt/kFsCache.h"
34#include "make.h"
35#if defined(KMK) && !defined(__OS2__)
36# include "glob/glob.h"
37#else
38# include <glob.h>
39#endif
40
41
42#include "nt_fullpath.h" /* for the time being - will be implemented here later on. */
43
44
45/*********************************************************************************************************************************
46* Defined Constants And Macros *
47*********************************************************************************************************************************/
48/** User data key indicating that it's an impossible file to make.
49 * See file_impossible() and file_impossible_p(). */
50#define KMK_DIR_NT_IMPOSSIBLE_KEY (~(KUPTR)7)
51
52
53/*********************************************************************************************************************************
54* Structures and Typedefs *
55*********************************************************************************************************************************/
56/**
57 * glob directory stream.
58 */
59typedef struct KMKNTOPENDIR
60{
61 /** Reference to the directory. */
62 PKFSDIR pDir;
63 /** Index of the next directory entry (child) to return. */
64 KU32 idxNext;
65 /** The structure in which to return the directory entry. */
66 struct dirent DirEnt;
67} KMKNTOPENDIR;
68
69
70/*********************************************************************************************************************************
71* Global Variables *
72*********************************************************************************************************************************/
73/** The cache.*/
74PKFSCACHE g_pFsCache = NULL;
75/** Number of times dir_cache_invalid_missing was called. */
76static KU32 g_cInvalidates = 0;
77/** Set by dir_cache_volatile_dir to indicate that the user has marked the
78 * volatile parts of the file system with custom revisioning and we only need to
79 * flush these. This is very handy when using a separate output directory
80 * from the sources. */
81static KBOOL g_fFsCacheIsUsingCustomRevision = K_FALSE;
82
83
84void hash_init_directories(void)
85{
86 g_pFsCache = kFsCacheCreate(0);
87 if (g_pFsCache)
88 return;
89 fputs("kFsCacheCreate failed!", stderr);
90 exit(9);
91}
92
93
94/**
95 * Checks if @a pszName exists in directory @a pszDir.
96 *
97 * @returns 1 if it does, 0 if it doesn't.
98 *
99 * @param pszDir The directory.
100 * @param pszName The name.
101 *
102 * If empty string, just check if the directory exists.
103 *
104 * If NULL, just read the whole cache the directory into
105 * the cache (we always do that).
106 */
107int dir_file_exists_p(const char *pszDir, const char *pszName)
108{
109 int fRc = 0;
110 KFSLOOKUPERROR enmError;
111 PKFSOBJ pDirObj = kFsCacheLookupA(g_pFsCache, pszDir, &enmError);
112 if (pDirObj)
113 {
114 if (pDirObj->bObjType == KFSOBJ_TYPE_DIR)
115 {
116 if (pszName != 0)
117 {
118 /* Empty filename is just checking out the directory. */
119 if (*pszName == '\0')
120 fRc = 1;
121 else
122 {
123 PKFSOBJ pNameObj = kFsCacheLookupRelativeToDirA(g_pFsCache, (PKFSDIR)pDirObj, pszName, strlen(pszName),
124 0/*fFlags*/, &enmError, NULL);
125 if (pNameObj)
126 {
127 fRc = pNameObj->bObjType == KFSOBJ_TYPE_MISSING;
128 kFsCacheObjRelease(g_pFsCache, pNameObj);
129 }
130 }
131 }
132 }
133 kFsCacheObjRelease(g_pFsCache, pDirObj);
134 }
135 return fRc;
136}
137
138
139/**
140 * Checks if a file exists.
141 *
142 * @returns 1 if it does exist, 0 if it doesn't.
143 * @param pszPath The path to check out.
144 */
145int file_exists_p(const char *pszPath)
146{
147 int fRc;
148 KFSLOOKUPERROR enmError;
149 PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError);
150 if (pPathObj)
151 {
152 fRc = pPathObj->bObjType != KFSOBJ_TYPE_MISSING;
153 kFsCacheObjRelease(g_pFsCache, pPathObj);
154 }
155 else
156 fRc = 0;
157 return fRc;
158}
159
160
161/**
162 * Just a way for vpath.c to get a correctly cased path, I think.
163 *
164 * @returns Directory path in string cache.
165 * @param pszDir The directory.
166 */
167const char *dir_name(const char *pszDir)
168{
169 char szTmp[MAX_PATH];
170 nt_fullpath(pszDir, szTmp, sizeof(szTmp));
171 return strcache_add(szTmp);
172}
173
174
175/**
176 * Makes future file_impossible_p calls return 1 for pszPath.
177 */
178void file_impossible(const char *pszPath)
179{
180 KFSLOOKUPERROR enmError;
181 PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError);
182 if (pPathObj)
183 {
184 kFsCacheObjAddUserData(g_pFsCache, pPathObj, KMK_DIR_NT_IMPOSSIBLE_KEY, sizeof(KFSUSERDATA));
185 kFsCacheObjRelease(g_pFsCache, pPathObj);
186 }
187}
188
189/**
190 * Makes future file_impossible_p calls return 1 for pszPath.
191 */
192int file_impossible_p(const char *pszPath)
193{
194 int fRc;
195 KFSLOOKUPERROR enmError;
196 PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError);
197 if (pPathObj)
198 {
199 fRc = kFsCacheObjGetUserData(g_pFsCache, pPathObj, KMK_DIR_NT_IMPOSSIBLE_KEY) != NULL;
200 kFsCacheObjRelease(g_pFsCache, pPathObj);
201 }
202 else
203 fRc = 0;
204 return fRc;
205}
206
207
208/**
209 * opendir for glob.
210 *
211 * @returns Pointer to DIR like handle, NULL if directory not found.
212 * @param pszDir The directory to enumerate.
213 */
214static __ptr_t dir_glob_opendir(const char *pszDir)
215{
216 KFSLOOKUPERROR enmError;
217 PKFSOBJ pDirObj = kFsCacheLookupA(g_pFsCache, pszDir, &enmError);
218 if (pDirObj)
219 {
220 if (pDirObj->bObjType == KFSOBJ_TYPE_DIR)
221 {
222 if (kFsCacheDirEnsurePopuplated(g_pFsCache, (PKFSDIR)pDirObj, NULL))
223 {
224 KMKNTOPENDIR *pDir = xmalloc(sizeof(*pDir));
225 pDir->pDir = (PKFSDIR)pDirObj;
226 pDir->idxNext = 0;
227 return pDir;
228 }
229 }
230 kFsCacheObjRelease(g_pFsCache, pDirObj);
231 }
232 return NULL;
233}
234
235
236/**
237 * readdir for glob.
238 *
239 * @returns Pointer to DIR like handle, NULL if directory not found.
240 * @param pDir Directory enum handle by dir_glob_opendir.
241 */
242static struct dirent *dir_glob_readdir(__ptr_t pvDir)
243{
244 KMKNTOPENDIR *pDir = (KMKNTOPENDIR *)pvDir;
245 KU32 const cChildren = pDir->pDir->cChildren;
246 while (pDir->idxNext < cChildren)
247 {
248 PKFSOBJ pEntry = pDir->pDir->papChildren[pDir->idxNext++];
249
250 /* Don't return missing objects. */
251 if (pEntry->bObjType != KFSOBJ_TYPE_MISSING)
252 {
253 /* Copy the name that fits, trying to avoid names with spaces.
254 If neither fits, skip the name. */
255 if ( pEntry->cchName < sizeof(pDir->DirEnt.d_name)
256 && ( pEntry->pszShortName == pEntry->pszName
257 || memchr(pEntry->pszName, ' ', pEntry->cchName) == NULL))
258 {
259 pDir->DirEnt.d_namlen = pEntry->cchName;
260 memcpy(pDir->DirEnt.d_name, pEntry->pszName, pEntry->cchName + 1);
261 }
262 else if (pEntry->cchShortName < sizeof(pDir->DirEnt.d_name))
263 {
264 pDir->DirEnt.d_namlen = pEntry->cchShortName;
265 memcpy(pDir->DirEnt.d_name, pEntry->pszShortName, pEntry->cchShortName + 1);
266 }
267 else
268 continue;
269
270 pDir->DirEnt.d_reclen = offsetof(struct dirent, d_name) + pDir->DirEnt.d_namlen;
271 if (pEntry->bObjType == KFSOBJ_TYPE_DIR)
272 pDir->DirEnt.d_type = DT_DIR;
273 else if (pEntry->bObjType == KFSOBJ_TYPE_FILE)
274 pDir->DirEnt.d_type = DT_REG;
275 else
276 pDir->DirEnt.d_type = DT_UNKNOWN;
277
278 return &pDir->DirEnt;
279 }
280 }
281
282 /*
283 * Fake the '.' and '..' directories because they're not part of papChildren above.
284 */
285 if (pDir->idxNext < cChildren + 2)
286 {
287 pDir->idxNext++;
288 pDir->DirEnt.d_type = DT_DIR;
289 pDir->DirEnt.d_namlen = pDir->idxNext - cChildren;
290 pDir->DirEnt.d_reclen = offsetof(struct dirent, d_name) + pDir->DirEnt.d_namlen;
291 pDir->DirEnt.d_name[0] = '.';
292 pDir->DirEnt.d_name[1] = '.';
293 pDir->DirEnt.d_name[pDir->DirEnt.d_namlen] = '\0';
294 return &pDir->DirEnt;
295 }
296
297 return NULL;
298}
299
300
301/**
302 * closedir for glob.
303 *
304 * @param pDir Directory enum handle by dir_glob_opendir.
305 */
306static void dir_glob_closedir(__ptr_t pvDir)
307{
308 KMKNTOPENDIR *pDir = (KMKNTOPENDIR *)pvDir;
309 kFsCacheObjRelease(g_pFsCache, &pDir->pDir->Obj);
310 pDir->pDir = NULL;
311 free(pDir);
312}
313
314
315/**
316 * stat for glob.
317 *
318 * @returns 0 on success, -1 + errno on failure.
319 * @param pszPath The path to stat.
320 * @param pStat Where to return the info.
321 */
322static int dir_glob_stat(const char *pszPath, struct stat *pStat)
323{
324 KFSLOOKUPERROR enmError;
325 PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError);
326/** @todo follow symlinks vs. on symlink! */
327 if (pPathObj)
328 {
329 if (pPathObj->bObjType != KFSOBJ_TYPE_MISSING)
330 {
331 kHlpAssert(pPathObj->fHaveStats); /* currently always true. */
332 *pStat = pPathObj->Stats;
333 kFsCacheObjRelease(g_pFsCache, pPathObj);
334 return 0;
335 }
336 kFsCacheObjRelease(g_pFsCache, pPathObj);
337 }
338 errno = ENOENT;
339 return -1;
340}
341
342
343/**
344 * lstat for glob.
345 *
346 * @returns 0 on success, -1 + errno on failure.
347 * @param pszPath The path to stat.
348 * @param pStat Where to return the info.
349 */
350static int dir_glob_lstat(const char *pszPath, struct stat *pStat)
351{
352 KFSLOOKUPERROR enmError;
353 PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError);
354 if (pPathObj)
355 {
356 if (pPathObj->bObjType != KFSOBJ_TYPE_MISSING)
357 {
358 kHlpAssert(pPathObj->fHaveStats); /* currently always true. */
359 *pStat = pPathObj->Stats;
360 kFsCacheObjRelease(g_pFsCache, pPathObj);
361 return 0;
362 }
363 kFsCacheObjRelease(g_pFsCache, pPathObj);
364 errno = ENOENT;
365 }
366 else
367 errno = enmError == KFSLOOKUPERROR_NOT_DIR
368 || enmError == KFSLOOKUPERROR_PATH_COMP_NOT_DIR
369 ? ENOTDIR : ENOENT;
370
371 return -1;
372}
373
374
375/**
376 * Checks if @a pszDir exists and is a directory.
377 *
378 * @returns 1 if is directory, 0 if isn't or doesn't exists.
379 * @param pszDir The alleged directory.
380 */
381static int dir_globl_dir_exists_p(const char *pszDir)
382{
383 int fRc;
384 KFSLOOKUPERROR enmError;
385 PKFSOBJ pDirObj = kFsCacheLookupA(g_pFsCache, pszDir, &enmError);
386 if (pDirObj)
387 {
388 fRc = pDirObj->bObjType == KFSOBJ_TYPE_DIR;
389 kFsCacheObjRelease(g_pFsCache, pDirObj);
390 }
391 else
392 fRc = 0;
393 return fRc;
394
395}
396
397
398/**
399 * Sets up pGlob with the necessary callbacks.
400 *
401 * @param pGlob Structure to populate.
402 */
403void dir_setup_glob(glob_t *pGlob)
404{
405 pGlob->gl_opendir = dir_glob_opendir;
406 pGlob->gl_readdir = dir_glob_readdir;
407 pGlob->gl_closedir = dir_glob_closedir;
408 pGlob->gl_stat = dir_glob_stat;
409#ifdef __EMX__ /* The FreeBSD implementation actually uses gl_lstat!! */
410 pGlob->gl_lstat = dir_glob_lstat;
411#else
412 pGlob->gl_exists = file_exists_p;
413 pGlob->gl_isdir = dir_globl_dir_exists_p;
414#endif
415}
416
417
418/**
419 * Print statitstics.
420 */
421void print_dir_stats(void)
422{
423 FILE *pOut = stdout;
424 KU32 cMisses;
425
426 fputs("\n"
427 "# NT dir cache stats:\n", pOut);
428 fprintf(pOut, "# %u objects, taking up %u (%#x) bytes, avg %u bytes\n",
429 g_pFsCache->cObjects, g_pFsCache->cbObjects, g_pFsCache->cbObjects, g_pFsCache->cbObjects / g_pFsCache->cObjects);
430 fprintf(pOut, "# %u A path hashes, taking up %u (%#x) bytes, avg %u bytes, %u collision\n",
431 g_pFsCache->cAnsiPaths, g_pFsCache->cbAnsiPaths, g_pFsCache->cbAnsiPaths,
432 g_pFsCache->cbAnsiPaths / K_MAX(g_pFsCache->cAnsiPaths, 1), g_pFsCache->cAnsiPathCollisions);
433#ifdef KFSCACHE_CFG_UTF16
434 fprintf(pOut, "# %u W path hashes, taking up %u (%#x) bytes, avg %u bytes, %u collisions\n",
435 g_pFsCache->cUtf16Paths, g_pFsCache->cbUtf16Paths, g_pFsCache->cbUtf16Paths,
436 g_pFsCache->cbUtf16Paths / K_MAX(g_pFsCache->cUtf16Paths, 1), g_pFsCache->cUtf16PathCollisions);
437#endif
438 fprintf(pOut, "# %u child hash tables, total of %u entries, %u children inserted, %u collisions\n",
439 g_pFsCache->cChildHashTabs, g_pFsCache->cChildHashEntriesTotal,
440 g_pFsCache->cChildHashed, g_pFsCache->cChildHashCollisions);
441
442 cMisses = g_pFsCache->cLookups - g_pFsCache->cPathHashHits - g_pFsCache->cWalkHits;
443 fprintf(pOut, "# %u lookups: %u (%" KU64_PRI " %%) path hash hits, %u (%" KU64_PRI "%%) walks hits, %u (%" KU64_PRI "%%) misses\n",
444 g_pFsCache->cLookups,
445 g_pFsCache->cPathHashHits, g_pFsCache->cPathHashHits * (KU64)100 / K_MAX(g_pFsCache->cLookups, 1),
446 g_pFsCache->cWalkHits, g_pFsCache->cWalkHits * (KU64)100 / K_MAX(g_pFsCache->cLookups, 1),
447 cMisses, cMisses * (KU64)100 / K_MAX(g_pFsCache->cLookups, 1));
448 fprintf(pOut, "# %u child searches, %u (%" KU64_PRI "%%) hash hits\n",
449 g_pFsCache->cChildSearches,
450 g_pFsCache->cChildHashHits, g_pFsCache->cChildHashHits * (KU64)100 / K_MAX(g_pFsCache->cChildSearches, 1));
451}
452
453
454void print_dir_data_base(void)
455{
456 /** @todo. */
457
458}
459
460
461/* duplicated in kWorker.c
462 * Note! Tries avoid to produce a result with spaces since they aren't supported by makefiles. */
463void nt_fullpath_cached(const char *pszPath, char *pszFull, size_t cbFull)
464{
465 KFSLOOKUPERROR enmError;
466 PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError);
467 if (pPathObj)
468 {
469 KSIZE off = pPathObj->cchParent;
470 if (off > 0)
471 {
472 KSIZE offEnd = off + pPathObj->cchName;
473 if (offEnd < cbFull)
474 {
475 PKFSDIR pAncestor;
476
477 pszFull[offEnd] = '\0';
478 memcpy(&pszFull[off], pPathObj->pszName, pPathObj->cchName);
479
480 for (pAncestor = pPathObj->pParent; off > 0; pAncestor = pAncestor->Obj.pParent)
481 {
482 kHlpAssert(off > 1);
483 kHlpAssert(pAncestor != NULL);
484 kHlpAssert(pAncestor->Obj.cchName > 0);
485 pszFull[--off] = '/';
486#ifdef KFSCACHE_CFG_SHORT_NAMES
487 if ( pAncestor->Obj.pszName == pAncestor->Obj.pszShortName
488 || memchr(pAncestor->Obj.pszName, ' ', pAncestor->Obj.cchName) == NULL)
489#endif
490 {
491 off -= pAncestor->Obj.cchName;
492 kHlpAssert(pAncestor->Obj.cchParent == off);
493 memcpy(&pszFull[off], pAncestor->Obj.pszName, pAncestor->Obj.cchName);
494 }
495#ifdef KFSCACHE_CFG_SHORT_NAMES
496 else
497 {
498 /*
499 * The long name constains a space, so use the alternative name instead.
500 * Most likely the alternative name differs in length, usually it's shorter,
501 * so we have to shift the part of the path we've already assembled
502 * accordingly.
503 */
504 KSSIZE cchDelta = (KSSIZE)pAncestor->Obj.cchShortName - (KSSIZE)pAncestor->Obj.cchName;
505 if (cchDelta != 0)
506 {
507 if ((KSIZE)(offEnd + cchDelta) >= cbFull)
508 goto l_fallback;
509 memmove(&pszFull[off + cchDelta], &pszFull[off], offEnd + 1 - off);
510 off += cchDelta;
511 offEnd += cchDelta;
512 }
513 off -= pAncestor->Obj.cchShortName;
514 kHlpAssert(pAncestor->Obj.cchParent == off);
515 memcpy(&pszFull[off], pAncestor->Obj.pszShortName, pAncestor->Obj.cchShortName);
516 }
517#endif
518 }
519 kFsCacheObjRelease(g_pFsCache, pPathObj);
520 return;
521 }
522 }
523 else
524 {
525 if ((size_t)pPathObj->cchName + 1 < cbFull)
526 {
527 /* Assume no spaces here. */
528 memcpy(pszFull, pPathObj->pszName, pPathObj->cchName);
529 pszFull[pPathObj->cchName] = '/';
530 pszFull[pPathObj->cchName + 1] = '\0';
531
532 kFsCacheObjRelease(g_pFsCache, pPathObj);
533 return;
534 }
535 }
536
537 /* do fallback. */
538#ifdef KFSCACHE_CFG_SHORT_NAMES
539l_fallback:
540#endif
541 kHlpAssertFailed();
542 kFsCacheObjRelease(g_pFsCache, pPathObj);
543 }
544
545 nt_fullpath(pszPath, pszFull, cbFull);
546}
547
548
549/**
550 * Special stat call used by remake.c
551 *
552 * @returns 0 on success, -1 + errno on failure.
553 * @param pszPath The path to stat.
554 * @param pStat Where to return the mtime field only.
555 */
556int stat_only_mtime(const char *pszPath, struct stat *pStat)
557{
558 /* Currently a little expensive, so just hit the file system once the
559 jobs starts comming in. */
560 if (g_cInvalidates == 0)
561 {
562 KFSLOOKUPERROR enmError;
563 PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError);
564 if (pPathObj)
565 {
566 if (pPathObj->bObjType != KFSOBJ_TYPE_MISSING)
567 {
568 kHlpAssert(pPathObj->fHaveStats); /* currently always true. */
569 pStat->st_mtime = pPathObj->Stats.st_mtime;
570 kFsCacheObjRelease(g_pFsCache, pPathObj);
571 return 0;
572 }
573
574 kFsCacheObjRelease(g_pFsCache, pPathObj);
575 errno = ENOENT;
576 }
577 else
578 errno = enmError == KFSLOOKUPERROR_NOT_DIR
579 || enmError == KFSLOOKUPERROR_PATH_COMP_NOT_DIR
580 ? ENOTDIR : ENOENT;
581 return -1;
582 }
583 return birdStatModTimeOnly(pszPath, &pStat->st_mtim, 1 /*fFollowLink*/);
584}
585
586/**
587 * Do cache invalidation after a job completes.
588 */
589void dir_cache_invalid_after_job(void)
590{
591 g_cInvalidates++;
592 if (g_fFsCacheIsUsingCustomRevision)
593 kFsCacheInvalidateCustomBoth(g_pFsCache);
594 else
595 kFsCacheInvalidateAll(g_pFsCache);
596}
597
598/**
599 * Invalidate the whole directory cache
600 *
601 * Used by $(dircache-ctl invalidate)
602 */
603void dir_cache_invalid_all(void)
604{
605 g_cInvalidates++;
606 kFsCacheInvalidateAll(g_pFsCache);
607}
608
609/**
610 * Invalidate missing bits of the directory cache.
611 *
612 * Used by $(dircache-ctl invalidate-missing)
613 */
614void dir_cache_invalid_missing(void)
615{
616 g_cInvalidates++;
617 kFsCacheInvalidateAll(g_pFsCache);
618}
619
620/**
621 * Invalidate the volatile bits of the directory cache.
622 *
623 * Used by $(dircache-ctl invalidate-missing)
624 */
625void dir_cache_invalid_volatile(void)
626{
627 g_cInvalidates++;
628 if (g_fFsCacheIsUsingCustomRevision)
629 kFsCacheInvalidateCustomBoth(g_pFsCache);
630 else
631 kFsCacheInvalidateAll(g_pFsCache);
632}
633
634/**
635 * Used by $(dircache-ctl ) to mark a directory subtree or file as volatile.
636 *
637 * The first call changes the rest of the cache to be considered non-volatile.
638 *
639 * @returns 0 on success, -1 on failure.
640 * @param pszDir The directory (or file for what that is worth).
641 */
642int dir_cache_volatile_dir(const char *pszDir)
643{
644 KFSLOOKUPERROR enmError;
645 PKFSOBJ pObj = kFsCacheLookupA(g_pFsCache, pszDir, &enmError);
646 if (pObj)
647 {
648 KBOOL fRc = kFsCacheSetupCustomRevisionForTree(g_pFsCache, pObj);
649 kFsCacheObjRelease(g_pFsCache, pObj);
650 if (fRc)
651 {
652 g_fFsCacheIsUsingCustomRevision = K_TRUE;
653 return 0;
654 }
655 error(reading_file, "failed to mark '%s' as volatile", pszDir);
656 }
657 else
658 error(reading_file, "failed to mark '%s' as volatile (not found)", pszDir);
659 return -1;
660}
661
662/**
663 * Invalidates a deleted directory so the cache can close handles to it.
664 *
665 * Used by kmk_builtin_rm and kmk_builtin_rmdir.
666 *
667 * @returns 0 on success, -1 on failure.
668 * @param pszDir The directory to invalidate as deleted.
669 */
670int dir_cache_deleted_directory(const char *pszDir)
671{
672 if (kFsCacheInvalidateDeletedDirectoryA(g_pFsCache, pszDir))
673 return 0;
674 return -1;
675}
676
677
678int kmk_builtin_dircache(int argc, char **argv, char **envp)
679{
680 if (argc >= 2)
681 {
682 const char *pszCmd = argv[1];
683 if (strcmp(pszCmd, "invalidate") == 0)
684 {
685 if (argc == 2)
686 {
687 dir_cache_invalid_all();
688 return 0;
689 }
690 fprintf(stderr, "kmk_builtin_dircache: the 'invalidate' command takes no arguments!\n");
691 }
692 else if (strcmp(pszCmd, "invalidate-missing") == 0)
693 {
694 if (argc == 2)
695 {
696 dir_cache_invalid_missing ();
697 return 0;
698 }
699 fprintf(stderr, "kmk_builtin_dircache: the 'invalidate-missing' command takes no arguments!\n");
700 }
701 else if (strcmp(pszCmd, "volatile") == 0)
702 {
703 int i;
704 for (i = 2; i < argc; i++)
705 dir_cache_volatile_dir(argv[i]);
706 return 0;
707 }
708 else if (strcmp(pszCmd, "deleted") == 0)
709 {
710 int i;
711 for (i = 2; i < argc; i++)
712 dir_cache_deleted_directory(argv[i]);
713 return 0;
714 }
715 else
716 fprintf(stderr, "kmk_builtin_dircache: Invalid command '%s'!\n", pszCmd);
717 }
718 else
719 fprintf(stderr, "kmk_builtin_dircache: No command given!\n");
720
721 K_NOREF(envp);
722 return 2;
723}
724
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette