commit 9f9ee62dc3e3d5a1cc825298b93afedc2eaf0aeb Author: Jonathan Wakely Date: Tue Sep 22 23:43:59 2015 +0100 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. diff --git a/libstdc++-v3/src/filesystem/ops.cc b/libstdc++-v3/src/filesystem/ops.cc index b5c8eb9..5ff8120 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 0000000..b84d966 --- /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(); +}