VirtualFileSystem.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  1. #include "VirtualFileSystem.h"
  2. #include <Kernel/FileSystem/FileDescriptor.h>
  3. #include "FileSystem.h"
  4. #include <AK/FileSystemPath.h>
  5. #include <AK/StringBuilder.h>
  6. #include <Kernel/Devices/CharacterDevice.h>
  7. #include <LibC/errno_numbers.h>
  8. #include <Kernel/Process.h>
  9. #include <Kernel/FileSystem/Custody.h>
  10. //#define VFS_DEBUG
  11. static VFS* s_the;
  12. VFS& VFS::the()
  13. {
  14. ASSERT(s_the);
  15. return *s_the;
  16. }
  17. VFS::VFS()
  18. {
  19. #ifdef VFS_DEBUG
  20. kprintf("VFS: Constructing VFS\n");
  21. #endif
  22. s_the = this;
  23. }
  24. VFS::~VFS()
  25. {
  26. }
  27. InodeIdentifier VFS::root_inode_id() const
  28. {
  29. ASSERT(m_root_inode);
  30. return m_root_inode->identifier();
  31. }
  32. bool VFS::mount(Retained<FS>&& file_system, StringView path)
  33. {
  34. auto result = resolve_path(path, root_custody());
  35. if (result.is_error()) {
  36. kprintf("VFS: mount can't resolve mount point '%s'\n", path.characters());
  37. return false;
  38. }
  39. auto& inode = result.value()->inode();
  40. kprintf("VFS: mounting %s{%p} at %s (inode: %u)\n", file_system->class_name(), file_system.ptr(), path.characters(), inode.index());
  41. // FIXME: check that this is not already a mount point
  42. auto mount = make<Mount>(*result.value(), move(file_system));
  43. m_mounts.append(move(mount));
  44. result.value()->did_mount_on({});
  45. return true;
  46. }
  47. bool VFS::mount_root(Retained<FS>&& file_system)
  48. {
  49. if (m_root_inode) {
  50. kprintf("VFS: mount_root can't mount another root\n");
  51. return false;
  52. }
  53. auto mount = make<Mount>(nullptr, move(file_system));
  54. auto root_inode_id = mount->guest().fs()->root_inode();
  55. auto root_inode = mount->guest().fs()->get_inode(root_inode_id);
  56. if (!root_inode->is_directory()) {
  57. kprintf("VFS: root inode (%02u:%08u) for / is not a directory :(\n", root_inode_id.fsid(), root_inode_id.index());
  58. return false;
  59. }
  60. m_root_inode = move(root_inode);
  61. kprintf("VFS: mounted root on %s{%p}\n",
  62. m_root_inode->fs().class_name(),
  63. &m_root_inode->fs());
  64. m_mounts.append(move(mount));
  65. return true;
  66. }
  67. auto VFS::find_mount_for_host(InodeIdentifier inode) -> Mount*
  68. {
  69. for (auto& mount : m_mounts) {
  70. if (mount->host() == inode)
  71. return mount.ptr();
  72. }
  73. return nullptr;
  74. }
  75. auto VFS::find_mount_for_guest(InodeIdentifier inode) -> Mount*
  76. {
  77. for (auto& mount : m_mounts) {
  78. if (mount->guest() == inode)
  79. return mount.ptr();
  80. }
  81. return nullptr;
  82. }
  83. bool VFS::is_vfs_root(InodeIdentifier inode) const
  84. {
  85. return inode == root_inode_id();
  86. }
  87. void VFS::traverse_directory_inode(Inode& dir_inode, Function<bool(const FS::DirectoryEntry&)> callback)
  88. {
  89. dir_inode.traverse_as_directory([&] (const FS::DirectoryEntry& entry) {
  90. InodeIdentifier resolved_inode;
  91. if (auto mount = find_mount_for_host(entry.inode))
  92. resolved_inode = mount->guest();
  93. else
  94. resolved_inode = entry.inode;
  95. if (dir_inode.identifier().is_root_inode() && !is_vfs_root(dir_inode.identifier()) && !strcmp(entry.name, "..")) {
  96. auto mount = find_mount_for_guest(entry.inode);
  97. ASSERT(mount);
  98. resolved_inode = mount->host();
  99. }
  100. callback(FS::DirectoryEntry(entry.name, entry.name_length, resolved_inode, entry.file_type));
  101. return true;
  102. });
  103. }
  104. KResult VFS::utime(StringView path, Custody& base, time_t atime, time_t mtime)
  105. {
  106. auto descriptor_or_error = VFS::the().open(move(path), 0, 0, base);
  107. if (descriptor_or_error.is_error())
  108. return descriptor_or_error.error();
  109. auto& inode = *descriptor_or_error.value()->inode();
  110. if (inode.fs().is_readonly())
  111. return KResult(-EROFS);
  112. if (inode.metadata().uid != current->process().euid())
  113. return KResult(-EACCES);
  114. int error = inode.set_atime(atime);
  115. if (error)
  116. return KResult(error);
  117. error = inode.set_mtime(mtime);
  118. if (error)
  119. return KResult(error);
  120. return KSuccess;
  121. }
  122. KResult VFS::stat(StringView path, int options, Custody& base, struct stat& statbuf)
  123. {
  124. auto custody_or_error = resolve_path(path, base, nullptr, options);
  125. if (custody_or_error.is_error())
  126. return custody_or_error.error();
  127. return custody_or_error.value()->inode().metadata().stat(statbuf);
  128. }
  129. KResultOr<Retained<FileDescriptor>> VFS::open(StringView path, int options, mode_t mode, Custody& base)
  130. {
  131. auto custody_or_error = resolve_path(path, base, nullptr, options);
  132. if (options & O_CREAT) {
  133. if (custody_or_error.is_error())
  134. return create(path, options, mode, base);
  135. if (options & O_EXCL)
  136. return KResult(-EEXIST);
  137. }
  138. if (custody_or_error.is_error())
  139. return custody_or_error.error();
  140. auto& custody = *custody_or_error.value();
  141. auto& inode = custody.inode();
  142. auto metadata = inode.metadata();
  143. bool should_truncate_file = false;
  144. // NOTE: Read permission is a bit weird, since O_RDONLY == 0,
  145. // so we check if (NOT write_only OR read_and_write)
  146. if (!(options & O_WRONLY) || (options & O_RDWR)) {
  147. if (!metadata.may_read(current->process()))
  148. return KResult(-EACCES);
  149. }
  150. if ((options & O_WRONLY) || (options & O_RDWR)) {
  151. if (!metadata.may_write(current->process()))
  152. return KResult(-EACCES);
  153. if (metadata.is_directory())
  154. return KResult(-EISDIR);
  155. should_truncate_file = options & O_TRUNC;
  156. }
  157. if (metadata.is_device()) {
  158. auto it = m_devices.find(encoded_device(metadata.major_device, metadata.minor_device));
  159. if (it == m_devices.end()) {
  160. return KResult(-ENODEV);
  161. }
  162. auto descriptor_or_error = (*it).value->open(options);
  163. if (descriptor_or_error.is_error())
  164. return descriptor_or_error.error();
  165. descriptor_or_error.value()->set_original_inode({}, inode);
  166. return descriptor_or_error;
  167. }
  168. if (should_truncate_file)
  169. inode.truncate(0);
  170. return FileDescriptor::create(custody);
  171. }
  172. KResult VFS::mknod(StringView path, mode_t mode, dev_t dev, Custody& base)
  173. {
  174. if (!is_regular_file(mode) && !is_block_device(mode) && !is_character_device(mode) && !is_fifo(mode) && !is_socket(mode))
  175. return KResult(-EINVAL);
  176. RetainPtr<Custody> parent_custody;
  177. auto existing_file_or_error = resolve_path(path, base, &parent_custody);
  178. if (!existing_file_or_error.is_error())
  179. return KResult(-EEXIST);
  180. if (!parent_custody)
  181. return KResult(-ENOENT);
  182. if (existing_file_or_error.error() != -ENOENT)
  183. return existing_file_or_error.error();
  184. auto& parent_inode = parent_custody->inode();
  185. if (!parent_inode.metadata().may_write(current->process()))
  186. return KResult(-EACCES);
  187. FileSystemPath p(path);
  188. dbgprintf("VFS::mknod: '%s' mode=%o dev=%u in %u:%u\n", p.basename().characters(), mode, dev, parent_inode.fsid(), parent_inode.index());
  189. int error;
  190. auto new_file = parent_inode.fs().create_inode(parent_inode.identifier(), p.basename(), mode, 0, dev, error);
  191. if (!new_file)
  192. return KResult(error);
  193. return KSuccess;
  194. }
  195. KResultOr<Retained<FileDescriptor>> VFS::create(StringView path, int options, mode_t mode, Custody& base)
  196. {
  197. (void)options;
  198. if (!is_socket(mode) && !is_fifo(mode) && !is_block_device(mode) && !is_character_device(mode)) {
  199. // Turn it into a regular file. (This feels rather hackish.)
  200. mode |= 0100000;
  201. }
  202. RetainPtr<Custody> parent_custody;
  203. auto existing_custody_or_error = resolve_path(path, base, &parent_custody);
  204. if (!existing_custody_or_error.is_error())
  205. return KResult(-EEXIST);
  206. if (!parent_custody)
  207. return KResult(-ENOENT);
  208. auto& parent_inode = parent_custody->inode();
  209. if (existing_custody_or_error.error() != -ENOENT)
  210. return existing_custody_or_error.error();
  211. if (!parent_inode.metadata().may_write(current->process()))
  212. return KResult(-EACCES);
  213. FileSystemPath p(path);
  214. dbgprintf("VFS::create_file: '%s' in %u:%u\n", p.basename().characters(), parent_inode.fsid(), parent_inode.index());
  215. int error;
  216. auto new_file = parent_inode.fs().create_inode(parent_inode.identifier(), p.basename(), mode, 0, 0, error);
  217. if (!new_file)
  218. return KResult(error);
  219. auto new_custody = Custody::create(parent_custody, p.basename(), *new_file);
  220. return FileDescriptor::create(*new_custody);
  221. }
  222. KResult VFS::mkdir(StringView path, mode_t mode, Custody& base)
  223. {
  224. RetainPtr<Custody> parent_custody;
  225. auto result = resolve_path(path, base, &parent_custody);
  226. if (!result.is_error())
  227. return KResult(-EEXIST);
  228. if (!parent_custody)
  229. return KResult(-ENOENT);
  230. if (result.error() != -ENOENT)
  231. return result.error();
  232. auto& parent_inode = parent_custody->inode();
  233. if (!parent_inode.metadata().may_write(current->process()))
  234. return KResult(-EACCES);
  235. FileSystemPath p(path);
  236. dbgprintf("VFS::mkdir: '%s' in %u:%u\n", p.basename().characters(), parent_inode.fsid(), parent_inode.index());
  237. int error;
  238. auto new_dir = parent_inode.fs().create_directory(parent_inode.identifier(), p.basename(), mode, error);
  239. if (new_dir)
  240. return KSuccess;
  241. return KResult(error);
  242. }
  243. KResult VFS::access(StringView path, int mode, Custody& base)
  244. {
  245. auto custody_or_error = resolve_path(path, base);
  246. if (custody_or_error.is_error())
  247. return custody_or_error.error();
  248. auto& custody = *custody_or_error.value();
  249. auto& inode = custody.inode();
  250. auto metadata = inode.metadata();
  251. if (mode & R_OK) {
  252. if (!metadata.may_read(current->process()))
  253. return KResult(-EACCES);
  254. }
  255. if (mode & W_OK) {
  256. if (!metadata.may_write(current->process()))
  257. return KResult(-EACCES);
  258. }
  259. if (mode & X_OK) {
  260. if (!metadata.may_execute(current->process()))
  261. return KResult(-EACCES);
  262. }
  263. return KSuccess;
  264. }
  265. KResultOr<Retained<Custody>> VFS::open_directory(StringView path, Custody& base)
  266. {
  267. auto inode_or_error = resolve_path(path, base);
  268. if (inode_or_error.is_error())
  269. return inode_or_error.error();
  270. auto& custody = *inode_or_error.value();
  271. auto& inode = custody.inode();
  272. if (!inode.is_directory())
  273. return KResult(-ENOTDIR);
  274. if (!inode.metadata().may_execute(current->process()))
  275. return KResult(-EACCES);
  276. return custody;
  277. }
  278. KResult VFS::chmod(Inode& inode, mode_t mode)
  279. {
  280. if (inode.fs().is_readonly())
  281. return KResult(-EROFS);
  282. if (current->process().euid() != inode.metadata().uid && !current->process().is_superuser())
  283. return KResult(-EPERM);
  284. // Only change the permission bits.
  285. mode = (inode.mode() & ~04777u) | (mode & 04777u);
  286. return inode.chmod(mode);
  287. }
  288. KResult VFS::chmod(StringView path, mode_t mode, Custody& base)
  289. {
  290. auto custody_or_error = resolve_path(path, base);
  291. if (custody_or_error.is_error())
  292. return custody_or_error.error();
  293. auto& custody = *custody_or_error.value();
  294. auto& inode = custody.inode();
  295. return chmod(inode, mode);
  296. }
  297. KResult VFS::rename(StringView old_path, StringView new_path, Custody& base)
  298. {
  299. RetainPtr<Custody> old_parent_custody;
  300. auto old_custody_or_error = resolve_path(old_path, base, &old_parent_custody);
  301. if (old_custody_or_error.is_error())
  302. return old_custody_or_error.error();
  303. auto& old_custody = *old_custody_or_error.value();
  304. auto& old_inode = old_custody.inode();
  305. RetainPtr<Custody> new_parent_custody;
  306. auto new_custody_or_error = resolve_path(new_path, base, &new_parent_custody);
  307. if (new_custody_or_error.is_error()) {
  308. if (new_custody_or_error.error() != -ENOENT)
  309. return new_custody_or_error.error();
  310. }
  311. auto& old_parent_inode = old_parent_custody->inode();
  312. auto& new_parent_inode = new_parent_custody->inode();
  313. if (!new_parent_inode.metadata().may_write(current->process()))
  314. return KResult(-EACCES);
  315. if (!old_parent_inode.metadata().may_write(current->process()))
  316. return KResult(-EACCES);
  317. if (old_parent_inode.metadata().is_sticky()) {
  318. if (!current->process().is_superuser() && old_inode.metadata().uid != current->process().euid())
  319. return KResult(-EACCES);
  320. }
  321. auto new_basename = FileSystemPath(new_path).basename();
  322. if (!new_custody_or_error.is_error()) {
  323. auto& new_custody = *new_custody_or_error.value();
  324. auto& new_inode = new_custody.inode();
  325. // FIXME: Is this really correct? Check what other systems do.
  326. if (&new_inode == &old_inode)
  327. return KSuccess;
  328. if (new_parent_inode.metadata().is_sticky()) {
  329. if (!current->process().is_superuser() && new_inode.metadata().uid != current->process().euid())
  330. return KResult(-EACCES);
  331. }
  332. if (new_inode.is_directory() && !old_inode.is_directory())
  333. return KResult(-EISDIR);
  334. auto result = new_parent_inode.remove_child(new_basename);
  335. if (result.is_error())
  336. return result;
  337. new_custody.did_delete({});
  338. }
  339. auto result = new_parent_inode.add_child(old_inode.identifier(), new_basename, old_inode.mode());
  340. if (result.is_error())
  341. return result;
  342. result = old_parent_inode.remove_child(FileSystemPath(old_path).basename());
  343. if (result.is_error())
  344. return result;
  345. old_custody.did_rename({}, new_basename);
  346. return KSuccess;
  347. }
  348. KResult VFS::chown(Inode& inode, uid_t a_uid, gid_t a_gid)
  349. {
  350. if (inode.fs().is_readonly())
  351. return KResult(-EROFS);
  352. auto metadata = inode.metadata();
  353. if (current->process().euid() != metadata.uid && !current->process().is_superuser())
  354. return KResult(-EPERM);
  355. uid_t new_uid = metadata.uid;
  356. gid_t new_gid = metadata.gid;
  357. if (a_uid != (uid_t)-1) {
  358. if (current->process().euid() != a_uid && !current->process().is_superuser())
  359. return KResult(-EPERM);
  360. new_uid = a_uid;
  361. }
  362. if (a_gid != (gid_t)-1) {
  363. if (!current->process().in_group(a_gid) && !current->process().is_superuser())
  364. return KResult(-EPERM);
  365. new_gid = a_gid;
  366. }
  367. dbgprintf("VFS::chown(): inode %u:%u <- uid:%d, gid:%d\n", inode.fsid(), inode.index(), new_uid, new_gid);
  368. return inode.chown(new_uid, new_gid);
  369. }
  370. KResult VFS::chown(StringView path, uid_t a_uid, gid_t a_gid, Custody& base)
  371. {
  372. auto custody_or_error = resolve_path(path, base);
  373. if (custody_or_error.is_error())
  374. return custody_or_error.error();
  375. auto& custody = *custody_or_error.value();
  376. auto& inode = custody.inode();
  377. return chown(inode, a_uid, a_gid);
  378. }
  379. KResult VFS::link(StringView old_path, StringView new_path, Custody& base)
  380. {
  381. auto old_custody_or_error = resolve_path(old_path, base);
  382. if (old_custody_or_error.is_error())
  383. return old_custody_or_error.error();
  384. auto& old_custody = *old_custody_or_error.value();
  385. auto& old_inode = old_custody.inode();
  386. RetainPtr<Custody> parent_custody;
  387. auto new_custody_or_error = resolve_path(new_path, base, &parent_custody);
  388. if (!new_custody_or_error.is_error())
  389. return KResult(-EEXIST);
  390. if (!parent_custody)
  391. return KResult(-ENOENT);
  392. auto& parent_inode = parent_custody->inode();
  393. if (parent_inode.fsid() != old_inode.fsid())
  394. return KResult(-EXDEV);
  395. if (parent_inode.fs().is_readonly())
  396. return KResult(-EROFS);
  397. if (!parent_inode.metadata().may_write(current->process()))
  398. return KResult(-EACCES);
  399. return parent_inode.add_child(old_inode.identifier(), FileSystemPath(new_path).basename(), old_inode.mode());
  400. }
  401. KResult VFS::unlink(StringView path, Custody& base)
  402. {
  403. RetainPtr<Custody> parent_custody;
  404. auto custody_or_error = resolve_path(path, base, &parent_custody);
  405. if (custody_or_error.is_error())
  406. return custody_or_error.error();
  407. auto& custody = *custody_or_error.value();
  408. auto& inode = custody.inode();
  409. if (inode.is_directory())
  410. return KResult(-EISDIR);
  411. auto& parent_inode = parent_custody->inode();
  412. if (!parent_inode.metadata().may_write(current->process()))
  413. return KResult(-EACCES);
  414. if (parent_inode.metadata().is_sticky()) {
  415. if (!current->process().is_superuser() && inode.metadata().uid != current->process().euid())
  416. return KResult(-EACCES);
  417. }
  418. auto result = parent_inode.remove_child(FileSystemPath(path).basename());
  419. if (result.is_error())
  420. return result;
  421. custody.did_delete({});
  422. return KSuccess;
  423. }
  424. KResult VFS::symlink(StringView target, StringView linkpath, Custody& base)
  425. {
  426. RetainPtr<Custody> parent_custody;
  427. auto existing_custody_or_error = resolve_path(linkpath, base, &parent_custody);
  428. if (!existing_custody_or_error.is_error())
  429. return KResult(-EEXIST);
  430. if (!parent_custody)
  431. return KResult(-ENOENT);
  432. if (existing_custody_or_error.error() != -ENOENT)
  433. return existing_custody_or_error.error();
  434. auto& parent_inode = parent_custody->inode();
  435. if (!parent_inode.metadata().may_write(current->process()))
  436. return KResult(-EACCES);
  437. FileSystemPath p(linkpath);
  438. dbgprintf("VFS::symlink: '%s' (-> '%s') in %u:%u\n", p.basename().characters(), target.characters(), parent_inode.fsid(), parent_inode.index());
  439. int error;
  440. auto new_file = parent_inode.fs().create_inode(parent_inode.identifier(), p.basename(), 0120644, 0, 0, error);
  441. if (!new_file)
  442. return KResult(error);
  443. ssize_t nwritten = new_file->write_bytes(0, target.length(), (const byte*)target.characters(), nullptr);
  444. if (nwritten < 0)
  445. return KResult(nwritten);
  446. return KSuccess;
  447. }
  448. KResult VFS::rmdir(StringView path, Custody& base)
  449. {
  450. RetainPtr<Custody> parent_custody;
  451. auto custody_or_error = resolve_path(path, base, &parent_custody);
  452. if (custody_or_error.is_error())
  453. return KResult(custody_or_error.error());
  454. auto& custody = *custody_or_error.value();
  455. auto& inode = custody.inode();
  456. if (inode.fs().is_readonly())
  457. return KResult(-EROFS);
  458. // FIXME: We should return EINVAL if the last component of the path is "."
  459. // FIXME: We should return ENOTEMPTY if the last component of the path is ".."
  460. if (!inode.is_directory())
  461. return KResult(-ENOTDIR);
  462. auto& parent_inode = parent_custody->inode();
  463. if (!parent_inode.metadata().may_write(current->process()))
  464. return KResult(-EACCES);
  465. if (inode.directory_entry_count() != 2)
  466. return KResult(-ENOTEMPTY);
  467. auto result = inode.remove_child(".");
  468. if (result.is_error())
  469. return result;
  470. result = inode.remove_child("..");
  471. if (result.is_error())
  472. return result;
  473. return parent_inode.remove_child(FileSystemPath(path).basename());
  474. }
  475. RetainPtr<Inode> VFS::get_inode(InodeIdentifier inode_id)
  476. {
  477. if (!inode_id.is_valid())
  478. return nullptr;
  479. return inode_id.fs()->get_inode(inode_id);
  480. }
  481. VFS::Mount::Mount(RetainPtr<Custody>&& host_custody, Retained<FS>&& guest_fs)
  482. : m_guest(guest_fs->root_inode())
  483. , m_guest_fs(move(guest_fs))
  484. , m_host_custody(move(host_custody))
  485. {
  486. }
  487. String VFS::Mount::absolute_path() const
  488. {
  489. if (!m_host_custody)
  490. return "/";
  491. return m_host_custody->absolute_path();
  492. }
  493. InodeIdentifier VFS::Mount::host() const
  494. {
  495. if (!m_host_custody)
  496. return { };
  497. return m_host_custody->inode().identifier();
  498. }
  499. void VFS::register_device(Badge<Device>, Device& device)
  500. {
  501. m_devices.set(encoded_device(device.major(), device.minor()), &device);
  502. }
  503. void VFS::unregister_device(Badge<Device>, Device& device)
  504. {
  505. m_devices.remove(encoded_device(device.major(), device.minor()));
  506. }
  507. Device* VFS::get_device(unsigned major, unsigned minor)
  508. {
  509. auto it = m_devices.find(encoded_device(major, minor));
  510. if (it == m_devices.end())
  511. return nullptr;
  512. return (*it).value;
  513. }
  514. void VFS::for_each_mount(Function<void(const Mount&)> callback) const
  515. {
  516. for (auto& mount : m_mounts) {
  517. callback(*mount);
  518. }
  519. }
  520. void VFS::sync()
  521. {
  522. FS::sync();
  523. }
  524. Custody& VFS::root_custody()
  525. {
  526. if (!m_root_custody)
  527. m_root_custody = Custody::create(nullptr, "", *m_root_inode);
  528. return *m_root_custody;
  529. }
  530. KResultOr<Retained<Custody>> VFS::resolve_path(StringView path, Custody& base, RetainPtr<Custody>* parent_custody, int options)
  531. {
  532. if (path.is_empty())
  533. return KResult(-EINVAL);
  534. auto parts = path.split_view('/');
  535. InodeIdentifier crumb_id;
  536. Vector<Retained<Custody>, 32> custody_chain;
  537. if (path[0] == '/') {
  538. custody_chain.append(root_custody());
  539. crumb_id = root_inode_id();
  540. } else {
  541. for (auto* custody = &base; custody; custody = custody->parent()) {
  542. // FIXME: Prepending here is not efficient! Fix this.
  543. custody_chain.prepend(*custody);
  544. }
  545. crumb_id = base.inode().identifier();
  546. }
  547. if (parent_custody)
  548. *parent_custody = custody_chain.last();
  549. for (int i = 0; i < parts.size(); ++i) {
  550. bool inode_was_root_at_head_of_loop = crumb_id.is_root_inode();
  551. auto& part = parts[i];
  552. if (part.is_empty())
  553. break;
  554. auto crumb_inode = get_inode(crumb_id);
  555. if (!crumb_inode)
  556. return KResult(-EIO);
  557. auto metadata = crumb_inode->metadata();
  558. if (!metadata.is_directory())
  559. return KResult(-ENOTDIR);
  560. if (!metadata.may_execute(current->process()))
  561. return KResult(-EACCES);
  562. auto current_parent = custody_chain.last();
  563. crumb_id = crumb_inode->lookup(part);
  564. if (!crumb_id.is_valid())
  565. return KResult(-ENOENT);
  566. if (auto mount = find_mount_for_host(crumb_id))
  567. crumb_id = mount->guest();
  568. if (inode_was_root_at_head_of_loop && crumb_id.is_root_inode() && !is_vfs_root(crumb_id) && part == "..") {
  569. auto mount = find_mount_for_guest(crumb_id);
  570. auto dir_inode = get_inode(mount->host());
  571. ASSERT(dir_inode);
  572. crumb_id = dir_inode->lookup("..");
  573. }
  574. crumb_inode = get_inode(crumb_id);
  575. ASSERT(crumb_inode);
  576. custody_chain.append(Custody::get_or_create(custody_chain.last().ptr(), part, *crumb_inode));
  577. metadata = crumb_inode->metadata();
  578. if (metadata.is_directory()) {
  579. if (i != parts.size() - 1) {
  580. if (parent_custody)
  581. *parent_custody = custody_chain.last();
  582. }
  583. }
  584. if (metadata.is_symlink()) {
  585. if (i == parts.size() - 1) {
  586. if (options & O_NOFOLLOW)
  587. return KResult(-ELOOP);
  588. if (options & O_NOFOLLOW_NOERROR)
  589. return custody_chain.last();
  590. }
  591. auto symlink_contents = crumb_inode->read_entire();
  592. if (!symlink_contents)
  593. return KResult(-ENOENT);
  594. // FIXME: We should limit the recursion here and return -ELOOP if it goes to deep.
  595. return resolve_path(
  596. StringView(symlink_contents.pointer(),
  597. symlink_contents.size()),
  598. *current_parent,
  599. parent_custody,
  600. options
  601. );
  602. }
  603. }
  604. return custody_chain.last();
  605. }