| 198 | } |
| 199 | |
| 200 | BAN::ErrorOr<uint32_t> Ext2FS::create_inode(const Ext2::Inode& ext2_inode) |
| 201 | { |
| 202 | auto bgd_buffer = TRY(m_buffer_manager.get_buffer()); |
| 203 | auto inode_bitmap = TRY(m_buffer_manager.get_buffer()); |
| 204 | |
| 205 | LockGuard _(m_mutex); |
| 206 | |
| 207 | ASSERT(ext2_inode.size == 0); |
| 208 | |
| 209 | if (m_superblock.free_inodes_count == 0) |
| 210 | return BAN::Error::from_errno(ENOSPC); |
| 211 | |
| 212 | const uint32_t block_size = this->block_size(); |
| 213 | |
| 214 | uint32_t current_group = -1; |
| 215 | BlockLocation bgd_location {}; |
| 216 | Ext2::BlockGroupDescriptor* bgd = nullptr; |
| 217 | |
| 218 | for (uint32_t ino = superblock().first_ino; ino <= superblock().inodes_count; ino++) |
| 219 | { |
| 220 | const uint32_t ino_group = (ino - 1) / superblock().inodes_per_group; |
| 221 | const uint32_t ino_index = (ino - 1) % superblock().inodes_per_group; |
| 222 | |
| 223 | if (ino_group != current_group) |
| 224 | { |
| 225 | current_group = ino_group; |
| 226 | |
| 227 | bgd_location = locate_block_group_descriptior(current_group); |
| 228 | TRY(read_block(bgd_location.block, bgd_buffer)); |
| 229 | |
| 230 | bgd = (Ext2::BlockGroupDescriptor*)(bgd_buffer.data() + bgd_location.offset); |
| 231 | if (bgd->free_inodes_count == 0) |
| 232 | { |
| 233 | ino = superblock().first_ino + (current_group + 1) * superblock().inodes_per_group - 1; |
| 234 | continue; |
| 235 | } |
| 236 | |
| 237 | TRY(read_block(bgd->inode_bitmap, inode_bitmap)); |
| 238 | } |
| 239 | |
| 240 | const uint32_t ino_bitmap_byte = ino_index / 8; |
| 241 | const uint32_t ino_bitmap_bit = ino_index % 8; |
| 242 | if (inode_bitmap[ino_bitmap_byte] & (1 << ino_bitmap_bit)) |
| 243 | continue; |
| 244 | |
| 245 | inode_bitmap[ino_bitmap_byte] |= 1 << ino_bitmap_bit; |
| 246 | TRY(write_block(bgd->inode_bitmap, inode_bitmap)); |
| 247 | |
| 248 | bgd->free_inodes_count--; |
| 249 | if (Inode::Mode(ext2_inode.mode).ifdir()) |
| 250 | bgd->used_dirs_count++; |
| 251 | TRY(write_block(bgd_location.block, bgd_buffer)); |
| 252 | |
| 253 | const uint32_t inode_table_offset = ino_index * superblock().inode_size; |
| 254 | const BlockLocation inode_location { |
| 255 | .block = inode_table_offset / block_size + bgd->inode_table, |
| 256 | .offset = inode_table_offset % block_size |
| 257 | }; |
no test coverage detected