Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
cfile.hpp
Go to the documentation of this file.
1#pragma once
2#include <fc/filesystem.hpp>
4#include <cstdio>
5#include <ios>
6#include <fcntl.h>
7#include <sys/stat.h>
8
9#include <boost/interprocess/file_mapping.hpp>
10
11#ifndef _WIN32
12#define FC_FOPEN(p, m) fopen(p, m)
13#else
14#define FC_CAT(s1, s2) s1 ## s2
15#define FC_PREL(s) FC_CAT(L, s)
16#define FC_FOPEN(p, m) _wfopen(p, FC_PREL(m))
17#endif
18
19namespace fc {
20
21namespace detail {
22 using unique_file = std::unique_ptr<FILE, decltype( &fclose )>;
23}
24
26
31class cfile {
32public:
34 : _file(nullptr, &fclose)
35 {}
36
37 void set_file_path( fc::path file_path ) {
38 _file_path = std::move( file_path );
39 }
40
42 return _file_path;
43 }
44
45 bool is_open() const { return _open; }
46
47 auto fileno() const {
48 int fd = ::fileno(_file.get());
49 if( -1 == fd ) {
50 throw std::ios_base::failure( "cfile: " + _file_path.generic_string() +
51 " unable to convert file pointer to file descriptor, error: " +
52 std::to_string( errno ) );
53 }
54 return fd;
55 }
56
57 static constexpr const char* create_or_update_rw_mode = "ab+";
58 static constexpr const char* update_rw_mode = "rb+";
59 static constexpr const char* truncate_rw_mode = "wb+";
60
65 void open( const char* mode ) {
66 _file.reset( FC_FOPEN( _file_path.generic_string().c_str(), mode ) );
67 if( !_file ) {
68 throw std::ios_base::failure( "cfile unable to open: " + _file_path.generic_string() + " in mode: " + std::string( mode ) );
69 }
70#ifndef _WIN32
71 struct stat st;
72 _file_blk_size = 4096;
73 if( fstat(fileno(), &st) == 0 )
74 _file_blk_size = st.st_blksize;
75#endif
76 _open = true;
77 }
78
79 size_t tellp() const {
80 long result = ftell( _file.get() );
81 if (result == -1)
82 throw std::ios_base::failure("cfile: " + get_file_path().generic_string() +
83 " unable to get the current position of the file, error: " + std::to_string( errno ));
84 return static_cast<size_t>(result);
85 }
86
87 void seek( long loc ) {
88 if( 0 != fseek( _file.get(), loc, SEEK_SET ) ) {
89 int err = ferror(_file.get());
90 throw std::ios_base::failure( "cfile: " + _file_path.generic_string() +
91 " unable to SEEK_SET to: " + std::to_string(loc) +
92 ", ferror: " + std::to_string(err) );
93 }
94 }
95
96 void seek_end( long loc ) {
97 if( 0 != fseek( _file.get(), loc, SEEK_END ) ) {
98 int err = ferror(_file.get());
99 throw std::ios_base::failure( "cfile: " + _file_path.generic_string() +
100 " unable to SEEK_END to: " + std::to_string(loc) +
101 ", ferror: " + std::to_string(err) );
102 }
103 }
104
105 void skip( long loc) {
106 if( 0 != fseek( _file.get(), loc, SEEK_CUR ) ) {
107 int err = ferror(_file.get());
108 throw std::ios_base::failure( "cfile: " + _file_path.generic_string() +
109 " unable to SEEK_CUR to: " + std::to_string(loc) +
110 ", ferror: " + std::to_string(err) );
111 }
112 }
113
114 void read( char* d, size_t n ) {
115 size_t result = fread( d, 1, n, _file.get() );
116 if( result != n ) {
117 int err = ferror(_file.get());
118 int eof = feof(_file.get());
119 throw std::ios_base::failure( "cfile: " + _file_path.generic_string() +
120 " unable to read " + std::to_string( n ) + " bytes;"
121 " only read " + std::to_string( result ) +
122 ", eof: " + (eof == 0 ? "false" : "true") +
123 ", ferror: " + std::to_string(err) );
124 }
125 }
126
127 void write( const char* d, size_t n ) {
128 size_t result = fwrite( d, 1, n, _file.get() );
129 if( result != n ) {
130 throw std::ios_base::failure( "cfile: " + _file_path.generic_string() +
131 " unable to write " + std::to_string( n ) + " bytes; only wrote " + std::to_string( result ) );
132 }
133 }
134
135 void flush() {
136 if( 0 != fflush( _file.get() ) ) {
137 int err = ferror( _file.get() );
138 throw std::ios_base::failure( "cfile: " + _file_path.generic_string() +
139 " unable to flush file, ferror: " + std::to_string( err ) );
140 }
141 }
142
143 void sync() {
144 const int fd = fileno();
145 if( -1 == fsync( fd ) ) {
146 throw std::ios_base::failure( "cfile: " + _file_path.generic_string() +
147 " unable to sync file, error: " + std::to_string( errno ) );
148 }
149#ifdef __APPLE__
150 if( -1 == fcntl( fd, F_FULLFSYNC ) ) {
151 throw std::ios_base::failure( "cfile: " + _file_path.generic_string() +
152 " unable to F_FULLFSYNC file, error: " + std::to_string( errno ) );
153 }
154#endif
155 }
156
157 //rounds to filesystem block boundaries; e.g. punch_hole(5000, 14000) when blocksz=4096 punches from 8192 to 12288
158 //end is not inclusive; eg punch_hole(4096, 8192) will punch 4096 bytes (assuming blocksz=4096)
159 void punch_hole(size_t begin, size_t end) {
160 if(begin % _file_blk_size) {
161 begin &= ~(_file_blk_size-1);
162 begin += _file_blk_size;
163 }
164 end &= ~(_file_blk_size-1);
165
166 if(begin >= end)
167 return;
168
169 int ret = 0;
170#if defined(__linux__)
171 ret = fallocate(fileno(), FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE, begin, end-begin);
172#elif defined(__APPLE__)
173 struct fpunchhole puncher = {0, 0, static_cast<off_t>(begin), static_cast<off_t>(end-begin)};
174 ret = fcntl(fileno(), F_PUNCHHOLE, &puncher);
175#endif
176 if(ret == -1)
177 wlog("Failed to punch hole in file ${f}: ${e}", ("f", _file_path)("e", strerror(errno)));
178
179 flush();
180 }
181
183#if defined(__linux__) || defined(__APPLE__)
184 return true;
185#endif
186 return false;
187 }
188
189 size_t filesystem_block_size() const { return _file_blk_size; }
190
191 bool eof() const { return feof(_file.get()) != 0; }
192
193 int getc() {
194 int ret = fgetc(_file.get());
195 if (ret == EOF) {
196 throw std::ios_base::failure( "cfile: " + _file_path.generic_string() +
197 " unable to read 1 byte");
198 }
199 return ret;
200 }
201
202 void close() {
203 _file.reset();
204 _open = false;
205 }
206
207 boost::interprocess::mapping_handle_t get_mapping_handle() const {
208 return {fileno(), false};
209 }
210
212
213private:
214 bool _open = false;
215 fc::path _file_path;
216 size_t _file_blk_size = 4096;
218};
219
220/*
221 * @brief datastream adapter that adapts cfile for use with fc unpack
222 *
223 * This class supports unpack functionality but not pack.
224 */
226public:
227 explicit cfile_datastream( cfile& cf ) : cf(cf) {}
228
229 void skip( size_t s ) {
230 std::vector<char> d( s );
231 read( &d[0], s );
232 }
233
234 bool read( char* d, size_t s ) {
235 cf.read( d, s );
236 return true;
237 }
238
239 bool get( unsigned char& c ) { return get( *(char*)&c ); }
240
241 bool get( char& c ) { return read(&c, 1); }
242
243 size_t tellp() const { return cf.tellp(); }
244
245 private:
246 cfile& cf;
247};
248
252
253template <>
254class datastream<fc::cfile, void> : public fc::cfile {
255 public:
256 using fc::cfile::cfile;
257
258 bool seekp(size_t pos) { return this->seek(pos), true; }
259
260 bool get(char& c) {
261 c = this->getc();
262 return true;
263 }
264
265 fc::cfile& storage() { return *this; }
266 const fc::cfile& storage() const { return *this; }
267};
268
269
270} // namespace fc
271
272#ifndef _WIN32
273#undef FC_FOPEN
274#else
275#undef FC_CAT
276#undef FC_PREL
277#undef FC_FOPEN
278#endif
#define FC_FOPEN(p, m)
Definition block_log.cpp:16
cfile_datastream(cfile &cf)
Definition cfile.hpp:227
bool get(char &c)
Definition cfile.hpp:241
bool read(char *d, size_t s)
Definition cfile.hpp:234
bool get(unsigned char &c)
Definition cfile.hpp:239
size_t tellp() const
Definition cfile.hpp:243
void skip(size_t s)
Definition cfile.hpp:229
size_t filesystem_block_size() const
Definition cfile.hpp:189
void read(char *d, size_t n)
Definition cfile.hpp:114
void close()
Definition cfile.hpp:202
void sync()
Definition cfile.hpp:143
void seek_end(long loc)
Definition cfile.hpp:96
static constexpr const char * truncate_rw_mode
Definition cfile.hpp:59
void flush()
Definition cfile.hpp:135
static bool supports_hole_punching()
Definition cfile.hpp:182
auto fileno() const
Definition cfile.hpp:47
bool eof() const
Definition cfile.hpp:191
static constexpr const char * update_rw_mode
Definition cfile.hpp:58
boost::interprocess::mapping_handle_t get_mapping_handle() const
Definition cfile.hpp:207
void seek(long loc)
Definition cfile.hpp:87
static constexpr const char * create_or_update_rw_mode
Definition cfile.hpp:57
cfile_datastream create_datastream()
Definition cfile.hpp:249
void skip(long loc)
Definition cfile.hpp:105
void punch_hole(size_t begin, size_t end)
Definition cfile.hpp:159
void open(const char *mode)
Definition cfile.hpp:65
fc::path get_file_path() const
Definition cfile.hpp:41
size_t tellp() const
Definition cfile.hpp:79
void set_file_path(fc::path file_path)
Definition cfile.hpp:37
bool is_open() const
Definition cfile.hpp:45
void write(const char *d, size_t n)
Definition cfile.hpp:127
int getc()
Definition cfile.hpp:193
const fc::cfile & storage() const
Definition cfile.hpp:266
wraps boost::filesystem::path to provide platform independent path manipulation.
std::string generic_string() const
#define wlog(FORMAT,...)
Definition logger.hpp:124
std::unique_ptr< FILE, decltype(&fclose)> unique_file
Definition cfile.hpp:22
namespace sysio::chain
Definition authority.cpp:3
CK_ULONG d
CK_RV ret
char * s