diff --git a/libcxx/src/filesystem/file_descriptor.h b/libcxx/src/filesystem/file_descriptor.h --- a/libcxx/src/filesystem/file_descriptor.h +++ b/libcxx/src/filesystem/file_descriptor.h @@ -129,7 +129,25 @@ static FileDescriptor create(const path* p, error_code& ec, Args... args) { ec.clear(); int fd; - if ((fd = detail::open(p->c_str(), args...)) == -1) { +#ifdef _LIBCPP_WIN32API + // TODO: most of the filesystem implementation uses native Win32 calls + // (mostly via posix_compat.h). However, here we use the C-runtime APIs to + // open a file, because we subsequently pass the C-runtime fd to + // `std::[io]fstream::__open(int fd)` in order to implement copy_file. + // + // Because we're calling the windows C-runtime, win32 error codes are + // translated into C error numbers by the C runtime, and returned in errno, + // rather than being accessible directly via GetLastError. + // + // Ideally copy_file should be calling the Win32 CopyFile2 function, which + // works on paths, not open files -- at which point this FileDescriptor type + // will no longer be needed on windows at all. + fd = ::_wopen(p->c_str(), args...); +#else + fd = open(p->c_str(), args...); +#endif + + if (fd == -1) { ec = capture_errno(); return FileDescriptor{p}; } @@ -154,8 +172,14 @@ file_status refresh_status(error_code& ec); void close() noexcept { - if (fd != -1) - detail::close(fd); + if (fd != -1) { +#ifdef _LIBCPP_WIN32API + ::_close(fd); +#else + ::close(fd); +#endif + // FIXME: shouldn't this return an error_code? + } fd = -1; } diff --git a/libcxx/src/filesystem/posix_compat.h b/libcxx/src/filesystem/posix_compat.h --- a/libcxx/src/filesystem/posix_compat.h +++ b/libcxx/src/filesystem/posix_compat.h @@ -273,7 +273,9 @@ int mkdir(const wchar_t *path, int permissions) { (void)permissions; - return _wmkdir(path); + if (!CreateDirectoryW(path, nullptr)) + return set_errno(); + return 0; } int symlink_file_dir(const wchar_t *oldname, const wchar_t *newname, @@ -348,11 +350,11 @@ return 0; } -template int open(const wchar_t *filename, Args... args) { - return _wopen(filename, args...); +int chdir(const wchar_t* path) { + if (!SetCurrentDirectoryW(path)) + return set_errno(); + return 0; } -int close(int fd) { return _close(fd); } -int chdir(const wchar_t *path) { return _wchdir(path); } struct StatVFS { uint64_t f_frsize; @@ -387,7 +389,25 @@ return 0; } -wchar_t *getcwd(wchar_t *buff, size_t size) { return _wgetcwd(buff, size); } +wchar_t* getcwd(wchar_t* in_buf, size_t in_size) { + // Only expected to be used with us allocating the buffer. + _LIBCPP_ASSERT(in_buf == nullptr, "Windows getcwd() assumes in_buf==nullptr"); + _LIBCPP_ASSERT(in_size == 0, "Windows getcwd() assumes in_size==0"); + + size_t buff_size = MAX_PATH + 10; + std::unique_ptr buff(static_cast(malloc(buff_size * sizeof(wchar_t))), &::free); + DWORD retval = GetCurrentDirectoryW(buff_size, buff.get()); + if (retval > buff_size) { + buff_size = retval; + buff.reset(static_cast(malloc(buff_size * sizeof(wchar_t)))); + retval = GetCurrentDirectoryW(buff_size, buff.get()); + } + if (!retval) { + set_errno(); + return nullptr; + } + return buff.release(); +} wchar_t *realpath(const wchar_t *path, wchar_t *resolved_name) { // Only expected to be used with us allocating the buffer. @@ -530,7 +550,6 @@ return ::symlink(oldname, newname); } using ::chdir; -using ::close; using ::fchmod; #if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_FDCWD) using ::fchmodat; @@ -541,7 +560,6 @@ using ::link; using ::lstat; using ::mkdir; -using ::open; using ::readlink; using ::realpath; using ::remove;