source: trunk/kLdr/kLdrDyldFind.c@ 3003

Last change on this file since 3003 was 2886, checked in by bird, 19 years ago

Bugfixing.

  • Property svn:keywords set to Id
File size: 37.8 KB
Line 
1/* $Id: kLdrDyldFind.c 2886 2006-11-18 15:01:05Z bird $ */
2/** @file
3 *
4 * kLdr - The Dynamic Loader, File Searching Methods.
5 *
6 * Copyright (c) 2006 knut st. osmundsen <bird-kbuild-src@anduin.net>
7 *
8 *
9 * This file is part of kLdr.
10 *
11 * kLdr is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * kLdr is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kLdr; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
27
28
29/*******************************************************************************
30* Header Files *
31*******************************************************************************/
32#ifdef __OS2__
33# define INCL_BASE
34# define INCL_ERRORS
35# include <os2.h>
36# ifndef LIBPATHSTRICT
37# define LIBPATHSTRICT 3
38# endif
39 extern APIRET APIENTRY DosQueryHeaderInfo(HMODULE hmod, ULONG ulIndex, PVOID pvBuffer, ULONG cbBuffer, ULONG ulSubFunction);
40# define QHINF_EXEINFO 1 /* NE exeinfo. */
41# define QHINF_READRSRCTBL 2 /* Reads from the resource table. */
42# define QHINF_READFILE 3 /* Reads from the executable file. */
43# define QHINF_LIBPATHLENGTH 4 /* Gets the libpath length. */
44# define QHINF_LIBPATH 5 /* Gets the entire libpath. */
45# define QHINF_FIXENTRY 6 /* NE only */
46# define QHINF_STE 7 /* NE only */
47# define QHINF_MAPSEL 8 /* NE only */
48
49#elif defined(__WIN__)
50# include <Windows.h>
51#endif
52
53#include <kLdr.h>
54#include "kLdrHlp.h"
55#include "kLdrInternal.h"
56
57/*******************************************************************************
58* Defined Constants And Macros *
59*******************************************************************************/
60/** @def KLDRDYLDFIND_STRICT
61 * Define KLDRDYLDFIND_STRICT to enabled strict checks in kLdrDyldFind. */
62#define KLDRDYLDFIND_STRICT 1
63
64/** @def KLDRDYLDFIND_ASSERT
65 * Assert that an expression is true when KLDRDYLDFIND_STRICT is defined.
66 */
67#ifdef KLDRDYLDFIND_STRICT
68# define KLDRDYLDFIND_ASSERT(expr) kldrHlpAssert(expr)
69#else
70# define KLDRDYLDFIND_ASSERT(expr) do {} while (0)
71#endif
72
73
74/*******************************************************************************
75* Structures and Typedefs *
76*******************************************************************************/
77/**
78 * Search arguments.
79 * This avoids a bunch of unnecessary string lengths and calculations.
80 */
81typedef struct KLDRDYLDFINDARGS
82{
83 const char *pszName;
84 size_t cchName;
85
86 const char *pszPrefix;
87 size_t cchPrefix;
88
89 const char *pszSuffix;
90 size_t cchSuffix;
91
92 size_t cchMaxLength;
93
94 KLDRDYLDSEARCH enmSearch;
95 uint32_t fFlags;
96 PPKLDRRDR ppRdr;
97} KLDRDYLDFINDARGS, *PKLDRDYLDFINDARGS;
98
99typedef const KLDRDYLDFINDARGS *PCKLDRDYLDFINDARGS;
100
101
102/*******************************************************************************
103* Global Variables *
104*******************************************************************************/
105/** @name The kLdr search method parameters.
106 * @{ */
107/** The kLdr EXE search path.
108 * During EXE searching the it's initialized with the values of the KLDR_PATH and
109 * the PATH env.vars. Both ';' and ':' can be used as separators.
110 */
111char kLdrDyldExePath[8192];
112/** The kLdr DLL search path.
113 * During initialization the KLDR_LIBRARY_PATH env.var. and the path in the
114 * executable stub is appended. Both ';' and ':' can be used as separators.
115 */
116char kLdrDyldLibraryPath[8192];
117/** The kLdr application directory.
118 * This is initialized when the executable is 'loaded' or by a kLdr user.
119 */
120char kLdrDyldAppDir[260];
121/** The default kLdr DLL prefix.
122 * This is initialized with the KLDR_DEF_PREFIX env.var. + the prefix in the executable stub.
123 */
124char kLdrDyldDefPrefix[16];
125/** The default kLdr DLL suffix.
126 * This is initialized with the KLDR_DEF_SUFFIX env.var. + the prefix in the executable stub.
127 */
128char kLdrDyldDefSuffix[16];
129/** @} */
130
131
132/** @name The OS/2 search method parameters.
133 * @{
134 */
135/** The OS/2 LIBPATH.
136 * This is queried from the os2krnl on OS/2, while on other systems initialized using
137 * the KLDR_OS2_LIBPATH env.var.
138 */
139char kLdrDyldOS2Libpath[2048];
140/** The OS/2 LIBPATHSTRICT ("T" or '\0').
141 * This is queried from the os2krnl on OS/2, while on other systems initialized using
142 * the KLDR_OS2_LIBPATHSTRICT env.var.
143 */
144char kLdrDyldOS2LibpathStrict[8];
145/** The OS/2 BEGINLIBPATH.
146 * This is queried from the os2krnl on OS/2, while on other systems initialized using
147 * the KLDR_OS2_BEGINLIBPATH env.var.
148 */
149char kLdrDyldOS2BeginLibpath[2048];
150/** The OS/2 ENDLIBPATH.
151 * This is queried from the os2krnl on OS/2, while on other systems initialized using
152 * the KLDR_OS2_ENDLIBPATH env.var.
153 */
154char kLdrDyldOS2EndLibpath[2048];
155/** @} */
156
157
158/** @name The Windows search method parameters.
159 * @{ */
160/** The Windows application directory.
161 * This is initialized when the executable is 'loaded' or by a kLdr user.
162 */
163char kLdrDyldWindowsAppDir[260];
164/** The Windows system directory.
165 * This is queried from the Win32/64 subsystem on Windows, while on other systems
166 * initialized using the KLDR_WINDOWS_SYSTEM_DIR env.var.
167 */
168char kLdrDyldWindowsSystemDir[260];
169/** The Windows directory.
170 * This is queried from the Win32/64 subsystem on Windows, while on other systems
171 * initialized using the KLDR_WINDOWS_DIR env.var.
172 */
173char kLdrDyldWindowsDir[260];
174/** The Windows path.
175 * This is queried from the PATH env.var. on Windows, while on other systems
176 * initialized using the KLDR_WINDOWS_PATH env.var. and falling back on
177 * the PATH env.var. if it wasn't found.
178 */
179char kLdrDyldWindowsPath[8192];
180/** @} */
181
182
183/** @name The Common Unix search method parameters.
184 * @{
185 */
186/** The Common Unix library path.
187 * Initialized from the env.var. KLDR_UNIX_LIBRARY_PATH or LD_LIBRARY_PATH or the
188 * former wasn't found.
189 */
190char kLdrDyldUnixLibraryPath[8192];
191/** The Common Unix system library path. */
192char kLdrDyldUnixSystemLibraryPath[1024] = "/lib;/usr/lib";
193/** @} */
194
195/** @todo Deal with DT_RUNPATH and DT_RPATH. */
196/** @todo ld.so.cache? */
197
198
199/*******************************************************************************
200* Internal Functions *
201*******************************************************************************/
202static int kldrDyldFindDoDllSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix,
203 KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRRDR ppRdr);
204static int kldrDyldFindDoExeSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix,
205 KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRRDR ppRdr);
206static int kldrDyldFindTryOpen(const char *pszFilename, PPKLDRRDR ppRdr);
207static int kldrDyldFindTryOpenPath(const char *pchPath, size_t cchPath, PCKLDRDYLDFINDARGS pArgs);
208static int kldrDyldFindEnumeratePath(const char *pszSearchPath, PCKLDRDYLDFINDARGS pArgs);
209static int kldrDyldFindGetDefaults(KLDRDYLDSEARCH *penmSearch, const char **pszPrefix,
210 const char **pszSuffix, const char *pszName, uint32_t fFlags);
211
212
213/**
214 * Initializes the find paths.
215 *
216 * @returns 0 on success, non-zero on failure.
217 */
218int kldrDyldFindInit(void)
219{
220 size_t cch;
221 int rc;
222 char szTmp[sizeof(kLdrDyldDefSuffix)];
223
224 /*
225 * The kLdr search parameters.
226 */
227 rc = kldrHlpGetEnv("KLDR_LIBRARY_PATH", kLdrDyldLibraryPath, sizeof(kLdrDyldLibraryPath));
228 rc = kldrHlpGetEnv("KLDR_DEF_PREFIX", szTmp, sizeof(szTmp));
229 if (!rc)
230 kLdrHlpMemCopy(kLdrDyldDefPrefix, szTmp, sizeof(szTmp));
231 rc = kldrHlpGetEnv("KLDR_DEF_SUFFIX", szTmp, sizeof(szTmp));
232 if (!rc)
233 kLdrHlpMemCopy(kLdrDyldDefSuffix, szTmp, sizeof(szTmp));
234
235 /*
236 * The OS/2 search parameters.
237 */
238#ifdef __OS2__
239 rc = DosQueryHeaderInfo(NULLHANDLE, 0, kLdrDyldOS2Libpath, sizeof(kLdrDyldOS2Libpath), QHINF_LIBPATH);
240 if (rc)
241 return rc;
242 rc = DosQueryExtLIBPATH((PSZ)kLdrDyldOS2LibpathStrict, LIBPATHSTRICT);
243 if (rc)
244 kLdrDyldOS2LibpathStrict[0] = '\0';
245 rc = DosQueryExtLIBPATH((PSZ)kLdrDyldOS2BeginLibpath, BEGIN_LIBPATH);
246 if (rc)
247 kLdrDyldOS2BeginLibpath[0] = '\0';
248 rc = DosQueryExtLIBPATH((PSZ)kLdrDyldOS2EndLibpath, END_LIBPATH);
249 if (rc)
250 kLdrDyldOS2EndLibpath[0] = '\0';
251
252#else
253 kldrHlpGetEnv("KLDR_OS2_LIBPATH", kLdrDyldOS2Libpath, sizeof(kLdrDyldOS2Libpath));
254 kldrHlpGetEnv("KLDR_OS2_LIBPATHSTRICT", kLdrDyldOS2LibpathStrict, sizeof(kLdrDyldOS2LibpathStrict));
255 if ( kLdrDyldOS2LibpathStrict[0] == 'T'
256 || kLdrDyldOS2LibpathStrict[0] == 't')
257 kLdrDyldOS2LibpathStrict[0] = 'T';
258 else
259 kLdrDyldOS2LibpathStrict[0] = '\0';
260 kLdrDyldOS2LibpathStrict[1] = '\0';
261 kldrHlpGetEnv("KLDR_OS2_BEGINLIBPATH", kLdrDyldOS2BeginLibpath, sizeof(kLdrDyldOS2BeginLibpath));
262 kldrHlpGetEnv("KLDR_OS2_ENDLIBPATH", kLdrDyldOS2EndLibpath, sizeof(kLdrDyldOS2EndLibpath));
263#endif
264
265 /*
266 * The windows search parameters.
267 */
268#if defined(__WIN__)
269 cch = GetSystemDirectory(kLdrDyldWindowsSystemDir, sizeof(kLdrDyldWindowsSystemDir));
270 if (cch >= sizeof(kLdrDyldWindowsSystemDir))
271 return (rc = GetLastError()) ? rc : -1;
272 cch = GetWindowsDirectory(kLdrDyldWindowsDir, sizeof(kLdrDyldWindowsDir));
273 if (cch >= sizeof(kLdrDyldWindowsDir))
274 return (rc = GetLastError()) ? rc : -1;
275 kldrHlpGetEnv("PATH", kLdrDyldWindowsPath, sizeof(kLdrDyldWindowsPath));
276#else
277 kldrHlpGetEnv("KLDR_WINDOWS_SYSTEM_DIR", kLdrDyldWindowsSystemDir, sizeof(kLdrDyldWindowsSystemDir));
278 kldrHlpGetEnv("KLDR_WINDOWS_DIR", kLdrDyldWindowsDir, sizeof(kLdrDyldWindowsDir));
279 rc = kldrHlpGetEnv("KLDR_WINDOWS_PATH", kLdrDyldWindowsPath, sizeof(kLdrDyldWindowsPath));
280 if (rc)
281 kldrHlpGetEnv("PATH", kLdrDyldWindowsPath, sizeof(kLdrDyldWindowsPath));
282#endif
283
284 /*
285 * The Unix search parameters.
286 */
287 rc = kldrHlpGetEnv("KLDR_UNIX_LIBRARY_PATH", kLdrDyldUnixLibraryPath, sizeof(kLdrDyldUnixLibraryPath));
288 if (rc)
289 kldrHlpGetEnv("LD_LIBRARY_PATH", kLdrDyldUnixLibraryPath, sizeof(kLdrDyldUnixLibraryPath));
290
291 (void)cch;
292 return 0;
293}
294
295
296/**
297 * Lazily initialize the two application directory paths.
298 */
299static void kldrDyldFindLazyInitAppDir(void)
300{
301 if (!kLdrDyldAppDir[0])
302 {
303#if defined(__OS2__)
304 PPIB pPib;
305 PTIB pTib;
306 APIRET rc;
307
308 DosGetInfoBlocks(&pTib, &pPib);
309 rc = DosQueryModuleName(pPib->pib_hmte, sizeof(kLdrDyldAppDir), kLdrDyldAppDir);
310 if (!rc)
311 {
312 *kldrHlpGetFilename(kLdrDyldAppDir) = '\0';
313 kLdrHlpMemCopy(kLdrDyldWindowsAppDir, kLdrDyldAppDir, sizeof(kLdrDyldAppDir));
314 }
315 else
316 {
317 kLdrDyldWindowsAppDir[0] = kLdrDyldAppDir[0] = '.';
318 kLdrDyldWindowsAppDir[1] = kLdrDyldAppDir[1] = '\0';
319 }
320
321
322#elif defined(__WIN__)
323 DWORD dwSize = GetModuleFileName(NULL /* the executable */, kLdrDyldAppDir, sizeof(kLdrDyldAppDir));
324 if (dwSize > 0)
325 {
326 *kldrHlpGetFilename(kLdrDyldAppDir) = '\0';
327 kLdrHlpMemCopy(kLdrDyldWindowsAppDir, kLdrDyldAppDir, sizeof(kLdrDyldAppDir));
328 }
329 else
330 {
331 kLdrDyldWindowsAppDir[0] = kLdrDyldAppDir[0] = '.';
332 kLdrDyldWindowsAppDir[1] = kLdrDyldAppDir[1] = '\0';
333 }
334
335#else
336# error "Port me"
337#endif
338 }
339}
340
341
342/**
343 * Locates and opens a module using the specified search method.
344 *
345 * @returns 0 and *ppMod on success, non-zero OS specific error on failure.
346 *
347 * @param pszName Partial or complete name, it's specific to the search method to determin which.
348 * @param pszPrefix Prefix than can be used when searching.
349 * @param pszSuffix Suffix than can be used when searching.
350 * @param enmSearch The file search method to apply.
351 * @param fFlags Search flags.
352 * @param ppMod Where to store the file provider instance on success.
353 */
354int kldrDyldFindNewModule(const char *pszName, const char *pszPrefix, const char *pszSuffix,
355 KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod)
356{
357 int rc;
358 PKLDRRDR pRdr = NULL;
359
360 *ppMod = NULL;
361
362 /*
363 * If this isn't just a filename, we the caller has specified a file
364 * that should be opened directly and not a module name to be searched for.
365 */
366 if (!kldrHlpIsFilenameOnly(pszName))
367 rc = kldrDyldFindTryOpen(pszName, &pRdr);
368 else if (!(fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE))
369 rc = kldrDyldFindDoDllSearch(pszName, pszPrefix, pszSuffix, enmSearch, fFlags, &pRdr);
370 else
371 rc = kldrDyldFindDoExeSearch(pszName, pszPrefix, pszSuffix, enmSearch, fFlags, &pRdr);
372 if (!rc)
373 {
374#ifdef KLDRDYLDFIND_STRICT
375 /* Sanity check of kldrDyldFindExistingModule. */
376 if (fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE)
377 {
378 const char *pszFilename = kLdrRdrName(pRdr);
379 const size_t cchFilename = kLdrHlpStrLen(pszFilename);
380 PKLDRDYLDMOD pCur;
381 for (pCur = kLdrDyldHead; pCur; pCur = pCur->Load.pNext)
382 KLDRDYLDFIND_ASSERT( pCur->pMod->cchFilename != cchFilename
383 || kLdrHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename));
384 }
385#endif
386
387 /*
388 * Check for matching non-global modules that should be promoted.
389 */
390 if (!(fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE))
391 {
392 const char *pszFilename = kLdrRdrName(pRdr);
393 const size_t cchFilename = kLdrHlpStrLen(pszFilename);
394 PKLDRDYLDMOD pCur;
395 for (pCur = kLdrDyldHead; pCur; pCur = pCur->Load.pNext)
396 {
397 if ( !pCur->fGlobalOrSpecific
398 && pCur->pMod->cchFilename == cchFilename
399 && !kLdrHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename))
400 {
401 kLdrRdrClose(pRdr);
402 kldrDyldModMarkGlobal(pCur);
403 *ppMod = pCur;
404 return 0;
405 }
406 KLDRDYLDFIND_ASSERT( pCur->pMod->cchFilename != cchFilename
407 || kLdrHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename));
408 }
409 }
410
411 /*
412 * Create a new module.
413 */
414 rc = kldrDyldModCreate(pRdr, fFlags, ppMod);
415 if (rc)
416 kLdrRdrClose(pRdr);
417 }
418 return rc;
419}
420
421
422/**
423 * Searches for a DLL file using the specified method.
424 *
425 * @returns 0 on success and *ppMod pointing to the new module.
426 * @returns KLDR_ERR_MODULE_NOT_FOUND if the specified file couldn't be opened.
427 * @returns non-zero kLdr or OS specific status code on other failures.
428 * @param pszName The name.
429 * @param pszPrefix The prefix, optional.
430 * @param pszSuffix The suffix, optional.
431 * @param enmSearch The search method.
432 * @param fFlags The load/search flags.
433 * @param ppRdr Where to store the pointer to the file provider instance on success.
434 */
435static int kldrDyldFindDoDllSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix,
436 KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRRDR ppRdr)
437{
438 int rc;
439 KLDRDYLDFINDARGS Args;
440
441 /*
442 * Initialize the argument structure and resolve defaults.
443 */
444 Args.enmSearch = enmSearch;
445 Args.pszPrefix = pszPrefix;
446 Args.pszSuffix = pszSuffix;
447 rc = kldrDyldFindGetDefaults(&Args.enmSearch, &Args.pszPrefix, &Args.pszSuffix, pszName, fFlags);
448 if (rc)
449 return rc;
450 Args.pszName = pszName;
451 Args.cchName = kLdrHlpStrLen(pszName);
452 Args.cchPrefix = Args.pszPrefix ? kLdrHlpStrLen(Args.pszPrefix) : 0;
453 Args.cchSuffix = Args.pszSuffix ? kLdrHlpStrLen(Args.pszSuffix) : 0;
454 Args.cchMaxLength = Args.cchName + Args.cchSuffix + Args.cchPrefix;
455 Args.fFlags = fFlags;
456 Args.ppRdr = ppRdr;
457
458 /*
459 * Apply the specified search method.
460 */
461/** @todo get rid of the strlen() on the various paths here! */
462 switch (Args.enmSearch)
463 {
464 case KLDRDYLD_SEARCH_KLDR:
465 {
466 kldrDyldFindLazyInitAppDir();
467 if (kLdrDyldAppDir[0] != '\0')
468 {
469 rc = kldrDyldFindTryOpenPath(kLdrDyldAppDir, kLdrHlpStrLen(kLdrDyldAppDir), &Args);
470 if (rc != KLDR_ERR_MODULE_NOT_FOUND)
471 break;
472 }
473 rc = kldrDyldFindTryOpenPath(".", 1, &Args);
474 if (rc != KLDR_ERR_MODULE_NOT_FOUND)
475 break;
476 rc = kldrDyldFindEnumeratePath(kLdrDyldLibraryPath, &Args);
477 break;
478 }
479
480 case KLDRDYLD_SEARCH_OS2:
481 {
482 rc = kldrDyldFindEnumeratePath(kLdrDyldOS2BeginLibpath, &Args);
483 if (rc != KLDR_ERR_MODULE_NOT_FOUND)
484 break;
485 rc = kldrDyldFindEnumeratePath(kLdrDyldOS2Libpath, &Args);
486 if (rc != KLDR_ERR_MODULE_NOT_FOUND)
487 break;
488 rc = kldrDyldFindEnumeratePath(kLdrDyldOS2EndLibpath, &Args);
489 break;
490 }
491
492 case KLDRDYLD_SEARCH_WINDOWS:
493 case KLDRDYLD_SEARCH_WINDOWS_ALTERED:
494 {
495 kldrDyldFindLazyInitAppDir();
496 rc = kldrDyldFindTryOpenPath(kLdrDyldWindowsAppDir, kLdrHlpStrLen(kLdrDyldWindowsAppDir), &Args);
497 if (rc != KLDR_ERR_MODULE_NOT_FOUND)
498 break;
499 if (Args.enmSearch == KLDRDYLD_SEARCH_WINDOWS_ALTERED)
500 {
501 rc = kldrDyldFindTryOpenPath(".", 1, &Args);
502 if (rc != KLDR_ERR_MODULE_NOT_FOUND)
503 break;
504 }
505 rc = kldrDyldFindTryOpenPath(kLdrDyldWindowsSystemDir, kLdrHlpStrLen(kLdrDyldWindowsSystemDir), &Args);
506 if (rc != KLDR_ERR_MODULE_NOT_FOUND)
507 break;
508 rc = kldrDyldFindTryOpenPath(kLdrDyldWindowsDir, kLdrHlpStrLen(kLdrDyldWindowsDir), &Args);
509 if (rc != KLDR_ERR_MODULE_NOT_FOUND)
510 break;
511 if (Args.enmSearch == KLDRDYLD_SEARCH_WINDOWS)
512 {
513 rc = kldrDyldFindTryOpenPath(".", 1, &Args);
514 if (rc != KLDR_ERR_MODULE_NOT_FOUND)
515 break;
516 }
517 rc = kldrDyldFindEnumeratePath(kLdrDyldWindowsPath, &Args);
518 break;
519 }
520
521 case KLDRDYLD_SEARCH_UNIX_COMMON:
522 {
523 rc = kldrDyldFindEnumeratePath(kLdrDyldUnixLibraryPath, &Args);
524 if (rc == KLDR_ERR_MODULE_NOT_FOUND)
525 break;
526 rc = kldrDyldFindEnumeratePath(kLdrDyldUnixSystemLibraryPath, &Args);
527 break;
528 }
529
530 default: kldrHlpAssert(!"internal error"); return -1;
531 }
532 return rc;
533}
534
535
536/**
537 * Searches for an EXE file using the specified method.
538 *
539 * @returns 0 on success and *ppMod pointing to the new module.
540 * @returns KLDR_ERR_MODULE_NOT_FOUND if the specified file couldn't be opened.
541 * @returns non-zero kLdr or OS specific status code on other failures.
542 * @param pszName The name.
543 * @param pszPrefix The prefix, optional.
544 * @param pszSuffix The suffix, optional.
545 * @param enmSearch The search method.
546 * @param fFlags The load/search flags.
547 * @param ppRdr Where to store the pointer to the file provider instance on success.
548 */
549static int kldrDyldFindDoExeSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix,
550 KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRRDR ppRdr)
551{
552 int rc;
553 KLDRDYLDFINDARGS Args;
554
555 /*
556 * Initialize the argument structure and resolve defaults.
557 */
558 Args.enmSearch = enmSearch;
559 Args.pszPrefix = pszPrefix;
560 Args.pszSuffix = pszSuffix;
561 rc = kldrDyldFindGetDefaults(&Args.enmSearch, &Args.pszPrefix, &Args.pszSuffix, pszName, fFlags);
562 if (rc)
563 return rc;
564 Args.pszName = pszName;
565 Args.cchName = kLdrHlpStrLen(pszName);
566 Args.cchPrefix = Args.pszPrefix ? kLdrHlpStrLen(Args.pszPrefix) : 0;
567 Args.cchSuffix = Args.pszSuffix ? kLdrHlpStrLen(Args.pszSuffix) : 0;
568 Args.cchMaxLength = Args.cchName + Args.cchSuffix + Args.cchPrefix;
569 Args.fFlags = fFlags;
570 Args.ppRdr = ppRdr;
571
572 /*
573 * If we're bootstrapping a process, we'll start by looking in the
574 * application directory and the check out the path.
575 */
576 if (g_fBootstrapping)
577 {
578 kldrDyldFindLazyInitAppDir();
579 if (kLdrDyldAppDir[0] != '\0')
580 {
581 rc = kldrDyldFindTryOpenPath(kLdrDyldAppDir, kLdrHlpStrLen(kLdrDyldAppDir), &Args);
582 if (rc != KLDR_ERR_MODULE_NOT_FOUND)
583 return rc;
584 }
585 }
586
587 /*
588 * Search the EXE search path. Initialize it the first time around.
589 */
590 if (!kLdrDyldExePath[0])
591 {
592 size_t cch;
593 kldrHlpGetEnv("KLDR_EXE_PATH", kLdrDyldExePath, sizeof(kLdrDyldExePath) - 10);
594 cch = kLdrHlpStrLen(kLdrDyldExePath);
595 kLdrDyldExePath[cch++] = ';';
596 kldrHlpGetEnv("PATH", &kLdrDyldExePath[cch], sizeof(kLdrDyldExePath) - cch);
597 }
598 return kldrDyldFindEnumeratePath(kLdrDyldExePath, &Args);
599}
600
601
602/**
603 * Try open the specfied file.
604 *
605 * @returns 0 on success and *ppMod pointing to the new module.
606 * @returns KLDR_ERR_MODULE_NOT_FOUND if the specified file couldn't be opened.
607 * @returns non-zero kLdr or OS specific status code on other failures.
608 * @param pszFilename The filename.
609 * @param ppRdr Where to store the pointer to the new module.
610 */
611static int kldrDyldFindTryOpen(const char *pszFilename, PPKLDRRDR ppRdr)
612{
613 int rc;
614
615 /*
616 * Try open the file.
617 */
618 rc = kLdrRdrOpen(ppRdr, pszFilename);
619 if (!rc)
620 return 0;
621 /** @todo deal with return codes properly. */
622 if (rc >= KLDR_ERR_BASE && rc <= KLDR_ERR_END)
623 return rc;
624
625 return KLDR_ERR_MODULE_NOT_FOUND;
626}
627
628
629/**
630 * Composes a filename from the specified directory path,
631 * prefix (optional), name and suffix (optional, will try with and without).
632 *
633 * @param pchPath The directory path - this doesn't have to be null terminated.
634 * @param cchPath The length of the path.
635 * @param pArgs The search argument structure.
636 *
637 * @returns See kldrDyldFindTryOpen
638 */
639static int kldrDyldFindTryOpenPath(const char *pchPath, size_t cchPath, PCKLDRDYLDFINDARGS pArgs)
640{
641 static char s_szFilename[1024];
642 char *psz;
643 int rc;
644
645 /*
646 * Ignore any attempts at opening empty paths.
647 * This can happen when a *Dir globals is empty.
648 */
649 if (!cchPath)
650 return KLDR_ERR_MODULE_NOT_FOUND; /* ignore */
651
652 /*
653 * Limit check first.
654 */
655 if (cchPath + 1 + pArgs->cchMaxLength >= sizeof(s_szFilename))
656 {
657 KLDRDYLDFIND_ASSERT(!"too long");
658 return KLDR_ERR_MODULE_NOT_FOUND; /* ignore */
659 }
660
661 /*
662 * The directory path.
663 */
664 kLdrHlpMemCopy(s_szFilename, pchPath, cchPath);
665 psz = &s_szFilename[cchPath];
666 if (psz[-1] != '/'
667#if defined(__OS2__) || defined(__WIN__)
668 && psz[-1] != '\\'
669 && psz[-1] != ':'
670#endif
671 )
672 *psz++ = '/';
673
674 /*
675 * The name.
676 */
677 if (pArgs->cchPrefix)
678 {
679 kLdrHlpMemCopy(psz, pArgs->pszPrefix, pArgs->cchPrefix);
680 psz += pArgs->cchPrefix;
681 }
682 kLdrHlpMemCopy(psz, pArgs->pszName, pArgs->cchName);
683 psz += pArgs->cchName;
684 if (pArgs->cchSuffix)
685 {
686 kLdrHlpMemCopy(psz, pArgs->pszSuffix, pArgs->cchSuffix);
687 psz += pArgs->cchSuffix;
688 }
689 *psz = '\0';
690
691
692 /*
693 * Try open it.
694 */
695 rc = kldrDyldFindTryOpen(s_szFilename, pArgs->ppRdr);
696 /* If we're opening an executable, try again without the suffix.*/
697 if ( rc
698 && pArgs->cchSuffix
699 && (pArgs->fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE))
700 {
701 psz -= pArgs->cchSuffix;
702 *psz = '\0';
703 rc = kldrDyldFindTryOpen(s_szFilename, pArgs->ppRdr);
704 }
705 return rc;
706}
707
708
709/**
710 * Enumerates the specfied path.
711 *
712 * @returns Any return code from the kldrDyldFindTryOpenPath() which isn't KLDR_ERR_MODULE_NOT_FOUND.
713 * @returns KLDR_ERR_MODULE_NOT_FOUND if the end of the search path was reached.
714 * @param pszSearchPath The search path to enumeare.
715 * @param pArgs The search argument structure.
716 */
717static int kldrDyldFindEnumeratePath(const char *pszSearchPath, PCKLDRDYLDFINDARGS pArgs)
718{
719 const char *psz = pszSearchPath;
720 for (;;)
721 {
722 const char *pszEnd;
723 size_t cchPath;
724
725 /*
726 * Trim.
727 */
728 while (*psz == ';' || *psz == ':')
729 psz++;
730 if (*psz == '\0')
731 return KLDR_ERR_MODULE_NOT_FOUND;
732
733 /*
734 * Find the end.
735 */
736 pszEnd = psz + 1;
737 while ( *pszEnd != '\0'
738 && *pszEnd != ';'
739#if defined(__OS2__) || defined(__WIN__)
740 && ( *pszEnd != ':'
741 || ( pszEnd - psz == 1
742 && ( (*psz >= 'A' && *psz <= 'Z')
743 || (*psz >= 'a' && *psz <= 'z')
744 )
745 )
746 )
747#else
748 && *pszEnd != ':'
749#endif
750 )
751 pszEnd++;
752
753 /*
754 * If not empty path, try open the module using it.
755 */
756 cchPath = pszEnd - psz;
757 if (cchPath > 0)
758 {
759 int rc;
760 rc = kldrDyldFindTryOpenPath(psz, cchPath, pArgs);
761 if (rc != KLDR_ERR_MODULE_NOT_FOUND)
762 return rc;
763 }
764
765 /* next */
766 psz = pszEnd;
767 }
768}
769
770
771/**
772 * Resolve default search method, prefix and suffix.
773 *
774 * @returns 0 on success, KLDR_ERR_INVALID_PARAMETER on failure.
775 * @param penmSearch The search method. In/Out.
776 * @param ppszPrefix The prefix. In/Out.
777 * @param ppszSuffix The suffix. In/Out.
778 * @param pszName The name. In.
779 * @param fFlags The load/search flags.
780 */
781static int kldrDyldFindGetDefaults(KLDRDYLDSEARCH *penmSearch, const char **ppszPrefix, const char **ppszSuffix,
782 const char *pszName, uint32_t fFlags)
783{
784 unsigned fCaseSensitive;
785
786 /*
787 * Fixup search method alias.
788 */
789 if (*penmSearch == KLDRDYLD_SEARCH_HOST)
790#if defined(__OS2__)
791 *penmSearch = KLDRDYLD_SEARCH_OS2;
792#elif defined(__WIN__)
793 *penmSearch = KLDRDYLD_SEARCH_WINDOWS;
794#else
795# error "Port me"
796#endif
797
798 /*
799 * Apply search method specific prefix/suffix.
800 */
801 switch (*penmSearch)
802 {
803 case KLDRDYLD_SEARCH_KLDR:
804 if (!*ppszPrefix && kLdrDyldDefPrefix[0])
805 *ppszPrefix = kLdrDyldDefPrefix;
806 if (!*ppszSuffix && kLdrDyldDefSuffix[0])
807 *ppszSuffix = kLdrDyldDefSuffix;
808 fCaseSensitive = 1;
809 break;
810
811 case KLDRDYLD_SEARCH_OS2:
812 if (!*ppszSuffix)
813 *ppszSuffix = !(fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE) ? ".dll" : ".exe";
814 fCaseSensitive = 0;
815 break;
816
817 case KLDRDYLD_SEARCH_WINDOWS:
818 case KLDRDYLD_SEARCH_WINDOWS_ALTERED:
819 if (!*ppszSuffix)
820 *ppszSuffix = !(fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE) ? ".dll" : ".exe";
821 fCaseSensitive = 0;
822 break;
823
824 case KLDRDYLD_SEARCH_UNIX_COMMON:
825 fCaseSensitive = 1;
826 break;
827
828 default:
829 KLDRDYLDFIND_ASSERT(!"invalid search method");
830 return KLDR_ERR_INVALID_PARAMETER;
831 }
832
833 /*
834 * Drop the suffix if it's already included in the name.
835 */
836 if (*ppszSuffix)
837 {
838 const size_t cchName = kLdrHlpStrLen(pszName);
839 const size_t cchSuffix = kLdrHlpStrLen(*ppszSuffix);
840 if ( cchName > cchSuffix
841 && ( fCaseSensitive
842 ? !kLdrHlpMemComp(pszName + cchName - cchSuffix, *ppszSuffix, cchSuffix)
843 : !kLdrHlpMemIComp(pszName + cchName - cchSuffix, *ppszSuffix, cchSuffix))
844 )
845 *ppszSuffix = NULL;
846 }
847
848 return 0;
849}
850
851
852/**
853 * Locates an already open module using the specified search method.
854 *
855 * @returns 0 and *ppMod on success, non-zero OS specific error on failure.
856 *
857 * @param pszName Partial or complete name, it's specific to the search method to determin which.
858 * @param pszPrefix Prefix than can be used when searching.
859 * @param pszSuffix Suffix than can be used when searching.
860 * @param enmSearch The file search method to apply.
861 * @param fFlags Search flags.
862 * @param ppMod Where to store the file provider instance on success.
863 */
864int kldrDyldFindExistingModule(const char *pszName, const char *pszPrefix, const char *pszSuffix,
865 KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod)
866{
867
868 int rc;
869 unsigned fOS2LibpathStrict;
870 *ppMod = NULL;
871
872 /*
873 * Don't bother if no modules are loaded yet.
874 */
875 if (!kLdrDyldHead)
876 return KLDR_ERR_MODULE_NOT_FOUND;
877
878 /*
879 * Defaults.
880 */
881 rc = kldrDyldFindGetDefaults(&enmSearch, &pszPrefix, &pszSuffix, pszName, fFlags);
882 if (rc)
883 return rc;
884
885 /*
886 * If this isn't just a filename, the caller has specified a file
887 * that should be opened directly and not a module name to be searched for.
888 *
889 * In order to do the right thing we'll have to open the file and get the
890 * correct filename for it.
891 *
892 * The OS/2 libpath strict method require us to find the correct DLL first.
893 */
894 fOS2LibpathStrict = 0;
895 if ( !kldrHlpIsFilenameOnly(pszName)
896 || (fOS2LibpathStrict = ( enmSearch == KLDRDYLD_SEARCH_OS2
897 && kLdrDyldOS2LibpathStrict[0] == 'T')
898 )
899 )
900 {
901 PKLDRRDR pRdr;
902 if (fOS2LibpathStrict)
903 rc = kldrDyldFindDoDllSearch(pszName, pszPrefix, pszSuffix, enmSearch, fFlags, &pRdr);
904 else
905 rc = kldrDyldFindTryOpen(pszName, &pRdr);
906 if (!rc)
907 {
908 /* do a filename based search. */
909 const char *pszFilename = kLdrRdrName(pRdr);
910 const size_t cchFilename = kLdrHlpStrLen(pszFilename);
911 PKLDRDYLDMOD pCur;
912 rc = KLDR_ERR_MODULE_NOT_FOUND;
913 for (pCur = kLdrDyldHead; pCur; pCur = pCur->Load.pNext)
914 {
915 if ( pCur->pMod->cchFilename == cchFilename
916 && !kLdrHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename))
917 {
918 *ppMod = pCur;
919 rc = 0;
920 break;
921 }
922 }
923 kLdrRdrClose(pRdr);
924 }
925 }
926 else
927 {
928 const size_t cchName = kLdrHlpStrLen(pszName);
929 const size_t cchPrefix = pszPrefix ? kLdrHlpStrLen(pszPrefix) : 0;
930 const size_t cchSuffix = pszSuffix ? kLdrHlpStrLen(pszSuffix) : 0;
931 const char *pszNameSuffix = kldrHlpGetSuff(pszName);
932 PKLDRDYLDMOD pCur = kLdrDyldHead;
933
934 /*
935 * Some of the methods are case insensitive (ASCII), others are case sensitive.
936 * To avoid having todo indirect calls to the compare functions here, we split
937 * ways even if it means a lot of duplicate code.
938 */
939 if ( enmSearch == KLDRDYLD_SEARCH_OS2
940 || enmSearch == KLDRDYLD_SEARCH_WINDOWS
941 || enmSearch == KLDRDYLD_SEARCH_WINDOWS_ALTERED)
942 {
943 const unsigned fNameHasSuffix = pszNameSuffix
944 && kLdrHlpStrLen(pszNameSuffix) == cchSuffix
945 && !kLdrHlpMemIComp(pszNameSuffix, pszName + cchName - cchSuffix, cchSuffix);
946 for (; pCur; pCur = pCur->Load.pNext)
947 {
948 /* match global / specific */
949 if ( !pCur->fGlobalOrSpecific
950 && !(fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE))
951 continue;
952
953 /* match name */
954 if ( pCur->pMod->cchName == cchName
955 && !kLdrHlpMemIComp(pCur->pMod->pszName, pszName, cchName))
956 break;
957 if (cchPrefix)
958 {
959 if ( pCur->pMod->cchName == cchName + cchPrefix
960 && !kLdrHlpMemIComp(pCur->pMod->pszName, pszPrefix, cchPrefix)
961 && !kLdrHlpMemIComp(pCur->pMod->pszName + cchPrefix, pszName, cchName))
962 break;
963 }
964 if (cchSuffix)
965 {
966 if ( pCur->pMod->cchName == cchName + cchSuffix
967 && !kLdrHlpMemIComp(pCur->pMod->pszName + cchName, pszSuffix, cchSuffix)
968 && !kLdrHlpMemIComp(pCur->pMod->pszName, pszName, cchName))
969 break;
970 if ( fNameHasSuffix
971 && pCur->pMod->cchName == cchName - cchSuffix
972 && !kLdrHlpMemIComp(pCur->pMod->pszName, pszName, cchName - cchSuffix))
973 break;
974 if (cchPrefix)
975 {
976 if ( pCur->pMod->cchName == cchName + cchPrefix + cchSuffix
977 && !kLdrHlpMemIComp(pCur->pMod->pszName, pszPrefix, cchPrefix)
978 && !kLdrHlpMemIComp(pCur->pMod->pszName + cchPrefix, pszName, cchName)
979 && !kLdrHlpMemIComp(pCur->pMod->pszName + cchPrefix + cchName, pszSuffix, cchSuffix))
980 break;
981 if ( fNameHasSuffix
982 && pCur->pMod->cchName == cchName + cchPrefix - cchSuffix
983 && !kLdrHlpMemIComp(pCur->pMod->pszName, pszPrefix, cchPrefix)
984 && !kLdrHlpMemIComp(pCur->pMod->pszName + cchPrefix, pszName, cchName - cchSuffix))
985 break;
986 }
987 }
988 }
989 }
990 else
991 {
992 const unsigned fNameHasSuffix = pszNameSuffix
993 && kLdrHlpStrLen(pszNameSuffix) == cchSuffix
994 && kLdrHlpMemComp(pszNameSuffix, pszName + cchName - cchSuffix, cchSuffix);
995 for (; pCur; pCur = pCur->Load.pNext)
996 {
997 /* match global / specific */
998 if ( !pCur->fGlobalOrSpecific
999 && !(fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE))
1000 continue;
1001
1002 /* match name */
1003 if ( pCur->pMod->cchName == cchName
1004 && !kLdrHlpMemComp(pCur->pMod->pszName, pszName, cchName))
1005 break;
1006 if (cchPrefix)
1007 {
1008 if ( pCur->pMod->cchName == cchName + cchPrefix
1009 && !kLdrHlpMemComp(pCur->pMod->pszName, pszPrefix, cchPrefix)
1010 && !kLdrHlpMemComp(pCur->pMod->pszName + cchPrefix, pszName, cchName))
1011 break;
1012 }
1013 if (cchSuffix)
1014 {
1015 if ( pCur->pMod->cchName == cchName + cchSuffix
1016 && !kLdrHlpMemComp(pCur->pMod->pszName + cchName, pszSuffix, cchSuffix)
1017 && !kLdrHlpMemComp(pCur->pMod->pszName, pszName, cchName))
1018 break;
1019 if ( fNameHasSuffix
1020 && pCur->pMod->cchName == cchName - cchSuffix
1021 && !kLdrHlpMemComp(pCur->pMod->pszName, pszName, cchName - cchSuffix))
1022 break;
1023 if (cchPrefix)
1024 {
1025 if ( pCur->pMod->cchName == cchName + cchPrefix + cchSuffix
1026 && !kLdrHlpMemComp(pCur->pMod->pszName, pszPrefix, cchPrefix)
1027 && !kLdrHlpMemComp(pCur->pMod->pszName + cchPrefix, pszName, cchName)
1028 && !kLdrHlpMemComp(pCur->pMod->pszName + cchPrefix + cchName, pszSuffix, cchSuffix))
1029 break;
1030 if ( pCur->pMod->cchName == cchName + cchPrefix - cchSuffix
1031 && !kLdrHlpMemComp(pCur->pMod->pszName, pszPrefix, cchPrefix)
1032 && !kLdrHlpMemComp(pCur->pMod->pszName + cchPrefix, pszName, cchName - cchSuffix))
1033 break;
1034 }
1035 }
1036 }
1037 }
1038
1039 /* search result. */
1040 if (pCur)
1041 {
1042 *ppMod = pCur;
1043 rc = 0;
1044 }
1045 else
1046 rc = KLDR_ERR_MODULE_NOT_FOUND;
1047 }
1048
1049 return rc;
1050}
1051
Note: See TracBrowser for help on using the repository browser.