Inode.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /*
  2. * Copyright (c) 2022, Undefine <undefine@undefine.pl>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/Time.h>
  7. #include <Kernel/Debug.h>
  8. #include <Kernel/FileSystem/FATFS/Inode.h>
  9. #include <Kernel/KBufferBuilder.h>
  10. namespace Kernel {
  11. ErrorOr<NonnullLockRefPtr<FATInode>> FATInode::create(FATFS& fs, FATEntry entry, Vector<FATLongFileNameEntry> const& lfn_entries)
  12. {
  13. auto filename = TRY(compute_filename(entry, lfn_entries));
  14. return adopt_nonnull_lock_ref_or_enomem(new (nothrow) FATInode(fs, entry, move(filename)));
  15. }
  16. FATInode::FATInode(FATFS& fs, FATEntry entry, NonnullOwnPtr<KString> filename)
  17. : Inode(fs, first_cluster())
  18. , m_entry(entry)
  19. , m_filename(move(filename))
  20. {
  21. dbgln_if(FAT_DEBUG, "FATFS: Creating inode {} with filename \"{}\"", index(), m_filename);
  22. m_metadata = {
  23. .inode = identifier(),
  24. .size = m_entry.file_size,
  25. .mode = static_cast<mode_t>((has_flag(m_entry.attributes, FATAttributes::Directory) ? S_IFDIR : S_IFREG) | 0777),
  26. .uid = 0,
  27. .gid = 0,
  28. .link_count = 0,
  29. .atime = fat_date_time(m_entry.last_accessed_date, { 0 }),
  30. .ctime = fat_date_time(m_entry.creation_date, m_entry.creation_time),
  31. .mtime = fat_date_time(m_entry.modification_date, m_entry.modification_time),
  32. .dtime = {},
  33. .block_count = 0,
  34. .block_size = 0,
  35. .major_device = 0,
  36. .minor_device = 0,
  37. };
  38. }
  39. ErrorOr<Vector<BlockBasedFileSystem::BlockIndex>> FATInode::compute_block_list()
  40. {
  41. VERIFY(m_inode_lock.is_locked());
  42. dbgln_if(FAT_DEBUG, "FATFS: computing block list for inode {}", index());
  43. u32 cluster = first_cluster();
  44. Vector<BlockBasedFileSystem::BlockIndex> block_list;
  45. auto fat_sector = TRY(KBuffer::try_create_with_size("FATFS: FAT read buffer"sv, fs().m_logical_block_size));
  46. auto fat_sector_buffer = UserOrKernelBuffer::for_kernel_buffer(fat_sector->data());
  47. while (cluster < no_more_clusters) {
  48. dbgln_if(FAT_DEBUG, "FATFS: Appending cluster {} to inode {}'s cluster chain", cluster, index());
  49. BlockBasedFileSystem::BlockIndex first_block = fs().first_block_of_cluster(cluster);
  50. for (u8 i = 0; i < fs().boot_record()->sectors_per_cluster; i++)
  51. block_list.append(BlockBasedFileSystem::BlockIndex { first_block.value() + i });
  52. u32 fat_offset = cluster * sizeof(u32);
  53. u32 fat_sector_index = fs().boot_record()->reserved_sector_count + (fat_offset / fs().m_logical_block_size);
  54. u32 entry_offset = fat_offset % fs().m_logical_block_size;
  55. TRY(fs().raw_read(fat_sector_index, fat_sector_buffer));
  56. cluster = *reinterpret_cast<u32*>(&fat_sector->data()[entry_offset]);
  57. cluster &= cluster_number_mask;
  58. }
  59. return block_list;
  60. }
  61. ErrorOr<NonnullOwnPtr<KBuffer>> FATInode::read_block_list()
  62. {
  63. VERIFY(m_inode_lock.is_locked());
  64. dbgln_if(FAT_DEBUG, "FATFS: reading block list for inode {} ({} blocks)", index(), m_block_list.size());
  65. if (m_block_list.is_empty())
  66. m_block_list = TRY(compute_block_list());
  67. auto builder = TRY(KBufferBuilder::try_create());
  68. u8 buffer[512];
  69. VERIFY(fs().m_logical_block_size <= sizeof(buffer));
  70. auto buf = UserOrKernelBuffer::for_kernel_buffer(buffer);
  71. for (BlockBasedFileSystem::BlockIndex block : m_block_list) {
  72. dbgln_if(FAT_DEBUG, "FATFS: reading block: {}", block);
  73. TRY(fs().raw_read(block, buf));
  74. TRY(builder.append((char const*)buffer, fs().m_logical_block_size));
  75. }
  76. auto blocks = builder.build();
  77. if (!blocks)
  78. return ENOMEM;
  79. return blocks.release_nonnull();
  80. }
  81. ErrorOr<void> FATInode::replace_child(StringView, Inode&)
  82. {
  83. // TODO: Implement this once we have write support.
  84. return Error::from_errno(EROFS);
  85. }
  86. ErrorOr<LockRefPtr<FATInode>> FATInode::traverse(Function<ErrorOr<bool>(LockRefPtr<FATInode>)> callback)
  87. {
  88. VERIFY(has_flag(m_entry.attributes, FATAttributes::Directory));
  89. Vector<FATLongFileNameEntry> lfn_entries;
  90. auto blocks = TRY(read_block_list());
  91. for (u32 i = 0; i < blocks->size() / sizeof(FATEntry); i++) {
  92. auto* entry = reinterpret_cast<FATEntry*>(blocks->data() + i * sizeof(FATEntry));
  93. if (entry->filename[0] == end_entry_byte) {
  94. dbgln_if(FAT_DEBUG, "FATFS: Found end entry");
  95. return nullptr;
  96. } else if (static_cast<u8>(entry->filename[0]) == unused_entry_byte) {
  97. dbgln_if(FAT_DEBUG, "FATFS: Found unused entry");
  98. lfn_entries.clear();
  99. } else if (entry->attributes == FATAttributes::LongFileName) {
  100. dbgln_if(FAT_DEBUG, "FATFS: Found LFN entry");
  101. TRY(lfn_entries.try_append(*reinterpret_cast<FATLongFileNameEntry*>(entry)));
  102. } else {
  103. dbgln_if(FAT_DEBUG, "FATFS: Found 8.3 entry");
  104. lfn_entries.reverse();
  105. auto inode = TRY(FATInode::create(fs(), *entry, lfn_entries));
  106. if (TRY(callback(inode)))
  107. return inode;
  108. lfn_entries.clear();
  109. }
  110. }
  111. return EINVAL;
  112. }
  113. ErrorOr<NonnullOwnPtr<KString>> FATInode::compute_filename(FATEntry& entry, Vector<FATLongFileNameEntry> const& lfn_entries)
  114. {
  115. if (lfn_entries.is_empty()) {
  116. StringBuilder filename;
  117. filename.append(byte_terminated_string(StringView(entry.filename, normal_filename_length), ' '));
  118. if (entry.extension[0] != ' ') {
  119. filename.append('.');
  120. filename.append(byte_terminated_string(StringView(entry.extension, normal_extension_length), ' '));
  121. }
  122. return TRY(KString::try_create(filename.string_view()));
  123. } else {
  124. StringBuilder filename;
  125. for (auto& lfn_entry : lfn_entries) {
  126. filename.append(lfn_entry.characters1[0]);
  127. filename.append(lfn_entry.characters1[1]);
  128. filename.append(lfn_entry.characters1[2]);
  129. filename.append(lfn_entry.characters1[3]);
  130. filename.append(lfn_entry.characters1[4]);
  131. filename.append(lfn_entry.characters2[0]);
  132. filename.append(lfn_entry.characters2[1]);
  133. filename.append(lfn_entry.characters2[2]);
  134. filename.append(lfn_entry.characters2[3]);
  135. filename.append(lfn_entry.characters2[4]);
  136. filename.append(lfn_entry.characters2[5]);
  137. filename.append(lfn_entry.characters3[0]);
  138. filename.append(lfn_entry.characters3[1]);
  139. }
  140. return TRY(KString::try_create(byte_terminated_string(filename.string_view(), lfn_entry_text_termination)));
  141. }
  142. VERIFY_NOT_REACHED();
  143. }
  144. Time FATInode::fat_date_time(FATPackedDate date, FATPackedTime time)
  145. {
  146. if (date.value == 0)
  147. return Time();
  148. return Time::from_timestamp(first_fat_year + date.year, date.month, date.day, time.hour, time.minute, time.second * 2, 0);
  149. }
  150. StringView FATInode::byte_terminated_string(StringView string, u8 fill_byte)
  151. {
  152. if (auto index = string.find_last_not(fill_byte); index.has_value())
  153. return string.substring_view(0, index.value());
  154. return string;
  155. }
  156. u32 FATInode::first_cluster() const
  157. {
  158. return (((u32)m_entry.first_cluster_high) << 16) | m_entry.first_cluster_low;
  159. }
  160. ErrorOr<size_t> FATInode::read_bytes_locked(off_t offset, size_t size, UserOrKernelBuffer& buffer, OpenFileDescription*) const
  161. {
  162. dbgln_if(FAT_DEBUG, "FATFS: Reading inode {}: size: {} offset: {}", identifier().index(), size, offset);
  163. // FIXME: Read only the needed blocks instead of the whole file
  164. auto blocks = TRY(const_cast<FATInode&>(*this).read_block_list());
  165. TRY(buffer.write(blocks->data() + offset, min(size, m_block_list.size() * fs().m_logical_block_size - offset)));
  166. return min(size, m_block_list.size() * fs().m_logical_block_size - offset);
  167. }
  168. InodeMetadata FATInode::metadata() const
  169. {
  170. return m_metadata;
  171. }
  172. ErrorOr<void> FATInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
  173. {
  174. MutexLocker locker(m_inode_lock);
  175. VERIFY(has_flag(m_entry.attributes, FATAttributes::Directory));
  176. [[maybe_unused]] auto inode = TRY(const_cast<FATInode&>(*this).traverse([&callback](auto inode) -> ErrorOr<bool> {
  177. if (inode->m_filename->view() == "" || inode->m_filename->view() == "." || inode->m_filename->view() == "..")
  178. return false;
  179. TRY(callback({ inode->m_filename->view(), inode->identifier(), static_cast<u8>(inode->m_entry.attributes) }));
  180. return false;
  181. }));
  182. return {};
  183. }
  184. ErrorOr<NonnullLockRefPtr<Inode>> FATInode::lookup(StringView name)
  185. {
  186. MutexLocker locker(m_inode_lock);
  187. VERIFY(has_flag(m_entry.attributes, FATAttributes::Directory));
  188. auto inode = TRY(traverse([name](auto child) -> ErrorOr<bool> {
  189. return child->m_filename->view() == name;
  190. }));
  191. if (inode.is_null())
  192. return ENOENT;
  193. else
  194. return inode.release_nonnull();
  195. }
  196. ErrorOr<size_t> FATInode::write_bytes_locked(off_t, size_t, UserOrKernelBuffer const&, OpenFileDescription*)
  197. {
  198. return EROFS;
  199. }
  200. ErrorOr<NonnullLockRefPtr<Inode>> FATInode::create_child(StringView, mode_t, dev_t, UserID, GroupID)
  201. {
  202. return EROFS;
  203. }
  204. ErrorOr<void> FATInode::add_child(Inode&, StringView, mode_t)
  205. {
  206. return EROFS;
  207. }
  208. ErrorOr<void> FATInode::remove_child(StringView)
  209. {
  210. return EROFS;
  211. }
  212. ErrorOr<void> FATInode::chmod(mode_t)
  213. {
  214. return EROFS;
  215. }
  216. ErrorOr<void> FATInode::chown(UserID, GroupID)
  217. {
  218. return EROFS;
  219. }
  220. ErrorOr<void> FATInode::flush_metadata()
  221. {
  222. return EROFS;
  223. }
  224. }