static int ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { int rc; struct dentry *lower_old_dentry; struct dentry *lower_new_dentry; struct dentry *lower_old_dir_dentry; struct dentry *lower_new_dir_dentry; lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry); lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry); dget(lower_old_dentry); dget(lower_new_dentry); lower_old_dir_dentry = dget_parent(lower_old_dentry); lower_new_dir_dentry = dget_parent(lower_new_dentry); lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); rc = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, lower_new_dir_dentry->d_inode, lower_new_dentry); if (rc) goto out_lock; fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode, NULL); if (new_dir != old_dir) fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode, NULL); out_lock: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_new_dentry->d_parent); dput(lower_old_dentry->d_parent); dput(lower_new_dentry); dput(lower_old_dentry); return rc; }
/* * The locking rules in wrapfs_rename are complex. We could use a simpler * superblock-level name-space lock for renames and copy-ups. */ static int wrapfs_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 path lower_old_path, lower_new_path; wrapfs_get_lower_path(old_dentry, &lower_old_path); wrapfs_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 = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, lower_new_dir_dentry->d_inode, lower_new_dentry, NULL, 0); if (err) goto out; fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode); fsstack_copy_inode_size(new_dir, lower_new_dir_dentry->d_inode); 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); } out: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_old_dir_dentry); dput(lower_new_dir_dentry); wrapfs_put_lower_path(old_dentry, &lower_old_path); wrapfs_put_lower_path(new_dentry, &lower_new_path); #ifdef NEKTECH_LOGGER /*NEKTECH LOGGING*/ nektech_logger (new_dir, new_dentry, NEKTECH_RENAME); #endif /*NEKTECH LOGGING*/ return err; }
static int ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { int rc; struct dentry *lower_old_dentry; struct dentry *lower_new_dentry; struct dentry *lower_old_dir_dentry; struct dentry *lower_new_dir_dentry; struct dentry *trap = NULL; struct inode *target_inode; #ifdef CONFIG_SDP if(IS_CHAMBER_DENTRY(old_dentry)) { printk("You're renaming chamber directory. I/O error\n"); return -EIO; } #endif lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry); lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry); dget(lower_old_dentry); dget(lower_new_dentry); lower_old_dir_dentry = dget_parent(lower_old_dentry); lower_new_dir_dentry = dget_parent(lower_new_dentry); target_inode = new_dentry->d_inode; trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); /* source should not be ancestor of target */ if (trap == lower_old_dentry) { rc = -EINVAL; goto out_lock; } /* target should not be ancestor of source */ if (trap == lower_new_dentry) { rc = -ENOTEMPTY; goto out_lock; } rc = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, lower_new_dir_dentry->d_inode, lower_new_dentry); if (rc) goto out_lock; if (target_inode) fsstack_copy_attr_all(target_inode, ecryptfs_inode_to_lower(target_inode)); fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode); if (new_dir != old_dir) fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode); out_lock: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_new_dir_dentry); dput(lower_old_dir_dentry); dput(lower_new_dentry); dput(lower_old_dentry); return rc; }
static int ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, unsigned int flags) { int rc; struct dentry *lower_old_dentry; struct dentry *lower_new_dentry; struct dentry *lower_old_dir_dentry; struct dentry *lower_new_dir_dentry; struct dentry *trap = NULL; struct inode *target_inode; if (flags) return -EINVAL; lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry); lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry); dget(lower_old_dentry); dget(lower_new_dentry); lower_old_dir_dentry = dget_parent(lower_old_dentry); lower_new_dir_dentry = dget_parent(lower_new_dentry); target_inode = d_inode(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) { rc = -EINVAL; goto out_lock; } /* target should not be ancestor of source */ if (trap == lower_new_dentry) { rc = -ENOTEMPTY; goto out_lock; } rc = vfs_rename(d_inode(lower_old_dir_dentry), lower_old_dentry, d_inode(lower_new_dir_dentry), lower_new_dentry, NULL, 0); if (rc) goto out_lock; if (target_inode) fsstack_copy_attr_all(target_inode, ecryptfs_inode_to_lower(target_inode)); fsstack_copy_attr_all(new_dir, d_inode(lower_new_dir_dentry)); if (new_dir != old_dir) fsstack_copy_attr_all(old_dir, d_inode(lower_old_dir_dentry)); out_lock: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_new_dir_dentry); dput(lower_old_dir_dentry); dput(lower_new_dentry); dput(lower_old_dentry); return rc; }
/* * The locking rules in diaryfs_rename are complex. We could use a simpler * superblock level namespace lock for renames and copy-ups */ static int diaryfs_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 path lower_old_path, lower_new_path; diaryfs_get_lower_path(old_dentry, &lower_old_path); diaryfs_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 the target */ if (trap == lower_old_dentry) { err = -EINVAL; goto out; } /* target should not be ancestor of source */ if (trap == lower_new_dentry) { err = -EINVAL; goto out; } err = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, lower_new_dir_dentry->d_inode, lower_new_dentry, NULL, 0); if (err) goto out; fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode); fsstack_copy_inode_size(new_dir, lower_new_dir_dentry->d_inode); 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); } out: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_old_dir_dentry); dput(lower_new_dir_dentry); diaryfs_put_lower_path(old_dentry, &lower_old_path); diaryfs_put_lower_path(new_dentry, &lower_new_path); return err; }
/** * ecryptfs_d_revalidate - revalidate an ecryptfs dentry * @dentry: The ecryptfs dentry * @nd: The associated nameidata * * Called when the VFS needs to revalidate a dentry. This * is called whenever a name lookup finds a dentry in the * dcache. Most filesystems leave this as NULL, because all their * dentries in the dcache are valid. * * Returns 1 if valid, 0 otherwise. * */ static int ecryptfs_d_revalidate(struct dentry *dentry, struct nameidata *nd) { struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry); struct dentry *dentry_save; struct vfsmount *vfsmount_save; int rc = 1; if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate) goto out; dentry_save = nd->dentry; vfsmount_save = nd->mnt; nd->dentry = lower_dentry; nd->mnt = lower_mnt; rc = lower_dentry->d_op->d_revalidate(lower_dentry, nd); nd->dentry = dentry_save; nd->mnt = vfsmount_save; if (dentry->d_inode) { struct inode *lower_inode = ecryptfs_inode_to_lower(dentry->d_inode); fsstack_copy_attr_all(dentry->d_inode, lower_inode, NULL); } out: return rc; }
static int ecryptfs_d_revalidate(struct dentry *dentry, struct nameidata *nd) { struct dentry *lower_dentry; struct vfsmount *lower_mnt; struct dentry *dentry_save = NULL; struct vfsmount *vfsmount_save = NULL; int rc = 1; if (nd && nd->flags & LOOKUP_RCU) return -ECHILD; lower_dentry = ecryptfs_dentry_to_lower(dentry); lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry); if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate) goto out; if (nd) { dentry_save = nd->path.dentry; vfsmount_save = nd->path.mnt; nd->path.dentry = lower_dentry; nd->path.mnt = lower_mnt; } rc = lower_dentry->d_op->d_revalidate(lower_dentry, nd); if (nd) { nd->path.dentry = dentry_save; nd->path.mnt = vfsmount_save; } if (dentry->d_inode) { struct inode *lower_inode = ecryptfs_inode_to_lower(dentry->d_inode); fsstack_copy_attr_all(dentry->d_inode, lower_inode); } out: return rc; }
static int ecryptfs_inode_set(struct inode *inode, void *opaque) { struct inode *lower_inode = opaque; ecryptfs_set_inode_lower(inode, lower_inode); fsstack_copy_attr_all(inode, lower_inode); /* i_size will be overwritten for encrypted regular files */ fsstack_copy_inode_size(inode, lower_inode); inode->i_ino = lower_inode->i_ino; inode->i_version++; inode->i_mapping->a_ops = &ecryptfs_aops; inode->i_mapping->backing_dev_info = inode->i_sb->s_bdi; if (S_ISLNK(inode->i_mode)) inode->i_op = &ecryptfs_symlink_iops; else if (S_ISDIR(inode->i_mode)) inode->i_op = &ecryptfs_dir_iops; else inode->i_op = &ecryptfs_main_iops; if (S_ISDIR(inode->i_mode)) inode->i_fop = &ecryptfs_dir_fops; else if (special_file(inode->i_mode)) init_special_inode(inode, inode->i_mode, inode->i_rdev); else inode->i_fop = &ecryptfs_main_fops; return 0; }
static int ccfs_setattr(struct dentry *dentry, struct iattr *ia) { int rc = 0; struct dentry *lower_dentry; struct inode *inode; struct inode *lower_inode; inode = dentry->d_inode; lower_inode = ccfs_get_nested_inode(inode); lower_dentry = ccfs_get_nested_dentry(dentry); if (ia->ia_valid & ATTR_SIZE) { mdbg(INFO3, "ia->ia_valid = [0x%x] ATTR_SIZE" " = [0x%x]", ia->ia_valid, ATTR_SIZE); rc = ccfs_truncate(dentry, ia->ia_size); ia->ia_valid &= ~ATTR_SIZE; mdbg(INFO3,"ia->ia_valid = [%x]", ia->ia_valid); if (rc < 0) goto out; } /* * mode change is for clearing setuid/setgid bits. Allow lower fs * to interpret this in its own way. */ if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) ia->ia_valid &= ~ATTR_MODE; rc = notify_change(lower_dentry, ia); out: fsstack_copy_attr_all(inode, lower_inode); return rc; }
static long ecryptfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct file *lower_file = NULL; long rc = -ENOIOCTLCMD; if (ecryptfs_file_to_private(file)) lower_file = ecryptfs_file_to_lower(file); if (!(lower_file && lower_file->f_op && lower_file->f_op->compat_ioctl)) return rc; switch (cmd) { case FITRIM: case FS_IOC32_GETFLAGS: case FS_IOC32_SETFLAGS: case FS_IOC32_GETVERSION: case FS_IOC32_SETVERSION: rc = lower_file->f_op->compat_ioctl(lower_file, cmd, arg); fsstack_copy_attr_all(file->f_path.dentry->d_inode, lower_file->f_path.dentry->d_inode); return rc; default: return rc; } }
static int scfs_inode_set(struct inode *inode, void *opaque) { struct inode *lower_inode = opaque; scfs_set_lower_inode(inode, lower_inode); fsstack_copy_attr_all(inode, lower_inode); fsstack_copy_inode_size(inode, lower_inode); inode->i_ino = lower_inode->i_ino; inode->i_version++; inode->i_mapping->a_ops = &scfs_aops; inode->i_mapping->backing_dev_info = inode->i_sb->s_bdi; if (S_ISLNK(inode->i_mode)) inode->i_op = &scfs_symlink_iops; else if (S_ISDIR(inode->i_mode)) inode->i_op = &scfs_dir_iops; else inode->i_op = &scfs_file_iops; if (S_ISDIR(inode->i_mode)) inode->i_fop = &scfs_dir_fops; else if (special_file(inode->i_mode)) init_special_inode(inode, inode->i_mode, inode->i_rdev); else inode->i_fop = &scfs_file_fops; return SCFS_SUCCESS; }
static int __open_dir(struct inode *inode, struct file *file, struct dentry *parent) { struct dentry *lower_dentry; struct file *lower_file; struct vfsmount *lower_mnt; struct dentry *dentry = file->f_path.dentry; int i = 0, idx = 0; for (i = 0; i <= 1; i++) { lower_dentry = wrapfs_lower_dentry_idx(dentry, i); if (!lower_dentry || !lower_dentry->d_inode) continue; dget(lower_dentry); lower_mnt = mntget(wrapfs_lower_mnt_idx(dentry, i)); if (!lower_mnt) lower_mnt = mntget(wrapfs_lower_mnt_idx(parent, i)); lower_file = dentry_open(lower_dentry, lower_mnt, file->f_flags, current_cred()); if (IS_ERR(lower_file)) return PTR_ERR(lower_file); wrapfs_set_lower_file_idx(file, i, lower_file); if (!wrapfs_lower_mnt_idx(dentry, i)) wrapfs_set_lower_mnt_idx(dentry, i, lower_mnt); branchget(inode->i_sb, i); idx = i; } fsstack_copy_attr_all(inode, wrapfs_lower_inode_idx(inode, idx)); return 0; }
static long ecryptfs_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct file *lower_file = NULL; long rc = -ENOTTY; if (ecryptfs_file_to_private(file)) lower_file = ecryptfs_file_to_lower(file); if (!(lower_file && lower_file->f_op && lower_file->f_op->unlocked_ioctl)) return rc; switch (cmd) { case FITRIM: case FS_IOC_GETFLAGS: case FS_IOC_SETFLAGS: case FS_IOC_GETVERSION: case FS_IOC_SETVERSION: rc = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg); fsstack_copy_attr_all(file_inode(file), file_inode(lower_file)); return rc; default: return rc; } }
static int ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { int rc; struct dentry *lower_old_dentry; struct dentry *lower_new_dentry; struct dentry *lower_old_dir_dentry; struct dentry *lower_new_dir_dentry; struct dentry *trap = NULL; if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode)) dentry_unhash(new_dentry); lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry); lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry); dget(lower_old_dentry); dget(lower_new_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) { rc = -EINVAL; goto out_lock; } /* target should not be ancestor of source */ if (trap == lower_new_dentry) { rc = -ENOTEMPTY; goto out_lock; } rc = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, lower_new_dir_dentry->d_inode, lower_new_dentry); if (rc) goto out_lock; fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode); if (new_dir != old_dir) fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode); out_lock: unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); dput(lower_new_dir_dentry); dput(lower_old_dir_dentry); dput(lower_new_dentry); dput(lower_old_dentry); return rc; }
static int ecryptfs_update_crypt_flag(struct dentry *dentry, int is_sensitive) { int rc = 0; struct inode *inode; struct inode *lower_inode; struct ecryptfs_crypt_stat *crypt_stat; u32 tmp_flags; crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat; if (!(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED)) ecryptfs_init_crypt_stat(crypt_stat); inode = dentry->d_inode; lower_inode = ecryptfs_inode_to_lower(inode); mutex_lock(&crypt_stat->cs_mutex); rc = ecryptfs_get_lower_file(dentry, inode); if (rc) { mutex_unlock(&crypt_stat->cs_mutex); DEK_LOGE("ecryptfs_get_lower_file rc=%d\n", rc); goto out; } tmp_flags = crypt_stat->flags; if (is_sensitive) { crypt_stat->flags |= ECRYPTFS_DEK_IS_SENSITIVE; /* * Set sensirive for all the pages in the inode */ set_sensitive_mapping_pages(inode->i_mapping, 0, -1); } else{ crypt_stat->flags &= ~ECRYPTFS_DEK_IS_SENSITIVE; } rc = ecryptfs_write_metadata(dentry, inode); if (rc) { crypt_stat->flags = tmp_flags; mutex_unlock(&crypt_stat->cs_mutex); DEK_LOGE("ecryptfs_write_metadata rc=%d\n", rc); goto out; } rc = ecryptfs_write_inode_size_to_metadata(inode); if (rc) { mutex_unlock(&crypt_stat->cs_mutex); DEK_LOGE("Problem with " "ecryptfs_write_inode_size_to_metadata; " "rc = [%d]\n", rc); goto out; } ecryptfs_put_lower_file(inode); mutex_unlock(&crypt_stat->cs_mutex); out: fsstack_copy_attr_all(inode, lower_inode); return rc; }
static int __open_file(struct inode *inode, struct file *file, struct dentry *parent) { struct dentry *lower_dentry; struct file *lower_file; struct vfsmount *lower_mnt; struct dentry *dentry = file->f_path.dentry; int lower_flags; int i = 0, idx = 0; for (i = 0; i <= 1; i++) { lower_dentry = wrapfs_lower_dentry_idx(dentry, i); if (!lower_dentry || !lower_dentry->d_inode) continue; lower_flags = file->f_flags; if (lower_dentry->d_inode && (i == 1)) { UDBG; if (lower_flags & O_TRUNC) { int size = 0; int err = -EROFS; UDBG; err = copyup_file(parent->d_inode, file, i, 0, size); if (!err) break; return err; } else lower_flags &= ~(OPEN_WRITE_FLAGS); } dget(lower_dentry); lower_mnt = mntget(wrapfs_lower_mnt_idx(dentry, i)); if (!lower_mnt) lower_mnt = mntget(wrapfs_lower_mnt_idx(parent, i)); lower_file = dentry_open(lower_dentry, lower_mnt, lower_flags, current_cred()); if (IS_ERR(lower_file)) return PTR_ERR(lower_file); wrapfs_set_lower_file(file, lower_file); branchget(inode->i_sb, i); idx = i; goto out; } out: if (!wrapfs_lower_inode_idx(inode, idx)) fsstack_copy_attr_all(inode, wrapfs_lower_inode_idx(inode, idx)); return 0; }
static int wrapfs_open(struct inode *inode, struct file *file) { int err = 0; struct file *lower_file = NULL; struct path lower_path; #ifdef EXTRA_CREDIT if(wrapfs_get_debug(file->f_dentry->d_sb) & DEBUG_FILE) DEBUG_MESG("Enter"); #endif /* don't open unhashed/deleted files */ if (d_unhashed(file->f_path.dentry)) { err = -ENOENT; goto out_err; } file->private_data = kzalloc(sizeof(struct wrapfs_file_info), GFP_KERNEL); if (!WRAPFS_F(file)) { err = -ENOMEM; goto out_err; } /* open lower object and link wrapfs's file struct to lower's */ wrapfs_get_lower_path(file->f_path.dentry, &lower_path); lower_file = dentry_open(lower_path.dentry, lower_path.mnt, file->f_flags, current_cred()); if (IS_ERR(lower_file)) { err = PTR_ERR(lower_file); lower_file = wrapfs_lower_file(file); if (lower_file) { wrapfs_set_lower_file(file, NULL); fput(lower_file); /* fput calls dput for lower_dentry */ } } else { wrapfs_set_lower_file(file, lower_file); } if (err) kfree(WRAPFS_F(file)); else fsstack_copy_attr_all(inode, wrapfs_lower_inode(inode)); out_err: #ifdef EXTRA_CREDIT if(wrapfs_get_debug(file->f_dentry->d_sb) & DEBUG_FILE) DEBUG_RETURN("Exit", err); #endif return err; }
static int ccfs_d_revalidate(struct dentry *dentry, struct nameidata *nd) { struct dentry *lower_dentry = ccfs_get_nested_dentry(dentry); struct vfsmount *lower_mnt = ccfs_dentry_to_nested_mnt(dentry); struct dentry *dentry_save; struct vfsmount *vfsmount_save; int rc = 1; mdbg(INFO3,"Revalidating dentry: (%s) %p", dentry->d_iname, dentry); // Do not cache negative dentries or uncachable dentries if ( !dentry->d_inode ) { mdbg(INFO3,"Inodeless dentry -> invalid"); return 0; } if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate) goto out; dentry_save = nd->path.dentry; vfsmount_save = nd->path.mnt; nd->path.dentry = lower_dentry; nd->path.mnt = lower_mnt; rc = lower_dentry->d_op->d_revalidate(lower_dentry, nd); nd->path.dentry = dentry_save; nd->path.mnt = vfsmount_save; if (dentry->d_inode) { struct inode *lower_inode = ccfs_get_nested_inode(dentry->d_inode); fsstack_copy_attr_all(dentry->d_inode, lower_inode); } out: /* No special handling of non-cacheable nodes.. if the dentry is still in cache, we just let lower FS to revalidate the dentry. If we return 0 here, some operations may break as some FS actions would failed even though they are valid. if ( !ccfs_inode_to_private(dentry->d_inode)->cacheable ) { mdbg(INFO3,"Non-cacheable inode -> invalid"); return 0; } */ mdbg(INFO3,"Revalidation result: %d", rc); return rc; }
static int diaryfs_getattr(struct vfsmount *mnt, struct dentry * dentry, struct kstat *stat) { int err; struct kstat lower_stat; struct path lower_path; diaryfs_get_lower_path(dentry, &lower_path); err = vfs_getattr(&lower_path, &lower_stat); if (err) goto out; fsstack_copy_attr_all(dentry->d_inode, lower_path.dentry->d_inode); generic_fillattr(dentry->d_inode, stat); stat->blocks = lower_stat.blocks; out: diaryfs_put_lower_path(dentry, &lower_path); return err; }
static void wrapfs_fill_inode(struct dentry *dentry, struct inode *inode) { struct inode *lower_inode; struct dentry *lower_dentry; int i = 0, id1 = 0, id2 = 0; for (i = 0; i <= 1; i++) { lower_dentry = wrapfs_lower_dentry_idx(dentry, i); if (!lower_dentry) { wrapfs_set_lower_inode_idx(inode, i, NULL); continue; } if (!lower_dentry->d_inode) continue; wrapfs_set_lower_inode_idx(inode, i, igrab(lower_dentry->d_inode)); id1++; id2 = i; } /* Use attributes from the first branch */ if (id1 == i) lower_inode = wrapfs_lower_inode(inode); else { lower_inode = wrapfs_lower_inode_idx(inode, id2); if (id2 == 1) wrapfs_set_lower_inode_idx(inode, 0, NULL); else wrapfs_set_lower_inode_idx(inode, 1, NULL); } /* Use different set of inode ops for symlinks and directories*/ if (S_ISLNK(lower_inode->i_mode)) inode->i_op = &wrapfs_symlink_iops; else if (S_ISDIR(lower_inode->i_mode)) inode->i_op = &wrapfs_dir_iops; if (S_ISDIR(lower_inode->i_mode)) inode->i_fop = &wrapfs_dir_fops; if (S_ISBLK(lower_inode->i_mode) || S_ISCHR(lower_inode->i_mode) || S_ISFIFO(lower_inode->i_mode) || S_ISSOCK(lower_inode->i_mode)) init_special_inode(inode, lower_inode->i_mode, lower_inode->i_rdev); fsstack_copy_attr_all(inode, lower_inode); fsstack_copy_inode_size(inode, lower_inode); }
static int diaryfs_removexattr(struct dentry * dentry, const char * name) { int err; struct dentry * lower_dentry; struct path lower_path; diaryfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; if (!lower_dentry->d_inode->i_op || !lower_dentry->d_inode->i_op->removexattr) { err = -EINVAL; goto out; } err = vfs_removexattr(lower_dentry, name); if (err) goto out; fsstack_copy_attr_all(dentry->d_inode, lower_path.dentry->d_inode); out: diaryfs_put_lower_path(dentry, &lower_path); return err; }
static int diaryfs_setxattr(struct dentry * dentry, const char * name, const void * value, size_t size, int flags) { int err; struct dentry * lower_dentry; struct path lower_path; diaryfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; if (!lower_dentry->d_inode->i_op->setxattr) { err = -EOPNOTSUPP; goto out; } err = vfs_setxattr(lower_dentry, name, value, size, flags); if (err) goto out; fsstack_copy_attr_all(dentry->d_inode, lower_path.dentry->d_inode); out: diaryfs_put_lower_path(dentry, &lower_path); return err; }
static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { struct dentry *lower_dentry; struct inode *inode; struct inode *lower_inode; struct path lower_path; inode = dentry->d_inode; sdcardfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_inode = sdcardfs_lower_inode(inode); fsstack_copy_attr_all(inode, lower_inode); fix_fat_permission(inode); generic_fillattr(inode, stat); sdcardfs_put_lower_path(dentry, &lower_path); return 0; }
static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { struct dentry *lower_dentry; struct inode *inode; struct inode *lower_inode; struct path lower_path; struct dentry *parent; struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); parent = dget_parent(dentry); if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name, sbi->options.derive, 0, 0)) { 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); dput(parent); return -EACCES; } dput(parent); inode = dentry->d_inode; sdcardfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_inode = sdcardfs_lower_inode(inode); fsstack_copy_attr_all(inode, lower_inode); fsstack_copy_inode_size(inode, lower_inode); /* if the dentry has been moved from other location * so, on this stage, its derived permission must be * rechecked from its private field. */ fix_derived_permission(inode); generic_fillattr(inode, stat); sdcardfs_put_lower_path(dentry, &lower_path); return 0; }
/** * ecryptfs_d_revalidate - revalidate an ecryptfs dentry * @dentry: The ecryptfs dentry * @flags: lookup flags * * Called when the VFS needs to revalidate a dentry. This * is called whenever a name lookup finds a dentry in the * dcache. Most filesystems leave this as NULL, because all their * dentries in the dcache are valid. * * Returns 1 if valid, 0 otherwise. * */ static int ecryptfs_d_revalidate(struct dentry *dentry, unsigned int flags) { struct dentry *lower_dentry; struct vfsmount *lower_mnt; int rc = 1; if (flags & LOOKUP_RCU) return -ECHILD; lower_dentry = ecryptfs_dentry_to_lower(dentry); lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry); if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate) goto out; rc = lower_dentry->d_op->d_revalidate(lower_dentry, flags); if (dentry->d_inode) { struct inode *lower_inode = ecryptfs_inode_to_lower(dentry->d_inode); fsstack_copy_attr_all(dentry->d_inode, lower_inode); } out: return rc; }
static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia) { int err = 0; struct dentry *lower_dentry; struct inode *inode; struct inode *lower_inode; struct path lower_path; struct iattr lower_ia; struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); struct dentry *parent; int has_rw; inode = dentry->d_inode; /* * Check if user has permission to change inode. We don't check if * this user can change the lower inode: that should happen when * calling notify_change on the lower inode. */ err = inode_change_ok(inode, ia); /* no vfs_XXX operations required, cred overriding will be skipped. wj*/ if (!err) { /* check the Android group ID */ has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); parent = dget_parent(dentry); if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name, sbi->options.derive, 1, has_rw)) err = -EACCES; dput(parent); } if (err) goto out_err; sdcardfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_inode = sdcardfs_lower_inode(inode); /* prepare our own lower struct iattr (with the lower file) */ memcpy(&lower_ia, ia, sizeof(lower_ia)); if (ia->ia_valid & ATTR_FILE) lower_ia.ia_file = sdcardfs_lower_file(ia->ia_file); lower_ia.ia_valid &= ~(ATTR_UID | ATTR_GID | ATTR_MODE); /* * If shrinking, first truncate upper level to cancel writing dirty * pages beyond the new eof; and also if its' maxbytes is more * limiting (fail with -EFBIG before making any change to the lower * level). There is no need to vmtruncate the upper level * afterwards in the other cases: we fsstack_copy_inode_size from * the lower level. */ down_write(¤t->mm->mmap_sem); if (ia->ia_valid & ATTR_SIZE) { err = inode_newsize_ok(inode, ia->ia_size); if (err) { up_write(¤t->mm->mmap_sem); goto out; } truncate_setsize(inode, ia->ia_size); } /* * mode change is for clearing setuid/setgid bits. Allow lower fs * to interpret this in its own way. */ if (lower_ia.ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) lower_ia.ia_valid &= ~ATTR_MODE; /* notify the (possibly copied-up) lower inode */ /* * Note: we use lower_dentry->d_inode, because lower_inode may be * unlinked (no inode->i_sb and i_ino==0. This happens if someone * tries to open(), unlink(), then ftruncate() a file. */ mutex_lock(&lower_dentry->d_inode->i_mutex); err = notify_change(lower_dentry, &lower_ia); /* note: lower_ia */ mutex_unlock(&lower_dentry->d_inode->i_mutex); up_write(¤t->mm->mmap_sem); if (err) goto out; /* get attributes from the lower inode */ fsstack_copy_attr_all(inode, lower_inode); /* update derived permission of the upper inode */ fix_derived_permission(inode); /* * Not running fsstack_copy_inode_size(inode, lower_inode), because * VFS should update our inode size, and notify_change on * lower_inode should update its size. */ out: sdcardfs_put_lower_path(dentry, &lower_path); out_err: return err; }
static int wrapfs_setattr(struct dentry *dentry, struct iattr *ia) { int err = 0; struct dentry *lower_dentry; struct inode *inode; struct inode *lower_inode; struct path lower_path; struct iattr lower_ia; inode = dentry->d_inode; /* * Check if user has permission to change inode. We don't check if * this user can change the lower inode: that should happen when * calling notify_change on the lower inode. */ err = inode_change_ok(inode, ia); if (err) goto out_err; wrapfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_inode = wrapfs_lower_inode(inode); /* prepare our own lower struct iattr (with the lower file) */ memcpy(&lower_ia, ia, sizeof(lower_ia)); if (ia->ia_valid & ATTR_FILE) lower_ia.ia_file = wrapfs_lower_file(ia->ia_file); /* * If shrinking, first truncate upper level to cancel writing dirty * pages beyond the new eof; and also if its' maxbytes is more * limiting (fail with -EFBIG before making any change to the lower * level). There is no need to vmtruncate the upper level * afterwards in the other cases: we fsstack_copy_inode_size from * the lower level. */ if (ia->ia_valid & ATTR_SIZE) { err = inode_newsize_ok(inode, ia->ia_size); if (err) goto out; truncate_setsize(inode, ia->ia_size); } /* * mode change is for clearing setuid/setgid bits. Allow lower fs * to interpret this in its own way. */ if (lower_ia.ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) lower_ia.ia_valid &= ~ATTR_MODE; /* notify the (possibly copied-up) lower inode */ /* * Note: we use lower_dentry->d_inode, because lower_inode may be * unlinked (no inode->i_sb and i_ino==0. This happens if someone * tries to open(), unlink(), then ftruncate() a file. */ mutex_lock(&lower_dentry->d_inode->i_mutex); err = notify_change(lower_dentry, &lower_ia); /* note: lower_ia */ mutex_unlock(&lower_dentry->d_inode->i_mutex); if (err) goto out; /* get attributes from the lower inode */ fsstack_copy_attr_all(inode, lower_inode); /* * Not running fsstack_copy_inode_size(inode, lower_inode), because * VFS should update our inode size, and notify_change on * lower_inode should update its size. */ out: wrapfs_put_lower_path(dentry, &lower_path); out_err: return err; }
/* * The locking rules in wrapfs_rename are complex. We could use a simpler * superblock-level name-space lock for renames and copy-ups. */ static int wrapfs_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 path lower_old_path, lower_new_path; wrapfs_get_lower_path(old_dentry, &lower_old_path); wrapfs_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; fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode); fsstack_copy_inode_size(new_dir, lower_new_dir_dentry->d_inode); 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); } 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); wrapfs_put_lower_path(old_dentry, &lower_old_path); wrapfs_put_lower_path(new_dentry, &lower_new_path); return err; }
static int scfs_open(struct inode *inode, struct file *file) { struct scfs_sb_info *sbi = SCFS_S(inode->i_sb); struct scfs_inode_info *sii = SCFS_I(inode); struct scfs_file_info *fi; int ret = 0; struct file *lower_file; if (IS_WROPENED(sii)) { SCFS_PRINT("This file is already opened with 'WRITE' flag\n"); return -EPERM; } fi = kmem_cache_zalloc(scfs_file_info_cache, GFP_KERNEL); if (!fi) return -ENOMEM; profile_add_kmcached(sizeof(struct scfs_file_info), sbi); file->private_data = fi; mutex_lock(&sii->cinfo_mutex); if (IS_INVALID_META(sii)) { SCFS_PRINT("meta is invalid, so we should re-load it\n"); ret = scfs_reload_meta(file); if (ret) { SCFS_PRINT_ERROR("error in re-reading footer, err : %d\n", ret); goto out; } } else if (sii->compressed && !sii->cinfo_array) { /* 1st lower-open is for getting cinfo */ ret = scfs_initialize_lower_file(file->f_dentry, &lower_file, O_RDONLY); if (ret) { SCFS_PRINT_ERROR("err in get_lower_file %s\n", file->f_dentry->d_name.name); goto out; } scfs_set_lower_file(file, lower_file); SCFS_PRINT("info size = %d \n", sii->cinfo_array_size); ret = scfs_load_cinfo(sii, lower_file); if (ret) { SCFS_PRINT_ERROR("err in loading cinfo, ret : %d\n", file->f_dentry->d_name.name); fput(lower_file); goto out; } fput(lower_file); } ret = scfs_initialize_lower_file(file->f_dentry, &lower_file, file->f_flags); if (ret) { SCFS_PRINT_ERROR("err in get_lower_file %s\n", file->f_dentry->d_name.name); goto out; } scfs_set_lower_file(file, lower_file); out: if (!ret) { fsstack_copy_attr_all(inode, scfs_lower_inode(inode)); if (file->f_flags & (O_RDWR | O_WRONLY)) MAKE_WROPENED(sii); } else { scfs_set_lower_file(file, NULL); kmem_cache_free(scfs_file_info_cache, file->private_data); profile_sub_kmcached(sizeof(struct scfs_file_info), sbi); sii->cinfo_array = NULL; } mutex_unlock(&sii->cinfo_mutex); SCFS_PRINT("lower, dentry name : %s, count : %d, ret : %d\n", file->f_dentry->d_name.name, file->f_dentry->d_count, ret); return ret; }
static int sdcardfs_open(struct inode *inode, struct file *file) { int err = 0; struct file *lower_file = NULL; struct path lower_path; struct dentry *dentry = file->f_path.dentry; struct dentry *parent = dget_parent(dentry); struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); const struct cred *saved_cred = NULL; int has_rw; /* don't open unhashed/deleted files */ if (d_unhashed(dentry)) { err = -ENOENT; goto out_err; } has_rw = get_caller_has_rw_locked(sbi->pkgl_id, sbi->options.derive); if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name, sbi->options.derive, open_flags_to_access_mode(file->f_flags), 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_err; } /* save current_cred and override it */ OVERRIDE_CRED(sbi, saved_cred); file->private_data = kzalloc(sizeof(struct sdcardfs_file_info), GFP_KERNEL); if (!SDCARDFS_F(file)) { err = -ENOMEM; goto out_revert_cred; } /* open lower object and link sdcardfs's file struct to lower's */ sdcardfs_get_lower_path(file->f_path.dentry, &lower_path); lower_file = dentry_open(lower_path.dentry, lower_path.mnt, file->f_flags, current_cred()); if (IS_ERR(lower_file)) { err = PTR_ERR(lower_file); lower_file = sdcardfs_lower_file(file); if (lower_file) { sdcardfs_set_lower_file(file, NULL); fput(lower_file); /* fput calls dput for lower_dentry */ } } else { sdcardfs_set_lower_file(file, lower_file); } if (err) kfree(SDCARDFS_F(file)); else { fsstack_copy_attr_all(inode, sdcardfs_lower_inode(inode)); fix_derived_permission(inode); } out_revert_cred: REVERT_CRED(saved_cred); out_err: dput(parent); return err; }