libstdc++
fs_dir.h
Go to the documentation of this file.
00001 // Filesystem directory utilities -*- C++ -*-
00002 
00003 // Copyright (C) 2014-2018 Free Software Foundation, Inc.
00004 //
00005 // This file is part of the GNU ISO C++ Library.  This library is free
00006 // software; you can redistribute it and/or modify it under the
00007 // terms of the GNU General Public License as published by the
00008 // Free Software Foundation; either version 3, or (at your option)
00009 // any later version.
00010 
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 // GNU General Public License for more details.
00015 
00016 // Under Section 7 of GPL version 3, you are granted additional
00017 // permissions described in the GCC Runtime Library Exception, version
00018 // 3.1, as published by the Free Software Foundation.
00019 
00020 // You should have received a copy of the GNU General Public License and
00021 // a copy of the GCC Runtime Library Exception along with this program;
00022 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
00023 // <http://www.gnu.org/licenses/>.
00024 
00025 /** @file include/bits/fs_dir.h
00026  *  This is an internal header file, included by other library headers.
00027  *  Do not attempt to use it directly. @headername{filesystem}
00028  */
00029 
00030 #ifndef _GLIBCXX_FS_DIR_H
00031 #define _GLIBCXX_FS_DIR_H 1
00032 
00033 #if __cplusplus >= 201703L
00034 # include <typeinfo>
00035 # include <ext/concurrence.h>
00036 # include <bits/unique_ptr.h>
00037 # include <bits/shared_ptr.h>
00038 
00039 namespace std _GLIBCXX_VISIBILITY(default)
00040 {
00041 _GLIBCXX_BEGIN_NAMESPACE_VERSION
00042 
00043 namespace filesystem
00044 {
00045   /**
00046    * @ingroup filesystem
00047    * @{
00048    */
00049 
00050   class file_status
00051   {
00052   public:
00053     // constructors and destructor
00054     file_status() noexcept : file_status(file_type::none) {}
00055 
00056     explicit
00057     file_status(file_type __ft, perms __prms = perms::unknown) noexcept
00058     : _M_type(__ft), _M_perms(__prms) { }
00059 
00060     file_status(const file_status&) noexcept = default;
00061     file_status(file_status&&) noexcept = default;
00062     ~file_status() = default;
00063 
00064     file_status& operator=(const file_status&) noexcept = default;
00065     file_status& operator=(file_status&&) noexcept = default;
00066 
00067     // observers
00068     file_type  type() const noexcept { return _M_type; }
00069     perms      permissions() const noexcept { return _M_perms; }
00070 
00071     // modifiers
00072     void       type(file_type __ft) noexcept { _M_type = __ft; }
00073     void       permissions(perms __prms) noexcept { _M_perms = __prms; }
00074 
00075   private:
00076     file_type   _M_type;
00077     perms       _M_perms;
00078   };
00079 
00080 _GLIBCXX_BEGIN_NAMESPACE_CXX11
00081 
00082   struct _Dir;
00083   class directory_iterator;
00084   class recursive_directory_iterator;
00085 
00086   class directory_entry
00087   {
00088   public:
00089     // constructors and destructor
00090     directory_entry() noexcept = default;
00091     directory_entry(const directory_entry&) = default;
00092     directory_entry(directory_entry&&) noexcept = default;
00093 
00094     explicit
00095     directory_entry(const filesystem::path& __p)
00096     : _M_path(__p)
00097     { refresh(); }
00098 
00099     directory_entry(const filesystem::path& __p, error_code& __ec)
00100     : _M_path(__p)
00101     {
00102       refresh(__ec);
00103       if (__ec)
00104         _M_path.clear();
00105     }
00106 
00107     ~directory_entry() = default;
00108 
00109     // modifiers
00110     directory_entry& operator=(const directory_entry&) = default;
00111     directory_entry& operator=(directory_entry&&) noexcept = default;
00112 
00113     void
00114     assign(const filesystem::path& __p)
00115     {
00116       _M_path = __p;
00117       refresh();
00118     }
00119 
00120     void
00121     assign(const filesystem::path& __p, error_code& __ec)
00122     {
00123       _M_path = __p;
00124       refresh(__ec);
00125     }
00126 
00127     void
00128     replace_filename(const filesystem::path& __p)
00129     {
00130       _M_path.replace_filename(__p);
00131       refresh();
00132     }
00133 
00134     void
00135     replace_filename(const filesystem::path& __p, error_code& __ec)
00136     {
00137       _M_path.replace_filename(__p);
00138       refresh(__ec);
00139     }
00140 
00141     void refresh() { _M_type = symlink_status().type(); }
00142     void refresh(error_code& __ec) { _M_type = symlink_status(__ec).type(); }
00143 
00144     // observers
00145     const filesystem::path& path() const noexcept { return _M_path; }
00146     operator const filesystem::path& () const noexcept { return _M_path; }
00147 
00148     bool
00149     exists() const
00150     { return filesystem::exists(file_status{_M_file_type()}); }
00151 
00152     bool
00153     exists(error_code& __ec) const noexcept
00154     { return filesystem::exists(file_status{_M_file_type(__ec)}); }
00155 
00156     bool
00157     is_block_file() const
00158     { return _M_file_type() == file_type::block; }
00159 
00160     bool
00161     is_block_file(error_code& __ec) const noexcept
00162     { return _M_file_type(__ec) == file_type::block; }
00163 
00164     bool
00165     is_character_file() const
00166     { return _M_file_type() == file_type::character; }
00167 
00168     bool
00169     is_character_file(error_code& __ec) const noexcept
00170     { return _M_file_type(__ec) == file_type::character; }
00171 
00172     bool
00173     is_directory() const
00174     { return _M_file_type() == file_type::directory; }
00175 
00176     bool
00177     is_directory(error_code& __ec) const noexcept
00178     { return _M_file_type(__ec) == file_type::directory; }
00179 
00180     bool
00181     is_fifo() const
00182     { return _M_file_type() == file_type::fifo; }
00183 
00184     bool
00185     is_fifo(error_code& __ec) const noexcept
00186     { return _M_file_type(__ec) == file_type::fifo; }
00187 
00188     bool
00189     is_other() const
00190     { return filesystem::is_other(file_status{_M_file_type()}); }
00191 
00192     bool
00193     is_other(error_code& __ec) const noexcept
00194     { return filesystem::is_other(file_status{_M_file_type(__ec)}); }
00195 
00196     bool
00197     is_regular_file() const
00198     { return _M_file_type() == file_type::regular; }
00199 
00200     bool
00201     is_regular_file(error_code& __ec) const noexcept
00202     { return _M_file_type(__ec) == file_type::regular; }
00203 
00204     bool
00205     is_socket() const
00206     { return _M_file_type() == file_type::socket; }
00207 
00208     bool
00209     is_socket(error_code& __ec) const noexcept
00210     { return _M_file_type(__ec) == file_type::socket; }
00211 
00212     bool
00213     is_symlink() const
00214     {
00215       if (_M_type != file_type::none)
00216         return _M_type == file_type::symlink;
00217       return symlink_status().type() == file_type::symlink;
00218     }
00219 
00220     bool
00221     is_symlink(error_code& __ec) const noexcept
00222     {
00223       if (_M_type != file_type::none)
00224         return _M_type == file_type::symlink;
00225       return symlink_status(__ec).type() == file_type::symlink;
00226     }
00227 
00228     uintmax_t
00229     file_size() const
00230     { return filesystem::file_size(_M_path); }
00231 
00232     uintmax_t
00233     file_size(error_code& __ec) const noexcept
00234     { return filesystem::file_size(_M_path, __ec); }
00235 
00236     uintmax_t
00237     hard_link_count() const
00238     { return filesystem::hard_link_count(_M_path); }
00239 
00240     uintmax_t
00241     hard_link_count(error_code& __ec) const noexcept
00242     { return filesystem::hard_link_count(_M_path, __ec); }
00243 
00244     file_time_type
00245     last_write_time() const
00246     { return filesystem::last_write_time(_M_path); }
00247 
00248 
00249     file_time_type
00250     last_write_time(error_code& __ec) const noexcept
00251     { return filesystem::last_write_time(_M_path, __ec); }
00252 
00253     file_status
00254     status() const
00255     { return filesystem::status(_M_path); }
00256 
00257     file_status
00258     status(error_code& __ec) const noexcept
00259     { return filesystem::status(_M_path, __ec); }
00260 
00261     file_status
00262     symlink_status() const
00263     { return filesystem::symlink_status(_M_path); }
00264 
00265     file_status
00266     symlink_status(error_code& __ec) const noexcept
00267     { return filesystem::symlink_status(_M_path, __ec); }
00268 
00269     bool
00270     operator< (const directory_entry& __rhs) const noexcept
00271     { return _M_path < __rhs._M_path; }
00272 
00273     bool
00274     operator==(const directory_entry& __rhs) const noexcept
00275     { return _M_path == __rhs._M_path; }
00276 
00277     bool
00278     operator!=(const directory_entry& __rhs) const noexcept
00279     { return _M_path != __rhs._M_path; }
00280 
00281     bool
00282     operator<=(const directory_entry& __rhs) const noexcept
00283     { return _M_path <= __rhs._M_path; }
00284 
00285     bool
00286     operator> (const directory_entry& __rhs) const noexcept
00287     { return _M_path > __rhs._M_path; }
00288 
00289     bool
00290     operator>=(const directory_entry& __rhs) const noexcept
00291     { return _M_path >= __rhs._M_path; }
00292 
00293   private:
00294     friend class _Dir;
00295     friend class directory_iterator;
00296     friend class recursive_directory_iterator;
00297 
00298     directory_entry(const filesystem::path& __p, file_type __t)
00299     : _M_path(__p), _M_type(__t)
00300     { }
00301 
00302     // Equivalent to status().type() but uses cached value, if any.
00303     file_type
00304     _M_file_type() const
00305     {
00306       if (_M_type != file_type::none && _M_type != file_type::symlink)
00307         return _M_type;
00308       return status().type();
00309     }
00310 
00311     // Equivalent to status(__ec).type() but uses cached value, if any.
00312     file_type
00313     _M_file_type(error_code& __ec) const noexcept
00314     {
00315       if (_M_type != file_type::none && _M_type != file_type::symlink)
00316         return _M_type;
00317       return status(__ec).type();
00318     }
00319 
00320     filesystem::path    _M_path;
00321     file_type           _M_type = file_type::none;
00322   };
00323 
00324   struct __directory_iterator_proxy
00325   {
00326     const directory_entry& operator*() const& noexcept { return _M_entry; }
00327 
00328     directory_entry operator*() && noexcept { return std::move(_M_entry); }
00329 
00330   private:
00331     friend class directory_iterator;
00332     friend class recursive_directory_iterator;
00333 
00334     explicit
00335     __directory_iterator_proxy(const directory_entry& __e) : _M_entry(__e) { }
00336 
00337     directory_entry _M_entry;
00338   };
00339 
00340   class directory_iterator
00341   {
00342   public:
00343     typedef directory_entry        value_type;
00344     typedef ptrdiff_t              difference_type;
00345     typedef const directory_entry* pointer;
00346     typedef const directory_entry& reference;
00347     typedef input_iterator_tag     iterator_category;
00348 
00349     directory_iterator() = default;
00350 
00351     explicit
00352     directory_iterator(const path& __p)
00353     : directory_iterator(__p, directory_options::none, nullptr) { }
00354 
00355     directory_iterator(const path& __p, directory_options __options)
00356     : directory_iterator(__p, __options, nullptr) { }
00357 
00358     directory_iterator(const path& __p, error_code& __ec)
00359     : directory_iterator(__p, directory_options::none, __ec) { }
00360 
00361     directory_iterator(const path& __p, directory_options __options,
00362                        error_code& __ec)
00363     : directory_iterator(__p, __options, &__ec) { }
00364 
00365     directory_iterator(const directory_iterator& __rhs) = default;
00366 
00367     directory_iterator(directory_iterator&& __rhs) noexcept = default;
00368 
00369     ~directory_iterator() = default;
00370 
00371     directory_iterator&
00372     operator=(const directory_iterator& __rhs) = default;
00373 
00374     directory_iterator&
00375     operator=(directory_iterator&& __rhs) noexcept = default;
00376 
00377     const directory_entry& operator*() const;
00378     const directory_entry* operator->() const { return &**this; }
00379     directory_iterator&    operator++();
00380     directory_iterator&    increment(error_code& __ec);
00381 
00382     __directory_iterator_proxy operator++(int)
00383     {
00384       __directory_iterator_proxy __pr{**this};
00385       ++*this;
00386       return __pr;
00387     }
00388 
00389   private:
00390     directory_iterator(const path&, directory_options, error_code*);
00391 
00392     friend bool
00393     operator==(const directory_iterator& __lhs,
00394                const directory_iterator& __rhs);
00395 
00396     friend class recursive_directory_iterator;
00397 
00398     std::shared_ptr<_Dir> _M_dir;
00399   };
00400 
00401   inline directory_iterator
00402   begin(directory_iterator __iter) noexcept
00403   { return __iter; }
00404 
00405   inline directory_iterator
00406   end(directory_iterator) noexcept
00407   { return directory_iterator(); }
00408 
00409   inline bool
00410   operator==(const directory_iterator& __lhs, const directory_iterator& __rhs)
00411   {
00412     return !__rhs._M_dir.owner_before(__lhs._M_dir)
00413       && !__lhs._M_dir.owner_before(__rhs._M_dir);
00414   }
00415 
00416   inline bool
00417   operator!=(const directory_iterator& __lhs, const directory_iterator& __rhs)
00418   { return !(__lhs == __rhs); }
00419 
00420   class recursive_directory_iterator
00421   {
00422   public:
00423     typedef directory_entry        value_type;
00424     typedef ptrdiff_t              difference_type;
00425     typedef const directory_entry* pointer;
00426     typedef const directory_entry& reference;
00427     typedef input_iterator_tag     iterator_category;
00428 
00429     recursive_directory_iterator() = default;
00430 
00431     explicit
00432     recursive_directory_iterator(const path& __p)
00433     : recursive_directory_iterator(__p, directory_options::none, nullptr) { }
00434 
00435     recursive_directory_iterator(const path& __p, directory_options __options)
00436     : recursive_directory_iterator(__p, __options, nullptr) { }
00437 
00438     recursive_directory_iterator(const path& __p, directory_options __options,
00439                                  error_code& __ec)
00440     : recursive_directory_iterator(__p, __options, &__ec) { }
00441 
00442     recursive_directory_iterator(const path& __p, error_code& __ec)
00443     : recursive_directory_iterator(__p, directory_options::none, &__ec) { }
00444 
00445     recursive_directory_iterator(
00446         const recursive_directory_iterator&) = default;
00447 
00448     recursive_directory_iterator(recursive_directory_iterator&&) = default;
00449 
00450     ~recursive_directory_iterator();
00451 
00452     // observers
00453     directory_options  options() const { return _M_options; }
00454     int                depth() const;
00455     bool               recursion_pending() const { return _M_pending; }
00456 
00457     const directory_entry& operator*() const;
00458     const directory_entry* operator->() const { return &**this; }
00459 
00460     // modifiers
00461     recursive_directory_iterator&
00462     operator=(const recursive_directory_iterator& __rhs) noexcept;
00463     recursive_directory_iterator&
00464     operator=(recursive_directory_iterator&& __rhs) noexcept;
00465 
00466     recursive_directory_iterator& operator++();
00467     recursive_directory_iterator& increment(error_code& __ec);
00468 
00469     __directory_iterator_proxy operator++(int)
00470     {
00471       __directory_iterator_proxy __pr{**this};
00472       ++*this;
00473       return __pr;
00474     }
00475 
00476     void pop();
00477     void pop(error_code&);
00478 
00479     void disable_recursion_pending() { _M_pending = false; }
00480 
00481   private:
00482     recursive_directory_iterator(const path&, directory_options, error_code*);
00483 
00484     friend bool
00485     operator==(const recursive_directory_iterator& __lhs,
00486                const recursive_directory_iterator& __rhs);
00487 
00488     struct _Dir_stack;
00489     std::shared_ptr<_Dir_stack> _M_dirs;
00490     directory_options _M_options = {};
00491     bool _M_pending = false;
00492   };
00493 
00494   inline recursive_directory_iterator
00495   begin(recursive_directory_iterator __iter) noexcept
00496   { return __iter; }
00497 
00498   inline recursive_directory_iterator
00499   end(recursive_directory_iterator) noexcept
00500   { return recursive_directory_iterator(); }
00501 
00502   inline bool
00503   operator==(const recursive_directory_iterator& __lhs,
00504              const recursive_directory_iterator& __rhs)
00505   {
00506     return !__rhs._M_dirs.owner_before(__lhs._M_dirs)
00507       && !__lhs._M_dirs.owner_before(__rhs._M_dirs);
00508   }
00509 
00510   inline bool
00511   operator!=(const recursive_directory_iterator& __lhs,
00512              const recursive_directory_iterator& __rhs)
00513   { return !(__lhs == __rhs); }
00514 
00515 _GLIBCXX_END_NAMESPACE_CXX11
00516 
00517   // @} group filesystem
00518 } // namespace filesystem
00519 
00520 _GLIBCXX_END_NAMESPACE_VERSION
00521 } // namespace std
00522 
00523 #endif // C++17
00524 
00525 #endif // _GLIBCXX_FS_DIR_H