diff --git a/include/ghc/filesystem.hpp b/include/ghc/filesystem.hpp index 12a67e3..30ad72d 100644 --- a/include/ghc/filesystem.hpp +++ b/include/ghc/filesystem.hpp @@ -862,12 +862,16 @@ public: private: friend class directory_iterator; +#ifdef GHC_WITH_EXCEPTIONS + file_type status_file_type() const; +#endif + file_type status_file_type(std::error_code& ec) const noexcept; filesystem::path _path; file_status _status; file_status _symlink_status; - uintmax_t _file_size = 0; + uintmax_t _file_size = static_cast(-1); #ifndef GHC_OS_WINDOWS - uintmax_t _hard_link_count = 0; + uintmax_t _hard_link_count = static_cast(-1); #endif time_t _last_write_time = 0; }; @@ -5009,9 +5013,9 @@ GHC_INLINE perms file_status::permissions() const noexcept #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE directory_entry::directory_entry(const filesystem::path& p) : _path(p) - , _file_size(0) + , _file_size(static_cast(-1)) #ifndef GHC_OS_WINDOWS - , _hard_link_count(0) + , _hard_link_count(static_cast(-1)) #endif , _last_write_time(0) { @@ -5021,9 +5025,9 @@ GHC_INLINE directory_entry::directory_entry(const filesystem::path& p) GHC_INLINE directory_entry::directory_entry(const filesystem::path& p, std::error_code& ec) : _path(p) - , _file_size(0) + , _file_size(static_cast(-1)) #ifndef GHC_OS_WINDOWS - , _hard_link_count(0) + , _hard_link_count(static_cast(-1)) #endif , _last_write_time(0) { @@ -5096,117 +5100,140 @@ GHC_INLINE directory_entry::operator const filesystem::path&() const noexcept return _path; } +#ifdef GHC_WITH_EXCEPTIONS +GHC_INLINE file_type directory_entry::status_file_type() const +{ + return _status.type() != file_type::none ? _status.type() : filesystem::status(path()).type(); +} +#endif + +GHC_INLINE file_type directory_entry::status_file_type(std::error_code& ec) const noexcept +{ + if(_status.type() != file_type::none) { + ec.clear(); + return _status.type(); + } + return filesystem::status(path(), ec).type(); +} + #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::exists() const { - return filesystem::exists(status()); + return status_file_type() != file_type::not_found; } #endif GHC_INLINE bool directory_entry::exists(std::error_code& ec) const noexcept { - return filesystem::exists(status(ec)); + return status_file_type(ec) != file_type::not_found; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::is_block_file() const { - return filesystem::is_block_file(status()); + return status_file_type() == file_type::block; } #endif GHC_INLINE bool directory_entry::is_block_file(std::error_code& ec) const noexcept { - return filesystem::is_block_file(status(ec)); + return status_file_type(ec) == file_type::block; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::is_character_file() const { - return filesystem::is_character_file(status()); + return status_file_type() == file_type::character; } #endif GHC_INLINE bool directory_entry::is_character_file(std::error_code& ec) const noexcept { - return filesystem::is_character_file(status(ec)); + return status_file_type(ec) == file_type::character; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::is_directory() const { - return filesystem::is_directory(status()); + return status_file_type() == file_type::directory; } #endif GHC_INLINE bool directory_entry::is_directory(std::error_code& ec) const noexcept { - return filesystem::is_directory(status(ec)); + return status_file_type(ec) == file_type::directory; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::is_fifo() const { - return filesystem::is_fifo(status()); + return status_file_type() == file_type::fifo; } #endif GHC_INLINE bool directory_entry::is_fifo(std::error_code& ec) const noexcept { - return filesystem::is_fifo(status(ec)); + return status_file_type(ec) == file_type::fifo; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::is_other() const { - return filesystem::is_other(status()); + auto ft = status_file_type(); + return ft != file_type::none && ft != file_type::not_found && ft != file_type::regular && ft != file_type::directory && !is_symlink(); } #endif GHC_INLINE bool directory_entry::is_other(std::error_code& ec) const noexcept { - return filesystem::is_other(status(ec)); + auto ft = status_file_type(ec); + bool other = ft != file_type::none && ft != file_type::not_found && ft != file_type::regular && ft != file_type::directory && !is_symlink(ec); + return !ec && other; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::is_regular_file() const { - return filesystem::is_regular_file(status()); + return status_file_type() == file_type::regular; } #endif GHC_INLINE bool directory_entry::is_regular_file(std::error_code& ec) const noexcept { - return filesystem::is_regular_file(status(ec)); + return status_file_type(ec) == file_type::regular; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::is_socket() const { - return filesystem::is_socket(status()); + return status_file_type() == file_type::socket; } #endif GHC_INLINE bool directory_entry::is_socket(std::error_code& ec) const noexcept { - return filesystem::is_socket(status(ec)); + return status_file_type(ec) == file_type::socket; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::is_symlink() const { - return filesystem::is_symlink(symlink_status()); + return _symlink_status.type() != file_type::none ? _symlink_status.type() == file_type::symlink : filesystem::is_symlink(symlink_status()); } #endif GHC_INLINE bool directory_entry::is_symlink(std::error_code& ec) const noexcept { + if(_symlink_status.type() != file_type::none) { + ec.clear(); + return _symlink_status.type() == file_type::symlink; + } return filesystem::is_symlink(symlink_status(ec)); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE uintmax_t directory_entry::file_size() const { - if (_status.type() != file_type::none) { + if (_file_size != static_cast(-1)) { return _file_size; } return filesystem::file_size(path()); @@ -5215,7 +5242,7 @@ GHC_INLINE uintmax_t directory_entry::file_size() const GHC_INLINE uintmax_t directory_entry::file_size(std::error_code& ec) const noexcept { - if (_status.type() != file_type::none) { + if (_file_size != static_cast(-1)) { ec.clear(); return _file_size; } @@ -5227,7 +5254,7 @@ GHC_INLINE uintmax_t directory_entry::file_size(std::error_code& ec) const noexc GHC_INLINE uintmax_t directory_entry::hard_link_count() const { #ifndef GHC_OS_WINDOWS - if (_status.type() != file_type::none) { + if (_hard_link_count != static_cast(-1)) { return _hard_link_count; } #endif @@ -5238,7 +5265,7 @@ GHC_INLINE uintmax_t directory_entry::hard_link_count() const GHC_INLINE uintmax_t directory_entry::hard_link_count(std::error_code& ec) const noexcept { #ifndef GHC_OS_WINDOWS - if (_status.type() != file_type::none) { + if (_hard_link_count != static_cast(-1)) { ec.clear(); return _hard_link_count; } @@ -5250,7 +5277,7 @@ GHC_INLINE uintmax_t directory_entry::hard_link_count(std::error_code& ec) const #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE file_time_type directory_entry::last_write_time() const { - if (_status.type() != file_type::none) { + if (_last_write_time != 0) { return std::chrono::system_clock::from_time_t(_last_write_time); } return filesystem::last_write_time(path()); @@ -5259,7 +5286,7 @@ GHC_INLINE file_time_type directory_entry::last_write_time() const GHC_INLINE file_time_type directory_entry::last_write_time(std::error_code& ec) const noexcept { - if (_status.type() != file_type::none) { + if (_last_write_time != 0) { ec.clear(); return std::chrono::system_clock::from_time_t(_last_write_time); } @@ -5269,7 +5296,7 @@ GHC_INLINE file_time_type directory_entry::last_write_time(std::error_code& ec) #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE file_status directory_entry::status() const { - if (_status.type() != file_type::none) { + if (_status.type() != file_type::none && _status.permissions() != perms::unknown) { return _status; } return filesystem::status(path()); @@ -5278,7 +5305,7 @@ GHC_INLINE file_status directory_entry::status() const GHC_INLINE file_status directory_entry::status(std::error_code& ec) const noexcept { - if (_status.type() != file_type::none) { + if (_status.type() != file_type::none && _status.permissions() != perms::unknown) { ec.clear(); return _status; } @@ -5288,7 +5315,7 @@ GHC_INLINE file_status directory_entry::status(std::error_code& ec) const noexce #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE file_status directory_entry::symlink_status() const { - if (_symlink_status.type() != file_type::none) { + if (_symlink_status.type() != file_type::none && _symlink_status.permissions() != perms::unknown) { return _symlink_status; } return filesystem::symlink_status(path()); @@ -5297,7 +5324,7 @@ GHC_INLINE file_status directory_entry::symlink_status() const GHC_INLINE file_status directory_entry::symlink_status(std::error_code& ec) const noexcept { - if (_symlink_status.type() != file_type::none) { + if (_symlink_status.type() != file_type::none && _symlink_status.permissions() != perms::unknown) { ec.clear(); return _symlink_status; } @@ -5360,7 +5387,7 @@ public: increment(_ec); } else { - _current = _base / std::wstring(_findData.cFileName); + _dir_entry._path = _base / std::wstring(_findData.cFileName); copyToDirEntry(_ec); } } @@ -5386,20 +5413,20 @@ public: if (_dirHandle != INVALID_HANDLE_VALUE) { do { if (FindNextFileW(_dirHandle, &_findData)) { - _current = _base; + _dir_entry._path = _base; #ifdef GHC_USE_WCHAR_T - _current.append_name(_findData.cFileName); + _dir_entry._path.append_name(_findData.cFileName); #else #ifdef GHC_RAISE_UNICODE_ERRORS try { - _current.append_name(detail::toUtf8(_findData.cFileName).c_str()); + _dir_entry._path.append_name(detail::toUtf8(_findData.cFileName).c_str()); } catch (filesystem_error& fe) { ec = fe.code(); return; } #else - _current.append_name(detail::toUtf8(_findData.cFileName).c_str()); + _dir_entry._path.append_name(detail::toUtf8(_findData.cFileName).c_str()); #endif #endif copyToDirEntry(ec); @@ -5411,7 +5438,7 @@ public: } FindClose(_dirHandle); _dirHandle = INVALID_HANDLE_VALUE; - _current = filesystem::path(); + _dir_entry._path.clear(); break; } } while (std::wstring(_findData.cFileName) == L"." || std::wstring(_findData.cFileName) == L".."); @@ -5422,12 +5449,11 @@ public: } void copyToDirEntry(std::error_code& ec) { - _dir_entry._path = _current; if (_findData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - _dir_entry._status = detail::status_ex(_current, ec, &_dir_entry._symlink_status, &_dir_entry._file_size, nullptr, &_dir_entry._last_write_time); + _dir_entry._status = detail::status_ex(_dir_entry._path, ec, &_dir_entry._symlink_status, &_dir_entry._file_size, nullptr, &_dir_entry._last_write_time); } else { - _dir_entry._status = detail::status_from_INFO(_current, &_findData, ec, &_dir_entry._file_size, &_dir_entry._last_write_time); + _dir_entry._status = detail::status_from_INFO(_dir_entry._path, &_findData, ec, &_dir_entry._file_size, &_dir_entry._last_write_time); _dir_entry._symlink_status = _dir_entry._status; } if (ec) { @@ -5444,7 +5470,6 @@ public: directory_options _options; WIN32_FIND_DATAW _findData; HANDLE _dirHandle; - path _current; directory_entry _dir_entry; std::error_code _ec; }; @@ -5489,9 +5514,9 @@ public: errno = 0; _entry = ::readdir(_dir); if (_entry) { - _current = _base; - _current.append_name(_entry->d_name); - _dir_entry.assign(_current, ec); + _dir_entry._path = _base; + _dir_entry._path.append_name(_entry->d_name); + copyToDirEntry(); if (ec && (ec.value() == EACCES || ec.value() == EPERM) && (_options & directory_options::skip_permission_denied) == directory_options::skip_permission_denied) { ec.clear(); skip = true; @@ -5500,7 +5525,7 @@ public: else { ::closedir(_dir); _dir = nullptr; - _current = path(); + _dir_entry._path.clear(); if (errno) { ec = detail::make_system_error(); } @@ -5509,9 +5534,32 @@ public: } while (skip || std::strcmp(_entry->d_name, ".") == 0 || std::strcmp(_entry->d_name, "..") == 0); } } + void copyToDirEntry() + { + _dir_entry._symlink_status.permissions(perms::unknown); + switch(_entry->d_type) { + case DT_BLK: _dir_entry._symlink_status.type(file_type::block); break; + case DT_CHR: _dir_entry._symlink_status.type(file_type::character); break; + case DT_DIR: _dir_entry._symlink_status.type(file_type::directory); break; + case DT_FIFO: _dir_entry._symlink_status.type(file_type::fifo); break; + case DT_LNK: _dir_entry._symlink_status.type(file_type::symlink); break; + case DT_REG: _dir_entry._symlink_status.type(file_type::regular); break; + case DT_SOCK: _dir_entry._symlink_status.type(file_type::socket); break; + default: _dir_entry._symlink_status.type(file_type::unknown); break; + } + if (_entry->d_type != DT_LNK) { + _dir_entry._status = _dir_entry._symlink_status; + } + else { + _dir_entry._status.type(file_type::none); + _dir_entry._status.permissions(perms::unknown); + } + _dir_entry._file_size = static_cast(-1); + _dir_entry._hard_link_count = static_cast(-1); + _dir_entry._last_write_time = 0; + } path _base; directory_options _options; - path _current; DIR* _dir; struct ::dirent* _entry; directory_entry _dir_entry; @@ -5600,7 +5648,7 @@ GHC_INLINE directory_iterator& directory_iterator::operator++() std::error_code ec; _impl->increment(ec); if (ec) { - throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_current, ec); + throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_entry._path, ec); } return *this; } @@ -5614,12 +5662,12 @@ GHC_INLINE directory_iterator& directory_iterator::increment(std::error_code& ec GHC_INLINE bool directory_iterator::operator==(const directory_iterator& rhs) const { - return _impl->_current == rhs._impl->_current; + return _impl->_dir_entry._path == rhs._impl->_dir_entry._path; } GHC_INLINE bool directory_iterator::operator!=(const directory_iterator& rhs) const { - return _impl->_current != rhs._impl->_current; + return _impl->_dir_entry._path != rhs._impl->_dir_entry._path; } // 30.10.13.2 directory_iterator non-member functions