This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] Windows support for std::filesystem
- From: niXman <i dot nixman at autistici dot org>
- To: gcc-patches at gcc dot gnu dot org, libstdc++ at gcc dot gnu dot org, jwakely at redhat dot com
- Date: Tue, 14 Mar 2017 23:53:31 +0300
- Subject: Re: [PATCH] Windows support for std::filesystem
- Authentication-results: sourceware.org; auth=none
- References: <b3f9ea2f7e622d0bd2c6dd89c339f286@autistici.org>
niXman 2017-02-12 20:28:
Hi,
Tested on i686/x86_64-MinGW-W64
Please test possible regressions on posix platform.
As continuation for:
https://gcc.gnu.org/ml/libstdc++/2017-02/msg00041.html
Regression on posix platform was fixed.
Tested on i686/x86_64-MinGW-W64 and x86_64-linux-gnu.
Index: libstdc++-v3/src/filesystem/dir.cc
===================================================================
--- libstdc++-v3/src/filesystem/dir.cc (revision 246136)
+++ libstdc++-v3/src/filesystem/dir.cc (working copy)
@@ -41,9 +41,10 @@
#endif
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
-# undef opendir
-# define opendir _wopendir
-#endif
+# include "fs-win32.h"
+#else
+# include "fs-posix.h"
+#endif // _GLIBCXX_FILESYSTEM_IS_WINDOWS
namespace fs = std::experimental::filesystem;
@@ -51,7 +52,7 @@
{
_Dir() : dirp(nullptr) { }
- _Dir(DIR* dirp, const fs::path& path) : dirp(dirp), path(path) { }
+ _Dir(os_DIR_t* dirp, const fs::path& path) : dirp(dirp), path(path) { }
_Dir(_Dir&& d)
: dirp(std::exchange(d.dirp, nullptr)), path(std::move(d.path)),
@@ -60,11 +61,11 @@
_Dir& operator=(_Dir&&) = delete;
- ~_Dir() { if (dirp) ::closedir(dirp); }
+ ~_Dir() { if (dirp) ::os_closedir(dirp); }
bool advance(std::error_code*, directory_options = directory_options::none);
- DIR* dirp;
+ os_DIR_t* dirp;
fs::path path;
directory_entry entry;
file_type type = file_type::none;
@@ -87,7 +88,7 @@
if (ec)
ec->clear();
- if (DIR* dirp = ::opendir(p.c_str()))
+ if (os_DIR_t* dirp = ::os_opendir(p.c_str()))
return {dirp, p};
const int err = errno;
@@ -105,7 +106,7 @@
}
inline fs::file_type
- get_file_type(const ::dirent& d __attribute__((__unused__)))
+ get_file_type(const ::os_dirent_t& d __attribute__((__unused__)))
{
#ifdef _GLIBCXX_HAVE_STRUCT_DIRENT_D_TYPE
switch (d.d_type)
@@ -145,13 +146,14 @@
ec->clear();
int err = std::exchange(errno, 0);
- const auto entp = readdir(dirp);
+ const auto entp = ::os_readdir(dirp);
std::swap(errno, err);
if (entp)
{
// skip past dot and dot-dot
- if (!strcmp(entp->d_name, ".") || !strcmp(entp->d_name, ".."))
+ if (!std::char_traits<path::value_type>::compare(entp->d_name, _WS("."), 1) ||
+ !std::char_traits<path::value_type>::compare(entp->d_name, _WS(".."), 2))
return advance(ec, options);
entry = fs::directory_entry{path / entp->d_name};
type = get_file_type(*entp);
@@ -239,7 +241,7 @@
error_code* ec)
: _M_options(options), _M_pending(true)
{
- if (DIR* dirp = ::opendir(p.c_str()))
+ if (os_DIR_t* dirp = ::os_opendir(p.c_str()))
{
auto sp = std::make_shared<_Dir_stack>();
sp->push(_Dir{ dirp, p });
Index: libstdc++-v3/src/filesystem/fs-posix.h
===================================================================
--- libstdc++-v3/src/filesystem/fs-posix.h (revision 0)
+++ libstdc++-v3/src/filesystem/fs-posix.h (working copy)
@@ -0,0 +1,49 @@
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef _GLIBCXX_EXPERIMENTAL_FS_POSIX_H
+#define _GLIBCXX_EXPERIMENTAL_FS_POSIX_H 1
+
+#define os_DIR_t DIR
+#define os_dirent_t dirent
+#define os_open open
+#define os_opendir opendir
+#define os_closedir closedir
+#define os_readdir readdir
+#define os_stat stat
+#define os_stat_t stat
+#define os_chmod chmod
+#define os_mkdir mkdir
+#define os_getcwd getcwd
+#define os_chdir chdir
+#define os_utimbuf_t utimbuf
+#define os_utime utime
+#define os_remove remove
+#define os_rename rename
+#define os_truncate truncate
+
+#define os_utime utime
+
+#define _WS(x) x
+
+#endif // _GLIBCXX_EXPERIMENTAL_FS_POSIX_H
Index: libstdc++-v3/src/filesystem/fs-win32.h
===================================================================
--- libstdc++-v3/src/filesystem/fs-win32.h (revision 0)
+++ libstdc++-v3/src/filesystem/fs-win32.h (working copy)
@@ -0,0 +1,64 @@
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef _GLIBCXX_EXPERIMENTAL_FS_WIN32_H
+#define _GLIBCXX_EXPERIMENTAL_FS_WIN32_H 1
+
+#define os_DIR_t _WDIR
+#define os_dirent_t _wdirent
+#define os_open _wopen
+#define os_opendir _wopendir
+#define os_closedir _wclosedir
+#define os_readdir _wreaddir
+#define os_stat _wstat
+#define os_stat_t _stat
+#define os_chmod _wchmod
+#define os_mkdir _wmkdir
+#define os_getcwd _wgetcwd
+#define os_chdir _wchdir
+#define os_utimbuf_t _utimbuf
+#define os_utime _wutime
+#define os_remove _wremove
+#define os_rename _wrename
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+inline int _wtruncate(const wchar_t *fname, _off64_t size) {
+ int fd = ::os_open(fname, _O_BINARY|_O_RDWR);
+ if (fd == -1) return fd;
+ int ret = ::ftruncate64(fd, size), err=0;
+ _get_errno(&err);
+ _close(fd);
+ _set_errno(err);
+ return ret;
+}
+
+#define os_truncate _wtruncate
+
+#define os_utime _wutime
+
+#define _WS(x) L##x
+
+#endif // _GLIBCXX_EXPERIMENTAL_FS_WIN32_H
Index: libstdc++-v3/src/filesystem/ops.cc
===================================================================
--- libstdc++-v3/src/filesystem/ops.cc (revision 246136)
+++ libstdc++-v3/src/filesystem/ops.cc (working copy)
@@ -56,11 +56,10 @@
#endif
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
-# undef utime
-# define utime _wutime
-# undef chmod
-# define chmod _wchmod
-#endif
+# include "fs-win32.h"
+#else
+# include "fs-posix.h"
+#endif // _GLIBCXX_FILESYSTEM_IS_WINDOWS
namespace fs = std::experimental::filesystem;
@@ -88,11 +87,7 @@
namespace
{
-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
- inline bool is_dot(wchar_t c) { return c == L'.'; }
-#else
- inline bool is_dot(char c) { return c == '.'; }
-#endif
+ inline bool is_dot(fs::path::value_type c) { return c == _WS('.'); }
inline bool is_dot(const fs::path& path)
{
@@ -111,7 +106,7 @@
void operator()(void* p) const { ::free(p); }
};
- using char_ptr = std::unique_ptr<char[], free_as_in_malloc>;
+ using char_ptr = std::unique_ptr<fs::path::value_type[], free_as_in_malloc>;
}
fs::path
@@ -250,7 +245,7 @@
#ifdef _GLIBCXX_HAVE_SYS_STAT_H
namespace
{
- typedef struct ::stat stat_type;
+ typedef struct ::os_stat_t stat_type;
inline fs::file_type
make_file_type(const stat_type& st) noexcept
@@ -267,10 +262,12 @@
return file_type::block;
else if (S_ISFIFO(st.st_mode))
return file_type::fifo;
+#ifndef _GLIBCXX_FILESYSTEM_IS_WINDOWS
else if (S_ISLNK(st.st_mode))
return file_type::symlink;
else if (S_ISSOCK(st.st_mode))
return file_type::socket;
+#endif // _GLIBCXX_FILESYSTEM_IS_WINDOWS
#endif
return file_type::unknown;
@@ -323,7 +320,7 @@
if (to_st == nullptr)
{
- if (::stat(to.c_str(), &st1))
+ if (::os_stat(to.c_str(), &st1))
{
int err = errno;
if (!is_not_found_errno(err))
@@ -345,7 +342,7 @@
if (from_st == nullptr)
{
- if (::stat(from.c_str(), &st2))
+ if (::os_stat(from.c_str(), &st2))
{
ec.assign(errno, std::generic_category());
return false;
@@ -410,7 +407,7 @@
int fd;
};
- CloseFD in = { ::open(from.c_str(), O_RDONLY) };
+ CloseFD in = { ::os_open(from.c_str(), O_RDONLY) };
if (in.fd == -1)
{
ec.assign(errno, std::generic_category());
@@ -421,7 +418,7 @@
oflag |= O_TRUNC;
else
oflag |= O_EXCL;
- CloseFD out = { ::open(to.c_str(), oflag, S_IWUSR) };
+ CloseFD out = { ::os_open(to.c_str(), oflag, S_IWUSR) };
if (out.fd == -1)
{
if (errno == EEXIST && is_set(option, opts::skip_existing))
@@ -436,7 +433,7 @@
#elif defined _GLIBCXX_USE_FCHMODAT
if (::fchmodat(AT_FDCWD, to.c_str(), from_st->st_mode, 0))
#else
- if (::chmod(to.c_str(), from_st->st_mode))
+ if (::os_chmod(to.c_str(), from_st->st_mode))
#endif
{
ec.assign(errno, std::generic_category());
@@ -502,16 +499,24 @@
stat_type from_st, to_st;
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2681. filesystem::copy() cannot copy symlinks
+#ifndef _GLIBCXX_FILESYSTEM_IS_WINDOWS
if (use_lstat || copy_symlinks
? ::lstat(from.c_str(), &from_st)
: ::stat(from.c_str(), &from_st))
+#else
+ if (::os_stat(from.c_str(), &from_st))
+#endif // _GLIBCXX_FILESYSTEM_IS_WINDOWS
{
ec.assign(errno, std::generic_category());
return;
}
+#ifndef _GLIBCXX_FILESYSTEM_IS_WINDOWS
if (use_lstat
? ::lstat(to.c_str(), &to_st)
: ::stat(to.c_str(), &to_st))
+#else
+ if (::os_stat(to.c_str(), &to_st))
+#endif // _GLIBCXX_FILESYSTEM_IS_WINDOWS
{
if (!is_not_found_errno(errno))
{
@@ -696,8 +701,12 @@
{
bool created = false;
#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+#ifndef _GLIBCXX_FILESYSTEM_IS_WINDOWS
::mode_t mode = static_cast<std::underlying_type_t<fs::perms>>(perm);
- if (::mkdir(p.c_str(), mode))
+ if (::os_mkdir(p.c_str(), mode))
+#else
+ if (::os_mkdir(p.c_str()))
+#endif // _GLIBCXX_FILESYSTEM_IS_WINDOWS
{
const int err = errno;
if (err != EEXIST || !is_directory(p))
@@ -752,7 +761,7 @@
{
#ifdef _GLIBCXX_HAVE_SYS_STAT_H
stat_type st;
- if (::stat(attributes.c_str(), &st))
+ if (::os_stat(attributes.c_str(), &st))
{
ec.assign(errno, std::generic_category());
return false;
@@ -801,7 +810,7 @@
fs::create_hard_link(const path& to, const path& new_hard_link,
error_code& ec) noexcept
{
-#ifdef _GLIBCXX_HAVE_UNISTD_H
+#if !defined(_GLIBCXX_FILESYSTEM_IS_WINDOWS) && defined(_GLIBCXX_HAVE_UNISTD_H)
if (::link(to.c_str(), new_hard_link.c_str()))
ec.assign(errno, std::generic_category());
else
@@ -825,7 +834,7 @@
fs::create_symlink(const path& to, const path& new_symlink,
error_code& ec) noexcept
{
-#ifdef _GLIBCXX_HAVE_UNISTD_H
+#if !defined(_GLIBCXX_FILESYSTEM_IS_WINDOWS) && defined(_GLIBCXX_HAVE_UNISTD_H)
if (::symlink(to.c_str(), new_symlink.c_str()))
ec.assign(errno, std::generic_category());
else
@@ -851,8 +860,8 @@
{
path p;
#ifdef _GLIBCXX_HAVE_UNISTD_H
-#ifdef __GLIBC__
- if (char_ptr cwd = char_ptr{::getcwd(nullptr, 0)})
+#if defined(__GLIBC__) || defined(_GLIBCXX_FILESYSTEM_IS_WINDOWS)
+ if (char_ptr cwd = char_ptr{::os_getcwd(nullptr, 0)})
{
p.assign(cwd.get());
ec.clear();
@@ -910,7 +919,7 @@
fs::current_path(const path& p, error_code& ec) noexcept
{
#ifdef _GLIBCXX_HAVE_UNISTD_H
- if (::chdir(p.c_str()))
+ if (::os_chdir(p.c_str()))
ec.assign(errno, std::generic_category());
else
ec.clear();
@@ -937,7 +946,7 @@
int err = 0;
file_status s1, s2;
stat_type st1, st2;
- if (::stat(p1.c_str(), &st1) == 0)
+ if (::os_stat(p1.c_str(), &st1) == 0)
s1 = make_file_status(st1);
else if (is_not_found_errno(errno))
s1.type(file_type::not_found);
@@ -944,7 +953,7 @@
else
err = errno;
- if (::stat(p2.c_str(), &st2) == 0)
+ if (::os_stat(p2.c_str(), &st2) == 0)
s2 = make_file_status(st2);
else if (is_not_found_errno(errno))
s2.type(file_type::not_found);
@@ -994,7 +1003,7 @@
{
#ifdef _GLIBCXX_HAVE_SYS_STAT_H
stat_type st;
- if (::stat(p.c_str(), &st))
+ if (::os_stat(p.c_str(), &st))
{
ec.assign(errno, std::generic_category());
return deflt;
@@ -1044,8 +1053,14 @@
std::uintmax_t
fs::hard_link_count(const path& p, error_code& ec) noexcept
{
+#ifndef _GLIBCXX_FILESYSTEM_IS_WINDOWS
return do_stat(p, ec, std::mem_fn(&stat::st_nlink),
static_cast<uintmax_t>(-1));
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+
+ return static_cast<uintmax_t>(-1);
+#endif // _GLIBCXX_FILESYSTEM_IS_WINDOWS
}
bool
@@ -1120,11 +1135,11 @@
else
ec.clear();
#elif _GLIBCXX_HAVE_UTIME_H
- ::utimbuf times;
+ ::os_utimbuf_t times;
times.modtime = s.count();
times.actime = do_stat(p, ec, [](const auto& st) { return st.st_atime; },
times.modtime);
- if (::utime(p.c_str(), ×))
+ if (::os_utime(p.c_str(), ×))
ec.assign(errno, std::generic_category());
else
ec.clear();
@@ -1177,7 +1192,7 @@
#else
if (nofollow && is_symlink(st))
ec = std::make_error_code(std::errc::operation_not_supported);
- else if (::chmod(p.c_str(), static_cast<mode_t>(prms)))
+ else if (::os_chmod(p.c_str(), static_cast<mode_t>(prms)))
err = errno;
#endif
@@ -1199,7 +1214,7 @@
fs::path fs::read_symlink(const path& p, error_code& ec)
{
-#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+#if !defined(_GLIBCXX_FILESYSTEM_IS_WINDOWS) && defined(_GLIBCXX_HAVE_SYS_STAT_H)
stat_type st;
if (::lstat(p.c_str(), &st))
{
@@ -1237,7 +1252,7 @@
{
if (exists(symlink_status(p, ec)))
{
- if (::remove(p.c_str()) == 0)
+ if (::os_remove(p.c_str()) == 0)
{
ec.clear();
return true;
@@ -1284,7 +1299,7 @@
void
fs::rename(const path& from, const path& to, error_code& ec) noexcept
{
- if (::rename(from.c_str(), to.c_str()))
+ if (::os_rename(from.c_str(), to.c_str()))
ec.assign(errno, std::generic_category());
else
ec.clear();
@@ -1305,7 +1320,7 @@
#ifdef _GLIBCXX_HAVE_UNISTD_H
if (size > static_cast<uintmax_t>(std::numeric_limits<off_t>::max()))
ec.assign(EINVAL, std::generic_category());
- else if (::truncate(p.c_str(), size))
+ else if (::os_truncate(p.c_str(), size))
ec.assign(errno, std::generic_category());
else
ec.clear();
@@ -1358,7 +1373,7 @@
{
file_status status;
stat_type st;
- if (::stat(p.c_str(), &st))
+ if (::os_stat(p.c_str(), &st))
{
int err = errno;
ec.assign(err, std::generic_category());
@@ -1376,11 +1391,13 @@
}
return status;
}
+#endif // _GLIBCXX_FILESYSTEM_IS_WINDOWS
fs::file_status
fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept
{
file_status status;
+#if !defined(_GLIBCXX_FILESYSTEM_IS_WINDOWS) && defined(_GLIBCXX_HAVE_SYS_STAT_H)
stat_type st;
if (::lstat(p.c_str(), &st))
{
@@ -1394,9 +1411,11 @@
status = make_file_status(st);
ec.clear();
}
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+#endif
return status;
}
-#endif
fs::file_status
fs::status(const fs::path& p)
Index: libstdc++-v3/src/filesystem/path.cc
===================================================================
--- libstdc++-v3/src/filesystem/path.cc (revision 246136)
+++ libstdc++-v3/src/filesystem/path.cc (working copy)
@@ -296,7 +296,7 @@
std::pair<const path::string_type*, std::size_t>
path::_M_find_extension() const
{
- const std::string* s = nullptr;
+ const path::string_type* s = nullptr;
if (_M_type != _Type::_Multi)
s = &_M_pathname;