Exheredludis/paludis/util/fs_iterator.cc
Saleem Abdulrasool 64ba7d5be8 modernize: use default method synthesis
Convert a number of destructors to default synthesized functions.  Try to
inline a few instances into the header.  It should be possible to inline all of
them, however, gcc seems to emit a number of warnings.  Furthermore, some of the
destructors are pure-virtualed, but provide an implementation.  Placing the
definition into the header causes ODR violations.
2016-08-06 11:58:04 -07:00

252 lines
6.8 KiB
C++

/* vim: set sw=4 sts=4 et foldmethod=syntax : */
/*
* Copyright (c) 2005, 2006, 2007, 2008, 2010, 2011 Ciaran McCreesh
* Copyright (c) 2008 Fernando J. Pereda
*
* This file is part of the Paludis package manager. Paludis is free software;
* you can redistribute it and/or modify it under the terms of the GNU General
* Public License version 2, as published by the Free Software Foundation.
*
* Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <paludis/util/fs_iterator.hh>
#include <paludis/util/fs_path.hh>
#include <paludis/util/fs_error.hh>
#include <paludis/util/fs_stat.hh>
#include <paludis/util/stringify.hh>
#include <paludis/util/exception.hh>
#include <paludis/util/pimp-impl.hh>
#include <paludis/util/options.hh>
#include <paludis/util/tribool.hh>
#include <dirent.h>
#include <sys/types.h>
#include <functional>
#include <set>
#include <cstring>
#include <cerrno>
#include "config.h"
using namespace paludis;
#include <paludis/util/fs_iterator-se.cc>
typedef std::multiset<std::pair<ino_t, FSPath>, std::function<bool (std::pair<ino_t, FSPath>, std::pair<ino_t, FSPath>)> > EntrySet;
namespace paludis
{
template<>
struct Imp<FSIterator>
{
std::shared_ptr<EntrySet> items;
EntrySet::iterator iter;
Imp(const std::shared_ptr<EntrySet> & ii) :
items(ii)
{
}
};
bool compare_inode(const std::pair<ino_t, FSPath> & a, const std::pair<ino_t, FSPath> & b)
{
return a.first < b.first;
}
bool compare_name(const std::pair<ino_t, FSPath> & a, const std::pair<ino_t, FSPath> & b)
{
return FSPathComparator()(a.second, b.second);
}
}
FSIterator::FSIterator(const FSPath & base, const FSIteratorOptions & options) :
_imp(std::shared_ptr<EntrySet>())
{
using namespace std::placeholders;
if (options[fsio_inode_sort])
_imp->items = std::make_shared<EntrySet>(&compare_inode);
else
_imp->items = std::make_shared<EntrySet>(&compare_name);
DIR * d(opendir(stringify(base).c_str()));
if (nullptr == d)
throw FSError("Error opening directory '" + stringify(base) + "': " + stringify(::strerror(errno)));
bool have_any_special_wants(options[fsio_want_directories] || options[fsio_want_regular_files]);
struct dirent * de;
bool done(false);
while (nullptr != ((de = readdir(d))))
{
if (done)
break;
bool want(false);
if (! options[fsio_include_dotfiles])
{
if ('.' != de->d_name[0])
want = true;
}
else if (! (de->d_name[0] == '.' &&
(de->d_name[1] == '\0' || (de->d_name[1] == '.' && de->d_name[2] == '\0'))))
want = true;
if (want)
{
FSPath f(stringify(base / std::string(de->d_name)));
if (have_any_special_wants)
{
Tribool still_want(indeterminate);
#ifdef HAVE_DIRENT_DTYPE
if (DT_UNKNOWN != de->d_type)
{
int s(DTTOIF(de->d_type));
if (S_ISLNK(s))
{
if (! options[fsio_deref_symlinks_for_wants])
still_want = false;
}
else if (S_ISREG(s))
still_want = options[fsio_want_regular_files];
else if (S_ISDIR(s))
still_want = options[fsio_want_directories];
else
still_want = false;
}
#endif
if (still_want.is_indeterminate())
{
FSStat f_stat(f);
if (f_stat.is_regular_file())
still_want = options[fsio_want_regular_files];
else if (f_stat.is_directory())
still_want = options[fsio_want_directories];
else if (f_stat.is_symlink())
{
if (options[fsio_deref_symlinks_for_wants])
{
if (f_stat.is_regular_file_or_symlink_to_regular_file())
still_want = options[fsio_want_regular_files];
else if (f_stat.is_directory_or_symlink_to_directory())
still_want = options[fsio_want_directories];
else
still_want = false;
}
else
still_want = false;
}
else
still_want = false;
}
want = still_want.is_true();
}
if (want)
{
_imp->items->insert(std::make_pair(de->d_ino, f));
if (options[fsio_first_only])
done = true;
}
}
}
_imp->iter = _imp->items->begin();
closedir(d);
}
FSIterator::FSIterator(const FSIterator & other) :
_imp(other._imp->items)
{
_imp->iter = other._imp->iter;
}
FSIterator::FSIterator() :
_imp(std::shared_ptr<EntrySet>(std::make_shared<EntrySet>(&compare_name)))
{
_imp->iter = _imp->items->end();
}
FSIterator::~FSIterator() = default;
FSIterator &
FSIterator::operator= (const FSIterator & other)
{
if (this != &other)
{
_imp->items = other._imp->items;
_imp->iter = other._imp->iter;
}
return *this;
}
const FSPath &
FSIterator::operator* () const
{
return _imp->iter->second;
}
const FSPath *
FSIterator::operator-> () const
{
return &_imp->iter->second;
}
FSIterator &
FSIterator::operator++ ()
{
++_imp->iter;
return *this;
}
FSIterator
FSIterator::operator++ (int)
{
FSIterator c(*this);
_imp->iter++;
return c;
}
bool
paludis::operator== (const FSIterator & me, const FSIterator & other)
{
if (other._imp->iter == other._imp->items->end())
return me._imp->iter == me._imp->items->end();
if (me._imp->iter == me._imp->items->end())
return other._imp->iter == other._imp->items->end();
if (other._imp->items != me._imp->items)
throw InternalError(PALUDIS_HERE, "comparing two different FSIterators.");
return other._imp->iter == me._imp->iter;
}
bool
paludis::operator!= (const FSIterator & me, const FSIterator & other)
{
return ! operator== (me, other);
}
namespace paludis
{
template class Pimp<FSIterator>;
}