Please use GitHub pull requests for new patches. Avoid migrating existing patches. Phabricator shutdown timeline
Changeset View
Changeset View
Standalone View
Standalone View
src/experimental/filesystem/operations.cpp
Show All 17 Lines | |||||
#include "cstdlib" | #include "cstdlib" | ||||
#include "climits" | #include "climits" | ||||
#include "filesystem_common.h" | #include "filesystem_common.h" | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#include <sys/stat.h> | #include <sys/stat.h> | ||||
#include <sys/statvfs.h> | #include <sys/statvfs.h> | ||||
#include <time.h> | |||||
#include <fcntl.h> /* values for fchmodat */ | #include <fcntl.h> /* values for fchmodat */ | ||||
#if defined(__linux__) | #if defined(__linux__) | ||||
# include <linux/version.h> | # include <linux/version.h> | ||||
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33) | # if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33) | ||||
# include <sys/sendfile.h> | # include <sys/sendfile.h> | ||||
# define _LIBCPP_USE_SENDFILE | # define _LIBCPP_USE_SENDFILE | ||||
# endif | # endif | ||||
#elif defined(__APPLE__) || __has_include(<copyfile.h>) | #elif defined(__APPLE__) || __has_include(<copyfile.h>) | ||||
#include <copyfile.h> | #include <copyfile.h> | ||||
# define _LIBCPP_USE_COPYFILE | # define _LIBCPP_USE_COPYFILE | ||||
#endif | #endif | ||||
#if !defined(__APPLE__) | |||||
#define _LIBCPP_USE_CLOCK_GETTIME | |||||
#endif | |||||
#if !defined(CLOCK_REALTIME) || !defined(_LIBCPP_USE_CLOCK_GETTIME) | |||||
#include <sys/time.h> // for gettimeofday and timeval | |||||
#endif // !defined(CLOCK_REALTIME) | |||||
#if defined(_LIBCPP_COMPILER_GCC) | #if defined(_LIBCPP_COMPILER_GCC) | ||||
#if _GNUC_VER < 500 | #if _GNUC_VER < 500 | ||||
#pragma GCC diagnostic ignored "-Wmissing-field-initializers" | #pragma GCC diagnostic ignored "-Wmissing-field-initializers" | ||||
#endif | #endif | ||||
#endif | #endif | ||||
_LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM | _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL_FILESYSTEM | ||||
filesystem_error::~filesystem_error() {} | |||||
namespace { namespace parser | namespace { namespace parser | ||||
{ | { | ||||
using string_view_t = path::__string_view; | using string_view_t = path::__string_view; | ||||
using string_view_pair = pair<string_view_t, string_view_t>; | using string_view_pair = pair<string_view_t, string_view_t>; | ||||
using PosPtr = path::value_type const*; | using PosPtr = path::value_type const*; | ||||
struct PathParser { | struct PathParser { | ||||
▲ Show 20 Lines • Show All 292 Lines • ▼ Show 20 Lines | struct FileDescriptor { | ||||
FileDescriptor() = default; | FileDescriptor() = default; | ||||
FileDescriptor(FileDescriptor const&) = delete; | FileDescriptor(FileDescriptor const&) = delete; | ||||
FileDescriptor& operator=(FileDescriptor const&) = delete; | FileDescriptor& operator=(FileDescriptor const&) = delete; | ||||
private: | private: | ||||
explicit FileDescriptor(const path* p, int fd = -1) : name(*p), fd(fd) {} | explicit FileDescriptor(const path* p, int fd = -1) : name(*p), fd(fd) {} | ||||
}; | }; | ||||
perms posix_get_perms(const struct ::stat& st) noexcept { | perms posix_get_perms(const StatT& st) noexcept { | ||||
return static_cast<perms>(st.st_mode) & perms::mask; | return static_cast<perms>(st.st_mode) & perms::mask; | ||||
} | } | ||||
::mode_t posix_convert_perms(perms prms) { | ::mode_t posix_convert_perms(perms prms) { | ||||
return static_cast< ::mode_t>(prms & perms::mask); | return static_cast< ::mode_t>(prms & perms::mask); | ||||
} | } | ||||
file_status create_file_status(error_code& m_ec, path const& p, | file_status create_file_status(error_code& m_ec, path const& p, | ||||
const struct ::stat& path_stat, | const StatT& path_stat, error_code* ec) { | ||||
error_code* ec) { | |||||
if (ec) | if (ec) | ||||
*ec = m_ec; | *ec = m_ec; | ||||
if (m_ec && (m_ec.value() == ENOENT || m_ec.value() == ENOTDIR)) { | if (m_ec && (m_ec.value() == ENOENT || m_ec.value() == ENOTDIR)) { | ||||
return file_status(file_type::not_found); | return file_status(file_type::not_found); | ||||
} else if (m_ec) { | } else if (m_ec) { | ||||
ErrorHandler<void> err("posix_stat", ec, &p); | ErrorHandler<void> err("posix_stat", ec, &p); | ||||
err.report(m_ec, "failed to determine attributes for the specified path"); | err.report(m_ec, "failed to determine attributes for the specified path"); | ||||
return file_status(file_type::none); | return file_status(file_type::none); | ||||
Show All 18 Lines | else if (S_ISSOCK(mode)) | ||||
fs_tmp.type(file_type::socket); | fs_tmp.type(file_type::socket); | ||||
else | else | ||||
fs_tmp.type(file_type::unknown); | fs_tmp.type(file_type::unknown); | ||||
fs_tmp.permissions(detail::posix_get_perms(path_stat)); | fs_tmp.permissions(detail::posix_get_perms(path_stat)); | ||||
return fs_tmp; | return fs_tmp; | ||||
} | } | ||||
file_status posix_stat(path const& p, struct ::stat& path_stat, | file_status posix_stat(path const& p, StatT& path_stat, error_code* ec) { | ||||
error_code* ec) { | |||||
error_code m_ec; | error_code m_ec; | ||||
if (::stat(p.c_str(), &path_stat) == -1) | if (::stat(p.c_str(), &path_stat) == -1) | ||||
m_ec = detail::capture_errno(); | m_ec = detail::capture_errno(); | ||||
return create_file_status(m_ec, p, path_stat, ec); | return create_file_status(m_ec, p, path_stat, ec); | ||||
} | } | ||||
file_status posix_stat(path const& p, error_code* ec) { | file_status posix_stat(path const& p, error_code* ec) { | ||||
struct ::stat path_stat; | StatT path_stat; | ||||
return posix_stat(p, path_stat, ec); | return posix_stat(p, path_stat, ec); | ||||
} | } | ||||
file_status posix_lstat(path const& p, struct ::stat& path_stat, | file_status posix_lstat(path const& p, StatT& path_stat, error_code* ec) { | ||||
error_code* ec) { | |||||
error_code m_ec; | error_code m_ec; | ||||
if (::lstat(p.c_str(), &path_stat) == -1) | if (::lstat(p.c_str(), &path_stat) == -1) | ||||
m_ec = detail::capture_errno(); | m_ec = detail::capture_errno(); | ||||
return create_file_status(m_ec, p, path_stat, ec); | return create_file_status(m_ec, p, path_stat, ec); | ||||
} | } | ||||
file_status posix_lstat(path const& p, error_code* ec) { | file_status posix_lstat(path const& p, error_code* ec) { | ||||
struct ::stat path_stat; | StatT path_stat; | ||||
return posix_lstat(p, path_stat, ec); | return posix_lstat(p, path_stat, ec); | ||||
} | } | ||||
bool posix_ftruncate(const FileDescriptor& fd, size_t to_size, | bool posix_ftruncate(const FileDescriptor& fd, size_t to_size, | ||||
error_code& ec) { | error_code& ec) { | ||||
if (::ftruncate(fd.fd, to_size) == -1) { | if (::ftruncate(fd.fd, to_size) == -1) { | ||||
ec = capture_errno(); | ec = capture_errno(); | ||||
return false; | return false; | ||||
Show All 25 Lines | file_status FileDescriptor::refresh_status(error_code& ec) { | ||||
m_status = create_file_status(m_ec, name, m_stat, &ec); | m_status = create_file_status(m_ec, name, m_stat, &ec); | ||||
return m_status; | return m_status; | ||||
} | } | ||||
}} // end namespace detail | }} // end namespace detail | ||||
using detail::capture_errno; | using detail::capture_errno; | ||||
using detail::ErrorHandler; | using detail::ErrorHandler; | ||||
using detail::StatT; | using detail::StatT; | ||||
using detail::TimeSpec; | |||||
using parser::createView; | using parser::createView; | ||||
using parser::PathParser; | using parser::PathParser; | ||||
using parser::string_view_t; | using parser::string_view_t; | ||||
const bool _FilesystemClock::is_steady; | |||||
_FilesystemClock::time_point _FilesystemClock::now() noexcept { | |||||
typedef chrono::duration<rep> __secs; | |||||
#if defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_REALTIME) | |||||
typedef chrono::duration<rep, nano> __nsecs; | |||||
struct timespec tp; | |||||
if (0 != clock_gettime(CLOCK_REALTIME, &tp)) | |||||
__throw_system_error(errno, "clock_gettime(CLOCK_REALTIME) failed"); | |||||
return time_point(__secs(tp.tv_sec) + | |||||
chrono::duration_cast<duration>(__nsecs(tp.tv_nsec))); | |||||
#else | |||||
typedef chrono::duration<rep, micro> __microsecs; | |||||
timeval tv; | |||||
gettimeofday(&tv, 0); | |||||
return time_point(__secs(tv.tv_sec) + __microsecs(tv.tv_usec)); | |||||
#endif // _LIBCPP_USE_CLOCK_GETTIME && CLOCK_REALTIME | |||||
} | |||||
filesystem_error::~filesystem_error() {} | |||||
void filesystem_error::__create_what(int __num_paths) { | void filesystem_error::__create_what(int __num_paths) { | ||||
const char* derived_what = system_error::what(); | const char* derived_what = system_error::what(); | ||||
__storage_->__what_ = [&]() -> string { | __storage_->__what_ = [&]() -> string { | ||||
const char* p1 = path1().native().empty() ? "\"\"" : path1().c_str(); | const char* p1 = path1().native().empty() ? "\"\"" : path1().c_str(); | ||||
const char* p2 = path2().native().empty() ? "\"\"" : path2().c_str(); | const char* p2 = path2().native().empty() ? "\"\"" : path2().c_str(); | ||||
switch (__num_paths) { | switch (__num_paths) { | ||||
default: | default: | ||||
return detail::format_string("filesystem error: %s", derived_what); | return detail::format_string("filesystem error: %s", derived_what); | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | void __copy(const path& from, const path& to, copy_options options, | ||||
ErrorHandler<void> err("copy", ec, &from, &to); | ErrorHandler<void> err("copy", ec, &from, &to); | ||||
const bool sym_status = bool( | const bool sym_status = bool( | ||||
options & (copy_options::create_symlinks | copy_options::skip_symlinks)); | options & (copy_options::create_symlinks | copy_options::skip_symlinks)); | ||||
const bool sym_status2 = bool(options & copy_options::copy_symlinks); | const bool sym_status2 = bool(options & copy_options::copy_symlinks); | ||||
error_code m_ec1; | error_code m_ec1; | ||||
struct ::stat f_st = {}; | StatT f_st = {}; | ||||
const file_status f = sym_status || sym_status2 | const file_status f = sym_status || sym_status2 | ||||
? detail::posix_lstat(from, f_st, &m_ec1) | ? detail::posix_lstat(from, f_st, &m_ec1) | ||||
: detail::posix_stat(from, f_st, &m_ec1); | : detail::posix_stat(from, f_st, &m_ec1); | ||||
if (m_ec1) | if (m_ec1) | ||||
return err.report(m_ec1); | return err.report(m_ec1); | ||||
struct ::stat t_st = {}; | StatT t_st = {}; | ||||
const file_status t = sym_status ? detail::posix_lstat(to, t_st, &m_ec1) | const file_status t = sym_status ? detail::posix_lstat(to, t_st, &m_ec1) | ||||
: detail::posix_stat(to, t_st, &m_ec1); | : detail::posix_stat(to, t_st, &m_ec1); | ||||
if (not status_known(t)) | if (not status_known(t)) | ||||
return err.report(m_ec1); | return err.report(m_ec1); | ||||
if (!exists(f) || is_other(f) || is_other(t) || | if (!exists(f) || is_other(f) || is_other(t) || | ||||
(is_directory(f) && is_regular_file(t)) || | (is_directory(f) && is_regular_file(t)) || | ||||
▲ Show 20 Lines • Show All 367 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
uintmax_t __file_size(const path& p, error_code *ec) | uintmax_t __file_size(const path& p, error_code *ec) | ||||
{ | { | ||||
ErrorHandler<uintmax_t> err("file_size", ec, &p); | ErrorHandler<uintmax_t> err("file_size", ec, &p); | ||||
error_code m_ec; | error_code m_ec; | ||||
struct ::stat st; | StatT st; | ||||
file_status fst = detail::posix_stat(p, st, &m_ec); | file_status fst = detail::posix_stat(p, st, &m_ec); | ||||
if (!exists(fst) || !is_regular_file(fst)) { | if (!exists(fst) || !is_regular_file(fst)) { | ||||
errc error_kind = | errc error_kind = | ||||
is_directory(fst) ? errc::is_a_directory : errc::not_supported; | is_directory(fst) ? errc::is_a_directory : errc::not_supported; | ||||
if (!m_ec) | if (!m_ec) | ||||
m_ec = make_error_code(error_kind); | m_ec = make_error_code(error_kind); | ||||
return err.report(m_ec); | return err.report(m_ec); | ||||
} | } | ||||
Show All 33 Lines | bool __fs_is_empty(const path& p, error_code *ec) | ||||
} else if (is_regular_file(st)) | } else if (is_regular_file(st)) | ||||
return static_cast<uintmax_t>(pst.st_size) == 0; | return static_cast<uintmax_t>(pst.st_size) == 0; | ||||
_LIBCPP_UNREACHABLE(); | _LIBCPP_UNREACHABLE(); | ||||
} | } | ||||
static file_time_type __extract_last_write_time(const path& p, const StatT& st, | static file_time_type __extract_last_write_time(const path& p, const StatT& st, | ||||
error_code* ec) { | error_code* ec) { | ||||
using detail::FSTime; | using detail::fs_time; | ||||
ErrorHandler<file_time_type> err("last_write_time", ec, &p); | ErrorHandler<file_time_type> err("last_write_time", ec, &p); | ||||
auto ts = detail::extract_mtime(st); | auto ts = detail::extract_mtime(st); | ||||
if (!FSTime::is_representable(ts)) | if (!fs_time::is_representable(ts)) | ||||
return err.report(errc::value_too_large); | return err.report(errc::value_too_large); | ||||
return FSTime::convert_timespec(ts); | return fs_time::convert_from_timespec(ts); | ||||
} | } | ||||
file_time_type __last_write_time(const path& p, error_code *ec) | file_time_type __last_write_time(const path& p, error_code *ec) | ||||
{ | { | ||||
using namespace chrono; | using namespace chrono; | ||||
ErrorHandler<file_time_type> err("last_write_time", ec, &p); | ErrorHandler<file_time_type> err("last_write_time", ec, &p); | ||||
error_code m_ec; | error_code m_ec; | ||||
StatT st; | StatT st; | ||||
detail::posix_stat(p, st, &m_ec); | detail::posix_stat(p, st, &m_ec); | ||||
if (m_ec) | if (m_ec) | ||||
return err.report(m_ec); | return err.report(m_ec); | ||||
return __extract_last_write_time(p, st, ec); | return __extract_last_write_time(p, st, ec); | ||||
} | } | ||||
void __last_write_time(const path& p, file_time_type new_time, | void __last_write_time(const path& p, file_time_type new_time, | ||||
error_code *ec) | error_code *ec) | ||||
{ | { | ||||
using namespace chrono; | |||||
using namespace detail; | |||||
ErrorHandler<void> err("last_write_time", ec, &p); | ErrorHandler<void> err("last_write_time", ec, &p); | ||||
error_code m_ec; | error_code m_ec; | ||||
TimeStructArray tbuf; | array<TimeSpec, 2> tbuf; | ||||
#if !defined(_LIBCXX_USE_UTIMENSAT) | #if !defined(_LIBCPP_USE_UTIMENSAT) | ||||
// This implementation has a race condition between determining the | // This implementation has a race condition between determining the | ||||
// last access time and attempting to set it to the same value using | // last access time and attempting to set it to the same value using | ||||
// ::utimes | // ::utimes | ||||
struct ::stat st; | StatT st; | ||||
file_status fst = detail::posix_stat(p, st, &m_ec); | file_status fst = detail::posix_stat(p, st, &m_ec); | ||||
if (m_ec && !status_known(fst)) | if (m_ec) | ||||
return err.report(m_ec); | return err.report(m_ec); | ||||
SetTimeStructTo(tbuf[0], detail::extract_atime(st)); | tbuf[0] = detail::extract_atime(st); | ||||
#else | #else | ||||
tbuf[0].tv_sec = 0; | tbuf[0].tv_sec = 0; | ||||
tbuf[0].tv_nsec = UTIME_OMIT; | tbuf[0].tv_nsec = UTIME_OMIT; | ||||
#endif | #endif | ||||
if (SetTimeStructTo(tbuf[1], new_time)) | if (detail::set_time_spec_to(tbuf[1], new_time)) | ||||
return err.report(errc::invalid_argument); | return err.report(errc::value_too_large); | ||||
SetFileTimes(p, tbuf, m_ec); | detail::set_file_times(p, tbuf, m_ec); | ||||
if (m_ec) | if (m_ec) | ||||
return err.report(m_ec); | return err.report(m_ec); | ||||
} | } | ||||
void __permissions(const path& p, perms prms, perm_options opts, | void __permissions(const path& p, perms prms, perm_options opts, | ||||
error_code *ec) | error_code *ec) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 559 Lines • ▼ Show 20 Lines | |||||
// directory entry definitions | // directory entry definitions | ||||
/////////////////////////////////////////////////////////////////////////////// | /////////////////////////////////////////////////////////////////////////////// | ||||
#ifndef _LIBCPP_WIN32API | #ifndef _LIBCPP_WIN32API | ||||
error_code directory_entry::__do_refresh() noexcept { | error_code directory_entry::__do_refresh() noexcept { | ||||
__data_.__reset(); | __data_.__reset(); | ||||
error_code failure_ec; | error_code failure_ec; | ||||
struct ::stat full_st; | StatT full_st; | ||||
file_status st = detail::posix_lstat(__p_, full_st, &failure_ec); | file_status st = detail::posix_lstat(__p_, full_st, &failure_ec); | ||||
if (!status_known(st)) { | if (!status_known(st)) { | ||||
__data_.__reset(); | __data_.__reset(); | ||||
return failure_ec; | return failure_ec; | ||||
} | } | ||||
if (!_VSTD_FS::exists(st) || !_VSTD_FS::is_symlink(st)) { | if (!_VSTD_FS::exists(st) || !_VSTD_FS::is_symlink(st)) { | ||||
__data_.__cache_type_ = directory_entry::_RefreshNonSymlink; | __data_.__cache_type_ = directory_entry::_RefreshNonSymlink; | ||||
▲ Show 20 Lines • Show All 84 Lines • Show Last 20 Lines |