VirtualBox

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

Last change on this file since 71765 was 62593, checked in by vboxsync, 8 years ago

kStuff related warnings

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