/* -*-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 } #include "prcs.h" extern "C" { #include #if HAVE_MMAP #include #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; }