mirror of
https://github.com/mhx/dwarfs.git
synced 2025-09-08 03:49:44 -04:00
refactor: delay file_stat errors
This commit is contained in:
parent
df6ff2ccbd
commit
1dfeb2e7f9
@ -26,11 +26,13 @@
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include <dwarfs/error.h>
|
||||
#include <dwarfs/file_type.h>
|
||||
|
||||
namespace dwarfs {
|
||||
|
||||
struct file_stat {
|
||||
using valid_fields_type = uint32_t;
|
||||
using perms_type = std::underlying_type_t<std::filesystem::perms>;
|
||||
using mode_type = uint32_t;
|
||||
using dev_type = uint64_t;
|
||||
@ -43,15 +45,22 @@ struct file_stat {
|
||||
using blkcnt_type = int64_t;
|
||||
using time_type = int64_t;
|
||||
|
||||
void ensure_valid(valid_fields_type fields) const;
|
||||
|
||||
std::filesystem::file_status status() const {
|
||||
ensure_valid(mode_valid);
|
||||
return file_mode_to_status(mode);
|
||||
};
|
||||
|
||||
posix_file_type::value type() const {
|
||||
ensure_valid(mode_valid);
|
||||
return static_cast<posix_file_type::value>(mode & posix_file_type::mask);
|
||||
};
|
||||
|
||||
perms_type permissions() const { return mode & 07777; };
|
||||
perms_type permissions() const {
|
||||
ensure_valid(mode_valid);
|
||||
return mode & 07777;
|
||||
};
|
||||
|
||||
void set_permissions(perms_type perms) { mode = type() | (perms & 07777); }
|
||||
|
||||
@ -69,6 +78,22 @@ struct file_stat {
|
||||
static std::string perm_string(mode_type mode);
|
||||
static std::string mode_string(mode_type mode);
|
||||
|
||||
static constexpr valid_fields_type dev_valid = 1 << 0;
|
||||
static constexpr valid_fields_type ino_valid = 1 << 1;
|
||||
static constexpr valid_fields_type nlink_valid = 1 << 2;
|
||||
static constexpr valid_fields_type mode_valid = 1 << 3;
|
||||
static constexpr valid_fields_type uid_valid = 1 << 4;
|
||||
static constexpr valid_fields_type gid_valid = 1 << 5;
|
||||
static constexpr valid_fields_type rdev_valid = 1 << 6;
|
||||
static constexpr valid_fields_type size_valid = 1 << 7;
|
||||
static constexpr valid_fields_type blksize_valid = 1 << 8;
|
||||
static constexpr valid_fields_type blocks_valid = 1 << 9;
|
||||
static constexpr valid_fields_type atime_valid = 1 << 10;
|
||||
static constexpr valid_fields_type mtime_valid = 1 << 11;
|
||||
static constexpr valid_fields_type ctime_valid = 1 << 12;
|
||||
static constexpr valid_fields_type all_valid = (1 << 13) - 1;
|
||||
|
||||
uint32_t valid_fields{0};
|
||||
dev_type dev;
|
||||
ino_type ino;
|
||||
nlink_type nlink;
|
||||
@ -82,6 +107,7 @@ struct file_stat {
|
||||
time_type atime;
|
||||
time_type mtime;
|
||||
time_type ctime;
|
||||
std::exception_ptr exception;
|
||||
};
|
||||
|
||||
file_stat make_file_stat(std::filesystem::path const& path);
|
||||
|
@ -84,7 +84,7 @@ class entry : public entry_interface {
|
||||
std::string unix_dpath() const override;
|
||||
std::string const& name() const override { return name_; }
|
||||
bool less_revpath(entry const& rhs) const;
|
||||
size_t size() const override { return stat_.size; }
|
||||
size_t size() const override;
|
||||
virtual type_t type() const = 0;
|
||||
bool is_directory() const override;
|
||||
virtual void walk(std::function<void(entry*)> const& f);
|
||||
@ -97,8 +97,8 @@ class entry : public entry_interface {
|
||||
file_stat const& status() const { return stat_; }
|
||||
void set_entry_index(uint32_t index) { entry_index_ = index; }
|
||||
std::optional<uint32_t> const& entry_index() const { return entry_index_; }
|
||||
uint64_t raw_inode_num() const { return stat_.ino; }
|
||||
uint64_t num_hard_links() const { return stat_.nlink; }
|
||||
uint64_t raw_inode_num() const;
|
||||
uint64_t num_hard_links() const;
|
||||
virtual void set_inode_num(uint32_t ino) = 0;
|
||||
virtual std::optional<uint32_t> const& inode_num() const = 0;
|
||||
|
||||
@ -116,7 +116,7 @@ class entry : public entry_interface {
|
||||
uint64_t get_ctime() const override;
|
||||
void set_ctime(uint64_t ctime) override;
|
||||
|
||||
void override_size(size_t size) { stat_.size = size; }
|
||||
void override_size(size_t size);
|
||||
|
||||
private:
|
||||
std::u8string u8name() const;
|
||||
|
@ -101,7 +101,19 @@ void perms_to_stream(std::ostream& os, file_stat::mode_type mode) {
|
||||
#ifdef _WIN32
|
||||
|
||||
file_stat make_file_stat(fs::path const& path) {
|
||||
auto status = fs::symlink_status(path);
|
||||
std::error_code ec;
|
||||
auto status = fs::symlink_status(path, ec);
|
||||
|
||||
if (ec) {
|
||||
status = fs::status(path, ec);
|
||||
}
|
||||
|
||||
file_stat rv;
|
||||
|
||||
if (ec) {
|
||||
rv.exception = std::make_exception_ptr(std::system_error(ec));
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (status.type() == fs::file_type::not_found ||
|
||||
status.type() == fs::file_type::unknown) {
|
||||
@ -113,7 +125,7 @@ file_stat make_file_stat(fs::path const& path) {
|
||||
u8string_to_string(path.u8string())));
|
||||
}
|
||||
|
||||
file_stat rv;
|
||||
rv.valid_fields = file_stat::mode_valid;
|
||||
rv.mode = file_status_to_mode(status);
|
||||
rv.blksize = 0;
|
||||
rv.blocks = 0;
|
||||
@ -124,64 +136,75 @@ file_stat make_file_stat(fs::path const& path) {
|
||||
::WIN32_FILE_ATTRIBUTE_DATA info;
|
||||
if (::GetFileAttributesExW(wps.c_str(), GetFileExInfoStandard, &info) ==
|
||||
0) {
|
||||
throw std::system_error(::GetLastError(), std::system_category(),
|
||||
"GetFileAttributesExW");
|
||||
rv.exception = std::make_exception_ptr(std::system_error(
|
||||
::GetLastError(), std::system_category(), "GetFileAttributesExW"));
|
||||
} else {
|
||||
rv.valid_fields = file_stat::all_valid;
|
||||
rv.dev = 0;
|
||||
rv.ino = 0;
|
||||
rv.nlink = 0;
|
||||
rv.uid = 0;
|
||||
rv.gid = 0;
|
||||
rv.rdev = 0;
|
||||
rv.size =
|
||||
(static_cast<uint64_t>(info.nFileSizeHigh) << 32) + info.nFileSizeLow;
|
||||
rv.atime = time_from_filetime(info.ftLastAccessTime);
|
||||
rv.mtime = time_from_filetime(info.ftLastWriteTime);
|
||||
rv.ctime = time_from_filetime(info.ftCreationTime);
|
||||
}
|
||||
rv.dev = 0;
|
||||
rv.ino = 0;
|
||||
rv.nlink = 0;
|
||||
rv.uid = 0;
|
||||
rv.gid = 0;
|
||||
rv.rdev = 0;
|
||||
rv.size =
|
||||
(static_cast<uint64_t>(info.nFileSizeHigh) << 32) + info.nFileSizeLow;
|
||||
rv.atime = time_from_filetime(info.ftLastAccessTime);
|
||||
rv.mtime = time_from_filetime(info.ftLastWriteTime);
|
||||
rv.ctime = time_from_filetime(info.ftCreationTime);
|
||||
} else {
|
||||
struct ::__stat64 st;
|
||||
|
||||
if (::_wstat64(wps.c_str(), &st) != 0) {
|
||||
throw std::system_error(errno, std::generic_category(), "_stat64");
|
||||
}
|
||||
if (::_wstat64(wps.c_str(), &st) == 0) {
|
||||
if (status.type() == fs::file_type::regular) {
|
||||
::HANDLE hdl =
|
||||
::CreateFileW(wps.c_str(), 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
|
||||
|
||||
if (status.type() == fs::file_type::regular) {
|
||||
::HANDLE hdl =
|
||||
::CreateFileW(wps.c_str(), 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
|
||||
|
||||
if (hdl == INVALID_HANDLE_VALUE) {
|
||||
throw std::system_error(::GetLastError(), std::system_category(),
|
||||
fmt::format("CreateFileW({})", path.string()));
|
||||
if (hdl != INVALID_HANDLE_VALUE) {
|
||||
::BY_HANDLE_FILE_INFORMATION info;
|
||||
if (::GetFileInformationByHandle(hdl, &info)) {
|
||||
if (::CloseHandle(hdl)) {
|
||||
rv.valid_fields |= file_stat::ino_valid | file_stat::nlink_valid;
|
||||
rv.ino = (static_cast<uint64_t>(info.nFileIndexHigh) << 32) +
|
||||
info.nFileIndexLow;
|
||||
rv.nlink = info.nNumberOfLinks;
|
||||
} else {
|
||||
rv.exception = std::make_exception_ptr(std::system_error(
|
||||
::GetLastError(), std::system_category(), "CloseHandle"));
|
||||
}
|
||||
} else {
|
||||
rv.exception = std::make_exception_ptr(
|
||||
std::system_error(::GetLastError(), std::system_category(),
|
||||
"GetFileInformationByHandle"));
|
||||
::CloseHandle(hdl);
|
||||
}
|
||||
} else {
|
||||
rv.exception = std::make_exception_ptr(std::system_error(
|
||||
::GetLastError(), std::system_category(), "CreateFileW"));
|
||||
}
|
||||
} else {
|
||||
rv.valid_fields |= file_stat::ino_valid | file_stat::nlink_valid;
|
||||
rv.ino = st.st_ino;
|
||||
rv.nlink = st.st_nlink;
|
||||
}
|
||||
|
||||
::BY_HANDLE_FILE_INFORMATION info;
|
||||
if (!::GetFileInformationByHandle(hdl, &info)) {
|
||||
throw std::system_error(::GetLastError(), std::system_category(),
|
||||
"GetFileInformationByHandle");
|
||||
}
|
||||
|
||||
if (!::CloseHandle(hdl)) {
|
||||
throw std::system_error(::GetLastError(), std::system_category(),
|
||||
"CloseHandle");
|
||||
}
|
||||
|
||||
rv.ino = (static_cast<uint64_t>(info.nFileIndexHigh) << 32) +
|
||||
info.nFileIndexLow;
|
||||
rv.nlink = info.nNumberOfLinks;
|
||||
rv.valid_fields |= file_stat::dev_valid | file_stat::uid_valid |
|
||||
file_stat::gid_valid | file_stat::rdev_valid |
|
||||
file_stat::size_valid | file_stat::atime_valid |
|
||||
file_stat::mtime_valid | file_stat::ctime_valid;
|
||||
rv.dev = st.st_dev;
|
||||
rv.uid = st.st_uid;
|
||||
rv.gid = st.st_gid;
|
||||
rv.rdev = st.st_rdev;
|
||||
rv.size = st.st_size;
|
||||
rv.atime = st.st_atime;
|
||||
rv.mtime = st.st_mtime;
|
||||
rv.ctime = st.st_ctime;
|
||||
} else {
|
||||
rv.ino = st.st_ino;
|
||||
rv.nlink = st.st_nlink;
|
||||
rv.exception = std::make_exception_ptr(
|
||||
std::system_error(errno, std::generic_category(), "_stat64"));
|
||||
}
|
||||
|
||||
rv.dev = st.st_dev;
|
||||
rv.uid = st.st_uid;
|
||||
rv.gid = st.st_gid;
|
||||
rv.rdev = st.st_rdev;
|
||||
rv.size = st.st_size;
|
||||
rv.atime = st.st_atime;
|
||||
rv.mtime = st.st_mtime;
|
||||
rv.ctime = st.st_ctime;
|
||||
}
|
||||
|
||||
return rv;
|
||||
@ -197,6 +220,7 @@ file_stat make_file_stat(fs::path const& path) {
|
||||
}
|
||||
|
||||
file_stat rv;
|
||||
rv.valid_fields = file_stat::all_valid;
|
||||
rv.dev = st.st_dev;
|
||||
rv.ino = st.st_ino;
|
||||
rv.nlink = st.st_nlink;
|
||||
@ -240,4 +264,16 @@ std::string file_stat::perm_string(mode_type mode) {
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void file_stat::ensure_valid(valid_fields_type fields) const {
|
||||
if ((valid_fields & fields) != fields) {
|
||||
if (exception) {
|
||||
std::rethrow_exception(exception);
|
||||
} else {
|
||||
DWARFS_THROW(runtime_error,
|
||||
fmt::format("missing stat fields: {:#x} (have: {:#x})",
|
||||
fields, valid_fields));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dwarfs
|
||||
|
@ -147,6 +147,9 @@ void entry::walk(std::function<void(entry*)> const& f) { f(this); }
|
||||
void entry::walk(std::function<void(const entry*)> const& f) const { f(this); }
|
||||
|
||||
void entry::update(global_entry_data& data) const {
|
||||
stat_.ensure_valid(file_stat::uid_valid | file_stat::gid_valid |
|
||||
file_stat::mode_valid | file_stat::atime_valid |
|
||||
file_stat::mtime_valid | file_stat::ctime_valid);
|
||||
data.add_uid(stat_.uid);
|
||||
data.add_gid(stat_.gid);
|
||||
data.add_mode(stat_.mode);
|
||||
@ -157,6 +160,9 @@ void entry::update(global_entry_data& data) const {
|
||||
|
||||
void entry::pack(thrift::metadata::inode_data& entry_v2,
|
||||
global_entry_data const& data) const {
|
||||
stat_.ensure_valid(file_stat::uid_valid | file_stat::gid_valid |
|
||||
file_stat::mode_valid | file_stat::atime_valid |
|
||||
file_stat::mtime_valid | file_stat::ctime_valid);
|
||||
entry_v2.mode_index() = data.get_mode_index(stat_.mode);
|
||||
entry_v2.owner_index() = data.get_uid_index(stat_.uid);
|
||||
entry_v2.group_index() = data.get_gid_index(stat_.gid);
|
||||
@ -165,31 +171,81 @@ void entry::pack(thrift::metadata::inode_data& entry_v2,
|
||||
entry_v2.ctime_offset() = data.get_ctime_offset(stat_.ctime);
|
||||
}
|
||||
|
||||
size_t entry::size() const {
|
||||
stat_.ensure_valid(file_stat::size_valid);
|
||||
return stat_.size;
|
||||
}
|
||||
|
||||
uint64_t entry::raw_inode_num() const {
|
||||
stat_.ensure_valid(file_stat::ino_valid);
|
||||
return stat_.ino;
|
||||
}
|
||||
|
||||
uint64_t entry::num_hard_links() const {
|
||||
stat_.ensure_valid(file_stat::nlink_valid);
|
||||
return stat_.nlink;
|
||||
}
|
||||
|
||||
void entry::override_size(size_t size) {
|
||||
stat_.size = size;
|
||||
stat_.valid_fields |= file_stat::size_valid;
|
||||
}
|
||||
|
||||
entry::type_t file::type() const { return E_FILE; }
|
||||
|
||||
auto entry::get_permissions() const -> mode_type { return stat_.permissions(); }
|
||||
|
||||
void entry::set_permissions(mode_type perm) { stat_.set_permissions(perm); }
|
||||
|
||||
auto entry::get_uid() const -> uid_type { return stat_.uid; }
|
||||
auto entry::get_uid() const -> uid_type {
|
||||
stat_.ensure_valid(file_stat::uid_valid);
|
||||
return stat_.uid;
|
||||
}
|
||||
|
||||
void entry::set_uid(uid_type uid) { stat_.uid = uid; }
|
||||
void entry::set_uid(uid_type uid) {
|
||||
stat_.uid = uid;
|
||||
stat_.valid_fields |= file_stat::uid_valid;
|
||||
}
|
||||
|
||||
auto entry::get_gid() const -> gid_type { return stat_.gid; }
|
||||
auto entry::get_gid() const -> gid_type {
|
||||
stat_.ensure_valid(file_stat::gid_valid);
|
||||
return stat_.gid;
|
||||
}
|
||||
|
||||
void entry::set_gid(gid_type gid) { stat_.gid = gid; }
|
||||
void entry::set_gid(gid_type gid) {
|
||||
stat_.gid = gid;
|
||||
stat_.valid_fields |= file_stat::gid_valid;
|
||||
}
|
||||
|
||||
uint64_t entry::get_atime() const { return stat_.atime; }
|
||||
uint64_t entry::get_atime() const {
|
||||
stat_.ensure_valid(file_stat::atime_valid);
|
||||
return stat_.atime;
|
||||
}
|
||||
|
||||
void entry::set_atime(uint64_t atime) { stat_.atime = atime; }
|
||||
void entry::set_atime(uint64_t atime) {
|
||||
stat_.atime = atime;
|
||||
stat_.valid_fields |= file_stat::atime_valid;
|
||||
}
|
||||
|
||||
uint64_t entry::get_mtime() const { return stat_.mtime; }
|
||||
uint64_t entry::get_mtime() const {
|
||||
stat_.ensure_valid(file_stat::mtime_valid);
|
||||
return stat_.mtime;
|
||||
}
|
||||
|
||||
void entry::set_mtime(uint64_t mtime) { stat_.mtime = mtime; }
|
||||
void entry::set_mtime(uint64_t mtime) {
|
||||
stat_.mtime = mtime;
|
||||
stat_.valid_fields |= file_stat::mtime_valid;
|
||||
}
|
||||
|
||||
uint64_t entry::get_ctime() const { return stat_.ctime; }
|
||||
uint64_t entry::get_ctime() const {
|
||||
stat_.ensure_valid(file_stat::ctime_valid);
|
||||
return stat_.ctime;
|
||||
}
|
||||
|
||||
void entry::set_ctime(uint64_t ctime) { stat_.ctime = ctime; }
|
||||
void entry::set_ctime(uint64_t ctime) {
|
||||
stat_.ctime = ctime;
|
||||
stat_.valid_fields |= file_stat::ctime_valid;
|
||||
}
|
||||
|
||||
std::string_view file::hash() const {
|
||||
auto& h = data_->hash;
|
||||
|
@ -1542,6 +1542,8 @@ metadata_<LoggerPolicy>::getattr_impl(inode_view iv,
|
||||
|
||||
::memset(&stbuf, 0, sizeof(stbuf));
|
||||
|
||||
stbuf.valid_fields = file_stat::all_valid;
|
||||
|
||||
auto mode = iv.mode();
|
||||
auto timebase = meta_.timestamp_base();
|
||||
auto inode = iv.inode_num();
|
||||
|
@ -50,6 +50,7 @@ namespace {
|
||||
file_stat make_file_stat(simplestat const& ss) {
|
||||
file_stat rv;
|
||||
::memset(&rv, 0, sizeof(rv));
|
||||
rv.valid_fields = file_stat::all_valid;
|
||||
rv.ino = ss.ino;
|
||||
rv.nlink = ss.nlink;
|
||||
rv.mode = ss.mode;
|
||||
|
Loading…
x
Reference in New Issue
Block a user