source: trunk/kLdr/kLdrDyldFind.c@ 3232

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

Bugfixing.

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