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

Last change on this file since 2868 was 2868, checked in by bird, 9 years ago

Only invalidate the PATH_OUT and TEMP in kWorker.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 15.1 KB
Line 
1/* $Id: dir-nt-bird.c 2868 2016-09-04 01:28:12Z 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 <bird-kBuild-spamx@anduin.net>
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*********************************************************************************************************************************/
73PKFSCACHE g_pFsCache = NULL;
74
75
76void hash_init_directories(void)
77{
78 g_pFsCache = kFsCacheCreate(0);
79 if (g_pFsCache)
80 return;
81 fputs("kFsCacheCreate failed!", stderr);
82 exit(9);
83}
84
85
86/**
87 * Checks if @a pszName exists in directory @a pszDir.
88 *
89 * @returns 1 if it does, 0 if it doesn't.
90 *
91 * @param pszDir The directory.
92 * @param pszName The name.
93 *
94 * If empty string, just check if the directory exists.
95 *
96 * If NULL, just read the whole cache the directory into
97 * the cache (we always do that).
98 */
99int dir_file_exists_p(const char *pszDir, const char *pszName)
100{
101 int fRc = 0;
102 KFSLOOKUPERROR enmError;
103 PKFSOBJ pDirObj = kFsCacheLookupA(g_pFsCache, pszDir, &enmError);
104 if (pDirObj)
105 {
106 if (pDirObj->bObjType == KFSOBJ_TYPE_DIR)
107 {
108 if (pszName != 0)
109 {
110 /* Empty filename is just checking out the directory. */
111 if (*pszName == '\0')
112 fRc = 1;
113 else
114 {
115 PKFSOBJ pNameObj = kFsCacheLookupRelativeToDirA(g_pFsCache, (PKFSDIR)pDirObj,
116 pszName, strlen(pszName), &enmError, NULL);
117 if (pNameObj)
118 {
119 fRc = pNameObj->bObjType == KFSOBJ_TYPE_MISSING;
120 kFsCacheObjRelease(g_pFsCache, pNameObj);
121 }
122 }
123 }
124 }
125 kFsCacheObjRelease(g_pFsCache, pDirObj);
126 }
127 return fRc;
128}
129
130
131/**
132 * Checks if a file exists.
133 *
134 * @returns 1 if it does exist, 0 if it doesn't.
135 * @param pszPath The path to check out.
136 */
137int file_exists_p(const char *pszPath)
138{
139 int fRc;
140 KFSLOOKUPERROR enmError;
141 PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError);
142 if (pPathObj)
143 {
144 fRc = pPathObj->bObjType != KFSOBJ_TYPE_MISSING;
145 kFsCacheObjRelease(g_pFsCache, pPathObj);
146 }
147 else
148 fRc = 0;
149 return fRc;
150}
151
152
153/**
154 * Just a way for vpath.c to get a correctly cased path, I think.
155 *
156 * @returns Directory path in string cache.
157 * @param pszDir The directory.
158 */
159const char *dir_name(const char *pszDir)
160{
161 char szTmp[MAX_PATH];
162 nt_fullpath(pszDir, szTmp, sizeof(szTmp));
163 return strcache_add(szTmp);
164}
165
166
167/**
168 * Makes future file_impossible_p calls return 1 for pszPath.
169 */
170void file_impossible(const char *pszPath)
171{
172 KFSLOOKUPERROR enmError;
173 PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError);
174 if (pPathObj)
175 {
176 kFsCacheObjAddUserData(g_pFsCache, pPathObj, KMK_DIR_NT_IMPOSSIBLE_KEY, sizeof(KFSUSERDATA));
177 kFsCacheObjRelease(g_pFsCache, pPathObj);
178 }
179}
180
181/**
182 * Makes future file_impossible_p calls return 1 for pszPath.
183 */
184int file_impossible_p(const char *pszPath)
185{
186 int fRc;
187 KFSLOOKUPERROR enmError;
188 PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError);
189 if (pPathObj)
190 {
191 fRc = kFsCacheObjGetUserData(g_pFsCache, pPathObj, KMK_DIR_NT_IMPOSSIBLE_KEY) != NULL;
192 kFsCacheObjRelease(g_pFsCache, pPathObj);
193 }
194 else
195 fRc = 0;
196 return fRc;
197}
198
199
200/**
201 * opendir for glob.
202 *
203 * @returns Pointer to DIR like handle, NULL if directory not found.
204 * @param pszDir The directory to enumerate.
205 */
206static __ptr_t dir_glob_opendir(const char *pszDir)
207{
208 KFSLOOKUPERROR enmError;
209 PKFSOBJ pDirObj = kFsCacheLookupA(g_pFsCache, pszDir, &enmError);
210 if (pDirObj)
211 {
212 if (pDirObj->bObjType == KFSOBJ_TYPE_DIR)
213 {
214 if (kFsCacheDirEnsurePopuplated(g_pFsCache, (PKFSDIR)pDirObj, NULL))
215 {
216 KMKNTOPENDIR *pDir = xmalloc(sizeof(*pDir));
217 pDir->pDir = (PKFSDIR)pDirObj;
218 pDir->idxNext = 0;
219 return pDir;
220 }
221 }
222 kFsCacheObjRelease(g_pFsCache, pDirObj);
223 }
224 return NULL;
225}
226
227
228/**
229 * readdir for glob.
230 *
231 * @returns Pointer to DIR like handle, NULL if directory not found.
232 * @param pDir Directory enum handle by dir_glob_opendir.
233 */
234static struct dirent *dir_glob_readdir(__ptr_t pvDir)
235{
236 KMKNTOPENDIR *pDir = (KMKNTOPENDIR *)pvDir;
237 KU32 const cChildren = pDir->pDir->cChildren;
238 while (pDir->idxNext < cChildren)
239 {
240 PKFSOBJ pEntry = pDir->pDir->papChildren[pDir->idxNext++];
241
242 /* Don't return missing objects. */
243 if (pEntry->bObjType != KFSOBJ_TYPE_MISSING)
244 {
245 /* Copy the name that fits. If neither fits, skip the name. */
246 if (pEntry->cchName < sizeof(pDir->DirEnt.d_name))
247 {
248 pDir->DirEnt.d_namlen = pEntry->cchName;
249 memcpy(pDir->DirEnt.d_name, pEntry->pszName, pEntry->cchName + 1);
250 }
251 else if (pEntry->cchShortName < sizeof(pDir->DirEnt.d_name))
252 {
253 pDir->DirEnt.d_namlen = pEntry->cchShortName;
254 memcpy(pDir->DirEnt.d_name, pEntry->pszShortName, pEntry->cchShortName + 1);
255 }
256 else
257 continue;
258
259 pDir->DirEnt.d_reclen = offsetof(struct dirent, d_name) + pDir->DirEnt.d_namlen;
260 if (pEntry->bObjType == KFSOBJ_TYPE_DIR)
261 pDir->DirEnt.d_type = DT_DIR;
262 else if (pEntry->bObjType == KFSOBJ_TYPE_FILE)
263 pDir->DirEnt.d_type = DT_REG;
264 else
265 pDir->DirEnt.d_type = DT_UNKNOWN;
266
267 return &pDir->DirEnt;
268 }
269 }
270
271 /*
272 * Fake the '.' and '..' directories because they're not part of papChildren above.
273 */
274 if (pDir->idxNext < cChildren + 2)
275 {
276 pDir->idxNext++;
277 pDir->DirEnt.d_type = DT_DIR;
278 pDir->DirEnt.d_namlen = pDir->idxNext - cChildren;
279 pDir->DirEnt.d_reclen = offsetof(struct dirent, d_name) + pDir->DirEnt.d_namlen;
280 pDir->DirEnt.d_name[0] = '.';
281 pDir->DirEnt.d_name[1] = '.';
282 pDir->DirEnt.d_name[pDir->DirEnt.d_namlen] = '\0';
283 return &pDir->DirEnt;
284 }
285
286 return NULL;
287}
288
289
290/**
291 * closedir for glob.
292 *
293 * @param pDir Directory enum handle by dir_glob_opendir.
294 */
295static void dir_glob_closedir(__ptr_t pvDir)
296{
297 KMKNTOPENDIR *pDir = (KMKNTOPENDIR *)pvDir;
298 kFsCacheObjRelease(g_pFsCache, &pDir->pDir->Obj);
299 pDir->pDir = NULL;
300 free(pDir);
301}
302
303
304/**
305 * stat for glob.
306 *
307 * @returns 0 on success, -1 + errno on failure.
308 * @param pszPath The path to stat.
309 * @param pStat Where to return the info.
310 */
311static int dir_glob_stat(const char *pszPath, struct stat *pStat)
312{
313 KFSLOOKUPERROR enmError;
314 PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError);
315/** @todo follow symlinks vs. on symlink! */
316 if (pPathObj)
317 {
318 if (pPathObj->bObjType != KFSOBJ_TYPE_MISSING)
319 {
320 kHlpAssert(pPathObj->fHaveStats); /* currently always true. */
321 *pStat = pPathObj->Stats;
322 kFsCacheObjRelease(g_pFsCache, pPathObj);
323 return 0;
324 }
325 kFsCacheObjRelease(g_pFsCache, pPathObj);
326 }
327 errno = ENOENT;
328 return -1;
329}
330
331
332/**
333 * lstat for glob.
334 *
335 * @returns 0 on success, -1 + errno on failure.
336 * @param pszPath The path to stat.
337 * @param pStat Where to return the info.
338 */
339static int dir_glob_lstat(const char *pszPath, struct stat *pStat)
340{
341 KFSLOOKUPERROR enmError;
342 PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError);
343 if (pPathObj)
344 {
345 if (pPathObj->bObjType != KFSOBJ_TYPE_MISSING)
346 {
347 kHlpAssert(pPathObj->fHaveStats); /* currently always true. */
348 *pStat = pPathObj->Stats;
349 kFsCacheObjRelease(g_pFsCache, pPathObj);
350 return 0;
351 }
352 kFsCacheObjRelease(g_pFsCache, pPathObj);
353 errno = ENOENT;
354 }
355 else
356 errno = enmError == KFSLOOKUPERROR_NOT_DIR
357 || enmError == KFSLOOKUPERROR_PATH_COMP_NOT_DIR
358 ? ENOTDIR : ENOENT;
359
360 return -1;
361}
362
363
364/**
365 * Checks if @a pszDir exists and is a directory.
366 *
367 * @returns 1 if is directory, 0 if isn't or doesn't exists.
368 * @param pszDir The alleged directory.
369 */
370static int dir_globl_dir_exists_p(const char *pszDir)
371{
372 int fRc;
373 KFSLOOKUPERROR enmError;
374 PKFSOBJ pDirObj = kFsCacheLookupA(g_pFsCache, pszDir, &enmError);
375 if (pDirObj)
376 {
377 fRc = pDirObj->bObjType == KFSOBJ_TYPE_DIR;
378 kFsCacheObjRelease(g_pFsCache, pDirObj);
379 }
380 else
381 fRc = 0;
382 return fRc;
383
384}
385
386
387/**
388 * Sets up pGlob with the necessary callbacks.
389 *
390 * @param pGlob Structure to populate.
391 */
392void dir_setup_glob(glob_t *pGlob)
393{
394 pGlob->gl_opendir = dir_glob_opendir;
395 pGlob->gl_readdir = dir_glob_readdir;
396 pGlob->gl_closedir = dir_glob_closedir;
397 pGlob->gl_stat = dir_glob_stat;
398#ifdef __EMX__ /* The FreeBSD implementation actually uses gl_lstat!! */
399 pGlob->gl_lstat = dir_glob_lstat;
400#else
401 pGlob->gl_exists = file_exists_p;
402 pGlob->gl_isdir = dir_globl_dir_exists_p;
403#endif
404}
405
406
407void print_dir_data_base(void)
408{
409 /** @todo. */
410}
411
412
413
414void nt_fullpath_cached(const char *pszPath, char *pszFull, size_t cbFull)
415{
416 KFSLOOKUPERROR enmError;
417 PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError);
418 if (pPathObj)
419 {
420 KSIZE off = pPathObj->cchParent;
421 if (off > 0)
422 {
423 KSIZE offEnd = off + pPathObj->cchName;
424 if (offEnd < cbFull)
425 {
426 PKFSDIR pAncestor;
427
428 pszFull[off + pPathObj->cchName] = '\0';
429 memcpy(&pszFull[off], pPathObj->pszName, pPathObj->cchName);
430
431 for (pAncestor = pPathObj->pParent; off > 0; pAncestor = pAncestor->Obj.pParent)
432 {
433 kHlpAssert(off > 1);
434 kHlpAssert(pAncestor != NULL);
435 kHlpAssert(pAncestor->ObjcchName > 0);
436 pszFull[--off] = '/';
437 off -= pAncestor->Obj.cchName;
438 kHlpAssert(pAncestor->Obj.cchParent == off);
439 memcpy(&pszFull[off], pAncestor->Obj.pszName, pAncestor->Obj.cchName);
440 }
441 kFsCacheObjRelease(g_pFsCache, pPathObj);
442 return;
443 }
444 }
445 else
446 {
447 if (pPathObj->cchName + 1 < cbFull)
448 {
449 memcpy(pszFull, pPathObj->pszName, pPathObj->cchName);
450 pszFull[pPathObj->cchName] = '/';
451 pszFull[pPathObj->cchName + 1] = '\0';
452
453 kFsCacheObjRelease(g_pFsCache, pPathObj);
454 return;
455 }
456 }
457
458 /* do fallback. */
459 kHlpAssertFailed();
460 kFsCacheObjRelease(g_pFsCache, pPathObj);
461 }
462
463 nt_fullpath(pszPath, pszFull, cbFull);
464}
465
466
467/**
468 * Special stat call used by remake.c
469 *
470 * @returns 0 on success, -1 + errno on failure.
471 * @param pszPath The path to stat.
472 * @param pStat Where to return the mtime field only.
473 */
474int stat_only_mtime(const char *pszPath, struct stat *pStat)
475{
476 KFSLOOKUPERROR enmError;
477 PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError);
478 if (pPathObj)
479 {
480 if (pPathObj->bObjType != KFSOBJ_TYPE_MISSING)
481 {
482 kHlpAssert(pPathObj->fHaveStats); /* currently always true. */
483 pStat->st_mtime = pPathObj->Stats.st_mtime;
484 kFsCacheObjRelease(g_pFsCache, pPathObj);
485 return 0;
486 }
487
488 kFsCacheObjRelease(g_pFsCache, pPathObj);
489 errno = ENOENT;
490 }
491 else
492 errno = enmError == KFSLOOKUPERROR_NOT_DIR
493 || enmError == KFSLOOKUPERROR_PATH_COMP_NOT_DIR
494 ? ENOTDIR : ENOENT;
495 return -1;
496}
497
498
499/**
500 * Invalidate missing bits of the directory cache.
501 *
502 * This is called each time a make job completes.
503 */
504void dir_cache_invalid_missing(void)
505{
506 kFsCacheInvalidateAll(g_pFsCache);
507}
508
Note: See TracBrowser for help on using the repository browser.