ultimatepp/uppsrc/Core/FileMapping.cpp

227 lines
4.6 KiB
C++

#include "Core.h"
#ifdef PLATFORM_POSIX
#include <sys/mman.h>
#endif
namespace Upp {
int FileMapping::MappingGranularity()
{
static int mg = 0;
#ifdef PLATFORM_WIN32
ONCELOCK {
SYSTEM_INFO info;
GetSystemInfo(&info);
mg = info.dwAllocationGranularity;
}
#else
ONCELOCK {
mg = getpagesize();
}
#endif
return mg;
}
FileMapping::FileMapping(const char *file_)
{
#ifdef PLATFORM_WIN32
hfile = INVALID_HANDLE_VALUE;
hmap = NULL;
#endif
#ifdef PLATFORM_POSIX
hfile = -1;
Zero(hfstat);
#endif
base = rawbase = NULL;
size = rawsize = 0;
offset = rawoffset = 0;
filesize = -1;
write = false;
if(file_)
Open(file_);
}
bool FileMapping::Open(const char *file)
{
Close();
write = false;
#ifdef PLATFORM_WIN32
hfile = CreateFileW(ToSystemCharsetW(file), GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if(hfile == INVALID_HANDLE_VALUE)
return false;
filesize = ::GetFileSize(hfile, NULL);
hmap = CreateFileMapping(hfile, NULL, PAGE_READONLY, 0, 0, NULL);
if(!hmap) {
Close();
return false;
}
#endif
#ifdef PLATFORM_POSIX
hfile = open(ToSystemCharset(file), O_RDONLY);
if(hfile == -1)
return false;
if(fstat(hfile, &hfstat) == -1) {
Close();
return false;
}
filesize = hfstat.st_size;
#endif
return true;
}
bool FileMapping::Create(const char *file, int64 filesize_, bool delete_share)
{
Close();
write = true;
#ifdef PLATFORM_WIN32
hfile = CreateFileW(ToSystemCharsetW(file), GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | (delete_share ? FILE_SHARE_DELETE : 0),
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if(hfile == INVALID_HANDLE_VALUE)
return false;
long lo = (dword)filesize_, hi = (dword)(filesize_ >> 32);
hmap = CreateFileMapping(hfile, NULL, PAGE_READWRITE, hi, lo, NULL);
if(!hmap) {
Close();
return false;
}
#endif
#ifdef PLATFORM_POSIX
hfile = open(ToSystemCharset(file), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if(hfile == -1)
return false;
#endif
filesize = filesize_;
return true;
}
byte *FileMapping::Map(int64 mapoffset, size_t maplen)
{
ASSERT(IsOpen());
Unmap();
mapoffset = minmax<int64>(mapoffset, 0, filesize);
int gran = MappingGranularity();
int64 rawoff = mapoffset & -gran;
maplen = (size_t)min<int64>(maplen, filesize - mapoffset);
size_t rawsz = (size_t)min<int64>((maplen + (size_t)(mapoffset - rawoff) + gran - 1) & -gran, filesize - rawoff);
rawoffset = rawoff;
rawsize = rawsz;
#ifdef PLATFORM_WIN32
rawbase = (byte *)MapViewOfFile(hmap, write ? FILE_MAP_WRITE : FILE_MAP_READ,
(dword)(rawoffset >> 32), (dword)(rawoffset >> 0), rawsize);
#else
rawbase = (byte *)mmap(0, rawsize,
PROT_READ | (write ? PROT_WRITE : 0),
#ifdef PLATFORM_FREEBSD
MAP_NOSYNC,
#else
MAP_SHARED,
#endif
hfile, rawoffset);
#endif
#ifdef PLATFORM_POSIX
if(rawbase == (byte *)~0)
#else
if(!rawbase)
#endif
return NULL;
offset = mapoffset;
size = maplen;
base = rawbase + (int)(offset - rawoffset);
return base;
}
bool FileMapping::Unmap()
{
bool ok = true;
if(rawbase) {
#ifdef PLATFORM_WIN32
ok = !!UnmapViewOfFile(rawbase);
#endif
#ifdef PLATFORM_POSIX
ok = (munmap((void *)rawbase, rawsize) == 0);
#endif
}
base = rawbase = NULL;
size = 0;
return ok;
}
bool FileMapping::Expand(int64 new_filesize)
{
ASSERT(IsOpen());
if(new_filesize > filesize) {
if(!Unmap())
return false;
#ifdef PLATFORM_WIN32
if(!CloseHandle(hmap)) {
hmap = NULL;
return false;
}
hmap = NULL;
#endif
#ifdef PLATFORM_POSIX
if(FTRUNCATE64_(hfile, new_filesize - filesize) != 0) {
Close();
return false;
}
#endif
filesize = new_filesize;
}
return true;
}
bool FileMapping::Close()
{
bool ok = Unmap();
#ifdef PLATFORM_WIN32
if(hmap) {
if(!CloseHandle(hmap)) ok = false;
hmap = NULL;
}
if(IsOpen()) {
if(!CloseHandle(hfile)) ok = false;
hfile = INVALID_HANDLE_VALUE;
}
#endif
#ifdef PLATFORM_POSIX
if(IsOpen()) {
if(close(hfile) != 0) ok = false;
Zero(hfstat);
hfile = -1;
}
#endif
filesize = -1;
offset = 0;
size = 0;
write = false;
return ok;
}
Time FileMapping::GetTime() const
{
ASSERT(IsOpen());
#ifdef PLATFORM_WIN32
FileTime ft;
GetFileTime(hfile, NULL, NULL, &ft);
return ft;
#endif
#ifdef PLATFORM_POSIX
return Time(hfstat.st_mtime);
#endif
}
String FileMapping::GetData(int64 offset, int len)
{
if(IsOpen() && Map(offset, len))
return String(base, len);
else {
NEVER();
return String::GetVoid();
}
}
}