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

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

updates

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 14.6 KB
Line 
1/* $Id: dir-nt-bird.c 2857 2016-09-01 03:39:51Z 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);
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 while (pDir->idxNext < pDir->pDir->cChildren)
238 {
239 PKFSOBJ pEntry = pDir->pDir->papChildren[pDir->idxNext++];
240
241 /* Don't return missing objects. */
242 if (pEntry->bObjType != KFSOBJ_TYPE_MISSING)
243 {
244 /* Copy the name that fits. If neither fits, skip the name. */
245 if (pEntry->cchName < sizeof(pDir->DirEnt.d_name))
246 {
247 pDir->DirEnt.d_namlen = pEntry->cchName;
248 memcpy(pDir->DirEnt.d_name, pEntry->pszName, pEntry->cchName + 1);
249 }
250 else if (pEntry->cchShortName < sizeof(pDir->DirEnt.d_name))
251 {
252 pDir->DirEnt.d_namlen = pEntry->cchShortName;
253 memcpy(pDir->DirEnt.d_name, pEntry->pszShortName, pEntry->cchShortName + 1);
254 }
255 else
256 continue;
257
258 pDir->DirEnt.d_reclen = offsetof(struct dirent, d_name) + pDir->DirEnt.d_namlen;
259 if (pEntry->bObjType == KFSOBJ_TYPE_DIR)
260 pDir->DirEnt.d_type = DT_DIR;
261 else if (pEntry->bObjType == KFSOBJ_TYPE_FILE)
262 pDir->DirEnt.d_type = DT_REG;
263 else
264 pDir->DirEnt.d_type = DT_UNKNOWN;
265
266 return &pDir->DirEnt;
267 }
268 }
269 return NULL;
270}
271
272
273/**
274 * closedir for glob.
275 *
276 * @param pDir Directory enum handle by dir_glob_opendir.
277 */
278static void dir_glob_closedir(__ptr_t pvDir)
279{
280 KMKNTOPENDIR *pDir = (KMKNTOPENDIR *)pvDir;
281 kFsCacheObjRelease(g_pFsCache, &pDir->pDir->Obj);
282 pDir->pDir = NULL;
283 free(pDir);
284}
285
286
287/**
288 * stat for glob.
289 *
290 * @returns 0 on success, -1 + errno on failure.
291 * @param pszPath The path to stat.
292 * @param pStat Where to return the info.
293 */
294static int dir_glob_stat(const char *pszPath, struct stat *pStat)
295{
296 KFSLOOKUPERROR enmError;
297 PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError);
298/** @todo follow symlinks vs. on symlink! */
299 if (pPathObj)
300 {
301 if (pPathObj->bObjType != KFSOBJ_TYPE_MISSING)
302 {
303 kHlpAssert(pPathObj->fHaveStats); /* currently always true. */
304 *pStat = pPathObj->Stats;
305 kFsCacheObjRelease(g_pFsCache, pPathObj);
306 return 0;
307 }
308 kFsCacheObjRelease(g_pFsCache, pPathObj);
309 }
310 errno = ENOENT;
311 return -1;
312}
313
314
315/**
316 * lstat 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_lstat(const char *pszPath, struct stat *pStat)
323{
324 KFSLOOKUPERROR enmError;
325 PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError);
326 if (pPathObj)
327 {
328 if (pPathObj->bObjType != KFSOBJ_TYPE_MISSING)
329 {
330 kHlpAssert(pPathObj->fHaveStats); /* currently always true. */
331 *pStat = pPathObj->Stats;
332 kFsCacheObjRelease(g_pFsCache, pPathObj);
333 return 0;
334 }
335 kFsCacheObjRelease(g_pFsCache, pPathObj);
336 errno = ENOENT;
337 }
338 else
339 errno = enmError == KFSLOOKUPERROR_NOT_DIR
340 || enmError == KFSLOOKUPERROR_PATH_COMP_NOT_DIR
341 ? ENOTDIR : ENOENT;
342
343 return -1;
344}
345
346
347/**
348 * Checks if @a pszDir exists and is a directory.
349 *
350 * @returns 1 if is directory, 0 if isn't or doesn't exists.
351 * @param pszDir The alleged directory.
352 */
353static int dir_globl_dir_exists_p(const char *pszDir)
354{
355 int fRc;
356 KFSLOOKUPERROR enmError;
357 PKFSOBJ pDirObj = kFsCacheLookupA(g_pFsCache, pszDir, &enmError);
358 if (pDirObj)
359 {
360 fRc = pDirObj->bObjType == KFSOBJ_TYPE_DIR;
361 kFsCacheObjRelease(g_pFsCache, pDirObj);
362 }
363 else
364 fRc = 0;
365 return fRc;
366
367}
368
369
370/**
371 * Sets up pGlob with the necessary callbacks.
372 *
373 * @param pGlob Structure to populate.
374 */
375void dir_setup_glob(glob_t *pGlob)
376{
377 pGlob->gl_opendir = dir_glob_opendir;
378 pGlob->gl_readdir = dir_glob_readdir;
379 pGlob->gl_closedir = dir_glob_closedir;
380 pGlob->gl_stat = dir_glob_stat;
381#ifdef __EMX__ /* The FreeBSD implementation actually uses gl_lstat!! */
382 pGlob->gl_lstat = dir_glob_lstat;
383#else
384 pGlob->gl_exists = file_exists_p;
385 pGlob->gl_isdir = dir_globl_dir_exists_p;
386#endif
387}
388
389
390void print_dir_data_base(void)
391{
392 /** @todo. */
393}
394
395
396
397void nt_fullpath_cached(const char *pszPath, char *pszFull, size_t cbFull)
398{
399 KFSLOOKUPERROR enmError;
400 PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError);
401 if (pPathObj)
402 {
403 KSIZE off = pPathObj->cchParent;
404 if (off > 0)
405 {
406 KSIZE offEnd = off + pPathObj->cchName;
407 if (offEnd < cbFull)
408 {
409 PKFSDIR pAncestor;
410
411 pszFull[off + pPathObj->cchName] = '\0';
412 memcpy(&pszFull[off], pPathObj->pszName, pPathObj->cchName);
413
414 for (pAncestor = pPathObj->pParent; off > 0; pAncestor = pAncestor->Obj.pParent)
415 {
416 kHlpAssert(off > 1);
417 kHlpAssert(pAncestor != NULL);
418 kHlpAssert(pAncestor->ObjcchName > 0);
419 pszFull[--off] = '/';
420 off -= pAncestor->Obj.cchName;
421 kHlpAssert(pAncestor->Obj.cchParent == off);
422 memcpy(&pszFull[off], pAncestor->Obj.pszName, pAncestor->Obj.cchName);
423 }
424 kFsCacheObjRelease(g_pFsCache, pPathObj);
425 return;
426 }
427 }
428 else
429 {
430 if (pPathObj->cchName + 1 < cbFull)
431 {
432 memcpy(pszFull, pPathObj->pszName, pPathObj->cchName);
433 pszFull[pPathObj->cchName] = '/';
434 pszFull[pPathObj->cchName + 1] = '\0';
435
436 kFsCacheObjRelease(g_pFsCache, pPathObj);
437 return;
438 }
439 }
440
441 /* do fallback. */
442 kHlpAssertFailed();
443 kFsCacheObjRelease(g_pFsCache, pPathObj);
444 }
445
446 nt_fullpath(pszPath, pszFull, cbFull);
447}
448
449
450/**
451 * Special stat call used by remake.c
452 *
453 * @returns 0 on success, -1 + errno on failure.
454 * @param pszPath The path to stat.
455 * @param pStat Where to return the mtime field only.
456 */
457int stat_only_mtime(const char *pszPath, struct stat *pStat)
458{
459 if (commands_started == 0)
460 {
461 KFSLOOKUPERROR enmError;
462 PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError);
463 if (pPathObj)
464 {
465 if (pPathObj->bObjType != KFSOBJ_TYPE_MISSING)
466 {
467 kHlpAssert(pPathObj->fHaveStats); /* currently always true. */
468 pStat->st_mtime = pPathObj->Stats.st_mtime;
469 kFsCacheObjRelease(g_pFsCache, pPathObj);
470 return 0;
471 }
472
473 kFsCacheObjRelease(g_pFsCache, pPathObj);
474 errno = ENOENT;
475 }
476 else
477 errno = enmError == KFSLOOKUPERROR_NOT_DIR
478 || enmError == KFSLOOKUPERROR_PATH_COMP_NOT_DIR
479 ? ENOTDIR : ENOENT;
480 return -1;
481 }
482 /** @todo implement cache refreshing. */
483 return birdStatFollowLink(pszPath, pStat);
484}
485
Note: See TracBrowser for help on using the repository browser.