static int sdcardfskk_rmdir(struct inode *dir, struct dentry *dentry) { struct dentry *lower_dentry; struct dentry *lower_dir_dentry; int err; struct path lower_path; struct sdcardfskk_sb_info *sbi = SDCARDFSKK_SB(dentry->d_sb); const struct cred *saved_cred = NULL; //char *path_s = NULL; int has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); if(!check_caller_access_to_name(dir, dentry->d_name.name, sbi->options.derive, 1, has_rw)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " dentry: %s, task:%s\n", __func__, dentry->d_name.name, current->comm); err = -EACCES; goto out_eacces; } /* save current_cred and override it */ OVERRIDE_CRED(SDCARDFSKK_SB(dir->i_sb), saved_cred); /* sdcardfskk_get_real_lower(): in case of remove an user's obb dentry * the dentry on the original path should be deleted. */ sdcardfskk_get_real_lower(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_dir_dentry = lock_parent(lower_dentry); err = mnt_want_write(lower_path.mnt); if (err) goto out_unlock; err = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry); if (err) goto out; d_drop(dentry); /* drop our dentry on success (why not VFS's job?) */ if (dentry->d_inode) clear_nlink(dentry->d_inode); fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode); fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode); dir->i_nlink = lower_dir_dentry->d_inode->i_nlink; out: mnt_drop_write(lower_path.mnt); out_unlock: unlock_dir(lower_dir_dentry); sdcardfskk_put_real_lower(dentry, &lower_path); REVERT_CRED(saved_cred); out_eacces: return err; }
/* * returns: -ERRNO if error (returned to user) * 0: tell VFS to invalidate dentry * 1: dentry is valid */ static int sdcardfskk_d_revalidate(struct dentry *dentry, struct nameidata *nd) { int err = 1; struct path parent_lower_path, lower_path; struct dentry *parent_dentry = NULL; struct dentry *parent_lower_dentry = NULL; struct dentry *lower_cur_parent_dentry = NULL; struct dentry *lower_dentry = NULL; if (nd && nd->flags & LOOKUP_RCU) return -ECHILD; spin_lock(&dentry->d_lock); if (IS_ROOT(dentry)) { spin_unlock(&dentry->d_lock); return 1; } spin_unlock(&dentry->d_lock); /* check uninitialized obb_dentry and * whether the base obbpath has been changed or not */ if (is_obbpath_invalid(dentry)) { d_drop(dentry); return 0; } parent_dentry = dget_parent(dentry); sdcardfskk_get_lower_path(parent_dentry, &parent_lower_path); sdcardfskk_get_real_lower(dentry, &lower_path); parent_lower_dentry = parent_lower_path.dentry; lower_dentry = lower_path.dentry; lower_cur_parent_dentry = dget_parent(lower_dentry); spin_lock(&lower_dentry->d_lock); if (d_unhashed(lower_dentry)) { spin_unlock(&lower_dentry->d_lock); d_drop(dentry); err = 0; goto out; } spin_unlock(&lower_dentry->d_lock); if (parent_lower_dentry != lower_cur_parent_dentry) { d_drop(dentry); err = 0; goto out; } if (dentry < lower_dentry) { spin_lock(&dentry->d_lock); spin_lock(&lower_dentry->d_lock); } else { spin_lock(&lower_dentry->d_lock); spin_lock(&dentry->d_lock); } if (dentry->d_name.len != lower_dentry->d_name.len) { __d_drop(dentry); err = 0; } else if (strncasecmp(dentry->d_name.name, lower_dentry->d_name.name, dentry->d_name.len) != 0) { __d_drop(dentry); err = 0; } if (dentry < lower_dentry) { spin_unlock(&lower_dentry->d_lock); spin_unlock(&dentry->d_lock); } else { spin_unlock(&dentry->d_lock); spin_unlock(&lower_dentry->d_lock); } out: dput(parent_dentry); dput(lower_cur_parent_dentry); sdcardfskk_put_lower_path(parent_dentry, &parent_lower_path); sdcardfskk_put_real_lower(dentry, &lower_path); return err; }
/* * The locking rules in sdcardfskk_rename are complex. We could use a simpler * superblock-level name-space lock for renames and copy-ups. */ static int sdcardfskk_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { int err = 0; struct dentry *lower_old_dentry = NULL; struct dentry *lower_new_dentry = NULL; struct dentry *lower_old_dir_dentry = NULL; struct dentry *lower_new_dir_dentry = NULL; struct dentry *trap = NULL; struct dentry *new_parent = NULL; struct path lower_old_path, lower_new_path; struct sdcardfskk_sb_info *sbi = SDCARDFSKK_SB(old_dentry->d_sb); const struct cred *saved_cred = NULL; int has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); if(!check_caller_access_to_name(old_dir, old_dentry->d_name.name, sbi->options.derive, 1, has_rw) || !check_caller_access_to_name(new_dir, new_dentry->d_name.name, sbi->options.derive, 1, has_rw)) { printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n" " new_dentry: %s, task:%s\n", __func__, new_dentry->d_name.name, current->comm); err = -EACCES; goto out_eacces; } /* save current_cred and override it */ OVERRIDE_CRED(SDCARDFSKK_SB(old_dir->i_sb), saved_cred); sdcardfskk_get_real_lower(old_dentry, &lower_old_path); sdcardfskk_get_lower_path(new_dentry, &lower_new_path); lower_old_dentry = lower_old_path.dentry; lower_new_dentry = lower_new_path.dentry; lower_old_dir_dentry = dget_parent(lower_old_dentry); lower_new_dir_dentry = dget_parent(lower_new_dentry); trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); /* source should not be ancestor of target */ if (trap == lower_old_dentry) { err = -EINVAL; goto out; } /* target should not be ancestor of source */ if (trap == lower_new_dentry) { err = -ENOTEMPTY; goto out; } err = mnt_want_write(lower_old_path.mnt); if (err) goto out; err = mnt_want_write(lower_new_path.mnt); if (err) goto out_drop_old_write; err = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, lower_new_dir_dentry->d_inode, lower_new_dentry); if (err) goto out_err; /* Copy attrs from lower dir, but i_uid/i_gid */ fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode); fsstack_copy_inode_size(new_dir, lower_new_dir_dentry->d_inode); fix_derived_permission(new_dir); if (new_dir != old_dir) { fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode); fsstack_copy_inode_size(old_dir, lower_old_dir_dentry->d_inode); fix_derived_permission(old_dir); /* update the derived permission of the old_dentry * with its new parent */ new_parent = dget_parent(new_dentry); if(new_parent) { if(old_dentry->d_inode) { get_derived_permission(new_parent, old_dentry); fix_derived_permission(old_dentry->d_inode); } dput(new_parent); } } out_err: mnt_drop_write(lower_new_path.mnt); out_drop_old_write: mnt_drop_write(lower_old_path.mnt); out: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_old_dir_dentry); dput(lower_new_dir_dentry); sdcardfskk_put_real_lower(old_dentry, &lower_old_path); sdcardfskk_put_lower_path(new_dentry, &lower_new_path); REVERT_CRED(saved_cred); out_eacces: return err; }