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

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

updates

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 13.1 KB
Line 
1/* $Id: dir-nt-bird.c 2856 2016-09-01 02:42:08Z 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 KMKNTOPENDIR *pDir = xmalloc(sizeof(*pDir));
215 pDir->pDir = (PKFSDIR)pDirObj;
216 pDir->idxNext = 0;
217 return pDir;
218 }
219 }
220 return NULL;
221}
222
223
224/**
225 * readdir for glob.
226 *
227 * @returns Pointer to DIR like handle, NULL if directory not found.
228 * @param pDir Directory enum handle by dir_glob_opendir.
229 */
230static struct dirent *dir_glob_readdir(__ptr_t pvDir)
231{
232 KMKNTOPENDIR *pDir = (KMKNTOPENDIR *)pvDir;
233 while (pDir->idxNext < pDir->pDir->cChildren)
234 {
235 PKFSOBJ pEntry = pDir->pDir->papChildren[pDir->idxNext++];
236
237 /* Don't return missing objects. */
238 if (pEntry->bObjType != KFSOBJ_TYPE_MISSING)
239 {
240 /* Copy the name that fits. If neither fits, skip the name. */
241 if (pEntry->cchName < sizeof(pDir->DirEnt.d_name))
242 {
243 pDir->DirEnt.d_namlen = pEntry->cchName;
244 memcpy(pDir->DirEnt.d_name, pEntry->pszName, pEntry->cchName + 1);
245 }
246 else if (pEntry->cchShortName < sizeof(pDir->DirEnt.d_name))
247 {
248 pDir->DirEnt.d_namlen = pEntry->cchShortName;
249 memcpy(pDir->DirEnt.d_name, pEntry->pszShortName, pEntry->cchShortName + 1);
250 }
251 else
252 continue;
253
254 pDir->DirEnt.d_reclen = offsetof(struct dirent, d_name) + pDir->DirEnt.d_namlen;
255 if (pEntry->bObjType == KFSOBJ_TYPE_DIR)
256 pDir->DirEnt.d_type = DT_DIR;
257 else if (pEntry->bObjType == KFSOBJ_TYPE_FILE)
258 pDir->DirEnt.d_type = DT_REG;
259 else
260 pDir->DirEnt.d_type = DT_UNKNOWN;
261
262 return &pDir->DirEnt;
263 }
264 }
265 return NULL;
266}
267
268
269/**
270 * closedir for glob.
271 *
272 * @param pDir Directory enum handle by dir_glob_opendir.
273 */
274static void dir_glob_closedir(__ptr_t pvDir)
275{
276 KMKNTOPENDIR *pDir = (KMKNTOPENDIR *)pvDir;
277 kFsCacheObjRelease(g_pFsCache, &pDir->pDir->Obj);
278 pDir->pDir = NULL;
279 free(pDir);
280}
281
282
283/**
284 * stat for glob.
285 *
286 * @returns 0 on success, -1 + errno on failure.
287 * @param pszPath The path to stat.
288 * @param pStat Where to return the info.
289 */
290static int dir_glob_stat(const char *pszPath, struct stat *pStat)
291{
292 KFSLOOKUPERROR enmError;
293 PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError);
294/** @todo follow symlinks vs. on symlink! */
295 if (pPathObj)
296 {
297 if (pPathObj->bObjType != KFSOBJ_TYPE_MISSING)
298 {
299 kHlpAssert(pPathObj->fHaveStats); /* currently always true. */
300 *pStat = pPathObj->Stats;
301 kFsCacheObjRelease(g_pFsCache, pPathObj);
302 return 0;
303 }
304 kFsCacheObjRelease(g_pFsCache, pPathObj);
305 }
306 errno = ENOENT;
307 return -1;
308}
309
310
311/**
312 * lstat for glob.
313 *
314 * @returns 0 on success, -1 + errno on failure.
315 * @param pszPath The path to stat.
316 * @param pStat Where to return the info.
317 */
318static int dir_glob_lstat(const char *pszPath, struct stat *pStat)
319{
320 KFSLOOKUPERROR enmError;
321 PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError);
322 if (pPathObj)
323 {
324 if (pPathObj->bObjType != KFSOBJ_TYPE_MISSING)
325 {
326 kHlpAssert(pPathObj->fHaveStats); /* currently always true. */
327 *pStat = pPathObj->Stats;
328 kFsCacheObjRelease(g_pFsCache, pPathObj);
329 return 0;
330 }
331 kFsCacheObjRelease(g_pFsCache, pPathObj);
332 }
333 errno = ENOENT;
334 return -1;
335}
336
337
338/**
339 * Checks if @a pszDir exists and is a directory.
340 *
341 * @returns 1 if is directory, 0 if isn't or doesn't exists.
342 * @param pszDir The alleged directory.
343 */
344static int dir_globl_dir_exists_p(const char *pszDir)
345{
346 int fRc;
347 KFSLOOKUPERROR enmError;
348 PKFSOBJ pDirObj = kFsCacheLookupA(g_pFsCache, pszDir, &enmError);
349 if (pDirObj)
350 {
351 fRc = pDirObj->bObjType == KFSOBJ_TYPE_DIR;
352 kFsCacheObjRelease(g_pFsCache, pDirObj);
353 }
354 else
355 fRc = 0;
356 return fRc;
357
358}
359
360
361/**
362 * Sets up pGlob with the necessary callbacks.
363 *
364 * @param pGlob Structure to populate.
365 */
366void dir_setup_glob(glob_t *pGlob)
367{
368 pGlob->gl_opendir = dir_glob_opendir;
369 pGlob->gl_readdir = dir_glob_readdir;
370 pGlob->gl_closedir = dir_glob_closedir;
371 pGlob->gl_stat = dir_glob_stat;
372#ifdef __EMX__ /* The FreeBSD implementation actually uses gl_lstat!! */
373 pGlob->gl_lstat = dir_glob_lstat;
374#else
375 pGlob->gl_exists = file_exists_p;
376 pGlob->gl_isdir = dir_globl_dir_exists_p;
377#endif
378}
379
380
381void print_dir_data_base(void)
382{
383 /** @todo. */
384}
385
386
387
388void nt_fullpath_cached(const char *pszPath, char *pszFull, size_t cbFull)
389{
390 KFSLOOKUPERROR enmError;
391 PKFSOBJ pPathObj = kFsCacheLookupA(g_pFsCache, pszPath, &enmError);
392 if (pPathObj)
393 {
394 KSIZE off = pPathObj->cchParent;
395 if (off > 0)
396 {
397 KSIZE offEnd = off + pPathObj->cchName;
398 if (offEnd < cbFull)
399 {
400 PKFSDIR pAncestor;
401
402 pszFull[off + pPathObj->cchName] = '\0';
403 memcpy(&pszFull[off], pPathObj->pszName, pPathObj->cchName);
404
405 for (pAncestor = pPathObj->pParent; off > 0; pAncestor = pAncestor->Obj.pParent)
406 {
407 kHlpAssert(off > 1);
408 kHlpAssert(pAncestor != NULL);
409 kHlpAssert(pAncestor->ObjcchName > 0);
410 pszFull[--off] = '/';
411 off -= pAncestor->Obj.cchName;
412 kHlpAssert(pAncestor->Obj.cchParent == off);
413 memcpy(&pszFull[off], pAncestor->Obj.pszName, pAncestor->Obj.cchName);
414 }
415 kFsCacheObjRelease(g_pFsCache, pPathObj);
416 return;
417 }
418 }
419 else
420 {
421 if (pPathObj->cchName + 1 < cbFull)
422 {
423 memcpy(pszFull, pPathObj->pszName, pPathObj->cchName);
424 pszFull[pPathObj->cchName] = '/';
425 pszFull[pPathObj->cchName + 1] = '\0';
426
427 kFsCacheObjRelease(g_pFsCache, pPathObj);
428 return;
429 }
430 }
431
432 /* do fallback. */
433 kHlpAssertFailed();
434 kFsCacheObjRelease(g_pFsCache, pPathObj);
435 }
436
437 nt_fullpath(pszPath, pszFull, cbFull);
438}
439
Note: See TracBrowser for help on using the repository browser.