source: trunk/kLdr/kLdrDyldFind.c@ 2870

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

Test all kLdrDyld apis.

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