VirtualBox

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

Last change on this file since 24 was 2, checked in by bird, 17 years ago

Imported http://svn.netlabs.org/repos/libc/trunk/kStuff, revision 3612.

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