Browse Source

* Implemented comparison of directory entries and path

* Fixed bug: Copy directory iterator caused SEGFAULT and wrong listings
master
bergmann 6 years ago
parent
commit
97de8ddbf6
6 changed files with 247 additions and 24 deletions
  1. +20
    -6
      include/cppfs/directory/directory.h
  2. +77
    -1
      include/cppfs/directory/directory.inl
  3. +29
    -16
      include/cppfs/directory/directory.linux.inl
  4. +14
    -0
      include/cppfs/path/path.h
  5. +36
    -0
      include/cppfs/path/path.inl
  6. +71
    -1
      test/cppfs/directory_tests.cpp

+ 20
- 6
include/cppfs/directory/directory.h View File

@@ -21,20 +21,33 @@ namespace cppfs
{
public:
file_type type;
std::string name;
cppfs::path path;

public:
static inline int compare(const entry& lhv, const entry& rhv);

public:
inline friend bool operator==(const entry& lhv, const entry& rhv);
inline friend bool operator!=(const entry& lhv, const entry& rhv);
inline friend bool operator<=(const entry& lhv, const entry& rhv);
inline friend bool operator>=(const entry& lhv, const entry& rhv);
inline friend bool operator< (const entry& lhv, const entry& rhv);
inline friend bool operator> (const entry& lhv, const entry& rhv);
};

struct iterator
: public std::iterator<std::forward_iterator_tag, const entry>
{
private:
const directory * _owner;
entry _entry;
cppfs::path _path;
entry _entry;

public:
inline iterator() = default;

inline iterator(
const directory& p_owner,
bool p_end);
bool p_end);

inline iterator(
iterator&& p_other);
@@ -58,8 +71,9 @@ namespace cppfs
private:
using dir_ptr_u = std::unique_ptr<DIR, decltype(&closedir)>;

dir_ptr_u _dir;
struct dirent * _dirent;
dir_ptr_u _dir { nullptr, &closedir };
long _pos { 0 };
struct dirent * _dirent { nullptr };

inline void next();
inline long offset() const;


+ 77
- 1
include/cppfs/directory/directory.inl View File

@@ -1,5 +1,7 @@
#pragma once

#include <cppcore/misc/compare.h>

#include "directory.h"
#include "../misc.h"
#include "../file.h"
@@ -7,6 +9,80 @@
namespace cppfs
{

/* directory::entry */

int directory::entry::compare(const entry& lhv, const entry& rhv)
{
cppcore::op_invariant_string_compare str_cmp;

auto lhp = lhv.path.parts();
auto rhp = rhv.path.parts();

auto lhi = lhp.begin();
auto rhi = rhp.begin();

auto lhc = lhp.size();
auto rhc = rhp.size();

auto lhd = lhv.type == file_type::directory ? 0 : 1;
auto rhd = rhv.type == file_type::directory ? 0 : 1;

/* check parts of the path (except the last one) */

while (lhc > 0 && rhc > 0)
{
auto lhx = lhc == 1 ? lhd : 0;
auto rhx = rhc == 1 ? rhd : 0;

/* check type (directory or file) */

if (lhx < rhx)
return -1;
if (lhx > rhx)
return 1;

/* check name */

auto cmp = str_cmp(*lhi, *rhi);
if (cmp != 0)
return cmp;

++lhi;
++rhi;

--lhc;
--rhc;
}

/* check length of the path */

if (lhc < rhc)
return -1;
if (lhc > rhc)
return 1;

return 0;
}

bool operator==(const directory::entry& lhv, const directory::entry& rhv)
{ return directory::entry::compare(lhv, rhv) == 0; }

bool operator!=(const directory::entry& lhv, const directory::entry& rhv)
{ return directory::entry::compare(lhv, rhv) != 0; }

bool operator<=(const directory::entry& lhv, const directory::entry& rhv)
{ return directory::entry::compare(lhv, rhv) <= 0; }

bool operator>=(const directory::entry& lhv, const directory::entry& rhv)
{ return directory::entry::compare(lhv, rhv) >= 0; }

bool operator< (const directory::entry& lhv, const directory::entry& rhv)
{ return directory::entry::compare(lhv, rhv) < 0; }

bool operator> (const directory::entry& lhv, const directory::entry& rhv)
{ return directory::entry::compare(lhv, rhv) > 0; }


/* directory */

template<typename... T_args>
@@ -27,7 +103,7 @@ namespace cppfs
{
for (auto& e : *this)
{
auto p = path().join(e.name);
auto p = path().join(e.path);
switch (e.type)
{
case file_type::directory:


+ 29
- 16
include/cppfs/directory/directory.linux.inl View File

@@ -10,15 +10,15 @@ namespace cppfs
/* directory::iterator */

directory::iterator::iterator(const directory& p_owner, bool p_end)
: _owner (&p_owner)
: _path (p_owner.path())
, _entry ()
, _dir (nullptr, &closedir)
, _pos (-1)
, _dirent (nullptr)
{
if (!p_end)
{
assert(_owner);
auto s = _owner->path().str();
auto s = _path.str();
_dir.reset(opendir(s.c_str()));
if (!_dir)
throw cppcore::error_exception("Unable to open directory", errno);
@@ -27,44 +27,58 @@ namespace cppfs
}

directory::iterator::iterator(iterator&& p_other)
: _owner (std::move(p_other)._owner)
: _path (std::move(p_other)._path)
, _entry (std::move(p_other)._entry)
, _dir (std::move(p_other)._dir)
, _pos (std::move(p_other)._pos)
, _dirent (std::move(p_other)._dirent)
{ }
{
p_other._dir.reset();
p_other._pos = -1;
p_other._dirent = nullptr;
}

directory::iterator::iterator(const iterator& p_other)
: _owner (p_other._owner)
: _path (p_other._path)
, _entry ()
, _dir (nullptr, &closedir)
, _pos (-1)
, _dirent (nullptr)
{ this->operator=(p_other); }

directory::iterator& directory::iterator::operator=(iterator&& p_other)
{
_owner = std::move(p_other)._owner;
_path = std::move(p_other)._path;
_entry = std::move(p_other)._entry;
_dir = std::move(p_other)._dir;
_pos = std::move(p_other)._pos;
_dirent = std::move(p_other)._dirent;

p_other._dir.reset();
p_other._pos = -1;
p_other._dirent = nullptr;

return *this;
}

directory::iterator& directory::iterator::operator=(const iterator& p_other)
{
_owner = p_other._owner;
_path = p_other._path;
_pos = p_other._pos;
_entry = entry { };
_dirent = nullptr;
_dir.reset();

assert(_owner);
auto s = _owner->path().str();
auto s = _path.str();
_dir.reset(opendir(s.c_str()));
if (!_dir)
throw cppcore::error_exception("Unable to open directory", errno);

seekdir(_dir.get(), p_other.offset());
next();
if (_dir && _pos >= 0)
{
seekdir(_dir.get(), _pos);
next();
}

return *this;
}
@@ -84,9 +98,7 @@ namespace cppfs

bool directory::iterator::operator==(const iterator& p_other) const
{
return _owner
&& p_other._owner
&& _owner == p_other._owner
return _path == p_other._path
&& ( (!_dirent && !p_other._dirent)
|| offset() == p_other.offset());
}
@@ -110,6 +122,7 @@ namespace cppfs
{
do
{
_pos = offset();
_dirent = readdir(_dir.get());
}
while (
@@ -122,7 +135,7 @@ namespace cppfs

if (_dirent)
{
_entry.name = &_dirent->d_name[0];
_entry.path = _path.join(std::string(&_dirent->d_name[0]));
switch (_dirent->d_type)
{
case DT_BLK: _entry.type = file_type::block_device; break;


+ 14
- 0
include/cppfs/path/path.h View File

@@ -139,6 +139,20 @@ namespace cppfs
*/
inline path join(const path& other) const;

public:
inline friend bool operator< (const path& lhv, const path& rhv);
inline friend bool operator<=(const path& lhv, const path& rhv);
inline friend bool operator==(const path& lhv, const path& rhv);
inline friend bool operator!=(const path& lhv, const path& rhv);
inline friend bool operator>=(const path& lhv, const path& rhv);
inline friend bool operator> (const path& lhv, const path& rhv);

public:
/**
* @brief Compare two paths.
*/
static inline int compare(const path& lhv, const path& rhv);

private:
/**
* @brief Create a path from the parts vector.


+ 36
- 0
include/cppfs/path/path.inl View File

@@ -119,4 +119,40 @@ namespace cppfs
}
}

bool operator< (const path& lhv, const path& rhv)
{ return path::compare(lhv, rhv) < 0; }

bool operator<=(const path& lhv, const path& rhv)
{ return path::compare(lhv, rhv) <= 0; }

bool operator==(const path& lhv, const path& rhv)
{ return path::compare(lhv, rhv) == 0; }

bool operator!=(const path& lhv, const path& rhv)
{ return path::compare(lhv, rhv) != 0; }

bool operator>=(const path& lhv, const path& rhv)
{ return path::compare(lhv, rhv) >= 0; }

bool operator> (const path& lhv, const path& rhv)
{ return path::compare(lhv, rhv) > 0; }


int path::compare(const path& lhv, const path& rhv)
{
auto& lhp = lhv.parts();
auto& rhp = rhv.parts();

auto lht = lhv._status == path_status::absoulte ? 0 : 1;
auto rht = rhv._status == path_status::absoulte ? 0 : 1;

return
lht < rht ? -1 :
lht > rht ? 1 :
lhp < rhp ? -1 :
rhp < rhp ? 1 :
0;

}

}

+ 71
- 1
test/cppfs/directory_tests.cpp View File

@@ -24,7 +24,7 @@ TEST(directory_tests, iterator)
directory dir("./cppfs");

std::vector<std::string> files;
std::transform(dir.begin(), dir.end(), std::back_inserter(files), [](auto& e) { return e.name; });
std::transform(dir.begin(), dir.end(), std::back_inserter(files), [](auto& e) { return e.path.parts().back(); });
std::sort(files.begin(), files.end());

EXPECT_EQ(
@@ -35,3 +35,73 @@ TEST(directory_tests, iterator)
"path_tests.cpp",
}));
}

TEST(directory_tests, entry_compare)
{
using namespace std::string_literals;

EXPECT_EQ(-1, directory::entry::compare(
directory::entry { file_type::directory, "/some/test/aaa"s },
directory::entry { file_type::directory, "/Some/Test/ZzZ"s }));

EXPECT_EQ(-1, directory::entry::compare(
directory::entry { file_type::directory, "/some/test"s },
directory::entry { file_type::directory, "/Some/Test/ZzZ"s }));

EXPECT_EQ(-1, directory::entry::compare(
directory::entry { file_type::directory, "/some/test/ZZZ"s },
directory::entry { file_type::file, "/Some/Test/AAA"s }));

EXPECT_EQ(-1, directory::entry::compare(
directory::entry { file_type::file, "/Some/aaa/AAA"s },
directory::entry { file_type::directory, "/some/bbb"s }));

EXPECT_EQ(-1, directory::entry::compare(
directory::entry { file_type::file, "/some/test/aAa"s },
directory::entry { file_type::file, "/Some/Test/ZzZ"s }));

EXPECT_EQ(-1, directory::entry::compare(
directory::entry { file_type::file, "/Some/Test/ZzZ"s },
directory::entry { file_type::file, "/some/test"s }));

EXPECT_EQ(-1, directory::entry::compare(
directory::entry { file_type::file, "/folder/file"s },
directory::entry { file_type::file, "/file"s }));



EXPECT_EQ(0, directory::entry::compare(
directory::entry { file_type::file, "/some/test/path"s },
directory::entry { file_type::file, "/Some/Test/paTh"s }));



EXPECT_EQ(1, directory::entry::compare(
directory::entry { file_type::directory, "/Some/Test/ZzZ"s },
directory::entry { file_type::directory, "/some/test/aaa"s }));

EXPECT_EQ(1, directory::entry::compare(
directory::entry { file_type::directory, "/Some/Test/ZzZ"s },
directory::entry { file_type::directory, "/some/test"s }));

EXPECT_EQ(1, directory::entry::compare(
directory::entry { file_type::file, "/Some/Test/AAA"s },
directory::entry { file_type::directory, "/some/test/ZZZ"s }));

EXPECT_EQ(1, directory::entry::compare(
directory::entry { file_type::directory, "/some/bbb"s },
directory::entry { file_type::file, "/Some/aaa/AAA"s }));

EXPECT_EQ(1, directory::entry::compare(
directory::entry { file_type::file, "/Some/Test/ZzZ"s },
directory::entry { file_type::file, "/some/test/aAa"s }));

EXPECT_EQ(1, directory::entry::compare(
directory::entry { file_type::file, "/some/test"s },
directory::entry { file_type::file, "/Some/Test/ZzZ"s }));

EXPECT_EQ(1, directory::entry::compare(
directory::entry { file_type::file, "/file"s },
directory::entry { file_type::file, "/folder/file"s }));

}

Loading…
Cancel
Save