Commit 30362998 by Jonathan Wakely Committed by Jonathan Wakely

Implement filesystem::canonical() without realpath

	PR libstdc++/67173
	* acinclude.m4 (GLIBCXX_CHECK_FILESYSTEM_DEPS): Check _XOPEN_VERSION
	and PATH_MAX for _GLIBCXX_USE_REALPATH.
	* config.h.in: Regenerate.
	* configure: Regenerate.
	* src/filesystem/ops.cc: (canonical) [!_GLIBCXX_USE_REALPATH]: Add
	alternative implementation.
	* testsuite/experimental/filesystem/operations/canonical.cc: New.
	* testsuite/experimental/filesystem/operations/exists.cc: Add more
	tests.
	* testsuite/experimental/filesystem/operations/absolute.cc: Add test
	variables.
	* testsuite/experimental/filesystem/operations/copy.cc: Likewise.
	* testsuite/experimental/filesystem/operations/current_path.cc:
	Likewise.
	* testsuite/experimental/filesystem/operations/file_size.cc: Likewise.
	* testsuite/experimental/filesystem/operations/status.cc: Likewise.
	* testsuite/experimental/filesystem/operations/temp_directory_path.cc:
	Likewise.

From-SVN: r227836
parent 4ec39494
2015-09-16 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/67173
* acinclude.m4 (GLIBCXX_CHECK_FILESYSTEM_DEPS): Check _XOPEN_VERSION
and PATH_MAX for _GLIBCXX_USE_REALPATH.
* config.h.in: Regenerate.
* configure: Regenerate.
* src/filesystem/ops.cc: (canonical) [!_GLIBCXX_USE_REALPATH]: Add
alternative implementation.
* testsuite/experimental/filesystem/operations/canonical.cc: New.
* testsuite/experimental/filesystem/operations/exists.cc: Add more
tests.
* testsuite/experimental/filesystem/operations/absolute.cc: Add test
variables.
* testsuite/experimental/filesystem/operations/copy.cc: Likewise.
* testsuite/experimental/filesystem/operations/current_path.cc:
Likewise.
* testsuite/experimental/filesystem/operations/file_size.cc: Likewise.
* testsuite/experimental/filesystem/operations/status.cc: Likewise.
* testsuite/experimental/filesystem/operations/temp_directory_path.cc:
Likewise.
2015-09-11 Jonathan Wakely <jwakely@redhat.com> 2015-09-11 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/67173 PR libstdc++/67173
......
...@@ -3947,13 +3947,24 @@ dnl ...@@ -3947,13 +3947,24 @@ dnl
AC_MSG_CHECKING([for realpath]) AC_MSG_CHECKING([for realpath])
AC_CACHE_VAL(glibcxx_cv_realpath, [dnl AC_CACHE_VAL(glibcxx_cv_realpath, [dnl
GCC_TRY_COMPILE_OR_LINK( GCC_TRY_COMPILE_OR_LINK(
[#include <stdlib.h>], [
[char *tmp = realpath((const char*)NULL, (char*)NULL);], #include <stdlib.h>
#include <unistd.h>
],
[
#if _XOPEN_VERSION < 500
#error
#elif _XOPEN_VERSION >= 700 || defined(PATH_MAX)
char *tmp = realpath((const char*)NULL, (char*)NULL);
#else
#error
#endif
],
[glibcxx_cv_realpath=yes], [glibcxx_cv_realpath=yes],
[glibcxx_cv_realpath=no]) [glibcxx_cv_realpath=no])
]) ])
if test $glibcxx_cv_realpath = yes; then if test $glibcxx_cv_realpath = yes; then
AC_DEFINE(_GLIBCXX_USE_REALPATH, 1, [Define if realpath is available in <stdlib.h>.]) AC_DEFINE(_GLIBCXX_USE_REALPATH, 1, [Define if usable realpath is available in <stdlib.h>.])
fi fi
AC_MSG_RESULT($glibcxx_cv_realpath) AC_MSG_RESULT($glibcxx_cv_realpath)
dnl dnl
......
...@@ -883,7 +883,7 @@ ...@@ -883,7 +883,7 @@
of TR1 (Chapter 5.1). */ of TR1 (Chapter 5.1). */
#undef _GLIBCXX_USE_RANDOM_TR1 #undef _GLIBCXX_USE_RANDOM_TR1
/* Define if realpath is available in <stdlib.h>. */ /* Define if usable realpath is available in <stdlib.h>. */
#undef _GLIBCXX_USE_REALPATH #undef _GLIBCXX_USE_REALPATH
/* Defined if sched_yield is available. */ /* Defined if sched_yield is available. */
......
...@@ -79178,11 +79178,22 @@ else ...@@ -79178,11 +79178,22 @@ else
if test x$gcc_no_link = xyes; then if test x$gcc_no_link = xyes; then
cat confdefs.h - <<_ACEOF >conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */ /* end confdefs.h. */
#include <stdlib.h>
#include <stdlib.h>
#include <unistd.h>
int int
main () main ()
{ {
char *tmp = realpath((const char*)NULL, (char*)NULL);
#if _XOPEN_VERSION < 500
#error
#elif _XOPEN_VERSION >= 700 || defined(PATH_MAX)
char *tmp = realpath((const char*)NULL, (char*)NULL);
#else
#error
#endif
; ;
return 0; return 0;
} }
...@@ -79199,11 +79210,22 @@ else ...@@ -79199,11 +79210,22 @@ else
fi fi
cat confdefs.h - <<_ACEOF >conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */ /* end confdefs.h. */
#include <stdlib.h>
#include <stdlib.h>
#include <unistd.h>
int int
main () main ()
{ {
char *tmp = realpath((const char*)NULL, (char*)NULL);
#if _XOPEN_VERSION < 500
#error
#elif _XOPEN_VERSION >= 700 || defined(PATH_MAX)
char *tmp = realpath((const char*)NULL, (char*)NULL);
#else
#error
#endif
; ;
return 0; return 0;
} }
...@@ -96,23 +96,98 @@ namespace ...@@ -96,23 +96,98 @@ namespace
fs::path fs::path
fs::canonical(const path& p, const path& base, error_code& ec) fs::canonical(const path& p, const path& base, error_code& ec)
{ {
path can; const path pa = absolute(p, base);
path result;
#ifdef _GLIBCXX_USE_REALPATH #ifdef _GLIBCXX_USE_REALPATH
char* buffer = nullptr; char_ptr buf{ nullptr };
#if defined(__SunOS_5_10) && defined(PATH_MAX) # if _XOPEN_VERSION < 700
buffer = (char*)::malloc(PATH_MAX); // Not safe to call realpath(path, NULL)
#endif buf.reset( (char*)::malloc(PATH_MAX) );
if (char_ptr rp = char_ptr{::realpath(absolute(p, base).c_str(), buffer)}) # endif
if (char* rp = ::realpath(pa.c_str(), buf.get()))
{ {
can.assign(rp.get()); if (buf == nullptr)
buf.reset(rp);
result.assign(rp);
ec.clear(); ec.clear();
return result;
}
if (errno != ENAMETOOLONG)
{
ec.assign(errno, std::generic_category());
return result;
} }
else
ec.assign(errno, std::generic_category());
#else
ec = std::make_error_code(std::errc::not_supported);
#endif #endif
return can;
auto fail = [&ec, &result](int e) mutable {
if (!ec.value())
ec.assign(e, std::generic_category());
result.clear();
};
if (!exists(pa, ec))
{
fail(ENOENT);
return result;
}
// else we can assume no unresolvable symlink loops
result = pa.root_path();
deque<path> cmpts;
for (auto& f : pa.relative_path())
cmpts.push_back(f);
while (!cmpts.empty())
{
path f = std::move(cmpts.front());
cmpts.pop_front();
if (f.compare(".") == 0)
{
if (!is_directory(result, ec))
{
fail(ENOTDIR);
break;
}
}
else if (f.compare("..") == 0)
{
auto parent = result.parent_path();
if (parent.empty())
result = pa.root_path();
else
result.swap(parent);
}
else
{
result /= f;
if (is_symlink(result, ec))
{
path link = read_symlink(result, ec);
if (!ec.value())
{
if (link.is_absolute())
{
result = link.root_path();
link = link.relative_path();
}
else
result.remove_filename();
cmpts.insert(cmpts.begin(), link.begin(), link.end());
}
}
if (ec.value() || !exists(result, ec))
{
fail(ENOENT);
break;
}
}
}
return result;
} }
fs::path fs::path
......
...@@ -29,6 +29,8 @@ using std::experimental::filesystem::path; ...@@ -29,6 +29,8 @@ using std::experimental::filesystem::path;
void void
test01() test01()
{ {
bool test __attribute__((unused)) = false;
for (const path& p : __gnu_test::test_paths) for (const path& p : __gnu_test::test_paths)
VERIFY( absolute(p).is_absolute() ); VERIFY( absolute(p).is_absolute() );
} }
...@@ -36,6 +38,8 @@ test01() ...@@ -36,6 +38,8 @@ test01()
void void
test02() test02()
{ {
bool test __attribute__((unused)) = false;
path p1("/"); path p1("/");
VERIFY( absolute(p1) == p1 ); VERIFY( absolute(p1) == p1 );
VERIFY( absolute(p1, "/bar") == p1 ); VERIFY( absolute(p1, "/bar") == p1 );
......
// Copyright (C) 2015 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++11 -lstdc++fs" }
// { dg-require-filesystem-ts "" }
#include <experimental/filesystem>
#include <testsuite_hooks.h>
#include <testsuite_fs.h>
namespace fs = std::experimental::filesystem;
void
test01()
{
bool test __attribute__((unused)) = false;
std::error_code ec;
auto p = __gnu_test::nonexistent_path();
canonical( p, ec );
VERIFY( ec );
p = fs::current_path();
canonical( p, ec );
VERIFY( !ec );
p = "/";
p = canonical( p, ec );
VERIFY( p == "/" );
VERIFY( !ec );
p = "/.";
p = canonical( p, ec );
VERIFY( p == "/" );
VERIFY( !ec );
p = "/..";
p = canonical( p, ec );
VERIFY( p == "/" );
VERIFY( !ec );
p = "/../.././.";
p = canonical( p, ec );
VERIFY( p == "/" );
VERIFY( !ec );
p = "/dev/stdin";
if (exists(p))
{
auto p2 = canonical(p);
if (is_symlink(p))
VERIFY( p != p2 );
else
VERIFY( p == p2 );
VERIFY( canonical(p2) == p2 );
}
}
int
main()
{
test01();
}
...@@ -29,6 +29,8 @@ using std::experimental::filesystem::path; ...@@ -29,6 +29,8 @@ using std::experimental::filesystem::path;
void void
test01() test01()
{ {
bool test __attribute__((unused)) = false;
for (const path& p : __gnu_test::test_paths) for (const path& p : __gnu_test::test_paths)
VERIFY( absolute(p).is_absolute() ); VERIFY( absolute(p).is_absolute() );
} }
...@@ -36,6 +38,8 @@ test01() ...@@ -36,6 +38,8 @@ test01()
void void
test02() test02()
{ {
bool test __attribute__((unused)) = false;
path p1("/"); path p1("/");
VERIFY( absolute(p1) == p1 ); VERIFY( absolute(p1) == p1 );
VERIFY( absolute(p1, "/bar") == p1 ); VERIFY( absolute(p1, "/bar") == p1 );
......
...@@ -29,6 +29,8 @@ namespace fs = std::experimental::filesystem; ...@@ -29,6 +29,8 @@ namespace fs = std::experimental::filesystem;
void void
test01() test01()
{ {
bool test __attribute__((unused)) = false;
fs::path dot("."); fs::path dot(".");
fs::path cwd = fs::current_path(); fs::path cwd = fs::current_path();
std::error_code ec; std::error_code ec;
...@@ -39,6 +41,8 @@ test01() ...@@ -39,6 +41,8 @@ test01()
void void
test02() test02()
{ {
bool test __attribute__((unused)) = false;
auto oldwd = fs::current_path(); auto oldwd = fs::current_path();
auto tmpdir = fs::temp_directory_path(); auto tmpdir = fs::temp_directory_path();
current_path(tmpdir); current_path(tmpdir);
......
...@@ -20,32 +20,37 @@ ...@@ -20,32 +20,37 @@
#include <experimental/filesystem> #include <experimental/filesystem>
#include <testsuite_hooks.h> #include <testsuite_hooks.h>
#include <testsuite_fs.h>
using std::experimental::filesystem::path; using std::experimental::filesystem::path;
void void
test01() test01()
{ {
bool test __attribute__((unused)) = false;
VERIFY( exists(path{"/"}) ); VERIFY( exists(path{"/"}) );
VERIFY( exists(path{"/."}) ); VERIFY( exists(path{"/."}) );
VERIFY( exists(path{"."}) ); VERIFY( exists(path{"."}) );
VERIFY( exists(path{".."}) );
VERIFY( exists(std::experimental::filesystem::current_path()) );
} }
void void
test02() test02()
{ {
path rel{"xXxXx"}; bool test __attribute__((unused)) = false;
while (exists(rel))
rel /= "x"; path rel = __gnu_test::nonexistent_path();
VERIFY( !exists(rel) ); VERIFY( !exists(rel) );
} }
void void
test03() test03()
{ {
path abs{"/xXxXx"}; bool test __attribute__((unused)) = false;
while (exists(abs))
abs /= "x"; path abs = absolute(__gnu_test::nonexistent_path());
VERIFY( !exists(abs) ); VERIFY( !exists(abs) );
} }
......
...@@ -27,6 +27,8 @@ namespace fs = std::experimental::filesystem; ...@@ -27,6 +27,8 @@ namespace fs = std::experimental::filesystem;
void void
test01() test01()
{ {
bool test __attribute__((unused)) = false;
std::error_code ec; std::error_code ec;
size_t size = fs::file_size(".", ec); size_t size = fs::file_size(".", ec);
VERIFY( ec == std::errc::is_a_directory ); VERIFY( ec == std::errc::is_a_directory );
...@@ -45,6 +47,8 @@ test01() ...@@ -45,6 +47,8 @@ test01()
void void
test02() test02()
{ {
bool test __attribute__((unused)) = false;
fs::path p = __gnu_test::nonexistent_path(); fs::path p = __gnu_test::nonexistent_path();
std::error_code ec; std::error_code ec;
......
...@@ -27,6 +27,8 @@ namespace fs = std::experimental::filesystem; ...@@ -27,6 +27,8 @@ namespace fs = std::experimental::filesystem;
void void
test01() test01()
{ {
bool test __attribute__((unused)) = false;
std::error_code ec; std::error_code ec;
fs::file_status st1 = fs::status(".", ec); fs::file_status st1 = fs::status(".", ec);
VERIFY( !ec ); VERIFY( !ec );
...@@ -39,6 +41,8 @@ test01() ...@@ -39,6 +41,8 @@ test01()
void void
test02() test02()
{ {
bool test __attribute__((unused)) = false;
fs::path p = __gnu_test::nonexistent_path(); fs::path p = __gnu_test::nonexistent_path();
std::error_code ec; std::error_code ec;
......
...@@ -37,6 +37,8 @@ namespace fs = std::experimental::filesystem; ...@@ -37,6 +37,8 @@ namespace fs = std::experimental::filesystem;
void void
test01() test01()
{ {
bool test __attribute__((unused)) = false;
clean_env(); clean_env();
if (!fs::exists("/tmp")) if (!fs::exists("/tmp"))
...@@ -53,6 +55,8 @@ test01() ...@@ -53,6 +55,8 @@ test01()
void void
test02() test02()
{ {
bool test __attribute__((unused)) = false;
clean_env(); clean_env();
if (::setenv("TMPDIR", __gnu_test::nonexistent_path().string().c_str(), 1)) if (::setenv("TMPDIR", __gnu_test::nonexistent_path().string().c_str(), 1))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment