source: trunk/kStuff/kLdr/kLdrDyldFind.c@ 3598

Last change on this file since 3598 was 3598, checked in by bird, 18 years ago

hacking darwin.

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