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         {
00317           __ec.clear();
00318           return _M_type;
00319         }
00320       return status(__ec).type();
00321     }
00322 
00323     filesystem::path    _M_path;
00324     file_type           _M_type = file_type::none;
00325   };
00326 
00327   struct __directory_iterator_proxy
00328   {
00329     const directory_entry& operator*() const& noexcept { return _M_entry; }
00330 
00331     directory_entry operator*() && noexcept { return std::move(_M_entry); }
00332 
00333   private:
00334     friend class directory_iterator;
00335     friend class recursive_directory_iterator;
00336 
00337     explicit
00338     __directory_iterator_proxy(const directory_entry& __e) : _M_entry(__e) { }
00339 
00340     directory_entry _M_entry;
00341   };
00342 
00343   class directory_iterator
00344   {
00345   public:
00346     typedef directory_entry        value_type;
00347     typedef ptrdiff_t              difference_type;
00348     typedef const directory_entry* pointer;
00349     typedef const directory_entry& reference;
00350     typedef input_iterator_tag     iterator_category;
00351 
00352     directory_iterator() = default;
00353 
00354     explicit
00355     directory_iterator(const path& __p)
00356     : directory_iterator(__p, directory_options::none, nullptr) { }
00357 
00358     directory_iterator(const path& __p, directory_options __options)
00359     : directory_iterator(__p, __options, nullptr) { }
00360 
00361     directory_iterator(const path& __p, error_code& __ec)
00362     : directory_iterator(__p, directory_options::none, __ec) { }
00363 
00364     directory_iterator(const path& __p, directory_options __options,
00365                        error_code& __ec)
00366     : directory_iterator(__p, __options, &__ec) { }
00367 
00368     directory_iterator(const directory_iterator& __rhs) = default;
00369 
00370     directory_iterator(directory_iterator&& __rhs) noexcept = default;
00371 
00372     ~directory_iterator() = default;
00373 
00374     directory_iterator&
00375     operator=(const directory_iterator& __rhs) = default;
00376 
00377     directory_iterator&
00378     operator=(directory_iterator&& __rhs) noexcept = default;
00379 
00380     const directory_entry& operator*() const;
00381     const directory_entry* operator->() const { return &**this; }
00382     directory_iterator&    operator++();
00383     directory_iterator&    increment(error_code& __ec);
00384 
00385     __directory_iterator_proxy operator++(int)
00386     {
00387       __directory_iterator_proxy __pr{**this};
00388       ++*this;
00389       return __pr;
00390     }
00391 
00392   private:
00393     directory_iterator(const path&, directory_options, error_code*);
00394 
00395     friend bool
00396     operator==(const directory_iterator& __lhs,
00397                const directory_iterator& __rhs);
00398 
00399     friend class recursive_directory_iterator;
00400 
00401     std::shared_ptr<_Dir> _M_dir;
00402   };
00403 
00404   inline directory_iterator
00405   begin(directory_iterator __iter) noexcept
00406   { return __iter; }
00407 
00408   inline directory_iterator
00409   end(directory_iterator) noexcept
00410   { return directory_iterator(); }
00411 
00412   inline bool
00413   operator==(const directory_iterator& __lhs, const directory_iterator& __rhs)
00414   {
00415     return !__rhs._M_dir.owner_before(__lhs._M_dir)
00416       && !__lhs._M_dir.owner_before(__rhs._M_dir);
00417   }
00418 
00419   inline bool
00420   operator!=(const directory_iterator& __lhs, const directory_iterator& __rhs)
00421   { return !(__lhs == __rhs); }
00422 
00423   class recursive_directory_iterator
00424   {
00425   public:
00426     typedef directory_entry        value_type;
00427     typedef ptrdiff_t              difference_type;
00428     typedef const directory_entry* pointer;
00429     typedef const directory_entry& reference;
00430     typedef input_iterator_tag     iterator_category;
00431 
00432     recursive_directory_iterator() = default;
00433 
00434     explicit
00435     recursive_directory_iterator(const path& __p)
00436     : recursive_directory_iterator(__p, directory_options::none, nullptr) { }
00437 
00438     recursive_directory_iterator(const path& __p, directory_options __options)
00439     : recursive_directory_iterator(__p, __options, nullptr) { }
00440 
00441     recursive_directory_iterator(const path& __p, directory_options __options,
00442                                  error_code& __ec)
00443     : recursive_directory_iterator(__p, __options, &__ec) { }
00444 
00445     recursive_directory_iterator(const path& __p, error_code& __ec)
00446     : recursive_directory_iterator(__p, directory_options::none, &__ec) { }
00447 
00448     recursive_directory_iterator(
00449         const recursive_directory_iterator&) = default;
00450 
00451     recursive_directory_iterator(recursive_directory_iterator&&) = default;
00452 
00453     ~recursive_directory_iterator();
00454 
00455     // observers
00456     directory_options  options() const { return _M_options; }
00457     int                depth() const;
00458     bool               recursion_pending() const { return _M_pending; }
00459 
00460     const directory_entry& operator*() const;
00461     const directory_entry* operator->() const { return &**this; }
00462 
00463     // modifiers
00464     recursive_directory_iterator&
00465     operator=(const recursive_directory_iterator& __rhs) noexcept;
00466     recursive_directory_iterator&
00467     operator=(recursive_directory_iterator&& __rhs) noexcept;
00468 
00469     recursive_directory_iterator& operator++();
00470     recursive_directory_iterator& increment(error_code& __ec);
00471 
00472     __directory_iterator_proxy operator++(int)
00473     {
00474       __directory_iterator_proxy __pr{**this};
00475       ++*this;
00476       return __pr;
00477     }
00478 
00479     void pop();
00480     void pop(error_code&);
00481 
00482     void disable_recursion_pending() { _M_pending = false; }
00483 
00484   private:
00485     recursive_directory_iterator(const path&, directory_options, error_code*);
00486 
00487     friend bool
00488     operator==(const recursive_directory_iterator& __lhs,
00489                const recursive_directory_iterator& __rhs);
00490 
00491     struct _Dir_stack;
00492     std::shared_ptr<_Dir_stack> _M_dirs;
00493     directory_options _M_options = {};
00494     bool _M_pending = false;
00495   };
00496 
00497   inline recursive_directory_iterator
00498   begin(recursive_directory_iterator __iter) noexcept
00499   { return __iter; }
00500 
00501   inline recursive_directory_iterator
00502   end(recursive_directory_iterator) noexcept
00503   { return recursive_directory_iterator(); }
00504 
00505   inline bool
00506   operator==(const recursive_directory_iterator& __lhs,
00507              const recursive_directory_iterator& __rhs)
00508   {
00509     return !__rhs._M_dirs.owner_before(__lhs._M_dirs)
00510       && !__lhs._M_dirs.owner_before(__rhs._M_dirs);
00511   }
00512 
00513   inline bool
00514   operator!=(const recursive_directory_iterator& __lhs,
00515              const recursive_directory_iterator& __rhs)
00516   { return !(__lhs == __rhs); }
00517 
00518 _GLIBCXX_END_NAMESPACE_CXX11
00519 
00520   // @} group filesystem
00521 } // namespace filesystem
00522 
00523 _GLIBCXX_END_NAMESPACE_VERSION
00524 } // namespace std
00525 
00526 #endif // C++17
00527 
00528 #endif // _GLIBCXX_FS_DIR_H