Index: libcxx/src/filesystem/operations.cpp =================================================================== --- libcxx/src/filesystem/operations.cpp +++ libcxx/src/filesystem/operations.cpp @@ -405,7 +405,7 @@ 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}; } @@ -431,7 +431,7 @@ void close() noexcept { if (fd != -1) - ::close(fd); + detail::close(fd); fd = -1; } @@ -521,7 +521,7 @@ // 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; } @@ -824,8 +824,8 @@ ErrorHandler 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); @@ -877,7 +877,7 @@ // 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( @@ -913,10 +913,13 @@ 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) { @@ -949,7 +952,7 @@ bool __create_directory(const path& p, error_code* ec) { ErrorHandler err("create_directory", ec, &p); - if (::mkdir(p.c_str(), static_cast(perms::all)) == 0) + if (detail::mkdir(p.c_str(), static_cast(perms::all)) == 0) return true; if (errno == EEXIST) { @@ -977,7 +980,7 @@ 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) { @@ -996,19 +999,19 @@ void __create_directory_symlink(path const& from, path const& to, error_code* ec) { ErrorHandler 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 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 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()); } @@ -1028,7 +1031,7 @@ void __current_path(const path& p, error_code* ec) { ErrorHandler err("current_path", ec, &p); - if (::chdir(p.c_str()) == -1) + if (detail::chdir(p.c_str()) == -1) err.report(capture_errno()); } @@ -1232,7 +1235,7 @@ bool __remove(const path& p, error_code* ec) { ErrorHandler 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; @@ -1281,13 +1284,13 @@ void __rename(const path& from, const path& to, error_code* ec) { ErrorHandler 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 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()); } Index: libcxx/src/filesystem/posix_compat.h =================================================================== --- libcxx/src/filesystem/posix_compat.h +++ libcxx/src/filesystem/posix_compat.h @@ -84,6 +84,8 @@ #define S_ISLNK(m) (((m) & _S_IFMT) == _S_IFLNK) #define S_ISSOCK(m) (((m) & _S_IFMT) == _S_IFSOCK) +#define O_NONBLOCK 0 + // There were 369 years and 89 leap days from the Windows epoch // (1601) to the Unix epoch (1970). @@ -192,10 +194,108 @@ HANDLE h = reinterpret_cast(_get_osfhandle(fd)); return stat_handle(h, buf); } + +int mkdir(const wchar_t *path, int permissions) { + (void)permissions; + return _wmkdir(path); +} + +int symlink_file_dir(const wchar_t *oldname, const wchar_t *newname, + bool is_dir) { + DWORD flags = is_dir ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0; + if (CreateSymbolicLinkW(newname, oldname, + flags | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)) + return 0; + int e = GetLastError(); + if (e != ERROR_INVALID_PARAMETER) + return set_errno(e); + if (CreateSymbolicLinkW(newname, oldname, flags)) + return 0; + return set_errno(); +} + +int symlink_file(const wchar_t *oldname, const wchar_t *newname) { + return symlink_file_dir(oldname, newname, false); +} + +int symlink_dir(const wchar_t *oldname, const wchar_t *newname) { + return symlink_file_dir(oldname, newname, true); +} + +int link(const wchar_t *oldname, const wchar_t *newname) { + if (CreateHardLinkW(newname, oldname, nullptr)) + return 0; + return set_errno(); +} + +int remove(const wchar_t *path) { + detail::WinHandle h(path, DELETE, FILE_FLAG_OPEN_REPARSE_POINT); + if (!h) + return set_errno(); + FILE_DISPOSITION_INFO info; + info.DeleteFile = TRUE; + if (!SetFileInformationByHandle(h, FileDispositionInfo, &info, sizeof(info))) + return set_errno(); + return 0; +} + +int truncate_handle(HANDLE h, off_t length) { + LARGE_INTEGER size_param; + size_param.QuadPart = length; + if (!SetFilePointerEx(h, size_param, 0, FILE_BEGIN)) + return set_errno(); + if (!SetEndOfFile(h)) + return set_errno(); + return 0; +} + +int ftruncate(int fd, off_t length) { + HANDLE h = reinterpret_cast(_get_osfhandle(fd)); + return truncate_handle(h, length); +} + +int truncate(const wchar_t *path, off_t length) { + detail::WinHandle h(path, GENERIC_WRITE, 0); + if (!h) + return set_errno(); + return truncate_handle(h, length); +} + +int rename(const wchar_t *from, const wchar_t *to) { + if (!(MoveFileExW(from, to, + MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | + MOVEFILE_WRITE_THROUGH))) + return set_errno(); + return 0; +} + +template int open(const wchar_t *filename, Args... args) { + return _wopen(filename, args...); +} +int close(int fd) { return _close(fd); } +int chdir(const wchar_t *path) { return _wchdir(path); } #else +int symlink_file(const char *oldname, const char *newname) { + return ::symlink(oldname, newname); +} +int symlink_dir(const char *oldname, const char *newname) { + return ::symlink(oldname, newname); +} +using ::chdir; +using ::close; using ::fstat; +using ::ftruncate; +using ::link; using ::lstat; +using ::mkdir; +using ::open; +using ::remove; +using ::rename; using ::stat; +using ::truncate; + +#define O_BINARY 0 + #endif } // namespace