#include #include #include #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; static struct inode *books_inode = NULL; static struct vfsmount *libfs_mnt; 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; } 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); } struct cleanup_ctx { struct inode *victim; }; static void libfs_cleanup_links(struct inode *victim) { struct dentry *root = libfs_sb->s_root; struct qstr authors_q = QSTR_INIT("authors", 7); struct dentry *authors = d_lookup(root, &authors_q); if (!authors || d_really_is_negative(authors)) { dput(authors); return; } // Здесь конкретный пример: если ты сам знаешь имя линка на victim // То можешь через d_lookup() найти его и удалить struct qstr filename = QSTR_INIT("some_symlink", 12); struct dentry *maybe_link = d_lookup(authors, &filename); if (maybe_link && maybe_link->d_inode == victim) { inode_lock(authors->d_inode); vfs_unlink(NULL, authors->d_inode, maybe_link, NULL); inode_unlock(authors->d_inode); } dput(maybe_link); dput(authors); } static int libfs_unlink(struct inode *dir, struct dentry *dentry) { if (dir == libfs_sb->s_root->d_inode && is_protected_dentry(dentry)) return -EPERM; struct inode *victim = dentry->d_inode; int ret = simple_unlink(dir, dentry); if (ret == 0 && dir == books_inode) { libfs_cleanup_links(victim); } return ret; } 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; } 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_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) { int ret = register_filesystem(&libfs_type); if (ret) return ret; libfs_mnt = kern_mount(&libfs_type); return PTR_ERR_OR_ZERO(libfs_mnt); } static void __exit libfs_exit(void) { kern_unmount(libfs_mnt); 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");