2017-10-23 14:11:22 +02:00
|
|
|
// Filesystem directory utilities -*- C++ -*-
|
|
|
|
|
2021-01-04 10:26:59 +01:00
|
|
|
// Copyright (C) 2014-2021 Free Software Foundation, Inc.
|
2017-10-23 14:11:22 +02:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
|
|
|
|
// Under Section 7 of GPL version 3, you are granted additional
|
|
|
|
// permissions described in the GCC Runtime Library Exception, version
|
|
|
|
// 3.1, as published by the Free Software Foundation.
|
|
|
|
|
|
|
|
// You should have received a copy of the GNU General Public License and
|
|
|
|
// a copy of the GCC Runtime Library Exception along with this program;
|
|
|
|
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|
|
|
// <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
/** @file include/bits/fs_dir.h
|
|
|
|
* This is an internal header file, included by other library headers.
|
|
|
|
* Do not attempt to use it directly. @headername{filesystem}
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _GLIBCXX_FS_DIR_H
|
|
|
|
#define _GLIBCXX_FS_DIR_H 1
|
|
|
|
|
|
|
|
#if __cplusplus >= 201703L
|
|
|
|
# include <typeinfo>
|
|
|
|
# include <ext/concurrence.h>
|
|
|
|
# include <bits/unique_ptr.h>
|
|
|
|
# include <bits/shared_ptr.h>
|
|
|
|
|
2020-04-15 22:01:42 +02:00
|
|
|
#if __cplusplus > 201703L
|
|
|
|
# include <compare> // std::strong_ordering
|
|
|
|
#endif
|
|
|
|
|
2017-10-23 14:11:22 +02:00
|
|
|
namespace std _GLIBCXX_VISIBILITY(default)
|
|
|
|
{
|
|
|
|
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|
|
|
|
|
|
|
namespace filesystem
|
|
|
|
{
|
2019-05-02 17:46:38 +02:00
|
|
|
/** @addtogroup filesystem
|
|
|
|
* @{
|
2017-10-23 14:11:22 +02:00
|
|
|
*/
|
|
|
|
|
2019-05-02 17:46:38 +02:00
|
|
|
/// Information about a file's type and permissions.
|
2017-10-23 14:11:22 +02:00
|
|
|
class file_status
|
|
|
|
{
|
|
|
|
public:
|
2017-10-27 19:49:21 +02:00
|
|
|
// constructors and destructor
|
|
|
|
file_status() noexcept : file_status(file_type::none) {}
|
|
|
|
|
2017-10-23 14:11:22 +02:00
|
|
|
explicit
|
2017-10-27 19:49:21 +02:00
|
|
|
file_status(file_type __ft, perms __prms = perms::unknown) noexcept
|
2017-10-23 14:11:22 +02:00
|
|
|
: _M_type(__ft), _M_perms(__prms) { }
|
|
|
|
|
|
|
|
file_status(const file_status&) noexcept = default;
|
|
|
|
file_status(file_status&&) noexcept = default;
|
|
|
|
~file_status() = default;
|
|
|
|
|
|
|
|
file_status& operator=(const file_status&) noexcept = default;
|
|
|
|
file_status& operator=(file_status&&) noexcept = default;
|
|
|
|
|
|
|
|
// observers
|
|
|
|
file_type type() const noexcept { return _M_type; }
|
|
|
|
perms permissions() const noexcept { return _M_perms; }
|
|
|
|
|
|
|
|
// modifiers
|
|
|
|
void type(file_type __ft) noexcept { _M_type = __ft; }
|
|
|
|
void permissions(perms __prms) noexcept { _M_perms = __prms; }
|
|
|
|
|
2020-04-15 22:01:42 +02:00
|
|
|
#if __cpp_lib_three_way_comparison
|
|
|
|
friend bool
|
|
|
|
operator==(const file_status&, const file_status&) noexcept = default;
|
|
|
|
#endif
|
|
|
|
|
2017-10-23 14:11:22 +02:00
|
|
|
private:
|
|
|
|
file_type _M_type;
|
|
|
|
perms _M_perms;
|
|
|
|
};
|
|
|
|
|
|
|
|
_GLIBCXX_BEGIN_NAMESPACE_CXX11
|
|
|
|
|
|
|
|
struct _Dir;
|
|
|
|
class directory_iterator;
|
|
|
|
class recursive_directory_iterator;
|
|
|
|
|
2019-05-02 17:46:38 +02:00
|
|
|
/// The value type used by directory iterators
|
2017-10-23 14:11:22 +02:00
|
|
|
class directory_entry
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
// constructors and destructor
|
|
|
|
directory_entry() noexcept = default;
|
|
|
|
directory_entry(const directory_entry&) = default;
|
|
|
|
directory_entry(directory_entry&&) noexcept = default;
|
|
|
|
|
|
|
|
explicit
|
|
|
|
directory_entry(const filesystem::path& __p)
|
|
|
|
: _M_path(__p)
|
|
|
|
{ refresh(); }
|
|
|
|
|
|
|
|
directory_entry(const filesystem::path& __p, error_code& __ec)
|
|
|
|
: _M_path(__p)
|
|
|
|
{
|
|
|
|
refresh(__ec);
|
|
|
|
if (__ec)
|
|
|
|
_M_path.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
~directory_entry() = default;
|
|
|
|
|
|
|
|
// modifiers
|
|
|
|
directory_entry& operator=(const directory_entry&) = default;
|
|
|
|
directory_entry& operator=(directory_entry&&) noexcept = default;
|
|
|
|
|
|
|
|
void
|
|
|
|
assign(const filesystem::path& __p)
|
|
|
|
{
|
|
|
|
_M_path = __p;
|
|
|
|
refresh();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
assign(const filesystem::path& __p, error_code& __ec)
|
|
|
|
{
|
|
|
|
_M_path = __p;
|
|
|
|
refresh(__ec);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
replace_filename(const filesystem::path& __p)
|
|
|
|
{
|
|
|
|
_M_path.replace_filename(__p);
|
|
|
|
refresh();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
replace_filename(const filesystem::path& __p, error_code& __ec)
|
|
|
|
{
|
|
|
|
_M_path.replace_filename(__p);
|
|
|
|
refresh(__ec);
|
|
|
|
}
|
|
|
|
|
2018-07-20 13:52:54 +02:00
|
|
|
void
|
|
|
|
refresh()
|
|
|
|
{ _M_type = symlink_status().type(); }
|
|
|
|
|
|
|
|
void
|
|
|
|
refresh(error_code& __ec) noexcept
|
|
|
|
{ _M_type = symlink_status(__ec).type(); }
|
2017-10-23 14:11:22 +02:00
|
|
|
|
|
|
|
// observers
|
|
|
|
const filesystem::path& path() const noexcept { return _M_path; }
|
|
|
|
operator const filesystem::path& () const noexcept { return _M_path; }
|
|
|
|
|
|
|
|
bool
|
|
|
|
exists() const
|
|
|
|
{ return filesystem::exists(file_status{_M_file_type()}); }
|
|
|
|
|
|
|
|
bool
|
|
|
|
exists(error_code& __ec) const noexcept
|
|
|
|
{ return filesystem::exists(file_status{_M_file_type(__ec)}); }
|
|
|
|
|
|
|
|
bool
|
|
|
|
is_block_file() const
|
|
|
|
{ return _M_file_type() == file_type::block; }
|
|
|
|
|
|
|
|
bool
|
|
|
|
is_block_file(error_code& __ec) const noexcept
|
|
|
|
{ return _M_file_type(__ec) == file_type::block; }
|
|
|
|
|
|
|
|
bool
|
|
|
|
is_character_file() const
|
|
|
|
{ return _M_file_type() == file_type::character; }
|
|
|
|
|
|
|
|
bool
|
|
|
|
is_character_file(error_code& __ec) const noexcept
|
|
|
|
{ return _M_file_type(__ec) == file_type::character; }
|
|
|
|
|
|
|
|
bool
|
|
|
|
is_directory() const
|
|
|
|
{ return _M_file_type() == file_type::directory; }
|
|
|
|
|
|
|
|
bool
|
|
|
|
is_directory(error_code& __ec) const noexcept
|
|
|
|
{ return _M_file_type(__ec) == file_type::directory; }
|
|
|
|
|
|
|
|
bool
|
|
|
|
is_fifo() const
|
|
|
|
{ return _M_file_type() == file_type::fifo; }
|
|
|
|
|
|
|
|
bool
|
|
|
|
is_fifo(error_code& __ec) const noexcept
|
|
|
|
{ return _M_file_type(__ec) == file_type::fifo; }
|
|
|
|
|
|
|
|
bool
|
|
|
|
is_other() const
|
|
|
|
{ return filesystem::is_other(file_status{_M_file_type()}); }
|
|
|
|
|
|
|
|
bool
|
|
|
|
is_other(error_code& __ec) const noexcept
|
|
|
|
{ return filesystem::is_other(file_status{_M_file_type(__ec)}); }
|
|
|
|
|
|
|
|
bool
|
|
|
|
is_regular_file() const
|
|
|
|
{ return _M_file_type() == file_type::regular; }
|
|
|
|
|
|
|
|
bool
|
|
|
|
is_regular_file(error_code& __ec) const noexcept
|
|
|
|
{ return _M_file_type(__ec) == file_type::regular; }
|
|
|
|
|
|
|
|
bool
|
|
|
|
is_socket() const
|
|
|
|
{ return _M_file_type() == file_type::socket; }
|
|
|
|
|
|
|
|
bool
|
|
|
|
is_socket(error_code& __ec) const noexcept
|
|
|
|
{ return _M_file_type(__ec) == file_type::socket; }
|
|
|
|
|
|
|
|
bool
|
|
|
|
is_symlink() const
|
|
|
|
{
|
|
|
|
if (_M_type != file_type::none)
|
|
|
|
return _M_type == file_type::symlink;
|
|
|
|
return symlink_status().type() == file_type::symlink;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
is_symlink(error_code& __ec) const noexcept
|
|
|
|
{
|
|
|
|
if (_M_type != file_type::none)
|
|
|
|
return _M_type == file_type::symlink;
|
|
|
|
return symlink_status(__ec).type() == file_type::symlink;
|
|
|
|
}
|
|
|
|
|
|
|
|
uintmax_t
|
|
|
|
file_size() const
|
|
|
|
{ return filesystem::file_size(_M_path); }
|
|
|
|
|
|
|
|
uintmax_t
|
|
|
|
file_size(error_code& __ec) const noexcept
|
|
|
|
{ return filesystem::file_size(_M_path, __ec); }
|
|
|
|
|
|
|
|
uintmax_t
|
|
|
|
hard_link_count() const
|
|
|
|
{ return filesystem::hard_link_count(_M_path); }
|
|
|
|
|
|
|
|
uintmax_t
|
|
|
|
hard_link_count(error_code& __ec) const noexcept
|
|
|
|
{ return filesystem::hard_link_count(_M_path, __ec); }
|
|
|
|
|
|
|
|
file_time_type
|
|
|
|
last_write_time() const
|
|
|
|
{ return filesystem::last_write_time(_M_path); }
|
|
|
|
|
|
|
|
|
|
|
|
file_time_type
|
|
|
|
last_write_time(error_code& __ec) const noexcept
|
|
|
|
{ return filesystem::last_write_time(_M_path, __ec); }
|
|
|
|
|
|
|
|
file_status
|
|
|
|
status() const
|
|
|
|
{ return filesystem::status(_M_path); }
|
|
|
|
|
|
|
|
file_status
|
|
|
|
status(error_code& __ec) const noexcept
|
|
|
|
{ return filesystem::status(_M_path, __ec); }
|
|
|
|
|
|
|
|
file_status
|
|
|
|
symlink_status() const
|
|
|
|
{ return filesystem::symlink_status(_M_path); }
|
|
|
|
|
|
|
|
file_status
|
|
|
|
symlink_status(error_code& __ec) const noexcept
|
|
|
|
{ return filesystem::symlink_status(_M_path, __ec); }
|
|
|
|
|
|
|
|
bool
|
|
|
|
operator==(const directory_entry& __rhs) const noexcept
|
|
|
|
{ return _M_path == __rhs._M_path; }
|
|
|
|
|
2020-04-15 22:01:42 +02:00
|
|
|
#if __cpp_lib_three_way_comparison
|
|
|
|
strong_ordering
|
|
|
|
operator<=>(const directory_entry& __rhs) const noexcept
|
|
|
|
{ return _M_path <=> __rhs._M_path; }
|
|
|
|
#else
|
2017-10-23 14:11:22 +02:00
|
|
|
bool
|
|
|
|
operator!=(const directory_entry& __rhs) const noexcept
|
|
|
|
{ return _M_path != __rhs._M_path; }
|
|
|
|
|
2020-04-15 22:01:42 +02:00
|
|
|
bool
|
|
|
|
operator< (const directory_entry& __rhs) const noexcept
|
|
|
|
{ return _M_path < __rhs._M_path; }
|
|
|
|
|
2017-10-23 14:11:22 +02:00
|
|
|
bool
|
|
|
|
operator<=(const directory_entry& __rhs) const noexcept
|
|
|
|
{ return _M_path <= __rhs._M_path; }
|
|
|
|
|
|
|
|
bool
|
|
|
|
operator> (const directory_entry& __rhs) const noexcept
|
|
|
|
{ return _M_path > __rhs._M_path; }
|
|
|
|
|
|
|
|
bool
|
|
|
|
operator>=(const directory_entry& __rhs) const noexcept
|
|
|
|
{ return _M_path >= __rhs._M_path; }
|
2020-04-15 22:01:42 +02:00
|
|
|
#endif
|
2017-10-23 14:11:22 +02:00
|
|
|
|
|
|
|
private:
|
2020-07-06 17:19:23 +02:00
|
|
|
friend struct _Dir;
|
2017-10-23 14:11:22 +02:00
|
|
|
friend class directory_iterator;
|
|
|
|
friend class recursive_directory_iterator;
|
|
|
|
|
2018-12-18 17:57:36 +01:00
|
|
|
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
|
|
|
// 3171. LWG 2989 breaks directory_entry stream insertion
|
|
|
|
template<typename _CharT, typename _Traits>
|
|
|
|
friend basic_ostream<_CharT, _Traits>&
|
|
|
|
operator<<(basic_ostream<_CharT, _Traits>& __os,
|
|
|
|
const directory_entry& __d)
|
|
|
|
{ return __os << __d.path(); }
|
|
|
|
|
2017-10-23 14:11:22 +02:00
|
|
|
directory_entry(const filesystem::path& __p, file_type __t)
|
|
|
|
: _M_path(__p), _M_type(__t)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
// Equivalent to status().type() but uses cached value, if any.
|
|
|
|
file_type
|
|
|
|
_M_file_type() const
|
|
|
|
{
|
|
|
|
if (_M_type != file_type::none && _M_type != file_type::symlink)
|
|
|
|
return _M_type;
|
|
|
|
return status().type();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Equivalent to status(__ec).type() but uses cached value, if any.
|
|
|
|
file_type
|
|
|
|
_M_file_type(error_code& __ec) const noexcept
|
|
|
|
{
|
|
|
|
if (_M_type != file_type::none && _M_type != file_type::symlink)
|
2018-08-08 15:09:19 +02:00
|
|
|
{
|
|
|
|
__ec.clear();
|
|
|
|
return _M_type;
|
|
|
|
}
|
2017-10-23 14:11:22 +02:00
|
|
|
return status(__ec).type();
|
|
|
|
}
|
|
|
|
|
|
|
|
filesystem::path _M_path;
|
|
|
|
file_type _M_type = file_type::none;
|
|
|
|
};
|
|
|
|
|
2019-05-02 17:46:38 +02:00
|
|
|
/// Proxy returned by post-increment on directory iterators.
|
2017-10-23 14:11:22 +02:00
|
|
|
struct __directory_iterator_proxy
|
|
|
|
{
|
|
|
|
const directory_entry& operator*() const& noexcept { return _M_entry; }
|
|
|
|
|
|
|
|
directory_entry operator*() && noexcept { return std::move(_M_entry); }
|
|
|
|
|
|
|
|
private:
|
|
|
|
friend class directory_iterator;
|
|
|
|
friend class recursive_directory_iterator;
|
|
|
|
|
|
|
|
explicit
|
|
|
|
__directory_iterator_proxy(const directory_entry& __e) : _M_entry(__e) { }
|
|
|
|
|
|
|
|
directory_entry _M_entry;
|
|
|
|
};
|
|
|
|
|
2019-05-02 17:46:38 +02:00
|
|
|
/// Iterator type for traversing the entries in a single directory.
|
2017-10-23 14:11:22 +02:00
|
|
|
class directory_iterator
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
typedef directory_entry value_type;
|
|
|
|
typedef ptrdiff_t difference_type;
|
|
|
|
typedef const directory_entry* pointer;
|
|
|
|
typedef const directory_entry& reference;
|
|
|
|
typedef input_iterator_tag iterator_category;
|
|
|
|
|
|
|
|
directory_iterator() = default;
|
|
|
|
|
|
|
|
explicit
|
|
|
|
directory_iterator(const path& __p)
|
|
|
|
: directory_iterator(__p, directory_options::none, nullptr) { }
|
|
|
|
|
|
|
|
directory_iterator(const path& __p, directory_options __options)
|
|
|
|
: directory_iterator(__p, __options, nullptr) { }
|
|
|
|
|
2017-10-27 19:49:29 +02:00
|
|
|
directory_iterator(const path& __p, error_code& __ec)
|
2017-10-23 14:11:22 +02:00
|
|
|
: directory_iterator(__p, directory_options::none, __ec) { }
|
|
|
|
|
2017-10-27 19:49:29 +02:00
|
|
|
directory_iterator(const path& __p, directory_options __options,
|
|
|
|
error_code& __ec)
|
2017-10-23 14:11:22 +02:00
|
|
|
: directory_iterator(__p, __options, &__ec) { }
|
|
|
|
|
|
|
|
directory_iterator(const directory_iterator& __rhs) = default;
|
|
|
|
|
|
|
|
directory_iterator(directory_iterator&& __rhs) noexcept = default;
|
|
|
|
|
|
|
|
~directory_iterator() = default;
|
|
|
|
|
|
|
|
directory_iterator&
|
|
|
|
operator=(const directory_iterator& __rhs) = default;
|
|
|
|
|
|
|
|
directory_iterator&
|
|
|
|
operator=(directory_iterator&& __rhs) noexcept = default;
|
|
|
|
|
2019-04-05 18:56:31 +02:00
|
|
|
const directory_entry& operator*() const noexcept;
|
|
|
|
const directory_entry* operator->() const noexcept { return &**this; }
|
2017-10-23 14:11:22 +02:00
|
|
|
directory_iterator& operator++();
|
2017-10-27 19:49:29 +02:00
|
|
|
directory_iterator& increment(error_code& __ec);
|
2017-10-23 14:11:22 +02:00
|
|
|
|
|
|
|
__directory_iterator_proxy operator++(int)
|
|
|
|
{
|
|
|
|
__directory_iterator_proxy __pr{**this};
|
|
|
|
++*this;
|
|
|
|
return __pr;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
directory_iterator(const path&, directory_options, error_code*);
|
|
|
|
|
|
|
|
friend bool
|
|
|
|
operator==(const directory_iterator& __lhs,
|
2019-04-05 18:56:31 +02:00
|
|
|
const directory_iterator& __rhs) noexcept
|
|
|
|
{
|
|
|
|
return !__rhs._M_dir.owner_before(__lhs._M_dir)
|
|
|
|
&& !__lhs._M_dir.owner_before(__rhs._M_dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
friend bool
|
|
|
|
operator!=(const directory_iterator& __lhs,
|
|
|
|
const directory_iterator& __rhs) noexcept
|
|
|
|
{ return !(__lhs == __rhs); }
|
2017-10-23 14:11:22 +02:00
|
|
|
|
|
|
|
friend class recursive_directory_iterator;
|
|
|
|
|
PR libstdc++/67843 set shared_ptr lock policy at build-time
This resolves a longstanding issue where the lock policy for shared_ptr
reference counting depends on compilation options when the header is
included, so that different -march options can cause ABI changes. For
example, objects compiled with -march=armv7 will use atomics to
synchronize reference counts, and objects compiled with -march=armv5t
will use a mutex. That means the shared_ptr control block will have a
different layout in different objects, causing ODR violations and
undefined behaviour. This was the root cause of PR libstdc++/42734 as
well as PR libstdc++/67843.
The solution is to decide on the lock policy at build time, when
libstdc++ is configured. The configure script checks for the
availability of the necessary atomic built-ins for the target and fixes
that choice permanently. Different -march flags used to compile user
code will not cause changes to the lock policy. This results in an ABI
change for certain compilations, but only where there was already an ABI
incompatibility between the libstdc++.so library and objects built with
an incompatible -march option. In general, this means a more stable ABI
that isn't silently altered when -march flags make addition atomic ops
available.
To force a target to use "atomic" or "mutex" the new configure option
--with-libstdcxx-lock-policy can be used.
In order to turn ODR violations into linker errors, the uses of
shared_ptr in filesystem directory iterators have been replaced
with __shared_ptr, and explicit instantiations are declared. This
ensures that object files using those types cannot link to libstdc++
libs unless they use the same lock policy.
PR libstdc++/67843
* acinclude.m4 (GLIBCXX_ENABLE_LOCK_POLICY): Add new macro
that defines _GLIBCXX_HAVE_ATOMIC_LOCK_POLICY.
* config.h.in: Regenerate.
* configure: Regenerate.
* configure.ac: Use GLIBCXX_ENABLE_LOCK_POLICY.
* doc/xml/manual/configure.xml: Document new configure option.
* include/bits/fs_dir.h (directory_iterator): Use __shared_ptr
instead of shared_ptr.
(recursive_directory_iterator): Likewise.
(__shared_ptr<_Dir>): Add explicit instantiation declaration.
(__shared_ptr<recursive_directory_iterator::_Dir_stack>): Likewise.
* include/bits/shared_ptr_base.h (__allocate_shared, __make_shared):
Add default template argument for _Lock_policy template parameter.
* include/ext/concurrence.h (__default_lock_policy): Check macro
_GLIBCXX_HAVE_ATOMIC_LOCK_POLICY instead of checking if the current
target supports the builtins for compare-and-swap.
* src/filesystem/std-dir.cc (__shared_ptr<_Dir>): Add explicit
instantiation definition.
(__shared_ptr<recursive_directory_iterator::_Dir_stack>): Likewise.
(directory_iterator, recursive_directory_iterator): Use __make_shared
instead of make_shared.
From-SVN: r266533
2018-11-28 00:25:56 +01:00
|
|
|
std::__shared_ptr<_Dir> _M_dir;
|
2017-10-23 14:11:22 +02:00
|
|
|
};
|
|
|
|
|
2019-05-02 17:46:38 +02:00
|
|
|
/// @relates std::filesystem::directory_iterator @{
|
|
|
|
|
|
|
|
/** @brief Enable range-based `for` using directory_iterator.
|
|
|
|
*
|
|
|
|
* e.g. `for (auto& entry : std::filesystem::directory_iterator(".")) ...`
|
|
|
|
*/
|
2017-10-23 14:11:22 +02:00
|
|
|
inline directory_iterator
|
|
|
|
begin(directory_iterator __iter) noexcept
|
|
|
|
{ return __iter; }
|
|
|
|
|
2019-05-02 17:46:38 +02:00
|
|
|
/// Return a past-the-end directory_iterator
|
2017-10-23 14:11:22 +02:00
|
|
|
inline directory_iterator
|
|
|
|
end(directory_iterator) noexcept
|
|
|
|
{ return directory_iterator(); }
|
2019-05-02 17:46:38 +02:00
|
|
|
// @}
|
2017-10-23 14:11:22 +02:00
|
|
|
|
2019-05-02 17:46:38 +02:00
|
|
|
/// Iterator type for recursively traversing a directory hierarchy.
|
2017-10-23 14:11:22 +02:00
|
|
|
class recursive_directory_iterator
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
typedef directory_entry value_type;
|
|
|
|
typedef ptrdiff_t difference_type;
|
|
|
|
typedef const directory_entry* pointer;
|
|
|
|
typedef const directory_entry& reference;
|
|
|
|
typedef input_iterator_tag iterator_category;
|
|
|
|
|
|
|
|
recursive_directory_iterator() = default;
|
|
|
|
|
|
|
|
explicit
|
|
|
|
recursive_directory_iterator(const path& __p)
|
|
|
|
: recursive_directory_iterator(__p, directory_options::none, nullptr) { }
|
|
|
|
|
|
|
|
recursive_directory_iterator(const path& __p, directory_options __options)
|
|
|
|
: recursive_directory_iterator(__p, __options, nullptr) { }
|
|
|
|
|
2017-10-27 19:49:29 +02:00
|
|
|
recursive_directory_iterator(const path& __p, directory_options __options,
|
|
|
|
error_code& __ec)
|
2017-10-23 14:11:22 +02:00
|
|
|
: recursive_directory_iterator(__p, __options, &__ec) { }
|
|
|
|
|
2017-10-27 19:49:29 +02:00
|
|
|
recursive_directory_iterator(const path& __p, error_code& __ec)
|
2017-10-23 14:11:22 +02:00
|
|
|
: recursive_directory_iterator(__p, directory_options::none, &__ec) { }
|
|
|
|
|
|
|
|
recursive_directory_iterator(
|
|
|
|
const recursive_directory_iterator&) = default;
|
|
|
|
|
|
|
|
recursive_directory_iterator(recursive_directory_iterator&&) = default;
|
|
|
|
|
|
|
|
~recursive_directory_iterator();
|
|
|
|
|
|
|
|
// observers
|
2019-04-05 18:56:23 +02:00
|
|
|
directory_options options() const noexcept;
|
|
|
|
int depth() const noexcept;
|
|
|
|
bool recursion_pending() const noexcept;
|
2017-10-23 14:11:22 +02:00
|
|
|
|
2019-04-05 18:56:23 +02:00
|
|
|
const directory_entry& operator*() const noexcept;
|
|
|
|
const directory_entry* operator->() const noexcept { return &**this; }
|
2017-10-23 14:11:22 +02:00
|
|
|
|
|
|
|
// modifiers
|
|
|
|
recursive_directory_iterator&
|
|
|
|
operator=(const recursive_directory_iterator& __rhs) noexcept;
|
|
|
|
recursive_directory_iterator&
|
|
|
|
operator=(recursive_directory_iterator&& __rhs) noexcept;
|
|
|
|
|
|
|
|
recursive_directory_iterator& operator++();
|
2017-10-27 19:49:29 +02:00
|
|
|
recursive_directory_iterator& increment(error_code& __ec);
|
2017-10-23 14:11:22 +02:00
|
|
|
|
|
|
|
__directory_iterator_proxy operator++(int)
|
|
|
|
{
|
|
|
|
__directory_iterator_proxy __pr{**this};
|
|
|
|
++*this;
|
|
|
|
return __pr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void pop();
|
|
|
|
void pop(error_code&);
|
|
|
|
|
2019-04-05 18:56:23 +02:00
|
|
|
void disable_recursion_pending() noexcept;
|
2017-10-23 14:11:22 +02:00
|
|
|
|
|
|
|
private:
|
|
|
|
recursive_directory_iterator(const path&, directory_options, error_code*);
|
|
|
|
|
|
|
|
friend bool
|
|
|
|
operator==(const recursive_directory_iterator& __lhs,
|
2019-04-05 18:56:31 +02:00
|
|
|
const recursive_directory_iterator& __rhs) noexcept
|
|
|
|
{
|
|
|
|
return !__rhs._M_dirs.owner_before(__lhs._M_dirs)
|
|
|
|
&& !__lhs._M_dirs.owner_before(__rhs._M_dirs);
|
|
|
|
}
|
|
|
|
|
|
|
|
friend bool
|
|
|
|
operator!=(const recursive_directory_iterator& __lhs,
|
|
|
|
const recursive_directory_iterator& __rhs) noexcept
|
|
|
|
{ return !(__lhs == __rhs); }
|
2017-10-23 14:11:22 +02:00
|
|
|
|
|
|
|
struct _Dir_stack;
|
PR libstdc++/67843 set shared_ptr lock policy at build-time
This resolves a longstanding issue where the lock policy for shared_ptr
reference counting depends on compilation options when the header is
included, so that different -march options can cause ABI changes. For
example, objects compiled with -march=armv7 will use atomics to
synchronize reference counts, and objects compiled with -march=armv5t
will use a mutex. That means the shared_ptr control block will have a
different layout in different objects, causing ODR violations and
undefined behaviour. This was the root cause of PR libstdc++/42734 as
well as PR libstdc++/67843.
The solution is to decide on the lock policy at build time, when
libstdc++ is configured. The configure script checks for the
availability of the necessary atomic built-ins for the target and fixes
that choice permanently. Different -march flags used to compile user
code will not cause changes to the lock policy. This results in an ABI
change for certain compilations, but only where there was already an ABI
incompatibility between the libstdc++.so library and objects built with
an incompatible -march option. In general, this means a more stable ABI
that isn't silently altered when -march flags make addition atomic ops
available.
To force a target to use "atomic" or "mutex" the new configure option
--with-libstdcxx-lock-policy can be used.
In order to turn ODR violations into linker errors, the uses of
shared_ptr in filesystem directory iterators have been replaced
with __shared_ptr, and explicit instantiations are declared. This
ensures that object files using those types cannot link to libstdc++
libs unless they use the same lock policy.
PR libstdc++/67843
* acinclude.m4 (GLIBCXX_ENABLE_LOCK_POLICY): Add new macro
that defines _GLIBCXX_HAVE_ATOMIC_LOCK_POLICY.
* config.h.in: Regenerate.
* configure: Regenerate.
* configure.ac: Use GLIBCXX_ENABLE_LOCK_POLICY.
* doc/xml/manual/configure.xml: Document new configure option.
* include/bits/fs_dir.h (directory_iterator): Use __shared_ptr
instead of shared_ptr.
(recursive_directory_iterator): Likewise.
(__shared_ptr<_Dir>): Add explicit instantiation declaration.
(__shared_ptr<recursive_directory_iterator::_Dir_stack>): Likewise.
* include/bits/shared_ptr_base.h (__allocate_shared, __make_shared):
Add default template argument for _Lock_policy template parameter.
* include/ext/concurrence.h (__default_lock_policy): Check macro
_GLIBCXX_HAVE_ATOMIC_LOCK_POLICY instead of checking if the current
target supports the builtins for compare-and-swap.
* src/filesystem/std-dir.cc (__shared_ptr<_Dir>): Add explicit
instantiation definition.
(__shared_ptr<recursive_directory_iterator::_Dir_stack>): Likewise.
(directory_iterator, recursive_directory_iterator): Use __make_shared
instead of make_shared.
From-SVN: r266533
2018-11-28 00:25:56 +01:00
|
|
|
std::__shared_ptr<_Dir_stack> _M_dirs;
|
2017-10-23 14:11:22 +02:00
|
|
|
};
|
|
|
|
|
2019-05-02 17:46:38 +02:00
|
|
|
/// @relates std::filesystem::recursive_directory_iterator @{
|
|
|
|
|
|
|
|
/** @brief Enable range-based `for` using recursive_directory_iterator.
|
|
|
|
*
|
|
|
|
* e.g. `for (auto& entry : recursive_directory_iterator(".")) ...`
|
|
|
|
*/
|
2017-10-23 14:11:22 +02:00
|
|
|
inline recursive_directory_iterator
|
|
|
|
begin(recursive_directory_iterator __iter) noexcept
|
|
|
|
{ return __iter; }
|
|
|
|
|
2019-05-02 17:46:38 +02:00
|
|
|
/// Return a past-the-end recursive_directory_iterator
|
2017-10-23 14:11:22 +02:00
|
|
|
inline recursive_directory_iterator
|
|
|
|
end(recursive_directory_iterator) noexcept
|
|
|
|
{ return recursive_directory_iterator(); }
|
2019-05-02 17:46:38 +02:00
|
|
|
// @}
|
2017-10-23 14:11:22 +02:00
|
|
|
|
|
|
|
_GLIBCXX_END_NAMESPACE_CXX11
|
|
|
|
|
|
|
|
// @} group filesystem
|
|
|
|
} // namespace filesystem
|
|
|
|
|
PR libstdc++/67843 set shared_ptr lock policy at build-time
This resolves a longstanding issue where the lock policy for shared_ptr
reference counting depends on compilation options when the header is
included, so that different -march options can cause ABI changes. For
example, objects compiled with -march=armv7 will use atomics to
synchronize reference counts, and objects compiled with -march=armv5t
will use a mutex. That means the shared_ptr control block will have a
different layout in different objects, causing ODR violations and
undefined behaviour. This was the root cause of PR libstdc++/42734 as
well as PR libstdc++/67843.
The solution is to decide on the lock policy at build time, when
libstdc++ is configured. The configure script checks for the
availability of the necessary atomic built-ins for the target and fixes
that choice permanently. Different -march flags used to compile user
code will not cause changes to the lock policy. This results in an ABI
change for certain compilations, but only where there was already an ABI
incompatibility between the libstdc++.so library and objects built with
an incompatible -march option. In general, this means a more stable ABI
that isn't silently altered when -march flags make addition atomic ops
available.
To force a target to use "atomic" or "mutex" the new configure option
--with-libstdcxx-lock-policy can be used.
In order to turn ODR violations into linker errors, the uses of
shared_ptr in filesystem directory iterators have been replaced
with __shared_ptr, and explicit instantiations are declared. This
ensures that object files using those types cannot link to libstdc++
libs unless they use the same lock policy.
PR libstdc++/67843
* acinclude.m4 (GLIBCXX_ENABLE_LOCK_POLICY): Add new macro
that defines _GLIBCXX_HAVE_ATOMIC_LOCK_POLICY.
* config.h.in: Regenerate.
* configure: Regenerate.
* configure.ac: Use GLIBCXX_ENABLE_LOCK_POLICY.
* doc/xml/manual/configure.xml: Document new configure option.
* include/bits/fs_dir.h (directory_iterator): Use __shared_ptr
instead of shared_ptr.
(recursive_directory_iterator): Likewise.
(__shared_ptr<_Dir>): Add explicit instantiation declaration.
(__shared_ptr<recursive_directory_iterator::_Dir_stack>): Likewise.
* include/bits/shared_ptr_base.h (__allocate_shared, __make_shared):
Add default template argument for _Lock_policy template parameter.
* include/ext/concurrence.h (__default_lock_policy): Check macro
_GLIBCXX_HAVE_ATOMIC_LOCK_POLICY instead of checking if the current
target supports the builtins for compare-and-swap.
* src/filesystem/std-dir.cc (__shared_ptr<_Dir>): Add explicit
instantiation definition.
(__shared_ptr<recursive_directory_iterator::_Dir_stack>): Likewise.
(directory_iterator, recursive_directory_iterator): Use __make_shared
instead of make_shared.
From-SVN: r266533
2018-11-28 00:25:56 +01:00
|
|
|
// Use explicit instantiations of these types. Any inconsistency in the
|
|
|
|
// value of __default_lock_policy between code including this header and
|
|
|
|
// the library will cause a linker error.
|
|
|
|
extern template class
|
|
|
|
__shared_ptr<filesystem::_Dir>;
|
|
|
|
extern template class
|
|
|
|
__shared_ptr<filesystem::recursive_directory_iterator::_Dir_stack>;
|
|
|
|
|
2017-10-23 14:11:22 +02:00
|
|
|
_GLIBCXX_END_NAMESPACE_VERSION
|
|
|
|
} // namespace std
|
|
|
|
|
|
|
|
#endif // C++17
|
|
|
|
|
|
|
|
#endif // _GLIBCXX_FS_DIR_H
|