VirtualFileSystem.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. #include "VirtualFileSystem.h"
  2. #include "FileHandle.h"
  3. #include "FileSystem.h"
  4. #include <AK/kmalloc.h>
  5. #include <cstdio>
  6. #include <cstdlib>
  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. printf("[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. printf("[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. printf("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. printf("[VFS] mount can't resolve mount point '%s'\n", path.characters());
  64. return false;
  65. }
  66. printf("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, std::move(fileSystem));
  69. m_mounts.append(std::move(mount));
  70. return true;
  71. }
  72. bool VirtualFileSystem::mountRoot(RetainPtr<FileSystem>&& fileSystem)
  73. {
  74. if (m_rootNode) {
  75. printf("[VFS] mountRoot can't mount another root\n");
  76. return false;
  77. }
  78. auto mount = make<Mount>(InodeIdentifier(), std::move(fileSystem));
  79. auto node = makeNode(mount->guest());
  80. if (!node->inUse()) {
  81. printf("[VFS] root inode for / is not in use :(\n");
  82. return false;
  83. }
  84. if (!node->inode.metadata().isDirectory()) {
  85. printf("[VFS] root inode for / is not in use :(\n");
  86. return false;
  87. }
  88. m_rootNode = std::move(node);
  89. printf("[VFS] mountRoot mounted %s{%p}\n",
  90. m_rootNode->fileSystem()->className(),
  91. m_rootNode->fileSystem());
  92. m_mounts.append(std::move(mount));
  93. return true;
  94. }
  95. auto VirtualFileSystem::allocateNode() -> RetainPtr<Node>
  96. {
  97. if (m_nodeFreeList.isEmpty()) {
  98. printf("[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(std::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. printf("[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. printf("%02u:%08u ",
  191. metadata.inode.fileSystemID(),
  192. metadata.inode.index());
  193. if (metadata.isDirectory())
  194. printf("d");
  195. else if (metadata.isSymbolicLink())
  196. printf("l");
  197. else if (metadata.isBlockDevice())
  198. printf("b");
  199. else if (metadata.isCharacterDevice())
  200. printf("c");
  201. else if (metadata.isSocket())
  202. printf("s");
  203. else if (metadata.isFIFO())
  204. printf("f");
  205. else if (metadata.isRegularFile())
  206. printf("-");
  207. else
  208. printf("?");
  209. printf("%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. printf("t");
  221. else
  222. printf("%c", metadata.mode & 00001 ? 'x' : '-');
  223. if (metadata.isCharacterDevice() || metadata.isBlockDevice()) {
  224. char buf[16];
  225. sprintf(buf, "%u, %u", metadata.majorDevice, metadata.minorDevice);
  226. printf("%12s ", buf);
  227. } else {
  228. printf("%12lld ", metadata.size);
  229. }
  230. printf("\033[30;1m");
  231. auto tm = *localtime(&metadata.mtime);
  232. printf("%04u-%02u-%02u %02u:%02u:%02u ",
  233. tm.tm_year + 1900,
  234. tm.tm_mon + 1,
  235. tm.tm_mday,
  236. tm.tm_hour,
  237. tm.tm_min,
  238. tm.tm_sec);
  239. printf("\033[0m");
  240. printf("%s%s%s",
  241. nameColorBegin,
  242. entry.name.characters(),
  243. nameColorEnd);
  244. if (metadata.isDirectory()) {
  245. printf("/");
  246. } else if (metadata.isSymbolicLink()) {
  247. auto symlinkContents = directoryInode.fileSystem()->readEntireInode(metadata.inode);
  248. printf(" -> %s", String((const char*)symlinkContents.pointer(), symlinkContents.size()).characters());
  249. }
  250. printf("\n");
  251. return true;
  252. });
  253. }
  254. void VirtualFileSystem::listDirectoryRecursively(const String& path)
  255. {
  256. auto directory = resolvePath(path);
  257. if (!directory.isValid())
  258. return;
  259. printf("%s\n", path.characters());
  260. enumerateDirectoryInode(directory, [&] (const FileSystem::DirectoryEntry& entry) {
  261. auto metadata = entry.inode.metadata();
  262. if (metadata.isDirectory()) {
  263. if (entry.name != "." && entry.name != "..") {
  264. char buf[4096];
  265. sprintf(buf, "%s/%s", path.characters(), entry.name.characters());
  266. listDirectoryRecursively(buf);
  267. }
  268. } else {
  269. printf("%s/%s\n", path.characters(), entry.name.characters());
  270. }
  271. });
  272. }
  273. bool VirtualFileSystem::touch(const String& path)
  274. {
  275. auto inode = resolvePath(path);
  276. if (!inode.isValid())
  277. return false;
  278. return inode.fileSystem()->setModificationTime(inode, time(nullptr));
  279. }
  280. OwnPtr<FileHandle> VirtualFileSystem::open(const String& path)
  281. {
  282. auto inode = resolvePath(path);
  283. if (!inode.isValid())
  284. return nullptr;
  285. auto vnode = getOrCreateNode(inode);
  286. if (!vnode)
  287. return nullptr;
  288. return make<FileHandle>(std::move(vnode));
  289. }
  290. OwnPtr<FileHandle> VirtualFileSystem::create(const String& path)
  291. {
  292. // FIXME: Do the real thing, not just this fake thing!
  293. m_rootNode->fileSystem()->createInode(m_rootNode->fileSystem()->rootInode(), "empty", 0100644);
  294. return nullptr;
  295. }
  296. InodeIdentifier VirtualFileSystem::resolveSymbolicLink(const String& basePath, InodeIdentifier symlinkInode)
  297. {
  298. auto symlinkContents = symlinkInode.readEntireFile();
  299. if (!symlinkContents)
  300. return { };
  301. char buf[4096];
  302. sprintf(buf, "/%s/%s", basePath.characters(), String((const char*)symlinkContents.pointer(), symlinkContents.size()).characters());
  303. return resolvePath(buf);
  304. }
  305. InodeIdentifier VirtualFileSystem::resolvePath(const String& path)
  306. {
  307. auto parts = path.split('/');
  308. InodeIdentifier inode = m_rootNode->inode;
  309. for (unsigned i = 0; i < parts.size(); ++i) {
  310. auto& part = parts[i];
  311. auto metadata = inode.metadata();
  312. if (!metadata.isValid()) {
  313. #ifdef VFS_DEBUG
  314. printf("invalid metadata\n");
  315. #endif
  316. return InodeIdentifier();
  317. }
  318. if (!metadata.isDirectory()) {
  319. #ifdef VFS_DEBUG
  320. printf("not directory\n");
  321. #endif
  322. return InodeIdentifier();
  323. }
  324. inode = inode.fileSystem()->childOfDirectoryInodeWithName(inode, part);
  325. if (!inode.isValid()) {
  326. #ifdef VFS_DEBUG
  327. printf("bad child\n");
  328. #endif
  329. return InodeIdentifier();
  330. }
  331. #ifdef VFS_DEBUG
  332. printf("<%s> %02u:%08u\n", part.characters(), inode.fileSystemID(), inode.index());
  333. #endif
  334. if (auto mount = findMountForHost(inode)) {
  335. #ifdef VFS_DEBUG
  336. printf(" -- is host\n");
  337. #endif
  338. inode = mount->guest();
  339. }
  340. if (inode.isRootInode() && !isRoot(inode) && part == "..") {
  341. #ifdef VFS_DEBUG
  342. printf(" -- is guest\n");
  343. #endif
  344. auto mount = findMountForGuest(inode);
  345. inode = mount->host();
  346. inode = inode.fileSystem()->childOfDirectoryInodeWithName(inode, "..");
  347. }
  348. metadata = inode.metadata();
  349. if (metadata.isSymbolicLink()) {
  350. char buf[4096] = "";
  351. char* p = buf;
  352. for (unsigned j = 0; j < i; ++j) {
  353. p += sprintf(p, "/%s", parts[j].characters());
  354. }
  355. inode = resolveSymbolicLink(buf, inode);
  356. if (!inode.isValid()) {
  357. printf("Symbolic link resolution failed :(\n");
  358. return { };
  359. }
  360. }
  361. }
  362. return inode;
  363. }
  364. void VirtualFileSystem::Node::retain()
  365. {
  366. ++retainCount;
  367. }
  368. void VirtualFileSystem::Node::release()
  369. {
  370. ASSERT(retainCount);
  371. if (--retainCount == 0) {
  372. vfs->freeNode(this);
  373. }
  374. }
  375. VirtualFileSystem::Mount::Mount(InodeIdentifier host, RetainPtr<FileSystem>&& guestFileSystem)
  376. : m_host(host)
  377. , m_guest(guestFileSystem->rootInode())
  378. , m_fileSystem(std::move(guestFileSystem))
  379. {
  380. }
  381. void VirtualFileSystem::registerCharacterDevice(unsigned major, unsigned minor, CharacterDevice& device)
  382. {
  383. m_characterDevices.set(encodedDevice(major, minor), &device);
  384. }