filearr.cc 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. #include <set>
  2. #include <assert.h>
  3. #include <kernel/async/lock.hpp>
  4. #include <kernel/vfs.hpp>
  5. #include <kernel/vfs/dentry.hpp>
  6. #include <kernel/vfs/filearr.hpp>
  7. using namespace fs;
  8. using kernel::async::mutex, kernel::async::lock_guard;
  9. struct fditem {
  10. int fd;
  11. int flags;
  12. std::shared_ptr<file> pfile;
  13. };
  14. struct fditem_comparator {
  15. constexpr bool operator()(const fditem& lhs, const fditem& rhs) const {
  16. return lhs.fd < rhs.fd;
  17. }
  18. constexpr bool operator()(int fd, const fditem& rhs) const {
  19. return fd < rhs.fd;
  20. }
  21. constexpr bool operator()(const fditem& lhs, int fd) const {
  22. return lhs.fd < fd;
  23. }
  24. };
  25. // ALL METHODS SHOULD BE CALLED WITH LOCK HELD
  26. struct filearray::impl {
  27. mutex mtx;
  28. const fs_context* context;
  29. std::set<fditem, fditem_comparator> arr;
  30. int min_avail{};
  31. int allocate_fd(int from);
  32. void release_fd(int fd);
  33. int next_fd();
  34. int do_dup(const fditem& oldfile, int new_fd, int flags);
  35. int place_new_file(std::shared_ptr<file> pfile, int flags);
  36. };
  37. int filearray::impl::allocate_fd(int from) {
  38. if (from < min_avail)
  39. from = min_avail;
  40. if (from == min_avail) {
  41. int nextfd = min_avail + 1;
  42. auto iter = arr.find(nextfd);
  43. while (iter && nextfd == iter->fd)
  44. ++nextfd, ++iter;
  45. int retval = min_avail;
  46. min_avail = nextfd;
  47. return retval;
  48. }
  49. int fd = from;
  50. auto iter = arr.find(fd);
  51. while (iter && fd == iter->fd)
  52. ++fd, ++iter;
  53. return fd;
  54. }
  55. void filearray::impl::release_fd(int fd) {
  56. if (fd < min_avail)
  57. min_avail = fd;
  58. }
  59. int filearray::impl::next_fd() {
  60. return allocate_fd(min_avail);
  61. }
  62. int filearray::impl::do_dup(const fditem& oldfile, int new_fd, int flags) {
  63. bool inserted;
  64. std::tie(std::ignore, inserted) = arr.emplace(new_fd, flags, oldfile.pfile);
  65. assert(inserted);
  66. return new_fd;
  67. }
  68. int filearray::impl::place_new_file(std::shared_ptr<file> pfile, int flags) {
  69. int fd = next_fd();
  70. bool inserted;
  71. std::tie(std::ignore, inserted) = arr.emplace(fd, std::move(flags), pfile);
  72. assert(inserted);
  73. return fd;
  74. }
  75. int filearray::dup(int old_fd) {
  76. lock_guard lck{pimpl->mtx};
  77. auto iter = pimpl->arr.find(old_fd);
  78. if (!iter)
  79. return -EBADF;
  80. int fd = pimpl->next_fd();
  81. return pimpl->do_dup(*iter, fd, 0);
  82. }
  83. int filearray::dup(int old_fd, int new_fd, int flags) {
  84. lock_guard lck{pimpl->mtx};
  85. auto iter_old = pimpl->arr.find(old_fd);
  86. if (!iter_old)
  87. return -EBADF;
  88. auto iter_new = pimpl->arr.find(new_fd);
  89. if (iter_new) {
  90. iter_new->pfile = iter_old->pfile;
  91. iter_new->flags = flags;
  92. return new_fd;
  93. }
  94. int fd = pimpl->allocate_fd(new_fd);
  95. assert(fd == new_fd);
  96. return pimpl->do_dup(*iter_old, fd, flags);
  97. }
  98. int filearray::dupfd(int fd, int min_fd, int flags) {
  99. lock_guard lck{pimpl->mtx};
  100. auto iter = pimpl->arr.find(fd);
  101. if (!iter)
  102. return -EBADF;
  103. int new_fd = pimpl->allocate_fd(min_fd);
  104. return pimpl->do_dup(*iter, new_fd, flags);
  105. }
  106. int filearray::set_flags(int fd, int flags) {
  107. lock_guard lck{pimpl->mtx};
  108. auto iter = pimpl->arr.find(fd);
  109. if (!iter)
  110. return -EBADF;
  111. iter->flags |= flags;
  112. return 0;
  113. }
  114. int filearray::close(int fd) {
  115. lock_guard lck{pimpl->mtx};
  116. auto iter = pimpl->arr.find(fd);
  117. if (!iter)
  118. return -EBADF;
  119. pimpl->release_fd(fd);
  120. pimpl->arr.erase(iter);
  121. return 0;
  122. }
  123. static inline std::pair<dentry_pointer, int> _open_file(
  124. const fs_context& context, dentry* cwd, types::path_iterator filepath,
  125. int flags, mode_t mode) {
  126. auto [dent, ret] = fs::open(context, cwd, filepath);
  127. if (!dent)
  128. return {nullptr, ret};
  129. if (dent->flags & D_PRESENT) {
  130. if ((flags & O_CREAT) && (flags & O_EXCL))
  131. return {nullptr, -EEXIST};
  132. return {std::move(dent), 0};
  133. }
  134. if (!(flags & O_CREAT))
  135. return {nullptr, -ENOENT};
  136. // create file
  137. if (int ret = fs::creat(dent.get(), mode); ret != 0)
  138. return {nullptr, ret};
  139. return {std::move(dent), 0};
  140. }
  141. // TODO: file opening permissions check
  142. int filearray::open(dentry* cwd, types::path_iterator filepath, int flags,
  143. mode_t mode) {
  144. lock_guard lck{pimpl->mtx};
  145. auto [dent, ret] = _open_file(*pimpl->context, cwd, filepath, flags, mode);
  146. assert(dent || ret != 0);
  147. if (ret != 0)
  148. return ret;
  149. auto filemode = dent->inode->mode;
  150. int fdflag = (flags & O_CLOEXEC) ? FD_CLOEXEC : 0;
  151. file::file_flags fflags;
  152. fflags.read = !(flags & O_WRONLY);
  153. fflags.write = (flags & (O_WRONLY | O_RDWR));
  154. fflags.append = S_ISREG(filemode) && (flags & O_APPEND);
  155. // check whether dentry is a file if O_DIRECTORY is set
  156. if (flags & O_DIRECTORY) {
  157. if (!S_ISDIR(filemode))
  158. return -ENOTDIR;
  159. } else {
  160. if (S_ISDIR(filemode) && fflags.write)
  161. return -EISDIR;
  162. }
  163. // truncate file
  164. if (flags & O_TRUNC) {
  165. if (fflags.write && S_ISREG(filemode)) {
  166. auto ret = fs::truncate(dent->inode, 0);
  167. if (ret != 0)
  168. return ret;
  169. }
  170. }
  171. return pimpl->place_new_file(
  172. std::make_shared<regular_file>(fflags, 0, dent->inode), fdflag);
  173. }
  174. int filearray::pipe(int (&pipefd)[2]) {
  175. lock_guard lck{pimpl->mtx};
  176. if (1) {
  177. std::shared_ptr<fs::pipe> ppipe{new fs::pipe};
  178. pipefd[0] = pimpl->place_new_file(
  179. std::make_shared<fifo_file>(file::file_flags{1, 0, 0}, ppipe), 0);
  180. pipefd[1] = pimpl->place_new_file(
  181. std::make_shared<fifo_file>(file::file_flags{0, 1, 0}, ppipe), 0);
  182. }
  183. return 0;
  184. }
  185. filearray::filearray(std::shared_ptr<impl> ptr) : pimpl{ptr} {}
  186. filearray::filearray(const fs_context* context)
  187. : filearray{std::make_shared<impl>()} {
  188. pimpl->context = context;
  189. }
  190. filearray filearray::copy() const {
  191. lock_guard lck{pimpl->mtx};
  192. filearray ret{pimpl->context};
  193. ret.pimpl->min_avail = pimpl->min_avail;
  194. ret.pimpl->arr = pimpl->arr;
  195. return ret;
  196. }
  197. filearray filearray::share() const {
  198. return filearray{pimpl};
  199. }
  200. void filearray::clear() {
  201. pimpl.reset();
  202. }
  203. void filearray::onexec() {
  204. lock_guard lck{pimpl->mtx};
  205. for (auto iter = pimpl->arr.begin(); iter;) {
  206. if (!(iter->flags & FD_CLOEXEC)) {
  207. ++iter;
  208. continue;
  209. }
  210. pimpl->release_fd(iter->fd);
  211. iter = pimpl->arr.erase(iter);
  212. }
  213. }
  214. file* filearray::operator[](int i) const {
  215. lock_guard lck{pimpl->mtx};
  216. auto iter = pimpl->arr.find(i);
  217. if (!iter)
  218. return nullptr;
  219. return iter->pfile.get();
  220. }