123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- #include <defs.hpp>
- #include <assert.h>
- #include <errno.h>
- #include <sys/stat.h>
- #include <types/hash.hpp>
- #include <types/list.hpp>
- #include <types/path.hpp>
- #include <kernel/vfs.hpp>
- #include <kernel/vfs/dentry.hpp>
- using namespace fs;
- using types::hash_t, types::hash_str, types::hash_ptr;
- static inline struct dentry* __d_parent(struct dentry* dentry) {
- assert(dentry->parent);
- return dentry->parent;
- }
- static inline bool __d_is_present(struct dentry* dentry) {
- return dentry->flags & D_PRESENT;
- }
- static inline bool __d_is_dir(struct dentry* dentry) {
- return dentry->flags & D_DIRECTORY;
- }
- static inline bool __d_is_loaded(struct dentry* dentry) {
- return dentry->flags & D_LOADED;
- }
- static inline bool __d_equal(const struct dentry* dentry,
- const struct dentry* parent,
- types::string_view name) {
- return dentry->parent == parent && dentry->name == name;
- }
- static inline hash_t __d_hash(const struct dentry* parent,
- types::string_view name) {
- assert(parent && parent->cache);
- int bits = parent->cache->hash_bits;
- return hash_str(name, bits) ^ hash_ptr(parent, bits);
- }
- static inline struct dentry*& __d_first(const struct dcache* cache,
- hash_t hash) {
- return cache->arr[hash & ((1 << cache->hash_bits) - 1)];
- }
- static inline void __d_add(struct dentry* parent, struct dentry* dentry) {
- assert(!dentry->parent);
- assert(parent->refcount && dentry->refcount);
- dentry->parent = d_get(parent);
- dentry->prev = nullptr;
- dentry->next = __d_first(parent->cache, dentry->hash);
- __d_first(parent->cache, dentry->hash) = d_get(dentry);
- parent->cache->size++;
- }
- static inline struct dentry* __d_find_fast(const struct dentry* parent,
- types::string_view name) {
- auto* cache = parent->cache;
- assert(cache);
- hash_t hash = __d_hash(parent, name);
- for (struct dentry* dentry = __d_first(cache, hash); dentry;
- dentry = dentry->next) {
- if (!__d_equal(dentry, parent, name))
- continue;
- return d_get(dentry);
- }
- return nullptr;
- }
- static inline int __d_load(struct dentry* parent) {
- if (__d_is_loaded(parent))
- return 0;
- auto* inode = &parent->inode;
- if (!__d_is_dir(parent))
- return -ENOTDIR;
- size_t offset = 0;
- auto callback = readdir_callback_fn(
- [parent](const char* fn, size_t fnlen,
- const struct rust_inode_handle* handle,
- const struct inode_data* inode, u8) -> int {
- struct dentry* dentry = dcache_alloc(parent->cache);
- r_dentry_save_inode(dentry, handle);
- dentry->name.assign(fn, fnlen);
- if (S_ISDIR(inode->mode))
- dentry->flags = D_PRESENT | D_DIRECTORY;
- else if (S_ISLNK(inode->mode))
- dentry->flags = D_PRESENT | D_SYMLINK;
- else
- dentry->flags = D_PRESENT;
- dentry->hash = __d_hash(parent, dentry->name);
- __d_add(parent, dentry);
- d_put(dentry);
- return 0;
- });
- while (true) {
- ssize_t off = fs_readdir(inode, offset, &callback);
- if (off == 0)
- break;
- offset += off;
- }
- parent->flags |= D_LOADED;
- return 0;
- }
- std::pair<struct dentry*, int> fs::d_find(struct dentry* parent,
- types::string_view name) {
- assert(__d_is_present(parent));
- if (!__d_is_dir(parent))
- return {nullptr, -ENOTDIR};
- constexpr types::string_view dot{".", 1};
- constexpr types::string_view dotdot{"..", 2};
- if (name == dot) [[unlikely]]
- return {d_get(parent), 0};
- // this only works for dentries that is not fs_root of some context
- if (name == dotdot)
- return {d_get(__d_parent(parent)), 0};
- if (!__d_is_loaded(parent)) {
- if (int ret = __d_load(parent); ret != 0)
- return {nullptr, ret};
- }
- struct dentry* ret = __d_find_fast(parent, name);
- if (!ret) {
- auto* dentry = dcache_alloc(parent->cache);
- dentry->fs = parent->fs;
- dentry->name.assign(name.data(), name.size());
- dentry->hash = __d_hash(parent, dentry->name);
- __d_add(parent, dentry);
- return {dentry, -ENOENT};
- }
- return {ret, 0};
- }
- std::string fs::d_path(const struct dentry* dentry, const struct dentry* root) {
- const struct dentry* dents[32];
- int cnt = 0;
- const struct dentry* cur = dentry;
- while (cur != root) {
- assert(cur && cnt < 32);
- dents[cnt++] = cur;
- cur = cur->parent;
- }
- std::string ret = "/";
- for (int i = cnt - 1; i >= 0; --i) {
- ret += dents[i]->name;
- ret += '/';
- }
- return ret;
- }
- dentry_pointer fs::d_get(const dentry_pointer& dentry) {
- return d_get(dentry.get());
- }
- struct dentry* fs::d_get(struct dentry* dentry) {
- assert(dentry);
- ++dentry->refcount;
- return dentry;
- }
- struct dentry* fs::d_put(struct dentry* dentry) {
- assert(dentry);
- // TODO: if refcount is zero, mark dentry as unused
- --dentry->refcount;
- return dentry;
- ;
- }
- void dentry_deleter::operator()(struct dentry* dentry) const {
- fs::d_put(dentry);
- }
- void fs::dcache_init(struct dcache* cache, int hash_bits) {
- cache->hash_bits = hash_bits;
- cache->arr = new struct dentry*[1 << hash_bits]();
- cache->size = 0;
- }
- void fs::dcache_drop(struct dcache* cache) {
- assert(cache->size == 0);
- delete[] cache->arr;
- }
- struct dentry* fs::dcache_alloc(struct dcache* cache) {
- struct dentry* dentry = new struct dentry();
- dentry->cache = cache;
- return d_get(dentry);
- }
- void fs::dcache_init_root(struct dcache* cache, struct dentry* root) {
- assert(cache->size == 0);
- root->prev = root->next = nullptr;
- __d_first(cache, root->hash) = d_get(root);
- cache->size++;
- }
- void rust_get_cxx_string(const std::string* str,
- rust_get_cxx_string_result* out_result) {
- out_result->data = str->data();
- out_result->len = str->size();
- }
- void rust_operator_eql_cxx_string(const std::string* str, std::string* dst) {
- *dst = *str;
- }
|