Fix filesystem::create_directories() function

* src/filesystem/ops.cc (is_dot, is_dotdot): Define new helpers.
	(create_directories): Fix error handling.
	* testsuite/experimental/filesystem/operations/create_directories.cc:
	New.

From-SVN: r228041
This commit is contained in:
Jonathan Wakely 2015-09-23 12:25:59 +01:00 committed by Jonathan Wakely
parent be6e26f995
commit 366703118c
3 changed files with 123 additions and 6 deletions

View File

@ -1,3 +1,10 @@
2015-09-23 Jonathan Wakely <jwakely@redhat.com>
* src/filesystem/ops.cc (is_dot, is_dotdot): Define new helpers.
(create_directories): Fix error handling.
* testsuite/experimental/filesystem/operations/create_directories.cc:
New.
2015-09-21 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/67647

View File

@ -85,6 +85,24 @@ fs::absolute(const path& p, const path& base)
namespace
{
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
inline bool is_dot(wchar_t c) { return c == L'.'; }
#else
inline bool is_dot(char c) { return c == '.'; }
#endif
inline bool is_dot(const fs::path& path)
{
const auto& filename = path.native();
return filename.size() == 1 && is_dot(filename[0]);
}
inline bool is_dotdot(const fs::path& path)
{
const auto& filename = path.native();
return filename.size() == 2 && is_dot(filename[0]) && is_dot(filename[1]);
}
struct free_as_in_malloc
{
void operator()(void* p) const { ::free(p); }
@ -576,19 +594,36 @@ fs::create_directories(const path& p)
bool
fs::create_directories(const path& p, error_code& ec) noexcept
{
if (p.empty())
{
ec = std::make_error_code(errc::invalid_argument);
return false;
}
std::stack<path> missing;
path pp = p;
ec.clear();
while (!p.empty() && !exists(pp, ec) && !ec.value())
while (!pp.empty() && status(pp, ec).type() == file_type::not_found)
{
missing.push(pp);
pp = pp.parent_path();
ec.clear();
const auto& filename = pp.filename();
if (!is_dot(filename) && !is_dotdot(filename))
missing.push(pp);
pp.remove_filename();
}
while (!missing.empty() && !ec.value())
if (ec || missing.empty())
return false;
do
{
create_directory(missing.top(), ec);
const path& top = missing.top();
create_directory(top, ec);
if (ec && is_directory(top))
ec.clear();
missing.pop();
}
while (!missing.empty() && !ec);
return missing.empty();
}

View File

@ -0,0 +1,75 @@
// 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;
// Test empty path.
bool b = fs::create_directories( "", ec );
VERIFY( ec );
VERIFY( !b );
// Test existing path.
b = fs::create_directories( fs::current_path(), ec );
VERIFY( !ec );
VERIFY( !b );
// Test non-existent path.
const auto p = __gnu_test::nonexistent_path();
b = fs::create_directories( p, ec );
VERIFY( !ec );
VERIFY( b );
VERIFY( is_directory(p) );
b = fs::create_directories( p/".", ec );
VERIFY( !ec );
VERIFY( !b );
b = fs::create_directories( p/"..", ec );
VERIFY( !ec );
VERIFY( !b );
b = fs::create_directories( p/"d1/d2/d3", ec );
VERIFY( !ec );
VERIFY( b );
VERIFY( is_directory(p/"d1/d2/d3") );
b = fs::create_directories( p/"./d4/../d5", ec );
VERIFY( !ec );
VERIFY( b );
VERIFY( is_directory(p/"./d4/../d5") );
remove_all(p, ec);
}
int
main()
{
test01();
}