miniOS
x86_64 hobby kernel with SMP, VFS, and POSIX process model
Loading...
Searching...
No Matches
ext2.h File Reference
#include <miniOS/types.h>
#include <miniOS/fs/fs_types.h>
Include dependency graph for ext2.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  __attribute__

Macros

#define EXT2_MAGIC   0xEF53
#define EXT2_ROOT_INO   2
#define EXT2_S_IFREG   0x8000 /* regular file */
#define EXT2_S_IFDIR   0x4000 /* directory */
#define EXT2_S_IFLNK   0xA000 /* symbolic link */
#define EXT2_S_IFCHR   0x2000 /* character device */
#define EXT2_S_IFBLK   0x6000 /* block device */
#define EXT2_FT_UNKNOWN   0
#define EXT2_FT_REG_FILE   1
#define EXT2_FT_DIR   2
#define EXT2_FT_CHRDEV   3
#define EXT2_FT_BLKDEV   4
#define EXT2_FT_SYMLINK   7

Typedefs

typedef struct vfs_inode_info vfs_inode_info_t

Functions

int ext2_mount (uint64_t part_lba_start, uint64_t part_lba_end)
int ext2_lookup (const char *path, vfs_inode_info_t *out)
int ext2_read_file (uint32_t ino, uint64_t off, void *buf, uint32_t len)
int ext2_readdir (uint32_t dir_ino, uint64_t *offset, vfs_dirent_cb_t cb, void *ud)
int ext2_write_file (uint32_t ino, uint64_t off, const void *buf, uint32_t len)
: Null-terminated filename (no path separators).

ext2_create() - Create a new regular file inode and directory entry. @parent_ino: Inode number of the parent directory.

@out_ino: Output: inode number of the newly created file.

Allocates a new inode via the inode bitmap (first-fit). Initialises the inode with i_mode = EXT2_S_IFREG | (mode & 0777), i_links_count = 1, all block pointers zero, i_size = 0. Appends an ext2_dirent_t to the parent directory. Writes back the new inode, updated bitmaps, superblock, and BGD. @mode: Lower 9 bits used as permission bits; 0 defaults to 0644.

Returns
: 0 on success, -1 on allocation or I/O error, -28 if parent full.
int ext2_create (uint32_t parent_ino, const char *name, uint16_t mode, uint32_t *out_ino)
int ext2_flush_inode (uint32_t ino)
int ext2_truncate_inode (uint32_t ino, uint64_t new_size)
int ext2_readlink (uint32_t ino, char *buf, uint32_t len)
: Symlink filename (no path separators).

@target: Target string stored as-is (may be relative or absolute).

Returns
: 0 on success, -1 on I/O error, -2 on ENOSPC.
int ext2_symlink (uint32_t parent_ino, const char *name, const char *target)
: Null-terminated filename (no '/' allowed).

ext2_mknod() - Create a device-file inode (char or block) in a directory. @parent_ino: Inode number of the parent directory.

@mode: Inode mode: EXT2_S_IFCHR|perms or EXT2_S_IFBLK|perms. @dev: Device number encoded as (major<<8)|minor stored in i_block[0]. @out_ino: Set to the new inode number on success.

Returns
: 0 on success, -1 on I/O error, -2 on ENOSPC, -22 on bad mode.
int ext2_mknod (uint32_t parent_ino, const char *name, uint16_t mode, uint32_t dev, uint32_t *out_ino)
: Null-terminated directory name (no '/' allowed).

ext2_mkdir() - Create a new directory inode and link it into @parent_ino. @parent_ino: Inode number of the parent directory.

@out_ino: Set to the new directory inode number on success.

Allocates an inode (i_mode=EXT2_S_IFDIR|0755, i_links_count=2) and a data block containing '.' (→ new_ino) and '..' (→ parent_ino) entries. Inserts a directory entry with file_type=EXT2_FT_DIR in the parent, then increments the parent's i_links_count for the '..' back-reference and bumps bg_used_dirs_count in the block group descriptor.

Returns
: 0 on success, -1 on I/O error, -2 on ENOSPC.
int ext2_mkdir (uint32_t parent_ino, const char *name, uint32_t *out_ino)
: Directory name to remove.

ext2_rmdir() - Remove an empty directory inode and its parent entry. @parent_ino: Inode number of the parent directory.

The target must exist, be a directory, and contain only "." and "..". Frees the directory data block and inode, removes the parent directory entry, decrements the parent's link count, and updates bg_used_dirs_count.

Returns
: 0 on success, or a negative errno-style value on failure.
int ext2_rmdir (uint32_t parent_ino, const char *name)
void ext2_init (void)

Macro Definition Documentation

◆ EXT2_FT_BLKDEV

#define EXT2_FT_BLKDEV   4

◆ EXT2_FT_CHRDEV

#define EXT2_FT_CHRDEV   3

◆ EXT2_FT_DIR

#define EXT2_FT_DIR   2

◆ EXT2_FT_REG_FILE

#define EXT2_FT_REG_FILE   1

◆ EXT2_FT_SYMLINK

#define EXT2_FT_SYMLINK   7

◆ EXT2_FT_UNKNOWN

#define EXT2_FT_UNKNOWN   0

◆ EXT2_MAGIC

#define EXT2_MAGIC   0xEF53

◆ EXT2_ROOT_INO

#define EXT2_ROOT_INO   2

◆ EXT2_S_IFBLK

#define EXT2_S_IFBLK   0x6000 /* block device */

◆ EXT2_S_IFCHR

#define EXT2_S_IFCHR   0x2000 /* character device */

◆ EXT2_S_IFDIR

#define EXT2_S_IFDIR   0x4000 /* directory */

◆ EXT2_S_IFLNK

#define EXT2_S_IFLNK   0xA000 /* symbolic link */

◆ EXT2_S_IFREG

#define EXT2_S_IFREG   0x8000 /* regular file */

Typedef Documentation

◆ vfs_inode_info_t

Function Documentation

◆ ext2_create()

int ext2_create ( uint32_t parent_ino,
const char * name,
uint16_t mode,
uint32_t * out_ino )
Here is the call graph for this function:

◆ ext2_flush_inode()

int ext2_flush_inode ( uint32_t ino)

ext2_flush_inode() - Write the in-memory inode state back to disk. @ino: Inode number to flush.

Reads the inode table block containing @ino, updates the inode bytes in place with the current on-disk inode data, then writes the block back. Called from vfs_close() via ops->flush to persist i_size and i_block[] after a write sequence.

Returns
: 0 on success, -1 on I/O error.

ext2_flush_inode() - Write the current inode state back to disk. @ino: Inode number to flush.

Reads the inode from disk and immediately writes it back. Used by vfs_close() (via ops->flush) to ensure i_size and i_block[] are durable after writes. The ATA flush command is issued separately by the caller.

Returns
: 0 on success, -1 on I/O error.
Here is the call graph for this function:

◆ ext2_init()

void ext2_init ( void )

ext2_init() - Register the ext2 filesystem type with the VFS registry.

After this call, vfs_mount_fstype("ext2", source, target, data) can be used to mount any ext2 partition by passing a vfs_mount_data_t as @data. ext2_init() does NOT mount anything itself; it only registers the type. Call once during kernel startup, before the first ext2 mount.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ext2_lookup()

int ext2_lookup ( const char * path,
vfs_inode_info_t * out )

ext2_lookup() - Resolve an absolute path to typed inode metadata. @path: Absolute path string (e.g., "/hello.txt", "/bin/sh"). Must begin with '/'. Components separated by '/'. @out: Output metadata populated on success.

Starts at root inode (inode 2) and descends through each path component by iterating directory entries via ext2_readdir with a find_entry_cb callback. Directory traversal still handles only direct blocks (i_block[0..11]), which is sufficient for the current single-group test image. Uses static g_block_buf — not reentrant.

Context: Single-threaded; uses static g_block_buf. Not ISR-safe.

Returns
: 0 on success, -1 if path not found or on error.

ext2_lookup() - Resolve path components starting from root inode 2. @path: Absolute path; must start with '/'.

Tokenises @path on '/' using strtok-like manual scanning. For each component, calls ext2_readdir with find_entry_cb to search the current directory inode for a matching entry. Updates current_ino to the matched child inode and continues to the next component. Returns current_ino after all components.

Returns
: Final inode number (>= 2), or 0 if any component is not found.
Here is the call graph for this function:

◆ ext2_mkdir()

int ext2_mkdir ( uint32_t parent_ino,
const char * name,
uint32_t * out_ino )
Here is the call graph for this function:

◆ ext2_mknod()

int ext2_mknod ( uint32_t parent_ino,
const char * name,
uint16_t mode,
uint32_t dev,
uint32_t * out_ino )

ext2_mknod() - Create a char or block device inode in @parent_ino.

Allocates an inode with i_mode = @mode (EXT2_S_IFCHR|perms or EXT2_S_IFBLK|perms), i_links_count = 1, no data blocks, and stores @dev in i_block[0] (traditional Linux ext2 device number encoding). Inserts a directory entry with EXT2_FT_CHRDEV or EXT2_FT_BLKDEV into the parent directory using the same split-and-append logic as ext2_create.

Here is the call graph for this function:

◆ ext2_mount()

int ext2_mount ( uint64_t part_lba_start,
uint64_t part_lba_end )

ext2_mount() - Mount an ext2 partition by reading and validating its superblock. @part_lba_start: First sector of the partition (LBA offset from disk start). @part_lba_end: Last sector of the partition (inclusive).

Reads the superblock from byte offset 1024 within the partition (sector part_lba_start + 2 for 512-byte sectors). Validates the ext2 magic number (0xEF53). Initialises global filesystem state: block size, sectors per block, inodes per group, inode size, first data block. Reads block group descriptor table to locate the inode table. Assumes a single block group.

Returns
: 0 on success, -1 if superblock magic is wrong or ATA I/O failed.

ext2_mount() - Read superblock and initialise filesystem global state. @part_lba_start: LBA of partition start; stored in g_part_start.

Reads 2 sectors at part_lba_start + 2 (superblock at 1024-byte offset). Checks s_magic == 0xEF53. Sets g_block_size = 1024 << s_log_block_size, g_sectors_per_block, g_inodes_per_group, g_inode_size (128 for rev 0, s_inode_size for rev 1), g_first_data_block. Reads block group descriptor table at block g_first_data_block+1 to obtain inode table base. Single block group assumed (8 MiB image has exactly one group).

Returns
: 0 on success, -1 on ATA I/O error or invalid magic.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ext2_read_file()

int ext2_read_file ( uint32_t ino,
uint64_t off,
void * buf,
uint32_t len )

ext2_read_file() - Read bytes from an open inode. @ino: Inode number of the file (>= 2; must be a regular file). @off: Byte offset within the file to start reading from. @buf: Destination buffer for read data. @len: Maximum number of bytes to read.

Maps byte range [@off, @off+@len) to direct block indices plus the first single-indirect block (i_block[12]). Reads each required block via ata_read_sectors into g_block_buf, then copies the relevant slice to @buf. Clamps to file size (i_size). Handles cross-block reads by iterating over block boundaries.

Context: Single-threaded; uses static g_block_buf. Not reentrant.

Returns
: Number of bytes actually read (may be less than @len at EOF), or -1 on I/O error or unsupported inode type.

ext2_read_file() - Copy file data from inode blocks into caller's buffer. @ino: Inode number of the regular file. @off: Starting byte offset within the file. @buf: Destination buffer. @len: Requested byte count.

Reads the inode to get i_size and i_block[]. Clamps read to i_size. Computes starting block index as off / g_block_size, byte offset within block as off % g_block_size. Resolves each logical block through direct pointers and the first single-indirect block, then copies the relevant slice. Iterates until @len bytes are copied or EOF.

Returns
: Bytes copied (0..@len), or -1 on I/O error.
Here is the call graph for this function:

◆ ext2_readdir()

int ext2_readdir ( uint32_t dir_ino,
uint64_t * offset,
vfs_dirent_cb_t cb,
void * ud )

ext2_readdir() - Iterate directory entries in an inode. @dir_ino: Inode number of the directory to read (must have i_mode dir bit set). @offset: Caller-owned byte cursor. Entries before *@offset are skipped; on return it points just past the last emitted record. @cb: Callback invoked for each directory entry with (name, name_len, inode, file_type, ud). If @cb returns non-zero, iteration stops immediately. @ud: Opaque user data pointer forwarded to @cb unchanged.

Reads all direct blocks of the directory inode and iterates ext2_dirent_t records within each block. Skips entries with inode == 0 (deleted entries). Handles variable-length records via rec_len. Direct blocks only.

Context: Single-threaded; uses static g_block_buf. Not reentrant.

Returns
: 0 when all entries have been visited (or directory was empty), or the non-zero value returned by @cb if iteration was stopped early.

ext2_readdir() - Iterate directory entries in all direct blocks of a directory inode. @dir_ino: Directory inode number. @cb: Called for each valid entry (inode != 0) with name (not null-terminated), name_len, child inode, file_type, and @ud. @ud: Forwarded to @cb unchanged.

Reads each direct block (i_block[0..11]) of the directory inode. Within each block, walks ext2_dirent_t records by incrementing a byte pointer by rec_len. Skips entries with inode==0 (deleted or padding entries). Stops block iteration when the block pointer address reaches block_end. Returns early if @cb returns non-zero.

Returns
: 0 when all entries visited, or first non-zero return value from @cb.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ext2_readlink()

int ext2_readlink ( uint32_t ino,
char * buf,
uint32_t len )

ext2_readlink() - Read the target of a symlink inode (POSIX: not null-terminated). @ino: Inode number of the symlink. @buf: Output buffer. @len: Maximum bytes to copy.

Returns
: Bytes copied (>= 0) or -1 on error / not a symlink.

ext2_readlink() - Read the target string of a symlink inode. @ino: Inode number of the symlink (i_mode must have EXT2_S_IFLNK set). @buf: Output buffer. NOT null-terminated (POSIX readlink semantics). @len: Maximum bytes to copy into buf.

Fast-link (i_blocks == 0): target stored inline in i_block[0..14] bytes. Block-link (i_blocks > 0): target stored in data block i_block[0].

Returns
: Number of bytes copied (>= 0), or -1 on error.
Here is the call graph for this function:

◆ ext2_rmdir()

int ext2_rmdir ( uint32_t parent_ino,
const char * name )
Here is the call graph for this function:

◆ ext2_symlink()

int ext2_symlink ( uint32_t parent_ino,
const char * name,
const char * target )
Here is the call graph for this function:

◆ ext2_truncate_inode()

int ext2_truncate_inode ( uint32_t ino,
uint64_t new_size )

ext2_truncate_inode() - Truncate a regular file inode to zero bytes. @ino: Inode number of the file to truncate (must be a regular file).

Frees all data blocks referenced by the inode, clears i_block[0..14], resets i_size = 0 and i_blocks = 0, and writes the inode back to disk. Updates block bitmap, superblock s_free_blocks_count, and BGD bg_free_blocks_count for each freed block.

Returns
: 0 on success, -1 on type mismatch or I/O error.

ext2_truncate_inode() - Truncate a regular file to zero bytes. @ino: Inode number of the file to truncate.

Walks i_block[0..11] (direct blocks) and i_block[12..14] (indirect pointers, treated as direct block references — single-group, small files only use direct blocks). Frees each allocated block via free_block(). Clears all block pointer entries in the inode (i_block[0..14] = 0). Resets i_size = 0 and i_blocks = 0. Writes the updated inode back to disk.

Only truncates regular files (i_mode & EXT2_S_IFREG). Returns -1 for directories or other non-regular types.

Returns
: 0 on success, -1 on type mismatch or I/O error.
Here is the call graph for this function:

◆ ext2_write_file()

int ext2_write_file ( uint32_t ino,
uint64_t off,
const void * buf,
uint32_t len )

ext2_write_file() - Write bytes into an existing inode's data blocks. @ino: Inode number of the target regular file. @off: Byte offset within the file to start writing at. @buf: Source buffer containing bytes to write. @len: Number of bytes to write.

Allocates new data blocks as needed when the write extends past existing allocated blocks. Updates i_size if (off + len) > current i_size. Does NOT flush to disk — caller must call ext2_flush_inode() then ata_flush().

Returns
: Number of bytes written, or -1 on allocation or I/O error.

ext2_write_file() - Write bytes to an inode's data blocks, allocating as needed. @ino: Inode number of the target regular file. @off: Byte offset within the file. @buf: Source data. @len: Number of bytes to write.

For each block touched by the range [off, off+len):

  • If the block is not yet allocated (i_block[k]==0), allocate it and zero it.
  • If the write is a partial block, read-modify-write (read existing, patch bytes).
  • If the write covers a full block, write directly without reading first. Updates i_size = max(i_size, off + bytes_written). Does NOT write back the inode (caller calls ext2_flush_inode then ata_flush via vfs_close).
Returns
: Number of bytes written, or -1 on I/O or allocation error.
Here is the call graph for this function: