From: Tulio A M Mendes Date: Mon, 25 May 2026 17:13:38 +0000 (-0300) Subject: vfs: refactor FAT and EXT2 to support multiple independent mounts X-Git-Url: https://projects.tadryanom.me/?a=commitdiff_plain;h=1f46f9e1ce1d3534d5a94cfdc0fab0229abc34a9;p=AdrOS.git vfs: refactor FAT and EXT2 to support multiple independent mounts - Replace global g_fat/g_ext2 singletons with per-mount state structures - Add struct fat_mount and struct ext2_mount for filesystem-specific state - Update all FAT/EXT2 functions to accept mount pointer parameter - Refactor fat_mount/ext2_mount to allocate per-mount structures dynamically - Add fat_umount/ext2_umount functions to free allocated resources - Integrate filesystem-specific umount calls in vfs_umount_nolock - Remove global state dependencies to enable multiple independent mounts - Fix duplicate enum fat_type definition in fat.c - Test: smoke test 119/119 PASS --- diff --git a/include/ext2.h b/include/ext2.h index 4a3ce543..bda798c0 100644 --- a/include/ext2.h +++ b/include/ext2.h @@ -14,8 +14,31 @@ #include "blockdev.h" #include -/* Mount an ext2 filesystem on the given ATA drive starting at the given +struct ext2_group_desc; + +/* Per-mount filesystem state */ +struct ext2_mount { + const block_device_t* bdev; + int drive; + uint32_t part_lba; /* partition start LBA */ + uint32_t block_size; /* bytes per block (1024, 2048, or 4096) */ + uint32_t sectors_per_block; + uint32_t inodes_per_group; + uint32_t blocks_per_group; + uint32_t inode_size; /* on-disk inode size (128 or 256) */ + uint32_t num_groups; + uint32_t first_data_block; + uint32_t total_blocks; + uint32_t total_inodes; + struct ext2_group_desc* gdt; /* group descriptor table (heap-allocated) */ + uint32_t gdt_blocks; /* number of blocks occupied by GDT */ +}; + +/* Mount an ext2 filesystem on the given block device starting at the given * LBA offset. Returns a VFS root node or NULL on failure. */ fs_node_t* ext2_mount(const block_device_t* bdev, uint32_t partition_lba); +/* Unmount an ext2 filesystem and free its resources */ +void ext2_umount(struct ext2_mount* em); + #endif diff --git a/include/fat.h b/include/fat.h index 68ffa449..a580e75c 100644 --- a/include/fat.h +++ b/include/fat.h @@ -14,9 +14,38 @@ #include "blockdev.h" #include -/* Mount a FAT12/16/32 filesystem on the given ATA drive starting at +enum fat_type { + FAT_TYPE_12 = 12, + FAT_TYPE_16 = 16, + FAT_TYPE_32 = 32, +}; + +/* Per-mount filesystem state */ +struct fat_mount { + const block_device_t* bdev; + int drive; + uint32_t part_lba; + uint16_t bytes_per_sector; + uint8_t sectors_per_cluster; + uint16_t reserved_sectors; + uint8_t num_fats; + uint16_t root_entry_count; + uint32_t fat_size; /* sectors per FAT */ + uint32_t fat_lba; /* LBA of first FAT */ + uint32_t root_dir_lba; /* LBA of root directory (FAT12/16) */ + uint32_t root_dir_sectors; /* sectors used by root dir (FAT12/16), 0 for FAT32 */ + uint32_t data_lba; /* LBA of first data cluster */ + uint32_t total_clusters; + uint32_t root_cluster; /* FAT32 root cluster, 0 for FAT12/16 */ + enum fat_type type; +}; + +/* Mount a FAT12/16/32 filesystem on the given block device starting at * the given LBA offset. Auto-detects FAT type from BPB. * Returns a VFS root node or NULL on failure. */ fs_node_t* fat_mount(const block_device_t* bdev, uint32_t partition_lba); +/* Unmount a FAT filesystem and free its resources */ +void fat_umount(struct fat_mount* fm); + #endif diff --git a/src/kernel/ext2.c b/src/kernel/ext2.c index 664458c3..3371891b 100644 --- a/src/kernel/ext2.c +++ b/src/kernel/ext2.c @@ -141,30 +141,30 @@ struct ext2_state { struct ext2_node { fs_node_t vfs; + struct ext2_mount* mount; /* back-pointer to mount state */ uint32_t ino; /* inode number */ }; -static struct ext2_state g_ext2; -static struct ext2_node g_ext2_root; -static int g_ext2_ready = 0; /* ---- Block I/O ---- */ -static int ext2_read_block(uint32_t block, void* buf) { - uint32_t lba = g_ext2.part_lba + block * g_ext2.sectors_per_block; +static int ext2_read_block(struct ext2_mount* em, uint32_t block, void* buf) { + if (!em || !em->bdev) return -ENODEV; + uint32_t lba = em->part_lba + block * em->sectors_per_block; uint8_t* p = (uint8_t*)buf; - for (uint32_t s = 0; s < g_ext2.sectors_per_block; s++) { - if (blockdev_read(g_ext2.bdev, lba + s, p + s * EXT2_SECTOR_SIZE) < 0) + for (uint32_t s = 0; s < em->sectors_per_block; s++) { + if (blockdev_read(em->bdev, lba + s, p + s * EXT2_SECTOR_SIZE) < 0) return -EIO; } return 0; } -static int ext2_write_block(uint32_t block, const void* buf) { - uint32_t lba = g_ext2.part_lba + block * g_ext2.sectors_per_block; +static int ext2_write_block(struct ext2_mount* em, uint32_t block, const void* buf) { + if (!em || !em->bdev) return -ENODEV; + uint32_t lba = em->part_lba + block * em->sectors_per_block; const uint8_t* p = (const uint8_t*)buf; - for (uint32_t s = 0; s < g_ext2.sectors_per_block; s++) { - if (blockdev_write(g_ext2.bdev, lba + s, p + s * EXT2_SECTOR_SIZE) < 0) + for (uint32_t s = 0; s < em->sectors_per_block; s++) { + if (blockdev_write(em->bdev, lba + s, p + s * EXT2_SECTOR_SIZE) < 0) return -EIO; } return 0; @@ -172,29 +172,31 @@ static int ext2_write_block(uint32_t block, const void* buf) { /* ---- Superblock I/O ---- */ -static int ext2_read_superblock(struct ext2_superblock* sb) { +static int ext2_read_superblock(struct ext2_mount* em, struct ext2_superblock* sb) { + if (!em || !em->bdev) return -ENODEV; /* Superblock is at byte offset 1024, which is LBA 2-3 relative to partition */ uint8_t sec[EXT2_SECTOR_SIZE]; - uint32_t sb_lba = g_ext2.part_lba + EXT2_SUPER_OFFSET / EXT2_SECTOR_SIZE; + uint32_t sb_lba = em->part_lba + EXT2_SUPER_OFFSET / EXT2_SECTOR_SIZE; uint8_t raw[1024]; for (uint32_t i = 0; i < 1024 / EXT2_SECTOR_SIZE; i++) { - if (blockdev_read(g_ext2.bdev, sb_lba + i, sec) < 0) return -EIO; + if (blockdev_read(em->bdev, sb_lba + i, sec) < 0) return -EIO; memcpy(raw + i * EXT2_SECTOR_SIZE, sec, EXT2_SECTOR_SIZE); } memcpy(sb, raw, sizeof(*sb)); return 0; } -static int ext2_write_superblock(const struct ext2_superblock* sb) __attribute__((unused)); -static int ext2_write_superblock(const struct ext2_superblock* sb) { - uint32_t sb_lba = g_ext2.part_lba + EXT2_SUPER_OFFSET / EXT2_SECTOR_SIZE; +static int ext2_write_superblock(struct ext2_mount* em, const struct ext2_superblock* sb) __attribute__((unused)); +static int ext2_write_superblock(struct ext2_mount* em, const struct ext2_superblock* sb) { + if (!em || !em->bdev) return -ENODEV; + uint32_t sb_lba = em->part_lba + EXT2_SUPER_OFFSET / EXT2_SECTOR_SIZE; uint8_t raw[1024]; memset(raw, 0, sizeof(raw)); memcpy(raw, sb, sizeof(*sb)); for (uint32_t i = 0; i < 1024 / EXT2_SECTOR_SIZE; i++) { - if (blockdev_write(g_ext2.bdev, sb_lba + i, raw + i * EXT2_SECTOR_SIZE) < 0) + if (blockdev_write(em->bdev, sb_lba + i, raw + i * EXT2_SECTOR_SIZE) < 0) return -EIO; } return 0; @@ -202,68 +204,70 @@ static int ext2_write_superblock(const struct ext2_superblock* sb) { /* ---- GDT I/O ---- */ -static int ext2_write_gdt(void) { +static int ext2_write_gdt(struct ext2_mount* em) { + if (!em) return -EINVAL; /* GDT starts at block after superblock (block 1 for 1KB blocks, block 1 for others too * since superblock is in block 0 or 1 depending on block_size) */ - uint32_t gdt_block = g_ext2.first_data_block + 1; - uint8_t* p = (uint8_t*)g_ext2.gdt; + uint32_t gdt_block = em->first_data_block + 1; + uint8_t* p = (uint8_t*)em->gdt; - for (uint32_t b = 0; b < g_ext2.gdt_blocks; b++) { + for (uint32_t b = 0; b < em->gdt_blocks; b++) { uint8_t blk_buf[4096]; /* max block size */ - memset(blk_buf, 0, g_ext2.block_size); - uint32_t bytes = g_ext2.block_size; - uint32_t remain = g_ext2.num_groups * (uint32_t)sizeof(struct ext2_group_desc) - b * g_ext2.block_size; + memset(blk_buf, 0, em->block_size); + uint32_t bytes = em->block_size; + uint32_t remain = em->num_groups * (uint32_t)sizeof(struct ext2_group_desc) - b * em->block_size; if (bytes > remain) bytes = remain; - memcpy(blk_buf, p + b * g_ext2.block_size, bytes); - if (ext2_write_block(gdt_block + b, blk_buf) < 0) return -EIO; + memcpy(blk_buf, p + b * em->block_size, bytes); + if (ext2_write_block(em, gdt_block + b, blk_buf) < 0) return -EIO; } return 0; } /* ---- Inode I/O ---- */ -static int ext2_read_inode(uint32_t ino, struct ext2_inode* out) { - if (ino == 0 || !out) return -EINVAL; - uint32_t group = (ino - 1) / g_ext2.inodes_per_group; - uint32_t index = (ino - 1) % g_ext2.inodes_per_group; +static int ext2_read_inode(struct ext2_mount* em, uint32_t ino, struct ext2_inode* out) { + if (!em || ino == 0 || !out) return -EINVAL; + uint32_t group = (ino - 1) / em->inodes_per_group; + uint32_t index = (ino - 1) % em->inodes_per_group; - if (group >= g_ext2.num_groups) return -EINVAL; + if (group >= em->num_groups) return -EINVAL; - uint32_t inode_table_block = g_ext2.gdt[group].bg_inode_table; - uint32_t byte_offset = index * g_ext2.inode_size; - uint32_t block = inode_table_block + byte_offset / g_ext2.block_size; - uint32_t offset_in_block = byte_offset % g_ext2.block_size; + uint32_t inode_table_block = em->gdt[group].bg_inode_table; + uint32_t byte_offset = index * em->inode_size; + uint32_t block = inode_table_block + byte_offset / em->block_size; + uint32_t offset_in_block = byte_offset % em->block_size; uint8_t blk_buf[4096]; - if (ext2_read_block(block, blk_buf) < 0) return -EIO; + if (ext2_read_block(em, block, blk_buf) < 0) return -EIO; memcpy(out, blk_buf + offset_in_block, sizeof(*out)); return 0; } -static int ext2_write_inode(uint32_t ino, const struct ext2_inode* in) { - if (ino == 0 || !in) return -EINVAL; - uint32_t group = (ino - 1) / g_ext2.inodes_per_group; - uint32_t index = (ino - 1) % g_ext2.inodes_per_group; +static int ext2_write_inode(struct ext2_mount* em, uint32_t ino, const struct ext2_inode* in) { + if (!em || ino == 0 || !in) return -EINVAL; + uint32_t group = (ino - 1) / em->inodes_per_group; + uint32_t index = (ino - 1) % em->inodes_per_group; - if (group >= g_ext2.num_groups) return -EINVAL; + if (group >= em->num_groups) return -EINVAL; - uint32_t inode_table_block = g_ext2.gdt[group].bg_inode_table; - uint32_t byte_offset = index * g_ext2.inode_size; - uint32_t block = inode_table_block + byte_offset / g_ext2.block_size; - uint32_t offset_in_block = byte_offset % g_ext2.block_size; + uint32_t inode_table_block = em->gdt[group].bg_inode_table; + uint32_t byte_offset = index * em->inode_size; + uint32_t block = inode_table_block + byte_offset / em->block_size; + uint32_t offset_in_block = byte_offset % em->block_size; uint8_t blk_buf[4096]; - if (ext2_read_block(block, blk_buf) < 0) return -EIO; + if (ext2_read_block(em, block, blk_buf) < 0) return -EIO; memcpy(blk_buf + offset_in_block, in, sizeof(*in)); - return ext2_write_block(block, blk_buf); + return ext2_write_block(em, block, blk_buf); } /* ---- Block mapping: logical block → physical block ---- */ /* Resolve logical block number within an inode to physical block number. * Handles direct, indirect, doubly-indirect, and triply-indirect blocks. */ -static uint32_t ext2_block_map(const struct ext2_inode* inode, uint32_t logical) { - uint32_t ptrs_per_block = g_ext2.block_size / 4; +static uint32_t ext2_block_map(struct ext2_mount* em, const struct ext2_inode* inode, uint32_t logical) { + if (!em) return 0; + uint32_t ptrs_per_block = em->block_size / 4; /* Direct blocks (0..11) */ if (logical < EXT2_NDIR_BLOCKS) { @@ -276,7 +280,7 @@ static uint32_t ext2_block_map(const struct ext2_inode* inode, uint32_t logical) uint32_t ind_block = inode->i_block[EXT2_IND_BLOCK]; if (ind_block == 0) return 0; uint8_t blk_buf[4096]; - if (ext2_read_block(ind_block, blk_buf) < 0) return 0; + if (ext2_read_block(em, ind_block, blk_buf) < 0) return 0; return ((uint32_t*)blk_buf)[logical]; } logical -= ptrs_per_block; @@ -287,10 +291,10 @@ static uint32_t ext2_block_map(const struct ext2_inode* inode, uint32_t logical) if (dind_block == 0) return 0; uint8_t blk_buf[4096]; memset(blk_buf, 0, sizeof(blk_buf)); - if (ext2_read_block(dind_block, blk_buf) < 0) return 0; + if (ext2_read_block(em, dind_block, blk_buf) < 0) return 0; uint32_t ind = ((uint32_t*)blk_buf)[logical / ptrs_per_block]; if (ind == 0) return 0; - if (ext2_read_block(ind, blk_buf) < 0) return 0; + if (ext2_read_block(em, ind, blk_buf) < 0) return 0; return ((uint32_t*)blk_buf)[logical % ptrs_per_block]; } logical -= ptrs_per_block * ptrs_per_block; @@ -301,14 +305,14 @@ static uint32_t ext2_block_map(const struct ext2_inode* inode, uint32_t logical) if (tind_block == 0) return 0; uint8_t blk_buf[4096]; memset(blk_buf, 0, sizeof(blk_buf)); - if (ext2_read_block(tind_block, blk_buf) < 0) return 0; + if (ext2_read_block(em, tind_block, blk_buf) < 0) return 0; uint32_t dind = ((uint32_t*)blk_buf)[logical / (ptrs_per_block * ptrs_per_block)]; if (dind == 0) return 0; uint32_t rem = logical % (ptrs_per_block * ptrs_per_block); - if (ext2_read_block(dind, blk_buf) < 0) return 0; + if (ext2_read_block(em, dind, blk_buf) < 0) return 0; uint32_t ind = ((uint32_t*)blk_buf)[rem / ptrs_per_block]; if (ind == 0) return 0; - if (ext2_read_block(ind, blk_buf) < 0) return 0; + if (ext2_read_block(em, ind, blk_buf) < 0) return 0; return ((uint32_t*)blk_buf)[rem % ptrs_per_block]; } } @@ -316,100 +320,103 @@ static uint32_t ext2_block_map(const struct ext2_inode* inode, uint32_t logical) /* ---- Bitmap helpers (for RW) ---- */ /* Allocate a free block from group, returns block number or 0. */ -static uint32_t ext2_alloc_block(void) { - for (uint32_t g = 0; g < g_ext2.num_groups; g++) { - if (g_ext2.gdt[g].bg_free_blocks_count == 0) continue; +static uint32_t ext2_alloc_block(struct ext2_mount* em) { + if (!em) return 0; + for (uint32_t g = 0; g < em->num_groups; g++) { + if (em->gdt[g].bg_free_blocks_count == 0) continue; uint8_t bmap[4096]; memset(bmap, 0, sizeof(bmap)); - if (ext2_read_block(g_ext2.gdt[g].bg_block_bitmap, bmap) < 0) continue; + if (ext2_read_block(em, em->gdt[g].bg_block_bitmap, bmap) < 0) continue; - uint32_t blocks_in_group = g_ext2.blocks_per_group; - if (g == g_ext2.num_groups - 1) { - uint32_t rem = g_ext2.total_blocks - g * g_ext2.blocks_per_group; + uint32_t blocks_in_group = em->blocks_per_group; + if (g == em->num_groups - 1) { + uint32_t rem = em->total_blocks - g * em->blocks_per_group; if (rem < blocks_in_group) blocks_in_group = rem; } for (uint32_t bit = 0; bit < blocks_in_group; bit++) { if ((bmap[bit / 8] & (1 << (bit % 8))) == 0) { bmap[bit / 8] |= (1 << (bit % 8)); - if (ext2_write_block(g_ext2.gdt[g].bg_block_bitmap, bmap) < 0) return 0; - g_ext2.gdt[g].bg_free_blocks_count--; - (void)ext2_write_gdt(); - return g * g_ext2.blocks_per_group + bit + g_ext2.first_data_block; + if (ext2_write_block(em, em->gdt[g].bg_block_bitmap, bmap) < 0) return 0; + em->gdt[g].bg_free_blocks_count--; + (void)ext2_write_gdt(em); + return g * em->blocks_per_group + bit + em->first_data_block; } } } return 0; } -static void ext2_free_block(uint32_t block) { - if (block == 0) return; - uint32_t adj = block - g_ext2.first_data_block; - uint32_t g = adj / g_ext2.blocks_per_group; - uint32_t bit = adj % g_ext2.blocks_per_group; +static void ext2_free_block(struct ext2_mount* em, uint32_t block) { + if (!em || block == 0) return; + uint32_t adj = block - em->first_data_block; + uint32_t g = adj / em->blocks_per_group; + uint32_t bit = adj % em->blocks_per_group; - if (g >= g_ext2.num_groups) return; + if (g >= em->num_groups) return; uint8_t bmap[4096]; memset(bmap, 0, sizeof(bmap)); - if (ext2_read_block(g_ext2.gdt[g].bg_block_bitmap, bmap) < 0) return; + if (ext2_read_block(em, em->gdt[g].bg_block_bitmap, bmap) < 0) return; bmap[bit / 8] &= ~(1 << (bit % 8)); - (void)ext2_write_block(g_ext2.gdt[g].bg_block_bitmap, bmap); - g_ext2.gdt[g].bg_free_blocks_count++; - (void)ext2_write_gdt(); + (void)ext2_write_block(em, em->gdt[g].bg_block_bitmap, bmap); + em->gdt[g].bg_free_blocks_count++; + (void)ext2_write_gdt(em); } /* Allocate a free inode, returns inode number or 0. */ -static uint32_t ext2_alloc_inode(void) { - for (uint32_t g = 0; g < g_ext2.num_groups; g++) { - if (g_ext2.gdt[g].bg_free_inodes_count == 0) continue; +static uint32_t ext2_alloc_inode(struct ext2_mount* em) { + if (!em) return 0; + for (uint32_t g = 0; g < em->num_groups; g++) { + if (em->gdt[g].bg_free_inodes_count == 0) continue; uint8_t bmap[4096]; memset(bmap, 0, sizeof(bmap)); - if (ext2_read_block(g_ext2.gdt[g].bg_inode_bitmap, bmap) < 0) continue; + if (ext2_read_block(em, em->gdt[g].bg_inode_bitmap, bmap) < 0) continue; - for (uint32_t bit = 0; bit < g_ext2.inodes_per_group; bit++) { + for (uint32_t bit = 0; bit < em->inodes_per_group; bit++) { if ((bmap[bit / 8] & (1 << (bit % 8))) == 0) { bmap[bit / 8] |= (1 << (bit % 8)); - if (ext2_write_block(g_ext2.gdt[g].bg_inode_bitmap, bmap) < 0) return 0; - g_ext2.gdt[g].bg_free_inodes_count--; - (void)ext2_write_gdt(); - return g * g_ext2.inodes_per_group + bit + 1; + if (ext2_write_block(em, em->gdt[g].bg_inode_bitmap, bmap) < 0) return 0; + em->gdt[g].bg_free_inodes_count--; + (void)ext2_write_gdt(em); + return g * em->inodes_per_group + bit + 1; } } } return 0; } -static void ext2_free_inode(uint32_t ino) { - if (ino == 0) return; - uint32_t g = (ino - 1) / g_ext2.inodes_per_group; - uint32_t bit = (ino - 1) % g_ext2.inodes_per_group; +static void ext2_free_inode(struct ext2_mount* em, uint32_t ino) { + if (!em || ino == 0) return; + uint32_t g = (ino - 1) / em->inodes_per_group; + uint32_t bit = (ino - 1) % em->inodes_per_group; - if (g >= g_ext2.num_groups) return; + if (g >= em->num_groups) return; uint8_t bmap[4096]; memset(bmap, 0, sizeof(bmap)); - if (ext2_read_block(g_ext2.gdt[g].bg_inode_bitmap, bmap) < 0) return; + if (ext2_read_block(em, em->gdt[g].bg_inode_bitmap, bmap) < 0) return; bmap[bit / 8] &= ~(1 << (bit % 8)); - (void)ext2_write_block(g_ext2.gdt[g].bg_inode_bitmap, bmap); - g_ext2.gdt[g].bg_free_inodes_count++; - (void)ext2_write_gdt(); + (void)ext2_write_block(em, em->gdt[g].bg_inode_bitmap, bmap); + em->gdt[g].bg_free_inodes_count++; + (void)ext2_write_gdt(em); } /* ---- Block mapping write: set logical→physical mapping in inode ---- */ /* Allocate an indirect block if val is zero. Returns the block number (existing or new), or 0 on failure. */ -static uint32_t ext2_ensure_indirect(uint32_t val) { +static uint32_t ext2_ensure_indirect(struct ext2_mount* em, uint32_t val) { + if (!em) return 0; if (val != 0) return val; - uint32_t nb = ext2_alloc_block(); + uint32_t nb = ext2_alloc_block(em); if (nb == 0) return 0; /* Zero out the new indirect block */ uint8_t zero[4096]; - memset(zero, 0, g_ext2.block_size); - if (ext2_write_block(nb, zero) < 0) { - ext2_free_block(nb); + memset(zero, 0, em->block_size); + if (ext2_write_block(em, nb, zero) < 0) { + ext2_free_block(em, nb); return 0; } return nb; @@ -417,53 +424,54 @@ static uint32_t ext2_ensure_indirect(uint32_t val) { /* Set the physical block for a logical block in an inode. * Allocates indirect blocks as needed. Writes inode back to disk. */ -static int ext2_block_map_set(uint32_t ino, struct ext2_inode* inode, +static int ext2_block_map_set(struct ext2_mount* em, uint32_t ino, struct ext2_inode* inode, uint32_t logical, uint32_t phys_block) { - uint32_t ptrs_per_block = g_ext2.block_size / 4; + if (!em) return -EINVAL; + uint32_t ptrs_per_block = em->block_size / 4; if (logical < EXT2_NDIR_BLOCKS) { inode->i_block[logical] = phys_block; - return ext2_write_inode(ino, inode); + return ext2_write_inode(em, ino, inode); } logical -= EXT2_NDIR_BLOCKS; if (logical < ptrs_per_block) { - uint32_t ind_blk = ext2_ensure_indirect(inode->i_block[EXT2_IND_BLOCK]); + uint32_t ind_blk = ext2_ensure_indirect(em, inode->i_block[EXT2_IND_BLOCK]); if (ind_blk == 0) return -ENOSPC; inode->i_block[EXT2_IND_BLOCK] = ind_blk; - if (ext2_write_inode(ino, inode) < 0) return -EIO; + if (ext2_write_inode(em, ino, inode) < 0) return -EIO; uint8_t blk_buf[4096]; - if (ext2_read_block(inode->i_block[EXT2_IND_BLOCK], blk_buf) < 0) return -EIO; + if (ext2_read_block(em, inode->i_block[EXT2_IND_BLOCK], blk_buf) < 0) return -EIO; ((uint32_t*)blk_buf)[logical] = phys_block; - return ext2_write_block(inode->i_block[EXT2_IND_BLOCK], blk_buf); + return ext2_write_block(em, inode->i_block[EXT2_IND_BLOCK], blk_buf); } logical -= ptrs_per_block; if (logical < ptrs_per_block * ptrs_per_block) { - uint32_t dind_blk = ext2_ensure_indirect(inode->i_block[EXT2_DIND_BLOCK]); + uint32_t dind_blk = ext2_ensure_indirect(em, inode->i_block[EXT2_DIND_BLOCK]); if (dind_blk == 0) return -ENOSPC; inode->i_block[EXT2_DIND_BLOCK] = dind_blk; - if (ext2_write_inode(ino, inode) < 0) return -EIO; + if (ext2_write_inode(em, ino, inode) < 0) return -EIO; uint8_t blk_buf[4096]; - if (ext2_read_block(inode->i_block[EXT2_DIND_BLOCK], blk_buf) < 0) return -EIO; + if (ext2_read_block(em, inode->i_block[EXT2_DIND_BLOCK], blk_buf) < 0) return -EIO; uint32_t idx1 = logical / ptrs_per_block; uint32_t idx2 = logical % ptrs_per_block; uint32_t ind = ((uint32_t*)blk_buf)[idx1]; if (ind == 0) { - ind = ext2_alloc_block(); + ind = ext2_alloc_block(em); if (ind == 0) return -ENOSPC; uint8_t zero[4096]; - memset(zero, 0, g_ext2.block_size); - if (ext2_write_block(ind, zero) < 0) { ext2_free_block(ind); return -EIO; } + memset(zero, 0, em->block_size); + if (ext2_write_block(em, ind, zero) < 0) { ext2_free_block(em, ind); return -EIO; } ((uint32_t*)blk_buf)[idx1] = ind; - if (ext2_write_block(inode->i_block[EXT2_DIND_BLOCK], blk_buf) < 0) return -EIO; + if (ext2_write_block(em, inode->i_block[EXT2_DIND_BLOCK], blk_buf) < 0) return -EIO; } - if (ext2_read_block(ind, blk_buf) < 0) return -EIO; + if (ext2_read_block(em, ind, blk_buf) < 0) return -EIO; ((uint32_t*)blk_buf)[idx2] = phys_block; - return ext2_write_block(ind, blk_buf); + return ext2_write_block(em, ind, blk_buf); } /* Triply indirect — not implemented for now */ @@ -471,13 +479,14 @@ static int ext2_block_map_set(uint32_t ino, struct ext2_inode* inode, } /* Free all data blocks referenced by an inode (direct + indirect). */ -static void ext2_free_inode_blocks(struct ext2_inode* inode) { - uint32_t ptrs_per_block = g_ext2.block_size / 4; +static void ext2_free_inode_blocks(struct ext2_mount* em, struct ext2_inode* inode) { + if (!em) return; + uint32_t ptrs_per_block = em->block_size / 4; /* Direct */ for (uint32_t i = 0; i < EXT2_NDIR_BLOCKS; i++) { if (inode->i_block[i]) { - ext2_free_block(inode->i_block[i]); + ext2_free_block(em, inode->i_block[i]); inode->i_block[i] = 0; } } @@ -485,41 +494,41 @@ static void ext2_free_inode_blocks(struct ext2_inode* inode) { /* Singly indirect */ if (inode->i_block[EXT2_IND_BLOCK]) { uint8_t blk_buf[4096]; - if (ext2_read_block(inode->i_block[EXT2_IND_BLOCK], blk_buf) == 0) { + if (ext2_read_block(em, inode->i_block[EXT2_IND_BLOCK], blk_buf) == 0) { uint32_t* ptrs = (uint32_t*)blk_buf; for (uint32_t i = 0; i < ptrs_per_block; i++) { - if (ptrs[i]) ext2_free_block(ptrs[i]); + if (ptrs[i]) ext2_free_block(em, ptrs[i]); } } - ext2_free_block(inode->i_block[EXT2_IND_BLOCK]); + ext2_free_block(em, inode->i_block[EXT2_IND_BLOCK]); inode->i_block[EXT2_IND_BLOCK] = 0; } /* Doubly indirect */ if (inode->i_block[EXT2_DIND_BLOCK]) { uint8_t blk_buf[4096]; - if (ext2_read_block(inode->i_block[EXT2_DIND_BLOCK], blk_buf) == 0) { + if (ext2_read_block(em, inode->i_block[EXT2_DIND_BLOCK], blk_buf) == 0) { uint32_t* l1 = (uint32_t*)blk_buf; for (uint32_t i = 0; i < ptrs_per_block; i++) { if (l1[i]) { uint8_t blk2[4096]; - if (ext2_read_block(l1[i], blk2) == 0) { + if (ext2_read_block(em, l1[i], blk2) == 0) { uint32_t* l2 = (uint32_t*)blk2; for (uint32_t j = 0; j < ptrs_per_block; j++) { - if (l2[j]) ext2_free_block(l2[j]); + if (l2[j]) ext2_free_block(em, l2[j]); } } - ext2_free_block(l1[i]); + ext2_free_block(em, l1[i]); } } } - ext2_free_block(inode->i_block[EXT2_DIND_BLOCK]); + ext2_free_block(em, inode->i_block[EXT2_DIND_BLOCK]); inode->i_block[EXT2_DIND_BLOCK] = 0; } /* Triply indirect — free top level only for safety */ if (inode->i_block[EXT2_TIND_BLOCK]) { - ext2_free_block(inode->i_block[EXT2_TIND_BLOCK]); + ext2_free_block(em, inode->i_block[EXT2_TIND_BLOCK]); inode->i_block[EXT2_TIND_BLOCK] = 0; } @@ -570,13 +579,13 @@ static const struct inode_operations ext2_dir_iops = { static void ext2_close_impl(fs_node_t* node) { if (!node) return; struct ext2_node* en = (struct ext2_node*)node; - if (en == &g_ext2_root) return; kfree(en); } -static struct ext2_node* ext2_make_node(uint32_t ino, const struct ext2_inode* inode, const char* name) { +static struct ext2_node* ext2_make_node(struct ext2_mount* em, uint32_t ino, const struct ext2_inode* inode, const char* name) { struct ext2_node* en = (struct ext2_node*)kmalloc(sizeof(struct ext2_node)); if (!en) return NULL; + en->mount = em; memset(en, 0, sizeof(*en)); en->ino = ino; @@ -618,16 +627,18 @@ static struct ext2_node* ext2_make_node(uint32_t ino, const struct ext2_inode* i static uint32_t ext2_file_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) { if (!node || !buffer) return 0; struct ext2_node* en = (struct ext2_node*)node; + struct ext2_mount* em = en->mount; + if (!em) return 0; struct ext2_inode inode; - if (ext2_read_inode(en->ino, &inode) < 0) return 0; + if (ext2_read_inode(em, en->ino, &inode) < 0) return 0; uint32_t file_size = inode.i_size; if (offset >= file_size) return 0; if (offset + size > file_size) size = file_size - offset; if (size == 0) return 0; - uint32_t bs = g_ext2.block_size; + uint32_t bs = em->block_size; uint32_t total = 0; while (total < size) { @@ -637,11 +648,11 @@ static uint32_t ext2_file_read(fs_node_t* node, uint32_t offset, uint32_t size, uint32_t chunk = bs - offset_in_block; if (chunk > size - total) chunk = size - total; - uint32_t phys_block = ext2_block_map(&inode, logical_block); + uint32_t phys_block = ext2_block_map(em, &inode, logical_block); if (phys_block == 0) break; uint8_t blk_buf[4096]; - if (ext2_read_block(phys_block, blk_buf) < 0) break; + if (ext2_read_block(em, phys_block, blk_buf) < 0) break; memcpy(buffer + total, blk_buf + offset_in_block, chunk); total += chunk; } @@ -654,14 +665,16 @@ static uint32_t ext2_file_read(fs_node_t* node, uint32_t offset, uint32_t size, static uint32_t ext2_file_write(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer) { if (!node || !buffer || size == 0) return 0; struct ext2_node* en = (struct ext2_node*)node; + struct ext2_mount* em = en->mount; + if (!em) return 0; struct ext2_inode inode; - if (ext2_read_inode(en->ino, &inode) < 0) return 0; + if (ext2_read_inode(em, en->ino, &inode) < 0) return 0; uint64_t end64 = (uint64_t)offset + (uint64_t)size; if (end64 > 0xFFFFFFFFULL) return 0; - uint32_t bs = g_ext2.block_size; + uint32_t bs = em->block_size; uint32_t total = 0; while (total < size) { @@ -671,32 +684,32 @@ static uint32_t ext2_file_write(fs_node_t* node, uint32_t offset, uint32_t size, uint32_t chunk = bs - offset_in_block; if (chunk > size - total) chunk = size - total; - uint32_t phys_block = ext2_block_map(&inode, logical_block); + uint32_t phys_block = ext2_block_map(em, &inode, logical_block); if (phys_block == 0) { /* Need to allocate a new block */ - phys_block = ext2_alloc_block(); + phys_block = ext2_alloc_block(em); if (phys_block == 0) break; - if (ext2_block_map_set(en->ino, &inode, logical_block, phys_block) < 0) { - ext2_free_block(phys_block); + if (ext2_block_map_set(em, en->ino, &inode, logical_block, phys_block) < 0) { + ext2_free_block(em, phys_block); break; } - inode.i_blocks += g_ext2.block_size / EXT2_SECTOR_SIZE; - (void)ext2_write_inode(en->ino, &inode); + inode.i_blocks += em->block_size / EXT2_SECTOR_SIZE; + (void)ext2_write_inode(em, en->ino, &inode); } uint8_t blk_buf[4096]; if (offset_in_block != 0 || chunk != bs) { - if (ext2_read_block(phys_block, blk_buf) < 0) break; + if (ext2_read_block(em, phys_block, blk_buf) < 0) break; } memcpy(blk_buf + offset_in_block, buffer + total, chunk); - if (ext2_write_block(phys_block, blk_buf) < 0) break; + if (ext2_write_block(em, phys_block, blk_buf) < 0) break; total += chunk; } if (offset + total > inode.i_size) { inode.i_size = offset + total; } - (void)ext2_write_inode(en->ino, &inode); + (void)ext2_write_inode(em, en->ino, &inode); node->length = inode.i_size; return total; @@ -707,22 +720,24 @@ static uint32_t ext2_file_write(fs_node_t* node, uint32_t offset, uint32_t size, static fs_node_t* ext2_finddir(fs_node_t* node, const char* name) { if (!node || !name) return NULL; struct ext2_node* en = (struct ext2_node*)node; + struct ext2_mount* em = en->mount; + if (!em) return NULL; struct ext2_inode dir_inode; - if (ext2_read_inode(en->ino, &dir_inode) < 0) return NULL; + if (ext2_read_inode(em, en->ino, &dir_inode) < 0) return NULL; if ((dir_inode.i_mode & 0xF000) != EXT2_S_IFDIR) return NULL; uint32_t dir_size = dir_inode.i_size; - uint32_t bs = g_ext2.block_size; + uint32_t bs = em->block_size; uint32_t name_len = strlen(name); for (uint32_t pos = 0; pos < dir_size; ) { uint32_t logical = pos / bs; - uint32_t phys = ext2_block_map(&dir_inode, logical); + uint32_t phys = ext2_block_map(em, &dir_inode, logical); if (phys == 0) break; uint8_t blk_buf[4096]; - if (ext2_read_block(phys, blk_buf) < 0) break; + if (ext2_read_block(em, phys, blk_buf) < 0) break; uint32_t off = pos % bs; while (off < bs && pos < dir_size) { @@ -732,12 +747,12 @@ static fs_node_t* ext2_finddir(fs_node_t* node, const char* name) { if (de->inode != 0 && de->name_len == name_len) { if (memcmp(de->name, name, name_len) == 0) { struct ext2_inode child_inode; - if (ext2_read_inode(de->inode, &child_inode) < 0) return NULL; + if (ext2_read_inode(em, de->inode, &child_inode) < 0) return NULL; char child_name[128]; if (name_len >= sizeof(child_name)) name_len = sizeof(child_name) - 1; memcpy(child_name, name, name_len); child_name[name_len] = '\0'; - return (fs_node_t*)ext2_make_node(de->inode, &child_inode, child_name); + return (fs_node_t*)ext2_make_node(em, de->inode, &child_inode, child_name); } } @@ -760,11 +775,14 @@ static int ext2_readdir_impl(struct fs_node* node, uint32_t* inout_index, void* if (buf_len < sizeof(struct vfs_dirent)) return -1; struct ext2_node* en = (struct ext2_node*)node; + struct ext2_mount* em = en->mount; + if (!em) return -1; + struct ext2_inode dir_inode; - if (ext2_read_inode(en->ino, &dir_inode) < 0) return -1; + if (ext2_read_inode(em, en->ino, &dir_inode) < 0) return -1; uint32_t dir_size = dir_inode.i_size; - uint32_t bs = g_ext2.block_size; + uint32_t bs = em->block_size; uint32_t idx = *inout_index; uint32_t cap = buf_len / (uint32_t)sizeof(struct vfs_dirent); struct vfs_dirent* out = (struct vfs_dirent*)buf; @@ -773,11 +791,11 @@ static int ext2_readdir_impl(struct fs_node* node, uint32_t* inout_index, void* for (uint32_t pos = 0; pos < dir_size && written < cap; ) { uint32_t logical = pos / bs; - uint32_t phys = ext2_block_map(&dir_inode, logical); + uint32_t phys = ext2_block_map(em, &dir_inode, logical); if (phys == 0) break; uint8_t blk_buf[4096]; - if (ext2_read_block(phys, blk_buf) < 0) break; + if (ext2_read_block(em, phys, blk_buf) < 0) break; uint32_t off = pos % bs; while (off < bs && pos < dir_size && written < cap) { @@ -823,11 +841,12 @@ done: /* ---- Directory entry add/remove helpers ---- */ /* Add a directory entry (name → ino) to a directory inode. */ -static int ext2_dir_add_entry(uint32_t dir_ino, const char* name, uint32_t child_ino, uint8_t file_type) { +static int ext2_dir_add_entry(struct ext2_mount* em, uint32_t dir_ino, const char* name, uint32_t child_ino, uint8_t file_type) { + if (!em) return -EINVAL; struct ext2_inode dir_inode; - if (ext2_read_inode(dir_ino, &dir_inode) < 0) return -EIO; + if (ext2_read_inode(em, dir_ino, &dir_inode) < 0) return -EIO; - uint32_t bs = g_ext2.block_size; + uint32_t bs = em->block_size; uint32_t dir_size = dir_inode.i_size; uint32_t name_len = strlen(name); uint32_t needed = ((uint32_t)sizeof(struct ext2_dir_entry) + name_len + 3) & ~3U; /* 4-byte aligned */ @@ -835,11 +854,11 @@ static int ext2_dir_add_entry(uint32_t dir_ino, const char* name, uint32_t child /* Scan existing blocks for space */ for (uint32_t pos = 0; pos < dir_size; ) { uint32_t logical = pos / bs; - uint32_t phys = ext2_block_map(&dir_inode, logical); + uint32_t phys = ext2_block_map(em, &dir_inode, logical); if (phys == 0) break; uint8_t blk_buf[4096]; - if (ext2_read_block(phys, blk_buf) < 0) return -EIO; + if (ext2_read_block(em, phys, blk_buf) < 0) return -EIO; uint32_t off = 0; while (off < bs) { @@ -855,7 +874,7 @@ static int ext2_dir_add_entry(uint32_t dir_ino, const char* name, uint32_t child de->name_len = (uint8_t)name_len; de->file_type = file_type; memcpy(de->name, name, name_len); - return ext2_write_block(phys, blk_buf); + return ext2_write_block(em, phys, blk_buf); } if (free_space >= needed) { @@ -867,7 +886,7 @@ static int ext2_dir_add_entry(uint32_t dir_ino, const char* name, uint32_t child new_de->name_len = (uint8_t)name_len; new_de->file_type = file_type; memcpy(new_de->name, name, name_len); - return ext2_write_block(phys, blk_buf); + return ext2_write_block(em, phys, blk_buf); } off += de->rec_len; @@ -876,17 +895,17 @@ static int ext2_dir_add_entry(uint32_t dir_ino, const char* name, uint32_t child } /* Need a new block for the directory */ - uint32_t new_block = ext2_alloc_block(); + uint32_t new_block = ext2_alloc_block(em); if (new_block == 0) return -ENOSPC; uint32_t new_logical = dir_size / bs; - if (ext2_block_map_set(dir_ino, &dir_inode, new_logical, new_block) < 0) { - ext2_free_block(new_block); + if (ext2_block_map_set(em, dir_ino, &dir_inode, new_logical, new_block) < 0) { + ext2_free_block(em, new_block); return -EIO; } dir_inode.i_size += bs; dir_inode.i_blocks += bs / EXT2_SECTOR_SIZE; - (void)ext2_write_inode(dir_ino, &dir_inode); + (void)ext2_write_inode(em, dir_ino, &dir_inode); uint8_t blk_buf[4096]; memset(blk_buf, 0, bs); @@ -896,25 +915,26 @@ static int ext2_dir_add_entry(uint32_t dir_ino, const char* name, uint32_t child de->name_len = (uint8_t)name_len; de->file_type = file_type; memcpy(de->name, name, name_len); - return ext2_write_block(new_block, blk_buf); + return ext2_write_block(em, new_block, blk_buf); } /* Remove a directory entry by name. Returns the removed inode number. */ -static int ext2_dir_remove_entry(uint32_t dir_ino, const char* name, uint32_t* removed_ino) { +static int ext2_dir_remove_entry(struct ext2_mount* em, uint32_t dir_ino, const char* name, uint32_t* removed_ino) { + if (!em) return -EINVAL; struct ext2_inode dir_inode; - if (ext2_read_inode(dir_ino, &dir_inode) < 0) return -EIO; + if (ext2_read_inode(em, dir_ino, &dir_inode) < 0) return -EIO; - uint32_t bs = g_ext2.block_size; + uint32_t bs = em->block_size; uint32_t dir_size = dir_inode.i_size; uint32_t name_len = strlen(name); for (uint32_t pos = 0; pos < dir_size; ) { uint32_t logical = pos / bs; - uint32_t phys = ext2_block_map(&dir_inode, logical); + uint32_t phys = ext2_block_map(em, &dir_inode, logical); if (phys == 0) break; uint8_t blk_buf[4096]; - if (ext2_read_block(phys, blk_buf) < 0) return -EIO; + if (ext2_read_block(em, phys, blk_buf) < 0) return -EIO; uint32_t off = 0; uint32_t prev_off = 0; @@ -936,7 +956,7 @@ static int ext2_dir_remove_entry(uint32_t dir_ino, const char* name, uint32_t* r struct ext2_dir_entry* prev = (struct ext2_dir_entry*)(blk_buf + prev_off); prev->rec_len += de->rec_len; } - return ext2_write_block(phys, blk_buf); + return ext2_write_block(em, phys, blk_buf); } prev_off = off; @@ -949,21 +969,22 @@ static int ext2_dir_remove_entry(uint32_t dir_ino, const char* name, uint32_t* r } /* Find a directory entry by name, return its inode number. */ -static int ext2_dir_find(uint32_t dir_ino, const char* name, uint32_t* out_ino) { +static int ext2_dir_find(struct ext2_mount* em, uint32_t dir_ino, const char* name, uint32_t* out_ino) { + if (!em) return -EINVAL; struct ext2_inode dir_inode; - if (ext2_read_inode(dir_ino, &dir_inode) < 0) return -EIO; + if (ext2_read_inode(em, dir_ino, &dir_inode) < 0) return -EIO; - uint32_t bs = g_ext2.block_size; + uint32_t bs = em->block_size; uint32_t dir_size = dir_inode.i_size; uint32_t name_len = strlen(name); for (uint32_t pos = 0; pos < dir_size; ) { uint32_t logical = pos / bs; - uint32_t phys = ext2_block_map(&dir_inode, logical); + uint32_t phys = ext2_block_map(em, &dir_inode, logical); if (phys == 0) break; uint8_t blk_buf[4096]; - if (ext2_read_block(phys, blk_buf) < 0) return -EIO; + if (ext2_read_block(em, phys, blk_buf) < 0) return -EIO; uint32_t off = pos % bs; while (off < bs) { @@ -986,20 +1007,21 @@ not_found: } /* Check if a directory is empty (only . and .. entries). */ -static int ext2_dir_is_empty(uint32_t dir_ino) { +static int ext2_dir_is_empty(struct ext2_mount* em, uint32_t dir_ino) { + if (!em) return 0; struct ext2_inode dir_inode; - if (ext2_read_inode(dir_ino, &dir_inode) < 0) return 0; + if (ext2_read_inode(em, dir_ino, &dir_inode) < 0) return 0; - uint32_t bs = g_ext2.block_size; + uint32_t bs = em->block_size; uint32_t dir_size = dir_inode.i_size; for (uint32_t pos = 0; pos < dir_size; ) { uint32_t logical = pos / bs; - uint32_t phys = ext2_block_map(&dir_inode, logical); + uint32_t phys = ext2_block_map(em, &dir_inode, logical); if (phys == 0) break; uint8_t blk_buf[4096]; - if (ext2_read_block(phys, blk_buf) < 0) return 0; + if (ext2_read_block(em, phys, blk_buf) < 0) return 0; uint32_t off = 0; while (off < bs) { @@ -1025,23 +1047,25 @@ static int ext2_create_impl(struct fs_node* dir, const char* name, uint32_t flag if (!dir || !name || !out) return -EINVAL; *out = NULL; struct ext2_node* parent = (struct ext2_node*)dir; + struct ext2_mount* em = parent->mount; + if (!em) return -EIO; /* Check if exists */ uint32_t existing_ino; - int rc = ext2_dir_find(parent->ino, name, &existing_ino); + int rc = ext2_dir_find(em, parent->ino, name, &existing_ino); if (rc == 0) { struct ext2_inode existing; - if (ext2_read_inode(existing_ino, &existing) < 0) return -EIO; + if (ext2_read_inode(em, existing_ino, &existing) < 0) return -EIO; if ((existing.i_mode & 0xF000) == EXT2_S_IFDIR) return -EISDIR; if ((flags & 0x200U) != 0U) { /* O_TRUNC */ - ext2_free_inode_blocks(&existing); + ext2_free_inode_blocks(em, &existing); existing.i_size = 0; existing.i_blocks = 0; - (void)ext2_write_inode(existing_ino, &existing); + (void)ext2_write_inode(em, existing_ino, &existing); } - struct ext2_node* en = ext2_make_node(existing_ino, &existing, name); + struct ext2_node* en = ext2_make_node(em, existing_ino, &existing, name); if (!en) return -ENOMEM; *out = &en->vfs; return 0; @@ -1050,25 +1074,25 @@ static int ext2_create_impl(struct fs_node* dir, const char* name, uint32_t flag if ((flags & 0x40U) == 0U) return -ENOENT; /* O_CREAT not set */ /* Allocate new inode */ - uint32_t new_ino = ext2_alloc_inode(); + uint32_t new_ino = ext2_alloc_inode(em); if (new_ino == 0) return -ENOSPC; struct ext2_inode new_inode; memset(&new_inode, 0, sizeof(new_inode)); new_inode.i_mode = EXT2_S_IFREG | 0644; new_inode.i_links_count = 1; - if (ext2_write_inode(new_ino, &new_inode) < 0) { - ext2_free_inode(new_ino); + if (ext2_write_inode(em, new_ino, &new_inode) < 0) { + ext2_free_inode(em, new_ino); return -EIO; } - rc = ext2_dir_add_entry(parent->ino, name, new_ino, EXT2_FT_REG_FILE); + rc = ext2_dir_add_entry(em, parent->ino, name, new_ino, EXT2_FT_REG_FILE); if (rc < 0) { - ext2_free_inode(new_ino); + ext2_free_inode(em, new_ino); return rc; } - struct ext2_node* en = ext2_make_node(new_ino, &new_inode, name); + struct ext2_node* en = ext2_make_node(em, new_ino, &new_inode, name); if (!en) return -ENOMEM; *out = &en->vfs; return 0; @@ -1079,35 +1103,37 @@ static int ext2_create_impl(struct fs_node* dir, const char* name, uint32_t flag static int ext2_mkdir_impl(struct fs_node* dir, const char* name) { if (!dir || !name) return -EINVAL; struct ext2_node* parent = (struct ext2_node*)dir; + struct ext2_mount* em = parent->mount; + if (!em) return -EIO; - if (ext2_dir_find(parent->ino, name, NULL) == 0) return -EEXIST; + if (ext2_dir_find(em, parent->ino, name, NULL) == 0) return -EEXIST; - uint32_t new_ino = ext2_alloc_inode(); + uint32_t new_ino = ext2_alloc_inode(em); if (new_ino == 0) return -ENOSPC; /* Allocate one block for . and .. */ - uint32_t new_block = ext2_alloc_block(); + uint32_t new_block = ext2_alloc_block(em); if (new_block == 0) { - ext2_free_inode(new_ino); + ext2_free_inode(em, new_ino); return -ENOSPC; } struct ext2_inode new_inode; memset(&new_inode, 0, sizeof(new_inode)); new_inode.i_mode = EXT2_S_IFDIR | 0755; - new_inode.i_size = g_ext2.block_size; + new_inode.i_size = em->block_size; new_inode.i_links_count = 2; /* . and parent's entry */ - new_inode.i_blocks = g_ext2.block_size / EXT2_SECTOR_SIZE; + new_inode.i_blocks = em->block_size / EXT2_SECTOR_SIZE; new_inode.i_block[0] = new_block; - if (ext2_write_inode(new_ino, &new_inode) < 0) { - ext2_free_block(new_block); - ext2_free_inode(new_ino); + if (ext2_write_inode(em, new_ino, &new_inode) < 0) { + ext2_free_block(em, new_block); + ext2_free_inode(em, new_ino); return -EIO; } /* Write . and .. entries */ uint8_t blk_buf[4096]; - memset(blk_buf, 0, g_ext2.block_size); + memset(blk_buf, 0, em->block_size); struct ext2_dir_entry* dot = (struct ext2_dir_entry*)blk_buf; dot->inode = new_ino; @@ -1118,38 +1144,38 @@ static int ext2_mkdir_impl(struct fs_node* dir, const char* name) { struct ext2_dir_entry* dotdot = (struct ext2_dir_entry*)(blk_buf + 12); dotdot->inode = parent->ino; - dotdot->rec_len = (uint16_t)(g_ext2.block_size - 12); + dotdot->rec_len = (uint16_t)(em->block_size - 12); dotdot->name_len = 2; dotdot->file_type = EXT2_FT_DIR; dotdot->name[0] = '.'; dotdot->name[1] = '.'; - if (ext2_write_block(new_block, blk_buf) < 0) { - ext2_free_block(new_block); - ext2_free_inode(new_ino); + if (ext2_write_block(em, new_block, blk_buf) < 0) { + ext2_free_block(em, new_block); + ext2_free_inode(em, new_ino); return -EIO; } /* Add entry in parent */ - int rc = ext2_dir_add_entry(parent->ino, name, new_ino, EXT2_FT_DIR); + int rc = ext2_dir_add_entry(em, parent->ino, name, new_ino, EXT2_FT_DIR); if (rc < 0) { - ext2_free_block(new_block); - ext2_free_inode(new_ino); + ext2_free_block(em, new_block); + ext2_free_inode(em, new_ino); return rc; } /* Increment parent link count (for ..) */ struct ext2_inode parent_inode; - if (ext2_read_inode(parent->ino, &parent_inode) == 0) { + if (ext2_read_inode(em, parent->ino, &parent_inode) == 0) { parent_inode.i_links_count++; - (void)ext2_write_inode(parent->ino, &parent_inode); + (void)ext2_write_inode(em, parent->ino, &parent_inode); } /* Update group used_dirs_count */ - uint32_t g = (new_ino - 1) / g_ext2.inodes_per_group; - if (g < g_ext2.num_groups) { - g_ext2.gdt[g].bg_used_dirs_count++; - (void)ext2_write_gdt(); + uint32_t g = (new_ino - 1) / em->inodes_per_group; + if (g < em->num_groups) { + em->gdt[g].bg_used_dirs_count++; + (void)ext2_write_gdt(em); } return 0; @@ -1160,21 +1186,23 @@ static int ext2_mkdir_impl(struct fs_node* dir, const char* name) { static int ext2_unlink_impl(struct fs_node* dir, const char* name) { if (!dir || !name) return -EINVAL; struct ext2_node* parent = (struct ext2_node*)dir; + struct ext2_mount* em = parent->mount; + if (!em) return -EIO; uint32_t child_ino; - int rc = ext2_dir_remove_entry(parent->ino, name, &child_ino); + int rc = ext2_dir_remove_entry(em, parent->ino, name, &child_ino); if (rc < 0) return rc; struct ext2_inode child; - if (ext2_read_inode(child_ino, &child) < 0) return -EIO; + if (ext2_read_inode(em, child_ino, &child) < 0) return -EIO; if ((child.i_mode & 0xF000) == EXT2_S_IFDIR) return -EISDIR; child.i_links_count--; if (child.i_links_count == 0) { - ext2_free_inode_blocks(&child); - ext2_free_inode(child_ino); + ext2_free_inode_blocks(em, &child); + ext2_free_inode(em, child_ino); } - return ext2_write_inode(child_ino, &child); + return ext2_write_inode(em, child_ino, &child); } /* ---- VFS: rmdir ---- */ @@ -1182,38 +1210,40 @@ static int ext2_unlink_impl(struct fs_node* dir, const char* name) { static int ext2_rmdir_impl(struct fs_node* dir, const char* name) { if (!dir || !name) return -EINVAL; struct ext2_node* parent = (struct ext2_node*)dir; + struct ext2_mount* em = parent->mount; + if (!em) return -EIO; uint32_t child_ino; - int rc = ext2_dir_find(parent->ino, name, &child_ino); + int rc = ext2_dir_find(em, parent->ino, name, &child_ino); if (rc < 0) return rc; struct ext2_inode child; - if (ext2_read_inode(child_ino, &child) < 0) return -EIO; + if (ext2_read_inode(em, child_ino, &child) < 0) return -EIO; if ((child.i_mode & 0xF000) != EXT2_S_IFDIR) return -ENOTDIR; - if (!ext2_dir_is_empty(child_ino)) return -ENOTEMPTY; + if (!ext2_dir_is_empty(em, child_ino)) return -ENOTEMPTY; /* Remove entry from parent */ - rc = ext2_dir_remove_entry(parent->ino, name, NULL); + rc = ext2_dir_remove_entry(em, parent->ino, name, NULL); if (rc < 0) return rc; /* Free directory blocks and inode */ - ext2_free_inode_blocks(&child); + ext2_free_inode_blocks(em, &child); child.i_links_count = 0; - (void)ext2_write_inode(child_ino, &child); - ext2_free_inode(child_ino); + (void)ext2_write_inode(em, child_ino, &child); + ext2_free_inode(em, child_ino); /* Decrement parent link count (child's ".." pointed to parent) */ struct ext2_inode parent_inode; - if (ext2_read_inode(parent->ino, &parent_inode) == 0) { + if (ext2_read_inode(em, parent->ino, &parent_inode) == 0) { if (parent_inode.i_links_count > 0) parent_inode.i_links_count--; - (void)ext2_write_inode(parent->ino, &parent_inode); + (void)ext2_write_inode(em, parent->ino, &parent_inode); } - uint32_t g = (child_ino - 1) / g_ext2.inodes_per_group; - if (g < g_ext2.num_groups && g_ext2.gdt[g].bg_used_dirs_count > 0) { - g_ext2.gdt[g].bg_used_dirs_count--; - (void)ext2_write_gdt(); + uint32_t g = (child_ino - 1) / em->inodes_per_group; + if (g < em->num_groups && em->gdt[g].bg_used_dirs_count > 0) { + em->gdt[g].bg_used_dirs_count--; + (void)ext2_write_gdt(em); } return 0; @@ -1226,67 +1256,69 @@ static int ext2_rename_impl(struct fs_node* old_dir, const char* old_name, if (!old_dir || !old_name || !new_dir || !new_name) return -EINVAL; struct ext2_node* odir = (struct ext2_node*)old_dir; struct ext2_node* ndir = (struct ext2_node*)new_dir; + struct ext2_mount* em = odir->mount; + if (!em) return -EIO; /* Find source */ uint32_t src_ino; - int rc = ext2_dir_find(odir->ino, old_name, &src_ino); + int rc = ext2_dir_find(em, odir->ino, old_name, &src_ino); if (rc < 0) return rc; struct ext2_inode src_inode; - if (ext2_read_inode(src_ino, &src_inode) < 0) return -EIO; + if (ext2_read_inode(em, src_ino, &src_inode) < 0) return -EIO; uint8_t ft = ((src_inode.i_mode & 0xF000) == EXT2_S_IFDIR) ? EXT2_FT_DIR : EXT2_FT_REG_FILE; /* Remove destination if exists */ uint32_t dst_ino; - rc = ext2_dir_find(ndir->ino, new_name, &dst_ino); + rc = ext2_dir_find(em, ndir->ino, new_name, &dst_ino); if (rc == 0 && dst_ino != src_ino) { struct ext2_inode dst_inode; - if (ext2_read_inode(dst_ino, &dst_inode) == 0) { - (void)ext2_dir_remove_entry(ndir->ino, new_name, NULL); + if (ext2_read_inode(em, dst_ino, &dst_inode) == 0) { + (void)ext2_dir_remove_entry(em, ndir->ino, new_name, NULL); dst_inode.i_links_count--; if (dst_inode.i_links_count == 0) { - ext2_free_inode_blocks(&dst_inode); - ext2_free_inode(dst_ino); + ext2_free_inode_blocks(em, &dst_inode); + ext2_free_inode(em, dst_ino); } - (void)ext2_write_inode(dst_ino, &dst_inode); + (void)ext2_write_inode(em, dst_ino, &dst_inode); } } /* Remove from old dir */ - (void)ext2_dir_remove_entry(odir->ino, old_name, NULL); + (void)ext2_dir_remove_entry(em, odir->ino, old_name, NULL); /* Add to new dir */ - rc = ext2_dir_add_entry(ndir->ino, new_name, src_ino, ft); + rc = ext2_dir_add_entry(em, ndir->ino, new_name, src_ino, ft); if (rc < 0) return rc; /* If moving a directory, update ".." to point to new parent */ if (ft == EXT2_FT_DIR && odir->ino != ndir->ino) { /* Update ".." entry in moved dir */ struct ext2_inode moved; - if (ext2_read_inode(src_ino, &moved) == 0 && moved.i_block[0] != 0) { + if (ext2_read_inode(em, src_ino, &moved) == 0 && moved.i_block[0] != 0) { uint8_t blk_buf[4096]; - if (ext2_read_block(moved.i_block[0], blk_buf) == 0) { + if (ext2_read_block(em, moved.i_block[0], blk_buf) == 0) { /* ".." is typically the second entry */ struct ext2_dir_entry* dot = (struct ext2_dir_entry*)blk_buf; struct ext2_dir_entry* dotdot = (struct ext2_dir_entry*)(blk_buf + dot->rec_len); if (dotdot->name_len == 2 && dotdot->name[0] == '.' && dotdot->name[1] == '.') { dotdot->inode = ndir->ino; - (void)ext2_write_block(moved.i_block[0], blk_buf); + (void)ext2_write_block(em, moved.i_block[0], blk_buf); } } } /* Adjust link counts */ struct ext2_inode old_parent; - if (ext2_read_inode(odir->ino, &old_parent) == 0) { + if (ext2_read_inode(em, odir->ino, &old_parent) == 0) { if (old_parent.i_links_count > 0) old_parent.i_links_count--; - (void)ext2_write_inode(odir->ino, &old_parent); + (void)ext2_write_inode(em, odir->ino, &old_parent); } struct ext2_inode new_parent; - if (ext2_read_inode(ndir->ino, &new_parent) == 0) { + if (ext2_read_inode(em, ndir->ino, &new_parent) == 0) { new_parent.i_links_count++; - (void)ext2_write_inode(ndir->ino, &new_parent); + (void)ext2_write_inode(em, ndir->ino, &new_parent); } } @@ -1298,21 +1330,23 @@ static int ext2_rename_impl(struct fs_node* old_dir, const char* old_name, static int ext2_truncate_impl(struct fs_node* node, uint32_t length) { if (!node) return -EINVAL; struct ext2_node* en = (struct ext2_node*)node; + struct ext2_mount* em = en->mount; + if (!em) return -EIO; struct ext2_inode inode; - if (ext2_read_inode(en->ino, &inode) < 0) return -EIO; + if (ext2_read_inode(em, en->ino, &inode) < 0) return -EIO; if (length >= inode.i_size) return 0; /* only shrink */ - uint32_t bs = g_ext2.block_size; + uint32_t bs = em->block_size; uint32_t new_blocks = (length + bs - 1) / bs; uint32_t old_blocks = (inode.i_size + bs - 1) / bs; /* Free blocks beyond new size */ for (uint32_t b = new_blocks; b < old_blocks; b++) { - uint32_t phys = ext2_block_map(&inode, b); + uint32_t phys = ext2_block_map(em, &inode, b); if (phys != 0) { - ext2_free_block(phys); + ext2_free_block(em, phys); /* Note: we don't zero out the pointer in the inode for simplicity, * since the size field prevents access to freed blocks. */ } @@ -1320,7 +1354,7 @@ static int ext2_truncate_impl(struct fs_node* node, uint32_t length) { inode.i_size = length; inode.i_blocks = new_blocks * (bs / EXT2_SECTOR_SIZE); - (void)ext2_write_inode(en->ino, &inode); + (void)ext2_write_inode(em, en->ino, &inode); node->length = length; return 0; } @@ -1331,19 +1365,21 @@ static int ext2_link_impl(struct fs_node* dir, const char* name, struct fs_node* if (!dir || !name || !target) return -EINVAL; struct ext2_node* parent = (struct ext2_node*)dir; struct ext2_node* src = (struct ext2_node*)target; + struct ext2_mount* em = parent->mount; + if (!em) return -EIO; /* Check doesn't already exist */ - if (ext2_dir_find(parent->ino, name, NULL) == 0) return -EEXIST; + if (ext2_dir_find(em, parent->ino, name, NULL) == 0) return -EEXIST; struct ext2_inode src_inode; - if (ext2_read_inode(src->ino, &src_inode) < 0) return -EIO; + if (ext2_read_inode(em, src->ino, &src_inode) < 0) return -EIO; if ((src_inode.i_mode & 0xF000) == EXT2_S_IFDIR) return -EPERM; - int rc = ext2_dir_add_entry(parent->ino, name, src->ino, EXT2_FT_REG_FILE); + int rc = ext2_dir_add_entry(em, parent->ino, name, src->ino, EXT2_FT_REG_FILE); if (rc < 0) return rc; src_inode.i_links_count++; - return ext2_write_inode(src->ino, &src_inode); + return ext2_write_inode(em, src->ino, &src_inode); } /* ---- Mount ---- */ @@ -1354,96 +1390,122 @@ fs_node_t* ext2_mount(const block_device_t* bdev, uint32_t partition_lba) { return NULL; } - memset(&g_ext2, 0, sizeof(g_ext2)); - g_ext2.bdev = bdev; - g_ext2.drive = bdev->drive_id; - g_ext2.part_lba = partition_lba; + /* Allocate mount structure */ + struct ext2_mount* em = (struct ext2_mount*)kmalloc(sizeof(struct ext2_mount)); + if (!em) { + kprintf("[EXT2] Failed to allocate mount structure\n"); + return NULL; + } + memset(em, 0, sizeof(*em)); + + em->bdev = bdev; + em->drive = bdev->drive_id; + em->part_lba = partition_lba; struct ext2_superblock sb; - if (ext2_read_superblock(&sb) < 0) { + if (ext2_read_superblock(em, &sb) < 0) { kprintf("[EXT2] Failed to read superblock\n"); + kfree(em); return NULL; } if (sb.s_magic != EXT2_SUPER_MAGIC) { kprintf("[EXT2] Invalid magic: 0x%x\n", sb.s_magic); + kfree(em); return NULL; } - g_ext2.block_size = 1024U << sb.s_log_block_size; - if (g_ext2.block_size > 4096) { - kprintf("[EXT2] Unsupported block size %u\n", g_ext2.block_size); + em->block_size = 1024U << sb.s_log_block_size; + if (em->block_size > 4096) { + kprintf("[EXT2] Unsupported block size %u\n", em->block_size); + kfree(em); return NULL; } - g_ext2.sectors_per_block = g_ext2.block_size / EXT2_SECTOR_SIZE; - g_ext2.inodes_per_group = sb.s_inodes_per_group; - g_ext2.blocks_per_group = sb.s_blocks_per_group; - g_ext2.first_data_block = sb.s_first_data_block; - g_ext2.total_blocks = sb.s_blocks_count; - g_ext2.total_inodes = sb.s_inodes_count; + em->sectors_per_block = em->block_size / EXT2_SECTOR_SIZE; + em->inodes_per_group = sb.s_inodes_per_group; + em->blocks_per_group = sb.s_blocks_per_group; + em->first_data_block = sb.s_first_data_block; + em->total_blocks = sb.s_blocks_count; + em->total_inodes = sb.s_inodes_count; if (sb.s_rev_level >= 1 && sb.s_inode_size != 0) { - g_ext2.inode_size = sb.s_inode_size; + em->inode_size = sb.s_inode_size; } else { - g_ext2.inode_size = 128; + em->inode_size = 128; } - g_ext2.num_groups = (sb.s_blocks_count + sb.s_blocks_per_group - 1) / sb.s_blocks_per_group; + em->num_groups = (sb.s_blocks_count + sb.s_blocks_per_group - 1) / sb.s_blocks_per_group; /* Read Group Descriptor Table */ - g_ext2.gdt_blocks = (g_ext2.num_groups * (uint32_t)sizeof(struct ext2_group_desc) + - g_ext2.block_size - 1) / g_ext2.block_size; - uint32_t gdt_bytes = g_ext2.num_groups * (uint32_t)sizeof(struct ext2_group_desc); - g_ext2.gdt = (struct ext2_group_desc*)kmalloc(gdt_bytes); - if (!g_ext2.gdt) { + em->gdt_blocks = (em->num_groups * (uint32_t)sizeof(struct ext2_group_desc) + + em->block_size - 1) / em->block_size; + uint32_t gdt_bytes = em->num_groups * (uint32_t)sizeof(struct ext2_group_desc); + em->gdt = (struct ext2_group_desc*)kmalloc(gdt_bytes); + if (!em->gdt) { kprintf("[EXT2] Failed to allocate GDT (%u bytes)\n", gdt_bytes); + kfree(em); return NULL; } - memset(g_ext2.gdt, 0, gdt_bytes); + memset(em->gdt, 0, gdt_bytes); - uint32_t gdt_block = g_ext2.first_data_block + 1; - uint8_t* gp = (uint8_t*)g_ext2.gdt; - for (uint32_t b = 0; b < g_ext2.gdt_blocks; b++) { + uint32_t gdt_block = em->first_data_block + 1; + uint8_t* gp = (uint8_t*)em->gdt; + for (uint32_t b = 0; b < em->gdt_blocks; b++) { uint8_t blk_buf[4096]; - if (ext2_read_block(gdt_block + b, blk_buf) < 0) { + if (ext2_read_block(em, gdt_block + b, blk_buf) < 0) { kprintf("[EXT2] Failed to read GDT block %u\n", gdt_block + b); - kfree(g_ext2.gdt); - g_ext2.gdt = NULL; + kfree(em->gdt); + kfree(em); return NULL; } - uint32_t to_copy = g_ext2.block_size; - if (to_copy > gdt_bytes - b * g_ext2.block_size) - to_copy = gdt_bytes - b * g_ext2.block_size; - memcpy(gp + b * g_ext2.block_size, blk_buf, to_copy); + uint32_t to_copy = em->block_size; + if (to_copy > gdt_bytes - b * em->block_size) + to_copy = gdt_bytes - b * em->block_size; + memcpy(gp + b * em->block_size, blk_buf, to_copy); } /* Read root inode */ struct ext2_inode root_inode; - if (ext2_read_inode(EXT2_ROOT_INO, &root_inode) < 0) { + if (ext2_read_inode(em, EXT2_ROOT_INO, &root_inode) < 0) { kprintf("[EXT2] Failed to read root inode\n"); - kfree(g_ext2.gdt); - g_ext2.gdt = NULL; + kfree(em->gdt); + kfree(em); return NULL; } /* Build root node */ - memset(&g_ext2_root, 0, sizeof(g_ext2_root)); - memcpy(g_ext2_root.vfs.name, "ext2", 5); - g_ext2_root.vfs.flags = FS_DIRECTORY; - g_ext2_root.vfs.inode = EXT2_ROOT_INO; - g_ext2_root.vfs.length = root_inode.i_size; - g_ext2_root.vfs.uid = root_inode.i_uid; - g_ext2_root.vfs.gid = root_inode.i_gid; - g_ext2_root.vfs.mode = root_inode.i_mode; - g_ext2_root.ino = EXT2_ROOT_INO; - g_ext2_root.vfs.f_ops = &ext2_dir_fops; - g_ext2_root.vfs.i_ops = &ext2_dir_iops; - - g_ext2_ready = 1; + struct ext2_node* root = (struct ext2_node*)kmalloc(sizeof(struct ext2_node)); + if (!root) { + kprintf("[EXT2] Failed to allocate root node\n"); + kfree(em->gdt); + kfree(em); + return NULL; + } + memset(root, 0, sizeof(*root)); + root->mount = em; + memcpy(root->vfs.name, "ext2", 5); + root->vfs.flags = FS_DIRECTORY; + root->vfs.inode = EXT2_ROOT_INO; + root->vfs.length = root_inode.i_size; + root->vfs.uid = root_inode.i_uid; + root->vfs.gid = root_inode.i_gid; + root->vfs.mode = root_inode.i_mode; + root->ino = EXT2_ROOT_INO; + root->vfs.f_ops = &ext2_dir_fops; + root->vfs.i_ops = &ext2_dir_iops; kprintf("[EXT2] Mounted at LBA %u (%u blocks, %u inodes, %u groups, %uB/block)\n", - partition_lba, g_ext2.total_blocks, g_ext2.total_inodes, - g_ext2.num_groups, g_ext2.block_size); + partition_lba, em->total_blocks, em->total_inodes, + em->num_groups, em->block_size); + + return &root->vfs; +} - return &g_ext2_root.vfs; +void ext2_umount(struct ext2_mount* em) { + if (em) { + if (em->gdt) { + kfree(em->gdt); + } + kfree(em); + } } diff --git a/src/kernel/fat.c b/src/kernel/fat.c index 102a19db..60875654 100644 --- a/src/kernel/fat.c +++ b/src/kernel/fat.c @@ -81,12 +81,6 @@ struct fat_dirent { #define FAT_DIRENT_SIZE 32 #define FAT_SECTOR_SIZE 512 -enum fat_type { - FAT_TYPE_12 = 12, - FAT_TYPE_16 = 16, - FAT_TYPE_32 = 32, -}; - /* ---- In-memory filesystem state ---- */ struct fat_state { @@ -111,35 +105,34 @@ struct fat_state { /* Per-node private data */ struct fat_node { fs_node_t vfs; + struct fat_mount* mount; /* back-pointer to mount state */ uint32_t first_cluster; /* first cluster of this file/dir */ uint32_t parent_cluster; /* parent directory first cluster (0 = root for FAT12/16) */ uint32_t dir_entry_offset; /* byte offset of dirent within parent dir data */ }; -static struct fat_state g_fat; static struct fat_node g_fat_root; -static int g_fat_ready = 0; static uint8_t g_sec_buf[FAT_SECTOR_SIZE]; /* ---- Low-level sector I/O ---- */ -static int fat_read_sector(uint32_t lba, void* buf) { - if (!g_fat.bdev) return -ENODEV; - return blockdev_read(g_fat.bdev, lba, buf); +static int fat_read_sector(struct fat_mount* fm, uint32_t lba, void* buf) { + if (!fm || !fm->bdev) return -ENODEV; + return blockdev_read(fm->bdev, lba, buf); } -static int fat_write_sector(uint32_t lba, const void* buf) { - if (!g_fat.bdev) return -ENODEV; - return blockdev_write(g_fat.bdev, lba, buf); +static int fat_write_sector(struct fat_mount* fm, uint32_t lba, const void* buf) { + if (!fm || !fm->bdev) return -ENODEV; + return blockdev_write(fm->bdev, lba, buf); } /* ---- FAT table access ---- */ -static uint32_t fat_get_entry(uint32_t cluster) { +static uint32_t fat_get_entry(struct fat_mount* fm, uint32_t cluster) { uint32_t fat_offset; uint32_t val; - switch (g_fat.type) { + switch (fm->type) { case FAT_TYPE_12: fat_offset = cluster + (cluster / 2); /* 1.5 bytes per entry */ break; @@ -153,18 +146,18 @@ static uint32_t fat_get_entry(uint32_t cluster) { return 0x0FFFFFFF; } - uint32_t fat_sector = g_fat.fat_lba + fat_offset / FAT_SECTOR_SIZE; + uint32_t fat_sector = fm->fat_lba + fat_offset / FAT_SECTOR_SIZE; uint32_t offset_in_sec = fat_offset % FAT_SECTOR_SIZE; - if (fat_read_sector(fat_sector, g_sec_buf) < 0) return 0x0FFFFFFF; + if (fat_read_sector(fm, fat_sector, g_sec_buf) < 0) return 0x0FFFFFFF; - switch (g_fat.type) { + switch (fm->type) { case FAT_TYPE_12: if (offset_in_sec == FAT_SECTOR_SIZE - 1) { /* Entry spans two sectors */ val = g_sec_buf[offset_in_sec]; uint8_t sec2[FAT_SECTOR_SIZE]; - if (fat_read_sector(fat_sector + 1, sec2) < 0) return 0x0FFF; + if (fat_read_sector(fm, fat_sector + 1, sec2) < 0) return 0x0FFF; val |= (uint32_t)sec2[0] << 8; } else { val = *(uint16_t*)(g_sec_buf + offset_in_sec); @@ -185,10 +178,10 @@ static uint32_t fat_get_entry(uint32_t cluster) { return 0x0FFFFFFF; } -static int fat_set_entry(uint32_t cluster, uint32_t value) { +static int fat_set_entry(struct fat_mount* fm, uint32_t cluster, uint32_t value) { uint32_t fat_offset; - switch (g_fat.type) { + switch (fm->type) { case FAT_TYPE_12: fat_offset = cluster + (cluster / 2); break; @@ -203,20 +196,20 @@ static int fat_set_entry(uint32_t cluster, uint32_t value) { } /* Write to all FAT copies */ - for (uint8_t f = 0; f < g_fat.num_fats; f++) { - uint32_t fat_base = g_fat.fat_lba + (uint32_t)f * g_fat.fat_size; + for (uint8_t f = 0; f < fm->num_fats; f++) { + uint32_t fat_base = fm->fat_lba + (uint32_t)f * fm->fat_size; uint32_t fat_sector = fat_base + fat_offset / FAT_SECTOR_SIZE; uint32_t offset_in_sec = fat_offset % FAT_SECTOR_SIZE; uint8_t sec[FAT_SECTOR_SIZE]; - if (fat_read_sector(fat_sector, sec) < 0) return -EIO; + if (fat_read_sector(fm, fat_sector, sec) < 0) return -EIO; - switch (g_fat.type) { + switch (fm->type) { case FAT_TYPE_12: if (offset_in_sec == FAT_SECTOR_SIZE - 1) { /* Spans two sectors */ uint8_t sec2[FAT_SECTOR_SIZE]; - if (fat_read_sector(fat_sector + 1, sec2) < 0) return -EIO; + if (fat_read_sector(fm, fat_sector + 1, sec2) < 0) return -EIO; if (cluster & 1) { sec[offset_in_sec] = (sec[offset_in_sec] & 0x0F) | ((value & 0x0F) << 4); sec2[0] = (uint8_t)((value >> 4) & 0xFF); @@ -224,8 +217,8 @@ static int fat_set_entry(uint32_t cluster, uint32_t value) { sec[offset_in_sec] = (uint8_t)(value & 0xFF); sec2[0] = (sec2[0] & 0xF0) | ((value >> 8) & 0x0F); } - if (fat_write_sector(fat_sector, sec) < 0) return -EIO; - if (fat_write_sector(fat_sector + 1, sec2) < 0) return -EIO; + if (fat_write_sector(fm, fat_sector, sec) < 0) return -EIO; + if (fat_write_sector(fm, fat_sector + 1, sec2) < 0) return -EIO; } else { uint16_t* p = (uint16_t*)(sec + offset_in_sec); if (cluster & 1) { @@ -233,19 +226,19 @@ static int fat_set_entry(uint32_t cluster, uint32_t value) { } else { *p = (*p & 0xF000) | ((uint16_t)(value & 0x0FFF)); } - if (fat_write_sector(fat_sector, sec) < 0) return -EIO; + if (fat_write_sector(fm, fat_sector, sec) < 0) return -EIO; } break; case FAT_TYPE_16: *(uint16_t*)(sec + offset_in_sec) = (uint16_t)value; - if (fat_write_sector(fat_sector, sec) < 0) return -EIO; + if (fat_write_sector(fm, fat_sector, sec) < 0) return -EIO; break; case FAT_TYPE_32: { uint32_t* p = (uint32_t*)(sec + offset_in_sec); *p = (*p & 0xF0000000) | (value & 0x0FFFFFFF); - if (fat_write_sector(fat_sector, sec) < 0) return -EIO; + if (fat_write_sector(fm, fat_sector, sec) < 0) return -EIO; break; } } @@ -256,8 +249,8 @@ static int fat_set_entry(uint32_t cluster, uint32_t value) { /* ---- Cluster chain helpers ---- */ -static int fat_is_eoc(uint32_t val) { - switch (g_fat.type) { +static int fat_is_eoc(struct fat_mount* fm, uint32_t val) { + switch (fm->type) { case FAT_TYPE_12: return val >= 0x0FF8; case FAT_TYPE_16: return val >= 0xFFF8; case FAT_TYPE_32: return val >= 0x0FFFFFF8; @@ -265,8 +258,8 @@ static int fat_is_eoc(uint32_t val) { return 1; } -static uint32_t fat_eoc_mark(void) { - switch (g_fat.type) { +static uint32_t fat_eoc_mark(struct fat_mount* fm) { + switch (fm->type) { case FAT_TYPE_12: return 0x0FFF; case FAT_TYPE_16: return 0xFFFF; case FAT_TYPE_32: return 0x0FFFFFFF; @@ -274,48 +267,48 @@ static uint32_t fat_eoc_mark(void) { return 0x0FFFFFFF; } -static uint32_t fat_cluster_to_lba(uint32_t cluster) { - return g_fat.data_lba + (cluster - 2) * g_fat.sectors_per_cluster; +static uint32_t fat_cluster_to_lba(struct fat_mount* fm, uint32_t cluster) { + return fm->data_lba + (cluster - 2) * fm->sectors_per_cluster; } -static uint32_t fat_cluster_size(void) { - return (uint32_t)g_fat.sectors_per_cluster * g_fat.bytes_per_sector; +static uint32_t fat_cluster_size(struct fat_mount* fm) { + return (uint32_t)fm->sectors_per_cluster * fm->bytes_per_sector; } /* Follow cluster chain to the N-th cluster (0-indexed). Returns 0 on failure. */ -static uint32_t fat_follow_chain(uint32_t start, uint32_t n) { +static uint32_t fat_follow_chain(struct fat_mount* fm, uint32_t start, uint32_t n) { uint32_t c = start; for (uint32_t i = 0; i < n; i++) { - if (c < 2 || fat_is_eoc(c)) return 0; - c = fat_get_entry(c); + if (c < 2 || fat_is_eoc(fm, c)) return 0; + c = fat_get_entry(fm, c); } - return (c >= 2 && !fat_is_eoc(c)) ? c : (n == 0 ? start : 0); + return (c >= 2 && !fat_is_eoc(fm, c)) ? c : (n == 0 ? start : 0); } /* Count clusters in chain. */ -static uint32_t fat_chain_length(uint32_t start) { +static uint32_t fat_chain_length(struct fat_mount* fm, uint32_t start) { if (start < 2) return 0; uint32_t count = 0; uint32_t c = start; - while (c >= 2 && !fat_is_eoc(c) && count < g_fat.total_clusters) { + while (c >= 2 && !fat_is_eoc(fm, c) && count < fm->total_clusters) { count++; - c = fat_get_entry(c); + c = fat_get_entry(fm, c); } return count; } /* Allocate one free cluster, mark it as EOC. Returns cluster number or 0. */ -static uint32_t fat_alloc_cluster(void) { - for (uint32_t c = 2; c < g_fat.total_clusters + 2; c++) { - uint32_t val = fat_get_entry(c); +static uint32_t fat_alloc_cluster(struct fat_mount* fm) { + for (uint32_t c = 2; c < fm->total_clusters + 2; c++) { + uint32_t val = fat_get_entry(fm, c); if (val == 0) { - if (fat_set_entry(c, fat_eoc_mark()) < 0) return 0; + if (fat_set_entry(fm, c, fat_eoc_mark(fm)) < 0) return 0; /* Zero out the new cluster data */ uint8_t zero[FAT_SECTOR_SIZE]; memset(zero, 0, sizeof(zero)); - uint32_t lba = fat_cluster_to_lba(c); - for (uint8_t s = 0; s < g_fat.sectors_per_cluster; s++) { - (void)fat_write_sector(lba + s, zero); + uint32_t lba = fat_cluster_to_lba(fm, c); + for (uint8_t s = 0; s < fm->sectors_per_cluster; s++) { + (void)fat_write_sector(fm, lba + s, zero); } return c; } @@ -326,12 +319,12 @@ static uint32_t fat_alloc_cluster(void) { /* Extend a cluster chain to have at least 'need' clusters total. * If start == 0, allocates a new chain. * Returns first cluster of chain, or 0 on failure. */ -static uint32_t fat_extend_chain(uint32_t start, uint32_t need) { +static uint32_t fat_extend_chain(struct fat_mount* fm, uint32_t start, uint32_t need) { if (need == 0) return start; if (start < 2) { /* Allocate first cluster */ - start = fat_alloc_cluster(); + start = fat_alloc_cluster(fm); if (start == 0) return 0; need--; } @@ -339,23 +332,23 @@ static uint32_t fat_extend_chain(uint32_t start, uint32_t need) { /* Find end of existing chain */ uint32_t c = start; uint32_t count = 1; - while (!fat_is_eoc(fat_get_entry(c)) && count < need) { - c = fat_get_entry(c); + while (!fat_is_eoc(fm, fat_get_entry(fm, c)) && count < need) { + c = fat_get_entry(fm, c); count++; } - if (!fat_is_eoc(fat_get_entry(c))) { + if (!fat_is_eoc(fm, fat_get_entry(fm, c))) { /* Chain already long enough, keep following */ - while (!fat_is_eoc(fat_get_entry(c))) { - c = fat_get_entry(c); + while (!fat_is_eoc(fm, fat_get_entry(fm, c))) { + c = fat_get_entry(fm, c); count++; } } /* Allocate more clusters if needed */ while (count < need) { - uint32_t nc = fat_alloc_cluster(); + uint32_t nc = fat_alloc_cluster(fm); if (nc == 0) return 0; - if (fat_set_entry(c, nc) < 0) return 0; + if (fat_set_entry(fm, c, nc) < 0) return 0; c = nc; count++; } @@ -364,15 +357,15 @@ static uint32_t fat_extend_chain(uint32_t start, uint32_t need) { } /* Free a cluster chain starting at 'start'. */ -static void fat_free_chain(uint32_t start) { +static void fat_free_chain(struct fat_mount* fm, uint32_t start) { uint32_t c = start; - while (c >= 2 && !fat_is_eoc(c)) { - uint32_t next = fat_get_entry(c); - (void)fat_set_entry(c, 0); + while (c >= 2 && !fat_is_eoc(fm, c)) { + uint32_t next = fat_get_entry(fm, c); + (void)fat_set_entry(fm, c, 0); c = next; } if (c >= 2) { - (void)fat_set_entry(c, 0); + (void)fat_set_entry(fm, c, 0); } } @@ -381,46 +374,46 @@ static void fat_free_chain(uint32_t start) { /* Read N-th sector of a directory. * For FAT12/16 root dir (cluster==0), reads from fixed root area. * For subdirs / FAT32 root, follows cluster chain. */ -static int fat_dir_read_sector(uint32_t dir_cluster, uint32_t sector_index, void* buf) { - if (dir_cluster == 0 && g_fat.type != FAT_TYPE_32) { +static int fat_dir_read_sector(struct fat_mount* fm, uint32_t dir_cluster, uint32_t sector_index, void* buf) { + if (dir_cluster == 0 && fm->type != FAT_TYPE_32) { /* FAT12/16 fixed root directory */ - if (sector_index >= g_fat.root_dir_sectors) return -1; - return fat_read_sector(g_fat.root_dir_lba + sector_index, buf); + if (sector_index >= fm->root_dir_sectors) return -1; + return fat_read_sector(fm, fm->root_dir_lba + sector_index, buf); } /* Cluster-based directory */ - uint32_t cluster_index = sector_index / g_fat.sectors_per_cluster; - uint32_t sec_in_cluster = sector_index % g_fat.sectors_per_cluster; + uint32_t cluster_index = sector_index / fm->sectors_per_cluster; + uint32_t sec_in_cluster = sector_index % fm->sectors_per_cluster; - uint32_t c = fat_follow_chain(dir_cluster, cluster_index); + uint32_t c = fat_follow_chain(fm, dir_cluster, cluster_index); if (c < 2) return -1; - return fat_read_sector(fat_cluster_to_lba(c) + sec_in_cluster, buf); + return fat_read_sector(fm, fat_cluster_to_lba(fm, c) + sec_in_cluster, buf); } -static int fat_dir_write_sector(uint32_t dir_cluster, uint32_t sector_index, const void* buf) { - if (dir_cluster == 0 && g_fat.type != FAT_TYPE_32) { - if (sector_index >= g_fat.root_dir_sectors) return -1; - return fat_write_sector(g_fat.root_dir_lba + sector_index, buf); +static int fat_dir_write_sector(struct fat_mount* fm, uint32_t dir_cluster, uint32_t sector_index, const void* buf) { + if (dir_cluster == 0 && fm->type != FAT_TYPE_32) { + if (sector_index >= fm->root_dir_sectors) return -1; + return fat_write_sector(fm, fm->root_dir_lba + sector_index, buf); } - uint32_t cluster_index = sector_index / g_fat.sectors_per_cluster; - uint32_t sec_in_cluster = sector_index % g_fat.sectors_per_cluster; + uint32_t cluster_index = sector_index / fm->sectors_per_cluster; + uint32_t sec_in_cluster = sector_index % fm->sectors_per_cluster; - uint32_t c = fat_follow_chain(dir_cluster, cluster_index); + uint32_t c = fat_follow_chain(fm, dir_cluster, cluster_index); if (c < 2) return -1; - return fat_write_sector(fat_cluster_to_lba(c) + sec_in_cluster, buf); + return fat_write_sector(fm, fat_cluster_to_lba(fm, c) + sec_in_cluster, buf); } /* Get total number of directory sectors. * For fixed root: root_dir_sectors. * For cluster-based: chain_length * sectors_per_cluster. */ -static uint32_t fat_dir_total_sectors(uint32_t dir_cluster) { - if (dir_cluster == 0 && g_fat.type != FAT_TYPE_32) { - return g_fat.root_dir_sectors; +static uint32_t fat_dir_total_sectors(struct fat_mount* fm, uint32_t dir_cluster) { + if (dir_cluster == 0 && fm->type != FAT_TYPE_32) { + return fm->root_dir_sectors; } - return fat_chain_length(dir_cluster) * g_fat.sectors_per_cluster; + return fat_chain_length(fm, dir_cluster) * fm->sectors_per_cluster; } /* ---- 8.3 name conversion ---- */ @@ -466,17 +459,17 @@ static void fat_83_to_name(const struct fat_dirent* de, char* out, size_t out_sz out[fi] = '\0'; } -static uint32_t fat_dirent_cluster(const struct fat_dirent* de) { +static uint32_t fat_dirent_cluster(struct fat_mount* fm, const struct fat_dirent* de) { uint32_t cl = de->first_cluster_lo; - if (g_fat.type == FAT_TYPE_32) { + if (fm->type == FAT_TYPE_32) { cl |= (uint32_t)de->first_cluster_hi << 16; } return cl; } -static void fat_dirent_set_cluster(struct fat_dirent* de, uint32_t cl) { +static void fat_dirent_set_cluster(struct fat_mount* fm, struct fat_dirent* de, uint32_t cl) { de->first_cluster_lo = (uint16_t)(cl & 0xFFFF); - if (g_fat.type == FAT_TYPE_32) { + if (fm->type == FAT_TYPE_32) { de->first_cluster_hi = (uint16_t)((cl >> 16) & 0xFFFF); } } @@ -526,13 +519,14 @@ static void fat_close_impl(fs_node_t* node) { kfree(fn); } -static struct fat_node* fat_make_node(const struct fat_dirent* de, uint32_t parent_cluster, uint32_t dirent_offset) { +static struct fat_node* fat_make_node(struct fat_mount* fm, const struct fat_dirent* de, uint32_t parent_cluster, uint32_t dirent_offset) { struct fat_node* fn = (struct fat_node*)kmalloc(sizeof(struct fat_node)); if (!fn) return NULL; memset(fn, 0, sizeof(*fn)); + fn->mount = fm; fat_83_to_name(de, fn->vfs.name, sizeof(fn->vfs.name)); - fn->first_cluster = fat_dirent_cluster(de); + fn->first_cluster = fat_dirent_cluster(fm, de); fn->parent_cluster = parent_cluster; fn->dir_entry_offset = dirent_offset; @@ -558,27 +552,29 @@ static struct fat_node* fat_make_node(const struct fat_dirent* de, uint32_t pare static uint32_t fat_file_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) { if (!node || !buffer) return 0; struct fat_node* fn = (struct fat_node*)node; + struct fat_mount* fm = fn->mount; + if (!fm) return 0; if (offset >= node->length) return 0; if (offset + size > node->length) size = node->length - offset; if (size == 0) return 0; - uint32_t csize = fat_cluster_size(); + uint32_t csize = fat_cluster_size(fm); uint32_t cluster = fn->first_cluster; uint32_t bytes_read = 0; /* Skip to cluster containing 'offset' */ uint32_t skip = offset / csize; - for (uint32_t i = 0; i < skip && cluster >= 2 && !fat_is_eoc(cluster); i++) { - cluster = fat_get_entry(cluster); + for (uint32_t i = 0; i < skip && cluster >= 2 && !fat_is_eoc(fm, cluster); i++) { + cluster = fat_get_entry(fm, cluster); } uint32_t pos_in_cluster = offset % csize; - while (bytes_read < size && cluster >= 2 && !fat_is_eoc(cluster)) { - uint32_t lba = fat_cluster_to_lba(cluster); + while (bytes_read < size && cluster >= 2 && !fat_is_eoc(fm, cluster)) { + uint32_t lba = fat_cluster_to_lba(fm, cluster); for (uint32_t s = pos_in_cluster / FAT_SECTOR_SIZE; - s < g_fat.sectors_per_cluster && bytes_read < size; s++) { + s < fm->sectors_per_cluster && bytes_read < size; s++) { uint8_t sec[FAT_SECTOR_SIZE]; - if (fat_read_sector(lba + s, sec) < 0) return bytes_read; + if (fat_read_sector(fm, lba + s, sec) < 0) return bytes_read; uint32_t off_in_sec = (pos_in_cluster > 0 && s == pos_in_cluster / FAT_SECTOR_SIZE) ? pos_in_cluster % FAT_SECTOR_SIZE : 0; uint32_t to_copy = FAT_SECTOR_SIZE - off_in_sec; @@ -587,7 +583,7 @@ static uint32_t fat_file_read(fs_node_t* node, uint32_t offset, uint32_t size, u bytes_read += to_copy; } pos_in_cluster = 0; - cluster = fat_get_entry(cluster); + cluster = fat_get_entry(fm, cluster); } return bytes_read; @@ -597,33 +593,37 @@ static uint32_t fat_file_read(fs_node_t* node, uint32_t offset, uint32_t size, u /* Update the dirent on disk (file size / first cluster) after a write. */ static int fat_update_dirent(struct fat_node* fn) { + struct fat_mount* fm = fn->mount; + if (!fm) return -EIO; uint32_t sec_idx = fn->dir_entry_offset / FAT_SECTOR_SIZE; uint32_t off_in_sec = fn->dir_entry_offset % FAT_SECTOR_SIZE; uint8_t sec[FAT_SECTOR_SIZE]; - if (fat_dir_read_sector(fn->parent_cluster, sec_idx, sec) < 0) return -EIO; + if (fat_dir_read_sector(fm, fn->parent_cluster, sec_idx, sec) < 0) return -EIO; struct fat_dirent* de = (struct fat_dirent*)(sec + off_in_sec); de->file_size = fn->vfs.length; - fat_dirent_set_cluster(de, fn->first_cluster); + fat_dirent_set_cluster(fm, de, fn->first_cluster); - return fat_dir_write_sector(fn->parent_cluster, sec_idx, sec); + return fat_dir_write_sector(fm, fn->parent_cluster, sec_idx, sec); } static uint32_t fat_file_write(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer) { if (!node || !buffer || size == 0) return 0; struct fat_node* fn = (struct fat_node*)node; + struct fat_mount* fm = fn->mount; + if (!fm) return 0; uint64_t end64 = (uint64_t)offset + (uint64_t)size; if (end64 > 0xFFFFFFFFULL) return 0; uint32_t end = (uint32_t)end64; /* Ensure enough clusters allocated */ - uint32_t csize = fat_cluster_size(); + uint32_t csize = fat_cluster_size(fm); uint32_t need_clusters = (end + csize - 1) / csize; if (need_clusters == 0) need_clusters = 1; - fn->first_cluster = fat_extend_chain(fn->first_cluster, need_clusters); + fn->first_cluster = fat_extend_chain(fm, fn->first_cluster, need_clusters); if (fn->first_cluster == 0) return 0; /* Write data */ @@ -631,15 +631,15 @@ static uint32_t fat_file_write(fs_node_t* node, uint32_t offset, uint32_t size, uint32_t total = 0; uint32_t skip = offset / csize; - for (uint32_t i = 0; i < skip && cluster >= 2 && !fat_is_eoc(cluster); i++) { - cluster = fat_get_entry(cluster); + for (uint32_t i = 0; i < skip && cluster >= 2 && !fat_is_eoc(fm, cluster); i++) { + cluster = fat_get_entry(fm, cluster); } uint32_t pos_in_cluster = offset % csize; - while (total < size && cluster >= 2 && !fat_is_eoc(cluster)) { - uint32_t lba = fat_cluster_to_lba(cluster); + while (total < size && cluster >= 2 && !fat_is_eoc(fm, cluster)) { + uint32_t lba = fat_cluster_to_lba(fm, cluster); for (uint32_t s = pos_in_cluster / FAT_SECTOR_SIZE; - s < g_fat.sectors_per_cluster && total < size; s++) { + s < fm->sectors_per_cluster && total < size; s++) { uint8_t sec[FAT_SECTOR_SIZE]; uint32_t off_in_sec = (pos_in_cluster > 0 && s == pos_in_cluster / FAT_SECTOR_SIZE) ? pos_in_cluster % FAT_SECTOR_SIZE : 0; @@ -648,14 +648,14 @@ static uint32_t fat_file_write(fs_node_t* node, uint32_t offset, uint32_t size, /* Read-modify-write for partial sectors */ if (off_in_sec != 0 || chunk != FAT_SECTOR_SIZE) { - if (fat_read_sector(lba + s, sec) < 0) goto done; + if (fat_read_sector(fm, lba + s, sec) < 0) goto done; } memcpy(sec + off_in_sec, buffer + total, chunk); - if (fat_write_sector(lba + s, sec) < 0) goto done; + if (fat_write_sector(fm, lba + s, sec) < 0) goto done; total += chunk; } pos_in_cluster = 0; - cluster = fat_get_entry(cluster); + cluster = fat_get_entry(fm, cluster); } done: @@ -672,15 +672,17 @@ done: static fs_node_t* fat_finddir(fs_node_t* node, const char* name) { if (!node || !name) return NULL; struct fat_node* dir = (struct fat_node*)node; + struct fat_mount* fm = dir->mount; + if (!fm) return NULL; uint32_t dir_cluster = dir->first_cluster; /* For FAT12/16 root: dir_cluster may be 0 */ - uint32_t total_sec = fat_dir_total_sectors(dir_cluster); + uint32_t total_sec = fat_dir_total_sectors(fm, dir_cluster); uint32_t ents_per_sec = FAT_SECTOR_SIZE / FAT_DIRENT_SIZE; for (uint32_t s = 0; s < total_sec; s++) { uint8_t sec[FAT_SECTOR_SIZE]; - if (fat_dir_read_sector(dir_cluster, s, sec) < 0) return NULL; + if (fat_dir_read_sector(fm, dir_cluster, s, sec) < 0) return NULL; struct fat_dirent* de = (struct fat_dirent*)sec; for (uint32_t i = 0; i < ents_per_sec; i++) { @@ -694,7 +696,7 @@ static fs_node_t* fat_finddir(fs_node_t* node, const char* name) { if (strcmp(fname, name) == 0) { uint32_t dirent_off = s * FAT_SECTOR_SIZE + i * FAT_DIRENT_SIZE; - return (fs_node_t*)fat_make_node(&de[i], dir_cluster, dirent_off); + return (fs_node_t*)fat_make_node(fm, &de[i], dir_cluster, dirent_off); } } } @@ -709,8 +711,10 @@ static int fat_readdir_impl(struct fs_node* node, uint32_t* inout_index, void* b if (buf_len < sizeof(struct vfs_dirent)) return -1; struct fat_node* dir = (struct fat_node*)node; + struct fat_mount* fm = dir->mount; + if (!fm) return -1; uint32_t dir_cluster = dir->first_cluster; - uint32_t total_sec = fat_dir_total_sectors(dir_cluster); + uint32_t total_sec = fat_dir_total_sectors(fm, dir_cluster); uint32_t ents_per_sec = FAT_SECTOR_SIZE / FAT_DIRENT_SIZE; uint32_t idx = *inout_index; @@ -722,7 +726,7 @@ static int fat_readdir_impl(struct fs_node* node, uint32_t* inout_index, void* b uint32_t cur = 0; for (uint32_t s = 0; s < total_sec && written < cap; s++) { uint8_t sec[FAT_SECTOR_SIZE]; - if (fat_dir_read_sector(dir_cluster, s, sec) < 0) break; + if (fat_dir_read_sector(fm, dir_cluster, s, sec) < 0) break; struct fat_dirent* de = (struct fat_dirent*)sec; for (uint32_t i = 0; i < ents_per_sec && written < cap; i++) { @@ -737,7 +741,7 @@ static int fat_readdir_impl(struct fs_node* node, uint32_t* inout_index, void* b if (cur >= idx) { memset(&out[written], 0, sizeof(out[written])); - out[written].d_ino = fat_dirent_cluster(&de[i]); + out[written].d_ino = fat_dirent_cluster(fm, &de[i]); out[written].d_reclen = (uint16_t)sizeof(struct vfs_dirent); out[written].d_type = (de[i].attr & FAT_ATTR_DIRECTORY) ? 2 : 1; fat_83_to_name(&de[i], out[written].d_name, sizeof(out[written].d_name)); @@ -754,18 +758,18 @@ done: /* ---- VFS: create file ---- */ -static int fat_add_dirent(uint32_t dir_cluster, const char* name, uint8_t attr, +static int fat_add_dirent(struct fat_mount* fm, uint32_t dir_cluster, const char* name, uint8_t attr, uint32_t first_cluster, uint32_t file_size, uint32_t* out_offset) { char name83[11]; fat_name_to_83(name, name83); - uint32_t total_sec = fat_dir_total_sectors(dir_cluster); + uint32_t total_sec = fat_dir_total_sectors(fm, dir_cluster); uint32_t ents_per_sec = FAT_SECTOR_SIZE / FAT_DIRENT_SIZE; for (uint32_t s = 0; s < total_sec; s++) { uint8_t sec[FAT_SECTOR_SIZE]; - if (fat_dir_read_sector(dir_cluster, s, sec) < 0) return -EIO; + if (fat_dir_read_sector(fm, dir_cluster, s, sec) < 0) return -EIO; struct fat_dirent* de = (struct fat_dirent*)sec; for (uint32_t i = 0; i < ents_per_sec; i++) { @@ -774,9 +778,9 @@ static int fat_add_dirent(uint32_t dir_cluster, const char* name, uint8_t attr, memcpy(de[i].name, name83, 8); memcpy(de[i].ext, name83 + 8, 3); de[i].attr = attr; - fat_dirent_set_cluster(&de[i], first_cluster); + fat_dirent_set_cluster(fm, &de[i], first_cluster); de[i].file_size = file_size; - if (fat_dir_write_sector(dir_cluster, s, sec) < 0) return -EIO; + if (fat_dir_write_sector(fm, dir_cluster, s, sec) < 0) return -EIO; if (out_offset) *out_offset = s * FAT_SECTOR_SIZE + i * FAT_DIRENT_SIZE; return 0; } @@ -784,40 +788,40 @@ static int fat_add_dirent(uint32_t dir_cluster, const char* name, uint8_t attr, } /* Need to extend directory (only for cluster-based dirs) */ - if (dir_cluster == 0 && g_fat.type != FAT_TYPE_32) { + if (dir_cluster == 0 && fm->type != FAT_TYPE_32) { return -ENOSPC; /* can't extend fixed root */ } /* Extend directory by one cluster */ - uint32_t old_len = fat_chain_length(dir_cluster); - uint32_t new_first = fat_extend_chain(dir_cluster, old_len + 1); + uint32_t old_len = fat_chain_length(fm, dir_cluster); + uint32_t new_first = fat_extend_chain(fm, dir_cluster, old_len + 1); if (new_first == 0) return -ENOSPC; /* Write dirent into first entry of new cluster */ - uint32_t new_sec_idx = old_len * g_fat.sectors_per_cluster; + uint32_t new_sec_idx = old_len * fm->sectors_per_cluster; uint8_t sec[FAT_SECTOR_SIZE]; - if (fat_dir_read_sector(dir_cluster, new_sec_idx, sec) < 0) return -EIO; + if (fat_dir_read_sector(fm, dir_cluster, new_sec_idx, sec) < 0) return -EIO; struct fat_dirent* de = (struct fat_dirent*)sec; memset(&de[0], 0, sizeof(de[0])); memcpy(de[0].name, name83, 8); memcpy(de[0].ext, name83 + 8, 3); de[0].attr = attr; - fat_dirent_set_cluster(&de[0], first_cluster); + fat_dirent_set_cluster(fm, &de[0], first_cluster); de[0].file_size = file_size; - if (fat_dir_write_sector(dir_cluster, new_sec_idx, sec) < 0) return -EIO; + if (fat_dir_write_sector(fm, dir_cluster, new_sec_idx, sec) < 0) return -EIO; if (out_offset) *out_offset = new_sec_idx * FAT_SECTOR_SIZE; return 0; } /* Find dirent by name, returns sector index via sec_idx, entry index in sector via ent_idx */ -static int fat_find_dirent(uint32_t dir_cluster, const char* name, +static int fat_find_dirent(struct fat_mount* fm, uint32_t dir_cluster, const char* name, uint32_t* out_sec_idx, uint32_t* out_ent_idx) { - uint32_t total_sec = fat_dir_total_sectors(dir_cluster); + uint32_t total_sec = fat_dir_total_sectors(fm, dir_cluster); uint32_t ents_per_sec = FAT_SECTOR_SIZE / FAT_DIRENT_SIZE; for (uint32_t s = 0; s < total_sec; s++) { uint8_t sec[FAT_SECTOR_SIZE]; - if (fat_dir_read_sector(dir_cluster, s, sec) < 0) return -EIO; + if (fat_dir_read_sector(fm, dir_cluster, s, sec) < 0) return -EIO; struct fat_dirent* de = (struct fat_dirent*)sec; for (uint32_t i = 0; i < ents_per_sec; i++) { @@ -842,28 +846,30 @@ static int fat_create_impl(struct fs_node* dir, const char* name, uint32_t flags if (!dir || !name || !out) return -EINVAL; *out = NULL; struct fat_node* parent = (struct fat_node*)dir; + struct fat_mount* fm = parent->mount; + if (!fm) return -EIO; uint32_t dir_cluster = parent->first_cluster; /* Check if exists */ uint32_t sec_idx, ent_idx; - int rc = fat_find_dirent(dir_cluster, name, &sec_idx, &ent_idx); + int rc = fat_find_dirent(fm, dir_cluster, name, &sec_idx, &ent_idx); if (rc == 0) { /* Already exists */ uint8_t sec[FAT_SECTOR_SIZE]; - if (fat_dir_read_sector(dir_cluster, sec_idx, sec) < 0) return -EIO; + if (fat_dir_read_sector(fm, dir_cluster, sec_idx, sec) < 0) return -EIO; struct fat_dirent* de = (struct fat_dirent*)sec; if (de[ent_idx].attr & FAT_ATTR_DIRECTORY) return -EISDIR; if ((flags & 0x200U) != 0U) { /* O_TRUNC */ - uint32_t cl = fat_dirent_cluster(&de[ent_idx]); - if (cl >= 2) fat_free_chain(cl); - fat_dirent_set_cluster(&de[ent_idx], 0); + uint32_t cl = fat_dirent_cluster(fm, &de[ent_idx]); + if (cl >= 2) fat_free_chain(fm, cl); + fat_dirent_set_cluster(fm, &de[ent_idx], 0); de[ent_idx].file_size = 0; - if (fat_dir_write_sector(dir_cluster, sec_idx, sec) < 0) return -EIO; + if (fat_dir_write_sector(fm, dir_cluster, sec_idx, sec) < 0) return -EIO; } uint32_t dirent_off = sec_idx * FAT_SECTOR_SIZE + ent_idx * FAT_DIRENT_SIZE; - struct fat_node* fn = fat_make_node(&de[ent_idx], dir_cluster, dirent_off); + struct fat_node* fn = fat_make_node(fm, &de[ent_idx], dir_cluster, dirent_off); if (!fn) return -ENOMEM; *out = &fn->vfs; return 0; @@ -873,16 +879,16 @@ static int fat_create_impl(struct fs_node* dir, const char* name, uint32_t flags /* Create new file */ uint32_t dirent_off = 0; - rc = fat_add_dirent(dir_cluster, name, FAT_ATTR_ARCHIVE, 0, 0, &dirent_off); + rc = fat_add_dirent(fm, dir_cluster, name, FAT_ATTR_ARCHIVE, 0, 0, &dirent_off); if (rc < 0) return rc; /* Read back the dirent to build node */ uint32_t s2 = dirent_off / FAT_SECTOR_SIZE; uint32_t e2 = (dirent_off % FAT_SECTOR_SIZE) / FAT_DIRENT_SIZE; uint8_t sec2[FAT_SECTOR_SIZE]; - if (fat_dir_read_sector(dir_cluster, s2, sec2) < 0) return -EIO; + if (fat_dir_read_sector(fm, dir_cluster, s2, sec2) < 0) return -EIO; struct fat_dirent* de2 = (struct fat_dirent*)sec2; - struct fat_node* fn = fat_make_node(&de2[e2], dir_cluster, dirent_off); + struct fat_node* fn = fat_make_node(fm, &de2[e2], dir_cluster, dirent_off); if (!fn) return -ENOMEM; *out = &fn->vfs; return 0; @@ -893,13 +899,15 @@ static int fat_create_impl(struct fs_node* dir, const char* name, uint32_t flags static int fat_mkdir_impl(struct fs_node* dir, const char* name) { if (!dir || !name) return -EINVAL; struct fat_node* parent = (struct fat_node*)dir; + struct fat_mount* fm = parent->mount; + if (!fm) return -EIO; uint32_t dir_cluster = parent->first_cluster; /* Check doesn't exist */ - if (fat_find_dirent(dir_cluster, name, NULL, NULL) == 0) return -EEXIST; + if (fat_find_dirent(fm, dir_cluster, name, NULL, NULL) == 0) return -EEXIST; /* Allocate a cluster for the new directory */ - uint32_t new_cl = fat_alloc_cluster(); + uint32_t new_cl = fat_alloc_cluster(fm); if (new_cl == 0) return -ENOSPC; /* Write . and .. entries */ @@ -912,7 +920,7 @@ static int fat_mkdir_impl(struct fs_node* dir, const char* name) { memset(de[0].ext, ' ', 3); de[0].name[0] = '.'; de[0].attr = FAT_ATTR_DIRECTORY; - fat_dirent_set_cluster(&de[0], new_cl); + fat_dirent_set_cluster(fm, &de[0], new_cl); /* ".." entry */ memset(de[1].name, ' ', 8); @@ -920,18 +928,18 @@ static int fat_mkdir_impl(struct fs_node* dir, const char* name) { de[1].name[0] = '.'; de[1].name[1] = '.'; de[1].attr = FAT_ATTR_DIRECTORY; - fat_dirent_set_cluster(&de[1], dir_cluster); + fat_dirent_set_cluster(fm, &de[1], dir_cluster); - uint32_t lba = fat_cluster_to_lba(new_cl); - if (fat_write_sector(lba, sec) < 0) { - fat_free_chain(new_cl); + uint32_t lba = fat_cluster_to_lba(fm, new_cl); + if (fat_write_sector(fm, lba, sec) < 0) { + fat_free_chain(fm, new_cl); return -EIO; } /* Add dirent in parent */ - int rc = fat_add_dirent(dir_cluster, name, FAT_ATTR_DIRECTORY, new_cl, 0, NULL); + int rc = fat_add_dirent(fm, dir_cluster, name, FAT_ATTR_DIRECTORY, new_cl, 0, NULL); if (rc < 0) { - fat_free_chain(new_cl); + fat_free_chain(fm, new_cl); return rc; } @@ -943,36 +951,38 @@ static int fat_mkdir_impl(struct fs_node* dir, const char* name) { static int fat_unlink_impl(struct fs_node* dir, const char* name) { if (!dir || !name) return -EINVAL; struct fat_node* parent = (struct fat_node*)dir; + struct fat_mount* fm = parent->mount; + if (!fm) return -EIO; uint32_t dir_cluster = parent->first_cluster; uint32_t sec_idx, ent_idx; - int rc = fat_find_dirent(dir_cluster, name, &sec_idx, &ent_idx); + int rc = fat_find_dirent(fm, dir_cluster, name, &sec_idx, &ent_idx); if (rc < 0) return rc; uint8_t sec[FAT_SECTOR_SIZE]; - if (fat_dir_read_sector(dir_cluster, sec_idx, sec) < 0) return -EIO; + if (fat_dir_read_sector(fm, dir_cluster, sec_idx, sec) < 0) return -EIO; struct fat_dirent* de = (struct fat_dirent*)sec; if (de[ent_idx].attr & FAT_ATTR_DIRECTORY) return -EISDIR; /* Free cluster chain */ - uint32_t cl = fat_dirent_cluster(&de[ent_idx]); - if (cl >= 2) fat_free_chain(cl); + uint32_t cl = fat_dirent_cluster(fm, &de[ent_idx]); + if (cl >= 2) fat_free_chain(fm, cl); /* Mark entry as deleted */ de[ent_idx].name[0] = (char)0xE5; - return fat_dir_write_sector(dir_cluster, sec_idx, sec); + return fat_dir_write_sector(fm, dir_cluster, sec_idx, sec); } /* ---- VFS: rmdir ---- */ -static int fat_dir_is_empty(uint32_t dir_cluster) { - uint32_t total_sec = fat_dir_total_sectors(dir_cluster); +static int fat_dir_is_empty(struct fat_mount* fm, uint32_t dir_cluster) { + uint32_t total_sec = fat_dir_total_sectors(fm, dir_cluster); uint32_t ents_per_sec = FAT_SECTOR_SIZE / FAT_DIRENT_SIZE; for (uint32_t s = 0; s < total_sec; s++) { uint8_t sec[FAT_SECTOR_SIZE]; - if (fat_dir_read_sector(dir_cluster, s, sec) < 0) return 0; + if (fat_dir_read_sector(fm, dir_cluster, s, sec) < 0) return 0; struct fat_dirent* de = (struct fat_dirent*)sec; for (uint32_t i = 0; i < ents_per_sec; i++) { @@ -994,27 +1004,29 @@ static int fat_dir_is_empty(uint32_t dir_cluster) { static int fat_rmdir_impl(struct fs_node* dir, const char* name) { if (!dir || !name) return -EINVAL; struct fat_node* parent = (struct fat_node*)dir; + struct fat_mount* fm = parent->mount; + if (!fm) return -EIO; uint32_t dir_cluster = parent->first_cluster; uint32_t sec_idx, ent_idx; - int rc = fat_find_dirent(dir_cluster, name, &sec_idx, &ent_idx); + int rc = fat_find_dirent(fm, dir_cluster, name, &sec_idx, &ent_idx); if (rc < 0) return rc; uint8_t sec[FAT_SECTOR_SIZE]; - if (fat_dir_read_sector(dir_cluster, sec_idx, sec) < 0) return -EIO; + if (fat_dir_read_sector(fm, dir_cluster, sec_idx, sec) < 0) return -EIO; struct fat_dirent* de = (struct fat_dirent*)sec; if (!(de[ent_idx].attr & FAT_ATTR_DIRECTORY)) return -ENOTDIR; - uint32_t child_cl = fat_dirent_cluster(&de[ent_idx]); - if (child_cl >= 2 && !fat_dir_is_empty(child_cl)) return -ENOTEMPTY; + uint32_t child_cl = fat_dirent_cluster(fm, &de[ent_idx]); + if (child_cl >= 2 && !fat_dir_is_empty(fm, child_cl)) return -ENOTEMPTY; /* Free cluster chain */ - if (child_cl >= 2) fat_free_chain(child_cl); + if (child_cl >= 2) fat_free_chain(fm, child_cl); /* Mark entry deleted */ de[ent_idx].name[0] = (char)0xE5; - return fat_dir_write_sector(dir_cluster, sec_idx, sec); + return fat_dir_write_sector(fm, dir_cluster, sec_idx, sec); } /* ---- VFS: rename ---- */ @@ -1024,14 +1036,16 @@ static int fat_rename_impl(struct fs_node* old_dir, const char* old_name, if (!old_dir || !old_name || !new_dir || !new_name) return -EINVAL; struct fat_node* odir = (struct fat_node*)old_dir; struct fat_node* ndir = (struct fat_node*)new_dir; + struct fat_mount* fm = odir->mount; + if (!fm) return -EIO; /* Find source */ uint32_t src_sec, src_ent; - int rc = fat_find_dirent(odir->first_cluster, old_name, &src_sec, &src_ent); + int rc = fat_find_dirent(fm, odir->first_cluster, old_name, &src_sec, &src_ent); if (rc < 0) return rc; uint8_t src_buf[FAT_SECTOR_SIZE]; - if (fat_dir_read_sector(odir->first_cluster, src_sec, src_buf) < 0) return -EIO; + if (fat_dir_read_sector(fm, odir->first_cluster, src_sec, src_buf) < 0) return -EIO; struct fat_dirent* src_de = &((struct fat_dirent*)src_buf)[src_ent]; /* Save source dirent data */ @@ -1040,38 +1054,38 @@ static int fat_rename_impl(struct fs_node* old_dir, const char* old_name, /* Remove destination if exists */ uint32_t dst_sec, dst_ent; - rc = fat_find_dirent(ndir->first_cluster, new_name, &dst_sec, &dst_ent); + rc = fat_find_dirent(fm, ndir->first_cluster, new_name, &dst_sec, &dst_ent); if (rc == 0) { uint8_t dst_buf[FAT_SECTOR_SIZE]; - if (fat_dir_read_sector(ndir->first_cluster, dst_sec, dst_buf) < 0) return -EIO; + if (fat_dir_read_sector(fm, ndir->first_cluster, dst_sec, dst_buf) < 0) return -EIO; struct fat_dirent* dst_de = &((struct fat_dirent*)dst_buf)[dst_ent]; /* Free old destination data */ - uint32_t dst_cl = fat_dirent_cluster(dst_de); - if (dst_cl >= 2) fat_free_chain(dst_cl); + uint32_t dst_cl = fat_dirent_cluster(fm, dst_de); + if (dst_cl >= 2) fat_free_chain(fm, dst_cl); dst_de->name[0] = (char)0xE5; - if (fat_dir_write_sector(ndir->first_cluster, dst_sec, dst_buf) < 0) return -EIO; + if (fat_dir_write_sector(fm, ndir->first_cluster, dst_sec, dst_buf) < 0) return -EIO; } /* Delete source entry */ src_de->name[0] = (char)0xE5; - if (fat_dir_write_sector(odir->first_cluster, src_sec, src_buf) < 0) return -EIO; + if (fat_dir_write_sector(fm, odir->first_cluster, src_sec, src_buf) < 0) return -EIO; /* Add new entry in destination dir */ - uint32_t cl = fat_dirent_cluster(&saved); - rc = fat_add_dirent(ndir->first_cluster, new_name, saved.attr, cl, saved.file_size, NULL); + uint32_t cl = fat_dirent_cluster(fm, &saved); + rc = fat_add_dirent(fm, ndir->first_cluster, new_name, saved.attr, cl, saved.file_size, NULL); if (rc < 0) return rc; /* Update ".." in moved directory if applicable */ if (saved.attr & FAT_ATTR_DIRECTORY) { if (cl >= 2 && odir->first_cluster != ndir->first_cluster) { uint8_t dsec[FAT_SECTOR_SIZE]; - if (fat_dir_read_sector(cl, 0, dsec) == 0) { + if (fat_dir_read_sector(fm, cl, 0, dsec) == 0) { struct fat_dirent* entries = (struct fat_dirent*)dsec; if (entries[1].name[0] == '.' && entries[1].name[1] == '.') { - fat_dirent_set_cluster(&entries[1], ndir->first_cluster); - (void)fat_dir_write_sector(cl, 0, dsec); + fat_dirent_set_cluster(fm, &entries[1], ndir->first_cluster); + (void)fat_dir_write_sector(fm, cl, 0, dsec); } } } @@ -1085,28 +1099,30 @@ static int fat_rename_impl(struct fs_node* old_dir, const char* old_name, static int fat_truncate_impl(struct fs_node* node, uint32_t length) { if (!node) return -EINVAL; struct fat_node* fn = (struct fat_node*)node; + struct fat_mount* fm = fn->mount; + if (!fm) return -EIO; if (length >= fn->vfs.length) return 0; /* only shrink */ - uint32_t csize = fat_cluster_size(); + uint32_t csize = fat_cluster_size(fm); uint32_t need_clusters = (length + csize - 1) / csize; if (need_clusters == 0) { /* Free everything */ if (fn->first_cluster >= 2) { - fat_free_chain(fn->first_cluster); + fat_free_chain(fm, fn->first_cluster); fn->first_cluster = 0; } } else { /* Keep first N clusters, free the rest */ uint32_t c = fn->first_cluster; for (uint32_t i = 1; i < need_clusters; i++) { - c = fat_get_entry(c); + c = fat_get_entry(fm, c); } - uint32_t next = fat_get_entry(c); - (void)fat_set_entry(c, fat_eoc_mark()); - if (next >= 2 && !fat_is_eoc(next)) { - fat_free_chain(next); + uint32_t next = fat_get_entry(fm, c); + (void)fat_set_entry(fm, c, fat_eoc_mark(fm)); + if (next >= 2 && !fat_is_eoc(fm, next)) { + fat_free_chain(fm, next); } } @@ -1124,13 +1140,21 @@ fs_node_t* fat_mount(const block_device_t* bdev, uint32_t partition_lba) { return NULL; } - /* Store bdev early so fat_read_sector can use it */ - g_fat.bdev = bdev; - g_fat.drive = bdev->drive_id; + /* Allocate mount structure */ + struct fat_mount* fm = (struct fat_mount*)kmalloc(sizeof(struct fat_mount)); + if (!fm) { + kprintf("[FAT] Failed to allocate mount structure\n"); + return NULL; + } + memset(fm, 0, sizeof(*fm)); + + fm->bdev = bdev; + fm->drive = bdev->drive_id; uint8_t boot_sec[FAT_SECTOR_SIZE]; - if (fat_read_sector(partition_lba, boot_sec) < 0) { + if (fat_read_sector(fm, partition_lba, boot_sec) < 0) { kprintf("[FAT] Failed to read BPB at LBA %u\n", partition_lba); + kfree(fm); return NULL; } @@ -1138,66 +1162,70 @@ fs_node_t* fat_mount(const block_device_t* bdev, uint32_t partition_lba) { if (bpb->bytes_per_sector != 512) { kprintf("[FAT] Unsupported sector size %u\n", bpb->bytes_per_sector); + kfree(fm); return NULL; } if (bpb->num_fats == 0 || bpb->sectors_per_cluster == 0) { kprintf("[FAT] Invalid BPB\n"); + kfree(fm); return NULL; } - memset(&g_fat, 0, sizeof(g_fat)); - g_fat.bdev = bdev; - g_fat.drive = bdev->drive_id; - g_fat.part_lba = partition_lba; - g_fat.bytes_per_sector = bpb->bytes_per_sector; - g_fat.sectors_per_cluster = bpb->sectors_per_cluster; - g_fat.reserved_sectors = bpb->reserved_sectors; - g_fat.num_fats = bpb->num_fats; - g_fat.root_entry_count = bpb->root_entry_count; + fm->part_lba = partition_lba; + fm->bytes_per_sector = bpb->bytes_per_sector; + fm->sectors_per_cluster = bpb->sectors_per_cluster; + fm->reserved_sectors = bpb->reserved_sectors; + fm->num_fats = bpb->num_fats; + fm->root_entry_count = bpb->root_entry_count; /* Determine FAT size */ if (bpb->fat_size_16 != 0) { - g_fat.fat_size = bpb->fat_size_16; + fm->fat_size = bpb->fat_size_16; } else { struct fat32_ext* ext32 = (struct fat32_ext*)(boot_sec + 36); - g_fat.fat_size = ext32->fat_size_32; - g_fat.root_cluster = ext32->root_cluster; + fm->fat_size = ext32->fat_size_32; + fm->root_cluster = ext32->root_cluster; } - g_fat.fat_lba = partition_lba + bpb->reserved_sectors; - g_fat.root_dir_lba = g_fat.fat_lba + (uint32_t)bpb->num_fats * g_fat.fat_size; - g_fat.root_dir_sectors = ((uint32_t)bpb->root_entry_count * 32 + 511) / 512; - g_fat.data_lba = g_fat.root_dir_lba + g_fat.root_dir_sectors; + fm->fat_lba = partition_lba + bpb->reserved_sectors; + fm->root_dir_lba = fm->fat_lba + (uint32_t)bpb->num_fats * fm->fat_size; + fm->root_dir_sectors = ((uint32_t)bpb->root_entry_count * 32 + 511) / 512; + fm->data_lba = fm->root_dir_lba + fm->root_dir_sectors; /* Total data sectors & cluster count determine FAT type */ uint32_t total_sectors = bpb->total_sectors_16 ? bpb->total_sectors_16 : bpb->total_sectors_32; - uint32_t data_sectors = total_sectors - (g_fat.data_lba - partition_lba); - g_fat.total_clusters = data_sectors / g_fat.sectors_per_cluster; + uint32_t data_sectors = total_sectors - (fm->data_lba - partition_lba); + fm->total_clusters = data_sectors / fm->sectors_per_cluster; /* Microsoft FAT spec: type is determined by cluster count */ - if (g_fat.total_clusters < 4085) { - g_fat.type = FAT_TYPE_12; - } else if (g_fat.total_clusters < 65525) { - g_fat.type = FAT_TYPE_16; + if (fm->total_clusters < 4085) { + fm->type = FAT_TYPE_12; + } else if (fm->total_clusters < 65525) { + fm->type = FAT_TYPE_16; } else { - g_fat.type = FAT_TYPE_32; + fm->type = FAT_TYPE_32; } /* Build root node */ memset(&g_fat_root, 0, sizeof(g_fat_root)); + g_fat_root.mount = fm; memcpy(g_fat_root.vfs.name, "fat", 4); g_fat_root.vfs.flags = FS_DIRECTORY; g_fat_root.vfs.inode = 0; - g_fat_root.first_cluster = (g_fat.type == FAT_TYPE_32) ? g_fat.root_cluster : 0; + g_fat_root.first_cluster = (fm->type == FAT_TYPE_32) ? fm->root_cluster : 0; g_fat_root.parent_cluster = 0; g_fat_root.dir_entry_offset = 0; g_fat_root.vfs.f_ops = &fat_dir_fops; g_fat_root.vfs.i_ops = &fat_dir_iops; - g_fat_ready = 1; - kprintf("[FAT] Mounted FAT%u at LBA %u (%u clusters)\n", - (unsigned)g_fat.type, partition_lba, g_fat.total_clusters); + (unsigned)fm->type, partition_lba, fm->total_clusters); return &g_fat_root.vfs; } + +void fat_umount(struct fat_mount* fm) { + if (fm) { + kfree(fm); + } +} diff --git a/src/kernel/fs.c b/src/kernel/fs.c index a0265fbb..81665c17 100644 --- a/src/kernel/fs.c +++ b/src/kernel/fs.c @@ -8,6 +8,8 @@ */ #include "fs.h" +#include "fat.h" +#include "ext2.h" #include "utils.h" #include "errno.h" @@ -185,6 +187,16 @@ int vfs_umount_nolock(const char* mountpoint) { blockdev_release(g_mounts[idx].bdev); } + /* Call filesystem-specific umount to free mount structure */ + if (g_mounts[idx].sb && g_mounts[idx].sb->private_data) { + if (strcmp(g_mounts[idx].fstype, "fat") == 0) { + fat_umount((struct fat_mount*)g_mounts[idx].sb->private_data); + } else if (strcmp(g_mounts[idx].fstype, "ext2") == 0) { + ext2_umount((struct ext2_mount*)g_mounts[idx].sb->private_data); + } + g_mounts[idx].sb->private_data = NULL; + } + for (int j = idx; j < g_mount_count - 1; j++) g_mounts[j] = g_mounts[j + 1]; g_mount_count--;