Support symbolic links in walk_path.

This commit is contained in:
levlam 2023-01-04 17:25:30 +03:00
parent 8df67f0c3a
commit 3573990d52
7 changed files with 62 additions and 34 deletions

View File

@ -228,13 +228,7 @@ class CreateFileBench final : public td::Benchmark {
}
}
void tear_down() final {
td::walk_path("A/", [&](td::CSlice path, auto type) {
if (type == td::WalkPath::Type::ExitDir) {
td::rmdir(path).ignore();
} else if (type == td::WalkPath::Type::NotDir) {
td::unlink(path).ignore();
}
}).ignore();
td::rmrf("A/").ignore();
}
};
@ -250,22 +244,10 @@ class WalkPathBench final : public td::Benchmark {
}
void run(int n) final {
int cnt = 0;
td::walk_path("A/", [&](td::CSlice path, auto type) {
if (type == td::WalkPath::Type::EnterDir) {
return;
}
td::stat(path).ok();
cnt++;
}).ignore();
td::rmrf("A/").ignore();
}
void tear_down() final {
td::walk_path("A/", [&](td::CSlice path, auto type) {
if (type == td::WalkPath::Type::ExitDir) {
td::rmdir(path).ignore();
} else if (type == td::WalkPath::Type::NotDir) {
td::unlink(path).ignore();
}
}).ignore();
td::rmrf("A/").ignore();
}
};

View File

@ -17,8 +17,23 @@ int main(int argc, char *argv[]) {
auto status = td::walk_path(dir, [&](td::CSlice path, auto type) {
if (type != td::WalkPath::Type::EnterDir) {
cnt++;
LOG(INFO) << path << " " << (type == td::WalkPath::Type::ExitDir);
}
auto type_name = [&] {
switch (type) {
case td::WalkPath::Type::EnterDir:
return td::CSlice("Open");
case td::WalkPath::Type::ExitDir:
return td::CSlice("Exit");
case td::WalkPath::Type::RegularFile:
return td::CSlice("File");
case td::WalkPath::Type::Symlink:
return td::CSlice("Link");
default:
UNREACHABLE();
return td::CSlice();
}
}();
LOG(INFO) << type_name << ' ' << path;
//if (is_dir) {
// td::rmdir(path);
//} else {

View File

@ -112,7 +112,7 @@ void scan_fs(CancellationToken &token, CallbackT &&callback) {
if (token) {
return WalkPath::Action::Abort;
}
if (type != WalkPath::Type::NotDir) {
if (type != WalkPath::Type::RegularFile) {
return WalkPath::Action::Continue;
}
auto r_stat = stat(path);

View File

@ -121,7 +121,7 @@ X509_STORE *load_system_certificate_store() {
string default_cert_dir = X509_get_default_cert_dir();
for (auto cert_dir : full_split(default_cert_dir, ':')) {
walk_path(cert_dir, [&](CSlice path, WalkPath::Type type) {
if (type != WalkPath::Type::NotDir) {
if (type != WalkPath::Type::RegularFile) {
return type == WalkPath::Type::EnterDir && path != cert_dir ? WalkPath::Action::SkipDir
: WalkPath::Action::Continue;
}

View File

@ -91,9 +91,12 @@ Status rmrf(CSlice path) {
case WalkPath::Type::ExitDir:
rmdir(path).ignore();
break;
case WalkPath::Type::NotDir:
case WalkPath::Type::RegularFile:
unlink(path).ignore();
break;
case WalkPath::Type::Symlink:
// never follow symbolic links
break;
}
});
}
@ -263,6 +266,8 @@ Result<bool> walk_path_dir(string &path, const WalkFunction &func) TD_WARN_UNUSE
Result<bool> walk_path_file(string &path, const WalkFunction &func) TD_WARN_UNUSED_RESULT;
Result<bool> walk_path_symlink(string &path, const WalkFunction &func) TD_WARN_UNUSED_RESULT;
Result<bool> walk_path(string &path, const WalkFunction &func) TD_WARN_UNUSED_RESULT;
Result<bool> walk_path_subdir(string &path, DIR *dir, const WalkFunction &func) {
@ -296,6 +301,8 @@ Result<bool> walk_path_subdir(string &path, DIR *dir, const WalkFunction &func)
status = walk_path_dir(path, func);
} else if (entry->d_type == DT_REG) {
status = walk_path_file(path, func);
} else if (entry->d_type == DT_LNK) {
status = walk_path_symlink(path, func);
}
#else
#if !TD_SOLARIS
@ -354,7 +361,18 @@ Result<bool> walk_path_dir(string &path, const WalkFunction &func) {
}
Result<bool> walk_path_file(string &path, const WalkFunction &func) {
switch (func(path, WalkPath::Type::NotDir)) {
switch (func(path, WalkPath::Type::RegularFile)) {
case WalkPath::Action::Abort:
return false;
case WalkPath::Action::SkipDir:
case WalkPath::Action::Continue:
break;
}
return true;
}
Result<bool> walk_path_symlink(string &path, const WalkFunction &func) {
switch (func(path, WalkPath::Type::Symlink)) {
case WalkPath::Action::Abort:
return false;
case WalkPath::Action::SkipDir:
@ -368,17 +386,20 @@ Result<bool> walk_path(string &path, const WalkFunction &func) {
TRY_RESULT(fd, FileFd::open(path, FileFd::Read));
TRY_RESULT(stat, fd.stat());
bool is_dir = stat.is_dir_;
bool is_reg = stat.is_reg_;
if (is_dir) {
if (stat.is_dir_) {
return walk_path_dir(path, std::move(fd), func);
}
fd.close();
if (is_reg) {
if (stat.is_reg_) {
return walk_path_file(path, func);
}
if (stat.is_symbolic_link_) {
return walk_path_symlink(path, func);
}
return true;
}
} // namespace detail
@ -589,14 +610,24 @@ static Result<bool> walk_path_dir(const std::wstring &dir_name,
if (!is_ok) {
return false;
}
} else {
switch (func(entry_name, WalkPath::Type::NotDir)) {
} else if ((file_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0) {
switch (func(entry_name, WalkPath::Type::RegularFile)) {
case WalkPath::Action::Abort:
return false;
case WalkPath::Action::SkipDir:
case WalkPath::Action::Continue:
break;
}
} else if (file_data.dwReserved0 == IO_REPARSE_TAG_SYMLINK) {
switch (func(entry_name, WalkPath::Type::Symlink)) {
case WalkPath::Action::Abort:
return false;
case WalkPath::Action::SkipDir:
case WalkPath::Action::Continue:
break;
}
} else {
// skip other reparse points
}
}
auto status = FindNextFileW(handle, &file_data);

View File

@ -44,7 +44,7 @@ Result<string> mkdtemp(CSlice dir, Slice prefix) TD_WARN_UNUSED_RESULT;
class WalkPath {
public:
enum class Action { Continue, Abort, SkipDir };
enum class Type { EnterDir, ExitDir, NotDir };
enum class Type { EnterDir, ExitDir, RegularFile, Symlink };
template <class F, class R = decltype(std::declval<F>()("", Type::ExitDir))>
static TD_WARN_UNUSED_RESULT std::enable_if_t<std::is_same<R, Action>::value, Status> run(CSlice path, F &&func) {

View File

@ -54,7 +54,7 @@ TEST(Port, files) {
const int ITER_COUNT = 1000;
for (int i = 0; i < ITER_COUNT; i++) {
td::walk_path(main_dir, [&](td::CSlice name, td::WalkPath::Type type) {
if (type == td::WalkPath::Type::NotDir) {
if (type == td::WalkPath::Type::RegularFile) {
ASSERT_TRUE(name == fd_path || name == fd2_path);
}
cnt++;