//#define BOOST_NO_SCOPED_ENUMS #include #include #include #include #include #include #include #include #include #ifdef WIN32 #include #else #include #include #include #endif namespace fc { void to_variant( const fc::path& t, variant& v ) { std::string path = t.to_native_ansi_path(); for(auto& c : path) { if(c == '\\') c = '/'; } v = path; } void from_variant( const fc::variant& v, fc::path& t ) { t = fc::path(v.as_string()); } // Note: we can do this cast because the separator should be an ASCII character char path::separator_char = static_cast(boost::filesystem::path("/").make_preferred().native()[0]); path::path(){} path::~path(){}; path::path( const boost::filesystem::path& p ) :_p(p){} path::path( const char* p ) :_p(p){} path::path( const fc::string& p ) :_p(p.c_str()){} path::path(const std::wstring& p) :_p(p) {} path::path( const path& p ) :_p(p){} path::path( path&& p ) :_p(std::move(p)){} path& path::operator =( const path& p ) { *_p = *p._p; return *this; } path& path::operator =( path&& p ) { *_p = fc::move( *p._p ); return *this; } bool operator <( const fc::path& l, const fc::path& r ) { return *l._p < *r._p; } bool operator ==( const fc::path& l, const fc::path& r ) { return *l._p == *r._p; } bool operator !=( const fc::path& l, const fc::path& r ) { return *l._p != *r._p; } path& path::operator /=( const fc::path& p ) { *_p /= *p._p; return *this; } path operator /( const fc::path& p, const fc::path& o ) { path tmp; tmp = *p._p / *o._p; return tmp; } path::operator boost::filesystem::path& () { return *_p; } path::operator const boost::filesystem::path& ()const { return *_p; } fc::string path::generic_string()const { return _p->generic_string(); } std::wstring path::wstring() const { return _p->wstring(); } std::wstring path::generic_wstring() const { return _p->generic_wstring(); } std::string path::to_native_ansi_path() const { std::wstring path = generic_wstring(); #ifdef WIN32 const size_t maxPath = 32*1024; std::vector short_path; short_path.resize(maxPath + 1); wchar_t* buffer = short_path.data(); DWORD res = GetShortPathNameW(path.c_str(), buffer, maxPath); if(res != 0) path = buffer; #endif std::string filePath; fc::encodeUtf8(path, &filePath); return filePath; } /** * @todo use iterators instead of indexes for * faster performance */ fc::string path::windows_string()const { auto gs = _p->generic_string(); for( size_t i =0 ; i < gs.size(); ++i ) { if( gs[i] == '/' ) gs[i] = '\\'; } return gs; } fc::string path::string()const { return _p->string(); } fc::path path::filename()const { return _p->filename(); } void path::replace_extension( const fc::path& e ) { _p->replace_extension(e); } fc::path path::extension()const { return _p->extension(); } fc::path path::stem()const { return _p->stem(); } fc::path path::parent_path()const { return _p->parent_path(); } bool path::is_relative()const { return _p->is_relative(); } bool path::is_absolute()const { return _p->is_absolute(); } directory_iterator::directory_iterator( const fc::path& p ) :_p(p){} directory_iterator::directory_iterator(){} directory_iterator::~directory_iterator(){} fc::path directory_iterator::operator*()const { return boost::filesystem::path(*(*_p)); } directory_iterator& directory_iterator::operator++(int) { (*_p)++; return *this; } directory_iterator& directory_iterator::operator++() { (*_p)++; return *this; } bool operator==( const directory_iterator& r, const directory_iterator& l) { return *r._p == *l._p; } bool operator!=( const directory_iterator& r, const directory_iterator& l) { return *r._p != *l._p; } recursive_directory_iterator::recursive_directory_iterator( const fc::path& p ) :_p(p){} recursive_directory_iterator::recursive_directory_iterator(){} recursive_directory_iterator::~recursive_directory_iterator(){} fc::path recursive_directory_iterator::operator*()const { return boost::filesystem::path(*(*_p)); } recursive_directory_iterator& recursive_directory_iterator::operator++(int) { (*_p)++; return *this; } recursive_directory_iterator& recursive_directory_iterator::operator++() { (*_p)++; return *this; } void recursive_directory_iterator::pop() { (*_p).pop(); } int recursive_directory_iterator::level() { return _p->level(); } bool operator==( const recursive_directory_iterator& r, const recursive_directory_iterator& l) { return *r._p == *l._p; } bool operator!=( const recursive_directory_iterator& r, const recursive_directory_iterator& l) { return *r._p != *l._p; } bool exists( const path& p ) { return boost::filesystem::exists(p); } void create_directories( const path& p ) { try { boost::filesystem::create_directories(p); } catch ( ... ) { FC_THROW( "Unable to create directories ${path}", ("path", p )("inner", fc::except_str() ) ); } } bool is_directory( const path& p ) { return boost::filesystem::is_directory(p); } bool is_regular_file( const path& p ) { return boost::filesystem::is_regular_file(p); } uint64_t file_size( const path& p ) { return boost::filesystem::file_size(p); } void remove_all( const path& p ) { boost::filesystem::remove_all(p); } void copy( const path& f, const path& t ) { try { boost::filesystem::copy( boost::filesystem::path(f), boost::filesystem::path(t) ); } catch ( boost::system::system_error& e ) { FC_THROW( "Copy from ${srcfile} to ${dstfile} failed because ${reason}", ("srcfile",f)("dstfile",t)("reason",e.what() ) ); } catch ( ... ) { FC_THROW( "Copy from ${srcfile} to ${dstfile} failed", ("srcfile",f)("dstfile",t)("inner", fc::except_str() ) ); } } void resize_file( const path& f, size_t t ) { try { boost::filesystem::resize_file( f, t ); } catch ( boost::system::system_error& e ) { FC_THROW( "Resize file '${f}' to size ${s} failed: ${reason}", ("f",f)("s",t)( "reason", e.what() ) ); } catch ( ... ) { FC_THROW( "Resize file '${f}' to size ${s} failed: ${reason}", ("f",f)("s",t)( "reason", fc::except_str() ) ); } } void rename( const path& f, const path& t ) { try { boost::filesystem::rename( boost::filesystem::path(f), boost::filesystem::path(t) ); } catch ( boost::system::system_error& e ) { try{ boost::filesystem::copy( boost::filesystem::path(f), boost::filesystem::path(t) ); boost::filesystem::remove( boost::filesystem::path(f)); } catch ( boost::system::system_error& e ) { FC_THROW( "Rename from ${srcfile} to ${dstfile} failed because ${reason}", ("srcfile",f)("dstfile",t)("reason",e.what() ) ); } } catch ( ... ) { FC_THROW( "Rename from ${srcfile} to ${dstfile} failed", ("srcfile",f)("dstfile",t)("inner", fc::except_str() ) ); } } void create_hard_link( const path& f, const path& t ) { try { boost::filesystem::create_hard_link( f, t ); } catch ( ... ) { FC_THROW( "Unable to create hard link from '${from}' to '${to}'", ( "from", f )("to",t)("exception", fc::except_str() ) ); } } bool remove( const path& f ) { try { return boost::filesystem::remove( f ); } catch ( ... ) { FC_THROW( "Unable to remove '${path}'", ( "path", f )("exception", fc::except_str() ) ); } } fc::path canonical( const fc::path& p ) { try { return boost::filesystem::canonical(p); } catch ( ... ) { FC_THROW( "Unable to resolve path '${path}'", ( "path", p )("exception", fc::except_str() ) ); } } fc::path absolute( const fc::path& p ) { return boost::filesystem::absolute(p); } path unique_path() { return boost::filesystem::unique_path(); } path temp_directory_path() { return boost::filesystem::temp_directory_path(); } // Return path when appended to a_From will resolve to same as a_To fc::path make_relative(const fc::path& from, const fc::path& to) { boost::filesystem::path a_From = boost::filesystem::absolute(from); boost::filesystem::path a_To = boost::filesystem::absolute(to); boost::filesystem::path ret; boost::filesystem::path::const_iterator itrFrom(a_From.begin()), itrTo(a_To.begin()); // Find common base for( boost::filesystem::path::const_iterator toEnd( a_To.end() ), fromEnd( a_From.end() ) ; itrFrom != fromEnd && itrTo != toEnd && *itrFrom == *itrTo; ++itrFrom, ++itrTo ); // Navigate backwards in directory to reach previously found base for( boost::filesystem::path::const_iterator fromEnd( a_From.end() ); itrFrom != fromEnd; ++itrFrom ) { if( (*itrFrom) != "." ) ret /= ".."; } // Now navigate down the directory branch for (; itrTo != a_To.end(); ++itrTo) ret /= *itrTo; return ret; } temp_file::temp_file(const fc::path& p, bool create) : temp_file_base(p / fc::unique_path()) { if (fc::exists(*_path)) { FC_THROW( "Name collision: ${path}", ("path", _path->string()) ); } if (create) { fc::ofstream ofs(*_path, fc::ofstream::out | fc::ofstream::binary); ofs.close(); } } temp_file::temp_file(temp_file&& other) : temp_file_base(std::move(other._path)) { } temp_file& temp_file::operator=(temp_file&& other) { if (this != &other) { remove(); _path = std::move(other._path); } return *this; } temp_directory::temp_directory(const fc::path& p) : temp_file_base(p / fc::unique_path()) { if (fc::exists(*_path)) { FC_THROW( "Name collision: ${path}", ("path", _path->string()) ); } fc::create_directories(*_path); } temp_directory::temp_directory(temp_directory&& other) : temp_file_base(std::move(other._path)) { } temp_directory& temp_directory::operator=(temp_directory&& other) { if (this != &other) { remove(); _path = std::move(other._path); } return *this; } const fc::path& temp_file_base::path() const { if (!_path) { FC_THROW( "Temporary directory has been released." ); } return *_path; } void temp_file_base::remove() { if (_path) { try { fc::remove_all(*_path); } catch (...) { // eat errors on cleanup } release(); } } void temp_file_base::release() { _path = fc::optional(); } const fc::path& home_path() { static fc::path p = []() { #ifdef WIN32 char* home = getenv( "USERPROFILE" ); if( nullptr == home ) { FC_ASSERT( home != nullptr, "The USERPROFILE environment variable is not set" ); } return fc::path( home ); #else char* home = getenv( "HOME" ); if( nullptr == home ) { struct passwd* pwd = getpwuid(getuid()); if( pwd ) { return fc::path( std::string( pwd->pw_dir ) ); } FC_ASSERT( home != nullptr, "The HOME environment variable is not set" ); } return fc::path( std::string(home) ); #endif }(); return p; } const fc::path& app_path() { #ifdef __APPLE__ static fc::path appdir = [](){ return home_path() / "Library" / "Application Support"; }(); #elif defined( WIN32 ) static fc::path appdir = [](){ char* appdata = getenv( "APPDATA" ); if( nullptr == appdata ) { FC_ASSERT( appdata != nullptr, "The APPDATA environment variable is not set" ); } return fc::path( std::string(appdata) ); }(); #else static fc::path appdir = home_path(); #endif return appdir; } }