feat: Vfs and Ext2 support. Code style/attribute improvements
Added VFS and Ext2 support. Optimized attributes of methods to improve code highlighting. Printf attribute, malloc attribute, etc.
This commit is contained in:
@@ -7,7 +7,7 @@
|
|||||||
// retrieved from https://github.com/blanham/liballoc
|
// retrieved from https://github.com/blanham/liballoc
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
void *malloc(size_t);
|
void __attribute__((assume_aligned (16), alloc_size (1), malloc)) *malloc(size_t);
|
||||||
|
|
||||||
void *realloc(void *, size_t);
|
void *realloc(void *, size_t);
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <myke/driver.h>
|
#include <myke/driver.h>
|
||||||
|
|
||||||
|
#define BLOCK_DEV_LBA_SIZE 512
|
||||||
|
|
||||||
#define BLOCK_DEV_ACCESS_OK 0
|
#define BLOCK_DEV_ACCESS_OK 0
|
||||||
#define BLOCK_DEV_ACCESS_ERR 1
|
#define BLOCK_DEV_ACCESS_ERR 1
|
||||||
|
|
||||||
@@ -27,21 +29,21 @@
|
|||||||
|
|
||||||
typedef struct block_device block_device_t;
|
typedef struct block_device block_device_t;
|
||||||
|
|
||||||
typedef uint8_t (*block_device_driver_check_device)(const block_device_t *device, uint8_t *first_sector);
|
typedef uint8_t (*block_device_driver_check_device)(block_device_t *device);
|
||||||
|
|
||||||
typedef uint8_t (*block_device_driver_free)(const block_device_t *device);
|
typedef uint8_t (*block_device_driver_free)(block_device_t *device);
|
||||||
|
|
||||||
typedef uint8_t (*block_device_access)(const block_device_t *device, uint8_t direction, uint32_t lba, uint8_t sectors,
|
typedef uint8_t (*block_device_access)(const block_device_t *device, uint8_t direction, uint32_t lba, uint8_t sectors,
|
||||||
void *target);
|
void *target);
|
||||||
|
|
||||||
struct block_dev_driver {
|
typedef struct block_dev_driver {
|
||||||
char name[16];
|
char name[16];
|
||||||
struct {
|
struct {
|
||||||
uint8_t partitioning: 1;
|
uint8_t partitioning: 1;
|
||||||
} flags;
|
} flags;
|
||||||
block_device_driver_check_device check_device;
|
block_device_driver_check_device check_device;
|
||||||
block_device_driver_free free_device;
|
block_device_driver_free free_device;
|
||||||
} __attribute__((__aligned__(STRUCT_ALIGNMENT)));
|
} __attribute__((__aligned__(STRUCT_ALIGNMENT))) block_dev_driver_t;
|
||||||
|
|
||||||
#define BLOCK_DEV_DRIVER(order) GENERIC_DRIVER(block_dev_driver, order)
|
#define BLOCK_DEV_DRIVER(order) GENERIC_DRIVER(block_dev_driver, order)
|
||||||
|
|
||||||
@@ -59,6 +61,7 @@ struct block_device {
|
|||||||
block_device_access access;
|
block_device_access access;
|
||||||
struct block_dev_driver *driver;
|
struct block_dev_driver *driver;
|
||||||
void *device_info; // pointer to driver defined structure
|
void *device_info; // pointer to driver defined structure
|
||||||
|
void *driver_info; // pointer to driver defined structure
|
||||||
// todo device info
|
// todo device info
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -66,8 +69,8 @@ uint8_t block_dev_register(block_device_t *device);
|
|||||||
|
|
||||||
void block_dev_free(block_device_t *device);
|
void block_dev_free(block_device_t *device);
|
||||||
|
|
||||||
|
void *block_dev_mount(const char *device, const char *driver_name);
|
||||||
|
|
||||||
void block_dev_print_info();
|
void block_dev_print_info();
|
||||||
|
|
||||||
bool block_dev_mount(char *identifier, char *driver);
|
|
||||||
|
|
||||||
#endif //NEW_KERNEL_BLOCKDEV_H
|
#endif //NEW_KERNEL_BLOCKDEV_H
|
||||||
|
|||||||
223
include/myke/vfs/lfs/ext2.h
Normal file
223
include/myke/vfs/lfs/ext2.h
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
//
|
||||||
|
// Created by rick on 18-09-21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef NEW_KERNEL_EXT2_H
|
||||||
|
#define NEW_KERNEL_EXT2_H
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <attributes.h>
|
||||||
|
|
||||||
|
#define EXT2_SIGNATURE 0xEF53
|
||||||
|
|
||||||
|
#define EXT2_SB_ADDR 1024
|
||||||
|
#define EXT2_SB_SIZE 1024
|
||||||
|
#define EXT2_BGD_START_ADDR (EXT2_SB_ADDR + EXT2_SB_SIZE)
|
||||||
|
|
||||||
|
#define EXT2_DEFAULT_RESERVED_INODES 11
|
||||||
|
#define EXT2_DEFAULT_INODE_SIZE 128
|
||||||
|
|
||||||
|
#define EXT2_ROOT_INODE 2
|
||||||
|
|
||||||
|
typedef struct ext2_sb {
|
||||||
|
uint32_t total_inodes;
|
||||||
|
uint32_t total_blocks;
|
||||||
|
uint32_t num_reserved_su;
|
||||||
|
uint32_t unallocated_blocks;
|
||||||
|
uint32_t unallocated_inodes;
|
||||||
|
uint32_t no_blocks_with_sb;
|
||||||
|
uint32_t block_size;
|
||||||
|
uint32_t fragment_size;
|
||||||
|
uint32_t no_blocks_per_group;
|
||||||
|
uint32_t no_fragments_per_group;
|
||||||
|
uint32_t no_inodes_per_group;
|
||||||
|
uint32_t last_mounted;
|
||||||
|
uint32_t last_written;
|
||||||
|
uint16_t no_mounted_since_fschk;
|
||||||
|
uint16_t max_no_mounted_since_fschk;
|
||||||
|
uint16_t ext2_signature;
|
||||||
|
uint16_t fs_state;
|
||||||
|
uint16_t error_action;
|
||||||
|
uint16_t minor_version;
|
||||||
|
uint32_t last_fschk;
|
||||||
|
uint32_t interval_fschk;
|
||||||
|
uint32_t os_id;
|
||||||
|
uint32_t major_version;
|
||||||
|
uint16_t uid_reserved;
|
||||||
|
uint16_t gid_reserved;
|
||||||
|
|
||||||
|
// below extended fields
|
||||||
|
uint32_t first_nor_reserved_inode;
|
||||||
|
uint16_t size_inode;
|
||||||
|
uint16_t owner_bg;
|
||||||
|
uint32_t features_optional;
|
||||||
|
uint32_t features_required;
|
||||||
|
uint32_t features_ro;
|
||||||
|
uint8_t fs_id[16];
|
||||||
|
char fs_name[16];
|
||||||
|
char last_mounted_path[64];
|
||||||
|
uint32_t compression_alg;
|
||||||
|
uint8_t preallocate_files;
|
||||||
|
uint8_t preallocate_dirs;
|
||||||
|
uint16_t: 16; // unused
|
||||||
|
uint8_t journal_id[16];
|
||||||
|
uint32_t journal_inode;
|
||||||
|
uint32_t journal_device;
|
||||||
|
uint32_t head_of_orphan_inode_list;
|
||||||
|
} att_packed ext2_sb_t;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
EXT2_FS_STATE_CLEAN = 1,
|
||||||
|
EXT2_FS_STATE_ERROR = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
EXT2_ERROR_ACTION_IGNORE = 1,
|
||||||
|
EXT2_ERROR_ACTION_REMOUNT_RO = 2,
|
||||||
|
EXT2_ERROR_ACTION_PANIC = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
EXT2_OS_ID_LINUX = 0,
|
||||||
|
EXT2_OS_ID_GNU_HURD = 1,
|
||||||
|
EXT2_OS_ID_MASIX = 2,
|
||||||
|
EXT2_OS_ID_FREE_BSD = 3,
|
||||||
|
EXT2_OS_ID_LITES = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
EXT2_FEATURE_OPTIONAL_PREALLOCATE = 0x01,
|
||||||
|
EXT2_FEATURE_OPTIONAL_AFS_SERVER_INODE = 0x02,
|
||||||
|
EXT2_FEATURE_OPTIONAL_HAS_JOURNAL = 0x04,
|
||||||
|
EXT2_FEATURE_OPTIONAL_EXTENDED_ATTRIBUTES = 0x08,
|
||||||
|
EXT2_FEATURE_OPTIONAL_CAN_RESIZE = 0x10,
|
||||||
|
EXT2_FEATURE_OPTIONAL_DIR_HASH_INDEX = 0x20,
|
||||||
|
};
|
||||||
|
#define EXT2_FEAT_OPT_SUPPORTED ( \
|
||||||
|
0 \
|
||||||
|
)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
EXT2_FEATURE_REQUIRED_COMPRESSION = 0x01,
|
||||||
|
EXT2_FEATURE_REQUIRED_DIR_HAS_TYPE = 0x02,
|
||||||
|
EXT2_FEATURE_REQUIRED_JOURNAL_REPLAY_REQUIRED = 0x04,
|
||||||
|
EXT2_FEATURE_REQUIRED_HAS_JOURNAL_DEVICE = 0x08,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define EXT2_FEAT_REQ_SUPPORTED ( \
|
||||||
|
EXT2_FEATURE_REQUIRED_DIR_HAS_TYPE | \
|
||||||
|
0 \
|
||||||
|
)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
EXT2_FEATURE_RO_SPARSE_SUPERBLOCKS_AND_GROUPS_DESCRIPTOR = 0x01,
|
||||||
|
EXT2_FEATURE_RO_64BIT_SIZE = 0x02,
|
||||||
|
EXT2_FEATURE_RO_DIR_BTREE = 0X04
|
||||||
|
};
|
||||||
|
|
||||||
|
#define EXT2_FEAT_RO_64BIT_SIZE (SIZE_MAX > UINT32_MAX)
|
||||||
|
#define EXT2_FEAT_RO_SUPPORTED ( \
|
||||||
|
(EXT2_FEAT_RO_64BIT_SIZE ? EXT2_FEATURE_RO_64BIT_SIZE : 0) | \
|
||||||
|
0 \
|
||||||
|
)
|
||||||
|
|
||||||
|
typedef struct ext2_bg_descriptor {
|
||||||
|
uint32_t block_usage_bm;
|
||||||
|
uint32_t inode_usage_bm;
|
||||||
|
uint32_t start_block_inode;
|
||||||
|
uint16_t no_unallocated_blocks;
|
||||||
|
uint16_t no_unallocated_inodes;
|
||||||
|
uint16_t no_dirs;
|
||||||
|
uint8_t unused[14];
|
||||||
|
} ext2_bg_descriptor_t;
|
||||||
|
|
||||||
|
typedef struct ext2_inode {
|
||||||
|
union {
|
||||||
|
uint16_t type_permission;
|
||||||
|
struct {
|
||||||
|
uint8_t permission_o: 3;
|
||||||
|
uint8_t permission_g: 3;
|
||||||
|
uint8_t permission_u: 3;
|
||||||
|
bool permission_sticky: 1;
|
||||||
|
bool permission_setgid: 1;
|
||||||
|
bool permission_setuid: 1;
|
||||||
|
uint8_t type: 4;
|
||||||
|
} att_packed;
|
||||||
|
};
|
||||||
|
uint16_t uid;
|
||||||
|
uint32_t size_l;
|
||||||
|
uint32_t last_access;
|
||||||
|
uint32_t created;
|
||||||
|
uint32_t last_mod;
|
||||||
|
uint32_t deleted;
|
||||||
|
uint16_t gid;
|
||||||
|
uint16_t no_hard_links;
|
||||||
|
uint32_t no_sectors;
|
||||||
|
uint32_t flags;
|
||||||
|
uint32_t os_val1;
|
||||||
|
uint32_t dbp[12]; // fist 12 direct block pointers
|
||||||
|
uint32_t sibp;
|
||||||
|
uint32_t dibp;
|
||||||
|
uint32_t tibp;
|
||||||
|
uint32_t generation;
|
||||||
|
uint32_t extended_attr;
|
||||||
|
union {
|
||||||
|
uint32_t size_h;
|
||||||
|
uint32_t dir_acl;
|
||||||
|
};
|
||||||
|
uint32_t fragment_addr;
|
||||||
|
uint8_t os_val2[12];
|
||||||
|
} att_packed ext2_inode_t;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
EXT2_INODE_FLAG_SECURE_DELETE = 0x00000001,
|
||||||
|
EXT2_INODE_FLAG_KEEP_COPY_ON_DELETE = 0x00000002,
|
||||||
|
EXT2_INODE_FLAG_FILE_COMPRESSION = 0x00000004,
|
||||||
|
EXT2_INODE_FLAG_SYNC_UPDATE = 0x00000008,
|
||||||
|
EXT2_INODE_FLAG_IMMUTABLE = 0x00000010,
|
||||||
|
EXT2_INODE_FLAG_APPEND_ONLY = 0x00000020,
|
||||||
|
EXT2_INODE_FLAG_NO_DUMP = 0x00000040,
|
||||||
|
EXT2_INODE_FLAG_LAST_ACCESS_IGNORE = 0x00000080,
|
||||||
|
EXT2_INODE_FLAG_HASH_INDEXED_DIR = 0x00010000,
|
||||||
|
EXT2_INODE_FLAG_AFS_DIRECTORY = 0x00020000,
|
||||||
|
EXT2_INODE_FLAG_JOURNAL_FILE_DATA = 0x00040000,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct ext2_dir_entry {
|
||||||
|
uint32_t inode;
|
||||||
|
uint16_t ent_size;
|
||||||
|
uint8_t name_size;
|
||||||
|
uint8_t type_or_name_size_h;
|
||||||
|
char name;
|
||||||
|
} ext2_dir_entry_t;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
EXT2_INODE_TYPE_FIFO = 0x1,
|
||||||
|
EXT2_INODE_TYPE_CHAR_DEV = 0x2,
|
||||||
|
EXT2_INODE_TYPE_DIR = 0x4,
|
||||||
|
EXT2_INODE_TYPE_BLOCK_DEV = 0x6,
|
||||||
|
EXT2_INODE_TYPE_FILE = 0x8,
|
||||||
|
EXT2_INODE_TYPE_SYM_LINK = 0xA,
|
||||||
|
EXT2_INODE_TYPE_UNIX_SOCK = 0xC,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
EXT2_DIR_TYPE_UNKNOWN = 0,
|
||||||
|
EXT2_DIR_TYPE_FILE = 1,
|
||||||
|
EXT2_DIR_TYPE_DIR = 2,
|
||||||
|
EXT2_DIR_TYPE_CHAR_DEV = 3,
|
||||||
|
EXT2_DIR_TYPE_BLOCK_DEV = 4,
|
||||||
|
EXT2_DIR_TYPE_FIFO = 5,
|
||||||
|
EXT2_DIR_TYPE_SOCKET = 6,
|
||||||
|
EXT2_DIR_TYPE_SOFT_LINK = 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct ext2_mount_info {
|
||||||
|
ext2_sb_t sb;
|
||||||
|
uint32_t no_block_groups;
|
||||||
|
uint64_t block_size;
|
||||||
|
uint64_t fragment_size;
|
||||||
|
void *block_dev;
|
||||||
|
} ext2_mount_info_t;
|
||||||
|
|
||||||
|
#endif //NEW_KERNEL_EXT2_H
|
||||||
36
include/myke/vfs/vfs-driver.h
Normal file
36
include/myke/vfs/vfs-driver.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
//
|
||||||
|
// Created by rick on 19-09-21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef NEW_KERNEL_VFS_DRIVER_H
|
||||||
|
#define NEW_KERNEL_VFS_DRIVER_H
|
||||||
|
|
||||||
|
#include <myke/driver.h>
|
||||||
|
#include <myke/vfs/vfs.h>
|
||||||
|
|
||||||
|
typedef struct vfs_driver {
|
||||||
|
char name[16];
|
||||||
|
struct {
|
||||||
|
} flags;
|
||||||
|
|
||||||
|
// api
|
||||||
|
int (*vfs_mount)(vfs_mount_t *mount);
|
||||||
|
|
||||||
|
int (*open)(vfs_mount_t *mount, vfs_fd_t *dir, const char *path, int mode, vfs_fd_t *out);
|
||||||
|
|
||||||
|
int (*close)(vfs_mount_t *mount, vfs_fd_t *fd);
|
||||||
|
|
||||||
|
int (*fstat)(vfs_mount_t *mount, vfs_fd_t *fd, stat_t *target, int flags);
|
||||||
|
|
||||||
|
int (*fread)(vfs_mount_t *mount, vfs_fd_t *fd, void *target, size_t size);
|
||||||
|
|
||||||
|
int (*dgetent)(vfs_mount_t *mount, vfs_fd_t *fd, void *target, size_t size);
|
||||||
|
|
||||||
|
} __attribute__((__aligned__(STRUCT_ALIGNMENT))) vfs_driver_t;
|
||||||
|
|
||||||
|
void vfs_mk_dirent_record(vfs_dirent_t *ent, uint32_t inode, uint32_t cur_offset, uint8_t type, char *name,
|
||||||
|
size_t name_length);
|
||||||
|
|
||||||
|
#define VFS_DRIVER(order) GENERIC_DRIVER(vfs_driver, order)
|
||||||
|
|
||||||
|
#endif //NEW_KERNEL_VFS_DRIVER_H
|
||||||
70
include/myke/vfs/vfs.h
Normal file
70
include/myke/vfs/vfs.h
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
//
|
||||||
|
// Created by rick on 19-09-21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef NEW_KERNEL_VFS_H
|
||||||
|
#define NEW_KERNEL_VFS_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#define VFS_MOUNT_OK 0
|
||||||
|
#define VFS_MOUNT_ERROR 1
|
||||||
|
|
||||||
|
#define VFS_OPEN_ERROR 1
|
||||||
|
#define VFS_OPEN_OK 0
|
||||||
|
|
||||||
|
#define VFS_CLOSE_OK 1
|
||||||
|
|
||||||
|
#define VFS_READ_ERROR (-1)
|
||||||
|
|
||||||
|
#define VFS_DGETENTS_ERR 1
|
||||||
|
|
||||||
|
struct vfs_mount;
|
||||||
|
|
||||||
|
typedef struct vfs_mount {
|
||||||
|
struct {
|
||||||
|
} flags;
|
||||||
|
const char *prefix;
|
||||||
|
const char *device;
|
||||||
|
void *driver; // vfs_mount_driver_t
|
||||||
|
void *global_driver_data;
|
||||||
|
struct vfs_mount *next;
|
||||||
|
} vfs_mount_t;
|
||||||
|
|
||||||
|
typedef struct vfs_fd {
|
||||||
|
struct {
|
||||||
|
} flags;
|
||||||
|
vfs_mount_t *mount;
|
||||||
|
void *driver_data;
|
||||||
|
} vfs_fd_t;
|
||||||
|
|
||||||
|
#define VFS_DIRENT_BASE_SIZE (4 + 4 + 2 + 1)
|
||||||
|
#define VFS_DIRENT_SIZE(name_length) ((VFS_DIRENT_BASE_SIZE + (name_length) + 1 + 15) & (~0xF))
|
||||||
|
#define VFS_DIRENT_MAX_SIZE (VFS_DIRENT_BASE_SIZE + 256 + 1)
|
||||||
|
|
||||||
|
typedef struct vfs_dirent {
|
||||||
|
uint32_t inode;
|
||||||
|
uint32_t offset_next;
|
||||||
|
uint16_t reclen;
|
||||||
|
uint8_t type;
|
||||||
|
char name[];
|
||||||
|
} vfs_dirent_t;
|
||||||
|
|
||||||
|
int vfs_mount(const char *path, const char *device, const char *driver);
|
||||||
|
|
||||||
|
// https://man7.org/linux/man-pages/man2/open.2.html
|
||||||
|
vfs_fd_t *vfs_open(const char *path, int flags, int mode);
|
||||||
|
|
||||||
|
void vfs_close(vfs_fd_t *fd);
|
||||||
|
|
||||||
|
// https://man7.org/linux/man-pages/man2/stat.2.html
|
||||||
|
int vfs_fstat(vfs_fd_t *fd, stat_t *target, int flags);
|
||||||
|
|
||||||
|
// https://man7.org/linux/man-pages/man2/read.2.html
|
||||||
|
int vfs_read(vfs_fd_t *fd, void *target, size_t size);
|
||||||
|
|
||||||
|
// inspiration https://man7.org/linux/man-pages/man2/getdents.2.html
|
||||||
|
int vfs_getdents(vfs_fd_t *fd, void *target, int count);
|
||||||
|
|
||||||
|
#endif //NEW_KERNEL_VFS_H
|
||||||
@@ -24,7 +24,7 @@ void fflush(FILE *);
|
|||||||
|
|
||||||
FILE *fopen(const char *, const char *);
|
FILE *fopen(const char *, const char *);
|
||||||
|
|
||||||
void fprintf(FILE *, const char *, ...);
|
void __attribute__((format (printf, 2, 3))) fprintf(FILE *, const char *, ...);
|
||||||
|
|
||||||
size_t fread(void *, size_t, size_t, FILE *);
|
size_t fread(void *, size_t, size_t, FILE *);
|
||||||
|
|
||||||
@@ -38,11 +38,11 @@ void setbuf(FILE *, char *);
|
|||||||
|
|
||||||
int vfprintf(FILE *, const char *, va_list);
|
int vfprintf(FILE *, const char *, va_list);
|
||||||
|
|
||||||
int vprintf(const char* fmt, va_list args);
|
int vprintf(const char *fmt, va_list args);
|
||||||
|
|
||||||
int printf(const char *fmt, ...);
|
int __attribute__((format (printf, 1, 2))) printf(const char *fmt, ...);
|
||||||
|
|
||||||
int sprintf(char *target, const char *fmt, ...);
|
int __attribute__((format (printf, 2, 3))) sprintf(char *target, const char *fmt, ...);
|
||||||
|
|
||||||
|
|
||||||
#endif //NEW_KERNEL_STDIO_H
|
#endif //NEW_KERNEL_STDIO_H
|
||||||
|
|||||||
@@ -7,9 +7,9 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
void* memcpy(void *dst, const void *src, size_t amount);
|
void *memcpy(void *dst, const void *src, size_t amount);
|
||||||
|
|
||||||
void* memset(void *dst, int data, size_t amount);
|
void *memset(void *dst, int data, size_t amount);
|
||||||
|
|
||||||
void *memmove(void *dst, const void *src, size_t amount);
|
void *memmove(void *dst, const void *src, size_t amount);
|
||||||
|
|
||||||
@@ -19,19 +19,19 @@ void *strncpy(char *dst, const char *src, size_t n);
|
|||||||
|
|
||||||
size_t strlen(const char *str);
|
size_t strlen(const char *str);
|
||||||
|
|
||||||
const char *strchr(const char *s, char c);
|
char *strchr(const char *s, char c);
|
||||||
|
|
||||||
const char *strrchr(const char *s, char c);
|
char *strrchr(const char *s, char c);
|
||||||
|
|
||||||
int memcmp(const void *s1, const void *s2, size_t n);
|
int memcmp(const void *s1, const void *s2, size_t n);
|
||||||
|
|
||||||
int strcmp(const char *s1, const char *s2);
|
int strcmp(const char *s1, const char *s2);
|
||||||
|
|
||||||
int strncmp(const char *s1, const char *s2, int n);
|
int strncmp(const char *s1, const char *s2, size_t n);
|
||||||
|
|
||||||
char* strdup(const char* s);
|
char *strdup(const char *s);
|
||||||
|
|
||||||
char* strndup(const char* s, size_t n);
|
char *strndup(const char *s, size_t n);
|
||||||
|
|
||||||
char *strcat(char *dest, const char *src);
|
char *strcat(char *dest, const char *src);
|
||||||
|
|
||||||
|
|||||||
50
include/sys/stat.h
Normal file
50
include/sys/stat.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
//
|
||||||
|
// Created by rick on 06-10-21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef NEW_KERNEL_STAT_H
|
||||||
|
#define NEW_KERNEL_STAT_H
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
// https://man7.org/linux/man-pages/man2/stat.2.html
|
||||||
|
|
||||||
|
typedef uint32_t dev_t;
|
||||||
|
typedef uint32_t ino_t;
|
||||||
|
typedef uint32_t mode_t;
|
||||||
|
typedef uint32_t nlink_t;
|
||||||
|
typedef uint32_t uid_t;
|
||||||
|
typedef uint32_t gid_t;
|
||||||
|
typedef size_t off_t;
|
||||||
|
typedef size_t blksize_t;
|
||||||
|
typedef uint32_t blkcnt_t;
|
||||||
|
|
||||||
|
|
||||||
|
struct stat {
|
||||||
|
dev_t st_dev; /* ID of device containing file */
|
||||||
|
ino_t st_ino; /* Inode number */
|
||||||
|
mode_t st_mode; /* File type and mode */
|
||||||
|
nlink_t st_nlink; /* Number of hard links */
|
||||||
|
uid_t st_uid; /* User ID of owner */
|
||||||
|
gid_t st_gid; /* Group ID of owner */
|
||||||
|
dev_t st_rdev; /* Device ID (if special file) */
|
||||||
|
off_t st_size; /* Total size, in bytes */
|
||||||
|
blksize_t st_blksize; /* Block size for filesystem I/O */
|
||||||
|
blkcnt_t st_blocks; /* Number of 512B blocks allocated */
|
||||||
|
|
||||||
|
/* Since Linux 2.6, the kernel supports nanosecond
|
||||||
|
precision for the following timestamp fields.
|
||||||
|
For the details before Linux 2.6, see NOTES. */
|
||||||
|
|
||||||
|
struct timespec st_atim; /* Time of last access */
|
||||||
|
struct timespec st_mtim; /* Time of last modification */
|
||||||
|
struct timespec st_ctim; /* Time of last status change */
|
||||||
|
|
||||||
|
#define st_atime st_atim.tv_sec /* Backward compatibility */
|
||||||
|
#define st_mtime st_mtim.tv_sec
|
||||||
|
#define st_ctime st_ctim.tv_sec
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct stat stat_t;
|
||||||
|
|
||||||
|
#endif //NEW_KERNEL_STAT_H
|
||||||
@@ -5,4 +5,10 @@
|
|||||||
#ifndef NEW_KERNEL_TIME_H
|
#ifndef NEW_KERNEL_TIME_H
|
||||||
#define NEW_KERNEL_TIME_H
|
#define NEW_KERNEL_TIME_H
|
||||||
|
|
||||||
|
typedef uint32_t time_t;
|
||||||
|
|
||||||
|
struct timespec {
|
||||||
|
time_t tv_sec;
|
||||||
|
long tv_nsec;
|
||||||
|
};
|
||||||
#endif //NEW_KERNEL_TIME_H
|
#endif //NEW_KERNEL_TIME_H
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <myke/mem/mem.h>
|
#include <myke/mem/mem.h>
|
||||||
#include <myke/tasks/task.h>
|
#include <myke/tasks/task.h>
|
||||||
#include <myke/util/power.h>
|
#include <myke/util/power.h>
|
||||||
|
#include <myke/vfs/vfs.h>
|
||||||
|
|
||||||
#ifdef ENABLE_SELF_TEST
|
#ifdef ENABLE_SELF_TEST
|
||||||
|
|
||||||
@@ -54,6 +55,12 @@ void shutdown(const char *args);
|
|||||||
|
|
||||||
void ps(const char *args);
|
void ps(const char *args);
|
||||||
|
|
||||||
|
void mount(const char *args);
|
||||||
|
|
||||||
|
void ls(const char *args);
|
||||||
|
|
||||||
|
void cat(const char *args);
|
||||||
|
|
||||||
#ifdef ENABLE_SELF_TEST
|
#ifdef ENABLE_SELF_TEST
|
||||||
|
|
||||||
void explode(const char *args);
|
void explode(const char *args);
|
||||||
@@ -75,6 +82,9 @@ cmd_handler cmd_handlers[] = {
|
|||||||
{"ide", ide},
|
{"ide", ide},
|
||||||
{"shutdown", shutdown},
|
{"shutdown", shutdown},
|
||||||
{"ps", ps},
|
{"ps", ps},
|
||||||
|
{"mount", mount},
|
||||||
|
{"ls", ls},
|
||||||
|
{"cat", cat},
|
||||||
#ifdef ENABLE_SELF_TEST
|
#ifdef ENABLE_SELF_TEST
|
||||||
{"slingurl", slingurl},
|
{"slingurl", slingurl},
|
||||||
{"kill-self", kill_self},
|
{"kill-self", kill_self},
|
||||||
@@ -185,17 +195,74 @@ void ide(const char *arg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mount(const char *arg) {
|
||||||
|
vfs_mount("/", "ide0p0", "ext2");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ls(const char *arg) {
|
||||||
|
vfs_fd_t *fd = vfs_open("/", 0, 0);
|
||||||
|
if (fd == NULL) {
|
||||||
|
printf("could not open /\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
void *data = malloc(1024);
|
||||||
|
if (data == NULL) {
|
||||||
|
printf("malloc fail\n");
|
||||||
|
vfs_close(fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint32_t num = 0;
|
||||||
|
while ((num = vfs_getdents(fd, data, 1024)) > 0) {
|
||||||
|
vfs_dirent_t *ent = data;
|
||||||
|
while (true) {
|
||||||
|
printf("%s\n", ent->name);
|
||||||
|
if (ent->offset_next >= 1024) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ent = &data[ent->offset_next];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(data);
|
||||||
|
vfs_close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cat(const char *arg) {
|
||||||
|
vfs_fd_t *fd = vfs_open("/sda1", 0, 0);
|
||||||
|
vfs_close(fd);
|
||||||
|
fd = vfs_open("/test.txt", 0, 0);
|
||||||
|
if (fd == NULL) {
|
||||||
|
printf("could not open /test.txt\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char *data = malloc(1024);
|
||||||
|
if (data == NULL) {
|
||||||
|
printf("no mem\n");
|
||||||
|
vfs_close(fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int read = vfs_read(fd, data, 1024);
|
||||||
|
if (read < 0) {
|
||||||
|
printf("Failed to read\n");
|
||||||
|
} else if (read == 0) {
|
||||||
|
printf("emtpy file\n");
|
||||||
|
} else {
|
||||||
|
printf("first 10 chars %10s\n", data);
|
||||||
|
}
|
||||||
|
free(data);
|
||||||
|
vfs_close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
void store_bootloader_info(multiboot_info_t *multiboot_info) {
|
void store_bootloader_info(multiboot_info_t *multiboot_info) {
|
||||||
// get bootloader and cmdline
|
// get bootloader and cmdline
|
||||||
if (multiboot_info->flags & MULTIBOOT_INFO_CMDLINE) {
|
if (multiboot_info->flags & MULTIBOOT_INFO_CMDLINE) {
|
||||||
int cmdline_length = strlen((const char *) multiboot_info->cmdline);
|
size_t cmdline_length = strlen((const char *) multiboot_info->cmdline);
|
||||||
if (cmdline_length > CMDLINE_MAX_LENGTH) {
|
if (cmdline_length > CMDLINE_MAX_LENGTH) {
|
||||||
k_panics("cmdline to long!\n");
|
k_panics("cmdline to long!\n");
|
||||||
}
|
}
|
||||||
memcpy(cmdline, (char *) multiboot_info->cmdline, cmdline_length);
|
memcpy(cmdline, (char *) multiboot_info->cmdline, cmdline_length);
|
||||||
}
|
}
|
||||||
if (multiboot_info->flags & MULTIBOOT_INFO_BOOT_LOADER_NAME) {
|
if (multiboot_info->flags & MULTIBOOT_INFO_BOOT_LOADER_NAME) {
|
||||||
int bootloader_length = strlen((const char *) multiboot_info->boot_loader_name);
|
size_t bootloader_length = strlen((const char *) multiboot_info->boot_loader_name);
|
||||||
if (bootloader_length > BOOTLOADER_NAME_MAX_LENGTH) {
|
if (bootloader_length > BOOTLOADER_NAME_MAX_LENGTH) {
|
||||||
k_panics("bootloader name to long!\n");
|
k_panics("bootloader name to long!\n");
|
||||||
}
|
}
|
||||||
@@ -226,6 +293,7 @@ void att_noreturn main_loop(void *data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef K_SHELL
|
#ifdef K_SHELL
|
||||||
|
|
||||||
void main_loop_start() {
|
void main_loop_start() {
|
||||||
task_spawn(main_loop, NULL, "main");
|
task_spawn(main_loop, NULL, "main");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,11 @@ uint32_t vasprintf(char *buf, const char *fmt, va_list args) {
|
|||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
int l = 0;
|
||||||
|
while (fmt[i] == 'l') {
|
||||||
|
l++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
switch (fmt[i]) {
|
switch (fmt[i]) {
|
||||||
case 's': { // string
|
case 's': { // string
|
||||||
uint32_t j = 0;
|
uint32_t j = 0;
|
||||||
@@ -87,7 +92,12 @@ uint32_t vasprintf(char *buf, const char *fmt, va_list args) {
|
|||||||
case 'x':
|
case 'x':
|
||||||
case 'p':
|
case 'p':
|
||||||
case 'X': // todo capitalize
|
case 'X': // todo capitalize
|
||||||
print_int((uint32_t) va_arg(args, uint32_t), field_width, buf, &ptr, 16);
|
if (l == 0 || l == 1) {
|
||||||
|
print_int((uint32_t) va_arg(args, uint32_t), field_width, buf, &ptr, 16);
|
||||||
|
} else if (l == 2) {
|
||||||
|
print_int((uint64_t) va_arg(args, uint64_t), field_width, buf, &ptr, 16);
|
||||||
|
}
|
||||||
|
// todo error
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
case 'd':
|
case 'd':
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ void *memset(void *dst, int data, size_t amount) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void *memmove(void *dst, const void *src, size_t amount) {
|
void *memmove(void *dst, const void *src, size_t amount) {
|
||||||
void* tmp = malloc(amount);
|
void *tmp = malloc(amount);
|
||||||
if (tmp == NULL) {
|
if (tmp == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -48,16 +48,19 @@ size_t strlen(const char *str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int strcmp(const char *s1, const char *s2) {
|
int strcmp(const char *s1, const char *s2) {
|
||||||
int len1 = strlen(s1);
|
size_t len1 = strlen(s1);
|
||||||
int len2 = strlen(s2);
|
size_t len2 = strlen(s2);
|
||||||
return strncmp(s1, s2, MAX(len1, len2));
|
return strncmp(s1, s2, MAX(len1, len2));
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *strchr(const char *s, char c) {
|
char *strchr(const char *s, char c) {
|
||||||
int index = 0;
|
size_t index = 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
if (s[index] == c) {
|
if (s[index] == c) {
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers"
|
||||||
return &s[index];
|
return &s[index];
|
||||||
|
#pragma clang diagnostic pop
|
||||||
}
|
}
|
||||||
if (s[index] == 0) {
|
if (s[index] == 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -66,11 +69,14 @@ const char *strchr(const char *s, char c) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *strrchr(const char *s, char c) {
|
char *strrchr(const char *s, char c) {
|
||||||
int index = strlen(s);
|
size_t index = strlen(s);
|
||||||
while (1) {
|
while (1) {
|
||||||
if (s[index] == c) {
|
if (s[index] == c) {
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers"
|
||||||
return &s[index];
|
return &s[index];
|
||||||
|
#pragma clang diagnostic pop
|
||||||
}
|
}
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -90,8 +96,8 @@ int memcmp(const void *s1, const void *s2, size_t n) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int strncmp(const char *s1, const char *s2, int n) {
|
int strncmp(const char *s1, const char *s2, size_t n) {
|
||||||
for (int i = 0; i < n; ++i) {
|
for (size_t i = 0; i < n; ++i) {
|
||||||
if (s1[i] == 0 && s2[i] == 0) {
|
if (s1[i] == 0 && s2[i] == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ static struct liballoc_major *allocate_new_page(unsigned int size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void *malloc(size_t req_size) {
|
void __attribute__((assume_aligned (16), alloc_size (1), malloc)) *malloc(size_t req_size) {
|
||||||
int startedBet = 0;
|
int startedBet = 0;
|
||||||
unsigned long long bestSize = 0;
|
unsigned long long bestSize = 0;
|
||||||
void *p = NULL;
|
void *p = NULL;
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
#include <attributes.h>
|
#include <attributes.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <myke/vfs/blockdev.h>
|
#include <myke/vfs/blockdev.h>
|
||||||
@@ -26,6 +25,25 @@ extern struct block_dev_driver __stop_block_dev_driver[];
|
|||||||
semaphore_t *block_semaphore;
|
semaphore_t *block_semaphore;
|
||||||
bool blockdev_task_running = false;
|
bool blockdev_task_running = false;
|
||||||
|
|
||||||
|
block_device_t *block_dev_get_by_id(const char *name) {
|
||||||
|
for (int i = 0; i < last_block_dev; ++i) {
|
||||||
|
if (block_devices[i].flags.present
|
||||||
|
&& strcmp(block_devices[i].identifier, name) == 0) {
|
||||||
|
return &block_devices[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
block_dev_driver_t *block_dev_driver_by_name(const char *name) {
|
||||||
|
for (size_t i = 0; i < NUM_DRIVERS; ++i) {
|
||||||
|
if (strcmp(DRIVER(i)->name, name) == 0) {
|
||||||
|
return DRIVER(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t block_dev_register(block_device_t *device) {
|
uint8_t block_dev_register(block_device_t *device) {
|
||||||
if (last_block_dev >= MAX_BLOCK_DEVS - 1) {
|
if (last_block_dev >= MAX_BLOCK_DEVS - 1) {
|
||||||
return BLOCK_DEV_REGISTER_FULL;
|
return BLOCK_DEV_REGISTER_FULL;
|
||||||
@@ -39,6 +57,25 @@ uint8_t block_dev_register(block_device_t *device) {
|
|||||||
return BLOCK_DEV_REGISTER_OK;
|
return BLOCK_DEV_REGISTER_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *block_dev_mount(const char *device, const char *driver_name) {
|
||||||
|
if (device == NULL || driver_name == NULL || strlen(device) == 0 || strlen(driver_name) == 0) {
|
||||||
|
return NULL; // invalid input
|
||||||
|
}
|
||||||
|
block_device_t *dev = block_dev_get_by_id(device);
|
||||||
|
if (dev == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
block_dev_driver_t *driver = block_dev_driver_by_name(driver_name);
|
||||||
|
if (driver == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (driver->check_device(dev) == BLOCK_DEV_DRIVER_CHECK_OK) {
|
||||||
|
dev->driver = driver;
|
||||||
|
return dev->driver_info;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void block_dev_free(block_device_t *device) {
|
void block_dev_free(block_device_t *device) {
|
||||||
//todo
|
//todo
|
||||||
k_panics("block dev free not supported");
|
k_panics("block dev free not supported");
|
||||||
@@ -52,53 +89,10 @@ int block_dev_num_not_scanned() {
|
|||||||
return not_scanned;
|
return not_scanned;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool block_dev_mount(char *identifier, char *driver_name) {
|
|
||||||
bool result = true;
|
|
||||||
block_device_t *device = NULL;
|
|
||||||
for (int i = 0; i < last_block_dev; ++i) {
|
|
||||||
if (strncmp(block_devices[i].identifier, identifier, 16) == 0) {
|
|
||||||
device = &block_devices[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (identifier == NULL) {
|
|
||||||
result = false;
|
|
||||||
goto _end;
|
|
||||||
}
|
|
||||||
struct block_dev_driver *driver = NULL;
|
|
||||||
for (size_t j = 0; j < NUM_DRIVERS; ++j) {
|
|
||||||
if (strncmp(DRIVER(j)->name, driver_name, 16) == 0) {
|
|
||||||
driver = DRIVER(j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (driver == NULL) {
|
|
||||||
result = false;
|
|
||||||
goto _end;
|
|
||||||
}
|
|
||||||
uint8_t *lba0 = malloc(device->block_size);
|
|
||||||
uint8_t read_result = device->access(device, BLOCK_DEV_DIRECTION_READ, 0, 1, lba0);
|
|
||||||
if (read_result != BLOCK_DEV_ACCESS_OK) {
|
|
||||||
result = false;
|
|
||||||
goto _access_fail;
|
|
||||||
}
|
|
||||||
if (driver->check_device(device, lba0) != BLOCK_DEV_DRIVER_CHECK_OK) {
|
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
_access_fail:
|
|
||||||
free(lba0);
|
|
||||||
_end:
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void block_dev_scan() {
|
void block_dev_scan() {
|
||||||
int c_last_block_dev = last_block_dev;
|
int c_last_block_dev = last_block_dev;
|
||||||
for (int i = 0; i < c_last_block_dev; ++i) {
|
for (int i = 0; i < c_last_block_dev; ++i) {
|
||||||
if (block_devices[i].flags.scanned || !block_devices[i].flags.present) continue;
|
if (block_devices[i].flags.scanned || !block_devices[i].flags.present) continue;
|
||||||
uint8_t *lba0 = malloc(block_devices[i].block_size);
|
|
||||||
uint8_t read_result = block_devices[i].access(&block_devices[i], BLOCK_DEV_DIRECTION_READ, 0, 1, lba0);
|
|
||||||
if (read_result != BLOCK_DEV_ACCESS_OK) {
|
|
||||||
block_devices[i].flags.unreadable = 1;
|
|
||||||
goto _block_dev_scan_free;
|
|
||||||
}
|
|
||||||
for (size_t j = 0; j < NUM_DRIVERS; ++j) {
|
for (size_t j = 0; j < NUM_DRIVERS; ++j) {
|
||||||
// only partitioning drivers are automatically assigned
|
// only partitioning drivers are automatically assigned
|
||||||
if (!DRIVER(i)->flags.partitioning) {
|
if (!DRIVER(i)->flags.partitioning) {
|
||||||
@@ -110,15 +104,13 @@ void block_dev_scan() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// let the driver test the disk
|
// let the driver test the disk
|
||||||
uint8_t driver_result = DRIVER(j)->check_device(&block_devices[i], lba0);
|
uint8_t driver_result = DRIVER(j)->check_device(&block_devices[i]);
|
||||||
if (driver_result == BLOCK_DEV_DRIVER_CHECK_OK) {
|
if (driver_result == BLOCK_DEV_DRIVER_CHECK_OK) {
|
||||||
block_devices[i].driver = DRIVER(j);
|
block_devices[i].driver = DRIVER(j);
|
||||||
block_devices[i].flags.driver_installed = 1;
|
block_devices[i].flags.driver_installed = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_block_dev_scan_free:
|
|
||||||
free(lba0);
|
|
||||||
block_devices[i].flags.scanned = 1;
|
block_devices[i].flags.scanned = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
438
kernel/vfs/lfs/ext2.c
Normal file
438
kernel/vfs/lfs/ext2.c
Normal file
@@ -0,0 +1,438 @@
|
|||||||
|
//
|
||||||
|
// Created by rick on 19-09-21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <myke/vfs/blockdev.h>
|
||||||
|
#include <myke/vfs/lfs/ext2.h>
|
||||||
|
#include <myke/vfs/vfs-driver.h>
|
||||||
|
#include <myke/libk/libk.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
|
||||||
|
// https://wiki.osdev.org/Ext2
|
||||||
|
|
||||||
|
#define EXT2_DRIVER_NAME "ext2"
|
||||||
|
#define MI(mount) ((ext2_mount_info_t *)(mount)->global_driver_data)
|
||||||
|
#define FDI(fd) ((ext2_fd_info_t *)(fd)->driver_data)
|
||||||
|
#define DIV_ROUND_UP(a, b) (((a) + ((b) - 1)) / (b))
|
||||||
|
|
||||||
|
typedef struct ext2_dgetents_state {
|
||||||
|
uint32_t bp;
|
||||||
|
void *current_data;
|
||||||
|
void *current_data_pos;
|
||||||
|
void *current_data_end;
|
||||||
|
uint32_t cur;
|
||||||
|
bool at_end_of_block;
|
||||||
|
} ext2_dgetents_state_t;
|
||||||
|
|
||||||
|
typedef struct ext2_fd_info {
|
||||||
|
uint32_t inode_nr;
|
||||||
|
ext2_inode_t *inode;
|
||||||
|
size_t seek_position;
|
||||||
|
ext2_dgetents_state_t *dgetents_state;
|
||||||
|
size_t size;
|
||||||
|
bool dgetents_done;
|
||||||
|
} ext2_fd_info_t;
|
||||||
|
|
||||||
|
#define EXT2_READ_OK 0
|
||||||
|
#define EXT2_READ_ENOMEM 1
|
||||||
|
#define EXT2_READ_IOERR 2
|
||||||
|
#define EXT2_READ_EOF 3
|
||||||
|
|
||||||
|
int ext2_read_blocks(vfs_mount_t *mount, uint32_t block, uint32_t num, void *target) {
|
||||||
|
uint32_t lba = (block * MI(mount)->block_size) / BLOCK_DEV_LBA_SIZE;
|
||||||
|
uint32_t num_lba = DIV_ROUND_UP(num * MI(mount)->block_size, BLOCK_DEV_LBA_SIZE);
|
||||||
|
void *buffer = malloc(num_lba * BLOCK_DEV_LBA_SIZE);
|
||||||
|
if (buffer == NULL) {
|
||||||
|
return EXT2_READ_ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((block_device_t *) MI(mount)->block_dev)->access(
|
||||||
|
(block_device_t *) MI(mount)->block_dev,
|
||||||
|
BLOCK_DEV_DIRECTION_READ, lba, num_lba, buffer)
|
||||||
|
!= BLOCK_DEV_ACCESS_OK) {
|
||||||
|
free(buffer);
|
||||||
|
return EXT2_READ_IOERR; // todo
|
||||||
|
}
|
||||||
|
memcpy(target, buffer, MI(mount)->block_size);
|
||||||
|
free(buffer);
|
||||||
|
return EXT2_READ_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ext2_bg_descriptor_t *ext2_get_bg_descriptor(vfs_mount_t *mount, uint32_t idx) {
|
||||||
|
uint32_t bg_per_block = MI(mount)->block_size / sizeof(ext2_bg_descriptor_t);
|
||||||
|
uint32_t block = idx / bg_per_block;
|
||||||
|
if (MI(mount)->block_size != 1024) {
|
||||||
|
k_panics("only 1024 supported for now");
|
||||||
|
}
|
||||||
|
block += 2;
|
||||||
|
ext2_bg_descriptor_t *blocks = malloc(MI(mount)->block_size);
|
||||||
|
if (blocks == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (ext2_read_blocks(mount, block, 1, blocks) != EXT2_READ_OK) {
|
||||||
|
free(blocks);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ext2_bg_descriptor_t *res = malloc(sizeof(ext2_bg_descriptor_t));
|
||||||
|
if (res == NULL) {
|
||||||
|
free(blocks);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
uint32_t block_index = idx % bg_per_block;
|
||||||
|
memcpy(res, &blocks[block_index], sizeof(ext2_bg_descriptor_t));
|
||||||
|
free(blocks);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
ext2_bg_descriptor_t *ext2_get_bg_descriptor_for_inode(vfs_mount_t *mount, uint32_t inode) {
|
||||||
|
uint32_t group_idx = (inode - 1) / MI(mount)->sb.no_inodes_per_group;
|
||||||
|
if (group_idx > MI(mount)->no_block_groups) {
|
||||||
|
return NULL; // todo report
|
||||||
|
}
|
||||||
|
ext2_bg_descriptor_t *result = ext2_get_bg_descriptor(mount, group_idx);
|
||||||
|
if (result == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ext2_inode_t *ext2_get_inode(vfs_mount_t *mount, uint32_t inode) {
|
||||||
|
if (inode > MI(mount)->sb.total_inodes) {
|
||||||
|
return NULL; // todo report
|
||||||
|
}
|
||||||
|
ext2_bg_descriptor_t *descriptor = ext2_get_bg_descriptor_for_inode(mount, inode);
|
||||||
|
if (descriptor == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *inodes_in_group = malloc(MI(mount)->block_size);
|
||||||
|
if (inodes_in_group == NULL) {
|
||||||
|
free(descriptor);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t inode_index = (inode - 1) % MI(mount)->sb.no_inodes_per_group;
|
||||||
|
uint32_t block = (inode_index * MI(mount)->sb.size_inode) / MI(mount)->block_size;
|
||||||
|
uint32_t inode_offset = (inode_index * MI(mount)->sb.size_inode) % MI(mount)->block_size;
|
||||||
|
|
||||||
|
// todo check bitmap?
|
||||||
|
if (ext2_read_blocks(mount, descriptor->start_block_inode + block, 1, inodes_in_group) != EXT2_READ_OK) {
|
||||||
|
free(descriptor);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
free(descriptor);
|
||||||
|
|
||||||
|
ext2_inode_t *node = malloc(sizeof(ext2_inode_t));
|
||||||
|
memcpy(node, &inodes_in_group[inode_offset], sizeof(ext2_inode_t));
|
||||||
|
|
||||||
|
free(inodes_in_group);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ext2_get_block_from_inode(vfs_mount_t *mount, vfs_fd_t *fd, void *target, uint32_t block_idx) {
|
||||||
|
if (block_idx < 12) {
|
||||||
|
uint32_t bp = FDI(fd)->inode->dbp[block_idx];
|
||||||
|
if (bp == 0) {
|
||||||
|
return EXT2_READ_EOF;
|
||||||
|
}
|
||||||
|
return ext2_read_blocks(mount, bp, 1, target);
|
||||||
|
} else {
|
||||||
|
k_panics("Not implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EXT2_DGETENT_CONT 1
|
||||||
|
#define EXT2_DGETENT_FULL 2
|
||||||
|
#define EXT2_DGETENT_END 3
|
||||||
|
#define EXT2_DGETENT_ERR 4
|
||||||
|
|
||||||
|
int ext2_dgetent_next(vfs_mount_t *mount, vfs_fd_t *fd, ext2_dgetents_state_t *state, void *target, size_t offset,
|
||||||
|
size_t max_size) {
|
||||||
|
if (state->bp == UINT32_MAX) {
|
||||||
|
// new
|
||||||
|
state->current_data = malloc(MI(mount)->block_size);
|
||||||
|
state->current_data_pos = state->current_data;
|
||||||
|
state->current_data_end = state->current_data + MI(mount)->block_size;
|
||||||
|
state->bp = 0;
|
||||||
|
state->at_end_of_block = false;
|
||||||
|
int result = ext2_get_block_from_inode(mount, fd, state->current_data, state->bp);
|
||||||
|
if (result != EXT2_READ_OK) {
|
||||||
|
return result == EXT2_READ_EOF ? EXT2_DGETENT_END : EXT2_DGETENT_ERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (state->at_end_of_block == true) {
|
||||||
|
state->bp += 1;
|
||||||
|
int result = ext2_get_block_from_inode(mount, fd, state->current_data, state->bp);
|
||||||
|
state->current_data_pos = state->current_data;
|
||||||
|
if (result != EXT2_READ_OK) {
|
||||||
|
return result == EXT2_READ_EOF ? EXT2_DGETENT_END : EXT2_DGETENT_ERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ext2_dir_entry_t *ent = state->current_data_pos;
|
||||||
|
if (VFS_DIRENT_SIZE(ent->name_size) > max_size) {
|
||||||
|
return EXT2_DGETENT_FULL;
|
||||||
|
}
|
||||||
|
vfs_mk_dirent_record(&target[offset], ent->inode, offset, 0, &ent->name, ent->name_size);
|
||||||
|
state->current_data_pos += ent->ent_size;
|
||||||
|
if (state->current_data_pos >= state->current_data_end) {
|
||||||
|
state->at_end_of_block = true;
|
||||||
|
}
|
||||||
|
return EXT2_DGETENT_CONT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ext2_vfs_mount(vfs_mount_t *mount) {
|
||||||
|
ext2_mount_info_t *mount_info = block_dev_mount(mount->device, EXT2_DRIVER_NAME);
|
||||||
|
if (mount_info == NULL) {
|
||||||
|
return VFS_MOUNT_ERROR;
|
||||||
|
}
|
||||||
|
mount->global_driver_data = mount_info;
|
||||||
|
return VFS_MOUNT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ext2_fd_info_t *ext2_get_inode_info(vfs_mount_t *mount, uint32_t inode) {
|
||||||
|
ext2_inode_t *node = ext2_get_inode(mount, inode);
|
||||||
|
if (node == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ext2_fd_info_t *driver_data = malloc(sizeof(ext2_fd_info_t));
|
||||||
|
if (driver_data == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
size_t size = node->size_l;
|
||||||
|
if (MI(mount)->sb.features_optional & EXT2_FEATURE_RO_64BIT_SIZE && node->type == EXT2_INODE_TYPE_FILE) {
|
||||||
|
#if EXT2_FEAT_RO_64BIT_SIZE
|
||||||
|
size += node->size_h << 32;
|
||||||
|
#else
|
||||||
|
if (node->size_h != 0) {
|
||||||
|
printf("WARN: file to large");
|
||||||
|
free(driver_data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
driver_data->inode_nr = inode;
|
||||||
|
driver_data->inode = node;
|
||||||
|
driver_data->size = size;
|
||||||
|
driver_data->seek_position = 0;
|
||||||
|
driver_data->dgetents_state = NULL;
|
||||||
|
driver_data->dgetents_done = false;
|
||||||
|
return driver_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
vfs_dirent_t *ext2_get_dirent_for_filename(vfs_mount_t *mount, vfs_fd_t *dir, const char *path) {
|
||||||
|
size_t name_length = strlen(path);
|
||||||
|
vfs_dirent_t *ent = malloc(VFS_DIRENT_MAX_SIZE);
|
||||||
|
if (ent == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ext2_dgetents_state_t *state = malloc(sizeof(ext2_dgetents_state_t));
|
||||||
|
if (state == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memset(state, 0, sizeof(ext2_dgetents_state_t));
|
||||||
|
state->bp = UINT32_MAX;
|
||||||
|
bool found = false;
|
||||||
|
// todo hash algorithm
|
||||||
|
while (true) {
|
||||||
|
const int result = ext2_dgetent_next(mount, dir, state, ent, 0, VFS_DIRENT_MAX_SIZE);
|
||||||
|
if (result == EXT2_DGETENT_FULL || result == EXT2_DGETENT_ERR) {
|
||||||
|
break; // whut
|
||||||
|
}
|
||||||
|
if (result == EXT2_DGETENT_END) {
|
||||||
|
// not found
|
||||||
|
break; // not found
|
||||||
|
}
|
||||||
|
if (name_length != strlen(ent->name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strncmp(path, ent->name, name_length) != 0) {
|
||||||
|
// not same name
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
free(state);
|
||||||
|
if (!found) {
|
||||||
|
free(ent);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return ent;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ext2_vfs_open(vfs_mount_t *mount, vfs_fd_t *dir, const char *path, int mode, vfs_fd_t *out) {
|
||||||
|
if (dir == NULL && path == NULL) {
|
||||||
|
ext2_fd_info_t *driver_data = ext2_get_inode_info(mount, EXT2_ROOT_INODE);
|
||||||
|
if (driver_data == NULL) {
|
||||||
|
return VFS_OPEN_ERROR;
|
||||||
|
}
|
||||||
|
out->driver_data = driver_data;
|
||||||
|
return VFS_OPEN_OK;
|
||||||
|
}
|
||||||
|
vfs_dirent_t *dirent = ext2_get_dirent_for_filename(mount, dir, path);
|
||||||
|
int open_result = VFS_OPEN_ERROR;
|
||||||
|
if (dirent != NULL) {
|
||||||
|
ext2_fd_info_t *driver_data = ext2_get_inode_info(mount, dirent->inode);
|
||||||
|
if (driver_data != NULL) {
|
||||||
|
out->driver_data = driver_data;
|
||||||
|
open_result = VFS_OPEN_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(dirent);
|
||||||
|
return open_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ext2_vfs_close(vfs_mount_t *mount, vfs_fd_t *fd) {
|
||||||
|
if (FDI(fd)->dgetents_state != NULL) {
|
||||||
|
free(FDI(fd)->dgetents_state);
|
||||||
|
}
|
||||||
|
free(fd);
|
||||||
|
return VFS_CLOSE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ext2_vfs_fstat(vfs_mount_t *mount, vfs_fd_t *fd, stat_t *target, int flags) {
|
||||||
|
target->st_dev = 0; // todo
|
||||||
|
target->st_ino = FDI(fd)->inode_nr;
|
||||||
|
target->st_mode = FDI(fd)->inode->type;
|
||||||
|
target->st_nlink = FDI(fd)->inode->no_hard_links;
|
||||||
|
target->st_uid = FDI(fd)->inode->uid;
|
||||||
|
target->st_gid = FDI(fd)->inode->gid;
|
||||||
|
target->st_size = FDI(fd)->size;
|
||||||
|
target->st_blksize = MI(mount)->block_size;
|
||||||
|
target->st_blocks = FDI(fd)->size / 512; // todo correct?
|
||||||
|
target->st_atim.tv_sec = FDI(fd)->inode->last_access;
|
||||||
|
target->st_mtim.tv_sec = FDI(fd)->inode->last_mod;
|
||||||
|
target->st_ctim.tv_sec = FDI(fd)->inode->created;
|
||||||
|
|
||||||
|
if (FDI(fd)->inode->type == EXT2_INODE_TYPE_BLOCK_DEV || FDI(fd)->inode->type == EXT2_INODE_TYPE_CHAR_DEV) {
|
||||||
|
target->st_rdev = FDI(fd)->inode->dbp[0];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ext2_vfs_fread(vfs_mount_t *mount, vfs_fd_t *fd, void *target, size_t size) {
|
||||||
|
size_t target_pos = 0;
|
||||||
|
|
||||||
|
void *buffer = malloc(MI(mount)->block_size);
|
||||||
|
if (buffer == NULL) {
|
||||||
|
return VFS_READ_ERROR;
|
||||||
|
}
|
||||||
|
while (true) {
|
||||||
|
uint32_t block = FDI(fd)->seek_position / MI(mount)->block_size;
|
||||||
|
uint32_t bytes_read_in_block = FDI(fd)->seek_position % MI(mount)->block_size;
|
||||||
|
uint32_t bytes_left_in_block = MI(mount)->block_size - bytes_read_in_block;
|
||||||
|
size_t toread = MIN(MIN(bytes_left_in_block, size - target_pos), FDI(fd)->size - target_pos);
|
||||||
|
|
||||||
|
if (ext2_get_block_from_inode(mount, fd, buffer, block) != EXT2_READ_OK) {
|
||||||
|
free(buffer);
|
||||||
|
return VFS_READ_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&target[target_pos], &buffer[block], toread);
|
||||||
|
target_pos += toread;
|
||||||
|
FDI(fd)->seek_position += toread;
|
||||||
|
if (target_pos == size || FDI(fd)->seek_position >= FDI(fd)->size) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(buffer);
|
||||||
|
return target_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ext2_vfs_dgetent(vfs_mount_t *mount, vfs_fd_t *fd, void *target, size_t size) {
|
||||||
|
if (FDI(fd)->dgetents_done == true) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
size_t offset = 0;
|
||||||
|
size_t prev_offset = 0;
|
||||||
|
if (FDI(fd)->dgetents_state == NULL) {
|
||||||
|
FDI(fd)->dgetents_state = malloc(sizeof(ext2_dgetents_state_t));
|
||||||
|
FDI(fd)->dgetents_state->bp = UINT32_MAX;
|
||||||
|
FDI(fd)->dgetents_state->cur = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
int result = ext2_dgetent_next(mount, fd, FDI(fd)->dgetents_state, target, offset, size - offset);
|
||||||
|
if (result != EXT2_DGETENT_CONT) {
|
||||||
|
if (result == EXT2_DGETENT_END) {
|
||||||
|
if (FDI(fd)->dgetents_state->current_data != NULL) {
|
||||||
|
free(FDI(fd)->dgetents_state->current_data);
|
||||||
|
FDI(fd)->dgetents_state->current_data = NULL;
|
||||||
|
}
|
||||||
|
free(FDI(fd)->dgetents_state);
|
||||||
|
FDI(fd)->dgetents_state = NULL;
|
||||||
|
FDI(fd)->dgetents_done = true;
|
||||||
|
}
|
||||||
|
if (result == EXT2_DGETENT_FULL || result == EXT2_DGETENT_END) {
|
||||||
|
((vfs_dirent_t *) &target[prev_offset])->offset_next = size;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
size_t reclen = ((vfs_dirent_t *) &target[offset])->reclen;
|
||||||
|
prev_offset = offset;
|
||||||
|
offset += reclen;
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ext2_get_no_bg(ext2_sb_t *sb) {
|
||||||
|
uint32_t no_bg_by_blocks = DIV_ROUND_UP(sb->total_blocks, sb->no_blocks_per_group);
|
||||||
|
uint32_t no_bg_by_inodes = DIV_ROUND_UP(sb->total_inodes, sb->no_inodes_per_group);
|
||||||
|
if (no_bg_by_blocks != no_bg_by_inodes) {
|
||||||
|
k_panics("No no match");
|
||||||
|
}
|
||||||
|
return no_bg_by_inodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ext2_check_device(block_device_t *device) {
|
||||||
|
ext2_sb_t *sb = malloc(EXT2_SB_SIZE);
|
||||||
|
if (device->access(device,
|
||||||
|
BLOCK_DEV_DIRECTION_READ,
|
||||||
|
EXT2_SB_ADDR / BLOCK_DEV_LBA_SIZE,
|
||||||
|
EXT2_SB_SIZE / BLOCK_DEV_LBA_SIZE,
|
||||||
|
sb) != BLOCK_DEV_ACCESS_OK) {
|
||||||
|
free(sb);
|
||||||
|
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
|
||||||
|
}
|
||||||
|
if (sb->ext2_signature != EXT2_SIGNATURE) {
|
||||||
|
printf("Missing signature\n");
|
||||||
|
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
|
||||||
|
}
|
||||||
|
printf("Ext2 features:\n\tRequired: %lx\n\tOptional: %lx\n\tRo: %lx\n", sb->features_required,
|
||||||
|
sb->features_optional, sb->features_ro);
|
||||||
|
if (sb->features_required ^ EXT2_FEAT_REQ_SUPPORTED) {
|
||||||
|
printf("Filesystem uses features not supported by implementation, %lx\n", sb->features_required);
|
||||||
|
free(sb);
|
||||||
|
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
|
||||||
|
}
|
||||||
|
printf("ext2 valid\n");
|
||||||
|
ext2_mount_info_t *mount_info = malloc(sizeof(ext2_mount_info_t));
|
||||||
|
memcpy(&mount_info->sb, sb, sizeof(ext2_sb_t));
|
||||||
|
mount_info->no_block_groups = ext2_get_no_bg(sb);
|
||||||
|
mount_info->block_size = 1024 << sb->block_size;
|
||||||
|
mount_info->fragment_size = 1024 << sb->fragment_size;
|
||||||
|
mount_info->block_dev = device;
|
||||||
|
device->driver_info = mount_info;
|
||||||
|
free(sb);
|
||||||
|
return BLOCK_DEV_DRIVER_CHECK_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
BLOCK_DEV_DRIVER(300) = {
|
||||||
|
.name = EXT2_DRIVER_NAME,
|
||||||
|
.check_device = ext2_check_device,
|
||||||
|
.free_device = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
VFS_DRIVER(300) = {
|
||||||
|
.name = EXT2_DRIVER_NAME,
|
||||||
|
.vfs_mount = ext2_vfs_mount,
|
||||||
|
.open = ext2_vfs_open,
|
||||||
|
.close = ext2_vfs_close,
|
||||||
|
.fstat = ext2_vfs_fstat,
|
||||||
|
.fread = ext2_vfs_fread,
|
||||||
|
.dgetent = ext2_vfs_dgetent,
|
||||||
|
};
|
||||||
@@ -107,9 +107,26 @@ void print_chars(char *chars, int amount) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t att_used fat_check_device(const block_device_t *device, uint8_t *first_sector) {
|
uint8_t att_used fat_check_device(const block_device_t *device) {
|
||||||
|
uint8_t *first_sector = malloc(512);
|
||||||
|
if (first_sector == NULL) {
|
||||||
|
printf("No mem\n");
|
||||||
|
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
|
||||||
|
}
|
||||||
|
uint8_t result = device->access(device, BLOCK_DEV_DIRECTION_READ, 0, 1, first_sector);
|
||||||
|
if (result != BLOCK_DEV_ACCESS_OK) {
|
||||||
|
printf("Could not access device\n");
|
||||||
|
free(first_sector);
|
||||||
|
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
|
||||||
|
}
|
||||||
|
if (first_sector[510] != 0x55 || first_sector[511] != 0xAA) {
|
||||||
|
printf("No boot signature\n");
|
||||||
|
free(first_sector);
|
||||||
|
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
|
||||||
|
}
|
||||||
fat_bpb bpb;
|
fat_bpb bpb;
|
||||||
memcpy((uint8_t *) &bpb, first_sector, sizeof(fat_bpb));
|
memcpy((uint8_t *) &bpb, first_sector, sizeof(fat_bpb));
|
||||||
|
free(first_sector);
|
||||||
if (bpb.bpb.sectors_per_fat == 0 || bpb.bpb.sectors_per_cluster == 0) {
|
if (bpb.bpb.sectors_per_fat == 0 || bpb.bpb.sectors_per_cluster == 0) {
|
||||||
printf("Definitely not FAT\n");
|
printf("Definitely not FAT\n");
|
||||||
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
|
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
|
||||||
|
|||||||
@@ -75,15 +75,20 @@ ustar_sector *ustar_next(ustar_sector *current) {
|
|||||||
return ustar_sector_valid(next) ? next : NULL;
|
return ustar_sector_valid(next) ? next : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t ustar_check_device(const block_device_t *device, uint8_t *first_sector) {
|
uint8_t ustar_check_device(const block_device_t *device) {
|
||||||
ustar_sector *sector = (ustar_sector *) first_sector;
|
ustar_sector *sector = malloc(512); // todo fix leak
|
||||||
|
if (device->access(device, BLOCK_DEV_DIRECTION_READ, 0, 1, sector) != BLOCK_DEV_ACCESS_OK) {
|
||||||
|
free(sector);
|
||||||
|
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
|
||||||
|
}
|
||||||
if (!ustar_sector_valid(sector)) {
|
if (!ustar_sector_valid(sector)) {
|
||||||
|
free(sector);
|
||||||
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
|
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
ustar_fs *fs = malloc(sizeof(ustar_fs));
|
ustar_fs *fs = malloc(sizeof(ustar_fs));
|
||||||
fs->first_inode = malloc(sizeof(ustar_inode));
|
fs->first_inode = malloc(sizeof(ustar_inode));
|
||||||
memcpy(&fs->first_inode->sector, first_sector, sizeof(ustar_sector));
|
memcpy(&fs->first_inode->sector, sector, sizeof(ustar_sector));
|
||||||
fs->first_inode->lba = 0;
|
fs->first_inode->lba = 0;
|
||||||
fs->device = device;
|
fs->device = device;
|
||||||
|
|
||||||
|
|||||||
@@ -33,12 +33,11 @@ typedef struct {
|
|||||||
} att_packed mbr_table;
|
} att_packed mbr_table;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const block_device_t *device;
|
block_device_t *device;
|
||||||
uint32_t start_lba;
|
uint32_t start_lba;
|
||||||
} mbr_block_driver_info;
|
} mbr_block_driver_info;
|
||||||
|
|
||||||
uint8_t
|
uint8_t mbr_block_dev_access(block_device_t *device, uint8_t direction, uint32_t lba, uint8_t sectors, void *target) {
|
||||||
mbr_block_dev_access(const block_device_t *device, uint8_t direction, uint32_t lba, uint8_t sectors, void *target) {
|
|
||||||
if (!device->flags.present || lba > device->num_lba) {
|
if (!device->flags.present || lba > device->num_lba) {
|
||||||
return BLOCK_DEV_ACCESS_ERR;
|
return BLOCK_DEV_ACCESS_ERR;
|
||||||
}
|
}
|
||||||
@@ -52,9 +51,15 @@ mbr_block_dev_access(const block_device_t *device, uint8_t direction, uint32_t l
|
|||||||
return info->device->access(info->device, direction, actual_lba, sectors, target);
|
return info->device->access(info->device, direction, actual_lba, sectors, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t att_used mbr_check_device(const block_device_t *device, uint8_t *first_sector) {
|
uint8_t mbr_check_device(block_device_t *device) {
|
||||||
|
uint8_t *first_sector = malloc(512);
|
||||||
|
if (device->access(device, BLOCK_DEV_DIRECTION_READ, 0, 1, first_sector) != BLOCK_DEV_ACCESS_OK) {
|
||||||
|
free(first_sector);
|
||||||
|
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
|
||||||
|
}
|
||||||
mbr_table table;
|
mbr_table table;
|
||||||
memcpy((uint8_t *) &table, first_sector + (device->block_size - sizeof(mbr_table)), sizeof(mbr_table));
|
memcpy((uint8_t *) &table, first_sector + (device->block_size - sizeof(mbr_table)), sizeof(mbr_table));
|
||||||
|
free(first_sector);
|
||||||
if (table.signature[0] != 0x55 && table.signature[1] != 0xAA) { // AA 55 but in little endian
|
if (table.signature[0] != 0x55 && table.signature[1] != 0xAA) { // AA 55 but in little endian
|
||||||
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
|
return BLOCK_DEV_DRIVER_CHECK_NO_MATCH;
|
||||||
}
|
}
|
||||||
|
|||||||
186
kernel/vfs/vfs.c
Normal file
186
kernel/vfs/vfs.c
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
//
|
||||||
|
// Created by rick on 12-08-21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <myke/tasks/locking.h>
|
||||||
|
#include <myke/vfs/vfs.h>
|
||||||
|
#include <myke/vfs/vfs-driver.h>
|
||||||
|
#include <myke/util/init.h>
|
||||||
|
#include <myke/libk/libk.h>
|
||||||
|
|
||||||
|
vfs_mount_t *first_mount = NULL;
|
||||||
|
mutex_t *mount_lock = NULL;
|
||||||
|
|
||||||
|
extern vfs_driver_t __start_vfs_driver[];
|
||||||
|
extern vfs_driver_t __stop_vfs_driver[];
|
||||||
|
#define NUM_DRIVERS ((size_t)(__stop_vfs_driver - __start_vfs_driver))
|
||||||
|
#define DRIVER(i) ((__start_vfs_driver) + (i))
|
||||||
|
|
||||||
|
vfs_driver_t *vfs_get_driver_by_name(const char *name) {
|
||||||
|
for (size_t i = 0; i < NUM_DRIVERS; ++i) {
|
||||||
|
if (strcmp(DRIVER(i)->name, name) == 0) {
|
||||||
|
return DRIVER(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vfs_register_mount(vfs_mount_t *mount) {
|
||||||
|
mutex_acquire(mount_lock);
|
||||||
|
if (first_mount == NULL) {
|
||||||
|
first_mount = mount;
|
||||||
|
} else {
|
||||||
|
vfs_mount_t *last_mount = first_mount;
|
||||||
|
while (last_mount->next != NULL) last_mount = last_mount->next;
|
||||||
|
last_mount->next = mount;
|
||||||
|
}
|
||||||
|
mutex_release(mount_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
vfs_mount_t *vfs_get_mount_for_path(const char *path) {
|
||||||
|
if (first_mount == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
mutex_acquire(mount_lock);
|
||||||
|
size_t max_length = strlen(path);
|
||||||
|
vfs_mount_t *longest_match = NULL;
|
||||||
|
size_t match_length = 0;
|
||||||
|
vfs_mount_t *last_mount = NULL;
|
||||||
|
do {
|
||||||
|
if (last_mount == NULL) {
|
||||||
|
last_mount = first_mount;
|
||||||
|
} else if ((last_mount = last_mount->next) == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
size_t mount_length = strlen(last_mount->prefix);
|
||||||
|
if (mount_length > max_length || mount_length < match_length) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strncmp(last_mount->prefix, path, strlen(last_mount->prefix)) == 0) {
|
||||||
|
longest_match = last_mount;
|
||||||
|
match_length = mount_length;
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
mutex_release(mount_lock);
|
||||||
|
return longest_match;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vfs_mount(const char *path, const char *device, const char *driver) {
|
||||||
|
vfs_driver_t *driver_impl = vfs_get_driver_by_name(driver);
|
||||||
|
if (driver_impl == NULL) {
|
||||||
|
return VFS_MOUNT_ERROR;
|
||||||
|
}
|
||||||
|
vfs_mount_t *mount = malloc(sizeof(vfs_mount_t));
|
||||||
|
mount->driver = driver_impl;
|
||||||
|
mount->device = device;
|
||||||
|
mount->prefix = path;
|
||||||
|
int result = driver_impl->vfs_mount(mount);
|
||||||
|
if (result != VFS_MOUNT_OK) {
|
||||||
|
free(mount);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
vfs_register_mount(mount);
|
||||||
|
return VFS_MOUNT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
vfs_fd_t *vfs_open_intermediate(vfs_mount_t *mount, const char *path, int flags, int mode) {
|
||||||
|
vfs_fd_t *intermediate_dir = malloc(sizeof(vfs_fd_t));
|
||||||
|
vfs_fd_t *out = malloc(sizeof(vfs_fd_t));
|
||||||
|
out->mount = mount;
|
||||||
|
intermediate_dir->mount = mount;
|
||||||
|
char *full_path = strdup(path);
|
||||||
|
char *current_path = full_path;
|
||||||
|
while (strlen(current_path) > 0) {
|
||||||
|
if (current_path[0] == '/') {
|
||||||
|
// root
|
||||||
|
if (((vfs_driver_t *) mount->driver)->open(mount, NULL, NULL, flags, out) != VFS_OPEN_OK) {
|
||||||
|
free(out);
|
||||||
|
free(intermediate_dir);
|
||||||
|
free(full_path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
current_path = ¤t_path[1];
|
||||||
|
} else {
|
||||||
|
char *next_dir = strchr(current_path, '/');
|
||||||
|
if (next_dir != NULL) {
|
||||||
|
next_dir[0] = 0;
|
||||||
|
}
|
||||||
|
if (((vfs_driver_t *) mount->driver)->open(mount, intermediate_dir, current_path, flags, out) !=
|
||||||
|
VFS_OPEN_OK) {
|
||||||
|
((vfs_driver_t *) mount->driver)->close(mount, intermediate_dir);
|
||||||
|
free(out);
|
||||||
|
free(intermediate_dir);
|
||||||
|
free(full_path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (next_dir == NULL) {
|
||||||
|
current_path = ¤t_path[strlen(current_path)];
|
||||||
|
} else {
|
||||||
|
current_path = &next_dir[1];
|
||||||
|
}
|
||||||
|
if (((vfs_driver_t *) mount->driver)->close(mount, intermediate_dir) != VFS_CLOSE_OK) {
|
||||||
|
free(out);
|
||||||
|
free(intermediate_dir);
|
||||||
|
free(full_path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memcpy(intermediate_dir, out, sizeof(vfs_fd_t));
|
||||||
|
}
|
||||||
|
free(full_path);
|
||||||
|
free(intermediate_dir);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://man7.org/linux/man-pages/man2/open.2.html
|
||||||
|
vfs_fd_t *vfs_open(const char *path, int flags, int mode) {
|
||||||
|
vfs_mount_t *mount = vfs_get_mount_for_path(path);
|
||||||
|
if (mount == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return vfs_open_intermediate(mount, &path[strlen(mount->prefix) - 1], flags, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vfs_close(vfs_fd_t *fd) {
|
||||||
|
((vfs_driver_t *) (fd->mount->driver))->close(fd->mount, fd);
|
||||||
|
free(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://man7.org/linux/man-pages/man2/stat.2.html
|
||||||
|
int vfs_fstat(vfs_fd_t *dirfd, stat_t *target, int flags) {
|
||||||
|
return ((vfs_driver_t *) (dirfd->mount->driver))->fstat(dirfd->mount, dirfd, target, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://man7.org/linux/man-pages/man2/read.2.html
|
||||||
|
int vfs_read(vfs_fd_t *fd, void *target, size_t size) {
|
||||||
|
return ((vfs_driver_t *) (fd->mount->driver))->fread(fd->mount, fd, target, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// inspiration https://man7.org/linux/man-pages/man2/getdents.2.html
|
||||||
|
int vfs_getdents(vfs_fd_t *fd, void *target, int count) {
|
||||||
|
return ((vfs_driver_t *) fd->mount->driver)->dgetent(fd->mount, fd, target, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vfs_mk_dirent_record(vfs_dirent_t *ent, uint32_t inode, uint32_t cur_offset, uint8_t type, char *name,
|
||||||
|
size_t name_length) {
|
||||||
|
ent->inode = inode;
|
||||||
|
strncpy(ent->name, name, name_length);
|
||||||
|
ent->name[name_length] = 0;
|
||||||
|
ent->type = type;
|
||||||
|
ent->reclen = VFS_DIRENT_SIZE(name_length);
|
||||||
|
ent->offset_next = cur_offset + ent->reclen;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vfs_init() {
|
||||||
|
mount_lock = mutex_create();
|
||||||
|
}
|
||||||
|
|
||||||
|
INIT_FUNCTION(100) = {
|
||||||
|
.name = "vfs-task",
|
||||||
|
.stage = INIT_STAGE_PRE_TASKING,
|
||||||
|
.init = vfs_init,
|
||||||
|
};
|
||||||
16
linker.ld
16
linker.ld
@@ -30,18 +30,26 @@ SECTIONS
|
|||||||
.data BLOCK(4K) : ALIGN(4K)
|
.data BLOCK(4K) : ALIGN(4K)
|
||||||
{
|
{
|
||||||
*(.data)
|
*(.data)
|
||||||
. = ALIGN(16);
|
|
||||||
__start_init = .;
|
|
||||||
*(SORT(.init.*))
|
|
||||||
__stop_init = .;
|
|
||||||
. = ALIGN(16);
|
. = ALIGN(16);
|
||||||
__start_pci_driver = .;
|
__start_pci_driver = .;
|
||||||
*(SORT(.pci_driver.*))
|
*(SORT(.pci_driver.*))
|
||||||
__stop_pci_driver = .;
|
__stop_pci_driver = .;
|
||||||
|
|
||||||
. = ALIGN(16);
|
. = ALIGN(16);
|
||||||
__start_block_dev_driver = .;
|
__start_block_dev_driver = .;
|
||||||
*(SORT(.block_dev_driver.*))
|
*(SORT(.block_dev_driver.*))
|
||||||
__stop_block_dev_driver = .;
|
__stop_block_dev_driver = .;
|
||||||
|
|
||||||
|
. = ALIGN(16);
|
||||||
|
__start_vfs_driver = .;
|
||||||
|
*(SORT(.vfs_driver.*))
|
||||||
|
__stop_vfs_driver = .;
|
||||||
|
|
||||||
|
. = ALIGN(16);
|
||||||
|
__start_init = .;
|
||||||
|
*(SORT(.init.*))
|
||||||
|
__stop_init = .;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read-write data (uninitialized) and stack */
|
/* Read-write data (uninitialized) and stack */
|
||||||
|
|||||||
3
rootfs/.gitignore
vendored
Normal file
3
rootfs/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
mnt/*
|
||||||
|
!mnt
|
||||||
|
rootfs.img
|
||||||
52
rootfs/mkrootfs.sh
Executable file
52
rootfs/mkrootfs.sh
Executable file
@@ -0,0 +1,52 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
IMG_FILE=rootfs.img
|
||||||
|
IMG_SIZE=100 # MB
|
||||||
|
|
||||||
|
function log() {
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
function yes_or_no() {
|
||||||
|
while true; do
|
||||||
|
read -p "$* [y/n]: " yn
|
||||||
|
case $yn in
|
||||||
|
[Yy]*) return 0 ;;
|
||||||
|
[Nn]*)
|
||||||
|
echo "Aborted"
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup_lb() {
|
||||||
|
sudo losetup -fP --show ${IMG_FILE}
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ ! -d mnt ]; then
|
||||||
|
mkdir mnt
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "${IMG_FILE}" ]; then
|
||||||
|
log "${IMG_FILE} already exists"
|
||||||
|
if ! yes_or_no "Continue?"; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# build img
|
||||||
|
dd if=/dev/zero of=${IMG_FILE} bs=1M count=${IMG_SIZE}
|
||||||
|
|
||||||
|
parted -s ${IMG_FILE} mktable msdos
|
||||||
|
parted -s ${IMG_FILE} mkpart primary ext2 0 100%
|
||||||
|
|
||||||
|
LB_DEV="$(setup_lb)"
|
||||||
|
|
||||||
|
if [ -z "${LB_DEV}" ]; then
|
||||||
|
log "Failed to setup loobback"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo mkfs.ext2 -L rootfs "${LB_DEV}p1"
|
||||||
|
sudo mount "${LB_DEV}p1" mnt
|
||||||
39
rootfs/mount_rootfs.sh
Executable file
39
rootfs/mount_rootfs.sh
Executable file
@@ -0,0 +1,39 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
IMG_FILE=rootfs.img
|
||||||
|
IMG_SIZE=100 # MB
|
||||||
|
|
||||||
|
function log() {
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
function yes_or_no() {
|
||||||
|
while true; do
|
||||||
|
read -p "$* [y/n]: " yn
|
||||||
|
case $yn in
|
||||||
|
[Yy]*) return 0 ;;
|
||||||
|
[Nn]*)
|
||||||
|
echo "Aborted"
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup_lb() {
|
||||||
|
sudo losetup -fP --show ${IMG_FILE}
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ ! -f "${IMG_FILE}" ]; then
|
||||||
|
log "${IMG_FILE} doesn't exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
LB_DEV="$(setup_lb)"
|
||||||
|
|
||||||
|
if [ -z "${LB_DEV}" ]; then
|
||||||
|
log "Failed to setup loobback"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo mount "${LB_DEV}p1" mnt
|
||||||
15
rootfs/umount_rootfsh.sh
Executable file
15
rootfs/umount_rootfsh.sh
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
function log() {
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
LB_DEV=$(findmnt -n -o SOURCE mnt)
|
||||||
|
|
||||||
|
if [ -z "${LB_DEV}" ]; then
|
||||||
|
log "Not mounted"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo umount mnt
|
||||||
|
sudo losetup -d "${LB_DEV%p1}"
|
||||||
Reference in New Issue
Block a user