diff options
Diffstat (limited to 'libcxx/src/filesystem/operations.cpp')
-rw-r--r-- | libcxx/src/filesystem/operations.cpp | 377 |
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 |