9#include <boost/interprocess/file_mapping.hpp>
12#define FC_FOPEN(p, m) fopen(p, m)
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))
22 using unique_file = std::unique_ptr<FILE,
decltype( &fclose )>;
34 : _file(nullptr, &fclose)
38 _file_path = std::move( file_path );
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 ) );
65 void open(
const char* mode ) {
68 throw std::ios_base::failure(
"cfile unable to open: " + _file_path.
generic_string() +
" in mode: " + std::string( mode ) );
72 _file_blk_size = 4096;
73 if( fstat(
fileno(), &st) == 0 )
74 _file_blk_size = st.st_blksize;
80 long result = ftell( _file.get() );
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);
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) );
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) );
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) );
114 void read(
char* d,
size_t n ) {
115 size_t result = fread(
d, 1, n, _file.get() );
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) );
127 void write(
const char* d,
size_t n ) {
128 size_t result = fwrite(
d, 1, n, _file.get() );
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 ) );
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 ) );
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 ) );
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 ) );
160 if(begin % _file_blk_size) {
161 begin &= ~(_file_blk_size-1);
162 begin += _file_blk_size;
164 end &= ~(_file_blk_size-1);
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);
177 wlog(
"Failed to punch hole in file ${f}: ${e}", (
"f", _file_path)(
"e", strerror(errno)));
183#if defined(__linux__) || defined(__APPLE__)
191 bool eof()
const {
return feof(_file.get()) != 0; }
194 int ret = fgetc(_file.get());
196 throw std::ios_base::failure(
"cfile: " + _file_path.
generic_string() +
197 " unable to read 1 byte");
216 size_t _file_blk_size = 4096;
230 std::vector<char>
d(
s );
239 bool get(
unsigned char& c ) {
return get( *(
char*)&c ); }
258 bool seekp(
size_t pos) {
return this->seek(pos),
true; }
cfile_datastream(cfile &cf)
bool read(char *d, size_t s)
bool get(unsigned char &c)
size_t filesystem_block_size() const
void read(char *d, size_t n)
static constexpr const char * truncate_rw_mode
static bool supports_hole_punching()
static constexpr const char * update_rw_mode
boost::interprocess::mapping_handle_t get_mapping_handle() const
static constexpr const char * create_or_update_rw_mode
cfile_datastream create_datastream()
void punch_hole(size_t begin, size_t end)
void open(const char *mode)
fc::path get_file_path() const
void set_file_path(fc::path file_path)
void write(const char *d, size_t n)
const fc::cfile & storage() const
wraps boost::filesystem::path to provide platform independent path manipulation.
std::string generic_string() const
std::unique_ptr< FILE, decltype(&fclose)> unique_file