// Copyright (C) 1999-2005 Open Source Telecom Corporation. // // This program 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. // // This program 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 this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. This exception does not however // invalidate any other reasons why the executable file might be covered by // the GNU General Public License. // // This exception applies only to the code released under the name GNU // Common C++. If you copy code from other releases into a copy of GNU // Common C++, as the General Public License permits, the exception does // not apply to the code that you add in this way. To avoid misleading // anyone as to the status of such modified files, you must delete // this exception notice from them. // // If you write modifications of your own for GNU Common C++, it is your choice // whether to permit this exception to apply to your modifications. // If you do not wish that, delete this exception notice. // // needed for GNU/LINUX glibc otherwise pread/pwrite wont work #ifdef __linux__ #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 500 #endif /* * on old glibc's, this has to be * defined explicitly */ #ifndef _XOPEN_SOURCE_EXTENDED #define _XOPEN_SOURCE_EXTENDED #endif #endif #include #include #include #include #include #include #include "private.h" #ifdef __BORLANDC__ #include #include #else #include #include #endif #include #include #ifndef WIN32 #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef HAVE_SYS_FILE_H #include #endif #ifdef HAVE_SYS_LOCKF_H #include #endif #ifdef COMMON_AIX_FIXES #undef LOCK_EX #undef LOCK_SH #endif #ifdef MACOSX #define MISSING_LOCKF #endif #ifndef F_LOCK #define MISSING_LOCKF enum { F_ULOCK = 1, F_LOCK, F_TLOCK, F_TEST }; #endif #endif // ndef WIN32 #if defined(_OSF_SOURCE) && defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE > 1 #undef LOCK_EX #undef LOCK_SH #endif #if 0 /* * not used anymore ? (hen) */ static const char *clearfile(const char *pathname) { remove(pathname); return pathname; } static const char *clearfifo(const char *pathname, int mode) { remove(pathname); mkfifo(pathname, mode); return pathname; } #endif #ifdef CCXX_NAMESPACES namespace ost { #endif RandomFile::RandomFile(const char *name) : Mutex(name) { #ifdef WIN32 fd = INVALID_HANDLE_VALUE; // immediate is not defined on Win32 #else fd = -1; flags.immediate = false; #endif flags.thrown = flags.initial = flags.temp = false; flags.count = 0; pathname = NULL; } RandomFile::RandomFile(const RandomFile &rf) : Mutex() { // first, `dup'-licate the file descriptor/handle #ifdef WIN32 HANDLE pidHandle = GetCurrentProcess(); HANDLE dupHandle; if(rf.fd != INVALID_HANDLE_VALUE) { if(!DuplicateHandle(pidHandle, rf.fd, pidHandle, &dupHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) fd = INVALID_HANDLE_VALUE; else fd = dupHandle; } else fd = INVALID_HANDLE_VALUE; #else if(rf.fd > -1) fd = dup(rf.fd); else fd = -1; #endif flags = rf.flags; flags.count = 0; if(rf.pathname) pathname = newString(rf.pathname); else pathname = NULL; } RandomFile::~RandomFile() { final(); } File::Error RandomFile::restart(void) { return errOpenFailed; } File::Attr RandomFile::initialize(void) { return attrPublic; } void RandomFile::final(void) { #ifdef WIN32 if(fd != INVALID_HANDLE_VALUE) { CloseHandle(fd); if(flags.temp && pathname) DeleteFile(pathname); } #else if(fd > -1) { close(fd); if(flags.temp && pathname) remove(pathname); } #endif if(pathname) { delString(pathname); pathname = NULL; } #ifdef WIN32 fd = INVALID_HANDLE_VALUE; #else fd = -1; #endif flags.count = 0; flags.initial = false; } RandomFile::Error RandomFile::error(Error id, char *str) { errstr = str; errid = id; if(!flags.thrown) { flags.thrown = true; #ifdef CCXX_EXCEPTIONS if(Thread::getException() == Thread::throwObject) throw(this); #ifdef COMMON_STD_EXCEPTION else if(Thread::getException() == Thread::throwException) { if(!str) str = ""; throw FileException(str); } #endif #endif } return id; } bool RandomFile::initial(void) { bool init; #ifdef WIN32 if(fd == INVALID_HANDLE_VALUE) #else if(fd < 0) #endif return false; enterMutex(); init = flags.initial; flags.initial = false; if(!init) { leaveMutex(); return false; } #ifdef WIN32 Attr access = initialize(); if(access == attrInvalid) { CloseHandle(fd); if(pathname) DeleteFile(pathname); fd = INVALID_HANDLE_VALUE; leaveMutex(); error(errInitFailed); return false; } #else int mode = (int)initialize(); if(!mode) { close(fd); fd = -1; if(pathname) remove(pathname); leaveMutex(); error(errInitFailed); return false; } fchmod(fd, mode); #endif leaveMutex(); return init; } #ifndef WIN32 RandomFile::Error RandomFile::setCompletion(Complete mode) { long flag = fcntl(fd, F_GETFL); if(fd < 0) return errNotOpened; flags.immediate = false; #ifdef O_SYNC flag &= ~(O_SYNC | O_NDELAY); #else flag &= ~O_NDELAY; #endif switch(mode) { case completionImmediate: #ifdef O_SYNC flag |= O_SYNC; #endif flags.immediate = true; break; case completionDelayed: flag |= O_NDELAY; //completionDeferred: ? (hen) case completionDeferred: break; } fcntl(fd, F_SETFL, flag); return errSuccess; } #endif off_t RandomFile::getCapacity(void) { off_t eof, pos = 0; #ifdef WIN32 if(!fd) #else if(fd < 0) #endif return 0; enterMutex(); #ifdef WIN32 pos = SetFilePointer(fd, 0l, NULL, FILE_CURRENT); eof = SetFilePointer(fd, 0l, NULL, FILE_END); SetFilePointer(fd, pos, NULL, FILE_BEGIN); #else lseek(fd, pos, SEEK_SET); pos = lseek(fd, 0l, SEEK_CUR); eof = lseek(fd, 0l, SEEK_END); #endif leaveMutex(); return eof; } bool RandomFile::operator!(void) { #ifdef WIN32 return fd == INVALID_HANDLE_VALUE; #else if(fd < 0) return true; return false; #endif } ThreadFile::ThreadFile(const char *path) : RandomFile(path) { first = NULL; open(path); } ThreadFile::~ThreadFile() { final(); fcb_t *next; while(first) { next = first->next; delete first; first = next; } } ThreadFile::Error ThreadFile::restart(void) { return open(pathname); } ThreadFile::Error ThreadFile::open(const char *path) { #ifdef WIN32 if(fd != INVALID_HANDLE_VALUE) #else if(fd > -1) #endif final(); if(path != pathname) { if(pathname) delString(pathname); pathname = newString(path); } flags.initial = false; #ifdef WIN32 fd = CreateFile(pathname, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); if(fd == INVALID_HANDLE_VALUE) { flags.initial = true; fd = CreateFile(pathname, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); } if(fd == INVALID_HANDLE_VALUE) return errOpenFailed; #else fd = ::open(pathname, O_RDWR); if(fd < 0) { flags.initial = true; fd = ::open(pathname, O_CREAT | O_RDWR | O_TRUNC, (int)attrPrivate); } if(fd < 0) return error(errOpenFailed); #ifdef LOCK_EX if(flock(fd, LOCK_EX | LOCK_NB)) { close(fd); fd = -1; return error(errOpenInUse); } #endif #endif // WIN32 return errSuccess; } ThreadFile::fcb_t *ThreadFile::getFCB(void) { fcb_t *fcb = (fcb_t *)state.getKey(); if(!fcb) { fcb = new fcb_t; fcb->next = first; first = fcb; fcb->address = NULL; fcb->len = 0; fcb->pos = 0; state.setKey(fcb); } return fcb; } ThreadFile::Error ThreadFile::fetch(caddr_t address, ccxx_size_t len, off_t pos) { fcb_t *fcb = getFCB(); #ifdef WIN32 Thread::Cancel save; if(fd == INVALID_HANDLE_VALUE) #else if(fd < 0) #endif return errNotOpened; if(address) fcb->address = address; if(len) fcb->len = len; if(pos != -1) fcb->pos = pos; #ifdef WIN32 enterMutex(); save = Thread::enterCancel(); SetFilePointer(fd, fcb->pos, NULL, FILE_BEGIN); DWORD count; if(!ReadFile(fd, fcb->address, fcb->len, &count, NULL)) { Thread::exitCancel(save); leaveMutex(); return errReadFailure; } Thread::exitCancel(save); leaveMutex(); if(count < fcb->len) return errReadIncomplete; return errSuccess; #else #ifdef HAVE_PREAD_PWRITE int io = ::pread(fd, fcb->address, fcb->len, fcb->pos); #else enterMutex(); lseek(fd, fcb->pos, SEEK_SET); int io = ::read(fd, fcb->address, fcb->len); leaveMutex(); #endif if((size_t) io == fcb->len) return errSuccess; if(io > -1) return errReadIncomplete; switch(errno) { case EINTR: return errReadInterrupted; default: return errReadFailure; } #endif // WIN32 } ThreadFile::Error ThreadFile::update(caddr_t address, ccxx_size_t len, off_t pos) { fcb_t *fcb = getFCB(); #ifdef WIN32 if(fd == INVALID_HANDLE_VALUE) #else if(fd < 0) #endif return errNotOpened; if(address) fcb->address = address; if(len) fcb->len = len; if(pos != -1) fcb->pos = pos; #ifdef WIN32 enterMutex(); Thread::Cancel save = Thread::enterCancel(); SetFilePointer(fd, fcb->pos, NULL, FILE_BEGIN); DWORD count; if(!WriteFile(fd, fcb->address, fcb->len, &count, NULL)) { Thread::exitCancel(save); leaveMutex(); return errWriteFailure; } Thread::exitCancel(save); leaveMutex(); if(count < fcb->len) return errWriteIncomplete; return errSuccess; #else #ifdef HAVE_PREAD_PWRITE int io = ::pwrite(fd, fcb->address, fcb->len, fcb->pos); #else enterMutex(); lseek(fd, fcb->pos, SEEK_SET); int io = ::write(fd, fcb->address, fcb->len); leaveMutex(); #endif if((size_t) io == fcb->len) return errSuccess; if(io > -1) return errWriteIncomplete; switch(errno) { case EINTR: return errWriteInterrupted; default: return errWriteFailure; } #endif //WIN32 } ThreadFile::Error ThreadFile::append(caddr_t address, ccxx_size_t len) { fcb_t *fcb = getFCB(); #ifdef WIN32 if(fd == INVALID_HANDLE_VALUE) #else if(fd < 0) #endif return errNotOpened; if(address) fcb->address = address; if(len) fcb->len = len; enterMutex(); #ifdef WIN32 Thread::Cancel save = Thread::enterCancel(); fcb->pos = SetFilePointer(fd, 0l, NULL, FILE_END); DWORD count; if(!WriteFile(fd, fcb->address, fcb->len, &count, NULL)) { Thread::exitCancel(save); leaveMutex(); return errWriteFailure; } Thread::exitCancel(save); leaveMutex(); if(count < fcb->len) return errWriteIncomplete; return errSuccess; #else fcb->pos = lseek(fd, 0l, SEEK_END); int io = ::write(fd, fcb->address, fcb->len); leaveMutex(); if((size_t) io == fcb->len) return errSuccess; if(io > -1) return errWriteIncomplete; switch(errno) { case EINTR: return errWriteInterrupted; default: return errWriteFailure; } #endif // WIN32 } off_t ThreadFile::getPosition(void) { fcb_t *fcb = getFCB(); return fcb->pos; } bool ThreadFile::operator++(void) { off_t eof; fcb_t *fcb = getFCB(); fcb->pos += fcb->len; enterMutex(); #ifdef WIN32 eof = SetFilePointer(fd, 0l, NULL, FILE_END); #else eof = lseek(fd, 0l, SEEK_END); #endif leaveMutex(); if(fcb->pos >= eof) { fcb->pos = eof; return true; } return false; } bool ThreadFile::operator--(void) { fcb_t *fcb = getFCB(); fcb->pos -= fcb->len; if(fcb->pos <= 0) { fcb->pos = 0; return true; } return false; } SharedFile::SharedFile(const char *path) : RandomFile(path) { fcb.address = NULL; fcb.len = 0; fcb.pos = 0; open(path); } SharedFile::SharedFile(const SharedFile &sh) : RandomFile(sh) { } SharedFile::~SharedFile() { final(); } SharedFile::Error SharedFile::open(const char *path) { #ifdef WIN32 if(fd != INVALID_HANDLE_VALUE) #else if(fd > -1) #endif final(); if(path != pathname) { if(pathname) delString(pathname); pathname = newString(path); } flags.initial = false; #ifdef WIN32 fd = CreateFile(pathname, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); if(fd == INVALID_HANDLE_VALUE) { flags.initial = true; fd = CreateFile(pathname, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); } if(fd == INVALID_HANDLE_VALUE) return errOpenFailed; return errSuccess; #else fd = ::open(pathname, O_RDWR); if(fd < 0) { flags.initial = true; fd = ::open(pathname, O_CREAT | O_RDWR | O_TRUNC, (int)attrPrivate); } if(fd < 0) return error(errOpenFailed); #ifdef LOCK_SH if(flock(fd, LOCK_SH | LOCK_NB)) { close(fd); fd = -1; return error(errOpenInUse); } #endif return errSuccess; #endif // WIN32 } SharedFile::Error SharedFile::fetch(caddr_t address, ccxx_size_t len, off_t pos) { #ifdef WIN32 if(fd == INVALID_HANDLE_VALUE) #else if(fd < 0) #endif return errNotOpened; enterMutex(); if(address) fcb.address = address; if(len) fcb.len = len; if(pos != -1) fcb.pos = pos; #ifdef WIN32 Thread::Cancel save = Thread::enterCancel(); OVERLAPPED over; SetFilePointer(fd, fcb.pos, NULL, FILE_BEGIN); over.hEvent = 0; over.Offset = fcb.pos; over.OffsetHigh = 0; LockFileEx(fd, LOCKFILE_EXCLUSIVE_LOCK, 0, fcb.len, 0, &over); DWORD count; if(!ReadFile(fd, fcb.address, fcb.len, &count, NULL)) { Thread::exitCancel(save); leaveMutex(); return errReadFailure; } Thread::exitCancel(save); leaveMutex(); if(count < fcb.len) return errReadIncomplete; return errSuccess; #else lseek(fd, fcb.pos, SEEK_SET); if(lockf(fd, F_LOCK, fcb.len)) { leaveMutex(); return errLockFailure; } int io = ::read(fd, fcb.address, fcb.len); leaveMutex(); if((size_t) io == fcb.len) return errSuccess; if(io > -1) return errReadIncomplete; switch(errno) { case EINTR: return errReadInterrupted; default: return errReadFailure; } #endif } #ifndef WIN32 SharedFile::Error SharedFile::clear(ccxx_size_t len, off_t pos) { if(fd < 0) return errNotOpened; enterMutex(); if(len) fcb.len = len; if(pos != -1) fcb.pos = pos; lseek(fd, fcb.pos, SEEK_SET); if(lockf(fd, F_ULOCK, fcb.len)) { leaveMutex(); return errLockFailure; } leaveMutex(); return errSuccess; } #endif // ndef WIN32 SharedFile::Error SharedFile::update(caddr_t address, ccxx_size_t len, off_t pos) { #ifdef WIN32 if(fd == INVALID_HANDLE_VALUE) #else if(fd < 0) #endif return errNotOpened; enterMutex(); if(address) fcb.address = address; if(len) fcb.len = len; if(pos != -1) fcb.pos = pos; #ifdef WIN32 Thread::Cancel save = Thread::enterCancel(); OVERLAPPED over; SetFilePointer(fd, fcb.pos, NULL, FILE_BEGIN); over.hEvent = 0; over.Offset = pos; over.OffsetHigh = 0; DWORD count; if(!WriteFile(fd, fcb.address, fcb.len, &count, NULL)) { SetFilePointer(fd, fcb.pos, NULL, FILE_CURRENT); UnlockFileEx(fd, 0, len, 0, &over); Thread::exitCancel(save); leaveMutex(); return errWriteFailure; } SetFilePointer(fd, fcb.pos, NULL, FILE_CURRENT); UnlockFileEx(fd, 0, len, 0, &over); Thread::exitCancel(save); leaveMutex(); if(count < fcb.len) return errWriteIncomplete; return errSuccess; #else lseek(fd, fcb.pos, SEEK_SET); int io = ::write(fd, fcb.address, fcb.len); if(lockf(fd, F_ULOCK, fcb.len)) { leaveMutex(); return errLockFailure; } leaveMutex(); if((size_t) io == fcb.len) return errSuccess; if(io > -1) return errWriteIncomplete; switch(errno) { case EINTR: return errWriteInterrupted; default: return errWriteFailure; } #endif // WIN32 } SharedFile::Error SharedFile::append(caddr_t address, ccxx_size_t len) { #ifdef WIN32 if(fd == INVALID_HANDLE_VALUE) #else if(fd < 0) #endif return errNotOpened; enterMutex(); if(address) fcb.address = address; if(len) fcb.len = len; #ifdef WIN32 Thread::Cancel save = Thread::enterCancel(); fcb.pos = SetFilePointer(fd, 0l, NULL, FILE_END); OVERLAPPED over; over.hEvent = 0; over.Offset = fcb.pos; over.OffsetHigh = 0; LONG eof = fcb.pos; LockFileEx(fd, LOCKFILE_EXCLUSIVE_LOCK, 0, 0x7fffffff, 0, &over); fcb.pos = SetFilePointer(fd, 0l, NULL, FILE_END); DWORD count; if(!WriteFile(fd, fcb.address, fcb.len, &count, NULL)) { SetFilePointer(fd, eof, NULL, FILE_CURRENT); Thread::exitCancel(save); UnlockFileEx(fd, 0, 0x7fffffff, 0, &over); Thread::exitCancel(save); leaveMutex(); return errWriteFailure; } SetFilePointer(fd, eof, NULL, FILE_CURRENT); UnlockFileEx(fd, 0, 0x7fffffff, 0, &over); Thread::exitCancel(save); leaveMutex(); if(count < fcb.len) return errWriteIncomplete; return errSuccess; #else fcb.pos = lseek(fd, 0l, SEEK_END); if(lockf(fd, F_LOCK, -1)) { leaveMutex(); return errLockFailure; } fcb.pos = lseek(fd, 0l, SEEK_END); int io = ::write(fd, fcb.address, fcb.len); lseek(fd, fcb.pos, SEEK_SET); if(lockf(fd, F_ULOCK, -1)) { leaveMutex(); return errLockFailure; } leaveMutex(); if((size_t) io == fcb.len) return errSuccess; if(io > -1) return errWriteIncomplete; switch(errno) { case EINTR: return errWriteInterrupted; default: return errWriteFailure; } #endif // WIN32 } off_t SharedFile::getPosition(void) { return fcb.pos; } bool SharedFile::operator++(void) { off_t eof; enterMutex(); fcb.pos += fcb.len; #ifdef WIN32 eof = SetFilePointer(fd, 0l, NULL, FILE_END); #else eof = lseek(fd, 0l, SEEK_END); #endif if(fcb.pos >= eof) { fcb.pos = eof; leaveMutex(); return true; } leaveMutex(); return false; } bool SharedFile::operator--(void) { enterMutex(); fcb.pos -= fcb.len; if(fcb.pos <= 0) { fcb.pos = 0; leaveMutex(); return true; } leaveMutex(); return false; } size_t MappedFile::pageAligned(size_t size) { size_t pages = size / Process::getPageSize(); if(size % Process::getPageSize()) ++pages; return pages * Process::getPageSize(); } #ifdef WIN32 static void makemapname(const char *source, char *target) { unsigned count = 60; while(*source && count--) { if(*source == '/' || *source == '\\') *(target++) = '_'; else *(target++) = toupper(*source); ++source; } *target = 0; } MappedFile::MappedFile(const char *fname, Access mode, size_t size) : RandomFile(fname) { DWORD share, page; map = INVALID_HANDLE_VALUE; fcb.address = NULL; switch(mode) { case accessReadOnly: share = FILE_SHARE_READ; page = PAGE_READONLY; prot = FILE_MAP_READ; break; case accessWriteOnly: share = FILE_SHARE_WRITE; page = PAGE_WRITECOPY; prot = FILE_MAP_COPY; break; case accessReadWrite: share = FILE_SHARE_READ|FILE_SHARE_WRITE; page = PAGE_READWRITE; prot = FILE_MAP_WRITE; } fd = CreateFile(pathname, mode, share, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); if(fd == INVALID_HANDLE_VALUE) { error(errOpenFailed); return; } SetFilePointer(fd, (LONG)size, 0, FILE_BEGIN); SetEndOfFile(fd); makemapname(fname, mapname); map = CreateFileMapping(fd, NULL, page, 0, 0, mapname); if(!map) error(errMapFailed); fcb.address = MapViewOfFile(map, prot, 0, 0, size); fcb.len = (ccxx_size_t)size; fcb.pos = 0; if(!fcb.address) error(errMapFailed); } MappedFile::MappedFile(const char *fname, Access mode) : RandomFile(fname) { DWORD share, page; map = INVALID_HANDLE_VALUE; fcb.address = NULL; switch(mode) { case accessReadOnly: share = FILE_SHARE_READ; page = PAGE_READONLY; prot = FILE_MAP_READ; break; case accessWriteOnly: share = FILE_SHARE_WRITE; page = PAGE_WRITECOPY; prot = FILE_MAP_COPY; break; case accessReadWrite: share = FILE_SHARE_READ|FILE_SHARE_WRITE; page = PAGE_READWRITE; prot = FILE_MAP_WRITE; } fd = CreateFile(pathname, mode, share, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); if(fd == INVALID_HANDLE_VALUE) { error(errOpenFailed); return; } makemapname(fname, mapname); map = CreateFileMapping(fd, NULL, page, 0, 0, mapname); if(!map) error(errMapFailed); } MappedFile::MappedFile(const char *fname, pos_t pos, size_t len, Access mode) : RandomFile(fname) { DWORD share, page; map = INVALID_HANDLE_VALUE; fcb.address = NULL; switch(mode) { case accessReadOnly: share = FILE_SHARE_READ; page = PAGE_READONLY; prot = FILE_MAP_READ; break; case accessWriteOnly: share = FILE_SHARE_WRITE; page = PAGE_WRITECOPY; prot = FILE_MAP_COPY; break; case accessReadWrite: share = FILE_SHARE_READ|FILE_SHARE_WRITE; page = PAGE_READWRITE; prot = FILE_MAP_WRITE; } fd = CreateFile(pathname, mode, share, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); if(fd == INVALID_HANDLE_VALUE) { error(errOpenFailed); return; } makemapname(fname, mapname); map = CreateFileMapping(fd, NULL, page, 0, 0, mapname); if(!map) { error(errMapFailed); return; } fcb.address = MapViewOfFile(map, prot, 0, pos, len); fcb.len = (ccxx_size_t)len; fcb.pos = pos; if(!fcb.address) error(errMapFailed); } MappedFile::~MappedFile() { if(fcb.address) { unlock(); UnmapViewOfFile(fcb.address); } if(map != INVALID_HANDLE_VALUE) CloseHandle(map); final(); } void MappedFile::sync(void) { } void MappedFile::sync(caddr_t address, size_t len) { } void MappedFile::release(caddr_t address, size_t len) { if(fcb.address) { unlock(); UnmapViewOfFile(fcb.address); } fcb.address = NULL; } caddr_t MappedFile::fetch(off_t pos, size_t len) { if(fcb.address) { unlock(); UnmapViewOfFile(fcb.address); } fcb.address = MapViewOfFile(map, prot, 0, pos, len); fcb.len = (ccxx_size_t)len; fcb.pos = pos; if(!fcb.address) error(errMapFailed); return fcb.address; } void MappedFile::update(size_t offset, size_t len) { } void MappedFile::update(caddr_t address, size_t len) { } bool MappedFile::lock(void) { unlock(); if(VirtualLock(fcb.address, fcb.len)) fcb.locked = true; return fcb.locked; } void MappedFile::unlock(void) { if(!fcb.address) fcb.locked = false; if(!fcb.locked) return; VirtualUnlock(fcb.address, fcb.len); fcb.locked = false; } #else #ifdef HAVE_MLOCK MappedFile::MappedFile(const char *fname, Access mode) : RandomFile(fname) { fd = open(fname, (int)mode); if(fd < 0 && mode != accessReadOnly) fd = ::open(pathname, O_CREAT | O_RDWR | O_TRUNC, (int)attrPrivate); if(fd < 0) { error(errOpenFailed); return; } switch(mode) { case O_RDONLY: prot = PROT_READ; break; case O_WRONLY: prot = PROT_WRITE; break; default: prot = PROT_READ | PROT_WRITE; } } MappedFile::MappedFile(const char *fname, Access mode, size_t size) : RandomFile(fname) { fd = open(fname, (int)mode | O_CREAT, 0660); if(fd < 0) { error(errOpenFailed); return; } switch(mode) { case O_RDONLY: prot = PROT_READ; break; case O_WRONLY: prot = PROT_WRITE; break; default: prot = PROT_READ | PROT_WRITE; } enterMutex(); lseek(fd, size, SEEK_SET); fcb.address = (caddr_t)mmap(NULL, size, prot, MAP_SHARED, fd, 0); fcb.len = size; fcb.pos = 0; leaveMutex(); if((caddr_t)(fcb.address) == (caddr_t)(MAP_FAILED)) { close(fd); fd = -1; error(errMapFailed); } } MappedFile::MappedFile(const char *fname, pos_t pos, size_t len, Access mode) : RandomFile(fname) { fd = open(fname, (int)mode); if(fd < 0) { error(errOpenFailed); return; } switch(mode) { case O_RDONLY: prot = PROT_READ; break; case O_WRONLY: prot = PROT_WRITE; break; default: prot = PROT_READ | PROT_WRITE; } enterMutex(); lseek(fd, pos + len, SEEK_SET); fcb.address = (caddr_t)mmap(NULL, len, prot, MAP_SHARED, fd, pos); fcb.len = len; fcb.pos = pos; leaveMutex(); if((caddr_t)(fcb.address) == (caddr_t)(MAP_FAILED)) { close(fd); fd = -1; error(errMapFailed); } } MappedFile::~MappedFile() { unlock(); final(); } void MappedFile::sync(void) { msync(fcb.address, fcb.len, MS_SYNC); } void MappedFile::release(caddr_t address, size_t len) { enterMutex(); if(address) fcb.address = address; if(len) fcb.len = len; if(fcb.locked) unlock(); munmap(fcb.address, fcb.len); leaveMutex(); } caddr_t MappedFile::fetch(off_t pos, size_t len) { enterMutex(); unlock(); fcb.len = len; fcb.pos = pos; lseek(fd, fcb.pos + len, SEEK_SET); fcb.address = (caddr_t)mmap(NULL, len, prot, MAP_SHARED, fd, pos); leaveMutex(); return fcb.address; } bool MappedFile::lock(void) { unlock(); if(!mlock(fcb.address, fcb.len)) fcb.locked = true; return fcb.locked; } void MappedFile::unlock(void) { if(!fcb.address) fcb.locked = false; if(!fcb.locked) return; munlock(fcb.address, fcb.len); fcb.locked = false; } void MappedFile::update(size_t offset, size_t len) { int mode = MS_ASYNC; caddr_t address; if(flags.immediate) mode = MS_SYNC; enterMutex(); address = fcb.address; address += offset; if(!len) len = fcb.len; leaveMutex(); msync(address, len, mode); } void MappedFile::update(caddr_t address, size_t len) { int mode = MS_ASYNC; if(flags.immediate) mode = MS_SYNC; msync(address, len, mode); } #endif #endif // ndef WIN32 #ifdef WIN32 #ifndef SECS_BETWEEN_EPOCHS #define SECS_BETWEEN_EPOCHS 11644473600LL #endif #ifndef SECS_TO_100NS #define SECS_TO_100NS 10000000LL #endif #endif time_t lastAccessed(const char *path) { #ifdef WIN32 __int64 ts; WIN32_FILE_ATTRIBUTE_DATA ino; if(!GetFileAttributesEx(path, GetFileExInfoStandard, &ino)) return 0; ts = ((__int64)ino.ftLastAccessTime.dwHighDateTime << 32) + ino.ftLastAccessTime.dwLowDateTime; ts -= (SECS_BETWEEN_EPOCHS * SECS_TO_100NS); ts /= SECS_TO_100NS; return(time_t)ts; #else struct stat ino; if(stat(path, &ino)) return 0; return ino.st_atime; #endif } time_t lastModified(const char *path) { #ifdef WIN32 __int64 ts; WIN32_FILE_ATTRIBUTE_DATA ino; if(!GetFileAttributesEx(path, GetFileExInfoStandard, &ino)) return 0; ts = ((__int64)ino.ftLastWriteTime.dwHighDateTime << 32) + ino.ftLastWriteTime.dwLowDateTime; ts -= (SECS_BETWEEN_EPOCHS * SECS_TO_100NS); ts /= SECS_TO_100NS; return(time_t)ts; #else struct stat ino; if(stat(path, &ino)) return 0; return ino.st_mtime; #endif } bool isDir(const char *path) { #ifdef WIN32 DWORD attr = GetFileAttributes(path); if(attr == (DWORD)~0l) return false; if(attr & FILE_ATTRIBUTE_DIRECTORY) return true; return false; #else struct stat ino; if(stat(path, &ino)) return false; if(S_ISDIR(ino.st_mode)) return true; return false; #endif // WIN32 } bool isFile(const char *path) { #ifdef WIN32 DWORD attr = GetFileAttributes(path); if(attr == (DWORD)~0l) return false; if(attr & FILE_ATTRIBUTE_DIRECTORY) return false; return true; #else struct stat ino; if(stat(path, &ino)) return false; if(S_ISREG(ino.st_mode)) return true; return false; #endif // WIN32 } #ifndef WIN32 // the Win32 version is given in line in the header bool isDevice(const char *path) { struct stat ino; if(stat(path, &ino)) return false; if(S_ISCHR(ino.st_mode)) return true; return false; } #endif bool canAccess(const char *path) { #ifdef WIN32 DWORD attr = GetFileAttributes(path); if(attr == (DWORD)~0l) return false; if(attr & FILE_ATTRIBUTE_SYSTEM) return false; if(attr & FILE_ATTRIBUTE_HIDDEN) return false; return true; #else if(!access(path, R_OK)) return true; return false; #endif } bool canModify(const char *path) { #ifdef WIN32 DWORD attr = GetFileAttributes(path); if(!canAccess(path)) return false; if(attr & FILE_ATTRIBUTE_READONLY) return false; if(attr & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_NORMAL)) return true; return false; #else if(!access(path, W_OK | R_OK)) return true; return false; #endif } #ifdef WIN32 const char *File::getExtension(const char *path) { const char *cp = strrchr(path, '\\'); if(!cp) cp = strrchr(path, '/'); if(!cp) cp = strrchr(path, ':'); if(cp) ++cp; else cp = path; if(*cp == '.') return ""; cp = strrchr(cp, '.'); if(!cp) cp = ""; return cp; } const char *File::getFilename(const char *path) { const char *cp = strrchr(path, '\\'); if(cp) return ++cp; cp = strrchr(path, '/'); if(cp) return ++cp; cp = strrchr(path, ':'); if(cp) ++cp; return path; } char *File::getFilename(const char *path, char *buffer, size_t size) { const char *cp = strrchr(path, '\\'); if(!cp) cp = strrchr(path, '/'); if(!cp) cp = strrchr(path, ':'); if(cp) snprintf(buffer, size, "%s", ++cp); else snprintf(buffer, size, "%s", path); return buffer; } char *File::getDirname(const char *path, char *buffer, size_t size) { size_t len; const char *cp = strrchr(path, '\\'); snprintf(buffer, size, "%s", path); if(!cp) cp = strrchr(path, '/'); if(!cp) cp = strrchr(path, ':'); if(!cp) return buffer; if(cp) len = cp - path; if(len >= size) len = size - 1; buffer[len] = 0; return buffer; } #else const char *File::getExtension(const char *path) { const char *cp = strrchr(path, '/'); if(cp) ++cp; else cp = path; if(*cp == '.') return ""; cp = strrchr(cp, '.'); if(cp) return cp; return ""; } char *File::getDirname(const char *path, char *buffer, size_t size) { unsigned len; const char *cp = strrchr(path, '/'); snprintf(buffer, size, "%s", path); if(!cp) return buffer; if(cp) len = cp - path; if(len >= size) len = size - 1; buffer[len] = 0; return buffer; } const char *File::getFilename(const char *path) { const char *cp = strrchr(path, '/'); if(cp) return ++cp; return path; } char *File::getFilename(const char *path, char *buffer, size_t size) { const char *cp = strrchr(path, '/'); if(cp) snprintf(buffer, size, "%s", ++cp); else snprintf(buffer, size, "%s", path); return buffer; } #endif #ifdef HAVE_REALPATH char *File::getRealpath(const char *path, char *buffer, size_t size) { char temp[PATH_MAX]; setString(buffer, size, "."); if(!realpath(path, temp)) return NULL; if(strlen(temp) >= size) return NULL; setString(buffer, size, temp); return buffer; } #else #ifdef WIN323 static char *getFile(char *path) { char *cp = strchr(path, '\\'); if(!cp) cp = strchr(path, '/'); if(!cp) cp = strchr(path, ':'); return cp; } #else static char *getFile(char *path) { return strchr(path, '/'); } #endif char *File::getRealpath(const char *path, char *buffer, size_t size) { if(size > PATH_MAX) size = PATH_MAX; unsigned symlinks = 0; #if !defined(DYNAMCIC_LOCAL_ARRAYS) char left[PATH_MAX]; #else char left[size]; #endif size_t left_len, buffer_len; #ifdef WIN32 if(path[1] == ':') #else if(path[0] == '/') #endif { buffer[0] = '/'; buffer[1] = 0; if(!path[1]) return buffer; buffer_len = 1; snprintf(left, size, "%s", path + 1); left_len = strlen(left); } else { if(!Dir::getPrefix(buffer, size)) { snprintf(buffer, size, "%s", "."); return NULL; } buffer_len = strlen(buffer); snprintf(left, size, "%s", path); left_len = strlen(left); } if(left_len >= size || buffer_len >= size) return NULL; while(left_len > 0) { #ifdef HAVE_LSTAT struct stat ino; #endif #if !defined(DYNAMIC_LOCAL_ARRAYS) char next_token[PATH_MAX]; #else char next_token[size]; #endif char *p; const char *s = (p = getFile(left)) ? p : left + left_len; memmove(next_token, left, s - left); left_len -= s - left; if(p != NULL) memmove(left, s + 1, left_len + 1); next_token[s - left] = 0; if(buffer[buffer_len - 1] != '/') { if(buffer_len +1 >= size) return NULL; buffer[buffer_len++] = '/'; buffer[buffer_len] = 0; } if(!next_token[0]) continue; else if(!strcmp(next_token, ".")) continue; else if(!strcmp(next_token, "..")) { if(buffer_len > 1) { char *q; buffer[buffer_len - 1] = 0; #ifdef WIN32 q = strrchr(buffer, '\\'); if(!q) q = strrchr(buffer, '/'); if(!q) q = strchr(buffer, ':'); #else q = strrchr(buffer, '/'); #endif *q = 0; buffer_len = q - buffer; } continue; } snprintf(next_token, size, "%s", buffer); buffer_len = strlen(buffer); if(buffer_len >= size) return NULL; #ifndef HAVE_LSTAT if(!isFile(buffer) && !isDir(buffer)) return buffer; continue; #else if(lstat(buffer, &ino) < 0) { if(errno == ENOENT && !p) return buffer; return NULL; } if((ino.st_mode & S_IFLNK) == S_IFLNK) { char symlink[size]; int slen; if (symlinks++ > MAXSYMLINKS) return NULL; slen = readlink(buffer, symlink, size); if (slen < 0) return NULL; symlink[slen] = 0; if (symlink[0] == '/') { buffer[1] = 0; buffer_len = 1; } else if (buffer_len > 1) { char *q; buffer[buffer_len - 1] = 0; q = strrchr(buffer, '/'); *q = 0; buffer_len = q - buffer; } if (symlink[slen - 1] != '/' && p) { if (slen >= size) return NULL; symlink[slen] = '/'; symlink[slen + 1] = 0; } if(p) { snprintf(symlink, size, "%s", left); left_len = strlen(symlink); } if(left_len >= size) return NULL; snprintf(left, size, "%s", symlink); left_len = strlen(left); } #endif } #ifdef WIN32 if(buffer_len > 1 && buffer[buffer_len - 1] == '\\') buffer[buffer_len - 1] = 0; else if(buffer_len > 1 && buffer[buffer_len - 1] == '/') buffer[buffer_len - 1] = 0; #else if(buffer_len > 1 && buffer[buffer_len - 1] == '/') buffer[buffer_len - 1] = 0; #endif return buffer; } #endif #ifdef CCXX_NAMESPACES } #endif /** EMACS ** * Local variables: * mode: c++ * c-basic-offset: 8 * End: */