1  // Filesystem directory utilities -*- C++ -*-
       2  
       3  // Copyright (C) 2014-2023 Free Software Foundation, Inc.
       4  //
       5  // This file is part of the GNU ISO C++ Library.  This library is free
       6  // software; you can redistribute it and/or modify it under the
       7  // terms of the GNU General Public License as published by the
       8  // Free Software Foundation; either version 3, or (at your option)
       9  // any later version.
      10  
      11  // This library is distributed in the hope that it will be useful,
      12  // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14  // GNU General Public License for more details.
      15  
      16  // Under Section 7 of GPL version 3, you are granted additional
      17  // permissions described in the GCC Runtime Library Exception, version
      18  // 3.1, as published by the Free Software Foundation.
      19  
      20  // You should have received a copy of the GNU General Public License and
      21  // a copy of the GCC Runtime Library Exception along with this program;
      22  // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      23  // <http://www.gnu.org/licenses/>.
      24  
      25  /** @file experimental/bits/fs_dir.h
      26   *  This is an internal header file, included by other library headers.
      27   *  Do not attempt to use it directly. @headername{experimental/filesystem}
      28   */
      29  
      30  #ifndef _GLIBCXX_EXPERIMENTAL_FS_DIR_H
      31  #define _GLIBCXX_EXPERIMENTAL_FS_DIR_H 1
      32  
      33  #if __cplusplus < 201103L
      34  # include <bits/c++0x_warning.h>
      35  #else
      36  # include <typeinfo>
      37  # include <ext/concurrence.h>
      38  # include <bits/unique_ptr.h>
      39  # include <bits/shared_ptr.h>
      40  
      41  namespace std _GLIBCXX_VISIBILITY(default)
      42  {
      43  _GLIBCXX_BEGIN_NAMESPACE_VERSION
      44  
      45  namespace experimental
      46  {
      47  namespace filesystem
      48  {
      49  inline namespace v1
      50  {
      51    /**
      52     * @addtogroup filesystem-ts
      53     * @{
      54     */
      55  
      56    class file_status
      57    {
      58    public:
      59      // constructors
      60      explicit
      61      file_status(file_type __ft = file_type::none,
      62  	        perms __prms = perms::unknown) noexcept
      63      : _M_type(__ft), _M_perms(__prms) { }
      64  
      65      file_status(const file_status&) noexcept = default;
      66      file_status(file_status&&) noexcept = default;
      67      ~file_status() = default;
      68  
      69      file_status& operator=(const file_status&) noexcept = default;
      70      file_status& operator=(file_status&&) noexcept = default;
      71  
      72      // observers
      73      file_type  type() const noexcept { return _M_type; }
      74      perms      permissions() const noexcept { return _M_perms; }
      75  
      76      // modifiers
      77      void       type(file_type __ft) noexcept { _M_type = __ft; }
      78      void       permissions(perms __prms) noexcept { _M_perms = __prms; }
      79  
      80    private:
      81      file_type	_M_type;
      82      perms	_M_perms;
      83    };
      84  
      85  _GLIBCXX_BEGIN_NAMESPACE_CXX11
      86  
      87    class directory_entry
      88    {
      89    public:
      90      // constructors and destructor
      91      directory_entry() noexcept = default;
      92      directory_entry(const directory_entry&) = default;
      93      directory_entry(directory_entry&&) noexcept = default;
      94      explicit directory_entry(const filesystem::path& __p) : _M_path(__p) { }
      95      ~directory_entry() = default;
      96  
      97      // modifiers
      98      directory_entry& operator=(const directory_entry&) = default;
      99      directory_entry& operator=(directory_entry&&) noexcept = default;
     100  
     101      void assign(const filesystem::path& __p) { _M_path = __p; }
     102  
     103      void
     104      replace_filename(const filesystem::path& __p)
     105      { _M_path = _M_path.parent_path() / __p; }
     106  
     107      // observers
     108      const filesystem::path&  path() const noexcept { return _M_path; }
     109      operator const filesystem::path&() const noexcept { return _M_path; }
     110  
     111      file_status
     112      status() const
     113      { return filesystem::status(_M_path); }
     114  
     115      file_status
     116      status(error_code& __ec) const noexcept
     117      { return filesystem::status(_M_path, __ec); }
     118  
     119      file_status
     120      symlink_status() const
     121      { return filesystem::symlink_status(_M_path); }
     122  
     123      file_status
     124      symlink_status(error_code& __ec) const noexcept
     125      { return filesystem::symlink_status(_M_path, __ec); }
     126  
     127      bool
     128      operator< (const directory_entry& __rhs) const noexcept
     129      { return _M_path < __rhs._M_path; }
     130  
     131      bool
     132      operator==(const directory_entry& __rhs) const noexcept
     133      { return _M_path == __rhs._M_path; }
     134  
     135      bool
     136      operator!=(const directory_entry& __rhs) const noexcept
     137      { return _M_path != __rhs._M_path; }
     138  
     139      bool
     140      operator<=(const directory_entry& __rhs) const noexcept
     141      { return _M_path <= __rhs._M_path; }
     142  
     143      bool
     144      operator> (const directory_entry& __rhs) const noexcept
     145      { return _M_path > __rhs._M_path; }
     146  
     147      bool
     148      operator>=(const directory_entry& __rhs) const noexcept
     149      { return _M_path >= __rhs._M_path; }
     150  
     151    private:
     152      filesystem::path    _M_path;
     153    };
     154  
     155    struct _Dir;
     156    class directory_iterator;
     157    class recursive_directory_iterator;
     158  
     159    struct __directory_iterator_proxy
     160    {
     161      const directory_entry& operator*() const& noexcept { return _M_entry; }
     162  
     163      directory_entry operator*() && noexcept { return std::move(_M_entry); }
     164  
     165    private:
     166      friend class directory_iterator;
     167      friend class recursive_directory_iterator;
     168  
     169      explicit
     170      __directory_iterator_proxy(const directory_entry& __e) : _M_entry(__e) { }
     171  
     172      directory_entry _M_entry;
     173    };
     174  
     175    class directory_iterator
     176    {
     177    public:
     178      typedef directory_entry        value_type;
     179      typedef ptrdiff_t              difference_type;
     180      typedef const directory_entry* pointer;
     181      typedef const directory_entry& reference;
     182      typedef input_iterator_tag     iterator_category;
     183  
     184      directory_iterator() = default;
     185  
     186      explicit
     187      directory_iterator(const path& __p)
     188      : directory_iterator(__p, directory_options::none, nullptr) { }
     189  
     190      directory_iterator(const path& __p, directory_options __options)
     191      : directory_iterator(__p, __options, nullptr) { }
     192  
     193      directory_iterator(const path& __p, error_code& __ec) noexcept
     194      : directory_iterator(__p, directory_options::none, __ec) { }
     195  
     196      directory_iterator(const path& __p,
     197  		       directory_options __options,
     198  		       error_code& __ec) noexcept
     199      : directory_iterator(__p, __options, &__ec) { }
     200  
     201      directory_iterator(const directory_iterator& __rhs) = default;
     202  
     203      directory_iterator(directory_iterator&& __rhs) noexcept = default;
     204  
     205      ~directory_iterator() = default;
     206  
     207      directory_iterator&
     208      operator=(const directory_iterator& __rhs) = default;
     209  
     210      directory_iterator&
     211      operator=(directory_iterator&& __rhs) noexcept = default;
     212  
     213      const directory_entry& operator*() const;
     214      const directory_entry* operator->() const { return &**this; }
     215      directory_iterator&    operator++();
     216      directory_iterator&    increment(error_code& __ec) noexcept;
     217  
     218      __directory_iterator_proxy operator++(int)
     219      {
     220        __directory_iterator_proxy __pr{**this};
     221        ++*this;
     222        return __pr;
     223      }
     224  
     225    private:
     226      directory_iterator(const path&, directory_options, error_code*);
     227  
     228      friend bool
     229      operator==(const directory_iterator& __lhs,
     230                 const directory_iterator& __rhs);
     231  
     232      friend class recursive_directory_iterator;
     233  
     234      std::shared_ptr<_Dir> _M_dir;
     235    };
     236  
     237    inline directory_iterator
     238    begin(directory_iterator __iter) noexcept
     239    { return __iter; }
     240  
     241    inline directory_iterator
     242    end(directory_iterator) noexcept
     243    { return directory_iterator(); }
     244  
     245    inline bool
     246    operator==(const directory_iterator& __lhs, const directory_iterator& __rhs)
     247    {
     248      return !__rhs._M_dir.owner_before(__lhs._M_dir)
     249        && !__lhs._M_dir.owner_before(__rhs._M_dir);
     250    }
     251  
     252    inline bool
     253    operator!=(const directory_iterator& __lhs, const directory_iterator& __rhs)
     254    { return !(__lhs == __rhs); }
     255  
     256    class recursive_directory_iterator
     257    {
     258    public:
     259      typedef directory_entry        value_type;
     260      typedef ptrdiff_t              difference_type;
     261      typedef const directory_entry* pointer;
     262      typedef const directory_entry& reference;
     263      typedef input_iterator_tag     iterator_category;
     264  
     265      recursive_directory_iterator() = default;
     266  
     267      explicit
     268      recursive_directory_iterator(const path& __p)
     269      : recursive_directory_iterator(__p, directory_options::none, nullptr) { }
     270  
     271      recursive_directory_iterator(const path& __p, directory_options __options)
     272      : recursive_directory_iterator(__p, __options, nullptr) { }
     273  
     274      recursive_directory_iterator(const path& __p,
     275                                   directory_options __options,
     276                                   error_code& __ec) noexcept
     277      : recursive_directory_iterator(__p, __options, &__ec) { }
     278  
     279      recursive_directory_iterator(const path& __p, error_code& __ec) noexcept
     280      : recursive_directory_iterator(__p, directory_options::none, &__ec) { }
     281  
     282      recursive_directory_iterator(
     283          const recursive_directory_iterator&) = default;
     284  
     285      recursive_directory_iterator(recursive_directory_iterator&&) = default;
     286  
     287      ~recursive_directory_iterator();
     288  
     289      // observers
     290      directory_options  options() const { return _M_options; }
     291      int                depth() const;
     292      bool               recursion_pending() const { return _M_pending; }
     293  
     294      const directory_entry& operator*() const;
     295      const directory_entry* operator->() const { return &**this; }
     296  
     297      // modifiers
     298      recursive_directory_iterator&
     299      operator=(const recursive_directory_iterator& __rhs) noexcept;
     300      recursive_directory_iterator&
     301      operator=(recursive_directory_iterator&& __rhs) noexcept;
     302  
     303      recursive_directory_iterator& operator++();
     304      recursive_directory_iterator& increment(error_code& __ec) noexcept;
     305  
     306      __directory_iterator_proxy operator++(int)
     307      {
     308        __directory_iterator_proxy __pr{**this};
     309        ++*this;
     310        return __pr;
     311      }
     312  
     313      void pop();
     314      void pop(error_code&);
     315  
     316      void disable_recursion_pending() { _M_pending = false; }
     317  
     318    private:
     319      recursive_directory_iterator(const path&, directory_options, error_code*);
     320  
     321      friend bool
     322      operator==(const recursive_directory_iterator& __lhs,
     323                 const recursive_directory_iterator& __rhs);
     324  
     325      struct _Dir_stack;
     326      std::shared_ptr<_Dir_stack> _M_dirs;
     327      directory_options _M_options = {};
     328      bool _M_pending = false;
     329    };
     330  
     331    inline recursive_directory_iterator
     332    begin(recursive_directory_iterator __iter) noexcept
     333    { return __iter; }
     334  
     335    inline recursive_directory_iterator
     336    end(recursive_directory_iterator) noexcept
     337    { return recursive_directory_iterator(); }
     338  
     339    inline bool
     340    operator==(const recursive_directory_iterator& __lhs,
     341               const recursive_directory_iterator& __rhs)
     342    {
     343      return !__rhs._M_dirs.owner_before(__lhs._M_dirs)
     344        && !__lhs._M_dirs.owner_before(__rhs._M_dirs);
     345    }
     346  
     347    inline bool
     348    operator!=(const recursive_directory_iterator& __lhs,
     349               const recursive_directory_iterator& __rhs)
     350    { return !(__lhs == __rhs); }
     351  
     352  _GLIBCXX_END_NAMESPACE_CXX11
     353  
     354    /// @} group filesystem-ts
     355  } // namespace v1
     356  } // namespace filesystem
     357  } // namespace experimental
     358  
     359  _GLIBCXX_END_NAMESPACE_VERSION
     360  } // namespace std
     361  
     362  #endif // C++11
     363  
     364  #endif // _GLIBCXX_EXPERIMENTAL_FS_DIR_H