VirtualBox

source: kStuff/trunk/kLdr/kLdrDyldFind.c

Last change on this file was 29, checked in by bird, 15 years ago

Finally got around execute the switch to the MIT license.

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

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