ops.cc (stat_type): Define alias for struct stat and use throughout the file.
* src/filesystem/ops.cc (stat_type): Define alias for struct stat and use throughout the file. (make_file_type): New function. (file_size(const path&, error_code&)): Report an error for anything that isn't a regular file. (status(const path&), symlink_status(const path&)): Do not throw for file_type::not_found. (temp_directory_path()): Check additional environment variables. * testsuite/experimental/filesystem/operations/exists.cc: New. * testsuite/experimental/filesystem/operations/file_size.cc: New. * testsuite/experimental/filesystem/operations/status.cc: New. * testsuite/experimental/filesystem/operations/temp_directory_path.cc: New. From-SVN: r223224
This commit is contained in:
parent
7a37fa9070
commit
9caf7b2729
7 changed files with 384 additions and 42 deletions
|
@ -1,3 +1,19 @@
|
|||
2015-05-15 Jonathan Wakely <jwakely@redhat.com>
|
||||
|
||||
* src/filesystem/ops.cc (stat_type): Define alias for struct stat and
|
||||
use throughout the file.
|
||||
(make_file_type): New function.
|
||||
(file_size(const path&, error_code&)): Report an error for anything
|
||||
that isn't a regular file.
|
||||
(status(const path&), symlink_status(const path&)): Do not throw for
|
||||
file_type::not_found.
|
||||
(temp_directory_path()): Check additional environment variables.
|
||||
* testsuite/experimental/filesystem/operations/exists.cc: New.
|
||||
* testsuite/experimental/filesystem/operations/file_size.cc: New.
|
||||
* testsuite/experimental/filesystem/operations/status.cc: New.
|
||||
* testsuite/experimental/filesystem/operations/temp_directory_path.cc:
|
||||
New.
|
||||
|
||||
2015-05-14 Nathan Myers <ncm@cantrip.org>
|
||||
Jonathan Wakely <jwakely@redhat.com>
|
||||
|
||||
|
|
|
@ -150,33 +150,39 @@ namespace
|
|||
#ifdef _GLIBCXX_HAVE_SYS_STAT_H
|
||||
namespace
|
||||
{
|
||||
fs::file_status
|
||||
make_file_status(const struct ::stat& st)
|
||||
typedef struct ::stat stat_type;
|
||||
|
||||
inline fs::file_type
|
||||
make_file_type(const stat_type& st)
|
||||
{
|
||||
using fs::file_status;
|
||||
using fs::file_type;
|
||||
using fs::perms;
|
||||
file_type ft;
|
||||
perms perm = static_cast<perms>(st.st_mode) & perms::mask;
|
||||
#ifdef _GLIBCXX_HAVE_S_ISREG
|
||||
if (S_ISREG(st.st_mode))
|
||||
ft = file_type::regular;
|
||||
return file_type::regular;
|
||||
else if (S_ISDIR(st.st_mode))
|
||||
ft = file_type::directory;
|
||||
return file_type::directory;
|
||||
else if (S_ISCHR(st.st_mode))
|
||||
ft = file_type::character;
|
||||
return file_type::character;
|
||||
else if (S_ISBLK(st.st_mode))
|
||||
ft = file_type::block;
|
||||
return file_type::block;
|
||||
else if (S_ISFIFO(st.st_mode))
|
||||
ft = file_type::fifo;
|
||||
return file_type::fifo;
|
||||
else if (S_ISLNK(st.st_mode))
|
||||
ft = file_type::symlink;
|
||||
return file_type::symlink;
|
||||
else if (S_ISSOCK(st.st_mode))
|
||||
ft = file_type::socket;
|
||||
else
|
||||
return file_type::socket;
|
||||
#endif
|
||||
ft = file_type::unknown;
|
||||
return file_status{ft, perm};
|
||||
return file_type::unknown;
|
||||
|
||||
}
|
||||
|
||||
inline fs::file_status
|
||||
make_file_status(const stat_type& st)
|
||||
{
|
||||
return fs::file_status{
|
||||
make_file_type(st),
|
||||
static_cast<fs::perms>(st.st_mode) & fs::perms::mask
|
||||
};
|
||||
}
|
||||
|
||||
inline bool
|
||||
|
@ -186,7 +192,7 @@ namespace
|
|||
}
|
||||
|
||||
inline fs::file_time_type
|
||||
file_time(const struct ::stat& st)
|
||||
file_time(const stat_type& st)
|
||||
{
|
||||
using namespace std::chrono;
|
||||
return fs::file_time_type{
|
||||
|
@ -201,10 +207,10 @@ namespace
|
|||
bool
|
||||
do_copy_file(const fs::path& from, const fs::path& to,
|
||||
fs::copy_options option,
|
||||
struct ::stat* from_st, struct ::stat* to_st,
|
||||
stat_type* from_st, stat_type* to_st,
|
||||
std::error_code& ec) noexcept
|
||||
{
|
||||
struct ::stat st1, st2;
|
||||
stat_type st1, st2;
|
||||
fs::file_status t, f;
|
||||
|
||||
if (to_st == nullptr)
|
||||
|
@ -342,7 +348,7 @@ fs::copy(const path& from, const path& to, copy_options options,
|
|||
bool use_lstat = create_symlinks || skip_symlinks;
|
||||
|
||||
file_status f, t;
|
||||
struct ::stat from_st, to_st;
|
||||
stat_type from_st, to_st;
|
||||
if (use_lstat
|
||||
? ::lstat(from.c_str(), &from_st)
|
||||
: ::stat(from.c_str(), &from_st))
|
||||
|
@ -564,7 +570,7 @@ fs::create_directory(const path& p, const path& attributes,
|
|||
error_code& ec) noexcept
|
||||
{
|
||||
#ifdef _GLIBCXX_HAVE_SYS_STAT_H
|
||||
struct ::stat st;
|
||||
stat_type st;
|
||||
if (::stat(attributes.c_str(), &st))
|
||||
{
|
||||
ec.assign(errno, std::generic_category());
|
||||
|
@ -747,7 +753,7 @@ bool
|
|||
fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept
|
||||
{
|
||||
#ifdef _GLIBCXX_HAVE_SYS_STAT_H
|
||||
struct ::stat st1, st2;
|
||||
stat_type st1, st2;
|
||||
if (::stat(p1.c_str(), &st1) == 0 && ::stat(p2.c_str(), &st2) == 0)
|
||||
{
|
||||
file_status s1 = make_file_status(st1);
|
||||
|
@ -789,7 +795,7 @@ namespace
|
|||
do_stat(const fs::path& p, std::error_code& ec, Accessor f, T deflt)
|
||||
{
|
||||
#ifdef _GLIBCXX_HAVE_SYS_STAT_H
|
||||
struct ::stat st;
|
||||
stat_type st;
|
||||
if (::stat(p.c_str(), &st))
|
||||
{
|
||||
ec.assign(errno, std::generic_category());
|
||||
|
@ -807,8 +813,24 @@ namespace
|
|||
std::uintmax_t
|
||||
fs::file_size(const path& p, error_code& ec) noexcept
|
||||
{
|
||||
return do_stat(p, ec, std::mem_fn(&stat::st_size),
|
||||
static_cast<uintmax_t>(-1));
|
||||
struct S
|
||||
{
|
||||
S(const stat_type& st) : type(make_file_type(st)), size(st.st_size) { }
|
||||
S() : type(file_type::not_found) { }
|
||||
file_type type;
|
||||
size_t size;
|
||||
};
|
||||
auto s = do_stat(p, ec, [](const auto& st) { return S{st}; }, S{});
|
||||
if (s.type == file_type::regular)
|
||||
return s.size;
|
||||
if (!ec)
|
||||
{
|
||||
if (s.type == file_type::directory)
|
||||
ec = std::make_error_code(std::errc::is_a_directory);
|
||||
else
|
||||
ec = std::make_error_code(std::errc::not_supported);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::uintmax_t
|
||||
|
@ -938,7 +960,7 @@ fs::read_symlink(const path& p)
|
|||
fs::path fs::read_symlink(const path& p, error_code& ec)
|
||||
{
|
||||
#ifdef _GLIBCXX_HAVE_SYS_STAT_H
|
||||
struct ::stat st;
|
||||
stat_type st;
|
||||
if (::lstat(p.c_str(), &st))
|
||||
{
|
||||
ec.assign(errno, std::generic_category());
|
||||
|
@ -1094,13 +1116,13 @@ fs::file_status
|
|||
fs::status(const fs::path& p, std::error_code& ec) noexcept
|
||||
{
|
||||
file_status status;
|
||||
struct ::stat st;
|
||||
stat_type st;
|
||||
if (::stat(p.c_str(), &st))
|
||||
{
|
||||
int err = errno;
|
||||
ec.assign(err, std::generic_category());
|
||||
if (is_not_found_errno(err))
|
||||
status = file_status{file_type::not_found};
|
||||
status.type(file_type::not_found);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1114,13 +1136,13 @@ fs::file_status
|
|||
fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept
|
||||
{
|
||||
file_status status;
|
||||
struct ::stat st;
|
||||
stat_type st;
|
||||
if (::lstat(p.c_str(), &st))
|
||||
{
|
||||
int err = errno;
|
||||
ec.assign(err, std::generic_category());
|
||||
if (is_not_found_errno(err))
|
||||
status = file_status{file_type::not_found};
|
||||
status.type(file_type::not_found);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1135,20 +1157,20 @@ fs::file_status
|
|||
fs::status(const fs::path& p)
|
||||
{
|
||||
std::error_code ec;
|
||||
auto s = status(p, ec);
|
||||
if (ec.value())
|
||||
auto result = status(p, ec);
|
||||
if (result.type() == file_type::none)
|
||||
_GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p, ec));
|
||||
return s;
|
||||
return result;
|
||||
}
|
||||
|
||||
fs::file_status
|
||||
fs::symlink_status(const fs::path& p)
|
||||
{
|
||||
std::error_code ec;
|
||||
auto s = symlink_status(p, ec);
|
||||
if (ec.value())
|
||||
_GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", ec));
|
||||
return s;
|
||||
auto result = symlink_status(p, ec);
|
||||
if (result.type() == file_type::none)
|
||||
_GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", p, ec));
|
||||
return result;
|
||||
}
|
||||
|
||||
fs::path
|
||||
|
@ -1194,11 +1216,18 @@ fs::path fs::temp_directory_path(error_code& ec)
|
|||
ec = std::make_error_code(std::errc::not_supported);
|
||||
return {}; // TODO
|
||||
#else
|
||||
const char* tmpdir = ::getenv("TMPDIR");
|
||||
if (!tmpdir)
|
||||
tmpdir = "/tmp";
|
||||
ec.clear();
|
||||
return tmpdir;
|
||||
const char* tmpdir = nullptr;
|
||||
const char* env[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr };
|
||||
for (auto e = env; tmpdir == nullptr && *e != nullptr; ++e)
|
||||
tmpdir = ::getenv(*e);
|
||||
path p = tmpdir ? tmpdir : "/tmp";
|
||||
if (exists(p) && is_directory(p))
|
||||
{
|
||||
ec.clear();
|
||||
return p;
|
||||
}
|
||||
ec = std::make_error_code(std::errc::not_a_directory);
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
// 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>
|
||||
|
||||
using std::experimental::filesystem::path;
|
||||
|
||||
void
|
||||
test01()
|
||||
{
|
||||
VERIFY( exists(path{"/"}) );
|
||||
VERIFY( exists(path{"/."}) );
|
||||
VERIFY( exists(path{"."}) );
|
||||
}
|
||||
|
||||
void
|
||||
test02()
|
||||
{
|
||||
path rel{"xXxXx"};
|
||||
while (exists(rel))
|
||||
rel /= "x";
|
||||
VERIFY( !exists(rel) );
|
||||
}
|
||||
|
||||
void
|
||||
test03()
|
||||
{
|
||||
path abs{"/xXxXx"};
|
||||
while (exists(abs))
|
||||
abs /= "x";
|
||||
VERIFY( !exists(abs) );
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
test01();
|
||||
test02();
|
||||
test03();
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
// 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()
|
||||
{
|
||||
std::error_code ec;
|
||||
size_t size = fs::file_size(".", ec);
|
||||
VERIFY( ec == std::errc::is_a_directory );
|
||||
VERIFY( size == -1 );
|
||||
|
||||
try {
|
||||
size = fs::file_size(".");
|
||||
ec.clear();
|
||||
} catch (const fs::filesystem_error& e) {
|
||||
ec = e.code();
|
||||
}
|
||||
VERIFY( ec == std::errc::is_a_directory );
|
||||
VERIFY( size == -1 );
|
||||
}
|
||||
|
||||
void
|
||||
test02()
|
||||
{
|
||||
fs::path p = __gnu_test::nonexistent_path();
|
||||
|
||||
std::error_code ec;
|
||||
size_t size = fs::file_size(p, ec);
|
||||
VERIFY( ec );
|
||||
VERIFY( size == -1 );
|
||||
|
||||
try {
|
||||
size = fs::file_size(p);
|
||||
ec.clear();
|
||||
} catch (const fs::filesystem_error& e) {
|
||||
ec = e.code();
|
||||
}
|
||||
VERIFY( ec );
|
||||
VERIFY( size == -1 );
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
test01();
|
||||
test02();
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
// 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()
|
||||
{
|
||||
std::error_code ec;
|
||||
fs::file_status st1 = fs::status(".", ec);
|
||||
VERIFY( !ec );
|
||||
VERIFY( st1.type() == fs::file_type::directory );
|
||||
|
||||
fs::file_status st2 = fs::status(".");
|
||||
VERIFY( st2.type() == fs::file_type::directory );
|
||||
}
|
||||
|
||||
void
|
||||
test02()
|
||||
{
|
||||
fs::path p = __gnu_test::nonexistent_path();
|
||||
|
||||
std::error_code ec;
|
||||
fs::file_status st1 = fs::status(p, ec);
|
||||
VERIFY( ec );
|
||||
VERIFY( st1.type() == fs::file_type::not_found );
|
||||
|
||||
fs::file_status st2 = fs::status(p);
|
||||
VERIFY( st2.type() == fs::file_type::not_found );
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
test01();
|
||||
test02();
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
// 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 <stdlib.h>
|
||||
#include <testsuite_hooks.h>
|
||||
#include <testsuite_fs.h>
|
||||
|
||||
void
|
||||
clean_env()
|
||||
{
|
||||
::unsetenv("TMPDIR");
|
||||
::unsetenv("TMP");
|
||||
::unsetenv("TEMPDIR");
|
||||
::unsetenv("TEMP");
|
||||
}
|
||||
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
void
|
||||
test01()
|
||||
{
|
||||
clean_env();
|
||||
|
||||
if (!fs::exists("/tmp"))
|
||||
return; // just give up
|
||||
|
||||
std::error_code ec;
|
||||
fs::path p1 = fs::temp_directory_path(ec);
|
||||
VERIFY( exists(p1) );
|
||||
|
||||
fs::path p2 = fs::temp_directory_path();
|
||||
VERIFY( p1 == p2 );
|
||||
}
|
||||
|
||||
void
|
||||
test02()
|
||||
{
|
||||
clean_env();
|
||||
|
||||
if (::setenv("TMPDIR", __gnu_test::nonexistent_path().string().c_str(), 1))
|
||||
return; // just give up
|
||||
|
||||
std::error_code ec;
|
||||
fs::path p = fs::temp_directory_path(ec);
|
||||
VERIFY( ec );
|
||||
|
||||
std::error_code ec2;
|
||||
try {
|
||||
p = fs::temp_directory_path();
|
||||
} catch (const fs::filesystem_error& e) {
|
||||
ec2 = e.code();
|
||||
}
|
||||
VERIFY( ec2 == ec );
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
test01();
|
||||
test02();
|
||||
}
|
|
@ -25,6 +25,11 @@
|
|||
#include <experimental/filesystem>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#if defined(_GNU_SOURCE) || _XOPEN_SOURCE >= 500 || _POSIX_C_SOURCE >= 200112L
|
||||
# include <stdlib.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace __gnu_test
|
||||
{
|
||||
|
@ -63,5 +68,31 @@ namespace __gnu_test
|
|||
"a", "a/b", "a/b/", "a/b/c", "a/b/c.d", "a/b/..", "a/b/c.", "a/b/.c"
|
||||
};
|
||||
|
||||
// This is NOT supposed to be a secure way to get a unique name!
|
||||
// We just need a path that doesn't exist for testing purposes.
|
||||
std::experimental::filesystem::path
|
||||
nonexistent_path()
|
||||
{
|
||||
std::experimental::filesystem::path p;
|
||||
#if defined(_GNU_SOURCE) || _XOPEN_SOURCE >= 500 || _POSIX_C_SOURCE >= 200112L
|
||||
char tmp[] = "test.XXXXXX";
|
||||
int fd = ::mkstemp(tmp);
|
||||
if (fd == -1)
|
||||
throw std::experimental::filesystem::filesystem_error("mkstemp failed",
|
||||
std::error_code(errno, std::generic_category()));
|
||||
::unlink(tmp);
|
||||
::close(fd);
|
||||
p = tmp;
|
||||
#else
|
||||
char* tmp = tempnam(".", "test.");
|
||||
if (!tmp)
|
||||
throw std::experimental::filesystem::filesystem_error("tempnam failed",
|
||||
std::error_code(errno, std::generic_category()));
|
||||
p = tmp;
|
||||
::free(tmp);
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
|
||||
} // namespace __gnu_test
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue