source: trunk/kStuff/kRdr/kRdrFile.cpp

Last change on this file was 3611, checked in by bird, 18 years ago

license update.

  • Property svn:keywords set to Id
File size: 36.9 KB
RevLine 
[2826]1/* $Id: kRdrFile.cpp 3611 2007-10-29 03:37:27Z bird $ */
[2825]2/** @file
[3544]3 * kRdrFile - The Native File Provider
4 */
5
6/*
[3611]7 * Copyright (c) 2006-2007 knut st. osmundsen <bird-kStuff-spam@anduin.net>
[2825]8 *
[3544]9 * This file is part of kStuff.
[2825]10 *
[3611]11 * kStuff is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
[2825]15 *
[3611]16 * In addition to the permissions in the GNU Lesser General Public
17 * License, you are granted unlimited permission to link the compiled
18 * version of this file into combinations with other programs, and to
19 * distribute those combinations without any restriction coming from
20 * the use of this file.
21 *
[3544]22 * kStuff is distributed in the hope that it will be useful,
[2825]23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
[3611]24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * Lesser General Public License for more details.
[2825]26 *
[3611]27 * You should have received a copy of the GNU Lesser General Public
28 * License along with kStuff; if not, write to the Free Software
29 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
30 * 02110-1301, USA
[2825]31 */
32
33/*******************************************************************************
34* Header Files *
35*******************************************************************************/
[3546]36#include "kRdrInternal.h"
37#include <k/kHlpAlloc.h>
38#include <k/kHlpString.h>
[3595]39#include <k/kErrors.h>
[3544]40
[3600]41#if K_OS == K_OS_DARWIN \
42 || K_OS == K_OS_FREEBSD \
43 || K_OS == K_OS_LINUX \
44 || K_OS == K_OS_NETBSD \
45 || K_OS == K_OS_OPENBSD \
46 || K_OS == K_OS_SOLARIS
47# include <k/kHlpSys.h>
[3595]48# include <sys/fcntl.h>
49# include <sys/mman.h>
50# include <unistd.h>
51
52#elif K_OS == K_OS_OS2
[2825]53# define INCL_ERRORS
54# define INCL_BASE
55# include <os2.h>
56
[3544]57#elif K_OS == K_OS_WINDOWS
[2861]58# define WIN32_NO_STATUS
[2825]59# include <Windows.h>
[2861]60# include <ntsecapi.h>
61# include <ntstatus.h>
[2825]62
[3552]63# ifdef __cplusplus
64 extern "C" {
65# endif
66
[2883]67 /** @todo find a non-conflicting header with NTSTATUS, NTAPI, ++ */
[2861]68 typedef LONG NTSTATUS;
69 #define NT_SUCCESS(x) ((x)>=0)
70
71 typedef struct _OBJECT_ATTRIBUTES
72 {
73 ULONG Length;
74 HANDLE RootDirectory;
75 PUNICODE_STRING ObjectName;
76 ULONG Attributes;
77 PVOID SecurityDescriptor;
78 PVOID SecurityQualityOfService;
79 } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
80
81 typedef enum _SECTION_INHERIT
82 {
83 ViewShare = 1,
84 ViewUnmap = 2
85 } SECTION_INHERIT;
86
87# define NTOSAPI __declspec(dllimport)
88# define NtCurrentProcess() GetCurrentProcess()
89
90# ifndef MEM_DOS_LIM
91# define MEM_DOS_LIM 0x40000000UL
92# endif
93
94 NTOSAPI
95 NTSTATUS
96 NTAPI
97 NtCreateSection(
98 OUT PHANDLE SectionHandle,
99 IN ACCESS_MASK DesiredAccess,
100 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
101 IN PLARGE_INTEGER SectionSize OPTIONAL,
102 IN ULONG Protect,
103 IN ULONG Attributes,
104 IN HANDLE FileHandle OPTIONAL
105 );
106
107 NTOSAPI
108 NTSTATUS
109 NTAPI
110 NtMapViewOfSection(
111 IN HANDLE SectionHandle,
112 IN HANDLE ProcessHandle,
113 IN OUT PVOID *BaseAddress,
114 IN ULONG ZeroBits,
115 IN ULONG CommitSize,
116 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
117 IN OUT PSIZE_T ViewSize,
118 IN SECTION_INHERIT InheritDisposition,
119 IN ULONG AllocationType,
120 IN ULONG Protect
121 );
122
123 NTOSAPI
124 NTSTATUS
125 NTAPI
126 NtUnmapViewOfSection(
127 IN HANDLE ProcessHandle,
128 IN PVOID BaseAddress
129 );
130
131 NTOSAPI
132 NTSTATUS
133 NTAPI
134 NtClose(
135 IN HANDLE Handle
136 );
137
138 NTOSAPI
139 NTSTATUS
140 NTAPI
141 ZwProtectVirtualMemory(
142 IN HANDLE ProcessHandle,
143 IN OUT PVOID *BaseAddress,
[3588]144 IN OUT PSIZE_T ProtectSize,
[2861]145 IN ULONG NewProtect,
146 OUT PULONG OldProtect
147 );
148# define NtProtectVirtualMemory ZwProtectVirtualMemory
149
150 NTOSAPI
151 NTSTATUS
152 NTAPI
153 NtAllocateVirtualMemory(
154 IN HANDLE ProcessHandle,
155 IN OUT PVOID *BaseAddress,
156 IN ULONG ZeroBits,
[3588]157 IN OUT PSIZE_T AllocationSize,
[2861]158 IN ULONG AllocationType,
159 IN ULONG Protect
160 );
161
162 NTOSAPI
163 NTSTATUS
164 NTAPI
165 NtFreeVirtualMemory(
166 IN HANDLE ProcessHandle,
167 IN OUT PVOID *BaseAddress,
[3588]168 IN OUT PSIZE_T FreeSize,
[2861]169 IN ULONG FreeType
170 );
171
[3552]172# ifdef __cplusplus
173 }
174# endif
175
[2825]176#else
177# error "port me"
178#endif
179
180
181/*******************************************************************************
182* Structures and Typedefs *
183*******************************************************************************/
184/**
[2860]185 * Prepared stuff.
186 */
[3544]187typedef struct KRDRFILEPREP
[2860]188{
189 /** The address of the prepared region. */
190 void *pv;
191 /** The size of the prepared region. */
[3544]192 KSIZE cb;
193#if K_OS == K_OS_WINDOWS
[2860]194 /** Handle to the section created to map the file. */
195 HANDLE hSection;
196#endif
[3544]197} KRDRFILEPREP, *PKRDRFILEPREP;
[2860]198
199/**
[2825]200 * The file provier instance for native files.
201 */
[3544]202typedef struct KRDRFILE
[2825]203{
204 /** The file reader vtable. */
[3544]205 KRDR Core;
[2825]206 /** The file handle. */
[3595]207#if K_OS == K_OS_DARWIN \
208 || K_OS == K_OS_LINUX \
209 || K_OS == K_OS_NETBSD \
210 || K_OS == K_OS_OPENBSD \
211 || K_OS == K_OS_SOLARIS
212 int File;
213#elif K_OS == K_OS_OS2
[2860]214 HFILE File;
[3544]215#elif K_OS == K_OS_WINDOWS
[2860]216 HANDLE File;
[2825]217#else
218# error "Port me!"
219#endif
220 /** The current file offset. */
[3544]221 KFOFF off;
[2825]222 /** The file size. */
[3544]223 KFOFF cb;
[2860]224 /** Array where we stuff the mapping area data. */
[3544]225 KRDRFILEPREP aPreps[4];
[2860]226 /** The number of current preps. */
[3544]227 KU32 cPreps;
[2825]228 /** Number of mapping references. */
[3544]229 KI32 cMappings;
[2825]230 /** The memory mapping. */
[2860]231 void *pvMapping;
[2825]232 /** The filename. */
[2860]233 char szFilename[1];
[3544]234} KRDRFILE, *PKRDRFILE;
[2825]235
236
237/*******************************************************************************
238* Internal Functions *
239*******************************************************************************/
[3544]240static void krdrFileDone(PKRDR pRdr);
241static int krdrFileUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments);
242static int krdrFileGenericUnmap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments);
[3546]243static int krdrFileProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect);
244static int krdrFileGenericProtect(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect);
[3544]245static int krdrFileRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments);
246static int krdrFileGenericRefresh(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments);
[3546]247static int krdrFileMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed);
248static int krdrFileGenericMap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed);
[3544]249static KSIZE krdrFilePageSize(PKRDR pRdr);
250static const char *krdrFileName(PKRDR pRdr);
251static KIPTR krdrFileNativeFH(PKRDR pRdr);
252static KFOFF krdrFileTell(PKRDR pRdr);
253static KFOFF krdrFileSize(PKRDR pRdr);
254static int krdrFileAllUnmap(PKRDR pRdr, const void *pvBits);
255static int krdrFileAllMap(PKRDR pRdr, const void **ppvBits);
256static int krdrFileRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off);
257static int krdrFileDestroy(PKRDR pRdr);
258static int krdrFileCreate(PPKRDR ppRdr, const char *pszFilename);
[2825]259
260
261/*******************************************************************************
262* Global Variables *
263*******************************************************************************/
264/** Native file provider operations. */
[3544]265const KRDROPS g_kRdrFileOps =
[2825]266{
267 "native file",
268 NULL,
[3544]269 krdrFileCreate,
270 krdrFileDestroy,
271 krdrFileRead,
272 krdrFileAllMap,
273 krdrFileAllUnmap,
274 krdrFileSize,
275 krdrFileTell,
276 krdrFileName,
277 krdrFileNativeFH,
278 krdrFilePageSize,
279 krdrFileMap,
280 krdrFileRefresh,
281 krdrFileProtect,
282 krdrFileUnmap,
283 krdrFileDone,
[2829]284 42
[2825]285};
286
287
[3544]288#if K_OS == K_OS_WINDOWS
[2861]289/**
290 * Converts a kLdr segment protection to NT protection for a mapping.
291 *
292 * @returns Nt page protection.
293 * @param enmProt kLdr protection.
294 */
[3571]295static ULONG krdrFileGetNtMapProt(KPROT enmProt)
[2829]296{
[2861]297 switch (enmProt)
298 {
[3571]299 case KPROT_NOACCESS: return PAGE_NOACCESS;
300 case KPROT_READONLY: return PAGE_READONLY;
301 case KPROT_READWRITE: return PAGE_READWRITE;
302 case KPROT_WRITECOPY: return PAGE_WRITECOPY;
303 case KPROT_EXECUTE: return PAGE_EXECUTE;
304 case KPROT_EXECUTE_READ: return PAGE_EXECUTE_READ;
305 case KPROT_EXECUTE_READWRITE: return PAGE_EXECUTE_READWRITE;
306 case KPROT_EXECUTE_WRITECOPY: return PAGE_EXECUTE_WRITECOPY;
[2861]307 default: return ~(ULONG)0;
308 }
[2829]309}
[2825]310
[2860]311
312/**
[2861]313 * Converts a kLdr segment protection to NT protection for a allocation.
[2860]314 *
[2861]315 * @returns Nt page protection.
316 * @param enmProt kLdr protection.
[2860]317 */
[3571]318static ULONG krdrFileGetNtAllocProt(KPROT enmProt)
[2860]319{
[2861]320 switch (enmProt)
321 {
[3571]322 case KPROT_NOACCESS: return PAGE_NOACCESS;
323 case KPROT_READONLY: return PAGE_READONLY;
324 case KPROT_WRITECOPY:
325 case KPROT_READWRITE: return PAGE_READWRITE;
326 case KPROT_EXECUTE: return PAGE_EXECUTE;
327 case KPROT_EXECUTE_READ: return PAGE_EXECUTE_READ;
328 case KPROT_EXECUTE_WRITECOPY:
329 case KPROT_EXECUTE_READWRITE: return PAGE_EXECUTE_READWRITE;
[2861]330 default: return ~(ULONG)0;
331 }
[2860]332}
[2861]333#endif
[2860]334
335
[3544]336/** @copydoc KRDROPS::pfnDone */
337static void krdrFileDone(PKRDR pRdr)
[2861]338{
339}
340
341
[2860]342/**
[2861]343 * Finds a prepared mapping region.
[2860]344 *
345 * @returns Pointer to the aPrep entry.
346 * @param pFile The instance data.
[2861]347 * @param pv The base of the region.
[2860]348 */
[3544]349static PKRDRFILEPREP krdrFileFindPrepExact(PKRDRFILE pFile, void *pv)
[2860]350{
[3544]351 KI32 i = pFile->cPreps;
[2860]352 while (i-- > 0)
[2861]353 if (pFile->aPreps[i].pv == pv)
354 return &pFile->aPreps[i];
[2860]355 return NULL;
356}
357
358
[3544]359/** @copydoc KRDROPS::pfnUnmap */
360static int krdrFileUnmap(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments)
[2829]361{
[3544]362 PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
363 PKRDRFILEPREP pPrep = krdrFileFindPrepExact(pRdrFile, pvBase);
[2861]364 int rc;
[2860]365 if (!pPrep)
[3544]366 return KERR_INVALID_PARAMETER;
[2860]367
[3544]368#if K_OS == K_OS_WINDOWS
[2861]369 if (pPrep->hSection != NULL)
370 {
371 /** @todo implement me. */
372 return -1;
373 }
374#endif
375
[3544]376 rc = krdrFileGenericUnmap(pRdr, pPrep, cSegments, paSegments);
[2861]377
378 /* remove the mapping data on success. */
379 if (!rc)
380 {
381 pRdrFile->cPreps--;
382 if (pPrep != &pRdrFile->aPreps[pRdrFile->cPreps])
383 *pPrep = pRdrFile->aPreps[pRdrFile->cPreps];
384 }
385 return rc;
[2829]386}
387
388
[3544]389/** Generic implementation of krdrFileUnmap. */
390static int krdrFileGenericUnmap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments)
[2829]391{
[3544]392 krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
393 return kHlpPageFree(pPrep->pv, pPrep->cb);
[2829]394}
395
396
[3544]397/** @copydoc KRDROPS::pfnProtect */
[3595]398static int krdrFileProtect(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect)
[2829]399{
[3544]400 PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
401 PKRDRFILEPREP pPrep = krdrFileFindPrepExact(pRdrFile, pvBase);
[2860]402 if (!pPrep)
[3544]403 return KERR_INVALID_PARAMETER;
[2860]404
[3544]405#if K_OS == K_OS_WINDOWS
[2861]406 if (pPrep->hSection != NULL)
407 {
408 /** @todo implement me. */
409 return -1;
410 }
411#endif
412
[3544]413 return krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, fUnprotectOrProtect);
[2829]414}
415
416
[3544]417/** Generic implementation of krdrFileProtect. */
[3546]418static int krdrFileGenericProtect(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fUnprotectOrProtect)
[2857]419{
[3544]420 KU32 i;
[2861]421
422 /*
423 * Iterate the segments and apply memory protection changes.
424 */
425 for (i = 0; i < cSegments; i++)
426 {
427 int rc;
428 void *pv;
[3546]429 KPROT enmProt;
[2861]430
431 if (paSegments[i].RVA == NIL_KLDRADDR)
432 continue;
433
434 /* calc new protection. */
[3546]435 enmProt = (KPROT)paSegments[i].enmProt; /** @todo drop cast */
[2861]436 if (fUnprotectOrProtect)
437 {
438 switch (enmProt)
439 {
[3546]440 case KPROT_NOACCESS:
441 case KPROT_READONLY:
442 case KPROT_READWRITE:
443 case KPROT_WRITECOPY:
444 enmProt = KPROT_READWRITE;
[2861]445 break;
[3546]446 case KPROT_EXECUTE:
447 case KPROT_EXECUTE_READ:
448 case KPROT_EXECUTE_READWRITE:
449 case KPROT_EXECUTE_WRITECOPY:
450 enmProt = KPROT_EXECUTE_READWRITE;
[2861]451 break;
452 default:
[3544]453 kRdrAssert(!"bad enmProt");
[2861]454 return -1;
455 }
456 }
457 else
458 {
459 /* copy on write -> normal write. */
[3546]460 if (enmProt == KPROT_EXECUTE_WRITECOPY)
461 enmProt = KPROT_EXECUTE_READWRITE;
462 else if (enmProt == KPROT_WRITECOPY)
463 enmProt = KPROT_READWRITE;
[2861]464 }
465
[3571]466 pv = (KU8 *)pPrep->pv + paSegments[i].RVA;
[2861]467
[3544]468 rc = kHlpPageProtect(pv, paSegments[i].cbMapped, enmProt);
[2861]469 if (rc)
470 break;
471 }
472
473 return 0;
474}
475
476
[3544]477/** @copydoc KRDROPS::pfnRefresh */
478static int krdrFileRefresh(PKRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments)
[2861]479{
[3544]480 PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
481 PKRDRFILEPREP pPrep = krdrFileFindPrepExact(pRdrFile, pvBase);
[2860]482 if (!pPrep)
[3544]483 return KERR_INVALID_PARAMETER;
[2860]484
[3544]485#if K_OS == K_OS_WINDOWS
[2861]486 if (pPrep->hSection != NULL)
487 {
488 /** @todo implement me. */
489 return -1;
490 }
491#endif
492
[3544]493 return krdrFileGenericRefresh(pRdr, pPrep, cSegments, paSegments);
[2857]494}
495
496
[3544]497/** Generic implementation of krdrFileRefresh. */
498static int krdrFileGenericRefresh(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments)
[2861]499{
500 int rc;
501 int rc2;
[3544]502 KU32 i;
[2861]503
504 /*
505 * Make everything writable again.
506 */
[3544]507 rc = krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
[2861]508 if (rc)
509 {
[3544]510 krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
[2861]511 return rc;
512 }
513
514 /*
515 * Clear everything.
516 */
517 /** @todo only zero the areas not covered by raw file bits. */
[3544]518 kHlpMemSet(pPrep->pv, 0, pPrep->cb);
[2861]519
520 /*
521 * Reload all the segments.
522 * We could possibly skip some segments, but we currently have
523 * no generic way of figuring out which at the moment.
524 */
525 for (i = 0; i < cSegments; i++)
526 {
527 void *pv;
528
529 if ( paSegments[i].RVA == NIL_KLDRADDR
[2970]530 || paSegments[i].cbFile <= 0)
[2861]531 continue;
532
[3571]533 pv = (KU8 *)pPrep->pv + paSegments[i].RVA;
[2861]534 rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile);
535 if (rc)
536 break;
537 }
538
539 /*
540 * Protect the bits again.
541 */
[3544]542 rc2 = krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
[2861]543 if (rc2 && rc)
544 rc = rc2;
545
546 return rc;
547}
548
549
[3544]550/** @copydoc KRDROPS::pfnMap */
[3546]551static int krdrFileMap(PKRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed)
[2829]552{
[3544]553 PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
554 PKRDRFILEPREP pPrep = &pRdrFile->aPreps[pRdrFile->cPreps];
555 KLDRSIZE cbTotal;
556 const KSIZE cbPage = pRdr->pOps->pfnPageSize(pRdr);
557 int rc;
558 KU32 i;
[2860]559
[3544]560 if (pRdrFile->cPreps >= K_ELEMENTS(pRdrFile->aPreps))
561 return KRDR_ERR_TOO_MANY_MAPPINGS;
[2861]562
563 /*
564 * Calc the total mapping space needed.
565 */
566 cbTotal = 0;
567 for (i = 0; i < cSegments; i++)
568 {
569 KLDRSIZE uRVASegmentEnd;
570 if (paSegments[i].RVA == NIL_KLDRADDR)
571 continue;
572 uRVASegmentEnd = paSegments[i].RVA + paSegments[i].cbMapped;
573 if (cbTotal < uRVASegmentEnd)
574 cbTotal = uRVASegmentEnd;
575 }
[3544]576 pPrep->cb = (KSIZE)cbTotal;
[2861]577 if (pPrep->cb != cbTotal)
578 return KLDR_ERR_ADDRESS_OVERFLOW;
579 pPrep->cb = (pPrep->cb + (cbPage - 1)) & ~(cbPage- 1);
580
[3600]581#if K_OS == K_OS_DARWIN \
582 || K_OS == K_OS_FREEBSD \
583 || K_OS == K_OS_LINUX \
584 || K_OS == K_OS_NETBSD \
585 || K_OS == K_OS_OPENBSD \
586 || K_OS == K_OS_SOLARIS
[3595]587 /** @todo */
588
589#elif K_OS == K_OS_WINDOWS
[2861]590 /*
591 * The NT memory mapped file API sucks in a lot of ways. Unless you're actually
592 * trying to map a PE image and the kernel can parse the file for it self, the
593 * API just isn't up to scratch.
594 *
595 * Problems:
596 * 1. Reserving memory for the views is risky because you can't reserve and
597 * map into the reserved space. So, other threads might grab the memory
598 * before we get to it.
599 * 2. The page aligning of file offsets makes it impossible to map most
600 * executable images since these are commonly sector aligned.
601 * 3. When mapping a read+execute file, its not possible to create section
602 * larger than the file since the section size is bound to the data file
603 * size. This wouldn't have been such a problem if it was possible to
604 * map views beyond the section restriction, i.e. have a file size and
605 * view size.
606 * 4. Only x86 can map views at page granularity it seems, and that only
607 * using an undocument flag. The default granularity is 64KB.
608 * 5. There is more crappyness here...
609 *
610 * So, first we'll have to check if we can the file using the crappy NT APIs.
611 * Chances are we can't.
612 */
613 for (i = 0; i < cSegments; i++)
614 {
615 if (paSegments[i].RVA == NIL_KLDRADDR)
616 continue;
617
618 /* The file backing of the segments must be page aligned. */
[2970]619 if ( paSegments[i].cbFile > 0
[2861]620 && paSegments[i].offFile & (cbPage - 1))
621 break;
622
623 /* Only page alignment gaps between the file size and the mapping size. */
[2970]624 if ( paSegments[i].cbFile > 0
[2861]625 && (paSegments[i].cbFile & ~(cbPage - 1)) != (paSegments[i].cbMapped & ~(cbPage - 1)) )
626 break;
627
628 /* The mapping addresses of the segments must be page aligned.
629 * Non-x86 will probably require 64KB alignment here. */
630 if (paSegments[i].RVA & (cbPage - 1))
631 break;
632
633 /* If we do have to allocate the segment it's RVA must be 64KB aligned. */
[2970]634 if ( paSegments[i].cbFile > 0
[2861]635 && (paSegments[i].RVA & 0xffff))
636 break;
637 }
638 /** @todo if this is a PE image, we might just try a SEC_IMAGE mapping. It'll work if the host and image machines matches. */
639 if (i == cSegments)
640 {
641 /* WOW! it may work out! Incredible! */
642 SIZE_T ViewSize;
643 LARGE_INTEGER SectionOffset;
644 LARGE_INTEGER MaxiumSize;
645 NTSTATUS Status;
646 PVOID pv;
647
648 MaxiumSize.QuadPart = pRdr->pOps->pfnSize(pRdr);
649 if (MaxiumSize.QuadPart > (LONGLONG)cbTotal)
650 MaxiumSize.QuadPart = cbTotal;
651
652 Status = NtCreateSection(&pPrep->hSection,
653 SECTION_MAP_EXECUTE | SECTION_MAP_READ, /* desired access */
654 NULL, /* object attributes */
655 &MaxiumSize,
656 PAGE_EXECUTE_WRITECOPY, /* page attributes */
657 SEC_COMMIT, /* section attributes */
658 pRdrFile->File);
659 if (!NT_SUCCESS(Status))
660 return (int)Status;
661
662 /*
663 * Determin the base address.
664 */
665 if (fFixed)
666 pPrep->pv = *ppvBase;
667 else
668 {
669 pv = NULL;
[3544]670 ViewSize = (KSIZE)cbTotal;
[2861]671
672 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
673 &pv,
674 0, /* ZeroBits */
675 &ViewSize,
676 MEM_RESERVE,
677 PAGE_READONLY);
678 if (NT_SUCCESS(Status))
679 {
680 pPrep->pv = *ppvBase = pv;
681 ViewSize = 0;
682 Status = NtFreeVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, MEM_RELEASE);
683 }
684 if (!NT_SUCCESS(Status))
685 {
686 NtClose(pPrep->hSection);
687 return Status;
688 }
689 }
690
691 /*
692 * Map the segments.
693 */
694 for (i = 0; i < cSegments; i++)
695 {
696 ULONG fPageProt;
697
698 if (paSegments[i].RVA == NIL_KLDRADDR)
699 continue;
700
[3571]701 pv = (KU8 *)pPrep->pv + paSegments[i].RVA;
[2970]702 if (paSegments[i].cbFile > 0)
[2861]703 {
704 SectionOffset.QuadPart = paSegments[i].offFile;
705 ViewSize = paSegments[i].cbFile;
[3544]706 fPageProt = krdrFileGetNtMapProt(paSegments[i].enmProt);
[2883]707 /* STATUS_MAPPED_ALIGNMENT
708 STATUS_CONFLICTING_ADDRESSES
709 STATUS_INVALID_VIEW_SIZE */
[2861]710 Status = NtMapViewOfSection(pPrep->hSection, NtCurrentProcess(),
711 &pv,
712 0, /* ZeroBits */
713 0, /* CommitSize */
714 &SectionOffset, /* SectionOffset */
715 &ViewSize,
716 ViewUnmap,
717 MEM_DOS_LIM, /* AllocationType */
718 fPageProt);
719 /* do we have to zero anything? */
720 if ( NT_SUCCESS(Status)
721 && 0/*later*/)
722 {
[2883]723 /*ULONG OldPageProt = 0;
724 NtProtectVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, , */
[2861]725 }
726 }
727 else
728 {
729 ViewSize = paSegments[i].cbMapped;
[3544]730 fPageProt = krdrFileGetNtAllocProt(paSegments[i].enmProt);
[2861]731 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
732 &pv,
733 0, /* ZeroBits */
734 &ViewSize,
735 MEM_COMMIT,
736 fPageProt);
737 }
738 if (!NT_SUCCESS(Status))
739 break;
740 }
741
742 /*
743 * On success, commit the mapping and return.
744 */
745 if (NT_SUCCESS(Status))
746 {
747 pRdrFile->cPreps++;
748 return 0;
749 }
750
751 /* bail out and fall back on the generic code. */
752 while (i-- > 0)
753 {
754 PVOID pv;
755
756 if (paSegments[i].RVA == NIL_KLDRADDR)
757 continue;
758
[3571]759 pv = (KU8 *)pPrep->pv + paSegments[i].RVA;
[2970]760 if (paSegments[i].cbFile > 0)
[2861]761 NtUnmapViewOfSection(NtCurrentProcess(), pv);
762 else
763 NtFreeVirtualMemory(NtCurrentProcess(), &pv, NULL, MEM_RELEASE);
764 }
765 NtClose(pPrep->hSection);
766 }
767 /* else: fall back to the generic code */
768 pPrep->hSection = NULL;
769#endif
770
771 /*
772 * Use the generic map emulation.
773 */
774 pPrep->pv = fFixed ? *ppvBase : NULL;
[3544]775 rc = krdrFileGenericMap(pRdr, pPrep, cSegments, paSegments, fFixed);
[2861]776 if (!rc)
777 {
778 *ppvBase = pPrep->pv;
779 pRdrFile->cPreps++;
780 }
781
782 return rc;
[2829]783}
784
785
[3544]786/** Generic implementation of krdrFileMap. */
[3546]787static int krdrFileGenericMap(PKRDR pRdr, PKRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, KBOOL fFixed)
[2829]788{
[2861]789 int rc;
[3544]790 KU32 i;
[2829]791
[2861]792 /*
[3544]793 * Generic mapping code using kHlpPageAlloc(), kHlpPageFree() and kHlpPageProtect().
[2861]794 */
[3546]795 rc = kHlpPageAlloc(&pPrep->pv, pPrep->cb, KPROT_EXECUTE_READWRITE, fFixed);
[2861]796 if (rc)
797 return rc;
[2829]798
[2861]799 /*
800 * Load the data.
801 */
802 for (i = 0; i < cSegments; i++)
803 {
804 void *pv;
[2829]805
[2861]806 if ( paSegments[i].RVA == NIL_KLDRADDR
[2970]807 || paSegments[i].cbFile <= 0)
[2861]808 continue;
809
[3571]810 pv = (KU8 *)pPrep->pv + paSegments[i].RVA;
[2861]811 rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile);
812 if (rc)
813 break;
814 }
815
816 /*
817 * Set segment protection.
818 */
819 if (!rc)
820 {
[3544]821 rc = krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
[2861]822 if (!rc)
823 return 0;
[3544]824 krdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
[2861]825 }
826
827 /* bailout */
[3544]828 kHlpPageFree(pPrep->pv, pPrep->cb);
[2861]829 return rc;
[2829]830}
831
832
[3544]833/** @copydoc KRDROPS::pfnPageSize */
834static KSIZE krdrFilePageSize(PKRDR pRdr)
[2857]835{
[3595]836#if K_OS == K_OS_DARWIN
837 return 0x1000; /** @todo find some header somewhere... */
838
[3600]839#elif K_OS == K_OS_LINUX
840 return 0x1000; /** @todo find some header somewhere... */
841
[3595]842#elif K_OS == K_OS_OS2
[2857]843 /* The page size on OS/2 wont change anytime soon. :-) */
844 return 0x1000;
845
[3545]846#elif K_OS == K_OS_WINDOWS
[2857]847 SYSTEM_INFO SysInfo;
848 GetSystemInfo(&SysInfo);
849 return SysInfo.dwPageSize;
850 /*return SysInfo.dwAllocationGranularity;*/
851#else
852# error "port me"
853#endif
854}
855
856
[3544]857/** @copydoc KRDROPS::pfnName */
858static const char *krdrFileName(PKRDR pRdr)
[2825]859{
[3544]860 PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
[2825]861 return &pRdrFile->szFilename[0];
862}
863
864
[3544]865static KIPTR krdrFileNativeFH(PKRDR pRdr)
[2825]866{
[3544]867 PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
[3595]868#if K_OS == K_OS_DARWIN \
[3600]869 || K_OS == K_OS_FREEBSD \
870 || K_OS == K_OS_LINUX \
871 || K_OS == K_OS_NETBSD \
872 || K_OS == K_OS_OPENBSD \
[3595]873 || K_OS == K_OS_OS2 \
[3600]874 || K_OS == K_OS_SOLARIS \
[3595]875 || K_OS == K_OS_WINDOWS
[3544]876 return (KIPTR)pRdrFile->File;
877#else
878# error "port me"
879#endif
880}
[2825]881
[3544]882
883/** @copydoc KRDROPS::pfnTell */
884static KFOFF krdrFileTell(PKRDR pRdr)
885{
886 PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
887
[2825]888 /*
889 * If the offset is undefined, try figure out what it is.
890 */
891 if (pRdrFile->off == -1)
892 {
[3600]893#if K_OS == K_OS_DARWIN \
894 || K_OS == K_OS_FREEBSD \
895 || K_OS == K_OS_LINUX \
896 || K_OS == K_OS_NETBSD \
897 || K_OS == K_OS_OPENBSD \
898 || K_OS == K_OS_SOLARIS
[3595]899 pRdrFile->off = kHlpSys_lseek(pRdrFile->File, SEEK_CUR, 0);
900 if (pRdrFile->off < 0)
901 pRdrFile->off = -1;
902
903#elif K_OS == K_OS_OS2
[2825]904 ULONG ulNew;
905 APIRET rc = DosSetFilePtr(pRdrFile->File, 0, FILE_CURRENT, &ulNew);
906 if (rc)
907 return -1;
908 pRdrFile->off = ulNew;
909
[3545]910#elif K_OS == K_OS_WINDOWS
[2825]911 LONG offHigh = 0;
912 LONG offLow;
913 int rc;
914
915 SetLastError(0);
[2858]916 offLow = SetFilePointer(pRdrFile->File, 0, &offHigh, FILE_CURRENT);
[2825]917 rc = GetLastError();
918 if (rc)
919 return -1;
[3544]920 pRdrFile->off = ((KFOFF)offHigh << 32) | offLow;
[2825]921
922#else
923# error "port me."
924#endif
925 }
926 return pRdrFile->off;
927}
928
929
[3544]930/** @copydoc KRDROPS::pfnSize */
931static KFOFF krdrFileSize(PKRDR pRdr)
[2825]932{
[3544]933 PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
[2825]934 return pRdrFile->cb;
935}
936
937
[3544]938/** @copydoc KRDROPS::pfnAllUnmap */
939static int krdrFileAllUnmap(PKRDR pRdr, const void *pvBits)
[2825]940{
[3544]941 PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
[2825]942
943 /* check for underflow */
944 if (pRdrFile->cMappings <= 0)
[3595]945 return KERR_INVALID_PARAMETER;
[2825]946
947 /* decrement usage counter, free mapping if no longer in use. */
948 if (!--pRdrFile->cMappings)
949 {
[3544]950 kHlpFree(pRdrFile->pvMapping);
[2825]951 pRdrFile->pvMapping = NULL;
952 }
953
954 return 0;
955}
956
957
[3544]958/** @copydoc KRDROPS::pfnAllMap */
959static int krdrFileAllMap(PKRDR pRdr, const void **ppvBits)
[2825]960{
[3544]961 PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
[2825]962
963 /*
964 * Do we need to map it?
965 */
966 if (!pRdrFile->pvMapping)
967 {
968 int rc;
[3546]969 KFOFF cbFile = pRdrFile->Core.pOps->pfnSize(pRdr);
970 KSIZE cb = (KSIZE)cbFile;
971 if (cb != cbFile)
[3595]972 return KERR_NO_MEMORY;
[2825]973
[3544]974 pRdrFile->pvMapping = kHlpAlloc(cb);
[2825]975 if (!pRdrFile->pvMapping)
[3595]976 return KERR_NO_MEMORY;
[2825]977 rc = pRdrFile->Core.pOps->pfnRead(pRdr, pRdrFile->pvMapping, cb, 0);
978 if (rc)
979 {
[3544]980 kHlpFree(pRdrFile->pvMapping);
[2825]981 pRdrFile->pvMapping = NULL;
982 return rc;
983 }
984 pRdrFile->cMappings = 0;
985 }
986
[2963]987 *ppvBits = pRdrFile->pvMapping;
[2825]988 pRdrFile->cMappings++;
989 return 0;
990}
991
992
[3544]993/** @copydoc KRDROPS::pfnRead */
994static int krdrFileRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off)
[2825]995{
[3544]996 PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
[2825]997
998 /*
999 * Do a seek if needed.
1000 */
1001 if (pRdrFile->off != off)
1002 {
[3600]1003#if K_OS == K_OS_DARWIN \
1004 || K_OS == K_OS_FREEBSD \
1005 || K_OS == K_OS_LINUX \
1006 || K_OS == K_OS_NETBSD \
1007 || K_OS == K_OS_OPENBSD \
1008 || K_OS == K_OS_SOLARIS
[3595]1009 pRdrFile->off = kHlpSys_lseek(pRdrFile->File, SEEK_SET, off);
1010 if (pRdrFile->off < 0)
1011 {
1012 int rc = (int)-pRdrFile->off;
1013 pRdrFile->off = -1;
1014 return -rc;
1015 }
1016
1017#elif K_OS == K_OS_OS2
[2825]1018 ULONG ulNew;
[2858]1019 APIRET rc;
1020
1021 rc = DosSetFilePtr(pRdrFile->File, off, FILE_BEGIN, &ulNew);
[2825]1022 if (rc)
1023 {
1024 pRdrFile->off = -1;
1025 return rc;
1026 }
1027
[3545]1028#elif K_OS == K_OS_WINDOWS
[2858]1029 LONG offHigh;
1030 LONG offLow;
1031
[3546]1032 offHigh = (LONG)(off >> 32);
[2858]1033 offLow = SetFilePointer(pRdrFile->File, (LONG)off, &offHigh, FILE_BEGIN);
[2825]1034 if ( offLow != (LONG)off
[3546]1035 || offHigh != (LONG)(off >> 32))
[2825]1036 {
1037 int rc = GetLastError();
1038 if (!rc)
[3595]1039 rc = KERR_GENERAL_FAILURE;
[2825]1040 pRdrFile->off = -1;
1041 return rc;
1042 }
1043
1044#else
1045# error "port me."
1046#endif
1047 }
1048
1049 /*
1050 * Do the read.
1051 */
[3600]1052#if K_OS == K_OS_DARWIN \
1053 || K_OS == K_OS_FREEBSD \
1054 || K_OS == K_OS_LINUX \
1055 || K_OS == K_OS_NETBSD \
1056 || K_OS == K_OS_OPENBSD \
1057 || K_OS == K_OS_SOLARIS
[2825]1058 {
[3595]1059 KSSIZE cbRead;
1060
1061 cbRead = kHlpSys_read(pRdrFile->File, pvBuf, cb);
1062 if (cbRead != cb)
1063 {
1064 pRdrFile->off = -1;
1065 if (cbRead < 0)
1066 return -cbRead;
1067 return KERR_GENERAL_FAILURE;
1068 }
1069 }
1070
1071#elif K_OS == K_OS_OS2
1072 {
[2825]1073 ULONG cbRead = 0;
1074 APIRET rc = DosRead(pRdrFile->File, pvBuf, cb, &cbRead);
1075 if (rc)
1076 {
1077 pRdrFile->off = -1;
1078 return rc;
1079 }
1080 if (cbRead != cb)
1081 {
1082 pRdrFile->off = -1;
[3595]1083 return KERR_GENERAL_FAILURE;
[2825]1084 }
1085 }
1086
[3545]1087#elif K_OS == K_OS_WINDOWS
[2825]1088 {
1089 DWORD cbRead = 0;
1090 if (!ReadFile(pRdrFile->File, pvBuf, cb, &cbRead, NULL))
1091 {
1092 int rc = GetLastError();
1093 if (!rc)
[3595]1094 rc = KERR_GENERAL_FAILURE;
[2825]1095 pRdrFile->off = -1;
1096 return rc;
1097 }
1098 if (cbRead != cb)
1099 {
1100 pRdrFile->off = -1;
[3595]1101 return KERR_GENERAL_FAILURE;
[2825]1102 }
1103 }
1104
1105#else
1106# error "port me."
1107#endif
1108
1109 pRdrFile->off = off + cb;
1110 return 0;
1111}
1112
1113
[3544]1114/** @copydoc KRDROPS::pfnDestroy */
1115static int krdrFileDestroy(PKRDR pRdr)
[2825]1116{
[3544]1117 PKRDRFILE pRdrFile = (PKRDRFILE)pRdr;
[3595]1118 int rc;
1119
[3600]1120#if K_OS == K_OS_DARWIN \
1121 || K_OS == K_OS_FREEBSD \
1122 || K_OS == K_OS_LINUX \
1123 || K_OS == K_OS_NETBSD \
1124 || K_OS == K_OS_OPENBSD \
1125 || K_OS == K_OS_SOLARIS
[3595]1126 rc = kHlpSys_close(pRdrFile->File);
1127
1128#elif K_OS == K_OS_OS2
[2825]1129 rc = DosClose(pRdrFile->File);
1130
[3545]1131#elif K_OS == K_OS_WINDOWS
[2858]1132 rc = 0;
[2825]1133 if (!CloseHandle(pRdrFile->File))
1134 rc = GetLastError();
1135
1136#else
1137# error "port me"
1138#endif
1139
1140 if (pRdrFile->pvMapping)
1141 {
[3544]1142 kHlpFree(pRdrFile->pvMapping);
[2825]1143 pRdrFile->pvMapping = NULL;
1144 }
1145
[3544]1146 kHlpFree(pRdr);
[2825]1147 return rc;
1148}
1149
1150
[3544]1151/** @copydoc KRDROPS::pfnCreate */
1152static int krdrFileCreate(PPKRDR ppRdr, const char *pszFilename)
[2825]1153{
[3544]1154 KSIZE cchFilename;
1155 PKRDRFILE pRdrFile;
[2825]1156
1157 /*
[3595]1158 * Open the file, determin its size and correct filename.
[2825]1159 */
[3600]1160#if K_OS == K_OS_DARWIN \
1161 || K_OS == K_OS_FREEBSD \
1162 || K_OS == K_OS_LINUX \
1163 || K_OS == K_OS_NETBSD \
1164 || K_OS == K_OS_OPENBSD \
1165 || K_OS == K_OS_SOLARIS
[3595]1166 int File;
1167 KFOFF cb;
1168 KFOFF rc;
1169 char szFilename[1024];
[2825]1170
[3595]1171 cchFilename = kHlpStrLen(pszFilename);
1172 if (cchFilename >= sizeof(szFilename))
1173 return KERR_OUT_OF_RANGE;
1174 kHlpMemCopy(szFilename, pszFilename, cchFilename + 1);
1175 /** @todo normalize the filename. */
1176
1177# ifdef O_BINARY
1178 File = kHlpSys_open(pszFilename, O_RDONLY | O_BINARY, 0);
1179# else
1180 File = kHlpSys_open(pszFilename, O_RDONLY, 0);
1181# endif
1182 if (File < 0)
1183 return -File;
1184
1185 cb = kHlpSys_lseek(File, SEEK_END, 0);
1186 rc = kHlpSys_lseek(File, SEEK_SET, 0);
1187 if ( cb < 0
1188 || rc < 0)
1189 {
1190 kHlpSys_close(File);
1191 return cb < 0 ? -cb : -rc;
1192 }
1193
1194#elif K_OS == K_OS_OS2
1195 ULONG ulAction = 0;
1196 FILESTATUS3 Info;
1197 APIRET rc;
1198 HFILE File = 0;
1199 KFOFF cb;
1200 char szFilename[CCHMAXPATH];
1201
[2825]1202 if ((uintptr_t)pszFilename >= 0x20000000)
1203 {
[2893]1204 char *psz;
[3544]1205 cchFilename = kHlpStrLen(szFilename);
1206 psz = (char *)kHlpAllocA(cchFilename + 1);
1207 kHlpMemCopy(psz, pszFilename, cchFilename + 1);
[2825]1208 pszFilename = psz;
1209 }
1210 rc = DosOpen((PCSZ)pszFilename, &File, &ulAction, 0, FILE_NORMAL,
1211 OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW,
1212 OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY | OPEN_FLAGS_RANDOMSEQUENTIAL,
1213 NULL);
1214 if (rc)
1215 return rc;
1216
[2883]1217 rc = DosQueryPathInfo((PCSZ)pszFilename, FIL_QUERYFULLNAME, szFilename, sizeof(szFilename));
[2858]1218 if (rc)
1219 {
1220 DosClose(File);
1221 return rc;
1222 }
1223
[2825]1224 rc = DosQueryFileInfo(File, FIL_STANDARD, &Info, sizeof(Info));
1225 if (rc)
1226 {
1227 DosClose(File);
1228 return rc;
1229 }
1230 cb = Info.cbFile;
1231
[3545]1232#elif K_OS == K_OS_WINDOWS
[2825]1233 SECURITY_ATTRIBUTES SecAttr;
1234 DWORD High;
1235 DWORD Low;
1236 int rc;
1237 HANDLE File;
[3544]1238 KFOFF cb;
[2858]1239 char szFilename[MAX_PATH];
[2825]1240
1241 SecAttr.bInheritHandle = FALSE;
1242 SecAttr.lpSecurityDescriptor = NULL;
1243 SecAttr.nLength = 0;
[2869]1244 File = CreateFile(pszFilename, GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ, &SecAttr, OPEN_EXISTING, 0, NULL);
[2825]1245 if (File == INVALID_HANDLE_VALUE)
1246 return GetLastError();
1247
[2858]1248 if (!GetFullPathName(pszFilename, sizeof(szFilename), szFilename, NULL))
1249 {
1250 rc = GetLastError();
1251 CloseHandle(File);
1252 return rc;
1253 }
1254
[2825]1255 SetLastError(0);
1256 Low = GetFileSize(File, &High);
1257 rc = GetLastError();
1258 if (rc)
1259 {
1260 CloseHandle(File);
1261 return rc;
1262 }
[3546]1263 cb = ((KFOFF)High << 32) | Low;
[2825]1264
1265#else
1266# error "port me"
1267#endif
1268
1269
1270 /*
1271 * Allocate the reader instance.
1272 */
[3544]1273 cchFilename = kHlpStrLen(szFilename);
1274 pRdrFile = (PKRDRFILE)kHlpAlloc(sizeof(*pRdrFile) + cchFilename);
[2825]1275 if (!pRdrFile)
1276 {
[3600]1277#if K_OS == K_OS_DARWIN \
1278 || K_OS == K_OS_FREEBSD \
1279 || K_OS == K_OS_LINUX \
1280 || K_OS == K_OS_NETBSD \
1281 || K_OS == K_OS_OPENBSD \
1282 || K_OS == K_OS_SOLARIS
[3595]1283 kHlpSys_close(File);
1284#elif K_OS == K_OS_OS2
[2825]1285 DosClose(File);
[3545]1286#elif K_OS == K_OS_WINDOWS
[2825]1287 CloseHandle(File);
1288#else
1289# error "port me"
1290#endif
[3595]1291 return KERR_NO_MEMORY;
1292 }
[2825]1293
1294 /*
1295 * Initialize it and return successfully.
1296 */
[3578]1297 pRdrFile->Core.u32Magic = KRDR_MAGIC;
[3544]1298 pRdrFile->Core.pOps = &g_kRdrFileOps;
[2825]1299 pRdrFile->File = File;
[2858]1300 pRdrFile->cb = cb;
[2825]1301 pRdrFile->off = 0;
[2860]1302 pRdrFile->cMappings = 0;
1303 pRdrFile->cPreps = 0;
[3544]1304 kHlpMemCopy(&pRdrFile->szFilename[0], szFilename, cchFilename + 1);
[2825]1305
1306 *ppRdr = &pRdrFile->Core;
1307 return 0;
1308}
1309
Note: See TracBrowser for help on using the repository browser.