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