dentry.cc 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. #include <defs.hpp>
  2. #include <assert.h>
  3. #include <errno.h>
  4. #include <sys/stat.h>
  5. #include <types/hash.hpp>
  6. #include <types/list.hpp>
  7. #include <types/path.hpp>
  8. #include <kernel/vfs.hpp>
  9. #include <kernel/vfs/dentry.hpp>
  10. using namespace fs;
  11. using types::hash_t, types::hash_str, types::hash_ptr;
  12. static inline struct dentry* __d_parent(struct dentry* dentry) {
  13. assert(dentry->parent);
  14. return dentry->parent;
  15. }
  16. static inline bool __d_is_present(struct dentry* dentry) {
  17. return dentry->flags & D_PRESENT;
  18. }
  19. static inline bool __d_is_dir(struct dentry* dentry) {
  20. return dentry->flags & D_DIRECTORY;
  21. }
  22. static inline bool __d_is_loaded(struct dentry* dentry) {
  23. return dentry->flags & D_LOADED;
  24. }
  25. static inline bool __d_equal(const struct dentry* dentry,
  26. const struct dentry* parent,
  27. types::string_view name) {
  28. return dentry->parent == parent && dentry->name == name;
  29. }
  30. static inline hash_t __d_hash(const struct dentry* parent,
  31. types::string_view name) {
  32. assert(parent && parent->cache);
  33. int bits = parent->cache->hash_bits;
  34. return hash_str(name, bits) ^ hash_ptr(parent, bits);
  35. }
  36. static inline struct dentry*& __d_first(const struct dcache* cache,
  37. hash_t hash) {
  38. return cache->arr[hash & ((1 << cache->hash_bits) - 1)];
  39. }
  40. static inline void __d_add(struct dentry* parent, struct dentry* dentry) {
  41. assert(!dentry->parent);
  42. assert(parent->refcount && dentry->refcount);
  43. dentry->parent = d_get(parent);
  44. dentry->prev = nullptr;
  45. dentry->next = __d_first(parent->cache, dentry->hash);
  46. __d_first(parent->cache, dentry->hash) = d_get(dentry);
  47. parent->cache->size++;
  48. }
  49. static inline struct dentry* __d_find_fast(const struct dentry* parent,
  50. types::string_view name) {
  51. auto* cache = parent->cache;
  52. assert(cache);
  53. hash_t hash = __d_hash(parent, name);
  54. for (struct dentry* dentry = __d_first(cache, hash); dentry;
  55. dentry = dentry->next) {
  56. if (!__d_equal(dentry, parent, name))
  57. continue;
  58. return d_get(dentry);
  59. }
  60. return nullptr;
  61. }
  62. static inline int __d_load(struct dentry* parent) {
  63. if (__d_is_loaded(parent))
  64. return 0;
  65. auto* inode = &parent->inode;
  66. if (!__d_is_dir(parent))
  67. return -ENOTDIR;
  68. size_t offset = 0;
  69. auto callback = readdir_callback_fn(
  70. [parent](const char* fn, size_t fnlen,
  71. const struct rust_inode_handle* handle,
  72. const struct inode_data* inode, u8) -> int {
  73. struct dentry* dentry = dcache_alloc(parent->cache);
  74. r_dentry_save_inode(dentry, handle);
  75. dentry->name.assign(fn, fnlen);
  76. if (S_ISDIR(inode->mode))
  77. dentry->flags = D_PRESENT | D_DIRECTORY;
  78. else if (S_ISLNK(inode->mode))
  79. dentry->flags = D_PRESENT | D_SYMLINK;
  80. else
  81. dentry->flags = D_PRESENT;
  82. dentry->hash = __d_hash(parent, dentry->name);
  83. __d_add(parent, dentry);
  84. d_put(dentry);
  85. return 0;
  86. });
  87. while (true) {
  88. ssize_t off = fs_readdir(inode, offset, &callback);
  89. if (off == 0)
  90. break;
  91. offset += off;
  92. }
  93. parent->flags |= D_LOADED;
  94. return 0;
  95. }
  96. std::pair<struct dentry*, int> fs::d_find(struct dentry* parent,
  97. types::string_view name) {
  98. assert(__d_is_present(parent));
  99. if (!__d_is_dir(parent))
  100. return {nullptr, -ENOTDIR};
  101. constexpr types::string_view dot{".", 1};
  102. constexpr types::string_view dotdot{"..", 2};
  103. if (name == dot) [[unlikely]]
  104. return {d_get(parent), 0};
  105. // this only works for dentries that is not fs_root of some context
  106. if (name == dotdot)
  107. return {d_get(__d_parent(parent)), 0};
  108. if (!__d_is_loaded(parent)) {
  109. if (int ret = __d_load(parent); ret != 0)
  110. return {nullptr, ret};
  111. }
  112. struct dentry* ret = __d_find_fast(parent, name);
  113. if (!ret) {
  114. auto* dentry = dcache_alloc(parent->cache);
  115. dentry->fs = parent->fs;
  116. dentry->name.assign(name.data(), name.size());
  117. dentry->hash = __d_hash(parent, dentry->name);
  118. __d_add(parent, dentry);
  119. return {dentry, -ENOENT};
  120. }
  121. return {ret, 0};
  122. }
  123. std::string fs::d_path(const struct dentry* dentry, const struct dentry* root) {
  124. const struct dentry* dents[32];
  125. int cnt = 0;
  126. const struct dentry* cur = dentry;
  127. while (cur != root) {
  128. assert(cur && cnt < 32);
  129. dents[cnt++] = cur;
  130. cur = cur->parent;
  131. }
  132. std::string ret = "/";
  133. for (int i = cnt - 1; i >= 0; --i) {
  134. ret += dents[i]->name;
  135. ret += '/';
  136. }
  137. return ret;
  138. }
  139. dentry_pointer fs::d_get(const dentry_pointer& dentry) {
  140. return d_get(dentry.get());
  141. }
  142. struct dentry* fs::d_get(struct dentry* dentry) {
  143. assert(dentry);
  144. ++dentry->refcount;
  145. return dentry;
  146. }
  147. struct dentry* fs::d_put(struct dentry* dentry) {
  148. assert(dentry);
  149. // TODO: if refcount is zero, mark dentry as unused
  150. --dentry->refcount;
  151. return dentry;
  152. ;
  153. }
  154. void dentry_deleter::operator()(struct dentry* dentry) const {
  155. fs::d_put(dentry);
  156. }
  157. void fs::dcache_init(struct dcache* cache, int hash_bits) {
  158. cache->hash_bits = hash_bits;
  159. cache->arr = new struct dentry*[1 << hash_bits]();
  160. cache->size = 0;
  161. }
  162. void fs::dcache_drop(struct dcache* cache) {
  163. assert(cache->size == 0);
  164. delete[] cache->arr;
  165. }
  166. struct dentry* fs::dcache_alloc(struct dcache* cache) {
  167. struct dentry* dentry = new struct dentry();
  168. dentry->cache = cache;
  169. return d_get(dentry);
  170. }
  171. void fs::dcache_init_root(struct dcache* cache, struct dentry* root) {
  172. assert(cache->size == 0);
  173. root->prev = root->next = nullptr;
  174. __d_first(cache, root->hash) = d_get(root);
  175. cache->size++;
  176. }
  177. void rust_get_cxx_string(const std::string* str,
  178. rust_get_cxx_string_result* out_result) {
  179. out_result->data = str->data();
  180. out_result->len = str->size();
  181. }
  182. void rust_operator_eql_cxx_string(const std::string* str, std::string* dst) {
  183. *dst = *str;
  184. }