From 366703118cd68810da3cc24ad2f9198d2116fa09 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Wed, 23 Sep 2015 12:25:59 +0100 Subject: [PATCH] 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 --- libstdc++-v3/ChangeLog | 7 ++ libstdc++-v3/src/filesystem/ops.cc | 47 ++++++++++-- .../operations/create_directories.cc | 75 +++++++++++++++++++ 3 files changed, 123 insertions(+), 6 deletions(-) create mode 100644 libstdc++-v3/testsuite/experimental/filesystem/operations/create_directories.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 7d0200ac1f4..a8dc5eba381 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,10 @@ +2015-09-23 Jonathan Wakely + + * 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 PR libstdc++/67647 diff --git a/libstdc++-v3/src/filesystem/ops.cc b/libstdc++-v3/src/filesystem/ops.cc index b5c8eb9e111..5ff8120f607 100644 --- a/libstdc++-v3/src/filesystem/ops.cc +++ b/libstdc++-v3/src/filesystem/ops.cc @@ -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 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(); } diff --git a/libstdc++-v3/testsuite/experimental/filesystem/operations/create_directories.cc b/libstdc++-v3/testsuite/experimental/filesystem/operations/create_directories.cc new file mode 100644 index 00000000000..b84d966ad74 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/filesystem/operations/create_directories.cc @@ -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 +// . + +// { dg-options "-std=gnu++11 -lstdc++fs" } +// { dg-require-filesystem-ts "" } + +#include +#include +#include + +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(); +} -- 2.30.2