libstdc++
fs_dir.h
Go to the documentation of this file.
00001 // Filesystem directory utilities -*- C++ -*-
00002 
00003 // Copyright (C) 2014-2019 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
00142     refresh()
00143     { _M_type = symlink_status().type(); }
00144 
00145     void
00146     refresh(error_code& __ec) noexcept
00147     { _M_type = symlink_status(__ec).type(); }
00148 
00149     // observers
00150     const filesystem::path& path() const noexcept { return _M_path; }
00151     operator const filesystem::path& () const noexcept { return _M_path; }
00152 
00153     bool
00154     exists() const
00155     { return filesystem::exists(file_status{_M_file_type()}); }
00156 
00157     bool
00158     exists(error_code& __ec) const noexcept
00159     { return filesystem::exists(file_status{_M_file_type(__ec)}); }
00160 
00161     bool
00162     is_block_file() const
00163     { return _M_file_type() == file_type::block; }
00164 
00165     bool
00166     is_block_file(error_code& __ec) const noexcept
00167     { return _M_file_type(__ec) == file_type::block; }
00168 
00169     bool
00170     is_character_file() const
00171     { return _M_file_type() == file_type::character; }
00172 
00173     bool
00174     is_character_file(error_code& __ec) const noexcept
00175     { return _M_file_type(__ec) == file_type::character; }
00176 
00177     bool
00178     is_directory() const
00179     { return _M_file_type() == file_type::directory; }
00180 
00181     bool
00182     is_directory(error_code& __ec) const noexcept
00183     { return _M_file_type(__ec) == file_type::directory; }
00184 
00185     bool
00186     is_fifo() const
00187     { return _M_file_type() == file_type::fifo; }
00188 
00189     bool
00190     is_fifo(error_code& __ec) const noexcept
00191     { return _M_file_type(__ec) == file_type::fifo; }
00192 
00193     bool
00194     is_other() const
00195     { return filesystem::is_other(file_status{_M_file_type()}); }
00196 
00197     bool
00198     is_other(error_code& __ec) const noexcept
00199     { return filesystem::is_other(file_status{_M_file_type(__ec)}); }
00200 
00201     bool
00202     is_regular_file() const
00203     { return _M_file_type() == file_type::regular; }
00204 
00205     bool
00206     is_regular_file(error_code& __ec) const noexcept
00207     { return _M_file_type(__ec) == file_type::regular; }
00208 
00209     bool
00210     is_socket() const
00211     { return _M_file_type() == file_type::socket; }
00212 
00213     bool
00214     is_socket(error_code& __ec) const noexcept
00215     { return _M_file_type(__ec) == file_type::socket; }
00216 
00217     bool
00218     is_symlink() const
00219     {
00220       if (_M_type != file_type::none)
00221         return _M_type == file_type::symlink;
00222       return symlink_status().type() == file_type::symlink;
00223     }
00224 
00225     bool
00226     is_symlink(error_code& __ec) const noexcept
00227     {
00228       if (_M_type != file_type::none)
00229         return _M_type == file_type::symlink;
00230       return symlink_status(__ec).type() == file_type::symlink;
00231     }
00232 
00233     uintmax_t
00234     file_size() const
00235     { return filesystem::file_size(_M_path); }
00236 
00237     uintmax_t
00238     file_size(error_code& __ec) const noexcept
00239     { return filesystem::file_size(_M_path, __ec); }
00240 
00241     uintmax_t
00242     hard_link_count() const
00243     { return filesystem::hard_link_count(_M_path); }
00244 
00245     uintmax_t
00246     hard_link_count(error_code& __ec) const noexcept
00247     { return filesystem::hard_link_count(_M_path, __ec); }
00248 
00249     file_time_type
00250     last_write_time() const
00251     { return filesystem::last_write_time(_M_path); }
00252 
00253 
00254     file_time_type
00255     last_write_time(error_code& __ec) const noexcept
00256     { return filesystem::last_write_time(_M_path, __ec); }
00257 
00258     file_status
00259     status() const
00260     { return filesystem::status(_M_path); }
00261 
00262     file_status
00263     status(error_code& __ec) const noexcept
00264     { return filesystem::status(_M_path, __ec); }
00265 
00266     file_status
00267     symlink_status() const
00268     { return filesystem::symlink_status(_M_path); }
00269 
00270     file_status
00271     symlink_status(error_code& __ec) const noexcept
00272     { return filesystem::symlink_status(_M_path, __ec); }
00273 
00274     bool
00275     operator< (const directory_entry& __rhs) const noexcept
00276     { return _M_path < __rhs._M_path; }
00277 
00278     bool
00279     operator==(const directory_entry& __rhs) const noexcept
00280     { return _M_path == __rhs._M_path; }
00281 
00282     bool
00283     operator!=(const directory_entry& __rhs) const noexcept
00284     { return _M_path != __rhs._M_path; }
00285 
00286     bool
00287     operator<=(const directory_entry& __rhs) const noexcept
00288     { return _M_path <= __rhs._M_path; }
00289 
00290     bool
00291     operator> (const directory_entry& __rhs) const noexcept
00292     { return _M_path > __rhs._M_path; }
00293 
00294     bool
00295     operator>=(const directory_entry& __rhs) const noexcept
00296     { return _M_path >= __rhs._M_path; }
00297 
00298   private:
00299     friend class _Dir;
00300     friend class directory_iterator;
00301     friend class recursive_directory_iterator;
00302 
00303     // _GLIBCXX_RESOLVE_LIB_DEFECTS
00304     // 3171. LWG 2989 breaks directory_entry stream insertion
00305     template<typename _CharT, typename _Traits>
00306       friend basic_ostream<_CharT, _Traits>&
00307       operator<<(basic_ostream<_CharT, _Traits>& __os,
00308                  const directory_entry& __d)
00309       { return __os << __d.path(); }
00310 
00311     directory_entry(const filesystem::path& __p, file_type __t)
00312     : _M_path(__p), _M_type(__t)
00313     { }
00314 
00315     // Equivalent to status().type() but uses cached value, if any.
00316     file_type
00317     _M_file_type() const
00318     {
00319       if (_M_type != file_type::none && _M_type != file_type::symlink)
00320         return _M_type;
00321       return status().type();
00322     }
00323 
00324     // Equivalent to status(__ec).type() but uses cached value, if any.
00325     file_type
00326     _M_file_type(error_code& __ec) const noexcept
00327     {
00328       if (_M_type != file_type::none && _M_type != file_type::symlink)
00329         {
00330           __ec.clear();
00331           return _M_type;
00332         }
00333       return status(__ec).type();
00334     }
00335 
00336     filesystem::path    _M_path;
00337     file_type           _M_type = file_type::none;
00338   };
00339 
00340   struct __directory_iterator_proxy
00341   {
00342     const directory_entry& operator*() const& noexcept { return _M_entry; }
00343 
00344     directory_entry operator*() && noexcept { return std::move(_M_entry); }
00345 
00346   private:
00347     friend class directory_iterator;
00348     friend class recursive_directory_iterator;
00349 
00350     explicit
00351     __directory_iterator_proxy(const directory_entry& __e) : _M_entry(__e) { }
00352 
00353     directory_entry _M_entry;
00354   };
00355 
00356   class directory_iterator
00357   {
00358   public:
00359     typedef directory_entry        value_type;
00360     typedef ptrdiff_t              difference_type;
00361     typedef const directory_entry* pointer;
00362     typedef const directory_entry& reference;
00363     typedef input_iterator_tag     iterator_category;
00364 
00365     directory_iterator() = default;
00366 
00367     explicit
00368     directory_iterator(const path& __p)
00369     : directory_iterator(__p, directory_options::none, nullptr) { }
00370 
00371     directory_iterator(const path& __p, directory_options __options)
00372     : directory_iterator(__p, __options, nullptr) { }
00373 
00374     directory_iterator(const path& __p, error_code& __ec)
00375     : directory_iterator(__p, directory_options::none, __ec) { }
00376 
00377     directory_iterator(const path& __p, directory_options __options,
00378                        error_code& __ec)
00379     : directory_iterator(__p, __options, &__ec) { }
00380 
00381     directory_iterator(const directory_iterator& __rhs) = default;
00382 
00383     directory_iterator(directory_iterator&& __rhs) noexcept = default;
00384 
00385     ~directory_iterator() = default;
00386 
00387     directory_iterator&
00388     operator=(const directory_iterator& __rhs) = default;
00389 
00390     directory_iterator&
00391     operator=(directory_iterator&& __rhs) noexcept = default;
00392 
00393     const directory_entry& operator*() const noexcept;
00394     const directory_entry* operator->() const noexcept { return &**this; }
00395     directory_iterator&    operator++();
00396     directory_iterator&    increment(error_code& __ec);
00397 
00398     __directory_iterator_proxy operator++(int)
00399     {
00400       __directory_iterator_proxy __pr{**this};
00401       ++*this;
00402       return __pr;
00403     }
00404 
00405   private:
00406     directory_iterator(const path&, directory_options, error_code*);
00407 
00408     friend bool
00409     operator==(const directory_iterator& __lhs,
00410                const directory_iterator& __rhs) noexcept
00411     {
00412       return !__rhs._M_dir.owner_before(__lhs._M_dir)
00413         && !__lhs._M_dir.owner_before(__rhs._M_dir);
00414     }
00415 
00416     friend bool
00417     operator!=(const directory_iterator& __lhs,
00418                const directory_iterator& __rhs) noexcept
00419     { return !(__lhs == __rhs); }
00420 
00421     friend class recursive_directory_iterator;
00422 
00423     std::__shared_ptr<_Dir> _M_dir;
00424   };
00425 
00426   inline directory_iterator
00427   begin(directory_iterator __iter) noexcept
00428   { return __iter; }
00429 
00430   inline directory_iterator
00431   end(directory_iterator) noexcept
00432   { return directory_iterator(); }
00433 
00434   class recursive_directory_iterator
00435   {
00436   public:
00437     typedef directory_entry        value_type;
00438     typedef ptrdiff_t              difference_type;
00439     typedef const directory_entry* pointer;
00440     typedef const directory_entry& reference;
00441     typedef input_iterator_tag     iterator_category;
00442 
00443     recursive_directory_iterator() = default;
00444 
00445     explicit
00446     recursive_directory_iterator(const path& __p)
00447     : recursive_directory_iterator(__p, directory_options::none, nullptr) { }
00448 
00449     recursive_directory_iterator(const path& __p, directory_options __options)
00450     : recursive_directory_iterator(__p, __options, nullptr) { }
00451 
00452     recursive_directory_iterator(const path& __p, directory_options __options,
00453                                  error_code& __ec)
00454     : recursive_directory_iterator(__p, __options, &__ec) { }
00455 
00456     recursive_directory_iterator(const path& __p, error_code& __ec)
00457     : recursive_directory_iterator(__p, directory_options::none, &__ec) { }
00458 
00459     recursive_directory_iterator(
00460         const recursive_directory_iterator&) = default;
00461 
00462     recursive_directory_iterator(recursive_directory_iterator&&) = default;
00463 
00464     ~recursive_directory_iterator();
00465 
00466     // observers
00467     directory_options  options() const noexcept;
00468     int                depth() const noexcept;
00469     bool               recursion_pending() const noexcept;
00470 
00471     const directory_entry& operator*() const noexcept;
00472     const directory_entry* operator->() const noexcept { return &**this; }
00473 
00474     // modifiers
00475     recursive_directory_iterator&
00476     operator=(const recursive_directory_iterator& __rhs) noexcept;
00477     recursive_directory_iterator&
00478     operator=(recursive_directory_iterator&& __rhs) noexcept;
00479 
00480     recursive_directory_iterator& operator++();
00481     recursive_directory_iterator& increment(error_code& __ec);
00482 
00483     __directory_iterator_proxy operator++(int)
00484     {
00485       __directory_iterator_proxy __pr{**this};
00486       ++*this;
00487       return __pr;
00488     }
00489 
00490     void pop();
00491     void pop(error_code&);
00492 
00493     void disable_recursion_pending() noexcept;
00494 
00495   private:
00496     recursive_directory_iterator(const path&, directory_options, error_code*);
00497 
00498     friend bool
00499     operator==(const recursive_directory_iterator& __lhs,
00500                const recursive_directory_iterator& __rhs) noexcept
00501     {
00502       return !__rhs._M_dirs.owner_before(__lhs._M_dirs)
00503         && !__lhs._M_dirs.owner_before(__rhs._M_dirs);
00504     }
00505 
00506     friend bool
00507     operator!=(const recursive_directory_iterator& __lhs,
00508                const recursive_directory_iterator& __rhs) noexcept
00509     { return !(__lhs == __rhs); }
00510 
00511     struct _Dir_stack;
00512     std::__shared_ptr<_Dir_stack> _M_dirs;
00513   };
00514 
00515   inline recursive_directory_iterator
00516   begin(recursive_directory_iterator __iter) noexcept
00517   { return __iter; }
00518 
00519   inline recursive_directory_iterator
00520   end(recursive_directory_iterator) noexcept
00521   { return recursive_directory_iterator(); }
00522 
00523 _GLIBCXX_END_NAMESPACE_CXX11
00524 
00525   // @} group filesystem
00526 } // namespace filesystem
00527 
00528   // Use explicit instantiations of these types. Any inconsistency in the
00529   // value of __default_lock_policy between code including this header and
00530   // the library will cause a linker error.
00531   extern template class
00532     __shared_ptr<filesystem::_Dir>;
00533   extern template class
00534     __shared_ptr<filesystem::recursive_directory_iterator::_Dir_stack>;
00535 
00536 _GLIBCXX_END_NAMESPACE_VERSION
00537 } // namespace std
00538 
00539 #endif // C++17
00540 
00541 #endif // _GLIBCXX_FS_DIR_H