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
RevLine 
[2826]1/* $Id: kLdrRdrFile.c 2860 2006-11-08 04:10:14Z bird $ */
[2825]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/**
[2860]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/**
[2825]69 * The file provier instance for native files.
70 */
71typedef struct KLDRRDRFILE
72{
73 /** The file reader vtable. */
[2860]74 KLDRRDR Core;
[2825]75 /** The file handle. */
76#ifdef __OS2__
[2860]77 HFILE File;
[2825]78#elif defined(__WIN__) || defined(__NT__)
[2860]79 HANDLE File;
[2825]80#else
81# error "Port me!"
82#endif
83 /** The current file offset. */
[2860]84 off_t off;
[2825]85 /** The file size. */
[2860]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;
[2825]91 /** Number of mapping references. */
[2860]92 int32_t cMappings;
[2825]93 /** The memory mapping. */
[2860]94 void *pvMapping;
[2825]95 /** The filename. */
[2860]96 char szFilename[1];
[2825]97} KLDRRDRFILE, *PKLDRRDRFILE;
98
99
100/*******************************************************************************
101* Internal Functions *
102*******************************************************************************/
[2829]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);
[2857]107static int kldrRdrFileRefreshMap(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile);
[2829]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);
[2857]110static size_t kldrRdrFilePageSize(PKLDRRDR pRdr);
[2825]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,
[2829]136 kldrRdrFileName,
[2857]137 kldrRdrFilePageSize,
[2829]138 kldrRdrFilePrepare,
139 kldrRdrFileMap,
[2857]140 kldrRdrFileRefreshMap,
[2829]141 kldrRdrFileProtect,
142 kldrRdrFileUnmap,
143 kldrRdrFileUnprepare,
144 kldrRdrFileDone,
145 42
[2825]146};
147
148
[2829]149/** @copydoc KLDRRDR::pfnDone */
150static void kldrRdrFileDone(PKLDRRDR pRdr)
151{
152}
[2825]153
[2860]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
[2829]196/** @copydoc KLDRRDR::pfnUnprepare */
197static int kldrRdrFileUnprepare(PKLDRRDR pRdr, void *pv, size_t cb)
198{
[2860]199 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
200 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv, cb);
201 if (!pPrep)
202 return KLDR_ERR_INVALID_PARAMETER;
203
[2829]204 return -1;
205}
206
207
208/** @copydoc KLDRRDR::pfnUnmap */
209static int kldrRdrFileUnmap(PKLDRRDR pRdr, void *pv, size_t cb)
210{
[2860]211 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
212 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv, cb);
213 if (!pPrep)
214 return KLDR_ERR_INVALID_PARAMETER;
215
[2829]216 return -1;
217}
218
219
220/** @copydoc KLDRRDR::pfnProtect */
221static int kldrRdrFileProtect(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt)
222{
[2860]223 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
224 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv, cb);
225 if (!pPrep)
226 return KLDR_ERR_INVALID_PARAMETER;
227
[2829]228 return -1;
229}
230
231
[2857]232/** @copydoc KLDRRDR::pfnRefreshMap */
233static int kldrRdrFileRefreshMap(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile)
234{
[2860]235 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
236 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv, cb);
237 if (!pPrep)
238 return KLDR_ERR_INVALID_PARAMETER;
239
[2857]240 return -1;
241}
242
243
[2829]244/** @copydoc KLDRRDR::pfnMap */
245static int kldrRdrFileMap(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile)
246{
[2860]247 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
248 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pv, cb);
249 if (!pPrep)
250 return KLDR_ERR_INVALID_PARAMETER;
251
[2829]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
[2857]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
[2825]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);
[2858]320 offLow = SetFilePointer(pRdrFile->File, 0, &offHigh, FILE_CURRENT);
[2825]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;
[2858]413 APIRET rc;
414
415 rc = DosSetFilePtr(pRdrFile->File, off, FILE_BEGIN, &ulNew);
[2825]416 if (rc)
417 {
418 pRdrFile->off = -1;
419 return rc;
420 }
421
422#elif defined(__WIN__)
[2858]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);
[2825]428 if ( offLow != (LONG)off
[2858]429 || offHigh != (LONG)(sizeof(off_t) == 4 ? 0 : (off >> 32)))
[2825]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__)
[2858]498 rc = 0;
[2825]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__
[2858]527 ULONG ulAction = 0;
528 FILESTATUS3 Info;
529 APIRET rc;
530 HFILE File = 0;
531 off_t cb;
532 char szFilename[CCHMAXPATH];
[2825]533
534 if ((uintptr_t)pszFilename >= 0x20000000)
535 {
[2828]536 char *psz = (char *)kLdrHlpAllocA(cchFilename + 1);
537 kLdrHlpMemCopy(psz, pszFilename, cchFilename + 1);
[2825]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
[2858]547 rc = DosQueryPathInfo(pszFilename, FIL_QUERYFULLNAME, szFilename, sizeof(szFilename));
548 if (rc)
549 {
550 DosClose(File);
551 return rc;
552 }
553
[2825]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;
[2858]569 char szFilename[MAX_PATH];
[2825]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
[2858]578 if (!GetFullPathName(pszFilename, sizeof(szFilename), szFilename, NULL))
579 {
580 rc = GetLastError();
581 CloseHandle(File);
582 return rc;
583 }
584
[2825]585 SetLastError(0);
586 Low = GetFileSize(File, &High);
587 rc = GetLastError();
588 if (rc)
589 {
590 CloseHandle(File);
591 return rc;
592 }
[2858]593 if (sizeof(off_t) == 4)
594 cb = High ? 0x7fffffff : Low;
595 else
596 cb = ((off_t)High << 32) | Low;
[2825]597
598#else
599# error "port me"
600#endif
601
602
603 /*
604 * Allocate the reader instance.
605 */
[2858]606 cchFilename = kLdrHlpStrLen(szFilename);
[2825]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 */
[2858]626 pRdrFile->Core.u32Magic = KLDRRDR_MAGIC;
[2825]627 pRdrFile->Core.pOps = &g_kLdrRdrFileOps;
628 pRdrFile->File = File;
[2858]629 pRdrFile->cb = cb;
[2825]630 pRdrFile->off = 0;
[2860]631 pRdrFile->cMappings = 0;
632 pRdrFile->cPreps = 0;
[2858]633 kLdrHlpMemCopy(&pRdrFile->szFilename[0], szFilename, cchFilename + 1);
[2825]634
635 *ppRdr = &pRdrFile->Core;
636 return 0;
637}
638
Note: See TracBrowser for help on using the repository browser.