BitShares-Core  5.0.0
BitShares blockchain implementation and command-line interface software
filesystem.cpp
Go to the documentation of this file.
1 //#define BOOST_NO_SCOPED_ENUMS
2 #include <fc/filesystem.hpp>
4 #include <fc/fwd_impl.hpp>
5 #include <fc/io/fstream.hpp>
6 
7 #include <fc/utf8.hpp>
8 #include <fc/variant.hpp>
9 
10 #include <boost/config.hpp>
11 #include <boost/filesystem.hpp>
12 
13 #ifdef _WIN32
14 # include <windows.h>
15 # include <userenv.h>
16 # include <shlobj.h>
17 #else
18  #include <sys/types.h>
19  #include <sys/stat.h>
20  #include <pwd.h>
21 # ifdef FC_HAS_SIMPLE_FILE_LOCK
22  #include <sys/file.h>
23  #include <fcntl.h>
24 # endif
25 #endif
26 
27 namespace fc {
28  // when converting to and from a variant, store utf-8 in the variant
29  void to_variant( const fc::path& path_to_convert, variant& variant_output, uint32_t max_depth )
30  {
31  std::wstring wide_string = path_to_convert.generic_wstring();
32  std::string utf8_string;
33  fc::encodeUtf8(wide_string, &utf8_string);
34  variant_output = utf8_string;
35  }
36 
37  void from_variant( const fc::variant& variant_to_convert, fc::path& path_output, uint32_t max_depth )
38  {
39  std::wstring wide_string;
40  fc::decodeUtf8(variant_to_convert.as_string(), &wide_string);
41  path_output = path(wide_string);
42  }
43 
44  // Note: we can do this cast because the separator should be an ASCII character
45  char path::separator_char = static_cast<char>(boost::filesystem::path("/").make_preferred().native()[0]);
46 
49  path::path( const boost::filesystem::path& p )
50  :_p(p){}
51 
52  path::path( const char* p )
53  :_p(p){}
54  path::path( const std::string& p )
55  :_p(p.c_str()){}
56 
57  path::path(const std::wstring& p)
58  :_p(p) {}
59 
60  path::path( const path& p )
61  :_p(p){}
62 
64  :_p(std::move(p)){}
65 
66  path& path::operator =( const path& p ) {
67  *_p = *p._p;
68  return *this;
69  }
71  *_p = std::move( *p._p );
72  return *this;
73  }
74 
75  bool operator <( const fc::path& l, const fc::path& r ) { return *l._p < *r._p; }
76  bool operator ==( const fc::path& l, const fc::path& r ) { return *l._p == *r._p; }
77  bool operator !=( const fc::path& l, const fc::path& r ) { return *l._p != *r._p; }
78 
80  *_p /= *p._p;
81  return *this;
82  }
83  path operator /( const fc::path& p, const fc::path& o ) {
84  path tmp;
85  tmp = *p._p / *o._p;
86  return tmp;
87  }
88 
89  path::operator boost::filesystem::path& () {
90  return *_p;
91  }
92  path::operator const boost::filesystem::path& ()const {
93  return *_p;
94  }
95  std::string path::generic_string()const {
96  return _p->generic_string();
97  }
98 
99  std::string path::preferred_string() const
100  {
101  return boost::filesystem::path(*_p).make_preferred().string();
102  }
103 
104  std::wstring path::wstring() const
105  {
106  return _p->wstring();
107  }
108 
109  std::wstring path::generic_wstring() const
110  {
111  return _p->generic_wstring();
112  }
113 
114  std::wstring path::preferred_wstring() const
115  {
116  return boost::filesystem::path(*_p).make_preferred().wstring();
117  }
118 
119  std::string path::to_native_ansi_path() const
120  {
121  std::wstring path = generic_wstring();
122 
123 #ifdef WIN32
124  const size_t maxPath = 32*1024;
125  std::vector<wchar_t> short_path;
126  short_path.resize(maxPath + 1);
127 
128  wchar_t* buffer = short_path.data();
129  DWORD res = GetShortPathNameW(path.c_str(), buffer, maxPath);
130  if(res != 0)
131  path = buffer;
132 #endif
133  std::string filePath;
134  fc::encodeUtf8(path, &filePath);
135  return filePath;
136  }
137 
142  std::string path::windows_string()const {
143  std::string result = _p->generic_string();
144  std::replace(result.begin(), result.end(), '/', '\\');
145  return result;
146  }
147 
148  std::string path::string()const {
149  return _p->string();
150  }
152  return _p->filename();
153  }
155  _p->replace_extension(e);
156  }
158  return _p->extension();
159  }
161  return _p->stem();
162  }
164  return _p->parent_path();
165  }
166  bool path::is_relative()const { return _p->is_relative(); }
167  bool path::is_absolute()const { return _p->is_absolute(); }
168 
170  :_p(p){}
171 
174 
175  fc::path directory_iterator::operator*()const { return boost::filesystem::path(*(*_p)); }
176  detail::path_wrapper directory_iterator::operator->() const { return detail::path_wrapper(boost::filesystem::path(*(*_p))); }
177  directory_iterator& directory_iterator::operator++(int) { (*_p)++; return *this; }
179 
181  return *r._p == *l._p;
182  }
184  return *r._p != *l._p;
185  }
186 
187 
189  :_p(p){}
190 
193 
194  fc::path recursive_directory_iterator::operator*()const { return boost::filesystem::path(*(*_p)); }
197 
198  void recursive_directory_iterator::pop() { (*_p).pop(); }
199  int recursive_directory_iterator::level() { return _p->level(); }
200 
202  return *r._p == *l._p;
203  }
205  return *r._p != *l._p;
206  }
207 
208 
209  bool exists( const path& p ) { return boost::filesystem::exists(p); }
210  void create_directories( const path& p ) {
211  try {
213  } catch ( ... ) {
214  FC_THROW( "Unable to create directories ${path}", ("path", p )("inner", fc::except_str() ) );
215  }
216  }
217  bool is_directory( const path& p ) { return boost::filesystem::is_directory(p); }
219  uint64_t file_size( const path& p ) { return boost::filesystem::file_size(p); }
220 
221  uint64_t directory_size(const path& p)
222  {
223  try {
224  FC_ASSERT( is_directory( p ) );
225 
227  uint64_t size = 0;
228  for( recursive_directory_iterator itr( p ); itr != end; ++itr )
229  {
230  if( is_regular_file( *itr ) )
231  size += file_size( *itr );
232  }
233 
234  return size;
235  } catch ( ... ) {
236  FC_THROW( "Unable to calculate size of directory ${path}", ("path", p )("inner", fc::except_str() ) );
237  }
238  }
239 
241  void copy( const path& f, const path& t ) {
242  try {
243  boost::system::error_code ec;
244  boost::filesystem::copy( boost::filesystem::path(f), boost::filesystem::path(t), ec );
245  if( ec )
246  {
247  FC_THROW( "Copy from ${srcfile} to ${dstfile} failed because ${code} : ${message}",
248  ("srcfile",f)("dstfile",t)("code",ec.value())("message",ec.message()) );
249  }
250  } catch ( boost::system::system_error& e ) {
251  FC_THROW( "Copy from ${srcfile} to ${dstfile} failed because ${reason}",
252  ("srcfile",f)("dstfile",t)("reason",std::string(e.what()) ) );
253  } catch ( ... ) {
254  FC_THROW( "Copy from ${srcfile} to ${dstfile} failed",
255  ("srcfile",f)("dstfile",t)("inner", fc::except_str() ) );
256  }
257  }
258  void resize_file( const path& f, size_t t )
259  {
260  try {
262  }
263  catch ( boost::system::system_error& e )
264  {
265  FC_THROW( "Resize file '${f}' to size ${s} failed: ${reason}",
266  ("f",f)("s",t)( "reason", std::string(e.what()) ) );
267  }
268  catch ( ... )
269  {
270  FC_THROW( "Resize file '${f}' to size ${s} failed: ${reason}",
271  ("f",f)("s",t)( "reason", fc::except_str() ) );
272  }
273  }
274 
275  // setuid, setgid not implemented.
276  // translates octal permission like 0755 to S_ stuff defined in sys/stat.h
277  // no-op on Windows.
278  void chmod( const path& p, int perm )
279  {
280 #ifndef WIN32
281  mode_t actual_perm =
282  ((perm & 0400) ? S_IRUSR : 0)
283  | ((perm & 0200) ? S_IWUSR : 0)
284  | ((perm & 0100) ? S_IXUSR : 0)
285 
286  | ((perm & 0040) ? S_IRGRP : 0)
287  | ((perm & 0020) ? S_IWGRP : 0)
288  | ((perm & 0010) ? S_IXGRP : 0)
289 
290  | ((perm & 0004) ? S_IROTH : 0)
291  | ((perm & 0002) ? S_IWOTH : 0)
292  | ((perm & 0001) ? S_IXOTH : 0)
293  ;
294 
295  int result = ::chmod( p.string().c_str(), actual_perm );
296  if( result != 0 )
297  FC_THROW( "chmod operation failed on ${p}", ("p",p) );
298 #endif
299  return;
300  }
301 
302  void rename( const path& f, const path& t ) {
303  try {
304  boost::filesystem::rename( boost::filesystem::path(f), boost::filesystem::path(t) );
305  } catch ( boost::system::system_error& er ) {
306  try {
307  copy( f, t );
308  remove( f );
309  } catch ( fc::exception& e ) {
310  FC_RETHROW_EXCEPTION( e, error,
311  "Rename from ${srcfile} to ${dstfile} failed due to ${reason}, trying to copy then remove",
312  ("srcfile",f)("dstfile",t)("reason",std::string(er.what())) );
313  }
314  } catch ( ... ) {
315  FC_THROW( "Rename from ${srcfile} to ${dstfile} failed",
316  ("srcfile",f)("dstfile",t)("inner", fc::except_str() ) );
317  }
318  }
319  void create_hard_link( const path& f, const path& t ) {
320  try {
322  } catch ( ... ) {
323  FC_THROW( "Unable to create hard link from '${from}' to '${to}'",
324  ( "from", f )("to",t)("exception", fc::except_str() ) );
325  }
326  }
327  bool remove( const path& f ) {
328  try {
329  return boost::filesystem::remove( f );
330  } catch ( ... ) {
331  FC_THROW( "Unable to remove '${path}'", ( "path", f )("exception", fc::except_str() ) );
332  }
333  }
334  fc::path canonical( const fc::path& p ) {
335  try {
336  return boost::filesystem::canonical(p);
337  } catch ( ... ) {
338  FC_THROW( "Unable to resolve path '${path}'", ( "path", p )("exception", fc::except_str() ) );
339  }
340  }
344 
345  // Return path when appended to a_From will resolve to same as a_To
346  fc::path make_relative(const fc::path& from, const fc::path& to) {
347  boost::filesystem::path a_From = boost::filesystem::absolute(from);
348  boost::filesystem::path a_To = boost::filesystem::absolute(to);
349  boost::filesystem::path ret;
350  boost::filesystem::path::const_iterator itrFrom(a_From.begin()), itrTo(a_To.begin());
351  // Find common base
352  for( boost::filesystem::path::const_iterator toEnd( a_To.end() ), fromEnd( a_From.end() ) ; itrFrom != fromEnd && itrTo != toEnd && *itrFrom == *itrTo; ++itrFrom, ++itrTo );
353  // Navigate backwards in directory to reach previously found base
354  for( boost::filesystem::path::const_iterator fromEnd( a_From.end() ); itrFrom != fromEnd; ++itrFrom ) {
355  if( (*itrFrom) != "." )
356  ret /= "..";
357  }
358  // Now navigate down the directory branch
359  for (; itrTo != a_To.end(); ++itrTo)
360  ret /= *itrTo;
361  return ret;
362  }
363 
364  temp_file::temp_file(const fc::path& p, bool create)
365  : temp_file_base(p / fc::unique_path())
366  {
367  if (fc::exists(*_path))
368  {
369  FC_THROW( "Name collision: ${path}", ("path", _path->string()) );
370  }
371  if (create)
372  {
373  fc::ofstream ofs(*_path, std::ios_base::out | std::ios_base::binary);
374  ofs.close();
375  }
376  }
377 
379  : temp_file_base(std::move(other._path))
380  {
381  }
382 
384  {
385  if (this != &other)
386  {
387  remove();
388  _path = std::move(other._path);
389  }
390  return *this;
391  }
392 
394  : temp_file_base(p / fc::unique_path())
395  {
396  if (fc::exists(*_path))
397  {
398  FC_THROW( "Name collision: ${path}", ("path", _path->string()) );
399  }
401  }
402 
404  : temp_file_base(std::move(other._path))
405  {
406  }
407 
409  {
410  if (this != &other)
411  {
412  remove();
413  _path = std::move(other._path);
414  }
415  return *this;
416  }
417 
419  {
420  if (!_path)
421  {
422  FC_THROW( "Temporary directory has been released." );
423  }
424  return *_path;
425  }
426 
428  {
429  if (_path.valid())
430  {
431  try
432  {
434  }
435  catch (...)
436  {
437  // eat errors on cleanup
438  }
439  release();
440  }
441  }
442 
444  {
446  }
447 
449  {
450  static fc::path p = []()
451  {
452 #ifdef WIN32
453  HANDLE access_token;
454  if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &access_token))
455  FC_ASSERT(false, "Unable to open an access token for the current process");
456  wchar_t user_profile_dir[MAX_PATH];
457  DWORD user_profile_dir_len = sizeof(user_profile_dir);
458  BOOL success = GetUserProfileDirectoryW(access_token, user_profile_dir, &user_profile_dir_len);
459  CloseHandle(access_token);
460  if (!success)
461  FC_ASSERT(false, "Unable to get the user profile directory");
462  return fc::path(std::wstring(user_profile_dir));
463 #else
464  char* home = getenv( "HOME" );
465  if( nullptr == home )
466  {
467  struct passwd* pwd = getpwuid(getuid());
468  if( pwd )
469  {
470  return fc::path( std::string( pwd->pw_dir ) );
471  }
472  FC_ASSERT( home != nullptr, "The HOME environment variable is not set" );
473  }
474  return fc::path( std::string(home) );
475 #endif
476  }();
477  return p;
478  }
479 
481  {
482 #ifdef __APPLE__
483  static fc::path appdir = [](){ return home_path() / "Library" / "Application Support"; }();
484 #elif defined( WIN32 )
485  static fc::path appdir = [](){
486  wchar_t app_data_dir[MAX_PATH];
487 
488  if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, app_data_dir)))
489  FC_ASSERT(false, "Unable to get the current AppData directory");
490  return fc::path(std::wstring(app_data_dir));
491  }();
492 #else
493  static fc::path appdir = home_path();
494 #endif
495  return appdir;
496  }
497 
499  {
500  static fc::path appCurrentPath = boost::filesystem::current_path();
501  return appCurrentPath;
502  }
503 
504 }
std::wstring preferred_wstring() const
Definition: filesystem.cpp:114
std::string except_str()
Definition: exception.cpp:272
bool exists(const path &p)
Definition: filesystem.cpp:209
friend bool operator<(const fc::path &p, const fc::path &)
Definition: filesystem.cpp:75
static char separator_char
Definition: filesystem.hpp:84
bool is_regular_file(const path &p)
Definition: filesystem.cpp:218
temp_directory(temp_directory &&other)
Definition: filesystem.cpp:403
void chmod(const path &p, int perm)
Definition: filesystem.cpp:278
friend bool operator==(const directory_iterator &, const directory_iterator &)
Definition: filesystem.cpp:180
const fc::path & path() const
Definition: filesystem.cpp:418
temp_directory & operator=(temp_directory &&other)
Definition: filesystem.cpp:408
recursive_directory_iterator & operator++()
Definition: filesystem.cpp:196
directory_iterator & operator++()
Definition: filesystem.cpp:178
path & operator/=(const fc::path &)
Definition: filesystem.cpp:79
std::string to_native_ansi_path() const
Definition: filesystem.cpp:119
path & operator=(const path &)
Definition: filesystem.cpp:66
friend bool operator!=(const recursive_directory_iterator &, const recursive_directory_iterator &)
Definition: filesystem.cpp:204
void encodeUtf8(const std::wstring &input, std::string *storage)
Definition: utf8.cpp:42
#define FC_RETHROW_EXCEPTION(ER, LOG_LEVEL, FORMAT,...)
Appends a log_message to the exception ER and rethrows it.
Definition: exception.hpp:388
Used to generate a useful error report when an exception is thrown.At each level in the stack where t...
Definition: exception.hpp:56
void rename(const path &from, const path &to)
Definition: filesystem.cpp:302
uint64_t directory_size(const path &p)
Definition: filesystem.cpp:221
bool valid() const
Definition: optional.hpp:186
friend bool operator==(const recursive_directory_iterator &, const recursive_directory_iterator &)
Definition: filesystem.cpp:201
void create_directories(const path &p)
Definition: filesystem.cpp:210
#define FC_THROW(...)
Definition: exception.hpp:366
void remove_all(const path &p)
Definition: filesystem.cpp:240
bool is_absolute() const
Definition: filesystem.cpp:167
fc::path filename() const
Definition: filesystem.cpp:151
void create_hard_link(const path &from, const path &to)
Definition: filesystem.cpp:319
std::string generic_string() const
Definition: filesystem.cpp:95
const path & app_path()
Definition: filesystem.cpp:480
fc::path extension() const
Definition: filesystem.cpp:157
std::string string() const
Definition: filesystem.cpp:148
friend path operator/(const fc::path &p, const fc::path &)
Definition: filesystem.cpp:83
path make_relative(const path &from, const path &to)
Definition: filesystem.cpp:346
void to_variant(const flat_set< T, A... > &var, variant &vo, uint32_t _max_depth)
Definition: flat.hpp:105
friend bool operator!=(const directory_iterator &, const directory_iterator &)
Definition: filesystem.cpp:183
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
Definition: exception.hpp:345
bool is_relative() const
Definition: filesystem.cpp:166
stores null, int64, uint64, double, bool, string, std::vector<variant>, and variant_object&#39;s.
Definition: variant.hpp:198
uint64_t file_size(const path &p)
Definition: filesystem.cpp:219
path canonical(const path &p)
Definition: filesystem.cpp:334
temp_file & operator=(temp_file &&other)
Definition: filesystem.cpp:383
temp_file(temp_file &&other)
Definition: filesystem.cpp:378
fc::path operator*() const
Definition: filesystem.cpp:175
std::wstring wstring() const
Definition: filesystem.cpp:104
bool is_directory(const path &p)
Definition: filesystem.cpp:217
friend bool operator!=(const fc::path &p, const fc::path &)
Definition: filesystem.cpp:77
path unique_path()
Definition: filesystem.cpp:342
const fc::path & current_path()
Definition: filesystem.cpp:498
Defines exception&#39;s used by fc.
void from_variant(const variant &var, flat_set< T, A... > &vo, uint32_t _max_depth)
Definition: flat.hpp:116
std::string preferred_string() const
Definition: filesystem.cpp:99
std::wstring generic_wstring() const
Definition: filesystem.cpp:109
path temp_directory_path()
Definition: filesystem.cpp:343
friend bool operator==(const fc::path &p, const fc::path &)
Definition: filesystem.cpp:76
Definition: api.hpp:15
bool remove(const path &p)
Definition: filesystem.cpp:327
const path & home_path()
Definition: filesystem.cpp:448
fc::path parent_path() const
Definition: filesystem.cpp:163
void replace_extension(const fc::path &e)
Definition: filesystem.cpp:154
std::string windows_string() const
replaces &#39;/&#39; with &#39;\&#39; in the result of generic_string()
Definition: filesystem.cpp:142
fc::path stem() const
Definition: filesystem.cpp:160
void copy(const path &from, const path &to)
Definition: filesystem.cpp:241
void decodeUtf8(const std::string &input, std::wstring *storage)
Definition: utf8.cpp:35
detail::path_wrapper operator->() const
Definition: filesystem.cpp:176
wraps boost::filesystem::path to provide platform independent path manipulation.
Definition: filesystem.hpp:28
path absolute(const path &p)
Definition: filesystem.cpp:341
std::string as_string() const
Definition: variant.cpp:469
void close()
Definition: fstream.cpp:48
void resize_file(const path &file, size_t s)
Definition: filesystem.cpp:258