VirtualBox

source: vbox/trunk/src/libs/kStuff/iprt/kRdrFile-iprt.cpp@ 14790

Last change on this file since 14790 was 8245, checked in by vboxsync, 16 years ago

rebranding: IPRT files again.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 17.9 KB
Line 
1/* $Id: kRdrFile-iprt.cpp 8245 2008-04-21 17:24:28Z vboxsync $ */
2/** @file
3 * IPRT - kRdr Backend.
4 */
5
6/*
7 * Copyright (C) 2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#include <k/kRdr.h>
26#include <k/kRdrAll.h>
27#include <k/kErrors.h>
28#include <k/kMagics.h>
29
30#include <iprt/file.h>
31#include <iprt/assert.h>
32#include <iprt/string.h>
33#include <iprt/path.h>
34#include <iprt/param.h>
35#include <iprt/mem.h>
36#include <iprt/err.h>
37
38
39/*******************************************************************************
40* Structures and Typedefs *
41*******************************************************************************/
42/**
43 * Prepared stuff.
44 */
45typedef struct KRDRFILEPREP
46{
47 /** The address of the prepared region. */
48 void *pv;
49 /** The size of the prepared region. */
50 KSIZE cb;
51} KRDRFILEPREP, *PKRDRFILEPREP;
52
53/**
54 * The file provier instance for native files.
55 */
56typedef struct KRDRFILE
57{
58 /** The file reader vtable. */
59 KRDR Core;
60 /** The file handle. */
61 RTFILE File;
62 /** The current file offset. */
63 KFOFF off;
64 /** The file size. */
65 KFOFF cb;
66 /** Array where we stuff the mapping area data. */
67 KRDRFILEPREP aPreps[4];
68 /** The number of current preps. */
69 KU32 cPreps;
70 /** Number of mapping references. */
71 KI32 cMappings;
72 /** The memory mapping. */
73 void *pvMapping;
74 /** The filename. */
75 char szFilename[1];
76} KRDRFILE, *PKRDRFILE;
77
78
79/*******************************************************************************
80* Internal Functions *
81*******************************************************************************/
82static void krdrRTFileDone(PKRDR pRdr);
83static int krdrRTFileUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments);
84static int krdrRTFileGenericUnmap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments);
85static int krdrRTFileProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect);
86static int krdrRTFileGenericProtect(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect);
87static int krdrRTFileRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments);
88static int krdrRTFileGenericRefresh(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments);
89static int krdrRTFileMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed);
90static int krdrRTFileGenericMap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed);
91static KSIZE krdrRTFilePageSize(PKRDR pRdr);
92static const char *krdrRTFileName(PKRDR pRdr);
93static KIPTR krdrRTFileNativeFH(PKRDR pRdr);
94static KFOFF krdrRTFileTell(PKRDR pRdr);
95static KFOFF krdrRTFileSize(PKRDR pRdr);
96static int krdrRTFileAllUnmap(PKRDR pRdr, const void *pvBits);
97static int krdrRTFileAllMap(PKRDR pRdr, const void **ppvBits);
98static int krdrRTFileRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off);
99static int krdrRTFileDestroy(PKRDR pRdr);
100static int krdrRTFileCreate(PPKRDR ppRdr, const char *pszFilename);
101
102
103/*******************************************************************************
104* Global Variables *
105*******************************************************************************/
106extern "C" const KRDROPS g_kRdrFileOps;
107
108/** Native file provider operations. */
109const KRDROPS g_kRdrFileOps =
110{
111 "IPRT file",
112 NULL,
113 krdrRTFileCreate,
114 krdrRTFileDestroy,
115 krdrRTFileRead,
116 krdrRTFileAllMap,
117 krdrRTFileAllUnmap,
118 krdrRTFileSize,
119 krdrRTFileTell,
120 krdrRTFileName,
121 krdrRTFileNativeFH,
122 krdrRTFilePageSize,
123 krdrRTFileMap,
124 krdrRTFileRefresh,
125 krdrRTFileProtect,
126 krdrRTFileUnmap,
127 krdrRTFileDone,
128 42
129};
130
131
132/** @copydoc KRDROPS::pfnDone */
133static void krdrRTFileDone(PKRDR pRdr)
134{
135}
136
137
138/**
139 * Finds a prepared mapping region.
140 *
141 * @returns Pointer to the aPrep entry.
142 * @param pFile The instance data.
143 * @param pv The base of the region.
144 */
145static PKRDRFILEPREP krdrRTFileFindPrepExact(PKRDRFILE pFile, void *pv)
146{
147 KI32 i = pFile->cPreps;
148 while (i-- > 0)
149 if (pFile->aPreps[i].pv == pv)
150 return &pFile->aPreps[i];
151 return NULL;
152}
153
154
155/** @copydoc KRDROPS::pfnUnmap */
156static int krdrRTFileUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments)
157{
158 PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
159 PKRDRFILEPREP pPrep = krdrRTFileFindPrepExact(pRdrFile, pvBase);
160 int rc;
161 if (!pPrep)
162 return KERR_INVALID_PARAMETER;
163
164 rc = krdrRTFileGenericUnmap(pRdr, pPrep, cSegments, paSegments);
165
166 /* remove the mapping data on success. */
167 if (!rc)
168 {
169 pRdrFile->cPreps--;
170 if (pPrep != &pRdrFile->aPreps[pRdrFile->cPreps])
171 *pPrep = pRdrFile->aPreps[pRdrFile->cPreps];
172 }
173 return rc;
174}
175
176
177/** Generic implementation of krdrRTFileUnmap. */
178static int krdrRTFileGenericUnmap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments)
179{
180 krdrRTFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
181 RTMemPageFree(pPrep->pv);
182 return 0;
183}
184
185
186/** @copydoc KRDROPS::pfnProtect */
187static int krdrRTFileProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect)
188{
189 PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
190 PKRDRFILEPREP pPrep = krdrRTFileFindPrepExact(pRdrFile, pvBase);
191 if (!pPrep)
192 return KERR_INVALID_PARAMETER;
193
194 return krdrRTFileGenericProtect(pRdr, pPrep, cSegments, paSegments, fUnprotectOrProtect);
195}
196
197
198static unsigned krdrRTFileConvertProt(KPROT enmProt)
199{
200 switch (enmProt)
201 {
202 case KPROT_NOACCESS: return RTMEM_PROT_NONE;
203 case KPROT_READONLY: return RTMEM_PROT_READ;
204 case KPROT_READWRITE: return RTMEM_PROT_READ | RTMEM_PROT_WRITE;
205 case KPROT_WRITECOPY: return RTMEM_PROT_READ | RTMEM_PROT_WRITE;
206 case KPROT_EXECUTE: return RTMEM_PROT_EXEC;
207 case KPROT_EXECUTE_READ: return RTMEM_PROT_EXEC | RTMEM_PROT_READ;
208 case KPROT_EXECUTE_READWRITE: return RTMEM_PROT_EXEC | RTMEM_PROT_READ | RTMEM_PROT_WRITE;
209 case KPROT_EXECUTE_WRITECOPY: return RTMEM_PROT_EXEC | RTMEM_PROT_READ | RTMEM_PROT_WRITE;
210 default:
211 AssertFailed();
212 return ~0U;
213 }
214}
215
216
217/** Generic implementation of krdrRTFileProtect. */
218static int krdrRTFileGenericProtect(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect)
219{
220 KU32 i;
221
222 /*
223 * Iterate the segments and apply memory protection changes.
224 */
225 for (i = 0; i < cSegments; i++)
226 {
227 int rc;
228 void *pv;
229 KPROT enmProt;
230
231 if (paSegments[i].RVA == NIL_KLDRADDR)
232 continue;
233
234 /* calc new protection. */
235 enmProt = (KPROT)paSegments[i].enmProt; /** @todo drop cast */
236 if (fUnprotectOrProtect)
237 {
238 switch (enmProt)
239 {
240 case KPROT_NOACCESS:
241 case KPROT_READONLY:
242 case KPROT_READWRITE:
243 case KPROT_WRITECOPY:
244 enmProt = KPROT_READWRITE;
245 break;
246 case KPROT_EXECUTE:
247 case KPROT_EXECUTE_READ:
248 case KPROT_EXECUTE_READWRITE:
249 case KPROT_EXECUTE_WRITECOPY:
250 enmProt = KPROT_EXECUTE_READWRITE;
251 break;
252 default:
253 AssertFailed();
254 return -1;
255 }
256 }
257 else
258 {
259 /* copy on write -> normal write. */
260 if (enmProt == KPROT_EXECUTE_WRITECOPY)
261 enmProt = KPROT_EXECUTE_READWRITE;
262 else if (enmProt == KPROT_WRITECOPY)
263 enmProt = KPROT_READWRITE;
264 }
265
266 pv = (KU8 *)pPrep->pv + paSegments[i].RVA;
267 rc = RTMemProtect(pv, paSegments[i].cbMapped, krdrRTFileConvertProt(enmProt));
268 if (rc)
269 break;
270 }
271
272 return 0;
273}
274
275
276/** @copydoc KRDROPS::pfnRefresh */
277static int krdrRTFileRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments)
278{
279 PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
280 PKRDRFILEPREP pPrep = krdrRTFileFindPrepExact(pRdrFile, pvBase);
281 if (!pPrep)
282 return KERR_INVALID_PARAMETER;
283 return krdrRTFileGenericRefresh(pRdr, pPrep, cSegments, paSegments);
284}
285
286
287/** Generic implementation of krdrRTFileRefresh. */
288static int krdrRTFileGenericRefresh(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments)
289{
290 int rc;
291 int rc2;
292 KU32 i;
293
294 /*
295 * Make everything writable again.
296 */
297 rc = krdrRTFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
298 if (rc)
299 {
300 krdrRTFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
301 return rc;
302 }
303
304 /*
305 * Clear everything.
306 */
307 /** @todo only zero the areas not covered by raw file bits. */
308 memset(pPrep->pv, 0, pPrep->cb);
309
310 /*
311 * Reload all the segments.
312 * We could possibly skip some segments, but we currently have
313 * no generic way of figuring out which at the moment.
314 */
315 for (i = 0; i < cSegments; i++)
316 {
317 void *pv;
318
319 if ( paSegments[i].RVA == NIL_KLDRADDR
320 || paSegments[i].cbFile <= 0)
321 continue;
322
323 pv = (KU8 *)pPrep->pv + paSegments[i].RVA;
324 rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile);
325 if (rc)
326 break;
327 }
328
329 /*
330 * Protect the bits again.
331 */
332 rc2 = krdrRTFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
333 if (rc2 && rc)
334 rc = rc2;
335
336 return rc;
337}
338
339
340/** @copydoc KRDROPS::pfnMap */
341static int krdrRTFileMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed)
342{
343 PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
344 PKRDRFILEPREP pPrep = &pRdrFile->aPreps[pRdrFile->cPreps];
345 KLDRSIZE cbTotal;
346 const KSIZE cbPage = pRdr->pOps->pfnPageSize(pRdr);
347 int rc;
348 KU32 i;
349
350 if (pRdrFile->cPreps >= K_ELEMENTS(pRdrFile->aPreps))
351 return KRDR_ERR_TOO_MANY_MAPPINGS;
352
353 /*
354 * Calc the total mapping space needed.
355 */
356 cbTotal = 0;
357 for (i = 0; i < cSegments; i++)
358 {
359 KLDRSIZE uRVASegmentEnd;
360 if (paSegments[i].RVA == NIL_KLDRADDR)
361 continue;
362 uRVASegmentEnd = paSegments[i].RVA + paSegments[i].cbMapped;
363 if (cbTotal < uRVASegmentEnd)
364 cbTotal = uRVASegmentEnd;
365 }
366 pPrep->cb = (KSIZE)cbTotal;
367 if (pPrep->cb != cbTotal)
368 return KLDR_ERR_ADDRESS_OVERFLOW;
369 pPrep->cb = (pPrep->cb + (cbPage - 1)) & ~(cbPage- 1);
370
371 /*
372 * Use the generic map emulation.
373 */
374 pPrep->pv = fFixed ? *ppvBase : NULL;
375 rc = krdrRTFileGenericMap(pRdr, pPrep, cSegments, paSegments, fFixed);
376 if (!rc)
377 {
378 *ppvBase = pPrep->pv;
379 pRdrFile->cPreps++;
380 }
381
382 return rc;
383}
384
385
386/** Generic implementation of krdrRTFileMap. */
387static int krdrRTFileGenericMap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed)
388{
389 int rc = 0;
390 KU32 i;
391
392 /*
393 * Generic mapping code using kHlpPageAlloc(), kHlpPageFree() and kHlpPageProtect().
394 */
395 pPrep->pv = RTMemPageAlloc(pPrep->cb);
396 if (!pPrep->pv)
397 return KERR_NO_MEMORY;
398
399 /*
400 * Load the data.
401 */
402 for (i = 0; i < cSegments; i++)
403 {
404 void *pv;
405
406 if ( paSegments[i].RVA == NIL_KLDRADDR
407 || paSegments[i].cbFile <= 0)
408 continue;
409
410 pv = (KU8 *)pPrep->pv + paSegments[i].RVA;
411 rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile);
412 if (rc)
413 break;
414 }
415
416 /*
417 * Set segment protection.
418 */
419 if (!rc)
420 {
421 rc = krdrRTFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
422 if (!rc)
423 return 0;
424 krdrRTFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
425 }
426
427 /* bailout */
428 RTMemPageFree(pPrep->pv);
429 return rc;
430}
431
432
433/** @copydoc KRDROPS::pfnPageSize */
434static KSIZE krdrRTFilePageSize(PKRDR pRdr)
435{
436 return PAGE_SIZE;
437}
438
439
440/** @copydoc KRDROPS::pfnName */
441static const char *krdrRTFileName(PKRDR pRdr)
442{
443 PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
444 return &pRdrFile->szFilename[0];
445}
446
447
448static KIPTR krdrRTFileNativeFH(PKRDR pRdr)
449{
450 PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
451 return (KIPTR)pRdrFile->File;
452}
453
454
455/** @copydoc KRDROPS::pfnTell */
456static KFOFF krdrRTFileTell(PKRDR pRdr)
457{
458 PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
459
460 /*
461 * If the offset is undefined, try figure out what it is.
462 */
463 if (pRdrFile->off == -1)
464 {
465 pRdrFile->off = RTFileTell(pRdrFile->File);
466 if (pRdrFile->off < 0)
467 pRdrFile->off = -1;
468 }
469 return pRdrFile->off;
470}
471
472
473/** @copydoc KRDROPS::pfnSize */
474static KFOFF krdrRTFileSize(PKRDR pRdr)
475{
476 PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
477 return pRdrFile->cb;
478}
479
480
481/** @copydoc KRDROPS::pfnAllUnmap */
482static int krdrRTFileAllUnmap(PKRDR pRdr, const void *pvBits)
483{
484 PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
485
486 /* check for underflow */
487 if (pRdrFile->cMappings <= 0)
488 return KERR_INVALID_PARAMETER;
489
490 /* decrement usage counter, free mapping if no longer in use. */
491 if (!--pRdrFile->cMappings)
492 {
493 RTMemFree(pRdrFile->pvMapping);
494 pRdrFile->pvMapping = NULL;
495 }
496
497 return 0;
498}
499
500
501/** @copydoc KRDROPS::pfnAllMap */
502static int krdrRTFileAllMap(PKRDR pRdr, const void **ppvBits)
503{
504 PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
505
506 /*
507 * Do we need to map it?
508 */
509 if (!pRdrFile->pvMapping)
510 {
511 int rc;
512 KFOFF cbFile = pRdrFile->Core.pOps->pfnSize(pRdr);
513 KSIZE cb = (KSIZE)cbFile;
514 if ((KFOFF)cb != cbFile)
515 return KERR_NO_MEMORY;
516
517 pRdrFile->pvMapping = RTMemAlloc(cb);
518 if (!pRdrFile->pvMapping)
519 return KERR_NO_MEMORY;
520 rc = pRdrFile->Core.pOps->pfnRead(pRdr, pRdrFile->pvMapping, cb, 0);
521 if (rc)
522 {
523 RTMemFree(pRdrFile->pvMapping);
524 pRdrFile->pvMapping = NULL;
525 return rc;
526 }
527 pRdrFile->cMappings = 0;
528 }
529
530 *ppvBits = pRdrFile->pvMapping;
531 pRdrFile->cMappings++;
532 return 0;
533}
534
535
536/** @copydoc KRDROPS::pfnRead */
537static int krdrRTFileRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off)
538{
539 PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
540 int rc;
541
542 /*
543 * Do a seek if needed.
544 */
545 if (pRdrFile->off != off)
546 {
547 rc = RTFileSeek(pRdrFile->File, off, RTFILE_SEEK_BEGIN, NULL);
548 if (RT_FAILURE(rc))
549 {
550 pRdrFile->off = -1;
551 return rc;
552 }
553 }
554
555 /*
556 * Do the read.
557 */
558 rc = RTFileRead(pRdrFile->File, pvBuf, cb, NULL);
559 if (RT_FAILURE(rc))
560 {
561 pRdrFile->off = -1;
562 return rc;
563 }
564
565 pRdrFile->off = off + cb;
566 return 0;
567}
568
569
570/** @copydoc KRDROPS::pfnDestroy */
571static int krdrRTFileDestroy(PKRDR pRdr)
572{
573 PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
574 int rc;
575
576 rc = RTFileClose(pRdrFile->File);
577
578 if (pRdrFile->pvMapping)
579 {
580 RTMemFree(pRdrFile->pvMapping);
581 pRdrFile->pvMapping = NULL;
582 }
583
584 RTMemFree(pRdr);
585 return rc;
586}
587
588
589/** @copydoc KRDROPS::pfnCreate */
590static int krdrRTFileCreate(PPKRDR ppRdr, const char *pszFilename)
591{
592 KSIZE cchFilename;
593 PKRDRFILE pRdrFile;
594 RTFILE File;
595 uint64_t cb;
596 int rc;
597 char szFilename[RTPATH_MAX];
598
599 /*
600 * Open the file, determin its size and correct filename.
601 */
602 rc = RTFileOpen(&File, pszFilename, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
603 if (RT_FAILURE(rc))
604 return rc;
605
606 rc = RTFileGetSize(File, &cb);
607 if (RT_SUCCESS(rc))
608 {
609 rc = RTPathReal(pszFilename, szFilename, sizeof(szFilename));
610 if (RT_SUCCESS(rc))
611 {
612 /*
613 * Allocate the reader instance.
614 */
615 cchFilename = strlen(szFilename);
616 pRdrFile = (PKRDRFILE)RTMemAlloc(sizeof(*pRdrFile) + cchFilename);
617 if (pRdrFile)
618 {
619 /*
620 * Initialize it and return successfully.
621 */
622 pRdrFile->Core.u32Magic = KRDR_MAGIC;
623 pRdrFile->Core.pOps = &g_kRdrFileOps;
624 pRdrFile->File = File;
625 pRdrFile->cb = cb;
626 pRdrFile->off = 0;
627 pRdrFile->cMappings = 0;
628 pRdrFile->cPreps = 0;
629 memcpy(&pRdrFile->szFilename[0], szFilename, cchFilename + 1);
630
631 *ppRdr = &pRdrFile->Core;
632 return 0;
633 }
634
635 rc = KERR_NO_MEMORY;
636 }
637 }
638
639 RTFileClose(File);
640 return rc;
641}
642
643
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette