2015-05-01 Jonathan Wakely <jwakely@redhat.com>
+ * acinclude.m4 (GLIBCXX_ENABLE_FILESYSTEM_TS): Disable when <dirent.h>
+ is not available.
+ (GLIBCXX_CHECK_FILESYSTEM_DEPS): Check for fchmodat.
+ * configure: Regenerate.
+ * config.h.in: Regenerate.
+ * configure.ac: Check for utime.h
+ * include/experimental/fs_path.h (path::string<>)
+ [_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Remove stray typename keyword.
+ * src/filesystem/dir.cc [!_GLIBCXX_HAVE_DIRENT_H] (DIR, opendir,
+ closedir, dirent, readdir_r): Replace dummy functions with #error.
+ (native_readdir, _Dir::advance): Use readdir when readdir_r is missing.
+ * src/filesystem/ops.cc (do_stat, is_set): Make inline.
+ (last_write_time) [!_GLIBCXX_USE_UTIMENSAT]: Use utime.
+ (permissions) [!_GLIBCXX_USE_FCHMODAT]: Use chmod.
+ (space, temp_directory_path) [_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Set
+ error_code.
+
* include/experimental/fs_path.h (path::_List): Use vector instead of
list.
* python/libstdcxx/v6/printers.py (StdExpPathPrinter): Adapt.
[permit yes|no|auto])
AC_MSG_CHECKING([whether to build Filesystem TS support])
+ if test x"$ac_cv_header_dirent_h" != x"yes"; then
+ enable_libstdcxx_filesystem_ts=no
+ fi
if test x"$enable_libstdcxx_filesystem_ts" = x"auto"; then
case "${target_os}" in
freebsd*|netbsd*|openbsd*|dragonfly*|darwin*)
AC_DEFINE(_GLIBCXX_USE_ST_MTIM, 1, [Define if struct stat has timespec members.])
fi
AC_MSG_RESULT($glibcxx_cv_st_mtim)
+dnl
+ AC_MSG_CHECKING([for fchmodat])
+ AC_CACHE_VAL(glibcxx_cv_fchmodat, [dnl
+ GCC_TRY_COMPILE_OR_LINK(
+ [
+ #include <fcntl.h>
+ #include <sys/stat.h>
+ ],
+ [fchmodat(AT_FDCWD, "", 0, AT_SYMLINK_NOFOLLOW);],
+ [glibcxx_cv_fchmodat=yes],
+ [glibcxx_cv_fchmodat=no])
+ ])
+ if test $glibcxx_cv_fchmodat = yes; then
+ AC_DEFINE(_GLIBCXX_USE_FCHMODAT, 1, [Define if fchmodat is available in <sys/stat.h>.])
+ fi
+ AC_MSG_RESULT($glibcxx_cv_fchmodat)
dnl
CXXFLAGS="$ac_save_CXXFLAGS"
AC_LANG_RESTORE
/* Defined if usleep exists. */
#undef HAVE_USLEEP
+/* Define to 1 if you have the <utime.h> header file. */
+#undef HAVE_UTIME_H
+
/* Defined if vfwscanf exists. */
#undef HAVE_VFWSCANF
this host. */
#undef _GLIBCXX_USE_DECIMAL_FLOAT
+/* Define if fchmodat is available in <sys/stat.h>. */
+#undef _GLIBCXX_USE_FCHMODAT
+
/* Define if __float128 is supported on this host. */
#undef _GLIBCXX_USE_FLOAT128
# For Filesystem TS.
-for ac_header in fcntl.h dirent.h sys/statvfs.h
+for ac_header in fcntl.h dirent.h sys/statvfs.h utime.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build Filesystem TS support" >&5
$as_echo_n "checking whether to build Filesystem TS support... " >&6; }
+ if test x"$ac_cv_header_dirent_h" != x"yes"; then
+ enable_libstdcxx_filesystem_ts=no
+ fi
if test x"$enable_libstdcxx_filesystem_ts" = x"auto"; then
case "${target_os}" in
freebsd*|netbsd*|openbsd*|dragonfly*|darwin*)
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_st_mtim" >&5
$as_echo "$glibcxx_cv_st_mtim" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fchmodat" >&5
+$as_echo_n "checking for fchmodat... " >&6; }
+ if test "${glibcxx_cv_fchmodat+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test x$gcc_no_link = xyes; then
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <fcntl.h>
+ #include <sys/stat.h>
+
+int
+main ()
+{
+fchmodat(AT_FDCWD, "", 0, AT_SYMLINK_NOFOLLOW);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ glibcxx_cv_fchmodat=yes
+else
+ glibcxx_cv_fchmodat=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ if test x$gcc_no_link = xyes; then
+ as_fn_error "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5
+fi
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #include <fcntl.h>
+ #include <sys/stat.h>
+
+int
+main ()
+{
+fchmodat(AT_FDCWD, "", 0, AT_SYMLINK_NOFOLLOW);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ glibcxx_cv_fchmodat=yes
+else
+ glibcxx_cv_fchmodat=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+
+fi
+
+ if test $glibcxx_cv_fchmodat = yes; then
+
+$as_echo "#define _GLIBCXX_USE_FCHMODAT 1" >>confdefs.h
+
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_fchmodat" >&5
+$as_echo "$glibcxx_cv_fchmodat" >&6; }
CXXFLAGS="$ac_save_CXXFLAGS"
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
GLIBCXX_CHECK_GTHREADS
# For Filesystem TS.
-AC_CHECK_HEADERS([fcntl.h dirent.h sys/statvfs.h])
+AC_CHECK_HEADERS([fcntl.h dirent.h sys/statvfs.h utime.h])
AC_STRUCT_DIRENT_D_TYPE
GLIBCXX_ENABLE_FILESYSTEM_TS
GLIBCXX_CHECK_FILESYSTEM_DEPS
const value_type* __last = __first + _M_pathname.size();
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
- using _CharAlloc = typename __alloc_rebind<_Allocator, char>;
+ using _CharAlloc = __alloc_rebind<_Allocator, char>;
using _String = basic_string<char, char_traits<char>, _CharAlloc>;
using _WString = basic_string<_CharT, _Traits, _Allocator>;
#include <experimental/filesystem>
#include <utility>
#include <stack>
-#include <tuple>
#include <string.h>
#include <errno.h>
#ifdef _GLIBCXX_HAVE_DIRENT_H
# endif
# include <dirent.h>
#else
-// TODO: replace dummy definitions with suitable Win32 code
-#ifndef EACCES
-# define EACCES static_cast<int>(std::errc::permission_denied)
+# error "the <dirent.h> header is needed to build the Filesystem TS"
#endif
-using DIR = void;
-using P = std::experimental::filesystem::path;
-static DIR* opendir(const P::value_type*) { return nullptr; }
-static void closedir(DIR*) { }
-struct dirent { const char* d_name; };
-static inline int readdir_r(DIR*, dirent*, dirent**)
-{ return static_cast<int>(std::errc::not_supported); }
+
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+# undef opendir
+# define opendir _wopendir
#endif
namespace fs = std::experimental::filesystem;
namespace
{
template<typename Bitmask>
- bool is_set(Bitmask obj, Bitmask bits)
+ inline bool is_set(Bitmask obj, Bitmask bits)
{
return (obj & bits) != Bitmask::none;
}
}
#else
return fs::file_type::none;
+#endif
+ }
+
+ int
+ native_readdir(DIR* dirp, ::dirent*& entryp)
+ {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ errno = 0;
+ if ((entryp = ::readdir(dirp)))
+ return 0;
+ return errno;
+#else
+ return ::readdir_r(dirp, entryp, &entryp);
#endif
}
}
fs::_Dir::advance(ErrorCode ec)
{
::dirent ent;
- ::dirent* result;
- if (int err = readdir_r(dirp, &ent, &result))
+ ::dirent* result = &ent;
+ if (int err = native_readdir(dirp, result))
{
if (!ec)
_GLIBCXX_THROW_OR_ABORT(filesystem_error(
# include <ext/stdio_filebuf.h>
# include <ostream>
#endif
+#if _GLIBCXX_HAVE_UTIME_H
+# include <utime.h>
+#endif
+
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+# undef utime
+# define utime _wutime
+# undef chmod
+# define chmod _wchmod
+#endif
namespace fs = std::experimental::filesystem;
namespace
{
template<typename Bitmask>
- bool is_set(Bitmask obj, Bitmask bits)
+ inline bool is_set(Bitmask obj, Bitmask bits)
{
return (obj & bits) != Bitmask::none;
}
namespace
{
template<typename Accessor, typename T>
- T
+ inline T
do_stat(const fs::path& p, std::error_code& ec, Accessor f, T deflt)
{
#ifdef _GLIBCXX_HAVE_SYS_STAT_H
ec.assign(errno, std::generic_category());
else
ec.clear();
+#elif _GLIBCXX_HAVE_UTIME_H
+ ::utimbuf times;
+ times.modtime = s.count();
+ times.actime = do_stat(p, ec, std::mem_fn(&stat::st_atime), times.modtime);
+ if (::utime(p.c_str(), ×))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
#else
ec = std::make_error_code(std::errc::not_supported);
#endif
void fs::permissions(const path& p, perms prms, error_code& ec) noexcept
{
+#if _GLIBCXX_USE_FCHMODAT
if (int err = ::fchmodat(AT_FDCWD, p.c_str(), static_cast<mode_t>(prms), 0))
+#else
+ if (int err = ::chmod(p.c_str(), static_cast<mode_t>(prms)))
+#endif
ec.assign(err, std::generic_category());
else
ec.clear();
};
ec.clear();
}
+#else
+ ec = std::make_error_code(std::errc::not_supported);
#endif
return info;
}
fs::path fs::temp_directory_path(error_code& ec)
{
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ ec = std::make_error_code(std::errc::not_supported);
return {}; // TODO
#else
const char* tmpdir = ::getenv("TMPDIR");