Fix build for systems without POSIX truncate
authorJonathan Wakely <jwakely@redhat.com>
Mon, 7 Jan 2019 12:38:51 +0000 (12:38 +0000)
committerJonathan Wakely <redi@gcc.gnu.org>
Mon, 7 Jan 2019 12:38:51 +0000 (12:38 +0000)
Older versions of newlib do not provide truncate so add a configure
check for it, and provide a fallback definition.

There were also some missing exports in the linker script, which went
unnoticed because there are no tests for some functions. A new link-only
test checks that every filesystem operation function is defined by the
library.

* acinclude.m4 (GLIBCXX_CHECK_FILESYSTEM_DEPS): Check for truncate.
* config.h.in: Regenerate.
* config/abi/pre/gnu.ver: Order patterns for filesystem operations
alphabetically and add missing entries for copy_symlink,
hard_link_count, rename, and resize_file.
* configure: Regenerate.
* src/c++17/fs_ops.cc (resize_file): Remove #if so posix::truncate is
used unconditionally.
* src/filesystem/ops-common.h (__gnu_posix::truncate)
[!_GLIBCXX_HAVE_TRUNCATE]: Provide fallback definition that only
supports truncating to zero length.
* testsuite/27_io/filesystem/operations/all.cc: New test.
* testsuite/27_io/filesystem/operations/resize_file.cc: New test.

From-SVN: r267647

libstdc++-v3/ChangeLog
libstdc++-v3/acinclude.m4
libstdc++-v3/config.h.in
libstdc++-v3/config/abi/pre/gnu.ver
libstdc++-v3/configure
libstdc++-v3/src/c++17/fs_ops.cc
libstdc++-v3/src/filesystem/ops-common.h
libstdc++-v3/testsuite/27_io/filesystem/operations/all.cc [new file with mode: 0644]
libstdc++-v3/testsuite/27_io/filesystem/operations/resize_file.cc [new file with mode: 0644]

index 7d21d89ba9575b67129874c212dd5b00ae914c10..274cf3fe56a882c2a319d8172d16af6ff968c916 100644 (file)
@@ -1,3 +1,19 @@
+2019-01-07  Jonathan Wakely  <jwakely@redhat.com>
+
+       * acinclude.m4 (GLIBCXX_CHECK_FILESYSTEM_DEPS): Check for truncate.
+       * config.h.in: Regenerate.
+       * config/abi/pre/gnu.ver: Order patterns for filesystem operations
+       alphabetically and add missing entries for copy_symlink,
+       hard_link_count, rename, and resize_file.
+       * configure: Regenerate.
+       * src/c++17/fs_ops.cc (resize_file): Remove #if so posix::truncate is
+       used unconditionally.
+       * src/filesystem/ops-common.h (__gnu_posix::truncate)
+       [!_GLIBCXX_HAVE_TRUNCATE]: Provide fallback definition that only
+       supports truncating to zero length.
+       * testsuite/27_io/filesystem/operations/all.cc: New test.
+       * testsuite/27_io/filesystem/operations/resize_file.cc: New test.
+
 2019-01-06  Jonathan Wakely  <jwakely@redhat.com>
 
        PR libstdc++/86756
index ce91e495fabf40ccae5ca5d8acfb8cc854c4e046..8950e4c88727feb5c868cbed13b3e7ecc2021ddb 100644 (file)
@@ -4589,6 +4589,19 @@ dnl
       AC_DEFINE(HAVE_SYMLINK, 1, [Define if symlink is available in <unistd.h>.])
     fi
     AC_MSG_RESULT($glibcxx_cv_symlink)
+dnl
+    AC_MSG_CHECKING([for truncate])
+    AC_CACHE_VAL(glibcxx_cv_truncate, [dnl
+      GCC_TRY_COMPILE_OR_LINK(
+        [#include <unistd.h>],
+        [truncate("", 99);],
+        [glibcxx_cv_truncate=yes],
+        [glibcxx_cv_truncate=no])
+    ])
+    if test $glibcxx_cv_truncate = yes; then
+      AC_DEFINE(HAVE_TRUNCATE, 1, [Define if truncate is available in <unistd.h>.])
+    fi
+    AC_MSG_RESULT($glibcxx_cv_truncate)
 dnl
     CXXFLAGS="$ac_save_CXXFLAGS"
     AC_LANG_RESTORE
index 97b5eed0a9a812a1420aa1e4062c15ca4434c973..225ef1bff9f3d8c3b7712f5d491353e50f6301db 100644 (file)
 /* Define to 1 if the target supports thread-local storage. */
 #undef HAVE_TLS
 
+/* Define if truncate is available in <unistd.h>. */
+#undef HAVE_TRUNCATE
+
 /* Define to 1 if you have the <uchar.h> header file. */
 #undef HAVE_UCHAR_H
 
index 20325bf7a33ff994cdffcc5d110e2a71b3a3da69..02a6ec90375dad749c18cb7d331c6199e7000c96 100644 (file)
@@ -2167,31 +2167,35 @@ GLIBCXX_3.4.26 {
     _ZNSt10filesystem7__cxx114pathpLERKS1_;
     _ZT[IV]NSt10filesystem7__cxx1116filesystem_errorE;
 
-    _ZNSt10filesystem10equivalent*;
-    _ZNSt10filesystem10remove_all*;
-    _ZNSt10filesystem11permissions*;
-    _ZNSt10filesystem12current_path*;
-    _ZNSt10filesystem12read_symlink*;
-    _ZNSt10filesystem14create_symlink*;
-    _ZNSt10filesystem14symlink_status*;
-    _ZNSt10filesystem15last_write_time*;
-    _ZNSt10filesystem16create_directory*;
-    _ZNSt10filesystem16create_hard_link*;
-    _ZNSt10filesystem16weakly_canonical*;
-    _ZNSt10filesystem18create_directories*;
-    _ZNSt10filesystem19temp_directory_path*;
-    _ZNSt10filesystem24create_directory_symlink*;
-    _ZNSt10filesystem4copy*;
-    _ZNSt10filesystem5space*;
-    _ZNSt10filesystem6remove*;
-    _ZNSt10filesystem6status*;
     _ZNSt10filesystem8absolute*;
-    _ZNSt10filesystem8is_empty*;
-    _ZNSt10filesystem8relative*;
     _ZNSt10filesystem9canonical*;
+    _ZNSt10filesystem4copy*;
     _ZNSt10filesystem9copy_file*;
+    _ZNSt10filesystem12copy_symlink*;
+    _ZNSt10filesystem18create_directories*;
+    _ZNSt10filesystem16create_directory*;
+    _ZNSt10filesystem24create_directory_symlink*;
+    _ZNSt10filesystem16create_hard_link*;
+    _ZNSt10filesystem14create_symlink*;
+    _ZNSt10filesystem12current_path*;
+    _ZNSt10filesystem10equivalent*;
     _ZNSt10filesystem9file_size*;
+    _ZNSt10filesystem15hard_link_count*;
+    _ZNSt10filesystem8is_empty*;
+    _ZNSt10filesystem15last_write_time*;
+    _ZNSt10filesystem11permissions*;
     _ZNSt10filesystem9proximate*;
+    _ZNSt10filesystem12read_symlink*;
+    _ZNSt10filesystem8relative*;
+    _ZNSt10filesystem6remove*;
+    _ZNSt10filesystem10remove_all*;
+    _ZNSt10filesystem6rename*;
+    _ZNSt10filesystem11resize_file*;
+    _ZNSt10filesystem5space*;
+    _ZNSt10filesystem6status*;
+    _ZNSt10filesystem14symlink_status*;
+    _ZNSt10filesystem19temp_directory_path*;
+    _ZNSt10filesystem16weakly_canonical*;
 
     _ZNKSt10filesystem18directory_iteratordeEv;
     _ZNKSt10filesystem28recursive_directory_iterator5depthEv;
index e01d900ad0b704314f0a3462315a270b8346684c..15848e364ab26aa874b18d76b5aaf6705ddae5dc 100755 (executable)
@@ -81038,6 +81038,62 @@ $as_echo "#define HAVE_SYMLINK 1" >>confdefs.h
     fi
     { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_symlink" >&5
 $as_echo "$glibcxx_cv_symlink" >&6; }
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for truncate" >&5
+$as_echo_n "checking for truncate... " >&6; }
+    if ${glibcxx_cv_truncate+:} false; 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 <unistd.h>
+int
+main ()
+{
+truncate("", 99);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  glibcxx_cv_truncate=yes
+else
+  glibcxx_cv_truncate=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 <unistd.h>
+int
+main ()
+{
+truncate("", 99);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  glibcxx_cv_truncate=yes
+else
+  glibcxx_cv_truncate=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+
+fi
+
+    if test $glibcxx_cv_truncate = yes; then
+
+$as_echo "#define HAVE_TRUNCATE 1" >>confdefs.h
+
+    fi
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_truncate" >&5
+$as_echo "$glibcxx_cv_truncate" >&6; }
     CXXFLAGS="$ac_save_CXXFLAGS"
     ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
index fd8cf353ba2b299525053d156cdc7d92958501c5..edd9315980bc95c77cfe9de38f61bcb028fde79a 100644 (file)
@@ -1268,16 +1268,12 @@ fs::resize_file(const path& p, uintmax_t size)
 void
 fs::resize_file(const path& p, uintmax_t size, error_code& ec) noexcept
 {
-#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 (posix::truncate(p.c_str(), size))
     ec.assign(errno, std::generic_category());
   else
     ec.clear();
-#else
-  ec = std::make_error_code(std::errc::not_supported);
-#endif
 }
 
 
index f20867c217e441d2ea6365dd1e4bcef0a4428984..55e482ff8f28c905a8a1454d75241e76c8e742a7 100644 (file)
@@ -29,6 +29,9 @@
 
 #ifdef _GLIBCXX_HAVE_UNISTD_H
 # include <unistd.h>
+# ifdef _GLIBCXX_HAVE_FCNTL_H
+#  include <fcntl.h>  // AT_FDCWD, O_TRUNC etc.
+# endif
 # if defined(_GLIBCXX_HAVE_SYS_STAT_H) && defined(_GLIBCXX_HAVE_SYS_TYPES_H)
 #  include <sys/types.h>
 #  include <sys/stat.h>
@@ -139,7 +142,23 @@ namespace __gnu_posix
   using ::utime;
 # endif
   using ::rename;
+# ifdef _GLIBCXX_HAVE_TRUNCATE
   using ::truncate;
+# else
+  inline int truncate(const char* path, off_t length)
+  {
+    if (length == 0)
+      {
+       const int fd = ::open(path, O_WRONLY|O_TRUNC);
+       if (fd == -1)
+         return fd;
+       ::close(fd);
+       return 0;
+      }
+    errno = ENOTSUP;
+    return -1;
+  }
+# endif
   using char_type = char;
 #else // ! _GLIBCXX_FILESYSTEM_IS_WINDOWS && ! _GLIBCXX_HAVE_UNISTD_H
   inline int open(const char*, int, ...) { errno = ENOTSUP; return -1; }
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/all.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/all.cc
new file mode 100644 (file)
index 0000000..c9f34f4
--- /dev/null
@@ -0,0 +1,188 @@
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++17 } }
+
+// Copyright (C) 2019 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.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -fno-inline" }
+// { dg-do link { target c++17 } }
+
+// C++17 30.10.15 Filesystem operation functions [fs.op.funcs]
+
+#include <filesystem>
+
+// Link-only test to ensure all operation functions are exported from the lib.
+
+int
+main()
+{
+  const std::filesystem::path p;
+  std::filesystem::path p2;
+  const std::filesystem::copy_options copyopts{};
+  const std::filesystem::file_status st{};
+  std::filesystem::file_status st2;
+  const std::filesystem::file_time_type t;
+  std::filesystem::file_time_type t2;
+  const std::filesystem::perms perms{};
+  const std::filesystem::perm_options permopts{};
+  std::filesystem::space_info sp;
+  std::error_code ec;
+  bool b;
+  std::uintmax_t size;
+
+  std::filesystem::absolute(p);
+  std::filesystem::absolute(p, ec);
+
+  std::filesystem::canonical(p);
+  std::filesystem::canonical(p, ec);
+
+  std::filesystem::copy(p, p);
+  std::filesystem::copy(p, p, ec);
+  std::filesystem::copy(p, p, copyopts);
+  std::filesystem::copy(p, p, copyopts, ec);
+
+  std::filesystem::copy_file(p, p);
+  std::filesystem::copy_file(p, p, ec);
+  std::filesystem::copy_file(p, p, copyopts);
+  std::filesystem::copy_file(p, p, copyopts, ec);
+
+  std::filesystem::copy_symlink(p, p);
+  std::filesystem::copy_symlink(p, p, ec);
+
+  std::filesystem::create_directories(p);
+  std::filesystem::create_directories(p, ec);
+
+  std::filesystem::create_directory(p);
+  std::filesystem::create_directory(p, ec);
+
+  std::filesystem::create_directory(p, p);
+  std::filesystem::create_directory(p, p, ec);
+
+  std::filesystem::create_directory_symlink(p, p);
+  std::filesystem::create_directory_symlink(p, p, ec);
+
+  std::filesystem::create_hard_link(p, p);
+  std::filesystem::create_hard_link(p, p, ec);
+
+  std::filesystem::create_symlink(p, p);
+  std::filesystem::create_symlink(p, p, ec);
+
+  p2 = std::filesystem::current_path();
+  p2 = std::filesystem::current_path(ec);
+  std::filesystem::current_path(p);
+  std::filesystem::current_path(p, ec);
+
+  b = std::filesystem::equivalent(p, p);
+  b = std::filesystem::equivalent(p, p, ec);
+
+  b = std::filesystem::exists(st);
+  b = std::filesystem::exists(p);
+  b = std::filesystem::exists(p, ec);
+
+  size = std::filesystem::file_size(p);
+  size = std::filesystem::file_size(p, ec);
+
+  size = std::filesystem::hard_link_count(p);
+  size = std::filesystem::hard_link_count(p, ec);
+
+  b = std::filesystem::is_block_file(st);
+  b = std::filesystem::is_block_file(p);
+  b = std::filesystem::is_block_file(p, ec);
+
+  b = std::filesystem::is_character_file(st);
+  b = std::filesystem::is_character_file(p);
+  b = std::filesystem::is_character_file(p, ec);
+
+  b = std::filesystem::is_directory(st);
+  b = std::filesystem::is_directory(p);
+  b = std::filesystem::is_directory(p, ec);
+
+  b = std::filesystem::is_empty(p);
+  b = std::filesystem::is_empty(p, ec);
+
+  b = std::filesystem::is_fifo(st);
+  b = std::filesystem::is_fifo(p);
+  b = std::filesystem::is_fifo(p, ec);
+
+  b = std::filesystem::is_other(st);
+  b = std::filesystem::is_other(p);
+  b = std::filesystem::is_other(p, ec);
+
+  b = std::filesystem::is_regular_file(st);
+  b = std::filesystem::is_regular_file(p);
+  b = std::filesystem::is_regular_file(p, ec);
+
+  b = std::filesystem::is_socket(st);
+  b = std::filesystem::is_socket(p);
+  b = std::filesystem::is_socket(p, ec);
+
+  b = std::filesystem::is_symlink(st);
+  b = std::filesystem::is_symlink(p);
+  b = std::filesystem::is_symlink(p, ec);
+
+  t2 = std::filesystem::last_write_time(p);
+  t2 = std::filesystem::last_write_time(p, ec);
+  std::filesystem::last_write_time(p, t);
+  std::filesystem::last_write_time(p, t, ec);
+
+  std::filesystem::permissions(p, perms);
+  std::filesystem::permissions(p, perms, permopts);
+  std::filesystem::permissions(p, perms, ec);
+  std::filesystem::permissions(p, perms, permopts, ec);
+
+  p2 = std::filesystem::proximate(p, ec);
+  p2 = std::filesystem::proximate(p);
+  p2 = std::filesystem::proximate(p, p);
+  p2 = std::filesystem::proximate(p, p, ec);
+
+  p2 = std::filesystem::read_symlink(p);
+  p2 = std::filesystem::read_symlink(p, ec);
+
+  p2 = std::filesystem::relative(p, ec);
+  p2 = std::filesystem::relative(p);
+  p2 = std::filesystem::relative(p, p);
+  p2 = std::filesystem::relative(p, p, ec);
+
+  b = std::filesystem::remove(p);
+  b = std::filesystem::remove(p, ec);
+
+  size = std::filesystem::remove_all(p);
+  size = std::filesystem::remove_all(p, ec);
+
+  std::filesystem::rename(p, p);
+  std::filesystem::rename(p, p, ec);
+
+  std::filesystem::resize_file(p, size);
+  std::filesystem::resize_file(p, size, ec);
+
+  sp = std::filesystem::space(p);
+  sp = std::filesystem::space(p, ec);
+
+  st2 = std::filesystem::status(p);
+  st2 = std::filesystem::status(p, ec);
+
+  b = std::filesystem::status_known(st);
+
+  st2 = std::filesystem::symlink_status(p);
+  st2 = std::filesystem::symlink_status(p, ec);
+
+  p2 = std::filesystem::temp_directory_path();
+  p2 = std::filesystem::temp_directory_path(ec);
+
+  p2 = std::filesystem::weakly_canonical(p);
+  p2 = std::filesystem::weakly_canonical(p, ec);
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/resize_file.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/resize_file.cc
new file mode 100644 (file)
index 0000000..953c4e1
--- /dev/null
@@ -0,0 +1,72 @@
+// Copyright (C) 2019 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.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++17 } }
+
+// C++17 30.10.15.33 Resize file [fs.op.resize_file]
+
+#include <filesystem>
+#include <string>
+#include <fstream>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  auto p = __gnu_test::nonexistent_path();
+  std::error_code ec;
+  resize_file(p, 0, ec);
+  VERIFY( ec );
+  ec = {};
+  resize_file(p, 1, ec);
+  VERIFY( ec );
+
+  __gnu_test::scoped_file f(p);
+  std::ofstream{p} << "some text";
+  std::ifstream fin;
+  std::string input;
+
+#ifdef _GLIBCXX_HAVE_TRUNCATE
+  resize_file(p, 4, ec);
+  VERIFY( !ec );
+  fin.open(p);
+  getline(fin, input);
+  VERIFY( input.length() == 4 );
+  fin.close();
+
+  resize_file(p, 2);
+  fin.open(p);
+  getline(fin, input);
+  VERIFY( input.length() == 2 );
+  fin.close();
+#endif
+
+  resize_file(p, 0, ec);
+  VERIFY( !ec );
+  fin.open(p);
+  getline(fin, input);
+  VERIFY( input.length() == 0 );
+  fin.close();
+}
+
+int
+main()
+{
+  test01();
+}