/* -*-Mode: C++;-*-
* PRCS - The Project Revision Control System
* Copyright (C) 1997 Josh MacDonald
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: memseg.cc 1.15.1.2.1.6 Sun, 17 Sep 2000 17:56:26 -0700 jmacd $
*/
extern "C" {
#include <fcntl.h>
}
#include "prcs.h"
extern "C" {
#include <unistd.h>
#if HAVE_MMAP
#include <sys/mman.h>
#endif
}
#include "memseg.h"
#include "system.h"
const int default_segment_size = 1 << 14;
PrVoidError MemorySegment::unmap()
{
bool close_ok = true;
#if HAVE_MMAP
if(_mapped_segment)
munmap(_segment, _length);
#endif
if(_own_fd && _fd >= 0) {
if(close(_fd) < 0)
close_ok = false;
}
_segment = 0;
_length = -1;
#if HAVE_MMAP
_mapped_segment = 0;
#endif
/* keep the _memory_segment and _allocated for the next use */
_fd = -1;
_own_fd = false;
if(close_ok) {
return NoError;
} else {
pthrow prcserror << "Close " << squote (_desc) << " failed: " << perror;
}
}
MemorySegment::~MemorySegment()
{
unmap();
if(_memory_segment)
free(_memory_segment);
}
void MemorySegment::clear_segment()
{
unmap();
_length = 0;
}
void MemorySegment::append_segment(const char* s, int len)
{
expand_memory_segment(len + _length);
memcpy(_memory_segment + _length, s, len);
_segment = _memory_segment;
_length += len;
}
PrVoidError MemorySegment::map_file(const char* filename)
{
struct stat statbuf;
int open_flags;
_desc = filename;
unmap();
if(_open_write) {
open_flags = O_RDWR;
} else {
open_flags = O_RDONLY;
}
_own_fd = true;
If_fail(_fd << Err_open(filename, open_flags))
pthrow prcserror << "Open " << squote (_desc) << " failed" << perror;
If_fail(Err_fstat(_fd, &statbuf))
pthrow prcserror << "Stat " << squote (_desc) << " failed" << perror;
_length = statbuf.st_size;
#if HAVE_MMAP
return init_mapped_segment();
#else
return init_memory_segment();
#endif
}
PrVoidError MemorySegment::map_file(const char* desc, int fd0, int length0)
{
struct stat statbuf;
_desc = desc;
unmap();
_fd = fd0;
If_fail(Err_fstat(_fd, &statbuf))
pthrow prcserror << "Fstat " << squote (_desc) << " failed" << perror;
if(S_ISREG(statbuf.st_mode) && !_force_read) {
_length = statbuf.st_size;
#if HAVE_MMAP
return init_mapped_segment();
#else
return init_memory_segment();
#endif
} else {
if(length0 >= 0)
_length = length0;
return init_memory_segment();
}
}
#if HAVE_MMAP
PrVoidError MemorySegment::init_mapped_segment()
{
if((_mapped_segment = (caddr_t)mmap(0, _length, PROT_READ, MAP_PRIVATE, _fd, 0)) < 0)
pthrow prcserror << "Mmap " << squote (_desc) << " failed" << perror;
_segment = _mapped_segment;
return NoError;
}
#endif
PrVoidError MemorySegment::init_memory_segment()
{
if(_length > 0) {
int n_read, total_read = 0;
char* read_ptr;
expand_memory_segment(_length);
read_ptr = _memory_segment;
while(total_read < _length) {
If_fail(n_read << Err_read(_fd, read_ptr, _length - total_read))
pthrow prcserror << "Read " << squote (_desc) << " failed" << perror;
if (n_read == 0) {
pthrow prcserror << "File " << squote (_desc) << " too short: expected " << _length << "; recieved " << total_read << prcsendl;
}
total_read += n_read;
read_ptr += n_read;
}
_segment = _memory_segment;
return NoError;
} else {
expand_memory_segment(default_segment_size);
_length = 0;
while(true) {
while(_length < _allocated) {
int n_read;
If_fail(n_read << Err_read(_fd, _memory_segment + _length, _allocated - _length))
pthrow prcserror << "Read " << squote (_desc) << " failed" << perror;
_length += n_read;
if (n_read == 0) {
_segment = _memory_segment;
return NoError;
}
}
_memory_segment = (char*)EXPANDVEC(_memory_segment, _allocated, _allocated);
_allocated *= 2;
}
}
}
void MemorySegment::expand_memory_segment(int new_length)
{
if(new_length < _allocated)
return;
if(!_memory_segment) {
_allocated = default_segment_size;
while(_allocated < new_length)
_allocated <<= 1;
_memory_segment = NEWVEC(char, _allocated);
} else {
int old_size = _allocated;
while(_allocated < new_length)
_allocated <<= 1;
_memory_segment = (char*)EXPANDVEC(_memory_segment, old_size, _allocated - old_size);
}
_segment = _memory_segment;
}
MemorySegment::MemorySegment(bool force_read, bool write)
:_fd(-1), _own_fd(false), _open_write(write),
_force_read(force_read), _segment(0), _length(0),
_allocated(0), _memory_segment(0)
#if HAVE_MMAP
, _mapped_segment(0)
#endif
{ }
const char* MemorySegment::segment() const { return _segment; }
char* MemorySegment::wr_segment() const { return _segment; }
int MemorySegment::length() const { return _length; }
int MemorySegment::fd() const { return _fd; }
syntax highlighted by Code2HTML, v. 0.9.1