#if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
# include <utime.h> // utime
#endif
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+# include <windows.h>
+#endif
#define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM \
namespace experimental { namespace filesystem {
#define _GLIBCXX_END_NAMESPACE_FILESYSTEM } }
#include "ops-common.h"
-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
-# undef utime
-# define utime _wutime
-# undef chmod
-# define chmod _wchmod
-#endif
-
namespace fs = std::experimental::filesystem;
+namespace posix = std::filesystem::__gnu_posix;
fs::path
fs::absolute(const path& p, const path& base)
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
char_ptr buf{ nullptr };
# if _XOPEN_VERSION < 700
// Not safe to call realpath(path, NULL)
- buf.reset( (char*)::malloc(PATH_MAX) );
+ using char_type = fs::path::value_type;
+ buf.reset( (char_type*)::malloc(PATH_MAX * sizeof(char_type)) );
# endif
if (char* rp = ::realpath(pa.c_str(), buf.get()))
{
using std::filesystem::is_set;
#ifdef _GLIBCXX_HAVE_SYS_STAT_H
- typedef struct ::stat stat_type;
+ using posix::stat_type;
using std::filesystem::is_not_found_errno;
using std::filesystem::file_time;
using std::filesystem::do_copy_file;
#endif // _GLIBCXX_HAVE_SYS_STAT_H
+
} // namespace
void
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2681. filesystem::copy() cannot copy symlinks
if (use_lstat || copy_symlinks
- ? ::lstat(from.c_str(), &from_st)
- : ::stat(from.c_str(), &from_st))
+ ? posix::lstat(from.c_str(), &from_st)
+ : posix::stat(from.c_str(), &from_st))
{
ec.assign(errno, std::generic_category());
return;
}
if (use_lstat
- ? ::lstat(to.c_str(), &to_st)
- : ::stat(to.c_str(), &to_st))
+ ? posix::lstat(to.c_str(), &to_st)
+ : posix::stat(to.c_str(), &to_st))
{
if (!is_not_found_errno(errno))
{
{
bool created = false;
#ifdef _GLIBCXX_HAVE_SYS_STAT_H
- ::mode_t mode = static_cast<std::underlying_type_t<fs::perms>>(perm);
- if (::mkdir(p.c_str(), mode))
+ posix::mode_t mode = static_cast<std::underlying_type_t<fs::perms>>(perm);
+ if (posix::mkdir(p.c_str(), mode))
{
const int err = errno;
if (err != EEXIST || !is_directory(p, ec))
{
#ifdef _GLIBCXX_HAVE_SYS_STAT_H
stat_type st;
- if (::stat(attributes.c_str(), &st))
+ if (posix::stat(attributes.c_str(), &st))
{
ec.assign(errno, std::generic_category());
return false;
fs::create_hard_link(const path& to, const path& new_hard_link,
error_code& ec) noexcept
{
-#ifdef _GLIBCXX_HAVE_UNISTD_H
+#ifdef _GLIBCXX_HAVE_LINK
if (::link(to.c_str(), new_hard_link.c_str()))
ec.assign(errno, std::generic_category());
else
ec.clear();
+#elif defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ if (CreateHardLinkW(new_hard_link.c_str(), to.c_str(), NULL))
+ ec.clear();
+ else
+ ec.assign((int)GetLastError(), generic_category());
#else
ec = std::make_error_code(std::errc::not_supported);
#endif
fs::create_symlink(const path& to, const path& new_symlink,
error_code& ec) noexcept
{
-#ifdef _GLIBCXX_HAVE_UNISTD_H
+#ifdef _GLIBCXX_HAVE_SYMLINK
if (::symlink(to.c_str(), new_symlink.c_str()))
ec.assign(errno, std::generic_category());
else
#endif
}
-
fs::path
fs::current_path()
{
{
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{posix::getcwd(nullptr, 0)})
{
p.assign(cwd.get());
ec.clear();
else
ec.assign(errno, std::generic_category());
#else
+#ifdef _PC_PATH_MAX
long path_max = pathconf(".", _PC_PATH_MAX);
size_t size;
if (path_max == -1)
size = 10240;
else
size = path_max;
+#elif defined(PATH_MAX)
+ size_t size = PATH_MAX;
+#else
+ size_t size = 1024;
+#endif
for (char_ptr buf; p.empty(); size *= 2)
{
- buf.reset((char*)malloc(size));
+ using char_type = fs::path::value_type;
+ buf.reset((char_type*)malloc(size * sizeof(char_type)));
if (buf)
{
if (getcwd(buf.get(), size))
fs::current_path(const path& p, error_code& ec) noexcept
{
#ifdef _GLIBCXX_HAVE_UNISTD_H
- if (::chdir(p.c_str()))
+ if (posix::chdir(p.c_str()))
ec.assign(errno, std::generic_category());
else
ec.clear();
int err = 0;
file_status s1, s2;
stat_type st1, st2;
- if (::stat(p1.c_str(), &st1) == 0)
+ if (posix::stat(p1.c_str(), &st1) == 0)
s1 = make_file_status(st1);
else if (is_not_found_errno(errno))
s1.type(file_type::not_found);
else
err = errno;
- if (::stat(p2.c_str(), &st2) == 0)
+ if (posix::stat(p2.c_str(), &st2) == 0)
s2 = make_file_status(st2);
else if (is_not_found_errno(errno))
s2.type(file_type::not_found);
{
#ifdef _GLIBCXX_HAVE_SYS_STAT_H
stat_type st;
- if (::stat(p.c_str(), &st))
+ if (posix::stat(p.c_str(), &st))
{
ec.assign(errno, std::generic_category());
return deflt;
std::uintmax_t
fs::hard_link_count(const path& p, error_code& ec) noexcept
{
- return do_stat(p, ec, std::mem_fn(&stat::st_nlink),
+ return do_stat(p, ec, std::mem_fn(&stat_type::st_nlink),
static_cast<uintmax_t>(-1));
}
else
ec.clear();
#elif _GLIBCXX_HAVE_UTIME_H
- ::utimbuf times;
+ posix::utimbuf 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 (posix::utime(p.c_str(), ×))
ec.assign(errno, std::generic_category());
else
ec.clear();
#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 (posix::chmod(p.c_str(), static_cast<mode_t>(prms)))
err = errno;
#endif
return tgt;
}
-fs::path fs::read_symlink(const path& p, error_code& ec)
+fs::path fs::read_symlink(const path& p [[gnu::unused]], error_code& ec)
{
path result;
-#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+#if defined(_GLIBCXX_HAVE_READLINK) && defined(_GLIBCXX_HAVE_SYS_STAT_H)
stat_type st;
if (::lstat(p.c_str(), &st))
{
bool
fs::remove(const path& p, error_code& ec) noexcept
{
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ if (exists(symlink_status(p, ec)))
+ {
+ if ((is_directory(p, ec) && RemoveDirectoryW(p.c_str()))
+ || DeleteFileW(p.c_str()))
+ {
+ ec.clear();
+ return true;
+ }
+ else if (!ec)
+ ec.assign((int)GetLastError(), generic_category());
+ }
+#else
if (::remove(p.c_str()) == 0)
{
ec.clear();
ec.clear();
else
ec.assign(errno, std::generic_category());
+#endif
return false;
}
void
fs::rename(const path& from, const path& to, error_code& ec) noexcept
{
- if (::rename(from.c_str(), to.c_str()))
+ if (posix::rename(from.c_str(), to.c_str()))
ec.assign(errno, std::generic_category());
else
ec.clear();
#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 (posix::truncate(p.c_str(), size))
ec.assign(errno, std::generic_category());
else
ec.clear();
static_cast<uintmax_t>(-1),
static_cast<uintmax_t>(-1)
};
-#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
- struct ::statvfs f;
- if (::statvfs(p.c_str(), &f))
- ec.assign(errno, std::generic_category());
- else
- {
- uintmax_t fragment_size = f.f_frsize;
- info = space_info{
- f.f_blocks * fragment_size,
- f.f_bfree * fragment_size,
- f.f_bavail * fragment_size
- };
- ec.clear();
- }
+#if _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ path dir = absolute(p);
+ dir.remove_filename();
+ auto str = dir.c_str();
#else
- ec = std::make_error_code(std::errc::not_supported);
+ auto str = p.c_str();
#endif
+ std::filesystem::do_space(str, info.capacity, info.free, info.available, ec);
return info;
}
{
file_status status;
stat_type st;
- if (::stat(p.c_str(), &st))
+ if (posix::stat(p.c_str(), &st))
{
int err = errno;
ec.assign(err, std::generic_category());
{
file_status status;
stat_type st;
- if (::lstat(p.c_str(), &st))
+ if (posix::lstat(p.c_str(), &st))
{
int err = errno;
ec.assign(err, std::generic_category());
fs::path fs::temp_directory_path(error_code& ec)
{
+ path p;
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
- ec = std::make_error_code(std::errc::not_supported);
- return {}; // TODO
+ unsigned len = 1024;
+ std::wstring buf;
+ do
+ {
+ buf.resize(len);
+ len = GetTempPathW(buf.size(), buf.data());
+ } while (len > buf.size());
+
+ if (len == 0)
+ {
+ ec.assign((int)GetLastError(), std::system_category());
+ return p;
+ }
+ buf.resize(len);
+ p = std::move(buf);
#else
const char* tmpdir = nullptr;
const char* env[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr };
for (auto e = env; tmpdir == nullptr && *e != nullptr; ++e)
tmpdir = ::getenv(*e);
- path p = tmpdir ? tmpdir : "/tmp";
+ p = tmpdir ? tmpdir : "/tmp";
auto st = status(p, ec);
- if (!ec)
+ if (ec)
+ p.clear();
+ else if (!is_directory(st))
{
- if (is_directory(st))
- {
- ec.clear();
- return p;
- }
- else
- ec = std::make_error_code(std::errc::not_a_directory);
+ p.clear();
+ ec = std::make_error_code(std::errc::not_a_directory);
}
- return {};
#endif
+ return p;
}