Support symbolic links in walk_path.
This commit is contained in:
parent
8df67f0c3a
commit
3573990d52
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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++;
|
||||
|
|
Loading…
Reference in New Issue