1*b0d29bc4SBrooks Davis // Copyright 2015 The Kyua Authors.
2*b0d29bc4SBrooks Davis // All rights reserved.
3*b0d29bc4SBrooks Davis //
4*b0d29bc4SBrooks Davis // Redistribution and use in source and binary forms, with or without
5*b0d29bc4SBrooks Davis // modification, are permitted provided that the following conditions are
6*b0d29bc4SBrooks Davis // met:
7*b0d29bc4SBrooks Davis //
8*b0d29bc4SBrooks Davis // * Redistributions of source code must retain the above copyright
9*b0d29bc4SBrooks Davis // notice, this list of conditions and the following disclaimer.
10*b0d29bc4SBrooks Davis // * Redistributions in binary form must reproduce the above copyright
11*b0d29bc4SBrooks Davis // notice, this list of conditions and the following disclaimer in the
12*b0d29bc4SBrooks Davis // documentation and/or other materials provided with the distribution.
13*b0d29bc4SBrooks Davis // * Neither the name of Google Inc. nor the names of its contributors
14*b0d29bc4SBrooks Davis // may be used to endorse or promote products derived from this software
15*b0d29bc4SBrooks Davis // without specific prior written permission.
16*b0d29bc4SBrooks Davis //
17*b0d29bc4SBrooks Davis // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*b0d29bc4SBrooks Davis // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*b0d29bc4SBrooks Davis // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*b0d29bc4SBrooks Davis // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*b0d29bc4SBrooks Davis // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*b0d29bc4SBrooks Davis // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*b0d29bc4SBrooks Davis // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*b0d29bc4SBrooks Davis // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*b0d29bc4SBrooks Davis // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*b0d29bc4SBrooks Davis // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*b0d29bc4SBrooks Davis // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*b0d29bc4SBrooks Davis
29*b0d29bc4SBrooks Davis #include "utils/fs/directory.hpp"
30*b0d29bc4SBrooks Davis
31*b0d29bc4SBrooks Davis extern "C" {
32*b0d29bc4SBrooks Davis #include <sys/types.h>
33*b0d29bc4SBrooks Davis
34*b0d29bc4SBrooks Davis #include <dirent.h>
35*b0d29bc4SBrooks Davis }
36*b0d29bc4SBrooks Davis
37*b0d29bc4SBrooks Davis #include <cerrno>
38*b0d29bc4SBrooks Davis #include <memory>
39*b0d29bc4SBrooks Davis
40*b0d29bc4SBrooks Davis #include "utils/format/macros.hpp"
41*b0d29bc4SBrooks Davis #include "utils/fs/exceptions.hpp"
42*b0d29bc4SBrooks Davis #include "utils/fs/path.hpp"
43*b0d29bc4SBrooks Davis #include "utils/noncopyable.hpp"
44*b0d29bc4SBrooks Davis #include "utils/sanity.hpp"
45*b0d29bc4SBrooks Davis #include "utils/text/operations.ipp"
46*b0d29bc4SBrooks Davis
47*b0d29bc4SBrooks Davis namespace detail = utils::fs::detail;
48*b0d29bc4SBrooks Davis namespace fs = utils::fs;
49*b0d29bc4SBrooks Davis namespace text = utils::text;
50*b0d29bc4SBrooks Davis
51*b0d29bc4SBrooks Davis
52*b0d29bc4SBrooks Davis /// Constructs a new directory entry.
53*b0d29bc4SBrooks Davis ///
54*b0d29bc4SBrooks Davis /// \param name_ Name of the directory entry.
directory_entry(const std::string & name_)55*b0d29bc4SBrooks Davis fs::directory_entry::directory_entry(const std::string& name_) : name(name_)
56*b0d29bc4SBrooks Davis {
57*b0d29bc4SBrooks Davis }
58*b0d29bc4SBrooks Davis
59*b0d29bc4SBrooks Davis
60*b0d29bc4SBrooks Davis /// Checks if two directory entries are equal.
61*b0d29bc4SBrooks Davis ///
62*b0d29bc4SBrooks Davis /// \param other The entry to compare to.
63*b0d29bc4SBrooks Davis ///
64*b0d29bc4SBrooks Davis /// \return True if the two entries are equal; false otherwise.
65*b0d29bc4SBrooks Davis bool
operator ==(const directory_entry & other) const66*b0d29bc4SBrooks Davis fs::directory_entry::operator==(const directory_entry& other) const
67*b0d29bc4SBrooks Davis {
68*b0d29bc4SBrooks Davis return name == other.name;
69*b0d29bc4SBrooks Davis }
70*b0d29bc4SBrooks Davis
71*b0d29bc4SBrooks Davis
72*b0d29bc4SBrooks Davis /// Checks if two directory entries are different.
73*b0d29bc4SBrooks Davis ///
74*b0d29bc4SBrooks Davis /// \param other The entry to compare to.
75*b0d29bc4SBrooks Davis ///
76*b0d29bc4SBrooks Davis /// \return True if the two entries are different; false otherwise.
77*b0d29bc4SBrooks Davis bool
operator !=(const directory_entry & other) const78*b0d29bc4SBrooks Davis fs::directory_entry::operator!=(const directory_entry& other) const
79*b0d29bc4SBrooks Davis {
80*b0d29bc4SBrooks Davis return !(*this == other);
81*b0d29bc4SBrooks Davis }
82*b0d29bc4SBrooks Davis
83*b0d29bc4SBrooks Davis
84*b0d29bc4SBrooks Davis /// Checks if this entry sorts before another entry.
85*b0d29bc4SBrooks Davis ///
86*b0d29bc4SBrooks Davis /// \param other The entry to compare to.
87*b0d29bc4SBrooks Davis ///
88*b0d29bc4SBrooks Davis /// \return True if this entry sorts before the other entry; false otherwise.
89*b0d29bc4SBrooks Davis bool
operator <(const directory_entry & other) const90*b0d29bc4SBrooks Davis fs::directory_entry::operator<(const directory_entry& other) const
91*b0d29bc4SBrooks Davis {
92*b0d29bc4SBrooks Davis return name < other.name;
93*b0d29bc4SBrooks Davis }
94*b0d29bc4SBrooks Davis
95*b0d29bc4SBrooks Davis
96*b0d29bc4SBrooks Davis /// Formats a directory entry.
97*b0d29bc4SBrooks Davis ///
98*b0d29bc4SBrooks Davis /// \param output Stream into which to inject the formatted entry.
99*b0d29bc4SBrooks Davis /// \param entry The entry to format.
100*b0d29bc4SBrooks Davis ///
101*b0d29bc4SBrooks Davis /// \return A reference to output.
102*b0d29bc4SBrooks Davis std::ostream&
operator <<(std::ostream & output,const directory_entry & entry)103*b0d29bc4SBrooks Davis fs::operator<<(std::ostream& output, const directory_entry& entry)
104*b0d29bc4SBrooks Davis {
105*b0d29bc4SBrooks Davis output << F("directory_entry{name=%s}") % text::quote(entry.name, '\'');
106*b0d29bc4SBrooks Davis return output;
107*b0d29bc4SBrooks Davis }
108*b0d29bc4SBrooks Davis
109*b0d29bc4SBrooks Davis
110*b0d29bc4SBrooks Davis /// Internal implementation details for the directory_iterator.
111*b0d29bc4SBrooks Davis ///
112*b0d29bc4SBrooks Davis /// In order to support multiple concurrent iterators over the same directory
113*b0d29bc4SBrooks Davis /// object, this class is the one that performs all directory-level accesses.
114*b0d29bc4SBrooks Davis /// In particular, even if it may seem surprising, this is the class that
115*b0d29bc4SBrooks Davis /// handles the DIR object for the directory.
116*b0d29bc4SBrooks Davis ///
117*b0d29bc4SBrooks Davis /// Note that iterators implemented by this class do not rely on the container
118*b0d29bc4SBrooks Davis /// directory class at all. This should not be relied on for object lifecycle
119*b0d29bc4SBrooks Davis /// purposes.
120*b0d29bc4SBrooks Davis struct utils::fs::detail::directory_iterator::impl : utils::noncopyable {
121*b0d29bc4SBrooks Davis /// Path of the directory accessed by this iterator.
122*b0d29bc4SBrooks Davis const fs::path _path;
123*b0d29bc4SBrooks Davis
124*b0d29bc4SBrooks Davis /// Raw pointer to the system representation of the directory.
125*b0d29bc4SBrooks Davis ///
126*b0d29bc4SBrooks Davis /// We also use this to determine if the iterator is valid (at the end) or
127*b0d29bc4SBrooks Davis /// not. A null pointer means an invalid iterator.
128*b0d29bc4SBrooks Davis ::DIR* _dirp;
129*b0d29bc4SBrooks Davis
130*b0d29bc4SBrooks Davis /// Raw representation of the system directory entry.
131*b0d29bc4SBrooks Davis ///
132*b0d29bc4SBrooks Davis /// We need to keep this at the class level so that we can use the
133*b0d29bc4SBrooks Davis /// readdir_r(3) function.
134*b0d29bc4SBrooks Davis ::dirent _dirent;
135*b0d29bc4SBrooks Davis
136*b0d29bc4SBrooks Davis /// Custom representation of the directory entry.
137*b0d29bc4SBrooks Davis ///
138*b0d29bc4SBrooks Davis /// This is separate from _dirent because this is the type we return to the
139*b0d29bc4SBrooks Davis /// user. We must keep this as a pointer so that we can support the common
140*b0d29bc4SBrooks Davis /// operators (* and ->) over iterators.
141*b0d29bc4SBrooks Davis std::auto_ptr< directory_entry > _entry;
142*b0d29bc4SBrooks Davis
143*b0d29bc4SBrooks Davis /// Constructs an iterator pointing to the "end" of the directory.
implutils::fs::detail::directory_iterator::impl144*b0d29bc4SBrooks Davis impl(void) : _path("invalid-directory-entry"), _dirp(NULL)
145*b0d29bc4SBrooks Davis {
146*b0d29bc4SBrooks Davis }
147*b0d29bc4SBrooks Davis
148*b0d29bc4SBrooks Davis /// Constructs a new iterator to start scanning a directory.
149*b0d29bc4SBrooks Davis ///
150*b0d29bc4SBrooks Davis /// \param path The directory that will be scanned.
151*b0d29bc4SBrooks Davis ///
152*b0d29bc4SBrooks Davis /// \throw system_error If there is a problem opening the directory.
implutils::fs::detail::directory_iterator::impl153*b0d29bc4SBrooks Davis explicit impl(const path& path) : _path(path)
154*b0d29bc4SBrooks Davis {
155*b0d29bc4SBrooks Davis DIR* dirp = ::opendir(_path.c_str());
156*b0d29bc4SBrooks Davis if (dirp == NULL) {
157*b0d29bc4SBrooks Davis const int original_errno = errno;
158*b0d29bc4SBrooks Davis throw fs::system_error(F("opendir(%s) failed") % _path,
159*b0d29bc4SBrooks Davis original_errno);
160*b0d29bc4SBrooks Davis }
161*b0d29bc4SBrooks Davis _dirp = dirp;
162*b0d29bc4SBrooks Davis
163*b0d29bc4SBrooks Davis // Initialize our first directory entry. Note that this may actually
164*b0d29bc4SBrooks Davis // close the directory we just opened if the directory happens to be
165*b0d29bc4SBrooks Davis // empty -- but directories are never empty because they at least have
166*b0d29bc4SBrooks Davis // '.' and '..' entries.
167*b0d29bc4SBrooks Davis next();
168*b0d29bc4SBrooks Davis }
169*b0d29bc4SBrooks Davis
170*b0d29bc4SBrooks Davis /// Destructor.
171*b0d29bc4SBrooks Davis ///
172*b0d29bc4SBrooks Davis /// This closes the directory if still open.
~implutils::fs::detail::directory_iterator::impl173*b0d29bc4SBrooks Davis ~impl(void)
174*b0d29bc4SBrooks Davis {
175*b0d29bc4SBrooks Davis if (_dirp != NULL)
176*b0d29bc4SBrooks Davis close();
177*b0d29bc4SBrooks Davis }
178*b0d29bc4SBrooks Davis
179*b0d29bc4SBrooks Davis /// Closes the directory and invalidates the iterator.
180*b0d29bc4SBrooks Davis void
closeutils::fs::detail::directory_iterator::impl181*b0d29bc4SBrooks Davis close(void)
182*b0d29bc4SBrooks Davis {
183*b0d29bc4SBrooks Davis PRE(_dirp != NULL);
184*b0d29bc4SBrooks Davis if (::closedir(_dirp) == -1) {
185*b0d29bc4SBrooks Davis UNREACHABLE_MSG("Invalid dirp provided to closedir(3)");
186*b0d29bc4SBrooks Davis }
187*b0d29bc4SBrooks Davis _dirp = NULL;
188*b0d29bc4SBrooks Davis }
189*b0d29bc4SBrooks Davis
190*b0d29bc4SBrooks Davis /// Advances the directory entry to the next one.
191*b0d29bc4SBrooks Davis ///
192*b0d29bc4SBrooks Davis /// It is possible to use this function on a new directory_entry object to
193*b0d29bc4SBrooks Davis /// initialize the first entry.
194*b0d29bc4SBrooks Davis ///
195*b0d29bc4SBrooks Davis /// \throw system_error If the call to readdir_r fails.
196*b0d29bc4SBrooks Davis void
nextutils::fs::detail::directory_iterator::impl197*b0d29bc4SBrooks Davis next(void)
198*b0d29bc4SBrooks Davis {
199*b0d29bc4SBrooks Davis ::dirent* result;
200*b0d29bc4SBrooks Davis
201*b0d29bc4SBrooks Davis if (::readdir_r(_dirp, &_dirent, &result) == -1) {
202*b0d29bc4SBrooks Davis const int original_errno = errno;
203*b0d29bc4SBrooks Davis throw fs::system_error(F("readdir_r(%s) failed") % _path,
204*b0d29bc4SBrooks Davis original_errno);
205*b0d29bc4SBrooks Davis }
206*b0d29bc4SBrooks Davis if (result == NULL) {
207*b0d29bc4SBrooks Davis _entry.reset(NULL);
208*b0d29bc4SBrooks Davis close();
209*b0d29bc4SBrooks Davis } else {
210*b0d29bc4SBrooks Davis _entry.reset(new directory_entry(_dirent.d_name));
211*b0d29bc4SBrooks Davis }
212*b0d29bc4SBrooks Davis }
213*b0d29bc4SBrooks Davis };
214*b0d29bc4SBrooks Davis
215*b0d29bc4SBrooks Davis
216*b0d29bc4SBrooks Davis /// Constructs a new directory iterator.
217*b0d29bc4SBrooks Davis ///
218*b0d29bc4SBrooks Davis /// \param pimpl The constructed internal implementation structure to use.
directory_iterator(std::shared_ptr<impl> pimpl)219*b0d29bc4SBrooks Davis detail::directory_iterator::directory_iterator(std::shared_ptr< impl > pimpl) :
220*b0d29bc4SBrooks Davis _pimpl(pimpl)
221*b0d29bc4SBrooks Davis {
222*b0d29bc4SBrooks Davis }
223*b0d29bc4SBrooks Davis
224*b0d29bc4SBrooks Davis
225*b0d29bc4SBrooks Davis /// Destructor.
~directory_iterator(void)226*b0d29bc4SBrooks Davis detail::directory_iterator::~directory_iterator(void)
227*b0d29bc4SBrooks Davis {
228*b0d29bc4SBrooks Davis }
229*b0d29bc4SBrooks Davis
230*b0d29bc4SBrooks Davis
231*b0d29bc4SBrooks Davis /// Creates a new directory iterator for a directory.
232*b0d29bc4SBrooks Davis ///
233*b0d29bc4SBrooks Davis /// \return The directory iterator. Note that the result may be invalid.
234*b0d29bc4SBrooks Davis ///
235*b0d29bc4SBrooks Davis /// \throw system_error If opening the directory or reading its first entry
236*b0d29bc4SBrooks Davis /// fails.
237*b0d29bc4SBrooks Davis detail::directory_iterator
new_begin(const path & path)238*b0d29bc4SBrooks Davis detail::directory_iterator::new_begin(const path& path)
239*b0d29bc4SBrooks Davis {
240*b0d29bc4SBrooks Davis return directory_iterator(std::shared_ptr< impl >(new impl(path)));
241*b0d29bc4SBrooks Davis }
242*b0d29bc4SBrooks Davis
243*b0d29bc4SBrooks Davis
244*b0d29bc4SBrooks Davis /// Creates a new invalid directory iterator.
245*b0d29bc4SBrooks Davis ///
246*b0d29bc4SBrooks Davis /// \return The invalid directory iterator.
247*b0d29bc4SBrooks Davis detail::directory_iterator
new_end(void)248*b0d29bc4SBrooks Davis detail::directory_iterator::new_end(void)
249*b0d29bc4SBrooks Davis {
250*b0d29bc4SBrooks Davis return directory_iterator(std::shared_ptr< impl >(new impl()));
251*b0d29bc4SBrooks Davis }
252*b0d29bc4SBrooks Davis
253*b0d29bc4SBrooks Davis
254*b0d29bc4SBrooks Davis /// Checks if two iterators are equal.
255*b0d29bc4SBrooks Davis ///
256*b0d29bc4SBrooks Davis /// We consider two iterators to be equal if both of them are invalid or,
257*b0d29bc4SBrooks Davis /// otherwise, if they have the exact same internal representation (as given by
258*b0d29bc4SBrooks Davis /// equality of the pimpl pointers).
259*b0d29bc4SBrooks Davis ///
260*b0d29bc4SBrooks Davis /// \param other The object to compare to.
261*b0d29bc4SBrooks Davis ///
262*b0d29bc4SBrooks Davis /// \return True if the two iterators are equal; false otherwise.
263*b0d29bc4SBrooks Davis bool
operator ==(const directory_iterator & other) const264*b0d29bc4SBrooks Davis detail::directory_iterator::operator==(const directory_iterator& other) const
265*b0d29bc4SBrooks Davis {
266*b0d29bc4SBrooks Davis return (_pimpl->_dirp == NULL && other._pimpl->_dirp == NULL) ||
267*b0d29bc4SBrooks Davis _pimpl == other._pimpl;
268*b0d29bc4SBrooks Davis }
269*b0d29bc4SBrooks Davis
270*b0d29bc4SBrooks Davis
271*b0d29bc4SBrooks Davis /// Checks if two iterators are different.
272*b0d29bc4SBrooks Davis ///
273*b0d29bc4SBrooks Davis /// \param other The object to compare to.
274*b0d29bc4SBrooks Davis ///
275*b0d29bc4SBrooks Davis /// \return True if the two iterators are different; false otherwise.
276*b0d29bc4SBrooks Davis bool
operator !=(const directory_iterator & other) const277*b0d29bc4SBrooks Davis detail::directory_iterator::operator!=(const directory_iterator& other) const
278*b0d29bc4SBrooks Davis {
279*b0d29bc4SBrooks Davis return !(*this == other);
280*b0d29bc4SBrooks Davis }
281*b0d29bc4SBrooks Davis
282*b0d29bc4SBrooks Davis
283*b0d29bc4SBrooks Davis /// Moves the iterator one element forward.
284*b0d29bc4SBrooks Davis ///
285*b0d29bc4SBrooks Davis /// \return A reference to the iterator.
286*b0d29bc4SBrooks Davis ///
287*b0d29bc4SBrooks Davis /// \throw system_error If advancing the iterator fails.
288*b0d29bc4SBrooks Davis detail::directory_iterator&
operator ++(void)289*b0d29bc4SBrooks Davis detail::directory_iterator::operator++(void)
290*b0d29bc4SBrooks Davis {
291*b0d29bc4SBrooks Davis _pimpl->next();
292*b0d29bc4SBrooks Davis return *this;
293*b0d29bc4SBrooks Davis }
294*b0d29bc4SBrooks Davis
295*b0d29bc4SBrooks Davis
296*b0d29bc4SBrooks Davis /// Dereferences the iterator to its contents.
297*b0d29bc4SBrooks Davis ///
298*b0d29bc4SBrooks Davis /// \return A reference to the directory entry pointed to by the iterator.
299*b0d29bc4SBrooks Davis const fs::directory_entry&
operator *(void) const300*b0d29bc4SBrooks Davis detail::directory_iterator::operator*(void) const
301*b0d29bc4SBrooks Davis {
302*b0d29bc4SBrooks Davis PRE(_pimpl->_entry.get() != NULL);
303*b0d29bc4SBrooks Davis return *_pimpl->_entry;
304*b0d29bc4SBrooks Davis }
305*b0d29bc4SBrooks Davis
306*b0d29bc4SBrooks Davis
307*b0d29bc4SBrooks Davis /// Dereferences the iterator to its contents.
308*b0d29bc4SBrooks Davis ///
309*b0d29bc4SBrooks Davis /// \return A pointer to the directory entry pointed to by the iterator.
310*b0d29bc4SBrooks Davis const fs::directory_entry*
operator ->(void) const311*b0d29bc4SBrooks Davis detail::directory_iterator::operator->(void) const
312*b0d29bc4SBrooks Davis {
313*b0d29bc4SBrooks Davis PRE(_pimpl->_entry.get() != NULL);
314*b0d29bc4SBrooks Davis return _pimpl->_entry.get();
315*b0d29bc4SBrooks Davis }
316*b0d29bc4SBrooks Davis
317*b0d29bc4SBrooks Davis
318*b0d29bc4SBrooks Davis /// Internal implementation details for the directory.
319*b0d29bc4SBrooks Davis struct utils::fs::directory::impl : utils::noncopyable {
320*b0d29bc4SBrooks Davis /// Path to the directory to scan.
321*b0d29bc4SBrooks Davis fs::path _path;
322*b0d29bc4SBrooks Davis
323*b0d29bc4SBrooks Davis /// Constructs a new directory.
324*b0d29bc4SBrooks Davis ///
325*b0d29bc4SBrooks Davis /// \param path_ Path to the directory to scan.
implutils::fs::directory::impl326*b0d29bc4SBrooks Davis impl(const fs::path& path_) : _path(path_)
327*b0d29bc4SBrooks Davis {
328*b0d29bc4SBrooks Davis }
329*b0d29bc4SBrooks Davis };
330*b0d29bc4SBrooks Davis
331*b0d29bc4SBrooks Davis
332*b0d29bc4SBrooks Davis /// Constructs a new directory.
333*b0d29bc4SBrooks Davis ///
334*b0d29bc4SBrooks Davis /// \param path_ Path to the directory to scan.
directory(const path & path_)335*b0d29bc4SBrooks Davis fs::directory::directory(const path& path_) : _pimpl(new impl(path_))
336*b0d29bc4SBrooks Davis {
337*b0d29bc4SBrooks Davis }
338*b0d29bc4SBrooks Davis
339*b0d29bc4SBrooks Davis
340*b0d29bc4SBrooks Davis /// Returns an iterator to start scanning the directory.
341*b0d29bc4SBrooks Davis ///
342*b0d29bc4SBrooks Davis /// \return An iterator on the directory.
343*b0d29bc4SBrooks Davis ///
344*b0d29bc4SBrooks Davis /// \throw system_error If the directory cannot be opened to obtain its first
345*b0d29bc4SBrooks Davis /// entry.
346*b0d29bc4SBrooks Davis fs::directory::const_iterator
begin(void) const347*b0d29bc4SBrooks Davis fs::directory::begin(void) const
348*b0d29bc4SBrooks Davis {
349*b0d29bc4SBrooks Davis return const_iterator::new_begin(_pimpl->_path);
350*b0d29bc4SBrooks Davis }
351*b0d29bc4SBrooks Davis
352*b0d29bc4SBrooks Davis
353*b0d29bc4SBrooks Davis /// Returns an invalid iterator to check for the end of an scan.
354*b0d29bc4SBrooks Davis ///
355*b0d29bc4SBrooks Davis /// \return An invalid iterator.
356*b0d29bc4SBrooks Davis fs::directory::const_iterator
end(void) const357*b0d29bc4SBrooks Davis fs::directory::end(void) const
358*b0d29bc4SBrooks Davis {
359*b0d29bc4SBrooks Davis return const_iterator::new_end();
360*b0d29bc4SBrooks Davis }
361