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
This commit is contained in:
parent
4ec39494ac
commit
3036299861
@ -1,3 +1,25 @@
|
||||
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>
|
||||
|
||||
PR libstdc++/67173
|
||||
|
@ -3947,13 +3947,24 @@ dnl
|
||||
AC_MSG_CHECKING([for realpath])
|
||||
AC_CACHE_VAL(glibcxx_cv_realpath, [dnl
|
||||
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=no])
|
||||
])
|
||||
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
|
||||
AC_MSG_RESULT($glibcxx_cv_realpath)
|
||||
dnl
|
||||
|
@ -883,7 +883,7 @@
|
||||
of TR1 (Chapter 5.1). */
|
||||
#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
|
||||
|
||||
/* Defined if sched_yield is available. */
|
||||
|
30
libstdc++-v3/configure
vendored
30
libstdc++-v3/configure
vendored
@ -79178,11 +79178,22 @@ else
|
||||
if test x$gcc_no_link = xyes; then
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int
|
||||
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;
|
||||
}
|
||||
@ -79199,11 +79210,22 @@ else
|
||||
fi
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int
|
||||
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;
|
||||
}
|
||||
|
@ -96,23 +96,98 @@ namespace
|
||||
fs::path
|
||||
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
|
||||
char* buffer = nullptr;
|
||||
#if defined(__SunOS_5_10) && defined(PATH_MAX)
|
||||
buffer = (char*)::malloc(PATH_MAX);
|
||||
#endif
|
||||
if (char_ptr rp = char_ptr{::realpath(absolute(p, base).c_str(), buffer)})
|
||||
char_ptr buf{ nullptr };
|
||||
# if _XOPEN_VERSION < 700
|
||||
// Not safe to call realpath(path, NULL)
|
||||
buf.reset( (char*)::malloc(PATH_MAX) );
|
||||
# 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();
|
||||
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
|
||||
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
|
||||
|
@ -29,6 +29,8 @@ using std::experimental::filesystem::path;
|
||||
void
|
||||
test01()
|
||||
{
|
||||
bool test __attribute__((unused)) = false;
|
||||
|
||||
for (const path& p : __gnu_test::test_paths)
|
||||
VERIFY( absolute(p).is_absolute() );
|
||||
}
|
||||
@ -36,6 +38,8 @@ test01()
|
||||
void
|
||||
test02()
|
||||
{
|
||||
bool test __attribute__((unused)) = false;
|
||||
|
||||
path p1("/");
|
||||
VERIFY( absolute(p1) == p1 );
|
||||
VERIFY( absolute(p1, "/bar") == p1 );
|
||||
|
@ -0,0 +1,77 @@
|
||||
// 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;
|
||||
void
|
||||
test01()
|
||||
{
|
||||
bool test __attribute__((unused)) = false;
|
||||
|
||||
for (const path& p : __gnu_test::test_paths)
|
||||
VERIFY( absolute(p).is_absolute() );
|
||||
}
|
||||
@ -36,6 +38,8 @@ test01()
|
||||
void
|
||||
test02()
|
||||
{
|
||||
bool test __attribute__((unused)) = false;
|
||||
|
||||
path p1("/");
|
||||
VERIFY( absolute(p1) == p1 );
|
||||
VERIFY( absolute(p1, "/bar") == p1 );
|
||||
|
@ -29,6 +29,8 @@ namespace fs = std::experimental::filesystem;
|
||||
void
|
||||
test01()
|
||||
{
|
||||
bool test __attribute__((unused)) = false;
|
||||
|
||||
fs::path dot(".");
|
||||
fs::path cwd = fs::current_path();
|
||||
std::error_code ec;
|
||||
@ -39,6 +41,8 @@ test01()
|
||||
void
|
||||
test02()
|
||||
{
|
||||
bool test __attribute__((unused)) = false;
|
||||
|
||||
auto oldwd = fs::current_path();
|
||||
auto tmpdir = fs::temp_directory_path();
|
||||
current_path(tmpdir);
|
||||
|
@ -20,32 +20,37 @@
|
||||
|
||||
#include <experimental/filesystem>
|
||||
#include <testsuite_hooks.h>
|
||||
#include <testsuite_fs.h>
|
||||
|
||||
using std::experimental::filesystem::path;
|
||||
|
||||
void
|
||||
test01()
|
||||
{
|
||||
bool test __attribute__((unused)) = false;
|
||||
|
||||
VERIFY( exists(path{"/"}) );
|
||||
VERIFY( exists(path{"/."}) );
|
||||
VERIFY( exists(path{"."}) );
|
||||
VERIFY( exists(path{".."}) );
|
||||
VERIFY( exists(std::experimental::filesystem::current_path()) );
|
||||
}
|
||||
|
||||
void
|
||||
test02()
|
||||
{
|
||||
path rel{"xXxXx"};
|
||||
while (exists(rel))
|
||||
rel /= "x";
|
||||
bool test __attribute__((unused)) = false;
|
||||
|
||||
path rel = __gnu_test::nonexistent_path();
|
||||
VERIFY( !exists(rel) );
|
||||
}
|
||||
|
||||
void
|
||||
test03()
|
||||
{
|
||||
path abs{"/xXxXx"};
|
||||
while (exists(abs))
|
||||
abs /= "x";
|
||||
bool test __attribute__((unused)) = false;
|
||||
|
||||
path abs = absolute(__gnu_test::nonexistent_path());
|
||||
VERIFY( !exists(abs) );
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,8 @@ namespace fs = std::experimental::filesystem;
|
||||
void
|
||||
test01()
|
||||
{
|
||||
bool test __attribute__((unused)) = false;
|
||||
|
||||
std::error_code ec;
|
||||
size_t size = fs::file_size(".", ec);
|
||||
VERIFY( ec == std::errc::is_a_directory );
|
||||
@ -45,6 +47,8 @@ test01()
|
||||
void
|
||||
test02()
|
||||
{
|
||||
bool test __attribute__((unused)) = false;
|
||||
|
||||
fs::path p = __gnu_test::nonexistent_path();
|
||||
|
||||
std::error_code ec;
|
||||
|
@ -27,6 +27,8 @@ namespace fs = std::experimental::filesystem;
|
||||
void
|
||||
test01()
|
||||
{
|
||||
bool test __attribute__((unused)) = false;
|
||||
|
||||
std::error_code ec;
|
||||
fs::file_status st1 = fs::status(".", ec);
|
||||
VERIFY( !ec );
|
||||
@ -39,6 +41,8 @@ test01()
|
||||
void
|
||||
test02()
|
||||
{
|
||||
bool test __attribute__((unused)) = false;
|
||||
|
||||
fs::path p = __gnu_test::nonexistent_path();
|
||||
|
||||
std::error_code ec;
|
||||
|
@ -37,6 +37,8 @@ namespace fs = std::experimental::filesystem;
|
||||
void
|
||||
test01()
|
||||
{
|
||||
bool test __attribute__((unused)) = false;
|
||||
|
||||
clean_env();
|
||||
|
||||
if (!fs::exists("/tmp"))
|
||||
@ -53,6 +55,8 @@ test01()
|
||||
void
|
||||
test02()
|
||||
{
|
||||
bool test __attribute__((unused)) = false;
|
||||
|
||||
clean_env();
|
||||
|
||||
if (::setenv("TMPDIR", __gnu_test::nonexistent_path().string().c_str(), 1))
|
||||
|
Loading…
Reference in New Issue
Block a user