#pragma message "using readdir" #include "error.hpp" #include "fs_closedir.hpp" #include "fs_inode.hpp" #include "fs_opendir.hpp" #include "fs_readdir.hpp" #include "hashset.hpp" #include "scope_guard.hpp" #include "ugid.hpp" #include "fuse_dirents.hpp" struct DirRV { const fs::path *branch_path; DIR *dir; int err; }; static uint64_t _dirent_exact_namelen(const struct dirent *d_) { #ifdef _D_EXACT_NAMLEN return _D_EXACT_NAMLEN(d_); #elif defined _DIRENT_HAVE_D_NAMLEN return d_->d_namlen; #else return strlen(d_->d_name); #endif } static inline std::vector> _opendir(ThreadPool &tp_, const Branches::Ptr &branches_, const fs::path &rel_dirpath_, uid_t const uid_, gid_t const gid_) { std::vector> futures; futures.reserve(branches_->size()); for(const auto &branch : *branches_) { auto func = [&branch,&rel_dirpath_,uid_,gid_]() { DIR *dir; fs::path abs_dirpath; const ugid::Set ugid(uid_,gid_); abs_dirpath = branch.path / rel_dirpath_; errno = 0; dir = fs::opendir(abs_dirpath); return DirRV{&branch.path,dir,-errno}; }; auto rv = tp_.enqueue_task(std::move(func)); futures.emplace_back(std::move(rv)); } return futures; } static inline int _readdir(std::vector> &dh_futures_, const fs::path &rel_dirpath_, fuse_dirents_t *dirents_) { Err err; HashSet names; fs::path rel_filepath; rel_filepath = rel_dirpath_ / "dummy"; for(auto &dh_future : dh_futures_) { DirRV dirrv; dirrv = dh_future.get(); err = dirrv.err; if(dirrv.dir == NULL) continue; DEFER { fs::closedir(dirrv.dir); }; for(dirent *de = fs::readdir(dirrv.dir); de; de = fs::readdir(dirrv.dir)) { int rv; int namelen; namelen = ::_dirent_exact_namelen(de); rv = names.put(de->d_name,namelen); if(rv == 0) continue; rel_filepath.replace_filename(de->d_name); de->d_ino = fs::inode::calc(*dirrv.branch_path, rel_filepath, DTTOIF(de->d_type), de->d_ino); fuse_dirents_add(dirents_,de,namelen); } } return err; }