commit f5cabb007fbf1b62531c2b0ccf76bfed37f9aaa4 Author: g2px1 Date: Sun Jun 15 09:28:16 2025 +0000 Initial diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9f65fff --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +*.cmd +*.ko +*.mod +*.mod.c +*.mod.o +*.o +CMakeLists.txt +Module.symvers +modules.order +.idea +cmake-build-debug +build \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..999f44f --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +obj-m := statsfs.o + +KDIR := /lib/modules/$(shell uname -r)/build +PWD := $(shell pwd) + +all: + $(MAKE) -C $(KDIR) M=$(PWD) modules + +clean: + $(MAKE) -C $(KDIR) M=$(PWD) clean \ No newline at end of file diff --git a/statsfs.c b/statsfs.c new file mode 100644 index 0000000..b6d7083 --- /dev/null +++ b/statsfs.c @@ -0,0 +1,160 @@ +// libfs.c +#include +#include +#include +#include +#include +#include +#include +#include + +#define LIBFS_MAGIC 0xA0B0C0D0 +#define LIBFS_BOOKS_MODE 01777 +#define LIBFS_AUTHORS_MODE 0777 +#define LIBFS_SUBDIR_MODE 01777 + +static struct super_block *libfs_sb; + +// Track books inode to monitor link targets +static struct inode *books_inode = NULL; + +static const struct super_operations libfs_sops = { + .statfs = simple_statfs, + .drop_inode = generic_delete_inode, +}; + +static const struct file_operations libfs_file_ops = { + .llseek = no_llseek, + .read = NULL, + .write = NULL, +}; + +static struct inode *libfs_get_inode(struct super_block *sb, umode_t mode) { + struct inode *inode = new_inode(sb); + if (!inode) return NULL; + + inode->i_ino = get_next_ino(); + inode->i_sb = sb; + inode->i_op = &simple_dir_inode_operations; + if (S_ISDIR(mode)) { + inode->i_fop = &simple_dir_operations; + } else { + inode->i_fop = &libfs_file_ops; // fallback + } + inode->i_mode = mode; + return inode; +} + +static bool is_protected_dentry(struct dentry *dentry) { + return (strcmp(dentry->d_name.name, "books") == 0 || strcmp(dentry->d_name.name, "authors") == 0); +} + +static int libfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode) { + if (dir == libfs_sb->s_root->d_inode) { + return -EPERM; // no mkdir in root + } + struct inode *inode = libfs_get_inode(dir->i_sb, S_IFDIR | LIBFS_SUBDIR_MODE); + if (!inode) + return -ENOMEM; + inode->i_uid = current_fsuid(); + d_add(dentry, inode); + inc_nlink(dir); + return 0; +} + +static int libfs_unlink(struct inode *dir, struct dentry *dentry) { + if (dir == libfs_sb->s_root->d_inode && is_protected_dentry(dentry)) + return -EPERM; + return simple_unlink(dir, dentry); +} + +static int libfs_rmdir(struct inode *dir, struct dentry *dentry) { + if (dir == libfs_sb->s_root->d_inode && is_protected_dentry(dentry)) + return -EPERM; + return simple_rmdir(dir, dentry); +} + +static int libfs_rename(struct mnt_idmap *idmap, struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, unsigned int flags) { + if ((old_dir == libfs_sb->s_root->d_inode || new_dir == libfs_sb->s_root->d_inode) && + (is_protected_dentry(old_dentry) || is_protected_dentry(new_dentry))) + return -EPERM; + return simple_rename(idmap, old_dir, old_dentry, new_dir, new_dentry, flags); +} + +static int libfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) { + if (dir->i_sb != old_dentry->d_inode->i_sb) + return -EXDEV; + if (!S_ISREG(old_dentry->d_inode->i_mode)) + return -EPERM; + return simple_link(old_dentry, dir, new_dentry); +} + +static const struct inode_operations libfs_dir_iops = { + .lookup = simple_lookup, + .mkdir = libfs_mkdir, + .unlink = libfs_unlink, + .rmdir = libfs_rmdir, + .rename = libfs_rename, + .link = libfs_link, +}; + +static int libfs_fill_super(struct super_block *sb, void *data, int silent) { + struct inode *inode; + struct dentry *root; + libfs_sb = sb; + sb->s_magic = LIBFS_MAGIC; + sb->s_op = &libfs_sops; + + inode = libfs_get_inode(sb, S_IFDIR | 0755); + if (!inode) + return -ENOMEM; + inode->i_op = &libfs_dir_iops; + inode->i_fop = &simple_dir_operations; + + root = d_make_root(inode); + if (!root) + return -ENOMEM; + sb->s_root = root; + + // /books + { + struct inode *books = libfs_get_inode(sb, S_IFDIR | LIBFS_BOOKS_MODE); + books_inode = books; + struct dentry *d = d_alloc_name(root, "books"); + d_add(d, books); + } + // /authors + { + struct inode *authors = libfs_get_inode(sb, S_IFDIR | LIBFS_AUTHORS_MODE); + struct dentry *d = d_alloc_name(root, "authors"); + d_add(d, authors); + } + return 0; +} + +static struct dentry *libfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { + return mount_nodev(fs_type, flags, data, libfs_fill_super); +} + +static struct file_system_type libfs_type = { + .owner = THIS_MODULE, + .name = "libfs", + .mount = libfs_mount, + .kill_sb = kill_litter_super, +}; + +static int __init libfs_init(void) { + return register_filesystem(&libfs_type); +} + +static void __exit libfs_exit(void) { + unregister_filesystem(&libfs_type); +} + +module_init(libfs_init); +module_exit(libfs_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("you"); +MODULE_DESCRIPTION("Custom library FS with books and authors"); \ No newline at end of file