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

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

WIN* DARWIN and OS2 removal.

  • Property svn:keywords set to Id
File size: 37.6 KB
Line 
1/* $Id: kLdrDyldFind.c 3582 2007-09-02 22:26:42Z 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 defined(__OS2__)
307 PPIB pPib;
308 PTIB pTib;
309 APIRET rc;
310
311 DosGetInfoBlocks(&pTib, &pPib);
312 rc = DosQueryModuleName(pPib->pib_hmte, sizeof(kLdrDyldAppDir), kLdrDyldAppDir);
313 if (!rc)
314 {
315 *kHlpGetFilename(kLdrDyldAppDir) = '\0';
316 kHlpMemCopy(kLdrDyldWindowsAppDir, kLdrDyldAppDir, sizeof(kLdrDyldAppDir));
317 }
318 else
319 {
320 kLdrDyldWindowsAppDir[0] = kLdrDyldAppDir[0] = '.';
321 kLdrDyldWindowsAppDir[1] = kLdrDyldAppDir[1] = '\0';
322 }
323
324
325#elif K_OS == K_OS_WINDOWS
326 DWORD dwSize = GetModuleFileName(NULL /* the executable */, kLdrDyldAppDir, sizeof(kLdrDyldAppDir));
327 if (dwSize > 0)
328 {
329 *kHlpGetFilename(kLdrDyldAppDir) = '\0';
330 kHlpMemCopy(kLdrDyldWindowsAppDir, kLdrDyldAppDir, sizeof(kLdrDyldAppDir));
331 }
332 else
333 {
334 kLdrDyldWindowsAppDir[0] = kLdrDyldAppDir[0] = '.';
335 kLdrDyldWindowsAppDir[1] = kLdrDyldAppDir[1] = '\0';
336 }
337
338#else
339# error "Port me"
340#endif
341 }
342}
343
344
345/**
346 * Locates and opens a module using the specified search method.
347 *
348 * @returns 0 and *ppMod on success, non-zero OS specific error on failure.
349 *
350 * @param pszName Partial or complete name, it's specific to the search method to determin which.
351 * @param pszPrefix Prefix than can be used when searching.
352 * @param pszSuffix Suffix than can be used when searching.
353 * @param enmSearch The file search method to apply.
354 * @param fFlags Search flags.
355 * @param ppMod Where to store the file provider instance on success.
356 */
357int kldrDyldFindNewModule(const char *pszName, const char *pszPrefix, const char *pszSuffix,
358 KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod)
359{
360 int rc;
361 PKRDR pRdr = NULL;
362
363 *ppMod = NULL;
364
365 /*
366 * If this isn't just a filename, we the caller has specified a file
367 * that should be opened directly and not a module name to be searched for.
368 */
369 if (!kHlpIsFilenameOnly(pszName))
370 rc = kldrDyldFindTryOpen(pszName, &pRdr);
371 else if (!(fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE))
372 rc = kldrDyldFindDoDllSearch(pszName, pszPrefix, pszSuffix, enmSearch, fFlags, &pRdr);
373 else
374 rc = kldrDyldFindDoExeSearch(pszName, pszPrefix, pszSuffix, enmSearch, fFlags, &pRdr);
375 if (!rc)
376 {
377#ifdef KLDRDYLDFIND_STRICT
378 /* Sanity check of kldrDyldFindExistingModule. */
379 if (fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE)
380 {
381 const char *pszFilename = kRdrName(pRdr);
382 const KSIZE cchFilename = kHlpStrLen(pszFilename);
383 PKLDRDYLDMOD pCur;
384 for (pCur = kLdrDyldHead; pCur; pCur = pCur->Load.pNext)
385 KLDRDYLDFIND_ASSERT( pCur->pMod->cchFilename != cchFilename
386 || kHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename));
387 }
388#endif
389
390 /*
391 * Check for matching non-global modules that should be promoted.
392 */
393 if (!(fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE))
394 {
395 const char *pszFilename = kRdrName(pRdr);
396 const KSIZE cchFilename = kHlpStrLen(pszFilename);
397 PKLDRDYLDMOD pCur;
398 for (pCur = kLdrDyldHead; pCur; pCur = pCur->Load.pNext)
399 {
400 if ( !pCur->fGlobalOrSpecific
401 && pCur->pMod->cchFilename == cchFilename
402 && !kHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename))
403 {
404 kRdrClose(pRdr);
405 kldrDyldModMarkGlobal(pCur);
406 *ppMod = pCur;
407 return 0;
408 }
409 KLDRDYLDFIND_ASSERT( pCur->pMod->cchFilename != cchFilename
410 || kHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename));
411 }
412 }
413
414 /*
415 * Create a new module.
416 */
417 rc = kldrDyldModCreate(pRdr, fFlags, ppMod);
418 if (rc)
419 kRdrClose(pRdr);
420 }
421 return rc;
422}
423
424
425/**
426 * Searches for a DLL file using the specified method.
427 *
428 * @returns 0 on success and *ppMod pointing to the new module.
429 * @returns KLDR_ERR_MODULE_NOT_FOUND if the specified file couldn't be opened.
430 * @returns non-zero kLdr or OS specific status code on other failures.
431 * @param pszName The name.
432 * @param pszPrefix The prefix, optional.
433 * @param pszSuffix The suffix, optional.
434 * @param enmSearch The search method.
435 * @param fFlags The load/search flags.
436 * @param ppRdr Where to store the pointer to the file provider instance on success.
437 */
438static int kldrDyldFindDoDllSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix,
439 KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKRDR ppRdr)
440{
441 int rc;
442 KLDRDYLDFINDARGS Args;
443
444 /*
445 * Initialize the argument structure and resolve defaults.
446 */
447 Args.enmSearch = enmSearch;
448 Args.pszPrefix = pszPrefix;
449 Args.pszSuffix = pszSuffix;
450 rc = kldrDyldFindGetDefaults(&Args.enmSearch, &Args.pszPrefix, &Args.pszSuffix, pszName, fFlags);
451 if (rc)
452 return rc;
453 Args.pszName = pszName;
454 Args.cchName = kHlpStrLen(pszName);
455 Args.cchPrefix = Args.pszPrefix ? kHlpStrLen(Args.pszPrefix) : 0;
456 Args.cchSuffix = Args.pszSuffix ? kHlpStrLen(Args.pszSuffix) : 0;
457 Args.cchMaxLength = Args.cchName + Args.cchSuffix + Args.cchPrefix;
458 Args.fFlags = fFlags;
459 Args.ppRdr = ppRdr;
460
461 /*
462 * Apply the specified search method.
463 */
464/** @todo get rid of the strlen() on the various paths here! */
465 switch (Args.enmSearch)
466 {
467 case KLDRDYLD_SEARCH_KLDR:
468 {
469 kldrDyldFindLazyInitAppDir();
470 if (kLdrDyldAppDir[0] != '\0')
471 {
472 rc = kldrDyldFindTryOpenPath(kLdrDyldAppDir, kHlpStrLen(kLdrDyldAppDir), &Args);
473 if (rc != KLDR_ERR_MODULE_NOT_FOUND)
474 break;
475 }
476 rc = kldrDyldFindTryOpenPath(".", 1, &Args);
477 if (rc != KLDR_ERR_MODULE_NOT_FOUND)
478 break;
479 rc = kldrDyldFindEnumeratePath(kLdrDyldLibraryPath, &Args);
480 break;
481 }
482
483 case KLDRDYLD_SEARCH_OS2:
484 {
485 rc = kldrDyldFindEnumeratePath(kLdrDyldOS2BeginLibpath, &Args);
486 if (rc != KLDR_ERR_MODULE_NOT_FOUND)
487 break;
488 rc = kldrDyldFindEnumeratePath(kLdrDyldOS2Libpath, &Args);
489 if (rc != KLDR_ERR_MODULE_NOT_FOUND)
490 break;
491 rc = kldrDyldFindEnumeratePath(kLdrDyldOS2EndLibpath, &Args);
492 break;
493 }
494
495 case KLDRDYLD_SEARCH_WINDOWS:
496 case KLDRDYLD_SEARCH_WINDOWS_ALTERED:
497 {
498 kldrDyldFindLazyInitAppDir();
499 rc = kldrDyldFindTryOpenPath(kLdrDyldWindowsAppDir, kHlpStrLen(kLdrDyldWindowsAppDir), &Args);
500 if (rc != KLDR_ERR_MODULE_NOT_FOUND)
501 break;
502 if (Args.enmSearch == KLDRDYLD_SEARCH_WINDOWS_ALTERED)
503 {
504 rc = kldrDyldFindTryOpenPath(".", 1, &Args);
505 if (rc != KLDR_ERR_MODULE_NOT_FOUND)
506 break;
507 }
508 rc = kldrDyldFindTryOpenPath(kLdrDyldWindowsSystemDir, kHlpStrLen(kLdrDyldWindowsSystemDir), &Args);
509 if (rc != KLDR_ERR_MODULE_NOT_FOUND)
510 break;
511 rc = kldrDyldFindTryOpenPath(kLdrDyldWindowsDir, kHlpStrLen(kLdrDyldWindowsDir), &Args);
512 if (rc != KLDR_ERR_MODULE_NOT_FOUND)
513 break;
514 if (Args.enmSearch == KLDRDYLD_SEARCH_WINDOWS)
515 {
516 rc = kldrDyldFindTryOpenPath(".", 1, &Args);
517 if (rc != KLDR_ERR_MODULE_NOT_FOUND)
518 break;
519 }
520 rc = kldrDyldFindEnumeratePath(kLdrDyldWindowsPath, &Args);
521 break;
522 }
523
524 case KLDRDYLD_SEARCH_UNIX_COMMON:
525 {
526 rc = kldrDyldFindEnumeratePath(kLdrDyldUnixLibraryPath, &Args);
527 if (rc == KLDR_ERR_MODULE_NOT_FOUND)
528 break;
529 rc = kldrDyldFindEnumeratePath(kLdrDyldUnixSystemLibraryPath, &Args);
530 break;
531 }
532
533 default: kHlpAssert(!"internal error"); return -1;
534 }
535 return rc;
536}
537
538
539/**
540 * Searches for an EXE file using the specified method.
541 *
542 * @returns 0 on success and *ppMod pointing to the new module.
543 * @returns KLDR_ERR_MODULE_NOT_FOUND if the specified file couldn't be opened.
544 * @returns non-zero kLdr or OS specific status code on other failures.
545 * @param pszName The name.
546 * @param pszPrefix The prefix, optional.
547 * @param pszSuffix The suffix, optional.
548 * @param enmSearch The search method.
549 * @param fFlags The load/search flags.
550 * @param ppRdr Where to store the pointer to the file provider instance on success.
551 */
552static int kldrDyldFindDoExeSearch(const char *pszName, const char *pszPrefix, const char *pszSuffix,
553 KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKRDR ppRdr)
554{
555 int rc;
556 KLDRDYLDFINDARGS Args;
557
558 /*
559 * Initialize the argument structure and resolve defaults.
560 */
561 Args.enmSearch = enmSearch;
562 Args.pszPrefix = pszPrefix;
563 Args.pszSuffix = pszSuffix;
564 rc = kldrDyldFindGetDefaults(&Args.enmSearch, &Args.pszPrefix, &Args.pszSuffix, pszName, fFlags);
565 if (rc)
566 return rc;
567 Args.pszName = pszName;
568 Args.cchName = kHlpStrLen(pszName);
569 Args.cchPrefix = Args.pszPrefix ? kHlpStrLen(Args.pszPrefix) : 0;
570 Args.cchSuffix = Args.pszSuffix ? kHlpStrLen(Args.pszSuffix) : 0;
571 Args.cchMaxLength = Args.cchName + Args.cchSuffix + Args.cchPrefix;
572 Args.fFlags = fFlags;
573 Args.ppRdr = ppRdr;
574
575 /*
576 * If we're bootstrapping a process, we'll start by looking in the
577 * application directory and the check out the path.
578 */
579 if (g_fBootstrapping)
580 {
581 kldrDyldFindLazyInitAppDir();
582 if (kLdrDyldAppDir[0] != '\0')
583 {
584 rc = kldrDyldFindTryOpenPath(kLdrDyldAppDir, kHlpStrLen(kLdrDyldAppDir), &Args);
585 if (rc != KLDR_ERR_MODULE_NOT_FOUND)
586 return rc;
587 }
588 }
589
590 /*
591 * Search the EXE search path. Initialize it the first time around.
592 */
593 if (!kLdrDyldExePath[0])
594 {
595 KSIZE cch;
596 kHlpGetEnv("KLDR_EXE_PATH", kLdrDyldExePath, sizeof(kLdrDyldExePath) - 10);
597 cch = kHlpStrLen(kLdrDyldExePath);
598 kLdrDyldExePath[cch++] = ';';
599 kHlpGetEnv("PATH", &kLdrDyldExePath[cch], sizeof(kLdrDyldExePath) - cch);
600 }
601 return kldrDyldFindEnumeratePath(kLdrDyldExePath, &Args);
602}
603
604
605/**
606 * Try open the specfied file.
607 *
608 * @returns 0 on success and *ppMod pointing to the new module.
609 * @returns KLDR_ERR_MODULE_NOT_FOUND if the specified file couldn't be opened.
610 * @returns non-zero kLdr or OS specific status code on other failures.
611 * @param pszFilename The filename.
612 * @param ppRdr Where to store the pointer to the new module.
613 */
614static int kldrDyldFindTryOpen(const char *pszFilename, PPKRDR ppRdr)
615{
616 int rc;
617
618 /*
619 * Try open the file.
620 */
621 rc = kRdrOpen(ppRdr, pszFilename);
622 if (!rc)
623 return 0;
624 /** @todo deal with return codes properly. */
625 if (rc >= KERR_BASE && rc <= KERR_END)
626 return rc;
627
628 return KLDR_ERR_MODULE_NOT_FOUND;
629}
630
631
632/**
633 * Composes a filename from the specified directory path,
634 * prefix (optional), name and suffix (optional, will try with and without).
635 *
636 * @param pchPath The directory path - this doesn't have to be null terminated.
637 * @param cchPath The length of the path.
638 * @param pArgs The search argument structure.
639 *
640 * @returns See kldrDyldFindTryOpen
641 */
642static int kldrDyldFindTryOpenPath(const char *pchPath, KSIZE cchPath, PCKLDRDYLDFINDARGS pArgs)
643{
644 static char s_szFilename[1024];
645 char *psz;
646 int rc;
647
648 /*
649 * Ignore any attempts at opening empty paths.
650 * This can happen when a *Dir globals is empty.
651 */
652 if (!cchPath)
653 return KLDR_ERR_MODULE_NOT_FOUND; /* ignore */
654
655 /*
656 * Limit check first.
657 */
658 if (cchPath + 1 + pArgs->cchMaxLength >= sizeof(s_szFilename))
659 {
660 KLDRDYLDFIND_ASSERT(!"too long");
661 return KLDR_ERR_MODULE_NOT_FOUND; /* ignore */
662 }
663
664 /*
665 * The directory path.
666 */
667 kHlpMemCopy(s_szFilename, pchPath, cchPath);
668 psz = &s_szFilename[cchPath];
669 if (psz[-1] != '/'
670#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS
671 && psz[-1] != '\\'
672 && psz[-1] != ':'
673#endif
674 )
675 *psz++ = '/';
676
677 /*
678 * The name.
679 */
680 if (pArgs->cchPrefix)
681 {
682 kHlpMemCopy(psz, pArgs->pszPrefix, pArgs->cchPrefix);
683 psz += pArgs->cchPrefix;
684 }
685 kHlpMemCopy(psz, pArgs->pszName, pArgs->cchName);
686 psz += pArgs->cchName;
687 if (pArgs->cchSuffix)
688 {
689 kHlpMemCopy(psz, pArgs->pszSuffix, pArgs->cchSuffix);
690 psz += pArgs->cchSuffix;
691 }
692 *psz = '\0';
693
694
695 /*
696 * Try open it.
697 */
698 rc = kldrDyldFindTryOpen(s_szFilename, pArgs->ppRdr);
699 /* If we're opening an executable, try again without the suffix.*/
700 if ( rc
701 && pArgs->cchSuffix
702 && (pArgs->fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE))
703 {
704 psz -= pArgs->cchSuffix;
705 *psz = '\0';
706 rc = kldrDyldFindTryOpen(s_szFilename, pArgs->ppRdr);
707 }
708 return rc;
709}
710
711
712/**
713 * Enumerates the specfied path.
714 *
715 * @returns Any return code from the kldrDyldFindTryOpenPath() which isn't KLDR_ERR_MODULE_NOT_FOUND.
716 * @returns KLDR_ERR_MODULE_NOT_FOUND if the end of the search path was reached.
717 * @param pszSearchPath The search path to enumeare.
718 * @param pArgs The search argument structure.
719 */
720static int kldrDyldFindEnumeratePath(const char *pszSearchPath, PCKLDRDYLDFINDARGS pArgs)
721{
722 const char *psz = pszSearchPath;
723 for (;;)
724 {
725 const char *pszEnd;
726 KSIZE cchPath;
727
728 /*
729 * Trim.
730 */
731 while (*psz == ';' || *psz == ':')
732 psz++;
733 if (*psz == '\0')
734 return KLDR_ERR_MODULE_NOT_FOUND;
735
736 /*
737 * Find the end.
738 */
739 pszEnd = psz + 1;
740 while ( *pszEnd != '\0'
741 && *pszEnd != ';'
742#if K_OS == K_OS_OS2 || K_OS == K_OS_WINDOWS
743 && ( *pszEnd != ':'
744 || ( pszEnd - psz == 1
745 && ( (*psz >= 'A' && *psz <= 'Z')
746 || (*psz >= 'a' && *psz <= 'z')
747 )
748 )
749 )
750#else
751 && *pszEnd != ':'
752#endif
753 )
754 pszEnd++;
755
756 /*
757 * If not empty path, try open the module using it.
758 */
759 cchPath = pszEnd - psz;
760 if (cchPath > 0)
761 {
762 int rc;
763 rc = kldrDyldFindTryOpenPath(psz, cchPath, pArgs);
764 if (rc != KLDR_ERR_MODULE_NOT_FOUND)
765 return rc;
766 }
767
768 /* next */
769 psz = pszEnd;
770 }
771}
772
773
774/**
775 * Resolve default search method, prefix and suffix.
776 *
777 * @returns 0 on success, KERR_INVALID_PARAMETER on failure.
778 * @param penmSearch The search method. In/Out.
779 * @param ppszPrefix The prefix. In/Out.
780 * @param ppszSuffix The suffix. In/Out.
781 * @param pszName The name. In.
782 * @param fFlags The load/search flags.
783 */
784static int kldrDyldFindGetDefaults(KLDRDYLDSEARCH *penmSearch, const char **ppszPrefix, const char **ppszSuffix,
785 const char *pszName, KU32 fFlags)
786{
787 unsigned fCaseSensitive;
788
789 /*
790 * Fixup search method alias.
791 */
792 if (*penmSearch == KLDRDYLD_SEARCH_HOST)
793#if defined(__OS2__)
794 *penmSearch = KLDRDYLD_SEARCH_OS2;
795#elif K_OS == K_OS_WINDOWS
796 *penmSearch = KLDRDYLD_SEARCH_WINDOWS;
797#else
798# error "Port me"
799#endif
800
801 /*
802 * Apply search method specific prefix/suffix.
803 */
804 switch (*penmSearch)
805 {
806 case KLDRDYLD_SEARCH_KLDR:
807 if (!*ppszPrefix && kLdrDyldDefPrefix[0])
808 *ppszPrefix = kLdrDyldDefPrefix;
809 if (!*ppszSuffix && kLdrDyldDefSuffix[0])
810 *ppszSuffix = kLdrDyldDefSuffix;
811 fCaseSensitive = 1;
812 break;
813
814 case KLDRDYLD_SEARCH_OS2:
815 if (!*ppszSuffix)
816 *ppszSuffix = !(fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE) ? ".dll" : ".exe";
817 fCaseSensitive = 0;
818 break;
819
820 case KLDRDYLD_SEARCH_WINDOWS:
821 case KLDRDYLD_SEARCH_WINDOWS_ALTERED:
822 if (!*ppszSuffix)
823 *ppszSuffix = !(fFlags & KLDRDYLD_LOAD_FLAGS_EXECUTABLE) ? ".dll" : ".exe";
824 fCaseSensitive = 0;
825 break;
826
827 case KLDRDYLD_SEARCH_UNIX_COMMON:
828 fCaseSensitive = 1;
829 break;
830
831 default:
832 KLDRDYLDFIND_ASSERT(!"invalid search method");
833 return KERR_INVALID_PARAMETER;
834 }
835
836 /*
837 * Drop the suffix if it's already included in the name.
838 */
839 if (*ppszSuffix)
840 {
841 const KSIZE cchName = kHlpStrLen(pszName);
842 const KSIZE cchSuffix = kHlpStrLen(*ppszSuffix);
843 if ( cchName > cchSuffix
844 && ( fCaseSensitive
845 ? !kHlpMemComp(pszName + cchName - cchSuffix, *ppszSuffix, cchSuffix)
846 : !kHlpMemICompAscii(pszName + cchName - cchSuffix, *ppszSuffix, cchSuffix))
847 )
848 *ppszSuffix = NULL;
849 }
850
851 return 0;
852}
853
854
855/**
856 * Locates an already open module using the specified search method.
857 *
858 * @returns 0 and *ppMod on success, non-zero OS specific error on failure.
859 *
860 * @param pszName Partial or complete name, it's specific to the search method to determin which.
861 * @param pszPrefix Prefix than can be used when searching.
862 * @param pszSuffix Suffix than can be used when searching.
863 * @param enmSearch The file search method to apply.
864 * @param fFlags Search flags.
865 * @param ppMod Where to store the file provider instance on success.
866 */
867int kldrDyldFindExistingModule(const char *pszName, const char *pszPrefix, const char *pszSuffix,
868 KLDRDYLDSEARCH enmSearch, unsigned fFlags, PPKLDRDYLDMOD ppMod)
869{
870
871 int rc;
872 unsigned fOS2LibpathStrict;
873 *ppMod = NULL;
874
875 /*
876 * Don't bother if no modules are loaded yet.
877 */
878 if (!kLdrDyldHead)
879 return KLDR_ERR_MODULE_NOT_FOUND;
880
881 /*
882 * Defaults.
883 */
884 rc = kldrDyldFindGetDefaults(&enmSearch, &pszPrefix, &pszSuffix, pszName, fFlags);
885 if (rc)
886 return rc;
887
888 /*
889 * If this isn't just a filename, the caller has specified a file
890 * that should be opened directly and not a module name to be searched for.
891 *
892 * In order to do the right thing we'll have to open the file and get the
893 * correct filename for it.
894 *
895 * The OS/2 libpath strict method require us to find the correct DLL first.
896 */
897 fOS2LibpathStrict = 0;
898 if ( !kHlpIsFilenameOnly(pszName)
899 || (fOS2LibpathStrict = ( enmSearch == KLDRDYLD_SEARCH_OS2
900 && kLdrDyldOS2LibpathStrict[0] == 'T')
901 )
902 )
903 {
904 PKRDR pRdr;
905 if (fOS2LibpathStrict)
906 rc = kldrDyldFindDoDllSearch(pszName, pszPrefix, pszSuffix, enmSearch, fFlags, &pRdr);
907 else
908 rc = kldrDyldFindTryOpen(pszName, &pRdr);
909 if (!rc)
910 {
911 /* do a filename based search. */
912 const char *pszFilename = kRdrName(pRdr);
913 const KSIZE cchFilename = kHlpStrLen(pszFilename);
914 PKLDRDYLDMOD pCur;
915 rc = KLDR_ERR_MODULE_NOT_FOUND;
916 for (pCur = kLdrDyldHead; pCur; pCur = pCur->Load.pNext)
917 {
918 if ( pCur->pMod->cchFilename == cchFilename
919 && !kHlpMemComp(pCur->pMod->pszFilename, pszFilename, cchFilename))
920 {
921 *ppMod = pCur;
922 rc = 0;
923 break;
924 }
925 }
926 kRdrClose(pRdr);
927 }
928 }
929 else
930 {
931 const KSIZE cchName = kHlpStrLen(pszName);
932 const KSIZE cchPrefix = pszPrefix ? kHlpStrLen(pszPrefix) : 0;
933 const KSIZE cchSuffix = pszSuffix ? kHlpStrLen(pszSuffix) : 0;
934 const char *pszNameSuffix = kHlpGetSuff(pszName);
935 PKLDRDYLDMOD pCur = kLdrDyldHead;
936
937 /*
938 * Some of the methods are case insensitive (ASCII), others are case sensitive.
939 * To avoid having todo indirect calls to the compare functions here, we split
940 * ways even if it means a lot of duplicate code.
941 */
942 if ( enmSearch == KLDRDYLD_SEARCH_OS2
943 || enmSearch == KLDRDYLD_SEARCH_WINDOWS
944 || enmSearch == KLDRDYLD_SEARCH_WINDOWS_ALTERED)
945 {
946 const unsigned fNameHasSuffix = pszNameSuffix
947 && kHlpStrLen(pszNameSuffix) == cchSuffix
948 && !kHlpMemICompAscii(pszNameSuffix, pszName + cchName - cchSuffix, cchSuffix);
949 for (; pCur; pCur = pCur->Load.pNext)
950 {
951 /* match global / specific */
952 if ( !pCur->fGlobalOrSpecific
953 && !(fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE))
954 continue;
955
956 /* match name */
957 if ( pCur->pMod->cchName == cchName
958 && !kHlpMemICompAscii(pCur->pMod->pszName, pszName, cchName))
959 break;
960 if (cchPrefix)
961 {
962 if ( pCur->pMod->cchName == cchName + cchPrefix
963 && !kHlpMemICompAscii(pCur->pMod->pszName, pszPrefix, cchPrefix)
964 && !kHlpMemICompAscii(pCur->pMod->pszName + cchPrefix, pszName, cchName))
965 break;
966 }
967 if (cchSuffix)
968 {
969 if ( pCur->pMod->cchName == cchName + cchSuffix
970 && !kHlpMemICompAscii(pCur->pMod->pszName + cchName, pszSuffix, cchSuffix)
971 && !kHlpMemICompAscii(pCur->pMod->pszName, pszName, cchName))
972 break;
973 if ( fNameHasSuffix
974 && pCur->pMod->cchName == cchName - cchSuffix
975 && !kHlpMemICompAscii(pCur->pMod->pszName, pszName, cchName - cchSuffix))
976 break;
977 if (cchPrefix)
978 {
979 if ( pCur->pMod->cchName == cchName + cchPrefix + cchSuffix
980 && !kHlpMemICompAscii(pCur->pMod->pszName, pszPrefix, cchPrefix)
981 && !kHlpMemICompAscii(pCur->pMod->pszName + cchPrefix, pszName, cchName)
982 && !kHlpMemICompAscii(pCur->pMod->pszName + cchPrefix + cchName, pszSuffix, cchSuffix))
983 break;
984 if ( fNameHasSuffix
985 && pCur->pMod->cchName == cchName + cchPrefix - cchSuffix
986 && !kHlpMemICompAscii(pCur->pMod->pszName, pszPrefix, cchPrefix)
987 && !kHlpMemICompAscii(pCur->pMod->pszName + cchPrefix, pszName, cchName - cchSuffix))
988 break;
989 }
990 }
991 }
992 }
993 else
994 {
995 const unsigned fNameHasSuffix = pszNameSuffix
996 && kHlpStrLen(pszNameSuffix) == cchSuffix
997 && kHlpMemComp(pszNameSuffix, pszName + cchName - cchSuffix, cchSuffix);
998 for (; pCur; pCur = pCur->Load.pNext)
999 {
1000 /* match global / specific */
1001 if ( !pCur->fGlobalOrSpecific
1002 && !(fFlags & KLDRYDLD_LOAD_FLAGS_SPECIFIC_MODULE))
1003 continue;
1004
1005 /* match name */
1006 if ( pCur->pMod->cchName == cchName
1007 && !kHlpMemComp(pCur->pMod->pszName, pszName, cchName))
1008 break;
1009 if (cchPrefix)
1010 {
1011 if ( pCur->pMod->cchName == cchName + cchPrefix
1012 && !kHlpMemComp(pCur->pMod->pszName, pszPrefix, cchPrefix)
1013 && !kHlpMemComp(pCur->pMod->pszName + cchPrefix, pszName, cchName))
1014 break;
1015 }
1016 if (cchSuffix)
1017 {
1018 if ( pCur->pMod->cchName == cchName + cchSuffix
1019 && !kHlpMemComp(pCur->pMod->pszName + cchName, pszSuffix, cchSuffix)
1020 && !kHlpMemComp(pCur->pMod->pszName, pszName, cchName))
1021 break;
1022 if ( fNameHasSuffix
1023 && pCur->pMod->cchName == cchName - cchSuffix
1024 && !kHlpMemComp(pCur->pMod->pszName, pszName, cchName - cchSuffix))
1025 break;
1026 if (cchPrefix)
1027 {
1028 if ( pCur->pMod->cchName == cchName + cchPrefix + cchSuffix
1029 && !kHlpMemComp(pCur->pMod->pszName, pszPrefix, cchPrefix)
1030 && !kHlpMemComp(pCur->pMod->pszName + cchPrefix, pszName, cchName)
1031 && !kHlpMemComp(pCur->pMod->pszName + cchPrefix + cchName, pszSuffix, cchSuffix))
1032 break;
1033 if ( pCur->pMod->cchName == cchName + cchPrefix - cchSuffix
1034 && !kHlpMemComp(pCur->pMod->pszName, pszPrefix, cchPrefix)
1035 && !kHlpMemComp(pCur->pMod->pszName + cchPrefix, pszName, cchName - cchSuffix))
1036 break;
1037 }
1038 }
1039 }
1040 }
1041
1042 /* search result. */
1043 if (pCur)
1044 {
1045 *ppMod = pCur;
1046 rc = 0;
1047 }
1048 else
1049 rc = KLDR_ERR_MODULE_NOT_FOUND;
1050 }
1051
1052 return rc;
1053}
1054
Note: See TracBrowser for help on using the repository browser.