/* * Copyright (c) 2002 * David Maisonave (david@axter.com) * * This material is provided "as is", with absolutely no warranty expressed * or implied. Any use is at your own risk. * * Permission to use or copy this software for any purpose is hereby granted * without fee, provided the above notices are retained on all copies. * Permission to modify the code and to distribute modified code is granted, * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. * * DESCRIPTION: This contains the implementation for mapped_file_generic * mapped_file_generic is used with the file_vector class * For a description of the file_vector class, see "file_vector.h" * The mapped_file_generic class hides OS implementation via mapped_file_imp_specific * Currently, only two decendent class exist. (mapped_file_imp_Win32 and mapped_file_imp_POSIX) * The mapped_file_imp_POSIX class has not yet been tested. * A third class called mapped_file_imp_generic, will be default class * for OS that does not support file mapping. * * Feel free to email bugs, suggestions, or questions to me at (david@axter.com) */ // file_vector.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "file_vector.h" #include #include namespace std_axter { class mapped_file_imp_specific { public: mapped_file_imp_specific(const char* FileName, mapped_file_openmode mode, report_error_method* report_error_method_) : m_report_error_method(report_error_method_), m_FileName(FileName), m_Mode(mode), Ptr(NULL) { } virtual ~mapped_file_imp_specific(){} virtual bool ReSize(size_t NewSize) = 0; virtual size_t GetSize() = 0; void* GetBuffer() { return Ptr; } protected: const std::string m_FileName; mapped_file_openmode m_Mode; void* Ptr; report_error_method* m_report_error_method; }; //WIN32 Implementation #if defined(WIN32) #include #include typedef HANDLE FILE_HANDLE_TYPE; class mapped_file_imp_Win32 : public mapped_file_imp_specific { public: mapped_file_imp_Win32(size_t InitialCapacity, const char* FileName, mapped_file_openmode mode, report_error_method* report_error_method_) : mapped_file_imp_specific(FileName, mode, m_report_error_method), FileHandle(NULL), MapHandle(NULL), LastError(0), SizeMapped(0) { InitiateAndSetSize(InitialCapacity, false); } virtual ~mapped_file_imp_Win32() { CleanUp(); } bool ReSize(size_t NewSize) { return InitiateAndSetSize(NewSize, true); } private: void CleanUp() { if (Ptr) { FlushViewOfFile(Ptr, 0); UnmapViewOfFile(Ptr); Ptr = NULL; } if (MapHandle) { FlushFileBuffers(MapHandle); CloseHandle(MapHandle); MapHandle = NULL; } if (FileHandle) { FlushFileBuffers(FileHandle); CloseHandle(FileHandle); FileHandle = NULL; } } bool InitiateAndSetSize(size_t Size, bool Resize) { CleanUp(); LastError = 0; const DWORD dwShareMode = FILE_SHARE_READ+FILE_SHARE_WRITE; const DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL; DWORD dw_flProtect = 0; DWORD dwDesiredAccess = 0; DWORD dwMapDesiredAccess = 0; DWORD dwCreationDisposition = ((m_Mode&mapped_file_truncate) && !Resize)?CREATE_ALWAYS:OPEN_ALWAYS; switch(m_Mode&mapped_file_read_write) { case mapped_file_read: dwDesiredAccess = GENERIC_READ; dw_flProtect = PAGE_READONLY; dwMapDesiredAccess = FILE_MAP_READ; break; case mapped_file_read_write: dwDesiredAccess = GENERIC_READ|GENERIC_WRITE; dw_flProtect = PAGE_READWRITE; dwMapDesiredAccess = FILE_MAP_ALL_ACCESS; break; } if ((FileHandle = CreateFile(m_FileName.c_str(), dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL)) != INVALID_HANDLE_VALUE) { DWORD FileSize = GetFileSize(FileHandle, NULL); if (FileSize < Size) { SetFilePointer(FileHandle, Size, 0, FILE_BEGIN); SetEndOfFile(FileHandle); } MapHandle = CreateFileMapping(FileHandle, NULL, dw_flProtect, 0, 0, NULL); if (MapHandle != INVALID_HANDLE_VALUE) Ptr = MapViewOfFile(MapHandle, dwMapDesiredAccess, 0, 0, Size); } if (!Ptr) { LastError = GetLastError(); SizeMapped=0; m_report_error_method->ReportError(LastError); return false; } else { SizeMapped = Size; } return true; } size_t GetSize() { return (size_t)SizeMapped; } FILE_HANDLE_TYPE FileHandle; FILE_HANDLE_TYPE MapHandle; DWORD LastError; DWORD SizeMapped; }; mapped_file_generic::mapped_file_generic(size_t InitialCapacity, const char* FileName, mapped_file_openmode mode, report_error_method* report_error_method_) : mapped_file(new mapped_file_imp_Win32(InitialCapacity, FileName, mode, report_error_method_)) { } //POSIX implementation #elif defined(_POSIX_SOURCE) #include #include #include #include #include typedef int FILE_HANDLE_TYPE; const int INVALID_HANDLE_VALUE = -1; class mapped_file_imp_POSIX : public mapped_file_imp_specific { public: mapped_file_imp_POSIX(size_t InitialCapacity, const char* FileName, mapped_file_openmode mode, report_error_method* report_error_method_) :mapped_file_imp_specific(FileName, mode, m_report_error_method), FileHandle(NULL), LastError(0), SizeSet(0) { InitiateAndSetSize(InitialCapacity, false); } virtual ~mapped_file_imp_POSIX() { CleanUp(); } bool ReSize(size_t NewSize) { return InitiateAndSetSize(NewSize, true); } private: void CleanUp() { if (Ptr) { munmap(Ptr, SizeSet); Ptr = NULL; SizeSet = 0; } if (FileHandle) { fsync(FileHandle); close(FileHandle); FileHandle = NULL; } } bool InitiateAndSetSize(size_t Size, bool Resize) { CleanUp(); int oflag = O_CREAT | (((m_Mode&mapped_file_truncate) && !Resize)?O_TRUNC:0); mode_t POSIX_mode = 0; int prot = 0; LastError = 0; switch(m_Mode&mapped_file_read_write) { case mapped_file_read: oflag |= O_RDONLY; POSIX_mode = S_IRUSR; prot = PROT_READ; break; case mapped_file_read_write: oflag |= O_RDWR; POSIX_mode = S_IRWXU; prot = PROT_READ|PROT_WRITE; break; } if ((FileHandle = open(m_FileName.c_str(), oflag, POSIX_mode)) != INVALID_HANDLE_VALUE) { stat stat_buffer; const int SuccesFullFstatFetch = 0; if (SuccesFullFstatFetch == fstat(FileHandle, &stat_buffer)) { long long FileSize = stat_buffer.st_size; if (FileSize < Size) ftruncate(FileHandle, Size); Ptr = mmap(NULL, Size, prot, MAP_FILE, FileHandle, 0); } } if (!Ptr) { LastError = errno; m_report_error_method->ReportError(LastError); return false; } SizeSet = Size; return true; } size_t GetSize() { return SizeSet; } FILE_HANDLE_TYPE FileHandle; size_t SizeSet; int LastError; }; mapped_file_generic::mapped_file_generic(size_t InitialCapacity, const char* FileName, mapped_file_openmode mode) :mapped_file(new mapped_file_imp_POSIX(InitialCapacity, FileName, mode)) { } #else //If not Win32 and not POSIX, then make memory type class mapped_file_imp_generic : public mapped_file_imp_specific {//This class still needs to be created. }; #endif //WIN32 void* mapped_file_generic::GetBuffer() { return mapped_file->GetBuffer(); } bool mapped_file_generic::ReSize(size_t NewSize) { return mapped_file->ReSize(NewSize); } size_t mapped_file_generic::GetSize() { return mapped_file->GetSize(); } mapped_file_generic::~mapped_file_generic() { delete mapped_file; } }