diff options
Diffstat (limited to 'akregator/src/mk4storage/metakit/src/fileio.cpp')
-rw-r--r-- | akregator/src/mk4storage/metakit/src/fileio.cpp | 434 |
1 files changed, 434 insertions, 0 deletions
diff --git a/akregator/src/mk4storage/metakit/src/fileio.cpp b/akregator/src/mk4storage/metakit/src/fileio.cpp new file mode 100644 index 000000000..28ff7dca0 --- /dev/null +++ b/akregator/src/mk4storage/metakit/src/fileio.cpp @@ -0,0 +1,434 @@ +// fileio.cpp -- +// $Id$ +// This is part of Metakit, see http://www.equi4.com/metakit/ + +/** @file + * Implementation of c4_FileStrategy and c4_FileStream + */ + +#include "header.h" +#include "mk4io.h" + +#if q4_WIN32 +#if q4_MSVC && !q4_STRICT +#pragma warning(disable: 4201) // nonstandard extension used : ... +#endif +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#if !defined (q4_WINCE) +#include <io.h> +#include <fcntl.h> +#include <sys/stat.h> +#endif +#endif + +#if q4_UNIX && HAVE_MMAP +#include <sys/types.h> +#include <sys/mman.h> +#endif + +#if q4_UNIX +#include <unistd.h> +#include <fcntl.h> +#endif + +#if q4_WINCE +#define _get_osfhandle(x) x +#endif + +#ifndef _O_NOINHERIT +#define _O_NOINHERIT 0 +#endif + +///////////////////////////////////////////////////////////////////////////// +// +// The "Carbon" version of a build on Macintosh supports running under +// either MacOS 7..9 (which has no mmap), or MacOS X (which has mmap). +// The logic below was adapted from a contribution by Paul Snively, it +// decides at run time which case it is, and switches I/O calls to match. + +#if defined (q4_CARBON) && q4_CARBON +//#if q4_MAC && !defined (__MACH__) && (!q4_MWCW || __MWERKS__ >= 0x3000) +#undef HAVE_MMAP +#define HAVE_MMAP 1 + +#include <CFBundle.h> +#include <Folders.h> + +#define PROT_NONE 0x00 +#define PROT_READ 0x01 +#define PROT_WRITE 0x02 +#define PROT_EXEC 0x04 + +#define MAP_SHARED 0x0001 +#define MAP_PRIVATE 0x0002 + +#define MAP_FIXED 0x0010 +#define MAP_RENAME 0x0020 +#define MAP_NORESERVE 0x0040 +#define MAP_INHERIT 0x0080 +#define MAP_NOEXTEND 0x0100 +#define MAP_HASSEMAPHORE 0x0200 + +typedef unsigned long t4_u32; + +static t4_u32 sfwRefCount = 0; +static CFBundleRef systemFramework = NULL; + +static char* fake_mmap(char*, t4_u32, int, int, int, long long) + { return (char*) -1L; } +static int fake_munmap(char*, t4_u32) + { return 0; } + +static FILE* (*my_fopen)(const char*,const char*) = fopen; +static int (*my_fclose)(FILE*) = fclose; +static long (*my_ftell)(FILE*) = ftell; +static int (*my_fseek)(FILE*,long,int) = fseek; +static t4_u32 (*my_fread)(void* ptr,t4_u32,t4_u32,FILE*) = fread; +static t4_u32 (*my_fwrite)(const void* ptr,t4_u32,t4_u32,FILE*) = fwrite; +static int (*my_ferror)(FILE*) = ferror; +static int (*my_fflush)(FILE*) = fflush; +static int (*my_fileno)(FILE*) = fileno; +static char* (*my_mmap)(char*,t4_u32,int,int,int,long long) = fake_mmap; +static int (*my_munmap)(char*,t4_u32) = fake_munmap; + +static void InitializeIO() +{ + if (sfwRefCount++) return; // race condition, infinitesimal risk + + FSRef theRef; + if (FSFindFolder(kOnAppropriateDisk, kFrameworksFolderType, + false, &theRef) == noErr) { + CFURLRef fw = CFURLCreateFromFSRef(kCFAllocatorSystemDefault, &theRef); + if (fw) { + CFURLRef bd = + CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, + fw, CFSTR("System.framework"), false); + CFRelease(fw); + if (bd) { + systemFramework = CFBundleCreate(kCFAllocatorSystemDefault, bd); + CFRelease(bd); + } + } + if (!systemFramework || !CFBundleLoadExecutable(systemFramework)) + return; +#define F(x) CFBundleGetFunctionPointerForName(systemFramework, CFSTR(#x)) + my_fopen = (FILE* (*)(const char*,const char*)) F(fopen); + my_fclose = (int (*)(FILE*)) F(fclose); + my_ftell = (long (*)(FILE*)) F(ftell); + my_fseek = (int (*)(FILE*,long,int)) F(fseek); + my_fread = (t4_u32 (*)(void* ptr,t4_u32,t4_u32,FILE*)) F(fread); + my_fwrite = (t4_u32 (*)(const void* ptr,t4_u32,t4_u32,FILE*)) F(fwrite); + my_ferror = (int (*)(FILE*)) F(ferror); + my_fflush = (int (*)(FILE*)) F(fflush); + my_fileno = (int (*)(FILE*)) F(fileno); + my_mmap = (char* (*)(char*,t4_u32,int,int,int,long long)) F(mmap); + my_munmap = (int (*)(char*,t4_u32)) F(munmap); +#undef F + d4_assert(my_fopen && my_fclose && my_ftell && my_fseek && + my_fread && my_fwrite && my_ferror && my_fflush && + my_fileno && my_mmap && my_munmap); + } +} + +static void FinalizeIO() +{ + if (--sfwRefCount) return; // race condition, infinitesimal risk + + if (systemFramework) { + CFBundleUnloadExecutable(systemFramework); + CFRelease(systemFramework); + systemFramework = 0; + } +} + +#define fopen my_fopen +#define fclose my_fclose +#define ftell my_ftell +#define fseek my_fseek +#define fread my_fread +#define fwrite my_fwrite +#define ferror my_ferror +#define fflush my_fflush +#define fileno my_fileno +#define mmap my_mmap +#define munmap my_munmap + +#else + +#define InitializeIO() +#define FinalizeIO() + +#endif + +///////////////////////////////////////////////////////////////////////////// + +#if q4_CHECK +#include <stdlib.h> + +void f4_AssertionFailed(const char* cond_, const char* file_, int line_) +{ + fprintf(stderr, "Assertion failed: %s (file %s, line %d)\n", + cond_, file_, line_); + abort(); +} + +#endif //q4_CHECK + +///////////////////////////////////////////////////////////////////////////// +// c4_FileStream + +c4_FileStream::c4_FileStream (FILE* stream_, bool owned_) + : _stream (stream_), _owned (owned_) +{ +} + +c4_FileStream::~c4_FileStream () +{ + if (_owned) + fclose(_stream); +} + +int c4_FileStream::Read(void* buffer_, int length_) +{ + d4_assert(_stream != 0); + + return (int) fread(buffer_, 1, length_, _stream); +} + +bool c4_FileStream::Write(const void* buffer_, int length_) +{ + d4_assert(_stream != 0); + + return (int) fwrite(buffer_, 1, length_, _stream) == length_; +} + +///////////////////////////////////////////////////////////////////////////// +// c4_FileStrategy + +c4_FileStrategy::c4_FileStrategy (FILE* file_) + : _file (file_), _cleanup (0) +{ + InitializeIO(); + ResetFileMapping(); +} + +c4_FileStrategy::~c4_FileStrategy () +{ + _file = 0; + ResetFileMapping(); + + if (_cleanup) + fclose(_cleanup); + + d4_assert(_mapStart == 0); + FinalizeIO(); +} + +bool c4_FileStrategy::IsValid() const +{ + return _file != 0; +} + +t4_i32 c4_FileStrategy::FileSize() +{ + d4_assert(_file != 0); + + long size = -1; + + long old = ftell(_file); + if (old >= 0 && fseek(_file, 0, 2) == 0) { + long pos = ftell(_file); + if (fseek(_file, old, 0) == 0) + size = pos; + } + + if (size < 0) + _failure = ferror(_file); + + return size; +} + +t4_i32 c4_FileStrategy::FreshGeneration() +{ + d4_assert(false); + return 0; +} + +void c4_FileStrategy::ResetFileMapping() +{ +#if q4_WIN32 + if (_mapStart != 0) { + _mapStart -= _baseOffset; + d4_dbgdef(BOOL g =) + ::UnmapViewOfFile((char*) _mapStart); + d4_assert(g); + _mapStart = 0; + _dataSize = 0; + } + + if (_file != 0) { + t4_i32 len = FileSize(); + + if (len > 0) { + FlushFileBuffers((HANDLE) _get_osfhandle(_fileno(_file))); + HANDLE h = ::CreateFileMapping((HANDLE) _get_osfhandle(_fileno(_file)), + 0, PAGE_READONLY, 0, len, 0); + d4_assert(h); // check for errors, but can continue without mapping + + if (h) { + _mapStart = (t4_byte*) ::MapViewOfFile(h, FILE_MAP_READ, 0, 0, len); + d4_assert(_mapStart != 0); + + if (_mapStart != 0) { + _mapStart += _baseOffset; + _dataSize = len - _baseOffset; + } + + d4_dbgdef(BOOL f =) + ::CloseHandle(h); + d4_assert(f); + } + } + } +#elif HAVE_MMAP + if (_mapStart != 0) { + _mapStart -= _baseOffset; + munmap((char*) _mapStart, _baseOffset + _dataSize); // also loses const + _mapStart = 0; + _dataSize = 0; + } + + if (_file != 0) { + t4_i32 len = FileSize(); + + if (len > 0) { + _mapStart = (const t4_byte*) mmap(0, len, PROT_READ, MAP_SHARED, + fileno(_file), 0); + if (_mapStart != (void*) -1L) { + _mapStart += _baseOffset; + _dataSize = len - _baseOffset; + } else + _mapStart = 0; + } + } +#endif +} + +bool c4_FileStrategy::DataOpen(const char* fname_, int mode_) +{ + d4_assert(!_file); + +#if q4_WIN32 && !q4_BORC && !q4_WINCE + int flags = _O_BINARY | _O_NOINHERIT | (mode_ > 0 ? _O_RDWR : _O_RDONLY); + int fd = _open(fname_, flags); + if (fd != -1) + _cleanup = _file = _fdopen(fd, mode_ > 0 ? "r+b" : "rb"); +#else + _cleanup = _file = fopen(fname_, mode_ > 0 ? "r+b" : "rb"); +#if q4_UNIX + if (_file != 0) + fcntl(fileno(_file), F_SETFD, FD_CLOEXEC); +#endif //q4_UNIX +#endif //q4_WIN32 && !q4_BORC && !q4_WINCE + + if (_file != 0) { + ResetFileMapping(); + return true; + } + + if (mode_ > 0) { +#if q4_WIN32 && !q4_BORC && !q4_WINCE + fd = _open(fname_, flags | _O_CREAT, _S_IREAD | _S_IWRITE); + if (fd != -1) + _cleanup = _file = _fdopen(fd, "w+b"); +#else + _cleanup = _file = fopen(fname_, "w+b"); +#if q4_UNIX + if (_file != 0) + fcntl(fileno(_file), F_SETFD, FD_CLOEXEC); +#endif //q4_UNIX +#endif //q4_WIN32 && !q4_BORC && !q4_WINCE + } + + //d4_assert(_file != 0); + return false; +} + +int c4_FileStrategy::DataRead(t4_i32 pos_, void* buf_, int len_) +{ + d4_assert(_baseOffset + pos_ >= 0); + d4_assert(_file != 0); + + //printf("DataRead at %d len %d\n", pos_, len_); + return fseek(_file, _baseOffset + pos_, 0) != 0 ? -1 : + (int) fread(buf_, 1, len_, _file); +} + +void c4_FileStrategy::DataWrite(t4_i32 pos_, const void* buf_, int len_) +{ + d4_assert(_baseOffset + pos_ >= 0); + d4_assert(_file != 0); +#if 0 + if (_mapStart <= buf_ && buf_ < _mapStart + _dataSize) { + printf("DataWrite %08x at %d len %d (map %d)\n", buf_, pos_, len_, + (const t4_byte*) buf_ - _mapStart + _baseOffset); + } else { + printf("DataWrite %08x at %d len %d\n", buf_, pos_, len_); + } + fprintf(stderr, " _mapStart %08x _dataSize %d buf_ %08x len_ %d _baseOffset %d\n", + _mapStart, _dataSize, buf_, len_, _baseOffset); + printf(" _mapStart %08x _dataSize %d buf_ %08x len_ %d _baseOffset %d\n", + _mapStart, _dataSize, buf_, len_, _baseOffset); + fflush(stdout); +#endif + +#if q4_WIN32 || __hpux || __MACH__ +// if (buf_ >= _mapStart && buf_ <= _mapLimit - len_) + + // a horrendous hack to allow file mapping for Win95 on network drive + // must use a temp buf to avoid write from mapped file to same file + // + // 6-Feb-1999 -- this workaround is not thread safe + // 30-Nov-2001 -- changed to use the stack so now it is + // 28-Oct-2002 -- added HP/UX to the mix, to avoid hard lockup + char tempBuf [4096]; + d4_assert(len_ <= sizeof tempBuf); + buf_ = memcpy(tempBuf, buf_, len_); +#endif + + if (fseek(_file, _baseOffset + pos_, 0) != 0 || + (int) fwrite(buf_, 1, len_, _file) != len_) { + _failure = ferror(_file); + d4_assert(_failure != 0); + d4_assert(true); // always force an assertion failure in debug mode + } +} + +void c4_FileStrategy::DataCommit(t4_i32 limit_) +{ + d4_assert(_file != 0); + + if (fflush(_file) < 0) { + _failure = ferror(_file); + d4_assert(_failure != 0); + d4_assert(true); // always force an assertion failure in debug mode + return; + } + + if (limit_ > 0) { +#if 0 // can't truncate file in a portable way! + // unmap the file first, WinNT is more picky about this than Win95 + FILE* save = _file; + + _file = 0; + ResetFileMapping(); + _file = save; + + _file->SetLength(limit_); // now we can resize the file +#endif + ResetFileMapping(); // remap, since file length may have changed + } +} + +///////////////////////////////////////////////////////////////////////////// |