source: trunk/kLdr/kLdrRdrFile.c@ 2860

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

Working on the mapping stuff (windows is gonna be a headache).

  • Property svn:keywords set to Id
File size: 16.6 KB
Line 
1/* $Id: kLdrRdrFile.c 2860 2006-11-08 04:10:14Z bird $ */
2/** @file
3 *
4 * kLdr - The Dynamic Loader, file abstraction.
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* Header Files *
30*******************************************************************************/
31#ifdef __OS2__
32# define INCL_ERRORS
33# define INCL_BASE
34# include <os2.h>
35
36#elif defined(__WIN32__) || defined(__WIN64__) || defined(__WIN__)
37# include <Windows.h>
38# ifndef __WIN__
39# define __WIN__
40# endif
41
42#else
43# error "port me"
44#endif
45
46#include <kLdr.h>
47#include "kLdrHlp.h"
48
49
50/*******************************************************************************
51* Structures and Typedefs *
52*******************************************************************************/
53/**
54 * Prepared stuff.
55 */
56typedef struct KLDRRDRFILEPREP
57{
58 /** The address of the prepared region. */
59 void *pv;
60 /** The size of the prepared region. */
61 size_t cb;
62#if defined(__WIN__) || defined(__NT__)
63 /** Handle to the section created to map the file. */
64 HANDLE hSection;
65#endif
66} KLDRRDRFILEPREP, *PKLDRRDRFILEPREP;
67
68/**
69 * The file provier instance for native files.
70 */
71typedef struct KLDRRDRFILE
72{
73 /** The file reader vtable. */
74 KLDRRDR Core;
75 /** The file handle. */
76#ifdef __OS2__
77 HFILE File;
78#elif defined(__WIN__) || defined(__NT__)
79 HANDLE File;
80#else
81# error "Port me!"
82#endif
83 /** The current file offset. */
84 off_t off;
85 /** The file size. */
86 off_t cb;
87 /** Array where we stuff the mapping area data. */
88 KLDRRDRFILEPREP aPreps[4];
89 /** The number of current preps. */
90 uint32_t cPreps;
91 /** Number of mapping references. */
92 int32_t cMappings;
93 /** The memory mapping. */
94 void *pvMapping;
95 /** The filename. */
96 char szFilename[1];
97} KLDRRDRFILE, *PKLDRRDRFILE;
98
99
100/*******************************************************************************
101* Internal Functions *
102*******************************************************************************/
103static void kldrRdrFileDone(PKLDRRDR pRdr);
104static int kldrRdrFileUnprepare(PKLDRRDR pRdr, void *pv, size_t cb);
105static int kldrRdrFileUnmap(PKLDRRDR pRdr, void *pv, size_t cb);
106static int kldrRdrFileProtect(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt);
107static int kldrRdrFileRefreshMap(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile);
108static int kldrRdrFileMap(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile);
109static int kldrRdrFilePrepare(PKLDRRDR pRdr, void **ppv, size_t cb, unsigned fFixed);
110static size_t kldrRdrFilePageSize(PKLDRRDR pRdr);
111static const char *kldrRdrFileName(PKLDRRDR pRdr);
112static off_t kldrRdrFileTell(PKLDRRDR pRdr);
113static off_t kldrRdrFileSize(PKLDRRDR pRdr);
114static int kldrRdrFileAllUnmap(PKLDRRDR pRdr, const void *pvBits);
115static int kldrRdrFileAllMap(PKLDRRDR pRdr, const void **ppvBits);
116static int kldrRdrFileRead(PKLDRRDR pRdr, void *pvBuf, size_t cb, off_t off);
117static int kldrRdrFileDestroy(PKLDRRDR pRdr);
118static int kldrRdrFileCreate(PPKLDRRDR ppRdr, const char *pszFilename);
119
120
121/*******************************************************************************
122* Global Variables *
123*******************************************************************************/
124/** Native file provider operations. */
125const KLDRRDROPS g_kLdrRdrFileOps =
126{
127 "native file",
128 NULL,
129 kldrRdrFileCreate,
130 kldrRdrFileDestroy,
131 kldrRdrFileRead,
132 kldrRdrFileAllMap,
133 kldrRdrFileAllUnmap,
134 kldrRdrFileSize,
135 kldrRdrFileTell,
136 kldrRdrFileName,
137 kldrRdrFilePageSize,
138 kldrRdrFilePrepare,
139 kldrRdrFileMap,
140 kldrRdrFileRefreshMap,
141 kldrRdrFileProtect,
142 kldrRdrFileUnmap,
143 kldrRdrFileUnprepare,
144 kldrRdrFileDone,
145 42
146};
147
148
149/** @copydoc KLDRRDR::pfnDone */
150static void kldrRdrFileDone(PKLDRRDR pRdr)
151{
152}
153
154
155/**
156 * Finds a prepared mapping region.
157 *
158 * @returns Pointer to the aPrep entry.
159 * @param pFile The instance data.
160 * @param pv The base of the region.
161 * @param cb The size of the region.
162 */
163static PKLDRRDRFILEPREP kldrRdrFileFindPrepExact(PKLDRRDRFILE pFile, void *pv, size_t cb)
164{
165 int32_t i = pFile->cPreps;
166 while (i-- > 0)
167 if ( pFile->aPreps[i].pv == pv
168 || pFile->aPreps[i].cb == cb)
169 return &pFile->aPreps[i];
170 return NULL;
171}
172
173
174/**
175 * Finds a prepared mapping region containing the specified region.
176 *
177 * @returns Pointer to the aPrep entry.
178 * @param pFile The instance data.
179 * @param pv The base of the sub region.
180 * @param cb The size of the sub region.
181 */
182static PKLDRRDRFILEPREP kldrRdrFileFindPrepWithin(PKLDRRDRFILE pFile, void *pv, size_t cb)
183{
184 int32_t i = pFile->cPreps;
185 while (i-- > 0)
186 if ((uintptr_t)pv - (uintptr_t)pFile->aPreps[i].pv < pFile->aPreps[i].cb)
187 {
188 if ((uintptr_t)pv - (uintptr_t)pFile->aPreps[i].pv + cb <= pFile->aPreps[i].cb)
189 return &pFile->aPreps[i];
190 return NULL;
191 }
192 return NULL;
193}
194
195
196/** @copydoc KLDRRDR::pfnUnprepare */
197static int kldrRdrFileUnprepare(PKLDRRDR pRdr, void *pv, size_t cb)
198{
199 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
200 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv, cb);
201 if (!pPrep)
202 return KLDR_ERR_INVALID_PARAMETER;
203
204 return -1;
205}
206
207
208/** @copydoc KLDRRDR::pfnUnmap */
209static int kldrRdrFileUnmap(PKLDRRDR pRdr, void *pv, size_t cb)
210{
211 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
212 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv, cb);
213 if (!pPrep)
214 return KLDR_ERR_INVALID_PARAMETER;
215
216 return -1;
217}
218
219
220/** @copydoc KLDRRDR::pfnProtect */
221static int kldrRdrFileProtect(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt)
222{
223 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
224 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv, cb);
225 if (!pPrep)
226 return KLDR_ERR_INVALID_PARAMETER;
227
228 return -1;
229}
230
231
232/** @copydoc KLDRRDR::pfnRefreshMap */
233static int kldrRdrFileRefreshMap(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile)
234{
235 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
236 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv, cb);
237 if (!pPrep)
238 return KLDR_ERR_INVALID_PARAMETER;
239
240 return -1;
241}
242
243
244/** @copydoc KLDRRDR::pfnMap */
245static int kldrRdrFileMap(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile)
246{
247 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
248 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv, cb);
249 if (!pPrep)
250 return KLDR_ERR_INVALID_PARAMETER;
251
252 return -1;
253}
254
255
256/** @copydoc KLDRRDR:pfnPrepare */
257static int kldrRdrFilePrepare(PKLDRRDR pRdr, void **ppv, size_t cb, unsigned fFixed)
258{
259#ifdef __OS2__
260
261
262#elif defined(__WIN__)
263
264#else
265# error "port me."
266#endif
267 return -1;
268}
269
270
271/** @copydoc KLDRRDR::pfnPageSize */
272static size_t kldrRdrFilePageSize(PKLDRRDR pRdr)
273{
274#ifdef __OS2__
275 /* The page size on OS/2 wont change anytime soon. :-) */
276 return 0x1000;
277
278#elif defined(__WIN__)
279 SYSTEM_INFO SysInfo;
280 GetSystemInfo(&SysInfo);
281 return SysInfo.dwPageSize;
282 /*return SysInfo.dwAllocationGranularity;*/
283#else
284# error "port me"
285#endif
286}
287
288
289/** @copydoc KLDRRDR::pfnName */
290static const char *kldrRdrFileName(PKLDRRDR pRdr)
291{
292 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
293 return &pRdrFile->szFilename[0];
294}
295
296
297/** @copydoc KLDRRDR::pfnTell */
298static off_t kldrRdrFileTell(PKLDRRDR pRdr)
299{
300 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
301
302 /*
303 * If the offset is undefined, try figure out what it is.
304 */
305 if (pRdrFile->off == -1)
306 {
307#ifdef __OS2__
308 ULONG ulNew;
309 APIRET rc = DosSetFilePtr(pRdrFile->File, 0, FILE_CURRENT, &ulNew);
310 if (rc)
311 return -1;
312 pRdrFile->off = ulNew;
313
314#elif defined(__WIN__)
315 LONG offHigh = 0;
316 LONG offLow;
317 int rc;
318
319 SetLastError(0);
320 offLow = SetFilePointer(pRdrFile->File, 0, &offHigh, FILE_CURRENT);
321 rc = GetLastError();
322 if (rc)
323 return -1;
324 pRdrFile->off = ((off_t)offHigh << 32) | offLow;
325
326#else
327# error "port me."
328#endif
329 }
330 return pRdrFile->off;
331}
332
333
334/** @copydoc KLDRRDR::pfnSize */
335static off_t kldrRdrFileSize(PKLDRRDR pRdr)
336{
337 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
338 return pRdrFile->cb;
339}
340
341
342/** @copydoc KLDRRDR::pfnAllUnmap */
343static int kldrRdrFileAllUnmap(PKLDRRDR pRdr, const void *pvBits)
344{
345 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
346
347 /* check for underflow */
348 if (pRdrFile->cMappings <= 0)
349#if defined(__OS2__) || defined(__WIN__)
350 return ERROR_INVALID_PARAMETER;
351#else
352# error "port me"
353#endif
354
355 /* decrement usage counter, free mapping if no longer in use. */
356 if (!--pRdrFile->cMappings)
357 {
358 kldrHlpFree(pRdrFile->pvMapping);
359 pRdrFile->pvMapping = NULL;
360 }
361
362 return 0;
363}
364
365
366/** @copydoc KLDRRDR::pfnAllMap */
367static int kldrRdrFileAllMap(PKLDRRDR pRdr, const void **ppvBits)
368{
369 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
370
371 /*
372 * Do we need to map it?
373 */
374 if (!pRdrFile->pvMapping)
375 {
376 int rc;
377 off_t cb = pRdrFile->Core.pOps->pfnSize(pRdr);
378
379 pRdrFile->pvMapping = kldrHlpAlloc(cb);
380 if (!pRdrFile->pvMapping)
381#if defined(__OS2__) || defined(__WIN__)
382 return ERROR_NOT_ENOUGH_MEMORY;
383#else
384# error "port me"
385#endif
386 rc = pRdrFile->Core.pOps->pfnRead(pRdr, pRdrFile->pvMapping, cb, 0);
387 if (rc)
388 {
389 kldrHlpFree(pRdrFile->pvMapping);
390 pRdrFile->pvMapping = NULL;
391 return rc;
392 }
393 pRdrFile->cMappings = 0;
394 }
395
396 pRdrFile->cMappings++;
397 return 0;
398}
399
400
401/** @copydoc KLDRRDR::pfnRead */
402static int kldrRdrFileRead(PKLDRRDR pRdr, void *pvBuf, size_t cb, off_t off)
403{
404 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
405
406 /*
407 * Do a seek if needed.
408 */
409 if (pRdrFile->off != off)
410 {
411#ifdef __OS2__
412 ULONG ulNew;
413 APIRET rc;
414
415 rc = DosSetFilePtr(pRdrFile->File, off, FILE_BEGIN, &ulNew);
416 if (rc)
417 {
418 pRdrFile->off = -1;
419 return rc;
420 }
421
422#elif defined(__WIN__)
423 LONG offHigh;
424 LONG offLow;
425
426 offHigh = sizeof(off_t) == 4 ? 0 : (off >> 32);
427 offLow = SetFilePointer(pRdrFile->File, (LONG)off, &offHigh, FILE_BEGIN);
428 if ( offLow != (LONG)off
429 || offHigh != (LONG)(sizeof(off_t) == 4 ? 0 : (off >> 32)))
430 {
431 int rc = GetLastError();
432 if (!rc)
433 rc = ERROR_GEN_FAILURE;
434 pRdrFile->off = -1;
435 return rc;
436 }
437
438#else
439# error "port me."
440#endif
441 }
442
443 /*
444 * Do the read.
445 */
446#ifdef __OS2__
447 {
448 ULONG cbRead = 0;
449 APIRET rc = DosRead(pRdrFile->File, pvBuf, cb, &cbRead);
450 if (rc)
451 {
452 pRdrFile->off = -1;
453 return rc;
454 }
455 if (cbRead != cb)
456 {
457 pRdrFile->off = -1;
458 return ERROR_GEN_FAILURE;
459 }
460 }
461
462#elif defined(__WIN__)
463 {
464 DWORD cbRead = 0;
465 if (!ReadFile(pRdrFile->File, pvBuf, cb, &cbRead, NULL))
466 {
467 int rc = GetLastError();
468 if (!rc)
469 rc = ERROR_GEN_FAILURE;
470 pRdrFile->off = -1;
471 return rc;
472 }
473 if (cbRead != cb)
474 {
475 pRdrFile->off = -1;
476 return ERROR_GEN_FAILURE;
477 }
478 }
479
480#else
481# error "port me."
482#endif
483
484 pRdrFile->off = off + cb;
485 return 0;
486}
487
488
489/** @copydoc KLDRRDR::pfnDestroy */
490static int kldrRdrFileDestroy(PKLDRRDR pRdr)
491{
492 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
493 int rc;
494#ifdef __OS2__
495 rc = DosClose(pRdrFile->File);
496
497#elif defined(__WIN__)
498 rc = 0;
499 if (!CloseHandle(pRdrFile->File))
500 rc = GetLastError();
501
502#else
503# error "port me"
504#endif
505
506 if (pRdrFile->pvMapping)
507 {
508 kldrHlpFree(pRdrFile->pvMapping);
509 pRdrFile->pvMapping = NULL;
510 }
511
512 kldrHlpFree(pRdr);
513 return rc;
514}
515
516
517/** @copydoc KLDRRDROPS::pfnCreate */
518static int kldrRdrFileCreate(PPKLDRRDR ppRdr, const char *pszFilename)
519{
520 size_t cchFilename;
521 PKLDRRDRFILE pRdrFile;
522
523 /*
524 * Open the file and determin its size.
525 */
526#ifdef __OS2__
527 ULONG ulAction = 0;
528 FILESTATUS3 Info;
529 APIRET rc;
530 HFILE File = 0;
531 off_t cb;
532 char szFilename[CCHMAXPATH];
533
534 if ((uintptr_t)pszFilename >= 0x20000000)
535 {
536 char *psz = (char *)kLdrHlpAllocA(cchFilename + 1);
537 kLdrHlpMemCopy(psz, pszFilename, cchFilename + 1);
538 pszFilename = psz;
539 }
540 rc = DosOpen((PCSZ)pszFilename, &File, &ulAction, 0, FILE_NORMAL,
541 OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW,
542 OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY | OPEN_FLAGS_RANDOMSEQUENTIAL,
543 NULL);
544 if (rc)
545 return rc;
546
547 rc = DosQueryPathInfo(pszFilename, FIL_QUERYFULLNAME, szFilename, sizeof(szFilename));
548 if (rc)
549 {
550 DosClose(File);
551 return rc;
552 }
553
554 rc = DosQueryFileInfo(File, FIL_STANDARD, &Info, sizeof(Info));
555 if (rc)
556 {
557 DosClose(File);
558 return rc;
559 }
560 cb = Info.cbFile;
561
562#elif defined(__WIN__)
563 SECURITY_ATTRIBUTES SecAttr;
564 DWORD High;
565 DWORD Low;
566 int rc;
567 HANDLE File;
568 off_t cb;
569 char szFilename[MAX_PATH];
570
571 SecAttr.bInheritHandle = FALSE;
572 SecAttr.lpSecurityDescriptor = NULL;
573 SecAttr.nLength = 0;
574 File = CreateFile(pszFilename, GENERIC_READ, FILE_SHARE_READ, &SecAttr, OPEN_ALWAYS, 0, NULL);
575 if (File == INVALID_HANDLE_VALUE)
576 return GetLastError();
577
578 if (!GetFullPathName(pszFilename, sizeof(szFilename), szFilename, NULL))
579 {
580 rc = GetLastError();
581 CloseHandle(File);
582 return rc;
583 }
584
585 SetLastError(0);
586 Low = GetFileSize(File, &High);
587 rc = GetLastError();
588 if (rc)
589 {
590 CloseHandle(File);
591 return rc;
592 }
593 if (sizeof(off_t) == 4)
594 cb = High ? 0x7fffffff : Low;
595 else
596 cb = ((off_t)High << 32) | Low;
597
598#else
599# error "port me"
600#endif
601
602
603 /*
604 * Allocate the reader instance.
605 */
606 cchFilename = kLdrHlpStrLen(szFilename);
607 pRdrFile = (PKLDRRDRFILE)kldrHlpAlloc(sizeof(*pRdrFile) + cchFilename);
608 if (!pRdrFile)
609#if defined(__OS2__)
610 {
611 DosClose(File);
612 return ERROR_NOT_ENOUGH_MEMORY;
613 }
614#elif defined(__WIN__)
615 {
616 CloseHandle(File);
617 return ERROR_NOT_ENOUGH_MEMORY;
618 }
619#else
620# error "port me"
621#endif
622
623 /*
624 * Initialize it and return successfully.
625 */
626 pRdrFile->Core.u32Magic = KLDRRDR_MAGIC;
627 pRdrFile->Core.pOps = &g_kLdrRdrFileOps;
628 pRdrFile->File = File;
629 pRdrFile->cb = cb;
630 pRdrFile->off = 0;
631 pRdrFile->cMappings = 0;
632 pRdrFile->cPreps = 0;
633 kLdrHlpMemCopy(&pRdrFile->szFilename[0], szFilename, cchFilename + 1);
634
635 *ppRdr = &pRdrFile->Core;
636 return 0;
637}
638
Note: See TracBrowser for help on using the repository browser.