opt
/
kaspersky
/
kav4fs
/
src
/
kernel
/
redirfs
➕ New
📤 Upload
✎ Editing:
rfs_inode.c
← Back
/* * RedirFS: Redirecting File System * Written by Frantisek Hrbata <frantisek.hrbata@redirfs.org> * * Copyright 2008 - 2010 Frantisek Hrbata * All rights reserved. * * This file is part of RedirFS. * * RedirFS is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * RedirFS is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with RedirFS. If not, see <http://www.gnu.org/licenses/>. */ #include "rfs.h" static rfs_kmem_cache_t* rfs_inode_cache = NULL; static int rfs_getattr(struct vfsmount* mnt, struct dentry* dentry, struct kstat* stat); DEFINE_RWLOCK(rfs_inode_rwlock); static struct rfs_inode* rfs_inode_alloc(struct inode* inode) { struct rfs_inode* rinode; rinode = kmem_cache_zalloc(rfs_inode_cache, GFP_KERNEL); if (IS_ERR(rinode)) return ERR_PTR(-ENOMEM); INIT_LIST_HEAD(&rinode->rdentries); INIT_LIST_HEAD(&rinode->data); rinode->inode = inode; rinode->op_old = inode->i_op; rinode->fop_old = inode->i_fop; spin_lock_init(&rinode->lock); rfs_mutex_init(&rinode->mutex); atomic_set(&rinode->count, 1); atomic_set(&rinode->nlink, 1); rinode->rdentries_nr = 0; #if defined(S_IOPS_WRAPPER) rinode->i_flags = inode->i_flags; #endif if (inode->i_op) { #if defined(S_IOPS_WRAPPER) if (IS_IOPS_WRAPPER(inode)) { memcpy(&rinode->op_new, inode->i_op, sizeof(struct inode_operations_wrapper)); } else { memcpy(&rinode->op_new, inode->i_op, sizeof(struct inode_operations)); } rinode->op_new.rename = rfs_rename; #else memcpy(&rinode->op_new, inode->i_op, sizeof(struct inode_operations)); #if defined(IOP_HAS_RENAME2) if (inode->i_op->rename2) rinode->op_new.rename2 = rfs_rename2; else rinode->op_new.rename = rfs_rename; #else rinode->op_new.rename = rfs_rename; #endif #endif } return rinode; } struct rfs_inode* rfs_inode_find(struct inode* inode) { struct rfs_inode* rinode; read_lock(&rfs_inode_rwlock); #if defined(IOP_HAS_RENAME2) && !defined(S_IOPS_WRAPPER) rinode = (inode && inode->i_op && (inode->i_op->rename == rfs_rename || inode->i_op->rename2 == rfs_rename2) ? #else rinode = (inode && inode->i_op && inode->i_op->rename == rfs_rename ? #endif rfs_inode_get(container_of(inode->i_op, struct rfs_inode, op_new)) : NULL); read_unlock(&rfs_inode_rwlock); return rinode; } struct rfs_inode* rfs_inode_get(struct rfs_inode* rinode) { if (!rinode || IS_ERR(rinode)) return NULL; BUG_ON(!atomic_read(&rinode->count)); atomic_inc(&rinode->count); return rinode; } void rfs_inode_put(struct rfs_inode* rinode) { if (!rinode || IS_ERR(rinode)) return; write_lock(&rfs_inode_rwlock); BUG_ON(!atomic_read(&rinode->count)); if (!atomic_dec_and_test(&rinode->count)) { write_unlock(&rfs_inode_rwlock); return; } write_unlock(&rfs_inode_rwlock); rfs_info_put(rinode->rinfo); rfs_data_remove(&rinode->data); kmem_cache_free(rfs_inode_cache, rinode); } struct rfs_inode* rfs_inode_add(struct inode* inode, struct rfs_info* rinfo) { struct rfs_inode* ri_new; struct rfs_inode* ri; if (!inode) return NULL; ri_new = rfs_inode_alloc(inode); if (IS_ERR(ri_new)) return ri_new; spin_lock(&inode->i_lock); ri = rfs_inode_find(inode); if (!ri) { ri_new->rinfo = rfs_info_get(rinfo); if (!rfs_skip_file(inode->i_mode)) inode->i_fop = &rfs_file_ops; inode->i_op = &ri_new->op_new; rfs_inode_get(ri_new); ri = rfs_inode_get(ri_new); } else atomic_inc(&ri->nlink); spin_unlock(&inode->i_lock); rfs_inode_put(ri_new); return ri; } void rfs_inode_del(struct rfs_inode* rinode) { if (!atomic_dec_and_test(&rinode->nlink)) return; if (!rfs_skip_file(rinode->inode->i_mode)) rinode->inode->i_fop = rinode->fop_old; rinode->inode->i_op = rinode->op_old; rfs_inode_put(rinode); } void rfs_inode_add_rdentry(struct rfs_inode* rinode, struct rfs_dentry* rdentry) { rfs_mutex_lock(&rinode->mutex); rinode->rdentries_nr++; list_add_tail(&rdentry->rinode_list, &rinode->rdentries); rfs_mutex_unlock(&rinode->mutex); rfs_dentry_get(rdentry); } void rfs_inode_rem_rdentry(struct rfs_inode* rinode, struct rfs_dentry* rdentry) { rfs_mutex_lock(&rinode->mutex); if (list_empty(&rdentry->rinode_list)) { rfs_mutex_unlock(&rinode->mutex); return; } rinode->rdentries_nr--; list_del_init(&rdentry->rinode_list); rfs_mutex_unlock(&rinode->mutex); rfs_dentry_put(rdentry); } static struct rfs_chain* rfs_inode_join_rchains(struct rfs_inode* rinode) { struct rfs_dentry* rdentry = NULL; struct rfs_info* rinfo = NULL; struct rfs_chain* rchain = NULL; struct rfs_chain* rchain_old = NULL; list_for_each_entry(rdentry, &rinode->rdentries, rinode_list) { spin_lock(&rdentry->lock); rinfo = rfs_info_get(rdentry->rinfo); spin_unlock(&rdentry->lock); rchain = rfs_chain_join(rinfo->rchain, rchain_old); rfs_info_put(rinfo); rfs_chain_put(rchain_old); if (IS_ERR(rchain)) return rchain; rchain_old = rchain; } return rchain; } static int rfs_inode_set_rinfo_fast(struct rfs_inode* rinode) { struct rfs_dentry* rdentry; if (!rinode->rdentries_nr) return 0; if (rinode->rdentries_nr > 1) return -1; rdentry = list_entry(rinode->rdentries.next, struct rfs_dentry, rinode_list); spin_lock(&rdentry->lock); spin_lock(&rinode->lock); rfs_info_put(rinode->rinfo); rinode->rinfo = rfs_info_get(rdentry->rinfo); spin_unlock(&rinode->lock); spin_unlock(&rdentry->lock); return 0; } struct rfs_info* rfs_inode_get_rinfo(struct rfs_inode* rinode) { struct rfs_info* rinfo; if (!rinode) return NULL; spin_lock(&rinode->lock); rinfo = rfs_info_get(rinode->rinfo); spin_unlock(&rinode->lock); return rinfo; } int rfs_inode_set_rinfo(struct rfs_inode* rinode) { struct rfs_chain* rchain; struct rfs_info* rinfo; struct rfs_ops* rops; int rv; if (!rinode) return 0; rfs_mutex_lock(&rinode->mutex); rv = rfs_inode_set_rinfo_fast(rinode); rfs_mutex_unlock(&rinode->mutex); if (!rv) return 0; rinfo = rfs_info_alloc(NULL, NULL); if (IS_ERR(rinfo)) return PTR_ERR(rinfo); rops = rfs_ops_alloc(); if (IS_ERR(rops)) { rfs_info_put(rinfo); return PTR_ERR(rops); } rinfo->rops = rops; rfs_mutex_lock(&rinode->mutex); rv = rfs_inode_set_rinfo_fast(rinode); if (!rv) { rfs_mutex_unlock(&rinode->mutex); rfs_info_put(rinfo); return 0; } rchain = rfs_inode_join_rchains(rinode); if (IS_ERR(rchain)) { rfs_mutex_unlock(&rinode->mutex); rfs_info_put(rinfo); return PTR_ERR(rchain); } rinfo->rchain = rchain; if (!rinfo->rchain) { rfs_info_put(rinfo); rinfo = rfs_info_get(rfs_info_none); } rfs_chain_ops(rinfo->rchain, rinfo->rops); spin_lock(&rinode->lock); rfs_info_put(rinode->rinfo); rinode->rinfo = rinfo; spin_unlock(&rinode->lock); rfs_mutex_unlock(&rinode->mutex); return 0; } int rfs_inode_cache_create(void) { rfs_inode_cache = rfs_kmem_cache_create("rfs_inode_cache", sizeof(struct rfs_inode)); if (!rfs_inode_cache) return -ENOMEM; return 0; } void rfs_inode_cache_destroy(void) { kmem_cache_destroy(rfs_inode_cache); } #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0) static struct dentry* rfs_lookup(struct inode* dir, struct dentry* dentry, struct nameidata* nd) { struct rfs_inode* rinode; struct rfs_info* rinfo; struct rfs_context rcont; struct redirfs_args rargs; struct dentry* dadd = dentry; unsigned int mask = nd ? (nd->flags & LOOKUP_OPEN) : 0; if (!dir) return NULL; if (S_ISDIR(dir->i_mode)) rargs.type.id = REDIRFS_DIR_IOP_LOOKUP; else return ERR_PTR(-ENOTDIR); rinode = rfs_inode_find(dir); if (!rinode) return NULL; rinfo = rfs_inode_get_rinfo(rinode); rfs_context_init(&rcont, 0); rargs.args.i_lookup.dir = dir; rargs.args.i_lookup.dentry = dentry; rargs.args.i_lookup.nd = nd; if (nd) rargs.args.i_lookup.nd->flags &= ~mask; if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) { if (rinode->op_old && rinode->op_old->lookup) rargs.rv.rv_dentry = rinode->op_old->lookup(rargs.args.i_lookup.dir, rargs.args.i_lookup.dentry, rargs.args.i_lookup.nd); else rargs.rv.rv_dentry = ERR_PTR(-ENOSYS); } if (nd) rargs.args.i_lookup.nd->flags |= mask; rfs_postcall_flts(rinfo->rchain, &rcont, &rargs); rfs_context_deinit(&rcont); if (IS_ERR(rargs.rv.rv_dentry)) goto exit; if (rargs.rv.rv_dentry) dadd = rargs.rv.rv_dentry; if (rfs_dcache_rdentry_add(dadd, rinfo)) BUG(); exit: rfs_inode_put(rinode); rfs_info_put(rinfo); return rargs.rv.rv_dentry; } #else static struct dentry* rfs_lookup(struct inode* dir, struct dentry* dentry, unsigned int flags) { struct rfs_inode* rinode; struct rfs_info* rinfo; struct rfs_context rcont; struct redirfs_args rargs; struct dentry* dadd = dentry; if (S_ISDIR(dir->i_mode)) rargs.type.id = REDIRFS_DIR_IOP_LOOKUP; else return ERR_PTR(-ENOTDIR); rinode = rfs_inode_find(dir); rinfo = rfs_inode_get_rinfo(rinode); rfs_context_init(&rcont, 0); rargs.args.i_lookup.dir = dir; rargs.args.i_lookup.dentry = dentry; rargs.args.i_lookup.flags = flags; if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) { if (rinode->op_old && rinode->op_old->lookup) rargs.rv.rv_dentry = rinode->op_old->lookup(rargs.args.i_lookup.dir, rargs.args.i_lookup.dentry, rargs.args.i_lookup.flags); else rargs.rv.rv_dentry = ERR_PTR(-ENOSYS); } rfs_postcall_flts(rinfo->rchain, &rcont, &rargs); rfs_context_deinit(&rcont); if (IS_ERR(rargs.rv.rv_dentry)) goto exit; if (rargs.rv.rv_dentry) dadd = rargs.rv.rv_dentry; if (rfs_dcache_rdentry_add(dadd, rinfo)) BUG(); exit: rfs_inode_put(rinode); rfs_info_put(rinfo); return rargs.rv.rv_dentry; } #endif static int rfs_mkdir(struct inode* dir, struct dentry* dentry, rfs_umode_t mode) { struct rfs_inode* rinode; struct rfs_info* rinfo; struct rfs_context rcont; struct redirfs_args rargs; rinode = rfs_inode_find(dir); rinfo = rfs_inode_get_rinfo(rinode); rfs_context_init(&rcont, 0); if (S_ISDIR(dir->i_mode)) rargs.type.id = REDIRFS_DIR_IOP_MKDIR; else BUG(); rargs.args.i_mkdir.dir = dir; rargs.args.i_mkdir.dentry = dentry; rargs.args.i_mkdir.mode = mode; if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) { if (rinode->op_old && rinode->op_old->mkdir) rargs.rv.rv_int = rinode->op_old->mkdir(rargs.args.i_mkdir.dir, rargs.args.i_mkdir.dentry, rargs.args.i_mkdir.mode); else rargs.rv.rv_int = -ENOSYS; } rfs_postcall_flts(rinfo->rchain, &rcont, &rargs); rfs_context_deinit(&rcont); if (!rargs.rv.rv_int) { if (rfs_dcache_rdentry_add(dentry, rinfo)) BUG(); } rfs_inode_put(rinode); rfs_info_put(rinfo); return rargs.rv.rv_int; } #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0) static int rfs_create(struct inode* dir, struct dentry* dentry, rfs_umode_t mode, struct nameidata* nd) { struct rfs_inode* rinode; struct rfs_info* rinfo; struct rfs_context rcont; struct redirfs_args rargs; rinode = rfs_inode_find(dir); rinfo = rfs_inode_get_rinfo(rinode); rfs_context_init(&rcont, 0); if (S_ISDIR(dir->i_mode)) rargs.type.id = REDIRFS_DIR_IOP_CREATE; else BUG(); rargs.args.i_create.dir = dir; rargs.args.i_create.dentry = dentry; rargs.args.i_create.mode = mode; rargs.args.i_create.nd = nd; if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) { if (rinode->op_old && rinode->op_old->create) rargs.rv.rv_int = rinode->op_old->create( rargs.args.i_create.dir, rargs.args.i_create.dentry, rargs.args.i_create.mode, rargs.args.i_create.nd); else rargs.rv.rv_int = -ENOSYS; } rfs_postcall_flts(rinfo->rchain, &rcont, &rargs); rfs_context_deinit(&rcont); if (!rargs.rv.rv_int) { if (rfs_dcache_rdentry_add(dentry, rinfo)) BUG(); /* Some fs like fuse fill file structure on i_op->create * and therefore willn't call f_op->open later. Here we assign * file ops to newly created in that way files. * * We skip this step if previous operation doesn't set default * rfs file ops to inode->i_fop. */ if (nd && (nd->flags & (LOOKUP_OPEN | LOOKUP_CREATE)) && (nd->intent.open.flags != O_EXCL) && !IS_ERR_OR_NULL(nd->intent.open.file) && !IS_ERR_OR_NULL(nd->intent.open.file->f_dentry) && (dentry->d_inode->i_fop == &rfs_file_ops)) { struct rfs_file* rfile = rfs_file_add(nd->intent.open.file); if (IS_ERR(rfile)) BUG(); rfs_file_put(rfile); } } rfs_inode_put(rinode); rfs_info_put(rinfo); return rargs.rv.rv_int; } #else static int rfs_create(struct inode* dir, struct dentry* dentry, rfs_umode_t mode, bool excl) { struct rfs_inode* rinode; struct rfs_info* rinfo; struct rfs_context rcont; struct redirfs_args rargs; rinode = rfs_inode_find(dir); rinfo = rfs_inode_get_rinfo(rinode); rfs_context_init(&rcont, 0); if (S_ISDIR(dir->i_mode)) rargs.type.id = REDIRFS_DIR_IOP_CREATE; else BUG(); rargs.args.i_create.dir = dir; rargs.args.i_create.dentry = dentry; rargs.args.i_create.mode = mode; rargs.args.i_create.excl = excl; if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) { if (rinode->op_old && rinode->op_old->create) rargs.rv.rv_int = rinode->op_old->create( rargs.args.i_create.dir, rargs.args.i_create.dentry, rargs.args.i_create.mode, rargs.args.i_create.excl); else rargs.rv.rv_int = -ENOSYS; } rfs_postcall_flts(rinfo->rchain, &rcont, &rargs); rfs_context_deinit(&rcont); if (!rargs.rv.rv_int) { if (rfs_dcache_rdentry_add(dentry, rinfo)) BUG(); } rfs_inode_put(rinode); rfs_info_put(rinfo); return rargs.rv.rv_int; } #endif #if 0 /* template for atomic_open operation introduced at kernel 3.6.0 */ static int rfs_atomic_open(struct inode *dir, struct dentry *dentry, struct file *file, unsigned int flags, rfs_umode_t mode, int *opened) { struct rfs_inode *rinode; struct rfs_info *rinfo; struct rfs_context rcont; struct redirfs_args rargs; struct dentry *dadd = dentry; rinode = rfs_inode_find(dir); rinfo = rfs_inode_get_rinfo(rinode); rfs_context_init(&rcont, 0); if (S_ISDIR(dir->i_mode)) rargs.type.id = REDIRFS_DIR_IOP_ATOMIC_OPEN; else BUG(); rargs.args.i_atomic_open.dir = dir; rargs.args.i_atomic_open.dentry = dentry; rargs.args.i_atomic_open.file = file; rargs.args.i_atomic_open.flags = flags; rargs.args.i_atomic_open.mode = mode; rargs.args.i_atomic_open.opened = opened; if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) { if (rinode->op_old && rinode->op_old->atomic_open) rargs.rv.rv_int = rinode->op_old->atomic_open( rargs.args.i_atomic_open.dir, rargs.args.i_atomic_open.dentry, rargs.args.i_atomic_open.file, rargs.args.i_atomic_open.flags, rargs.args.i_atomic_open.mode, rargs.args.i_atomic_open.opened); else BUG(); } rfs_postcall_flts(rinfo->rchain, &rcont, &rargs); rfs_context_deinit(&rcont); if (rargs.rv.rv_int >= 0) { if (!IS_ERR_OR_NULL(file->f_dentry)) dadd = file->f_dentry; if (rfs_dcache_rdentry_add(dadd, rinfo)) BUG(); BUG(); } rfs_inode_put(rinode); rfs_info_put(rinfo); return rargs.rv.rv_int; } #endif static int rfs_link(struct dentry* old_dentry, struct inode* dir, struct dentry* dentry) { struct rfs_inode* rinode; struct rfs_info* rinfo; struct rfs_context rcont; struct redirfs_args rargs; rinode = rfs_inode_find(dir); rinfo = rfs_inode_get_rinfo(rinode); rfs_context_init(&rcont, 0); if (S_ISDIR(dir->i_mode)) rargs.type.id = REDIRFS_DIR_IOP_LINK; else BUG(); rargs.args.i_link.old_dentry = old_dentry; rargs.args.i_link.dir = dir; rargs.args.i_link.dentry = dentry; if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) { if (rinode->op_old && rinode->op_old->link) rargs.rv.rv_int = rinode->op_old->link(rargs.args.i_link.old_dentry, rargs.args.i_link.dir, rargs.args.i_link.dentry); else rargs.rv.rv_int = -ENOSYS; } rfs_postcall_flts(rinfo->rchain, &rcont, &rargs); rfs_context_deinit(&rcont); if (!rargs.rv.rv_int) { if (rfs_dcache_rdentry_add(dentry, rinfo)) BUG(); } rfs_inode_put(rinode); rfs_info_put(rinfo); return rargs.rv.rv_int; } static int rfs_symlink(struct inode* dir, struct dentry* dentry, const char* oldname) { struct rfs_inode* rinode; struct rfs_info* rinfo; struct rfs_context rcont; struct redirfs_args rargs; rinode = rfs_inode_find(dir); rinfo = rfs_inode_get_rinfo(rinode); rfs_context_init(&rcont, 0); if (S_ISDIR(dir->i_mode)) rargs.type.id = REDIRFS_DIR_IOP_SYMLINK; else BUG(); rargs.args.i_symlink.dir = dir; rargs.args.i_symlink.dentry = dentry; rargs.args.i_symlink.oldname = oldname; if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) { if (rinode->op_old && rinode->op_old->symlink) rargs.rv.rv_int = rinode->op_old->symlink(rargs.args.i_symlink.dir, rargs.args.i_symlink.dentry, rargs.args.i_symlink.oldname); else rargs.rv.rv_int = -ENOSYS; } rfs_postcall_flts(rinfo->rchain, &rcont, &rargs); rfs_context_deinit(&rcont); if (!rargs.rv.rv_int) { if (rfs_dcache_rdentry_add(dentry, rinfo)) BUG(); } rfs_inode_put(rinode); rfs_info_put(rinfo); return rargs.rv.rv_int; } static int rfs_mknod(struct inode* dir, struct dentry* dentry, rfs_umode_t mode, dev_t rdev) { struct rfs_inode* rinode; struct rfs_info* rinfo; struct rfs_context rcont; struct redirfs_args rargs; rinode = rfs_inode_find(dir); rinfo = rfs_inode_get_rinfo(rinode); rfs_context_init(&rcont, 0); if (S_ISDIR(dir->i_mode)) rargs.type.id = REDIRFS_DIR_IOP_MKNOD; else BUG(); rargs.args.i_mknod.dir = dir; rargs.args.i_mknod.dentry = dentry; rargs.args.i_mknod.mode = mode; rargs.args.i_mknod.rdev = rdev; if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) { if (rinode->op_old && rinode->op_old->mknod) rargs.rv.rv_int = rinode->op_old->mknod( rargs.args.i_mknod.dir, rargs.args.i_mknod.dentry, rargs.args.i_mknod.mode, rargs.args.i_mknod.rdev); else rargs.rv.rv_int = -ENOSYS; } rfs_postcall_flts(rinfo->rchain, &rcont, &rargs); rfs_context_deinit(&rcont); if (!rargs.rv.rv_int) { if (rfs_dcache_rdentry_add(dentry, rinfo)) BUG(); } rfs_inode_put(rinode); rfs_info_put(rinfo); return rargs.rv.rv_int; } static int rfs_unlink(struct inode* inode, struct dentry* dentry) { struct rfs_inode* rinode; struct rfs_info* rinfo; struct rfs_context rcont; struct redirfs_args rargs; rinode = rfs_inode_find(inode); rinfo = rfs_inode_get_rinfo(rinode); rfs_context_init(&rcont, 0); if (S_ISDIR(inode->i_mode)) rargs.type.id = REDIRFS_DIR_IOP_UNLINK; else BUG(); rargs.args.i_unlink.dir = inode; rargs.args.i_unlink.dentry = dentry; if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) { if (rinode->op_old && rinode->op_old->unlink) rargs.rv.rv_int = rinode->op_old->unlink(rargs.args.i_unlink.dir, rargs.args.i_unlink.dentry); else rargs.rv.rv_int = -ENOSYS; } rfs_postcall_flts(rinfo->rchain, &rcont, &rargs); rfs_context_deinit(&rcont); rfs_inode_put(rinode); rfs_info_put(rinfo); return rargs.rv.rv_int; } static int rfs_rmdir(struct inode* inode, struct dentry* dentry) { struct rfs_inode* rinode; struct rfs_info* rinfo; struct rfs_context rcont; struct redirfs_args rargs; rinode = rfs_inode_find(inode); rinfo = rfs_inode_get_rinfo(rinode); rfs_context_init(&rcont, 0); if (S_ISDIR(inode->i_mode)) rargs.type.id = REDIRFS_DIR_IOP_RMDIR; else BUG(); rargs.args.i_unlink.dir = inode; rargs.args.i_unlink.dentry = dentry; if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) { if (rinode->op_old && rinode->op_old->rmdir) rargs.rv.rv_int = rinode->op_old->rmdir(rargs.args.i_unlink.dir, rargs.args.i_unlink.dentry); else rargs.rv.rv_int = -ENOSYS; } rfs_postcall_flts(rinfo->rchain, &rcont, &rargs); rfs_context_deinit(&rcont); rfs_inode_put(rinode); rfs_info_put(rinfo); return rargs.rv.rv_int; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) static int rfs_permission(struct inode* inode, int mask, struct nameidata* nd) { struct rfs_inode* rinode; struct rfs_info* rinfo; struct rfs_context rcont; struct redirfs_args rargs; int submask; submask = mask & ~MAY_APPEND; rinode = rfs_inode_find(inode); rinfo = rfs_inode_get_rinfo(rinode); rfs_context_init(&rcont, 0); if (S_ISREG(inode->i_mode)) rargs.type.id = REDIRFS_REG_IOP_PERMISSION; else if (S_ISDIR(inode->i_mode)) rargs.type.id = REDIRFS_DIR_IOP_PERMISSION; else if (S_ISLNK(inode->i_mode)) rargs.type.id = REDIRFS_LNK_IOP_PERMISSION; else if (S_ISCHR(inode->i_mode)) rargs.type.id = REDIRFS_CHR_IOP_PERMISSION; else if (S_ISBLK(inode->i_mode)) rargs.type.id = REDIRFS_BLK_IOP_PERMISSION; else if (S_ISFIFO(inode->i_mode)) rargs.type.id = REDIRFS_FIFO_IOP_PERMISSION; else rargs.type.id = REDIRFS_SOCK_IOP_PERMISSION; rargs.args.i_permission.inode = inode; rargs.args.i_permission.mask = mask; rargs.args.i_permission.nd = nd; if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) { if (rinode->op_old && rinode->op_old->permission) rargs.rv.rv_int = rinode->op_old->permission( rargs.args.i_permission.inode, rargs.args.i_permission.mask, rargs.args.i_permission.nd); else rargs.rv.rv_int = generic_permission(inode, submask, NULL); } rfs_postcall_flts(rinfo->rchain, &rcont, &rargs); rfs_context_deinit(&rcont); rfs_inode_put(rinode); rfs_info_put(rinfo); return rargs.rv.rv_int; } #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) static int rfs_permission(struct inode* inode, int mask) { struct rfs_inode* rinode; struct rfs_info* rinfo; struct rfs_context rcont; struct redirfs_args rargs; int submask; submask = mask & ~MAY_APPEND; rinode = rfs_inode_find(inode); rinfo = rfs_inode_get_rinfo(rinode); rfs_context_init(&rcont, 0); if (S_ISREG(inode->i_mode)) rargs.type.id = REDIRFS_REG_IOP_PERMISSION; else if (S_ISDIR(inode->i_mode)) rargs.type.id = REDIRFS_DIR_IOP_PERMISSION; else if (S_ISLNK(inode->i_mode)) rargs.type.id = REDIRFS_LNK_IOP_PERMISSION; else if (S_ISCHR(inode->i_mode)) rargs.type.id = REDIRFS_CHR_IOP_PERMISSION; else if (S_ISBLK(inode->i_mode)) rargs.type.id = REDIRFS_BLK_IOP_PERMISSION; else if (S_ISFIFO(inode->i_mode)) rargs.type.id = REDIRFS_FIFO_IOP_PERMISSION; else rargs.type.id = REDIRFS_SOCK_IOP_PERMISSION; rargs.args.i_permission.inode = inode; rargs.args.i_permission.mask = mask; if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) { if (rinode->op_old && rinode->op_old->permission) rargs.rv.rv_int = rinode->op_old->permission( rargs.args.i_permission.inode, rargs.args.i_permission.mask); else rargs.rv.rv_int = generic_permission(inode, submask, NULL); } rfs_postcall_flts(rinfo->rchain, &rcont, &rargs); rfs_context_deinit(&rcont); rfs_inode_put(rinode); rfs_info_put(rinfo); return rargs.rv.rv_int; } #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38) static int rfs_permission(struct inode* inode, int mask) { struct rfs_inode* rinode; struct rfs_info* rinfo; struct rfs_context rcont; struct redirfs_args rargs; int submask; submask = mask & ~MAY_APPEND; rinode = rfs_inode_find(inode); rinfo = rfs_inode_get_rinfo(rinode); rfs_context_init(&rcont, 0); if (S_ISREG(inode->i_mode)) rargs.type.id = REDIRFS_REG_IOP_PERMISSION; else if (S_ISDIR(inode->i_mode)) rargs.type.id = REDIRFS_DIR_IOP_PERMISSION; else if (S_ISLNK(inode->i_mode)) rargs.type.id = REDIRFS_LNK_IOP_PERMISSION; else if (S_ISCHR(inode->i_mode)) rargs.type.id = REDIRFS_CHR_IOP_PERMISSION; else if (S_ISBLK(inode->i_mode)) rargs.type.id = REDIRFS_BLK_IOP_PERMISSION; else if (S_ISFIFO(inode->i_mode)) rargs.type.id = REDIRFS_FIFO_IOP_PERMISSION; else rargs.type.id = REDIRFS_SOCK_IOP_PERMISSION; rargs.args.i_permission.inode = inode; rargs.args.i_permission.mask = mask; if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) { if (rinode->op_old && rinode->op_old->permission) rargs.rv.rv_int = rinode->op_old->permission( rargs.args.i_permission.inode, rargs.args.i_permission.mask); else rargs.rv.rv_int = generic_permission(inode, submask, inode->i_op->check_acl); } rfs_postcall_flts(rinfo->rchain, &rcont, &rargs); rfs_context_deinit(&rcont); rfs_inode_put(rinode); rfs_info_put(rinfo); return rargs.rv.rv_int; } #elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) static int rfs_permission(struct inode* inode, int mask, unsigned int flags) { struct rfs_inode* rinode; struct rfs_info* rinfo; struct rfs_context rcont; struct redirfs_args rargs; int submask; if (flags & IPERM_FLAG_RCU) return -ECHILD; submask = mask & ~MAY_APPEND; rinode = rfs_inode_find(inode); rinfo = rfs_inode_get_rinfo(rinode); rfs_context_init(&rcont, 0); if (S_ISREG(inode->i_mode)) rargs.type.id = REDIRFS_REG_IOP_PERMISSION; else if (S_ISDIR(inode->i_mode)) rargs.type.id = REDIRFS_DIR_IOP_PERMISSION; else if (S_ISLNK(inode->i_mode)) rargs.type.id = REDIRFS_LNK_IOP_PERMISSION; else if (S_ISCHR(inode->i_mode)) rargs.type.id = REDIRFS_CHR_IOP_PERMISSION; else if (S_ISBLK(inode->i_mode)) rargs.type.id = REDIRFS_BLK_IOP_PERMISSION; else if (S_ISFIFO(inode->i_mode)) rargs.type.id = REDIRFS_FIFO_IOP_PERMISSION; else rargs.type.id = REDIRFS_SOCK_IOP_PERMISSION; rargs.args.i_permission.inode = inode; rargs.args.i_permission.mask = mask; rargs.args.i_permission.flags = flags; if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) { if (rinode->op_old && rinode->op_old->permission) rargs.rv.rv_int = rinode->op_old->permission( rargs.args.i_permission.inode, rargs.args.i_permission.mask, rargs.args.i_permission.flags); else rargs.rv.rv_int = generic_permission(inode, submask, flags, inode->i_op->check_acl); } rfs_postcall_flts(rinfo->rchain, &rcont, &rargs); rfs_context_deinit(&rcont); rfs_inode_put(rinode); rfs_info_put(rinfo); return rargs.rv.rv_int; } #else static int rfs_permission(struct inode* inode, int mask) { struct rfs_inode* rinode; struct rfs_info* rinfo; struct rfs_context rcont; struct redirfs_args rargs; int submask; if (mask & MAY_NOT_BLOCK) return -ECHILD; submask = mask & ~MAY_APPEND; rinode = rfs_inode_find(inode); rinfo = rfs_inode_get_rinfo(rinode); rfs_context_init(&rcont, 0); if (S_ISREG(inode->i_mode)) rargs.type.id = REDIRFS_REG_IOP_PERMISSION; else if (S_ISDIR(inode->i_mode)) rargs.type.id = REDIRFS_DIR_IOP_PERMISSION; else if (S_ISLNK(inode->i_mode)) rargs.type.id = REDIRFS_LNK_IOP_PERMISSION; else if (S_ISCHR(inode->i_mode)) rargs.type.id = REDIRFS_CHR_IOP_PERMISSION; else if (S_ISBLK(inode->i_mode)) rargs.type.id = REDIRFS_BLK_IOP_PERMISSION; else if (S_ISFIFO(inode->i_mode)) rargs.type.id = REDIRFS_FIFO_IOP_PERMISSION; else rargs.type.id = REDIRFS_SOCK_IOP_PERMISSION; rargs.args.i_permission.inode = inode; rargs.args.i_permission.mask = mask; if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) { if (rinode->op_old && rinode->op_old->permission) rargs.rv.rv_int = rinode->op_old->permission( rargs.args.i_permission.inode, rargs.args.i_permission.mask); else rargs.rv.rv_int = generic_permission(inode, submask); } rfs_postcall_flts(rinfo->rchain, &rcont, &rargs); rfs_context_deinit(&rcont); rfs_inode_put(rinode); rfs_info_put(rinfo); return rargs.rv.rv_int; } #endif static int rfs_setattr_default(struct dentry* dentry, struct iattr* iattr) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) struct inode* inode = dentry->d_inode; int rv; rv = inode_change_ok(inode, iattr); if (rv) return rv; #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34) if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) || (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) return rfs_dq_transfer(inode, iattr) ? -EDQUOT : 0; #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) return inode_setattr(inode, iattr); #else return simple_setattr(dentry, iattr); #endif } static int rfs_setattr(struct dentry* dentry, struct iattr* iattr) { struct rfs_inode* rinode; struct rfs_info* rinfo; struct rfs_context rcont; struct redirfs_args rargs; rinode = rfs_inode_find(dentry->d_inode); rinfo = rfs_inode_get_rinfo(rinode); rfs_context_init(&rcont, 0); if (S_ISREG(dentry->d_inode->i_mode)) rargs.type.id = REDIRFS_REG_IOP_SETATTR; else if (S_ISDIR(dentry->d_inode->i_mode)) rargs.type.id = REDIRFS_DIR_IOP_SETATTR; else if (S_ISLNK(dentry->d_inode->i_mode)) rargs.type.id = REDIRFS_LNK_IOP_SETATTR; else if (S_ISCHR(dentry->d_inode->i_mode)) rargs.type.id = REDIRFS_CHR_IOP_SETATTR; else if (S_ISBLK(dentry->d_inode->i_mode)) rargs.type.id = REDIRFS_BLK_IOP_SETATTR; else if (S_ISFIFO(dentry->d_inode->i_mode)) rargs.type.id = REDIRFS_FIFO_IOP_SETATTR; else rargs.type.id = REDIRFS_SOCK_IOP_SETATTR; rargs.args.i_setattr.dentry = dentry; rargs.args.i_setattr.iattr = iattr; if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) { if (rinode->op_old && rinode->op_old->setattr) rargs.rv.rv_int = rinode->op_old->setattr(rargs.args.i_setattr.dentry, rargs.args.i_setattr.iattr); else rargs.rv.rv_int = rfs_setattr_default(dentry, iattr); } rfs_postcall_flts(rinfo->rchain, &rcont, &rargs); rfs_context_deinit(&rcont); rfs_inode_put(rinode); rfs_info_put(rinfo); return rargs.rv.rv_int; } static int rfs_getattr(struct vfsmount* mnt, struct dentry* dentry, struct kstat* stat) { struct rfs_inode* rinode; struct rfs_info* rinfo; struct rfs_context rcont; struct redirfs_args rargs; rinode = rfs_inode_find(dentry->d_inode); rinfo = rfs_inode_get_rinfo(rinode); rfs_context_init(&rcont, 0); if (S_ISREG(dentry->d_inode->i_mode)) rargs.type.id = REDIRFS_REG_IOP_GETATTR; else if (S_ISDIR(dentry->d_inode->i_mode)) rargs.type.id = REDIRFS_DIR_IOP_GETATTR; else if (S_ISLNK(dentry->d_inode->i_mode)) rargs.type.id = REDIRFS_LNK_IOP_GETATTR; else if (S_ISCHR(dentry->d_inode->i_mode)) rargs.type.id = REDIRFS_CHR_IOP_GETATTR; else if (S_ISBLK(dentry->d_inode->i_mode)) rargs.type.id = REDIRFS_BLK_IOP_GETATTR; else if (S_ISFIFO(dentry->d_inode->i_mode)) rargs.type.id = REDIRFS_FIFO_IOP_GETATTR; else rargs.type.id = REDIRFS_SOCK_IOP_GETATTR; rargs.args.i_getattr.mnt = mnt; rargs.args.i_getattr.dentry = dentry; rargs.args.i_getattr.stat = stat; if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) { if (rinode->op_old && rinode->op_old->getattr) rargs.rv.rv_int = rinode->op_old->getattr(rargs.args.i_getattr.mnt, rargs.args.i_getattr.dentry, rargs.args.i_getattr.stat); else generic_fillattr(dentry->d_inode, stat), rargs.rv.rv_int = 0; } rfs_postcall_flts(rinfo->rchain, &rcont, &rargs); rfs_context_deinit(&rcont); rfs_inode_put(rinode); rfs_info_put(rinfo); return rargs.rv.rv_int; } int rfs_rename(struct inode* old_dir, struct dentry* old_dentry, struct inode* new_dir, struct dentry* new_dentry #if (LINUX_VERSION_CODE > KERNEL_VERSION(4,9,0)) , unsigned int flags #endif ) { struct rfs_inode* rinode; struct rfs_info* rinfo; struct rfs_context rcont; struct redirfs_args rargs; rinode = rfs_inode_find(old_dir); rinfo = rfs_inode_get_rinfo(rinode); rfs_context_init(&rcont, 0); if (S_ISDIR(old_dir->i_mode)) rargs.type.id = REDIRFS_DIR_IOP_RENAME; else BUG(); rargs.args.i_rename.old_dir = old_dir; rargs.args.i_rename.old_dentry = old_dentry; rargs.args.i_rename.new_dir = new_dir; rargs.args.i_rename.new_dentry = new_dentry; if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) { if (rinode->op_old && rinode->op_old->rename) rargs.rv.rv_int = rinode->op_old->rename( rargs.args.i_rename.old_dir, rargs.args.i_rename.old_dentry, rargs.args.i_rename.new_dir, rargs.args.i_rename.new_dentry #if (LINUX_VERSION_CODE > KERNEL_VERSION(4,9,0)) , flags #endif ); else rargs.rv.rv_int = -ENOSYS; } if (!rargs.rv.rv_int) rargs.rv.rv_int = rfs_fsrename( rargs.args.i_rename.old_dir, rargs.args.i_rename.old_dentry, rargs.args.i_rename.new_dir, rargs.args.i_rename.new_dentry); rfs_postcall_flts(rinfo->rchain, &rcont, &rargs); rfs_context_deinit(&rcont); rfs_inode_put(rinode); rfs_info_put(rinfo); return rargs.rv.rv_int; } #if defined(IOP_HAS_RENAME2) || defined(IOPW_HAS_RENAME2) int rfs_rename2(struct inode* old_dir, struct dentry* old_dentry, struct inode* new_dir, struct dentry* new_dentry, unsigned int flags) { struct rfs_inode* rinode; struct rfs_info* rinfo; struct rfs_context rcont; struct redirfs_args rargs; rinode = rfs_inode_find(old_dir); rinfo = rfs_inode_get_rinfo(rinode); rfs_context_init(&rcont, 0); if (S_ISDIR(old_dir->i_mode)) rargs.type.id = REDIRFS_DIR_IOP_RENAME; else BUG(); rargs.args.i_rename.old_dir = old_dir; rargs.args.i_rename.old_dentry = old_dentry; rargs.args.i_rename.new_dir = new_dir; rargs.args.i_rename.new_dentry = new_dentry; if (!rfs_precall_flts(rinfo->rchain, &rcont, &rargs)) { if (IS_RINODE_RENAME2_SET(rinode)) rargs.rv.rv_int = RENAME2_CALL( rinode, rargs.args.i_rename.old_dir, rargs.args.i_rename.old_dentry, rargs.args.i_rename.new_dir, rargs.args.i_rename.new_dentry, flags); else rargs.rv.rv_int = -ENOSYS; } if (!rargs.rv.rv_int) rargs.rv.rv_int = rfs_fsrename( rargs.args.i_rename.old_dir, rargs.args.i_rename.old_dentry, rargs.args.i_rename.new_dir, rargs.args.i_rename.new_dentry); rfs_postcall_flts(rinfo->rchain, &rcont, &rargs); rfs_context_deinit(&rcont); rfs_inode_put(rinode); rfs_info_put(rinfo); return rargs.rv.rv_int; } #endif static void rfs_inode_set_ops_reg(struct rfs_inode* rinode) { RFS_SET_IOP(rinode, REDIRFS_REG_IOP_PERMISSION, permission); RFS_SET_IOP(rinode, REDIRFS_REG_IOP_SETATTR, setattr); RFS_SET_IOP(rinode, REDIRFS_REG_IOP_GETATTR, getattr); } static void rfs_inode_set_ops_dir(struct rfs_inode* rinode) { RFS_SET_IOP(rinode, REDIRFS_DIR_IOP_UNLINK, unlink); RFS_SET_IOP(rinode, REDIRFS_DIR_IOP_RMDIR, rmdir); RFS_SET_IOP(rinode, REDIRFS_DIR_IOP_PERMISSION, permission); RFS_SET_IOP(rinode, REDIRFS_DIR_IOP_SETATTR, setattr); RFS_SET_IOP(rinode, REDIRFS_DIR_IOP_GETATTR, getattr); RFS_SET_IOP_MGT(rinode, create); RFS_SET_IOP_MGT(rinode, link); RFS_SET_IOP_MGT(rinode, mknod); RFS_SET_IOP_MGT(rinode, symlink); rinode->op_new.lookup = rfs_lookup; rinode->op_new.mkdir = rfs_mkdir; #if !(LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) rinode->op_new.atomic_open = NULL; #endif } static void rfs_inode_set_ops_lnk(struct rfs_inode* rinode) { RFS_SET_IOP(rinode, REDIRFS_LNK_IOP_PERMISSION, permission); RFS_SET_IOP(rinode, REDIRFS_LNK_IOP_SETATTR, setattr); RFS_SET_IOP(rinode, REDIRFS_LNK_IOP_GETATTR, getattr); } static void rfs_inode_set_ops_chr(struct rfs_inode* rinode) { RFS_SET_IOP(rinode, REDIRFS_CHR_IOP_PERMISSION, permission); RFS_SET_IOP(rinode, REDIRFS_CHR_IOP_SETATTR, setattr); RFS_SET_IOP(rinode, REDIRFS_CHR_IOP_GETATTR, getattr); } static void rfs_inode_set_ops_blk(struct rfs_inode* rinode) { RFS_SET_IOP(rinode, REDIRFS_BLK_IOP_PERMISSION, permission); RFS_SET_IOP(rinode, REDIRFS_BLK_IOP_SETATTR, setattr); RFS_SET_IOP(rinode, REDIRFS_BLK_IOP_GETATTR, getattr); } static void rfs_inode_set_ops_fifo(struct rfs_inode* rinode) { RFS_SET_IOP(rinode, REDIRFS_FIFO_IOP_PERMISSION, permission); RFS_SET_IOP(rinode, REDIRFS_FIFO_IOP_SETATTR, setattr); RFS_SET_IOP(rinode, REDIRFS_FIFO_IOP_GETATTR, getattr); } static void rfs_inode_set_ops_sock(struct rfs_inode* rinode) { RFS_SET_IOP(rinode, REDIRFS_SOCK_IOP_PERMISSION, permission); RFS_SET_IOP(rinode, REDIRFS_SOCK_IOP_SETATTR, setattr); RFS_SET_IOP(rinode, REDIRFS_SOCK_IOP_GETATTR, getattr); } static void rfs_inode_set_aops_reg(struct rfs_inode* rinode) { } void rfs_inode_set_ops(struct rfs_inode* rinode) { umode_t mode = rinode->inode->i_mode; spin_lock(&rinode->lock); if (S_ISREG(mode)) { rfs_inode_set_ops_reg(rinode); rfs_inode_set_aops_reg(rinode); } else if (S_ISDIR(mode)) rfs_inode_set_ops_dir(rinode); else if (S_ISLNK(mode)) rfs_inode_set_ops_lnk(rinode); else if (S_ISCHR(mode)) rfs_inode_set_ops_chr(rinode); else if (S_ISBLK(mode)) rfs_inode_set_ops_blk(rinode); else if (S_ISFIFO(mode)) rfs_inode_set_ops_fifo(rinode); else if (S_ISSOCK(mode)) rfs_inode_set_ops_sock(rinode); spin_unlock(&rinode->lock); }
💾 Save Changes
Cancel
📤 Upload File
×
Select File
Upload
Cancel
➕ Create New
×
Type
📄 File
📁 Folder
Name
Create
Cancel
✎ Rename Item
×
Current Name
New Name
Rename
Cancel
🔐 Change Permissions
×
Target File
Permission (e.g., 0755, 0644)
0755
0644
0777
Apply
Cancel