VirtualFileSystem.cpp 13 KB

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