blob: 9b6d5ba2f30fe0faec90f268f69d8676bdfc68fd [file] [log] [blame]
#pragma once
#include <vfs.h>
struct ext2_superblock
{
/// Total number of inodes
uint total_inodes;
/// Total number of blocks
uint total_blocks;
/// Number of blocks reserved for superuser
uint blocks_reserved_for_superuser;
/// Number of unallocated blocks
uint unallocated_blocks;
/// Number of unallocated inodes
uint unallocated_inodes;
/// Block number containing the superblock
uint superblock_block_number;
/// the number to shift 1024 to the left by to get the block size
uint block_size_shift;
/// the number to shift 1024 to the left by to get the fragment size
uint fragment_size_shift;
/// Number of blocks in one block group
uint blocks_per_block_group;
/// Number of fragments in one block group
uint fragments_per_block_group;
/// Number of inodse in one block group
uint inodes_per_block_group;
/// UNIX time of last mount
uint last_mount_time;
/// UNIX time of last write
uint last_write_time;
/// Number of mounts since last consistency check
ushort mounts_since_last_fsck;
/// Number of mounts allowed between consistency checks
ushort mounts_allowed_before_fsck;
/// EXT2 signature, should be 0xef53
ushort signature;
/// File system state, see enum ext2_fs_state
ushort state;
/// What to do in case of an error, see enum ext2_error_case
ushort error_case;
/// Minor portion of version
ushort version_minor;
/// UNIX time of last consistency check
uint last_fsck_time;
/// Max time between consistency checks
uint fsck_time_interval;
/// Operating system ID of creator
uint creator_os_id;
/// Major portion of version
uint version_major;
/// User ID that can use reserved blocks
ushort reserved_blocks_uid;
/// Group ID that can use reserved blocks
ushort reserved_blocks_gid;
};
enum ext2_fs_state
{
EXT2_STATE_CLEAN = 1,
EXT2_STATE_ERRORS = 2,
};
enum ext2_error_case
{
EXT2_ERROR_IGNORE = 1,
EXT2_ERROR_REMOUNT = 2,
EXT2_ERROR_KPANIC = 3,
};
enum ext2_os_id
{
EXT2_OS_LINUX = 0,
EXT2_OS_HURD,
EXT2_OS_MASIX,
EXT2_OS_FREEBSD,
EXT2_OS_OTHER_BSD,
};
#define EXT2_SIGNATURE 0xef53
struct ext2_block_group_descriptor
{
/// Address of block usage bitmap
uint block_bitmap; // 4
/// Address of inode usage bitmap
uint inode_bitmap; // 8
/// Starting block address of inode table
uint inode_table_start_block; // 12
/// Number of unallocated blocks in this group
ushort unallocated_blocks; // 14
/// Number of unallocated inodes in this group
ushort unallocated_inodes; // 16
/// Number of directories in this group
ushort num_dirs; // 18
ushort padding; // 20
uchar reserved[12]; // 32
};
struct ext2_inode
{
/// The format and permissions of the file, see EXT2_S_*
ushort mode;
/// The user id of the owner
ushort uid;
/// The lower 32 bits of the file size
uint size;
/// Last time this was accessed in UNIX time
uint access_time;
/// Time this was created in UNIX time
uint created_time;
/// Time this was last modified in UNIX time
uint modified_time;
/// Time this was deleted in UNIX time
uint deleted_time;
/// Owner group id
ushort gid;
/// Reference count for hard links
ushort links_count;
/// Number of 512 byte blocks storing this files data, NOT EXT2 blocks!
uint num_blocks;
/// Flags describing how this file can be accessed
uint flags;
/// First field reserved for the operating system
uint os_reserved_1;
union
{
/// The blocks of this file
uint blocks[15];
struct
{
/// The direct blocks
uint direct_blocks[12];
/// The single indirect block
uint ind_block;
/// The double indirect block
uint ind2_block;
/// The triple indirect block
uint ind3_block;
};
};
/// Used by NFS to version files
uint generation;
/// File attributes, unused
uint file_acl;
/// Directory attributes, unused
uint dir_acl;
/// Location of file fragment, unused
uint faddr;
/// Second field reserved for the operating system
uchar os_reserved_2[12];
};
enum
{
// File types
EXT2_S_IFSOCK = 0xc000,
EXT2_S_IFLINK = 0xa000,
EXT2_S_IFREG = 0x8000,
EXT2_S_IFBLK = 0x6000,
EXT2_S_IFDIR = 0x4000,
EXT2_S_IFCHR = 0x2000,
EXT2_S_IFIFO = 0x1000,
/// Set UID
EXT2_S_ISUID = 0x0800,
/// Set GUID
EXT2_S_ISGID = 0x0400,
/// Sticky
EXT2_S_ISVTX = 0x0200,
// Normal UNIX file permissions
EXT2_S_IRUSR = 0x0100,
EXT2_S_IWUSR = 0x0080,
EXT2_S_IXUSR = 0x0040,
EXT2_S_IRGRP = 0x0020,
EXT2_S_IWGRP = 0x0010,
EXT2_S_IXGRP = 0x0008,
EXT2_S_IROTH = 0x0004,
EXT2_S_IWOTH = 0x0002,
EXT2_S_IXOTH = 0x0001,
};
/// File type flag (used on inode->mode)
#define EXT2_F_TYPE 0xf000
const extern uchar ext2_s_to_ft[];
/// Converts the file "mode" (inode->mode, EXT2_S_*) to a file type
/// (EXT2_FT_*).
#define EXT2_S_TO_FT(s) (ext2_s_to_ft[s >> 12])
struct ext2_dirent
{
uint inode;
ushort rec_len;
uchar name_len;
uchar file_type;
char name[];
};
enum
{
EXT2_FT_UNKNOWN = 0,
EXT2_FT_REGULAR_FILE,
EXT2_FT_DIR,
EXT2_FT_CHRDEV,
EXT2_FT_BLKDEV,
EXT2_FT_FIFO,
EXT2_FT_SOCK,
EXT2_FT_SYMLINK,
};
inline uint ext2_block_size(struct ext2_superblock *sb)
{
return 1024 << sb->block_size_shift;
}
/// Read a file system block (0-indexed), if necessary multiple disk
/// blocks will be read automatically
void ext2_read_block(struct ext2_superblock *sb, void *buffer,
uint block);
void ext2_write_block(struct ext2_superblock *sb, void *buffer,
uint block);
struct ext2_superblock ext2_read_superblock();
void ext2_write_superblock(struct ext2_superblock *sb);
/// Just for fun, corrupt the superblock (obviously don't actually do
/// this)
void ext2_corrupt_superblock_for_fun();
void ext2_mount(struct fs_node *where);
bool ext2_valid_filesystem();
/**
* @brief Get or set an inode
* @param inode Either a pointer to the value to be read (set=false),
* or the value to be written (set=true).
* @param set True if the inode should be set (written), false
* otherwise.
*/
bool ext2_get_or_set_inode(struct ext2_superblock *sb, uint number,
struct ext2_inode *inode, bool set);
bool ext2_find_inode(struct ext2_superblock *sb, uint number,
struct ext2_inode *inode);
bool ext2_set_inode(struct ext2_superblock *sb, uint number,
struct ext2_inode *inode);
/// Load a block group descriptor for a certain block group
struct ext2_block_group_descriptor ext2_load_bgd(
struct ext2_superblock *sb, uint block_group);
/// Write a block group descriptor for a certain block group
void ext2_write_bgd(struct ext2_superblock *sb, uint block_group,
struct ext2_block_group_descriptor *d);
/// Load or write a BGD
void ext2_load_or_write_bgd(struct ext2_superblock *sb,
uint block_group,
struct ext2_block_group_descriptor *d,
bool set);
/// List the contents of a directory dir. Calls `cb` for each item. If
/// `dir` is not a directory, returns false. Otherwise returns true.
/// if cb returns true, ls will continue. Otherwise it will stop.
bool ext2_dir_ls(struct ext2_superblock *sb,
struct ext2_inode *dir,
bool (*cb)(uint inode,
const char *name,
uint name_len,
void *data),
void *data);
/// Read a data block for the inode, 0 being the first block of the file.
bool ext2_read_inode_block(struct ext2_superblock *sb,
struct ext2_inode *inode,
void *buffer,
uint block);
/// Write a data block for the inode, 0 being the first block of the file.
bool ext2_write_inode_block(struct ext2_superblock *sb, struct ext2_inode *dir,
void *buffer, uint block);
ssize_t ext2_read_inode(struct ext2_superblock *sb,
struct ext2_inode *inode, void *buffer,
ssize_t size);
/**
* @brief Set a block in a bitmap
* @param bitmap_block The first block of the bitmap, not necessarily the block
* that this specific bit is in.
* @param index The bit to check, starting at 0
* @returns The value of the bit
*/
bool ext2_check_in_bitmap(struct ext2_superblock *sb, uint bitmap_block,
uint index);
/**
* @brief Set a block in a bitmap
* @param bitmap_block The first block of the bitmap, not necessarily the block
* that this specific bit is in.
* @param index The bit to set, starting at 0
* @param value The value of the bit, 0 for 0, non-0 for 1
*/
void ext2_set_in_bitmap(struct ext2_superblock *sb, uint bitmap_block,
uint index, bool value);
/**
* @brief Find the first zero bit in a bitset
* @param bitmap_block The first block of the bitmap
* @param num_blocks The number of blocks in the bitmap, or ~0 for no limit
* (UNSAFE).
* @param start_at The first bit to search from, useful if you want to ignore
* the first reserved inodes.
* @returns The index of the first zero bit, or -1 if there is none
*/
uint ext2_first_zero_bit(struct ext2_superblock *sb, uint bitmap_block,
uint num_blocks, uint start_at);
/**
* Find the first free inode number.
* @returns The inode if it was found, 0 if there are no free inodes.
*/
uint ext2_first_free_inode(struct ext2_superblock *sb);
void ext2_insert_into_dir(struct ext2_superblock *sb, struct ext2_inode *dir,
char *name, uint name_len, uint inode, uchar type);
/**
* Creates a hard link
* @param dir Directory to create the hard link in
* @param name Name of the link to create
* @param name_len length of name, not including (optional) NULL byte
* @param inode Inode number of link target
*/
bool ext2_hard_link(struct ext2_superblock *sb, struct ext2_inode *dir,
char *name, uint name_len, uint inode);
/**
* @brief Does a directory contain a certain entry?
* @param sb Superblock
* @param dir The directory to search in
* @param name The name of the entry to look for
* @param len The length of the name, not including the optional NULL byte
* @returns True if the entry is found, false if not, or if something
* goes wrong (ie: dir is not a directory)
*/
bool ext2_dir_contains(struct ext2_superblock *sb, struct ext2_inode *dir,
char *name, uint len);
/**
* @brief Find an entry in a directory
* @param dir Directory to search in
* @param name Name of file
* @param name_len Length of name, not including (optional) NULL byte.
* @returns 0 if no entry could be found, otherwise inode number for
* that entry
*/
uint ext2_dir_find(struct ext2_superblock *sb, struct ext2_inode *dir,
char *name, uint name_len);