aboutsummaryrefslogtreecommitdiff
path: root/libcxx/src/filesystem/operations.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libcxx/src/filesystem/operations.cpp')
-rw-r--r--libcxx/src/filesystem/operations.cpp377
1 files changed, 232 insertions, 145 deletions
diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp
index 50a895dc2fae..5179eeae42b5 100644
--- a/libcxx/src/filesystem/operations.cpp
+++ b/libcxx/src/filesystem/operations.cpp
@@ -17,6 +17,8 @@
#include "filesystem_common.h"
+#include "posix_compat.h"
+
#if defined(_LIBCPP_WIN32API)
# define WIN32_LEAN_AND_MEAN
# define NOMINMAX
@@ -40,7 +42,7 @@
# define _LIBCPP_FILESYSTEM_USE_FSTREAM
#endif
-#if !defined(CLOCK_REALTIME)
+#if !defined(CLOCK_REALTIME) && !defined(_LIBCPP_WIN32API)
# include <sys/time.h> // for gettimeofday and timeval
#endif
@@ -62,6 +64,10 @@ bool isSeparator(path::value_type C) {
return false;
}
+bool isDriveLetter(path::value_type C) {
+ return (C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z');
+}
+
namespace parser {
using string_view_t = path::__string_view;
@@ -118,7 +124,13 @@ public:
switch (State) {
case PS_BeforeBegin: {
- PosPtr TkEnd = consumeSeparator(Start, End);
+ PosPtr TkEnd = consumeRootName(Start, End);
+ if (TkEnd)
+ return makeState(PS_InRootName, Start, TkEnd);
+ }
+ _LIBCPP_FALLTHROUGH();
+ case PS_InRootName: {
+ PosPtr TkEnd = consumeAllSeparators(Start, End);
if (TkEnd)
return makeState(PS_InRootDir, Start, TkEnd);
else
@@ -128,7 +140,7 @@ public:
return makeState(PS_InFilenames, Start, consumeName(Start, End));
case PS_InFilenames: {
- PosPtr SepEnd = consumeSeparator(Start, End);
+ PosPtr SepEnd = consumeAllSeparators(Start, End);
if (SepEnd != End) {
PosPtr TkEnd = consumeName(SepEnd, End);
if (TkEnd)
@@ -140,7 +152,6 @@ public:
case PS_InTrailingSep:
return makeState(PS_AtEnd);
- case PS_InRootName:
case PS_AtEnd:
_LIBCPP_UNREACHABLE();
}
@@ -155,12 +166,18 @@ public:
switch (State) {
case PS_AtEnd: {
// Try to consume a trailing separator or root directory first.
- if (PosPtr SepEnd = consumeSeparator(RStart, REnd)) {
+ if (PosPtr SepEnd = consumeAllSeparators(RStart, REnd)) {
if (SepEnd == REnd)
return makeState(PS_InRootDir, Path.data(), RStart + 1);
+ PosPtr TkStart = consumeRootName(SepEnd, REnd);
+ if (TkStart == REnd)
+ return makeState(PS_InRootDir, RStart, RStart + 1);
return makeState(PS_InTrailingSep, SepEnd + 1, RStart + 1);
} else {
- PosPtr TkStart = consumeName(RStart, REnd);
+ PosPtr TkStart = consumeRootName(RStart, REnd);
+ if (TkStart == REnd)
+ return makeState(PS_InRootName, TkStart + 1, RStart + 1);
+ TkStart = consumeName(RStart, REnd);
return makeState(PS_InFilenames, TkStart + 1, RStart + 1);
}
}
@@ -168,14 +185,20 @@ public:
return makeState(PS_InFilenames, consumeName(RStart, REnd) + 1,
RStart + 1);
case PS_InFilenames: {
- PosPtr SepEnd = consumeSeparator(RStart, REnd);
+ PosPtr SepEnd = consumeAllSeparators(RStart, REnd);
if (SepEnd == REnd)
return makeState(PS_InRootDir, Path.data(), RStart + 1);
- PosPtr TkEnd = consumeName(SepEnd, REnd);
- return makeState(PS_InFilenames, TkEnd + 1, SepEnd + 1);
+ PosPtr TkStart = consumeRootName(SepEnd ? SepEnd : RStart, REnd);
+ if (TkStart == REnd) {
+ if (SepEnd)
+ return makeState(PS_InRootDir, SepEnd + 1, RStart + 1);
+ return makeState(PS_InRootName, TkStart + 1, RStart + 1);
+ }
+ TkStart = consumeName(SepEnd, REnd);
+ return makeState(PS_InFilenames, TkStart + 1, SepEnd + 1);
}
case PS_InRootDir:
- // return makeState(PS_InRootName, Path.data(), RStart + 1);
+ return makeState(PS_InRootName, Path.data(), RStart + 1);
case PS_InRootName:
case PS_BeforeBegin:
_LIBCPP_UNREACHABLE();
@@ -281,8 +304,9 @@ private:
_LIBCPP_UNREACHABLE();
}
- PosPtr consumeSeparator(PosPtr P, PosPtr End) const noexcept {
- if (P == End || !isSeparator(*P))
+ // Consume all consecutive separators.
+ PosPtr consumeAllSeparators(PosPtr P, PosPtr End) const noexcept {
+ if (P == nullptr || P == End || !isSeparator(*P))
return nullptr;
const int Inc = P < End ? 1 : -1;
P += Inc;
@@ -291,15 +315,72 @@ private:
return P;
}
+ // Consume exactly N separators, or return nullptr.
+ PosPtr consumeNSeparators(PosPtr P, PosPtr End, int N) const noexcept {
+ PosPtr Ret = consumeAllSeparators(P, End);
+ if (Ret == nullptr)
+ return nullptr;
+ if (P < End) {
+ if (Ret == P + N)
+ return Ret;
+ } else {
+ if (Ret == P - N)
+ return Ret;
+ }
+ return nullptr;
+ }
+
PosPtr consumeName(PosPtr P, PosPtr End) const noexcept {
- if (P == End || isSeparator(*P))
+ PosPtr Start = P;
+ if (P == nullptr || P == End || isSeparator(*P))
return nullptr;
const int Inc = P < End ? 1 : -1;
P += Inc;
while (P != End && !isSeparator(*P))
P += Inc;
+ if (P == End && Inc < 0) {
+ // Iterating backwards and consumed all the rest of the input.
+ // Check if the start of the string would have been considered
+ // a root name.
+ PosPtr RootEnd = consumeRootName(End + 1, Start);
+ if (RootEnd)
+ return RootEnd - 1;
+ }
return P;
}
+
+ PosPtr consumeDriveLetter(PosPtr P, PosPtr End) const noexcept {
+ if (P == End)
+ return nullptr;
+ if (P < End) {
+ if (P + 1 == End || !isDriveLetter(P[0]) || P[1] != ':')
+ return nullptr;
+ return P + 2;
+ } else {
+ if (P - 1 == End || !isDriveLetter(P[-1]) || P[0] != ':')
+ return nullptr;
+ return P - 2;
+ }
+ }
+
+ PosPtr consumeNetworkRoot(PosPtr P, PosPtr End) const noexcept {
+ if (P == End)
+ return nullptr;
+ if (P < End)
+ return consumeName(consumeNSeparators(P, End, 2), End);
+ else
+ return consumeNSeparators(consumeName(P, End), End, 2);
+ }
+
+ PosPtr consumeRootName(PosPtr P, PosPtr End) const noexcept {
+#if defined(_LIBCPP_WIN32API)
+ if (PosPtr Ret = consumeDriveLetter(P, End))
+ return Ret;
+ if (PosPtr Ret = consumeNetworkRoot(P, End))
+ return Ret;
+#endif
+ return nullptr;
+ }
};
string_view_pair separate_filename(string_view_t const& s) {
@@ -331,6 +412,7 @@ errc __win_err_to_errc(int err) {
{ERROR_ACCESS_DENIED, errc::permission_denied},
{ERROR_ALREADY_EXISTS, errc::file_exists},
{ERROR_BAD_NETPATH, errc::no_such_file_or_directory},
+ {ERROR_BAD_PATHNAME, errc::no_such_file_or_directory},
{ERROR_BAD_UNIT, errc::no_such_device},
{ERROR_BROKEN_PIPE, errc::broken_pipe},
{ERROR_BUFFER_OVERFLOW, errc::filename_too_long},
@@ -403,7 +485,7 @@ struct FileDescriptor {
static FileDescriptor create(const path* p, error_code& ec, Args... args) {
ec.clear();
int fd;
- if ((fd = ::open(p->c_str(), args...)) == -1) {
+ if ((fd = detail::open(p->c_str(), args...)) == -1) {
ec = capture_errno();
return FileDescriptor{p};
}
@@ -429,7 +511,7 @@ struct FileDescriptor {
void close() noexcept {
if (fd != -1)
- ::close(fd);
+ detail::close(fd);
fd = -1;
}
@@ -453,10 +535,6 @@ perms posix_get_perms(const StatT& st) noexcept {
return static_cast<perms>(st.st_mode) & perms::mask;
}
-::mode_t posix_convert_perms(perms prms) {
- return static_cast< ::mode_t>(prms & perms::mask);
-}
-
file_status create_file_status(error_code& m_ec, path const& p,
const StatT& path_stat, error_code* ec) {
if (ec)
@@ -495,7 +573,7 @@ file_status create_file_status(error_code& m_ec, path const& p,
file_status posix_stat(path const& p, StatT& path_stat, error_code* ec) {
error_code m_ec;
- if (::stat(p.c_str(), &path_stat) == -1)
+ if (detail::stat(p.c_str(), &path_stat) == -1)
m_ec = detail::capture_errno();
return create_file_status(m_ec, p, path_stat, ec);
}
@@ -507,7 +585,7 @@ file_status posix_stat(path const& p, error_code* ec) {
file_status posix_lstat(path const& p, StatT& path_stat, error_code* ec) {
error_code m_ec;
- if (::lstat(p.c_str(), &path_stat) == -1)
+ if (detail::lstat(p.c_str(), &path_stat) == -1)
m_ec = detail::capture_errno();
return create_file_status(m_ec, p, path_stat, ec);
}
@@ -519,7 +597,7 @@ file_status posix_lstat(path const& p, error_code* ec) {
// http://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html
bool posix_ftruncate(const FileDescriptor& fd, off_t to_size, error_code& ec) {
- if (::ftruncate(fd.fd, to_size) == -1) {
+ if (detail::ftruncate(fd.fd, to_size) == -1) {
ec = capture_errno();
return true;
}
@@ -528,7 +606,7 @@ bool posix_ftruncate(const FileDescriptor& fd, off_t to_size, error_code& ec) {
}
bool posix_fchmod(const FileDescriptor& fd, const StatT& st, error_code& ec) {
- if (::fchmod(fd.fd, st.st_mode) == -1) {
+ if (detail::fchmod(fd.fd, st.st_mode) == -1) {
ec = capture_errno();
return true;
}
@@ -545,7 +623,7 @@ file_status FileDescriptor::refresh_status(error_code& ec) {
m_status = file_status{};
m_stat = {};
error_code m_ec;
- if (::fstat(fd, &m_stat) == -1)
+ if (detail::fstat(fd, &m_stat) == -1)
m_ec = capture_errno();
m_status = create_file_status(m_ec, name, m_stat, &ec);
return m_status;
@@ -565,7 +643,14 @@ const bool _FilesystemClock::is_steady;
_FilesystemClock::time_point _FilesystemClock::now() noexcept {
typedef chrono::duration<rep> __secs;
-#if defined(CLOCK_REALTIME)
+#if defined(_LIBCPP_WIN32API)
+ typedef chrono::duration<rep, nano> __nsecs;
+ FILETIME time;
+ GetSystemTimeAsFileTime(&time);
+ TimeSpec tp = detail::filetime_to_timespec(time);
+ return time_point(__secs(tp.tv_sec) +
+ chrono::duration_cast<duration>(__nsecs(tp.tv_nsec)));
+#elif defined(CLOCK_REALTIME)
typedef chrono::duration<rep, nano> __nsecs;
struct timespec tp;
if (0 != clock_gettime(CLOCK_REALTIME, &tp))
@@ -582,27 +667,20 @@ _FilesystemClock::time_point _FilesystemClock::now() noexcept {
filesystem_error::~filesystem_error() {}
-#if defined(_LIBCPP_WIN32API)
-#define PS_FMT "%ls"
-#else
-#define PS_FMT "%s"
-#endif
-
void filesystem_error::__create_what(int __num_paths) {
const char* derived_what = system_error::what();
__storage_->__what_ = [&]() -> string {
- const path::value_type* p1 = path1().native().empty() ? PS("\"\"") : path1().c_str();
- const path::value_type* p2 = path2().native().empty() ? PS("\"\"") : path2().c_str();
switch (__num_paths) {
- default:
+ case 0:
return detail::format_string("filesystem error: %s", derived_what);
case 1:
- return detail::format_string("filesystem error: %s [" PS_FMT "]", derived_what,
- p1);
+ return detail::format_string("filesystem error: %s [" PATH_CSTR_FMT "]",
+ derived_what, path1().c_str());
case 2:
- return detail::format_string("filesystem error: %s [" PS_FMT "] [" PS_FMT "]",
- derived_what, p1, p2);
+ return detail::format_string("filesystem error: %s [" PATH_CSTR_FMT "] [" PATH_CSTR_FMT "]",
+ derived_what, path1().c_str(), path2().c_str());
}
+ _LIBCPP_UNREACHABLE();
}();
}
@@ -627,20 +705,20 @@ path __canonical(path const& orig_p, error_code* ec) {
ErrorHandler<path> err("canonical", ec, &orig_p, &cwd);
path p = __do_absolute(orig_p, &cwd, ec);
-#if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112
- std::unique_ptr<char, decltype(&::free)>
- hold(::realpath(p.c_str(), nullptr), &::free);
+#if (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || defined(_LIBCPP_WIN32API)
+ std::unique_ptr<path::value_type, decltype(&::free)>
+ hold(detail::realpath(p.c_str(), nullptr), &::free);
if (hold.get() == nullptr)
return err.report(capture_errno());
return {hold.get()};
#else
#if defined(__MVS__) && !defined(PATH_MAX)
- char buff[ _XOPEN_PATH_MAX + 1 ];
+ path::value_type buff[ _XOPEN_PATH_MAX + 1 ];
#else
- char buff[PATH_MAX + 1];
+ path::value_type buff[PATH_MAX + 1];
#endif
- char* ret;
- if ((ret = ::realpath(p.c_str(), buff)) == nullptr)
+ path::value_type* ret;
+ if ((ret = detail::realpath(p.c_str(), buff)) == nullptr)
return err.report(capture_errno());
return {ret};
#endif
@@ -819,8 +897,8 @@ bool __copy_file(const path& from, const path& to, copy_options options,
ErrorHandler<bool> err("copy_file", ec, &to, &from);
error_code m_ec;
- FileDescriptor from_fd =
- FileDescriptor::create_with_status(&from, m_ec, O_RDONLY | O_NONBLOCK);
+ FileDescriptor from_fd = FileDescriptor::create_with_status(
+ &from, m_ec, O_RDONLY | O_NONBLOCK | O_BINARY);
if (m_ec)
return err.report(m_ec);
@@ -872,7 +950,7 @@ bool __copy_file(const path& from, const path& to, copy_options options,
// Don't truncate right away. We may not be opening the file we originally
// looked at; we'll check this later.
- int to_open_flags = O_WRONLY;
+ int to_open_flags = O_WRONLY | O_BINARY;
if (!to_exists)
to_open_flags |= O_CREAT;
FileDescriptor to_fd = FileDescriptor::create_with_status(
@@ -908,10 +986,13 @@ void __copy_symlink(const path& existing_symlink, const path& new_symlink,
if (ec && *ec) {
return;
}
- // NOTE: proposal says you should detect if you should call
- // create_symlink or create_directory_symlink. I don't think this
- // is needed with POSIX
- __create_symlink(real_path, new_symlink, ec);
+#if defined(_LIBCPP_WIN32API)
+ error_code local_ec;
+ if (is_directory(real_path, local_ec))
+ __create_directory_symlink(real_path, new_symlink, ec);
+ else
+#endif
+ __create_symlink(real_path, new_symlink, ec);
}
bool __create_directories(const path& p, error_code* ec) {
@@ -932,31 +1013,34 @@ bool __create_directories(const path& p, error_code* ec) {
if (not status_known(parent_st))
return err.report(m_ec);
if (not exists(parent_st)) {
+ if (parent == p)
+ return err.report(errc::invalid_argument);
__create_directories(parent, ec);
if (ec && *ec) {
return false;
}
- }
+ } else if (not is_directory(parent_st))
+ return err.report(errc::not_a_directory);
}
- return __create_directory(p, ec);
+ bool ret = __create_directory(p, &m_ec);
+ if (m_ec)
+ return err.report(m_ec);
+ return ret;
}
bool __create_directory(const path& p, error_code* ec) {
ErrorHandler<bool> err("create_directory", ec, &p);
- if (::mkdir(p.c_str(), static_cast<int>(perms::all)) == 0)
+ if (detail::mkdir(p.c_str(), static_cast<int>(perms::all)) == 0)
return true;
- if (errno == EEXIST) {
- error_code mec = capture_errno();
- error_code ignored_ec;
- const file_status st = status(p, ignored_ec);
- if (!is_directory(st)) {
- err.report(mec);
- }
- } else {
- err.report(capture_errno());
- }
+ if (errno != EEXIST)
+ return err.report(capture_errno());
+ error_code mec = capture_errno();
+ error_code ignored_ec;
+ const file_status st = status(p, ignored_ec);
+ if (!is_directory(st))
+ return err.report(mec);
return false;
}
@@ -965,65 +1049,80 @@ bool __create_directory(path const& p, path const& attributes, error_code* ec) {
StatT attr_stat;
error_code mec;
- auto st = detail::posix_stat(attributes, attr_stat, &mec);
+ file_status st = detail::posix_stat(attributes, attr_stat, &mec);
if (!status_known(st))
return err.report(mec);
if (!is_directory(st))
return err.report(errc::not_a_directory,
"the specified attribute path is invalid");
- if (::mkdir(p.c_str(), attr_stat.st_mode) == 0)
+ if (detail::mkdir(p.c_str(), attr_stat.st_mode) == 0)
return true;
- if (errno == EEXIST) {
- error_code mec = capture_errno();
- error_code ignored_ec;
- const file_status st = status(p, ignored_ec);
- if (!is_directory(st)) {
- err.report(mec);
- }
- } else {
- err.report(capture_errno());
- }
+ if (errno != EEXIST)
+ return err.report(capture_errno());
+
+ mec = capture_errno();
+ error_code ignored_ec;
+ st = status(p, ignored_ec);
+ if (!is_directory(st))
+ return err.report(mec);
return false;
}
void __create_directory_symlink(path const& from, path const& to,
error_code* ec) {
ErrorHandler<void> err("create_directory_symlink", ec, &from, &to);
- if (::symlink(from.c_str(), to.c_str()) != 0)
+ if (detail::symlink_dir(from.c_str(), to.c_str()) == -1)
return err.report(capture_errno());
}
void __create_hard_link(const path& from, const path& to, error_code* ec) {
ErrorHandler<void> err("create_hard_link", ec, &from, &to);
- if (::link(from.c_str(), to.c_str()) == -1)
+ if (detail::link(from.c_str(), to.c_str()) == -1)
return err.report(capture_errno());
}
void __create_symlink(path const& from, path const& to, error_code* ec) {
ErrorHandler<void> err("create_symlink", ec, &from, &to);
- if (::symlink(from.c_str(), to.c_str()) == -1)
+ if (detail::symlink_file(from.c_str(), to.c_str()) == -1)
return err.report(capture_errno());
}
path __current_path(error_code* ec) {
ErrorHandler<path> err("current_path", ec);
+#if defined(_LIBCPP_WIN32API) || defined(__GLIBC__) || defined(__APPLE__)
+ // Common extension outside of POSIX getcwd() spec, without needing to
+ // preallocate a buffer. Also supported by a number of other POSIX libcs.
+ int size = 0;
+ path::value_type* ptr = nullptr;
+ typedef decltype(&::free) Deleter;
+ Deleter deleter = &::free;
+#else
auto size = ::pathconf(".", _PC_PATH_MAX);
_LIBCPP_ASSERT(size >= 0, "pathconf returned a 0 as max size");
- auto buff = unique_ptr<char[]>(new char[size + 1]);
- char* ret;
- if ((ret = ::getcwd(buff.get(), static_cast<size_t>(size))) == nullptr)
+ auto buff = unique_ptr<path::value_type[]>(new path::value_type[size + 1]);
+ path::value_type* ptr = buff.get();
+
+ // Preallocated buffer, don't free the buffer in the second unique_ptr
+ // below.
+ struct Deleter { void operator()(void*) const {} };
+ Deleter deleter;
+#endif
+
+ unique_ptr<path::value_type, Deleter> hold(detail::getcwd(ptr, size),
+ deleter);
+ if (hold.get() == nullptr)
return err.report(capture_errno(), "call to getcwd failed");
- return {buff.get()};
+ return {hold.get()};
}
void __current_path(const path& p, error_code* ec) {
ErrorHandler<void> err("current_path", ec, &p);
- if (::chdir(p.c_str()) == -1)
+ if (detail::chdir(p.c_str()) == -1)
err.report(capture_errno());
}
@@ -1119,6 +1218,17 @@ void __last_write_time(const path& p, file_time_type new_time, error_code* ec) {
using detail::fs_time;
ErrorHandler<void> err("last_write_time", ec, &p);
+#if defined(_LIBCPP_WIN32API)
+ TimeSpec ts;
+ if (!fs_time::convert_to_timespec(ts, new_time))
+ return err.report(errc::value_too_large);
+ detail::WinHandle h(p.c_str(), FILE_WRITE_ATTRIBUTES, 0);
+ if (!h)
+ return err.report(detail::make_windows_error(GetLastError()));
+ FILETIME last_write = timespec_to_filetime(ts);
+ if (!SetFileTime(h, nullptr, nullptr, &last_write))
+ return err.report(detail::make_windows_error(GetLastError()));
+#else
error_code m_ec;
array<TimeSpec, 2> tbuf;
#if !defined(_LIBCPP_USE_UTIMENSAT)
@@ -1140,6 +1250,7 @@ void __last_write_time(const path& p, file_time_type new_time, error_code* ec) {
detail::set_file_times(p, tbuf, m_ec);
if (m_ec)
return err.report(m_ec);
+#endif
}
void __permissions(const path& p, perms prms, perm_options opts,
@@ -1171,11 +1282,11 @@ void __permissions(const path& p, perms prms, perm_options opts,
else if (remove_perms)
prms = st.permissions() & ~prms;
}
- const auto real_perms = detail::posix_convert_perms(prms);
+ const auto real_perms = static_cast<detail::ModeT>(prms & perms::mask);
#if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_FDCWD)
const int flags = set_sym_perms ? AT_SYMLINK_NOFOLLOW : 0;
- if (::fchmodat(AT_FDCWD, p.c_str(), real_perms, flags) == -1) {
+ if (detail::fchmodat(AT_FDCWD, p.c_str(), real_perms, flags) == -1) {
return err.report(capture_errno());
}
#else
@@ -1190,21 +1301,25 @@ void __permissions(const path& p, perms prms, perm_options opts,
path __read_symlink(const path& p, error_code* ec) {
ErrorHandler<path> err("read_symlink", ec, &p);
-#ifdef PATH_MAX
+#if defined(PATH_MAX) || defined(MAX_SYMLINK_SIZE)
struct NullDeleter { void operator()(void*) const {} };
+#ifdef MAX_SYMLINK_SIZE
+ const size_t size = MAX_SYMLINK_SIZE + 1;
+#else
const size_t size = PATH_MAX + 1;
- char stack_buff[size];
- auto buff = std::unique_ptr<char[], NullDeleter>(stack_buff);
+#endif
+ path::value_type stack_buff[size];
+ auto buff = std::unique_ptr<path::value_type[], NullDeleter>(stack_buff);
#else
StatT sb;
- if (::lstat(p.c_str(), &sb) == -1) {
+ if (detail::lstat(p.c_str(), &sb) == -1) {
return err.report(capture_errno());
}
const size_t size = sb.st_size + 1;
- auto buff = unique_ptr<char[]>(new char[size]);
+ auto buff = unique_ptr<path::value_type[]>(new path::value_type[size]);
#endif
- ::ssize_t ret;
- if ((ret = ::readlink(p.c_str(), buff.get(), size)) == -1)
+ detail::SSizeT ret;
+ if ((ret = detail::readlink(p.c_str(), buff.get(), size)) == -1)
return err.report(capture_errno());
_LIBCPP_ASSERT(ret > 0, "TODO");
if (static_cast<size_t>(ret) >= size)
@@ -1215,7 +1330,7 @@ path __read_symlink(const path& p, error_code* ec) {
bool __remove(const path& p, error_code* ec) {
ErrorHandler<bool> err("remove", ec, &p);
- if (::remove(p.c_str()) == -1) {
+ if (detail::remove(p.c_str()) == -1) {
if (errno != ENOENT)
err.report(capture_errno());
return false;
@@ -1264,21 +1379,21 @@ uintmax_t __remove_all(const path& p, error_code* ec) {
void __rename(const path& from, const path& to, error_code* ec) {
ErrorHandler<void> err("rename", ec, &from, &to);
- if (::rename(from.c_str(), to.c_str()) == -1)
+ if (detail::rename(from.c_str(), to.c_str()) == -1)
err.report(capture_errno());
}
void __resize_file(const path& p, uintmax_t size, error_code* ec) {
ErrorHandler<void> err("resize_file", ec, &p);
- if (::truncate(p.c_str(), static_cast< ::off_t>(size)) == -1)
+ if (detail::truncate(p.c_str(), static_cast< ::off_t>(size)) == -1)
return err.report(capture_errno());
}
space_info __space(const path& p, error_code* ec) {
ErrorHandler<void> err("space", ec, &p);
space_info si;
- struct statvfs m_svfs = {};
- if (::statvfs(p.c_str(), &m_svfs) == -1) {
+ detail::StatVFS m_svfs = {};
+ if (detail::statvfs(p.c_str(), &m_svfs) == -1) {
err.report(capture_errno());
si.capacity = si.free = si.available = static_cast<uintmax_t>(-1);
return si;
@@ -1306,6 +1421,19 @@ file_status __symlink_status(const path& p, error_code* ec) {
path __temp_directory_path(error_code* ec) {
ErrorHandler<path> err("temp_directory_path", ec);
+#if defined(_LIBCPP_WIN32API)
+ wchar_t buf[MAX_PATH];
+ DWORD retval = GetTempPathW(MAX_PATH, buf);
+ if (!retval)
+ return err.report(detail::make_windows_error(GetLastError()));
+ if (retval > MAX_PATH)
+ return err.report(errc::filename_too_long);
+ // GetTempPathW returns a path with a trailing slash, which we
+ // shouldn't include for consistency.
+ if (buf[retval-1] == L'\\')
+ buf[retval-1] = L'\0';
+ path p(buf);
+#else
const char* env_paths[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};
const char* ret = nullptr;
@@ -1316,14 +1444,15 @@ path __temp_directory_path(error_code* ec) {
ret = "/tmp";
path p(ret);
+#endif
error_code m_ec;
file_status st = detail::posix_stat(p, &m_ec);
if (!status_known(st))
- return err.report(m_ec, "cannot access path \"" PS_FMT "\"", p);
+ return err.report(m_ec, "cannot access path " PATH_CSTR_FMT, p.c_str());
if (!exists(st) || !is_directory(st))
- return err.report(errc::not_a_directory, "path \"" PS_FMT "\" is not a directory",
- p);
+ return err.report(errc::not_a_directory,
+ "path " PATH_CSTR_FMT " is not a directory", p.c_str());
return p;
}
@@ -1586,6 +1715,7 @@ path path::lexically_normal() const {
if (NeedTrailingSep)
Result /= PS("");
+ Result.make_preferred();
return Result;
}
@@ -1806,7 +1936,6 @@ size_t __char_to_wide(const string &str, wchar_t *out, size_t outlen) {
// directory entry definitions
///////////////////////////////////////////////////////////////////////////////
-#ifndef _LIBCPP_WIN32API
error_code directory_entry::__do_refresh() noexcept {
__data_.__reset();
error_code failure_ec;
@@ -1860,47 +1989,5 @@ error_code directory_entry::__do_refresh() noexcept {
return failure_ec;
}
-#else
-error_code directory_entry::__do_refresh() noexcept {
- __data_.__reset();
- error_code failure_ec;
-
- file_status st = _VSTD_FS::symlink_status(__p_, failure_ec);
- if (!status_known(st)) {
- __data_.__reset();
- return failure_ec;
- }
-
- if (!_VSTD_FS::exists(st) || !_VSTD_FS::is_symlink(st)) {
- __data_.__cache_type_ = directory_entry::_RefreshNonSymlink;
- __data_.__type_ = st.type();
- __data_.__non_sym_perms_ = st.permissions();
- } else { // we have a symlink
- __data_.__sym_perms_ = st.permissions();
- // Get the information about the linked entity.
- // Ignore errors from stat, since we don't want errors regarding symlink
- // resolution to be reported to the user.
- error_code ignored_ec;
- st = _VSTD_FS::status(__p_, ignored_ec);
-
- __data_.__type_ = st.type();
- __data_.__non_sym_perms_ = st.permissions();
-
- // If we failed to resolve the link, then only partially populate the
- // cache.
- if (!status_known(st)) {
- __data_.__cache_type_ = directory_entry::_RefreshSymlinkUnresolved;
- return error_code{};
- }
- __data_.__cache_type_ = directory_entry::_RefreshSymlink;
- }
-
- // FIXME: This is currently broken, and the implementation only a placeholder.
- // We need to cache last_write_time, file_size, and hard_link_count here before
- // the implementation actually works.
-
- return failure_ec;
-}
-#endif
_LIBCPP_END_NAMESPACE_FILESYSTEM