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