2015-05-14 Jonathan Wakely <jwakely@redhat.com>
+ PR libstdc++/66011
+ * acinclude.m4 (GLIBCXX_CHECK_FILESYSTEM_DEPS): Check for fchmod and
+ sendfile.
+ * config.h.in: Regenerate.
+ * configure: Regenerate.
+ * src/filesystem/ops.cc (do_copy_file): Fix arguments to open(). Do
+ not return after copying contents. Use fchmod, fchmodat, and sendfile
+ when available.
+ (current_path, permissions, space): Use errno not return value.
+
PR libstdc++/66018
* acinclude.m4 (GLIBCXX_CHECK_FILESYSTEM_DEPS): Check for struct
dirent.d_type.
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 fchmod])
+ AC_CACHE_VAL(glibcxx_cv_fchmod, [dnl
+ GCC_TRY_COMPILE_OR_LINK(
+ [#include <sys/stat.h>],
+ [fchmod(1, S_IWUSR);],
+ [glibcxx_cv_fchmod=yes],
+ [glibcxx_cv_fchmod=no])
+ ])
+ if test $glibcxx_cv_fchmod = yes; then
+ AC_DEFINE(_GLIBCXX_USE_FCHMOD, 1, [Define if fchmod is available in <sys/stat.h>.])
+ fi
+ AC_MSG_RESULT($glibcxx_cv_fchmod)
dnl
AC_MSG_CHECKING([for fchmodat])
AC_CACHE_VAL(glibcxx_cv_fchmodat, [dnl
AC_DEFINE(_GLIBCXX_USE_FCHMODAT, 1, [Define if fchmodat is available in <sys/stat.h>.])
fi
AC_MSG_RESULT($glibcxx_cv_fchmodat)
+dnl
+ AC_MSG_CHECKING([for sendfile that can copy files])
+ AC_CACHE_VAL(glibcxx_cv_sendfile, [dnl
+ case "${target_os}" in
+ gnu* | linux* | solaris*)
+ GCC_TRY_COMPILE_OR_LINK(
+ [#include <sys/sendfile.h>],
+ [sendfile(1, 2, (off_t*)NULL, sizeof 1);],
+ [glibcxx_cv_sendfile=yes],
+ [glibcxx_cv_sendfile=no])
+ ;;
+ *)
+ glibcxx_cv_sendfile=no
+ ;;
+ esac
+ ])
+ if test $glibcxx_cv_sendfile = yes; then
+ AC_DEFINE(_GLIBCXX_USE_SENDFILE, 1, [Define if sendfile is available in <sys/stat.h>.])
+ fi
+ AC_MSG_RESULT($glibcxx_cv_sendfile)
dnl
CXXFLAGS="$ac_save_CXXFLAGS"
AC_LANG_RESTORE
this host. */
#undef _GLIBCXX_USE_DECIMAL_FLOAT
+/* Define if fchmod is available in <sys/stat.h>. */
+#undef _GLIBCXX_USE_FCHMOD
+
/* Define if fchmodat is available in <sys/stat.h>. */
#undef _GLIBCXX_USE_FCHMODAT
/* Define if _SC_NPROC_ONLN is available in <unistd.h>. */
#undef _GLIBCXX_USE_SC_NPROC_ONLN
+/* Define if sendfile is available in <sys/stat.h>. */
+#undef _GLIBCXX_USE_SENDFILE
+
/* Define if struct stat has timespec members. */
#undef _GLIBCXX_USE_ST_MTIM
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 fchmod" >&5
+$as_echo_n "checking for fchmod... " >&6; }
+ if test "${glibcxx_cv_fchmod+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 <sys/stat.h>
+int
+main ()
+{
+fchmod(1, S_IWUSR);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ glibcxx_cv_fchmod=yes
+else
+ glibcxx_cv_fchmod=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 <sys/stat.h>
+int
+main ()
+{
+fchmod(1, S_IWUSR);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ glibcxx_cv_fchmod=yes
+else
+ glibcxx_cv_fchmod=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+
+fi
+
+ if test $glibcxx_cv_fchmod = yes; then
+
+$as_echo "#define _GLIBCXX_USE_FCHMOD 1" >>confdefs.h
+
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_fchmod" >&5
+$as_echo "$glibcxx_cv_fchmod" >&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 :
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_fchmodat" >&5
$as_echo "$glibcxx_cv_fchmodat" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sendfile that can copy files" >&5
+$as_echo_n "checking for sendfile that can copy files... " >&6; }
+ if test "${glibcxx_cv_sendfile+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ case "${target_os}" in
+ gnu* | linux* | kfreebsd*-gnu | knetbsd*-gnu | solaris*)
+ if test x$gcc_no_link = xyes; then
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/sendfile.h>
+int
+main ()
+{
+sendfile(1, 2, (off_t*)NULL, sizeof 1);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ glibcxx_cv_sendfile=yes
+else
+ glibcxx_cv_sendfile=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 <sys/sendfile.h>
+int
+main ()
+{
+sendfile(1, 2, (off_t*)NULL, sizeof 1);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ glibcxx_cv_sendfile=yes
+else
+ glibcxx_cv_sendfile=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+ ;;
+ *)
+ glibcxx_cv_sendfile=no
+ ;;
+ esac
+
+fi
+
+ if test $glibcxx_cv_sendfile = yes; then
+
+$as_echo "#define _GLIBCXX_USE_SENDFILE 1" >>confdefs.h
+
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_sendfile" >&5
+$as_echo "$glibcxx_cv_sendfile" >&6; }
CXXFLAGS="$ac_save_CXXFLAGS"
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
# include <sys/statvfs.h>
#endif
-#ifdef _GLIBCXX_HAVE_GNU_SENDFILE
+#ifdef _GLIBCXX_USE_SENDFILE
# include <sys/sendfile.h>
#else
# include <ext/stdio_filebuf.h>
}
f = make_file_status(*from_st);
+ using opts = fs::copy_options;
+
if (exists(t))
{
if (!is_other(t) && !is_other(f)
return false;
}
- if (is_set(option, fs::copy_options::skip_existing))
+ if (is_set(option, opts::skip_existing))
{
ec.clear();
return false;
}
- else if (is_set(option, fs::copy_options::update_existing))
+ else if (is_set(option, opts::update_existing))
{
if (file_time(*from_st) <= file_time(*to_st))
{
return false;
}
}
- else if (!is_set(option, fs::copy_options::overwrite_existing))
+ else if (!is_set(option, opts::overwrite_existing))
{
ec = std::make_error_code(std::errc::file_exists);
return false;
ec.assign(errno, std::generic_category());
return false;
}
- CloseFD out = { ::open(to.c_str(), O_WRONLY|O_CREAT) };
+ int oflag = O_WRONLY|O_CREAT;
+ if (is_set(option, opts::overwrite_existing|opts::update_existing))
+ oflag |= O_TRUNC;
+ else
+ oflag |= O_EXCL;
+ CloseFD out = { ::open(to.c_str(), oflag, S_IWUSR) };
if (out.fd == -1)
{
- ec.assign(errno, std::generic_category());
+ if (errno == EEXIST && is_set(option, opts::skip_existing))
+ ec.clear();
+ else
+ ec.assign(errno, std::generic_category());
return false;
}
-#ifdef _GLIBCXX_HAVE_GNU_SENDFILE
+#ifdef _GLIBCXX_USE_SENDFILE
auto n = ::sendfile(out.fd, in.fd, nullptr, from_st->st_size);
if (n != from_st->st_size)
{
#else
__gnu_cxx::stdio_filebuf<char> sbin(in.fd, std::ios::in);
__gnu_cxx::stdio_filebuf<char> sbout(out.fd, std::ios::out);
- if (std::ostream(&sbout) << &sbin)
- {
- ec.clear();
- return true;
- }
- else
+ if ( !(std::ostream(&sbout) << &sbin) )
{
ec = std::make_error_code(std::errc::io_error);
return false;
}
#endif
-#ifdef _GLIBCXX_HAVE_FCHMOD
+#ifdef _GLIBCXX_USE_FCHMOD
if (::fchmod(out.fd, from_st->st_mode))
+#elif _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))
#endif
ec.assign(errno, std::generic_category());
return false;
}
+ ec.clear();
return true;
}
}
fs::current_path(const path& p, error_code& ec) noexcept
{
#ifdef _GLIBCXX_HAVE_UNISTD_H
- if (int err = ::chdir(p.c_str()))
- ec.assign(err, std::generic_category());
+ if (::chdir(p.c_str()))
+ ec.assign(errno, std::generic_category());
else
ec.clear();
#else
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))
+ if (::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)))
+ if (::chmod(p.c_str(), static_cast<mode_t>(prms)))
#endif
- ec.assign(err, std::generic_category());
+ ec.assign(errno, std::generic_category());
else
ec.clear();
}
};
#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
struct ::statvfs f;
- if (int err = ::statvfs(p.c_str(), &f))
- ec.assign(err, std::generic_category());
+ if (::statvfs(p.c_str(), &f))
+ ec.assign(errno, std::generic_category());
else
{
info = space_info{