1 // ------------------------------------------------------------------------
2 // eca-fileio-mmap.cpp: mmap based file-I/O and buffering routines.
3 // Copyright (C) 1999-2002,2009 Kai Vehmanen
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 // ------------------------------------------------------------------------
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <cstdio>
25 #include <cstring> /* memcpy */
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <errno.h>
29 #ifdef HAVE_SYS_MMAN_H
30 #include <sys/mman.h>
31 #endif
32 #include <sys/stat.h>
33 #include <sys/types.h>
34
35 #include "eca-fileio.h"
36 #include "eca-fileio-mmap.h"
37
ECA_FILE_IO_MMAP(void)38 ECA_FILE_IO_MMAP::ECA_FILE_IO_MMAP(void) { }
~ECA_FILE_IO_MMAP(void)39 ECA_FILE_IO_MMAP::~ECA_FILE_IO_MMAP(void) { }
40
open_file(const std::string & fname,const std::string & fmode)41 void ECA_FILE_IO_MMAP::open_file(const std::string& fname,
42 const std::string& fmode)
43 {
44 #ifdef HAVE_MMAP
45 int openflags = O_RDWR;
46 int mmapflags = PROT_READ | PROT_WRITE;
47 fname_rep = fname;
48
49 if (fmode == "rb") {
50 openflags = O_RDONLY;
51 mmapflags = PROT_READ;
52 }
53 else if (fmode == "wb") {
54 openflags = O_WRONLY;
55 mmapflags = PROT_WRITE;
56 }
57
58 fd_rep = ::open(fname.c_str(), openflags);
59 if (!fd_rep) {
60 file_ready_rep = false;
61 mode_rep = "";
62 }
63 else {
64 file_ready_rep = true;
65 file_ended_rep = false;
66 mode_rep = fmode;
67 fposition_rep = 0;
68 flength_rep = get_file_length();
69 // cerr << fname_rep << ": mmaping region from 0 to " <<
70 // flength_rep << "." << endl;
71 buffer_repp = (caddr_t)::mmap(0,
72 flength_rep,
73 mmapflags,
74 MAP_SHARED,
75 fd_rep,
76 0);
77
78 if (buffer_repp == MAP_FAILED) {
79 file_ready_rep = false;
80 mode_rep = "";
81 }
82 }
83 #else /* HAVE_MMAP */
84 file_ready_rep = false;
85 mode_rep = "";
86 #endif
87 }
88
close_file(void)89 void ECA_FILE_IO_MMAP::close_file(void) {
90 // cerr << fname_rep << ": munmaping region." << endl;
91 #ifdef HAVE_MMAP
92 ::munmap(buffer_repp, flength_rep);
93 ::close(fd_rep);
94 #endif
95 }
96
read_to_buffer(void * obuf,off_t bytes)97 void ECA_FILE_IO_MMAP::read_to_buffer(void* obuf, off_t bytes) {
98 if (is_file_ready() == false) {
99 bytes_rep = 0;
100 file_ended_rep = true;
101 return;
102 }
103
104 if (fposition_rep + bytes > flength_rep)
105 bytes = flength_rep - fposition_rep;
106
107 // cerr << fname_rep << ": mmap read " << fposition_rep << " -> ";
108 std::memcpy(obuf, buffer_repp + fposition_rep, bytes);
109 // cerr << fposition_rep + bytes << "." << endl;
110 set_file_position(fposition_rep + bytes, false);
111 bytes_rep = bytes;
112 }
113
write_from_buffer(void * obuf,off_t bytes)114 void ECA_FILE_IO_MMAP::write_from_buffer(void* obuf, off_t bytes) {
115 if (is_file_ready() == false) {
116 bytes_rep = 0;
117 file_ended_rep = true;
118 return;
119 }
120
121 if (fposition_rep + bytes > flength_rep)
122 bytes = flength_rep - fposition_rep;
123
124 std::memcpy(buffer_repp + fposition_rep, obuf, bytes);
125 set_file_position(fposition_rep + bytes, false);
126 bytes_rep = bytes;
127 }
128
file_bytes_processed(void) const129 off_t ECA_FILE_IO_MMAP::file_bytes_processed(void) const { return(bytes_rep); }
is_file_ready(void) const130 bool ECA_FILE_IO_MMAP::is_file_ready(void) const { return(file_ready_rep); }
is_file_ended(void) const131 bool ECA_FILE_IO_MMAP::is_file_ended(void) const { return(file_ended_rep); }
is_file_error(void) const132 bool ECA_FILE_IO_MMAP::is_file_error(void) const { return(!file_ready_rep && !file_ended_rep); }
133
set_file_position(off_t newpos,bool seek)134 void ECA_FILE_IO_MMAP::set_file_position(off_t newpos, bool seek) {
135 fposition_rep = newpos;
136 if (fposition_rep >= flength_rep) {
137 fposition_rep = flength_rep;
138 file_ready_rep = false;
139 file_ended_rep = true;
140 }
141 else {
142 file_ready_rep = true;
143 file_ended_rep = false;
144 }
145 }
146
set_file_position_advance(off_t fw)147 void ECA_FILE_IO_MMAP::set_file_position_advance(off_t fw) {
148 set_file_position(fposition_rep + fw, false);
149 }
150
set_file_position_end(void)151 void ECA_FILE_IO_MMAP::set_file_position_end(void) {
152 fposition_rep = get_file_length();
153 }
154
get_file_position(void) const155 off_t ECA_FILE_IO_MMAP::get_file_position(void) const { return(fposition_rep); }
156
get_file_length(void) const157 off_t ECA_FILE_IO_MMAP::get_file_length(void) const {
158 struct stat stattemp;
159 fstat(fd_rep, &stattemp);
160 return((off_t)stattemp.st_size);
161 }
162