/* $Id: kLdrRdrFile.c 2829 2006-10-23 17:04:04Z bird $ */ /** @file * * kLdr - The Dynamic Loader, file abstraction. * * Copyright (c) 2006 knut st. osmundsen * * * This file is part of kLdr. * * kLdr is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * kLdr is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with kLdr; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /******************************************************************************* * Header Files * *******************************************************************************/ #ifdef __OS2__ # define INCL_ERRORS # define INCL_BASE # include #elif defined(__WIN32__) || defined(__WIN64__) || defined(__WIN__) # include # ifndef __WIN__ # define __WIN__ # endif #else # error "port me" #endif #include #include "kLdrHlp.h" /******************************************************************************* * Structures and Typedefs * *******************************************************************************/ /** * The file provier instance for native files. */ typedef struct KLDRRDRFILE { /** The file reader vtable. */ KLDRRDR Core; /** The file handle. */ #ifdef __OS2__ HFILE File; #elif defined(__WIN__) || defined(__NT__) HANDLE File; #else # error "Port me!" #endif /** The current file offset. */ off_t off; /** The file size. */ off_t cb; /** Number of mapping references. */ int32_t cMappings; /** The memory mapping. */ void *pvMapping; /** The filename. */ char szFilename[1]; } KLDRRDRFILE, *PKLDRRDRFILE; /******************************************************************************* * Internal Functions * *******************************************************************************/ static void kldrRdrFileDone(PKLDRRDR pRdr); static int kldrRdrFileUnprepare(PKLDRRDR pRdr, void *pv, size_t cb); static int kldrRdrFileUnmap(PKLDRRDR pRdr, void *pv, size_t cb); static int kldrRdrFileProtect(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt); static int kldrRdrFileMap(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile); static int kldrRdrFilePrepare(PKLDRRDR pRdr, void **ppv, size_t cb, unsigned fFixed); static const char *kldrRdrFileName(PKLDRRDR pRdr); static off_t kldrRdrFileTell(PKLDRRDR pRdr); static off_t kldrRdrFileSize(PKLDRRDR pRdr); static int kldrRdrFileAllUnmap(PKLDRRDR pRdr, const void *pvBits); static int kldrRdrFileAllMap(PKLDRRDR pRdr, const void **ppvBits); static int kldrRdrFileRead(PKLDRRDR pRdr, void *pvBuf, size_t cb, off_t off); static int kldrRdrFileDestroy(PKLDRRDR pRdr); static int kldrRdrFileCreate(PPKLDRRDR ppRdr, const char *pszFilename); /******************************************************************************* * Global Variables * *******************************************************************************/ /** Native file provider operations. */ const KLDRRDROPS g_kLdrRdrFileOps = { "native file", NULL, kldrRdrFileCreate, kldrRdrFileDestroy, kldrRdrFileRead, kldrRdrFileAllMap, kldrRdrFileAllUnmap, kldrRdrFileSize, kldrRdrFileTell, kldrRdrFileName, kldrRdrFilePrepare, kldrRdrFileMap, kldrRdrFileProtect, kldrRdrFileUnmap, kldrRdrFileUnprepare, kldrRdrFileDone, 42 }; /** @copydoc KLDRRDR::pfnDone */ static void kldrRdrFileDone(PKLDRRDR pRdr) { } /** @copydoc KLDRRDR::pfnUnprepare */ static int kldrRdrFileUnprepare(PKLDRRDR pRdr, void *pv, size_t cb) { return -1; } /** @copydoc KLDRRDR::pfnUnmap */ static int kldrRdrFileUnmap(PKLDRRDR pRdr, void *pv, size_t cb) { return -1; } /** @copydoc KLDRRDR::pfnProtect */ static int kldrRdrFileProtect(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt) { return -1; } /** @copydoc KLDRRDR::pfnMap */ static int kldrRdrFileMap(PKLDRRDR pRdr, void *pv, size_t cb, KLDRPROT enmProt, off_t offFile, size_t cbFile) { return -1; } /** @copydoc KLDRRDR:pfnPrepare */ static int kldrRdrFilePrepare(PKLDRRDR pRdr, void **ppv, size_t cb, unsigned fFixed) { #ifdef __OS2__ #elif defined(__WIN__) #else # error "port me." #endif return -1; } /** @copydoc KLDRRDR::pfnName */ static const char *kldrRdrFileName(PKLDRRDR pRdr) { PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr; return &pRdrFile->szFilename[0]; } /** @copydoc KLDRRDR::pfnTell */ static off_t kldrRdrFileTell(PKLDRRDR pRdr) { PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr; /* * If the offset is undefined, try figure out what it is. */ if (pRdrFile->off == -1) { #ifdef __OS2__ ULONG ulNew; APIRET rc = DosSetFilePtr(pRdrFile->File, 0, FILE_CURRENT, &ulNew); if (rc) return -1; pRdrFile->off = ulNew; #elif defined(__WIN__) LONG offHigh = 0; LONG offLow; int rc; SetLastError(0); offLow = SetFilePointer(pRdrFile->File, 0, &offHigh, FILE_BEGIN); rc = GetLastError(); if (rc) return -1; pRdrFile->off = ((off_t)offHigh << 32) | offLow; #else # error "port me." #endif } return pRdrFile->off; } /** @copydoc KLDRRDR::pfnSize */ static off_t kldrRdrFileSize(PKLDRRDR pRdr) { PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr; return pRdrFile->cb; } /** @copydoc KLDRRDR::pfnAllUnmap */ static int kldrRdrFileAllUnmap(PKLDRRDR pRdr, const void *pvBits) { PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr; /* check for underflow */ if (pRdrFile->cMappings <= 0) #if defined(__OS2__) || defined(__WIN__) return ERROR_INVALID_PARAMETER; #else # error "port me" #endif /* decrement usage counter, free mapping if no longer in use. */ if (!--pRdrFile->cMappings) { kldrHlpFree(pRdrFile->pvMapping); pRdrFile->pvMapping = NULL; } return 0; } /** @copydoc KLDRRDR::pfnAllMap */ static int kldrRdrFileAllMap(PKLDRRDR pRdr, const void **ppvBits) { PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr; /* * Do we need to map it? */ if (!pRdrFile->pvMapping) { int rc; off_t cb = pRdrFile->Core.pOps->pfnSize(pRdr); pRdrFile->pvMapping = kldrHlpAlloc(cb); if (!pRdrFile->pvMapping) #if defined(__OS2__) || defined(__WIN__) return ERROR_NOT_ENOUGH_MEMORY; #else # error "port me" #endif rc = pRdrFile->Core.pOps->pfnRead(pRdr, pRdrFile->pvMapping, cb, 0); if (rc) { kldrHlpFree(pRdrFile->pvMapping); pRdrFile->pvMapping = NULL; return rc; } pRdrFile->cMappings = 0; } pRdrFile->cMappings++; return 0; } /** @copydoc KLDRRDR::pfnRead */ static int kldrRdrFileRead(PKLDRRDR pRdr, void *pvBuf, size_t cb, off_t off) { PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr; /* * Do a seek if needed. */ if (pRdrFile->off != off) { #ifdef __OS2__ ULONG ulNew; APIRET rc = DosSetFilePtr(pRdrFile->File, off, FILE_BEGIN, &ulNew); if (rc) { pRdrFile->off = -1; return rc; } #elif defined(__WIN__) LONG offHigh = (LONG)(off >> 32); LONG offLow = SetFilePointer(pRdrFile->File, (LONG)off, &offHigh, FILE_BEGIN); if ( offLow != (LONG)off && offHigh != (LONG)(off >> 32)) { int rc = GetLastError(); if (!rc) rc = ERROR_GEN_FAILURE; pRdrFile->off = -1; return rc; } #else # error "port me." #endif } /* * Do the read. */ #ifdef __OS2__ { ULONG cbRead = 0; APIRET rc = DosRead(pRdrFile->File, pvBuf, cb, &cbRead); if (rc) { pRdrFile->off = -1; return rc; } if (cbRead != cb) { pRdrFile->off = -1; return ERROR_GEN_FAILURE; } } #elif defined(__WIN__) { DWORD cbRead = 0; if (!ReadFile(pRdrFile->File, pvBuf, cb, &cbRead, NULL)) { int rc = GetLastError(); if (!rc) rc = ERROR_GEN_FAILURE; pRdrFile->off = -1; return rc; } if (cbRead != cb) { pRdrFile->off = -1; return ERROR_GEN_FAILURE; } } #else # error "port me." #endif pRdrFile->off = off + cb; return 0; } /** @copydoc KLDRRDR::pfnDestroy */ static int kldrRdrFileDestroy(PKLDRRDR pRdr) { PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr; int rc; #ifdef __OS2__ rc = DosClose(pRdrFile->File); #elif defined(__WIN__) if (!CloseHandle(pRdrFile->File)) rc = GetLastError(); #else # error "port me" #endif if (pRdrFile->pvMapping) { kldrHlpFree(pRdrFile->pvMapping); pRdrFile->pvMapping = NULL; } kldrHlpFree(pRdr); return rc; } /** @copydoc KLDRRDROPS::pfnCreate */ static int kldrRdrFileCreate(PPKLDRRDR ppRdr, const char *pszFilename) { size_t cchFilename; PKLDRRDRFILE pRdrFile; /* * Open the file and determin its size. */ #ifdef __OS2__ ULONG ulAction = 0; FILESTATUS3 Info; APIRET rc; HFILE File = 0; off_t cb; if ((uintptr_t)pszFilename >= 0x20000000) { char *psz = (char *)kLdrHlpAllocA(cchFilename + 1); kLdrHlpMemCopy(psz, pszFilename, cchFilename + 1); pszFilename = psz; } rc = DosOpen((PCSZ)pszFilename, &File, &ulAction, 0, FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW, OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY | OPEN_FLAGS_RANDOMSEQUENTIAL, NULL); if (rc) return rc; rc = DosQueryFileInfo(File, FIL_STANDARD, &Info, sizeof(Info)); if (rc) { DosClose(File); return rc; } cb = Info.cbFile; #elif defined(__WIN__) SECURITY_ATTRIBUTES SecAttr; DWORD High; DWORD Low; int rc; HANDLE File; off_t cb; SecAttr.bInheritHandle = FALSE; SecAttr.lpSecurityDescriptor = NULL; SecAttr.nLength = 0; File = CreateFile(pszFilename, GENERIC_READ, FILE_SHARE_READ, &SecAttr, OPEN_ALWAYS, 0, NULL); if (File == INVALID_HANDLE_VALUE) return GetLastError(); SetLastError(0); Low = GetFileSize(File, &High); rc = GetLastError(); if (rc) { CloseHandle(File); return rc; } cb = ((off_t)High << 32) | Low; #else # error "port me" #endif /* * Allocate the reader instance. */ cchFilename = kLdrHlpStrLen(pszFilename); pRdrFile = (PKLDRRDRFILE)kldrHlpAlloc(sizeof(*pRdrFile) + cchFilename); if (!pRdrFile) #if defined(__OS2__) { DosClose(File); return ERROR_NOT_ENOUGH_MEMORY; } #elif defined(__WIN__) { CloseHandle(File); return ERROR_NOT_ENOUGH_MEMORY; } #else # error "port me" #endif /* * Initialize it and return successfully. */ pRdrFile->Core.pOps = &g_kLdrRdrFileOps; pRdrFile->File = File; pRdrFile->off = 0; kLdrHlpMemCopy(&pRdrFile->szFilename[0], pszFilename, cchFilename + 1); *ppRdr = &pRdrFile->Core; return 0; }