VirtualFileSystem.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. #include "VirtualFileSystem.h"
  2. #include "FileHandle.h"
  3. #include "FileSystem.h"
  4. #include <AK/kmalloc.h>
  5. #include <AK/kstdio.h>
  6. #include <AK/ktime.h>
  7. //#define VFS_DEBUG
  8. static dword encodedDevice(unsigned major, unsigned minor)
  9. {
  10. return (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12);
  11. }
  12. static VirtualFileSystem* s_the;
  13. VirtualFileSystem& VirtualFileSystem::the()
  14. {
  15. ASSERT(s_the);
  16. return *s_the;
  17. }
  18. static SpinLock* s_vfsLock;
  19. SpinLock& VirtualFileSystem::lock()
  20. {
  21. ASSERT(s_vfsLock);
  22. return *s_vfsLock;
  23. }
  24. void VirtualFileSystem::initializeGlobals()
  25. {
  26. s_the = nullptr;
  27. s_vfsLock = new SpinLock;
  28. FileSystem::initializeGlobals();
  29. }
  30. VirtualFileSystem::VirtualFileSystem()
  31. {
  32. #ifdef VFS_DEBUG
  33. kprintf("[VFS] Constructing VFS\n");
  34. #endif
  35. s_the = this;
  36. m_maxNodeCount = 16;
  37. m_nodes = reinterpret_cast<Node*>(kmalloc(sizeof(Node) * maxNodeCount()));
  38. memset(m_nodes, 0, sizeof(Node) * maxNodeCount());
  39. for (unsigned i = 0; i < m_maxNodeCount; ++i)
  40. m_nodeFreeList.append(&m_nodes[i]);
  41. }
  42. VirtualFileSystem::~VirtualFileSystem()
  43. {
  44. kprintf("[VFS] ~VirtualFileSystem with %u nodes allocated\n", allocatedNodeCount());
  45. }
  46. auto VirtualFileSystem::makeNode(InodeIdentifier inode) -> RetainPtr<Node>
  47. {
  48. auto metadata = inode.metadata();
  49. if (!metadata.isValid())
  50. return nullptr;
  51. CharacterDevice* characterDevice = nullptr;
  52. if (metadata.isCharacterDevice()) {
  53. auto it = m_characterDevices.find(encodedDevice(metadata.majorDevice, metadata.minorDevice));
  54. if (it != m_characterDevices.end()) {
  55. characterDevice = (*it).value;
  56. } else {
  57. kprintf("[VFS] makeNode() no such character device %u,%u\n", metadata.majorDevice, metadata.minorDevice);
  58. return nullptr;
  59. }
  60. }
  61. auto vnode = allocateNode();
  62. ASSERT(vnode);
  63. FileSystem* fileSystem = inode.fileSystem();
  64. fileSystem->retain();
  65. vnode->inode = inode;
  66. vnode->m_cachedMetadata = { };
  67. #ifdef VFS_DEBUG
  68. kprintf("makeNode: inode=%u, size=%u, mode=%o, uid=%u, gid=%u\n", inode.index(), metadata.size, metadata.mode, metadata.uid, metadata.gid);
  69. #endif
  70. m_inode2vnode.set(inode, vnode.ptr());
  71. vnode->m_characterDevice = characterDevice;
  72. return vnode;
  73. }
  74. auto VirtualFileSystem::getOrCreateNode(InodeIdentifier inode) -> RetainPtr<Node>
  75. {
  76. auto it = m_inode2vnode.find(inode);
  77. if (it != m_inode2vnode.end())
  78. return (*it).value;
  79. return makeNode(inode);
  80. }
  81. bool VirtualFileSystem::mount(RetainPtr<FileSystem>&& fileSystem, const String& path)
  82. {
  83. ASSERT(fileSystem);
  84. auto inode = resolvePath(path);
  85. if (!inode.isValid()) {
  86. kprintf("[VFS] mount can't resolve mount point '%s'\n", path.characters());
  87. return false;
  88. }
  89. kprintf("mounting %s{%p} at %s (inode: %u)\n", fileSystem->className(), fileSystem.ptr(), path.characters(), inode.index());
  90. // FIXME: check that this is not already a mount point
  91. auto mount = make<Mount>(inode, move(fileSystem));
  92. m_mounts.append(move(mount));
  93. return true;
  94. }
  95. bool VirtualFileSystem::mountRoot(RetainPtr<FileSystem>&& fileSystem)
  96. {
  97. if (m_rootNode) {
  98. kprintf("[VFS] mountRoot can't mount another root\n");
  99. return false;
  100. }
  101. auto mount = make<Mount>(InodeIdentifier(), move(fileSystem));
  102. auto node = makeNode(mount->guest());
  103. if (!node->inUse()) {
  104. kprintf("[VFS] root inode for / is not in use :(\n");
  105. return false;
  106. }
  107. if (!node->inode.metadata().isDirectory()) {
  108. kprintf("[VFS] root inode for / is not in use :(\n");
  109. return false;
  110. }
  111. m_rootNode = move(node);
  112. kprintf("[VFS] mountRoot mounted %s{%p}\n",
  113. m_rootNode->fileSystem()->className(),
  114. m_rootNode->fileSystem());
  115. m_mounts.append(move(mount));
  116. return true;
  117. }
  118. auto VirtualFileSystem::allocateNode() -> RetainPtr<Node>
  119. {
  120. if (m_nodeFreeList.isEmpty()) {
  121. kprintf("[VFS] allocateNode has no nodes left\n");
  122. return nullptr;
  123. }
  124. auto* node = m_nodeFreeList.takeLast();
  125. ASSERT(node->retainCount == 0);
  126. node->retainCount = 1;
  127. node->m_vfs = this;
  128. return adopt(*node);
  129. }
  130. void VirtualFileSystem::freeNode(Node* node)
  131. {
  132. ASSERT(node);
  133. ASSERT(node->inUse());
  134. m_inode2vnode.remove(node->inode);
  135. node->inode.fileSystem()->release();
  136. node->inode = InodeIdentifier();
  137. node->m_characterDevice = nullptr;
  138. m_nodeFreeList.append(move(node));
  139. }
  140. bool VirtualFileSystem::isDirectory(const String& path)
  141. {
  142. auto inode = resolvePath(path);
  143. if (!inode.isValid())
  144. return false;
  145. return inode.metadata().isDirectory();
  146. }
  147. auto VirtualFileSystem::findMountForHost(InodeIdentifier inode) -> Mount*
  148. {
  149. for (auto& mount : m_mounts) {
  150. if (mount->host() == inode)
  151. return mount.ptr();
  152. }
  153. return nullptr;
  154. }
  155. auto VirtualFileSystem::findMountForGuest(InodeIdentifier inode) -> Mount*
  156. {
  157. for (auto& mount : m_mounts) {
  158. if (mount->guest() == inode)
  159. return mount.ptr();
  160. }
  161. return nullptr;
  162. }
  163. bool VirtualFileSystem::isRoot(InodeIdentifier inode) const
  164. {
  165. return inode == m_rootNode->inode;
  166. }
  167. void VirtualFileSystem::enumerateDirectoryInode(InodeIdentifier directoryInode, Function<bool(const FileSystem::DirectoryEntry&)> callback)
  168. {
  169. if (!directoryInode.isValid())
  170. return;
  171. directoryInode.fileSystem()->enumerateDirectoryInode(directoryInode, [&] (const FileSystem::DirectoryEntry& entry) {
  172. InodeIdentifier resolvedInode;
  173. if (auto mount = findMountForHost(entry.inode))
  174. resolvedInode = mount->guest();
  175. else
  176. resolvedInode = entry.inode;
  177. if (directoryInode.isRootInode() && !isRoot(directoryInode) && entry.name == "..") {
  178. auto mount = findMountForGuest(entry.inode);
  179. ASSERT(mount);
  180. resolvedInode = mount->host();
  181. }
  182. callback({ entry.name, resolvedInode });
  183. return true;
  184. });
  185. }
  186. void VirtualFileSystem::listDirectory(const String& path)
  187. {
  188. auto directoryInode = resolvePath(path);
  189. if (!directoryInode.isValid())
  190. return;
  191. kprintf("[VFS] ls %s -> %s %02u:%08u\n", path.characters(), directoryInode.fileSystem()->className(), directoryInode.fileSystemID(), directoryInode.index());
  192. enumerateDirectoryInode(directoryInode, [&] (const FileSystem::DirectoryEntry& entry) {
  193. const char* nameColorBegin = "";
  194. const char* nameColorEnd = "";
  195. auto metadata = entry.inode.metadata();
  196. ASSERT(metadata.isValid());
  197. if (metadata.isDirectory()) {
  198. nameColorBegin = "\033[34;1m";
  199. nameColorEnd = "\033[0m";
  200. } else if (metadata.isSymbolicLink()) {
  201. nameColorBegin = "\033[36;1m";
  202. nameColorEnd = "\033[0m";
  203. }
  204. if (metadata.isSticky()) {
  205. nameColorBegin = "\033[42;30m";
  206. nameColorEnd = "\033[0m";
  207. }
  208. if (metadata.isCharacterDevice() || metadata.isBlockDevice()) {
  209. nameColorBegin = "\033[33;1m";
  210. nameColorEnd = "\033[0m";
  211. }
  212. kprintf("%02u:%08u ",
  213. metadata.inode.fileSystemID(),
  214. metadata.inode.index());
  215. if (metadata.isDirectory())
  216. kprintf("d");
  217. else if (metadata.isSymbolicLink())
  218. kprintf("l");
  219. else if (metadata.isBlockDevice())
  220. kprintf("b");
  221. else if (metadata.isCharacterDevice())
  222. kprintf("c");
  223. else if (metadata.isSocket())
  224. kprintf("s");
  225. else if (metadata.isFIFO())
  226. kprintf("f");
  227. else if (metadata.isRegularFile())
  228. kprintf("-");
  229. else
  230. kprintf("?");
  231. kprintf("%c%c%c%c%c%c%c%c",
  232. metadata.mode & 00400 ? 'r' : '-',
  233. metadata.mode & 00200 ? 'w' : '-',
  234. metadata.mode & 00100 ? 'x' : '-',
  235. metadata.mode & 00040 ? 'r' : '-',
  236. metadata.mode & 00020 ? 'w' : '-',
  237. metadata.mode & 00010 ? 'x' : '-',
  238. metadata.mode & 00004 ? 'r' : '-',
  239. metadata.mode & 00002 ? 'w' : '-'
  240. );
  241. if (metadata.isSticky())
  242. kprintf("t");
  243. else
  244. kprintf("%c", metadata.mode & 00001 ? 'x' : '-');
  245. if (metadata.isCharacterDevice() || metadata.isBlockDevice()) {
  246. char buf[16];
  247. ksprintf(buf, "%u, %u", metadata.majorDevice, metadata.minorDevice);
  248. kprintf("%12s ", buf);
  249. } else {
  250. kprintf("%12lld ", metadata.size);
  251. }
  252. kprintf("\033[30;1m");
  253. time_t mtime = metadata.mtime;
  254. auto tm = *klocaltime(&mtime);
  255. kprintf("%04u-%02u-%02u %02u:%02u:%02u ",
  256. tm.tm_year + 1900,
  257. tm.tm_mon + 1,
  258. tm.tm_mday,
  259. tm.tm_hour,
  260. tm.tm_min,
  261. tm.tm_sec);
  262. kprintf("\033[0m");
  263. kprintf("%s%s%s",
  264. nameColorBegin,
  265. entry.name.characters(),
  266. nameColorEnd);
  267. if (metadata.isDirectory()) {
  268. kprintf("/");
  269. } else if (metadata.isSymbolicLink()) {
  270. auto symlinkContents = directoryInode.fileSystem()->readEntireInode(metadata.inode);
  271. kprintf(" -> %s", String((const char*)symlinkContents.pointer(), symlinkContents.size()).characters());
  272. }
  273. kprintf("\n");
  274. return true;
  275. });
  276. }
  277. void VirtualFileSystem::listDirectoryRecursively(const String& path)
  278. {
  279. auto directory = resolvePath(path);
  280. if (!directory.isValid())
  281. return;
  282. kprintf("%s\n", path.characters());
  283. enumerateDirectoryInode(directory, [&] (const FileSystem::DirectoryEntry& entry) {
  284. auto metadata = entry.inode.metadata();
  285. if (metadata.isDirectory()) {
  286. if (entry.name != "." && entry.name != "..") {
  287. char buf[4096];
  288. ksprintf(buf, "%s/%s", path.characters(), entry.name.characters());
  289. listDirectoryRecursively(buf);
  290. }
  291. } else {
  292. kprintf("%s/%s\n", path.characters(), entry.name.characters());
  293. }
  294. return true;
  295. });
  296. }
  297. bool VirtualFileSystem::touch(const String& path)
  298. {
  299. Locker locker(VirtualFileSystem::lock());
  300. auto inode = resolvePath(path);
  301. if (!inode.isValid())
  302. return false;
  303. return inode.fileSystem()->setModificationTime(inode, ktime(nullptr));
  304. }
  305. OwnPtr<FileHandle> VirtualFileSystem::open(const String& path)
  306. {
  307. Locker locker(VirtualFileSystem::lock());
  308. auto inode = resolvePath(path);
  309. if (!inode.isValid())
  310. return nullptr;
  311. auto vnode = getOrCreateNode(inode);
  312. if (!vnode)
  313. return nullptr;
  314. return make<FileHandle>(move(vnode));
  315. }
  316. OwnPtr<FileHandle> VirtualFileSystem::create(const String& path)
  317. {
  318. Locker locker(VirtualFileSystem::lock());
  319. // FIXME: Do the real thing, not just this fake thing!
  320. (void) path;
  321. m_rootNode->fileSystem()->createInode(m_rootNode->fileSystem()->rootInode(), "empty", 0100644, 0);
  322. return nullptr;
  323. }
  324. OwnPtr<FileHandle> VirtualFileSystem::mkdir(const String& path)
  325. {
  326. Locker locker(VirtualFileSystem::lock());
  327. // FIXME: Do the real thing, not just this fake thing!
  328. (void) path;
  329. m_rootNode->fileSystem()->makeDirectory(m_rootNode->fileSystem()->rootInode(), "mydir", 0400755);
  330. return nullptr;
  331. }
  332. InodeIdentifier VirtualFileSystem::resolveSymbolicLink(const String& basePath, InodeIdentifier symlinkInode)
  333. {
  334. auto symlinkContents = symlinkInode.readEntireFile();
  335. if (!symlinkContents)
  336. return { };
  337. char buf[4096];
  338. ksprintf(buf, "/%s/%s", basePath.characters(), String((const char*)symlinkContents.pointer(), symlinkContents.size()).characters());
  339. return resolvePath(buf);
  340. }
  341. InodeIdentifier VirtualFileSystem::resolvePath(const String& path)
  342. {
  343. auto parts = path.split('/');
  344. InodeIdentifier inode = m_rootNode->inode;
  345. for (unsigned i = 0; i < parts.size(); ++i) {
  346. auto& part = parts[i];
  347. auto metadata = inode.metadata();
  348. if (!metadata.isValid()) {
  349. #ifdef VFS_DEBUG
  350. kprintf("invalid metadata\n");
  351. #endif
  352. return InodeIdentifier();
  353. }
  354. if (!metadata.isDirectory()) {
  355. #ifdef VFS_DEBUG
  356. kprintf("not directory\n");
  357. #endif
  358. return InodeIdentifier();
  359. }
  360. inode = inode.fileSystem()->childOfDirectoryInodeWithName(inode, part);
  361. if (!inode.isValid()) {
  362. #ifdef VFS_DEBUG
  363. kprintf("bad child\n");
  364. #endif
  365. return InodeIdentifier();
  366. }
  367. #ifdef VFS_DEBUG
  368. kprintf("<%s> %02u:%08u\n", part.characters(), inode.fileSystemID(), inode.index());
  369. #endif
  370. if (auto mount = findMountForHost(inode)) {
  371. #ifdef VFS_DEBUG
  372. kprintf(" -- is host\n");
  373. #endif
  374. inode = mount->guest();
  375. }
  376. if (inode.isRootInode() && !isRoot(inode) && part == "..") {
  377. #ifdef VFS_DEBUG
  378. kprintf(" -- is guest\n");
  379. #endif
  380. auto mount = findMountForGuest(inode);
  381. inode = mount->host();
  382. inode = inode.fileSystem()->childOfDirectoryInodeWithName(inode, "..");
  383. }
  384. metadata = inode.metadata();
  385. if (metadata.isSymbolicLink()) {
  386. char buf[4096] = "";
  387. char* p = buf;
  388. for (unsigned j = 0; j < i; ++j) {
  389. p += ksprintf(p, "/%s", parts[j].characters());
  390. }
  391. inode = resolveSymbolicLink(buf, inode);
  392. if (!inode.isValid()) {
  393. kprintf("Symbolic link resolution failed :(\n");
  394. return { };
  395. }
  396. }
  397. }
  398. return inode;
  399. }
  400. void VirtualFileSystem::Node::retain()
  401. {
  402. ++retainCount;
  403. }
  404. void VirtualFileSystem::Node::release()
  405. {
  406. ASSERT(retainCount);
  407. if (--retainCount == 0) {
  408. m_vfs->freeNode(this);
  409. }
  410. }
  411. const InodeMetadata& VirtualFileSystem::Node::metadata() const
  412. {
  413. if (!m_cachedMetadata.isValid())
  414. m_cachedMetadata = inode.metadata();
  415. return m_cachedMetadata;
  416. }
  417. VirtualFileSystem::Mount::Mount(InodeIdentifier host, RetainPtr<FileSystem>&& guestFileSystem)
  418. : m_host(host)
  419. , m_guest(guestFileSystem->rootInode())
  420. , m_fileSystem(move(guestFileSystem))
  421. {
  422. }
  423. void VirtualFileSystem::registerCharacterDevice(unsigned major, unsigned minor, CharacterDevice& device)
  424. {
  425. m_characterDevices.set(encodedDevice(major, minor), &device);
  426. }