static ssize_t wrapfs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { int err = 0; struct file *lower_file; struct dentry *dentry = file->f_path.dentry; #ifdef WRAPFS_CRYPTO char zero_key[KEYLEN + 1]; memset(zero_key, '0', sizeof(zero_key)); zero_key[KEYLEN] = '\0'; #endif /*printk(KERN_ALERT "In wrapfs_write()\n");*/ lower_file = wrapfs_lower_file(file); if (1 == WRAPFS_SB(file->f_dentry->d_sb)->mount_options.mmap) { #ifdef WRAPFS_CRYPTO if (0 == memcmp(&(WRAPFS_SB(file->f_dentry->d_sb)->key), &zero_key, KEYLEN)) return -ENOKEY; #endif err = do_sync_write(file, buf, count, ppos); } else { /*printk(KERN_ALERT "calling vfs_read()\n");*/ err = vfs_write(lower_file, buf, count, ppos); } /* update our inode times+sizes upon a successful lower write */ if (err >= 0) { fsstack_copy_inode_size(dentry->d_inode, lower_file->f_path.dentry->d_inode); fsstack_copy_attr_times(dentry->d_inode, lower_file->f_path.dentry->d_inode); } return err; }
static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry) { int rc = 0; struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir); struct dentry *lower_dir_dentry; lower_dir_dentry = lock_parent(lower_dentry); rc = vfs_unlink(lower_dir_inode, lower_dentry); if (rc) { printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc); goto out_unlock; } fsstack_copy_attr_times(dir, lower_dir_inode); dentry->d_inode->i_nlink = ecryptfs_inode_to_lower(dentry->d_inode)->i_nlink; dentry->d_inode->i_ctime = dir->i_ctime; d_drop(dentry); out_unlock: unlock_dir(lower_dir_dentry); return rc; }
static int wrapfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) { int err = 0; struct dentry *lower_dentry; struct dentry *lower_parent_dentry = NULL; struct path lower_path; if(wrapfs_get_debug(dir->i_sb) & DEBUG_INODE) DEBUG_MESG("Enter"); wrapfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_parent_dentry = lock_parent(lower_dentry); err = mnt_want_write(lower_path.mnt); if (err) goto out_unlock; err = vfs_mknod(lower_parent_dentry->d_inode, lower_dentry, mode, dev); if (err) goto out; err = wrapfs_interpose(dentry, dir->i_sb, &lower_path); if (err) goto out; fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir)); fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); out: mnt_drop_write(lower_path.mnt); out_unlock: unlock_dir(lower_parent_dentry); wrapfs_put_lower_path(dentry, &lower_path); if(wrapfs_get_debug(dir->i_sb) & DEBUG_INODE) DEBUG_RETURN("Exit", err); return err; }
static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { int rc; struct dentry *lower_dentry; struct dentry *lower_dir_dentry; umode_t mode; char *encoded_symname; int encoded_symlen; struct ecryptfs_crypt_stat *crypt_stat = NULL; lower_dentry = ecryptfs_dentry_to_lower(dentry); dget(lower_dentry); lower_dir_dentry = lock_parent(lower_dentry); mode = S_IALLUGO; encoded_symlen = ecryptfs_encode_filename(crypt_stat, symname, strlen(symname), &encoded_symname); if (encoded_symlen < 0) { rc = encoded_symlen; goto out_lock; } rc = vfs_symlink(lower_dir_dentry->d_inode, lower_dentry, encoded_symname, mode); kfree(encoded_symname); if (rc || !lower_dentry->d_inode) goto out_lock; rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0); if (rc) goto out_lock; fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode); fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode); out_lock: unlock_dir(lower_dir_dentry); dput(lower_dentry); if (!dentry->d_inode) d_drop(dentry); return rc; }
static int diaryfs_unlink(struct inode *dir, struct dentry *dentry) { int err; struct dentry * lower_dentry; struct inode * lower_dir_inode = diaryfs_lower_inode(dir); struct dentry * lower_dir_dentry; struct path lower_path; diaryfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; dget(lower_dentry); lower_dir_dentry = lock_parent(lower_dentry); err = vfs_unlink(lower_dir_inode, lower_dentry, NULL); /* * Note: unlinking on top of NFS can cause silly-renamed files * Trying to delete such files results in EBUSY from NFS * below. Silly-renamed files will get deleted by NFS later on, * so we just need to detect them here and treat EBUSY errors * as if the upper file was successfully deleted. */ if (err == -EBUSY && lower_dentry->d_flags & DCACHE_NFSFS_RENAMED) err = 0; if (err) goto out; fsstack_copy_attr_times(dir, lower_dir_inode); fsstack_copy_inode_size(dir, lower_dir_inode); set_nlink(dentry->d_inode, diaryfs_lower_inode(dentry->d_inode)->i_nlink); dentry->d_inode->i_ctime = dir->i_ctime; d_drop(dentry); /* this is needed, else LTP fails */ out: unlock_dir(lower_dir_dentry); dput(lower_dentry); diaryfs_put_lower_path(dentry, &lower_path); return err; }
static ssize_t wrapfs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { int err = 0; struct file *lower_file; struct dentry *dentry = file->f_path.dentry; lower_file = wrapfs_lower_file(file); if (!lower_file) return -EPERM; err = vfs_write(lower_file, buf, count, ppos); /* update our inode times+sizes upon a successful lower write */ if (err >= 0) { fsstack_copy_inode_size(dentry->d_inode, lower_file->f_path.dentry->d_inode); fsstack_copy_attr_times(dentry->d_inode, lower_file->f_path.dentry->d_inode); } return err; }
static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry) { struct dentry *lower_dentry; struct dentry *lower_dir_dentry; int rc; lower_dentry = ecryptfs_dentry_to_lower(dentry); dget(dentry); lower_dir_dentry = lock_parent(lower_dentry); dget(lower_dentry); rc = vfs_rmdir(d_inode(lower_dir_dentry), lower_dentry); dput(lower_dentry); if (!rc && d_really_is_positive(dentry)) clear_nlink(d_inode(dentry)); fsstack_copy_attr_times(dir, d_inode(lower_dir_dentry)); set_nlink(dir, d_inode(lower_dir_dentry)->i_nlink); unlock_dir(lower_dir_dentry); if (!rc) d_drop(dentry); dput(dentry); return rc; }
static int wrapfs_rmdir(struct inode *dir, struct dentry *dentry) { struct dentry *lower_dentry; struct dentry *lower_dir_dentry; int err; struct path lower_path; if(wrapfs_get_debug(dir->i_sb) & DEBUG_INODE) DEBUG_MESG("Enter"); wrapfs_get_lower_path(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); set_nlink(dir, lower_dir_dentry->d_inode->i_nlink); out: mnt_drop_write(lower_path.mnt); out_unlock: unlock_dir(lower_dir_dentry); wrapfs_put_lower_path(dentry, &lower_path); if(wrapfs_get_debug(dir->i_sb) & DEBUG_INODE) DEBUG_RETURN("Exit", err); return err; }
static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { int rc; struct dentry *lower_dentry; struct dentry *lower_dir_dentry; char *encoded_symname; size_t encoded_symlen; struct ecryptfs_mount_crypt_stat *mount_crypt_stat = NULL; lower_dentry = ecryptfs_dentry_to_lower(dentry); dget(lower_dentry); lower_dir_dentry = lock_parent(lower_dentry); mount_crypt_stat = &ecryptfs_superblock_to_private( dir->i_sb)->mount_crypt_stat; rc = ecryptfs_encrypt_and_encode_filename(&encoded_symname, &encoded_symlen, NULL, mount_crypt_stat, symname, strlen(symname)); if (rc) goto out_lock; rc = vfs_symlink(lower_dir_dentry->d_inode, lower_dentry, encoded_symname); kfree(encoded_symname); if (rc || !lower_dentry->d_inode) goto out_lock; rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb); if (rc) goto out_lock; fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode); fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode); out_lock: unlock_dir(lower_dir_dentry); dput(lower_dentry); if (!dentry->d_inode) d_drop(dentry); return rc; }
static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry) { struct dentry *lower_dentry; struct dentry *lower_dir_dentry; int rc; lower_dentry = ecryptfs_dentry_to_lower(dentry); dget(dentry); lower_dir_dentry = lock_parent(lower_dentry); dget(lower_dentry); rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry); dput(lower_dentry); if (!rc && dentry->d_inode) clear_nlink(dentry->d_inode); fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode); dir->i_nlink = lower_dir_dentry->d_inode->i_nlink; unlock_dir(lower_dir_dentry); if (!rc) d_drop(dentry); dput(dentry); return rc; }
/** * ecryptfs_do_create * @directory_inode: inode of the new file's dentry's parent in ecryptfs * @ecryptfs_dentry: New file's dentry in ecryptfs * @mode: The mode of the new file * @nd: nameidata of ecryptfs' parent's dentry & vfsmount * * Creates the underlying file and the eCryptfs inode which will link to * it. It will also update the eCryptfs directory inode to mimic the * stat of the lower directory inode. * * Returns the new eCryptfs inode on success; an ERR_PTR on error condition */ static struct inode * ecryptfs_do_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry, int mode) { int rc; struct dentry *lower_dentry; struct dentry *lower_dir_dentry; struct inode *inode; lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); lower_dir_dentry = lock_parent(lower_dentry); if (IS_ERR(lower_dir_dentry)) { ecryptfs_printk(KERN_ERR, "Error locking directory of " "dentry\n"); inode = ERR_CAST(lower_dir_dentry); goto out; } rc = ecryptfs_create_underlying_file(lower_dir_dentry->d_inode, ecryptfs_dentry, mode); if (rc) { printk(KERN_ERR "%s: Failure to create dentry in lower fs; " "rc = [%d]\n", __func__, rc); inode = ERR_PTR(rc); goto out_lock; } inode = __ecryptfs_get_inode(lower_dentry->d_inode, directory_inode->i_sb); if (IS_ERR(inode)) { vfs_unlink(lower_dir_dentry->d_inode, lower_dentry); goto out_lock; } fsstack_copy_attr_times(directory_inode, lower_dir_dentry->d_inode); fsstack_copy_inode_size(directory_inode, lower_dir_dentry->d_inode); out_lock: unlock_dir(lower_dir_dentry); out: return inode; }
static int ccfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) { struct dentry *lower_old_dentry; struct dentry *lower_new_dentry; struct dentry *lower_dir_dentry; u64 file_size_save; int rc; // TODO: Update cached link file_size_save = i_size_read(old_dentry->d_inode); lower_old_dentry = ccfs_get_nested_dentry(old_dentry); lower_new_dentry = ccfs_get_nested_dentry(new_dentry); dget(lower_old_dentry); dget(lower_new_dentry); mdbg(INFO3,"Link w/ lower_dentry->d_name.name = [%s] Link = [%s]", lower_old_dentry->d_name.name, lower_new_dentry->d_name.name); lower_dir_dentry = lock_parent(lower_new_dentry); rc = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode, lower_new_dentry); if (rc || !lower_new_dentry->d_inode) goto out_lock; rc = ccfs_interpose(lower_new_dentry, new_dentry, dir->i_sb, 0); if (rc) goto out_lock; fsstack_copy_attr_times(dir, lower_new_dentry->d_inode); fsstack_copy_inode_size(dir, lower_new_dentry->d_inode); set_nlink(old_dentry->d_inode, ccfs_get_nested_inode(old_dentry->d_inode)->i_nlink); //Fix for kernel 3.7.1 use function set_nlink by Jiri Rakosnik i_size_write(new_dentry->d_inode, file_size_save); out_lock: unlock_dir(lower_dir_dentry); dput(lower_new_dentry); dput(lower_old_dentry); d_drop(lower_old_dentry); d_drop(new_dentry); d_drop(old_dentry); return rc; }
/* * scfs_mkdir * * Parameters: * @*dir: inode of the dir to create * @*scfs_dentry: dentry of the dir to create * @mode: * * Return: * SCFS_SUCCESS if success, otherwise if error * * Description: * mkdir() for SCFS. */ static int scfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { struct dentry *lower_dir_dentry; struct dentry *lower_parent_dentry; int ret; lower_dir_dentry = scfs_lower_dentry(dentry); lower_parent_dentry = lock_parent(lower_dir_dentry); ret = vfs_mkdir(lower_parent_dentry->d_inode, lower_dir_dentry, mode); if (ret || !lower_dir_dentry->d_inode) { SCFS_PRINT_ERROR("dir %s vfs_mkdir failed, " "lower_dir %s lower_parent %s mode %x\n", dentry->d_name.name, lower_dir_dentry->d_name.name, lower_parent_dentry->d_name.name, mode); goto out; } ret = scfs_interpose(lower_dir_dentry, dentry, dir->i_sb); if (ret) { SCFS_PRINT_ERROR("dir %s interpose failed, " "lower_dir %s lower_parent %s mode %x\n", dentry->d_name.name, lower_dir_dentry->d_name.name, lower_parent_dentry->d_name.name, mode); vfs_rmdir(lower_parent_dentry->d_inode, lower_dir_dentry); goto out; } fsstack_copy_attr_times(dir, lower_parent_dentry->d_inode); fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); set_nlink(dir, lower_parent_dentry->d_inode->i_nlink); out: unlock_dir(lower_parent_dentry); if (!dentry->d_inode) d_drop(dentry); return ret; }
static int ecryptfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { int rc; struct dentry *lower_dentry; struct dentry *lower_dir_dentry; lower_dentry = ecryptfs_dentry_to_lower(dentry); lower_dir_dentry = lock_parent(lower_dentry); rc = vfs_mkdir(d_inode(lower_dir_dentry), lower_dentry, mode); if (rc || d_really_is_negative(lower_dentry)) goto out; rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb); if (rc) goto out; fsstack_copy_attr_times(dir, d_inode(lower_dir_dentry)); fsstack_copy_inode_size(dir, d_inode(lower_dir_dentry)); set_nlink(dir, d_inode(lower_dir_dentry)->i_nlink); out: unlock_dir(lower_dir_dentry); if (d_really_is_negative(dentry)) d_drop(dentry); return rc; }
static int scfs_do_unlink(struct inode *dir, struct dentry *dentry, struct inode *inode) { struct dentry *lower_dentry = scfs_lower_dentry(dentry); struct inode *lower_dir_inode = scfs_lower_inode(dir); struct dentry *lower_dir_dentry; int ret; dget(lower_dentry); lower_dir_dentry = lock_parent(lower_dentry); ret = vfs_unlink(lower_dir_inode, lower_dentry); if (ret) { SCFS_PRINT_ERROR("error in vfs_unlink, ret : %d\n", ret); goto out; } fsstack_copy_attr_times(dir, lower_dir_inode); set_nlink(inode, scfs_lower_inode(inode)->i_nlink); inode->i_ctime = dir->i_ctime; d_drop(dentry); out: unlock_dir(lower_dir_dentry); dput(lower_dentry); return ret; }
static ssize_t wrapfs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { int err = 0; struct file *lower_file; struct dentry *dentry = file->f_path.dentry; lower_file = wrapfs_lower_file(file); err = vfs_write(lower_file, buf, count, ppos); /* update our inode times+sizes upon a successful lower write */ if (err >= 0) { fsstack_copy_inode_size(dentry->d_inode, lower_file->f_path.dentry->d_inode); fsstack_copy_attr_times(dentry->d_inode, lower_file->f_path.dentry->d_inode); spin_lock(&dentry->d_inode->i_lock); wrapfs_set_write_dirty(dentry->d_inode,WRITE_DIRTY_BIT); spin_unlock(&dentry->d_inode->i_lock); } return err; }
static int ecryptfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) { int rc; struct dentry *lower_dentry; struct dentry *lower_dir_dentry; lower_dentry = ecryptfs_dentry_to_lower(dentry); lower_dir_dentry = lock_parent(lower_dentry); rc = vfs_mknod(lower_dir_dentry->d_inode, lower_dentry, mode, dev); if (rc || !lower_dentry->d_inode) goto out; rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb); if (rc) goto out; fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode); fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode); out: unlock_dir(lower_dir_dentry); if (!dentry->d_inode) d_drop(dentry); return rc; }
/** * ecryptfs_do_create * @directory_inode: inode of the new file's dentry's parent in ecryptfs * @ecryptfs_dentry: New file's dentry in ecryptfs * @mode: The mode of the new file * @nd: nameidata of ecryptfs' parent's dentry & vfsmount * * Creates the underlying file and the eCryptfs inode which will link to * it. It will also update the eCryptfs directory inode to mimic the * stat of the lower directory inode. * * Returns zero on success; non-zero on error condition */ static int ecryptfs_do_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry, int mode, struct nameidata *nd) { int rc; struct dentry *lower_dentry; struct dentry *lower_dir_dentry; lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); lower_dir_dentry = lock_parent(lower_dentry); if (IS_ERR(lower_dir_dentry)) { ecryptfs_printk(KERN_ERR, "Error locking directory of " "dentry\n"); rc = PTR_ERR(lower_dir_dentry); goto out; } rc = ecryptfs_create_underlying_file(lower_dir_dentry->d_inode, ecryptfs_dentry, mode, nd); if (rc) { printk(KERN_ERR "%s: Failure to create dentry in lower fs; " "rc = [%d]\n", __func__, rc); goto out_lock; } rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry, directory_inode->i_sb); if (rc) { ecryptfs_printk(KERN_ERR, "Failure in ecryptfs_interpose\n"); goto out_lock; } fsstack_copy_attr_times(directory_inode, lower_dir_dentry->d_inode); fsstack_copy_inode_size(directory_inode, lower_dir_dentry->d_inode); out_lock: unlock_dir(lower_dir_dentry); out: return rc; }
struct dentry *amfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { int err; struct dentry *ret, *parent; struct path lower_parent_path; parent = dget_parent(dentry); amfs_get_lower_path(parent, &lower_parent_path); /* allocate dentry private data. We free it in ->d_release */ err = new_dentry_private_data(dentry); // printk("\n lookup.c-> dentry *amfs_lookup"); //aditi if (err) { ret = ERR_PTR(err); goto out; } ret = __amfs_lookup(dentry, flags, &lower_parent_path); if (IS_ERR(ret)) goto out; if (ret) dentry = ret; if (dentry->d_inode) fsstack_copy_attr_times(dentry->d_inode, amfs_lower_inode(dentry->d_inode)); /* update parent directory's atime */ fsstack_copy_attr_atime(parent->d_inode, amfs_lower_inode(parent->d_inode)); out: amfs_put_lower_path(parent, &lower_parent_path); dput(parent); return ret; }
static int wrapfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) { struct dentry *lower_old_dentry; struct dentry *lower_new_dentry; struct dentry *lower_dir_dentry; u64 file_size_save; int err; struct path lower_old_path, lower_new_path; file_size_save = i_size_read(old_dentry->d_inode); 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_dir_dentry = lock_parent(lower_new_dentry); err = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode, lower_new_dentry, NULL); if (err || !lower_new_dentry->d_inode) goto out; err = wrapfs_interpose(new_dentry, dir->i_sb, &lower_new_path); if (err) goto out; fsstack_copy_attr_times(dir, lower_new_dentry->d_inode); fsstack_copy_inode_size(dir, lower_new_dentry->d_inode); set_nlink(old_dentry->d_inode, wrapfs_lower_inode(old_dentry->d_inode)->i_nlink); i_size_write(new_dentry->d_inode, file_size_save); out: unlock_dir(lower_dir_dentry); wrapfs_put_lower_path(old_dentry, &lower_old_path); wrapfs_put_lower_path(new_dentry, &lower_new_path); return err; }
static int diaryfs_symlink(struct inode *dir, struct dentry *dentry, const char * symname) { int err; struct dentry *lower_dentry; struct dentry *lower_parent_dentry = NULL; struct path lower_path; diaryfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_parent_dentry = lock_parent(lower_dentry); err = vfs_symlink(lower_parent_dentry->d_inode, lower_dentry, symname); if (err) goto out; err = diaryfs_interpose(dentry, dir->i_sb, &lower_path); if (err) goto out; fsstack_copy_attr_times(dir, diaryfs_lower_inode(dir)); fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); out: unlock_dir(lower_parent_dentry); diaryfs_put_lower_path(dentry, &lower_path); return err; }
static int wrapfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { int err = 0; struct dentry *lower_dentry; struct dentry *lower_parent_dentry = NULL; struct path lower_path, saved_path; wrapfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_parent_dentry = lock_parent(lower_dentry); err = mnt_want_write(lower_path.mnt); if (err) goto out_unlock; pathcpy(&saved_path, &nd->path); pathcpy(&nd->path, &lower_path); err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode, nd); pathcpy(&nd->path, &saved_path); if (err) goto out; err = wrapfs_interpose(dentry, dir->i_sb, &lower_path); if (err) goto out; fsstack_copy_attr_times(dir, wrapfs_lower_inode(dir)); fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); out: mnt_drop_write(lower_path.mnt); out_unlock: unlock_dir(lower_parent_dentry); wrapfs_put_lower_path(dentry, &lower_path); return err; }
static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) { struct dentry *lower_old_dentry; struct dentry *lower_new_dentry; struct dentry *lower_dir_dentry; u64 file_size_save; int rc; file_size_save = i_size_read(old_dentry->d_inode); 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_dir_dentry = lock_parent(lower_new_dentry); rc = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode, lower_new_dentry); if (rc || !lower_new_dentry->d_inode) goto out_lock; rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb, 0); if (rc) goto out_lock; fsstack_copy_attr_times(dir, lower_new_dentry->d_inode); fsstack_copy_inode_size(dir, lower_new_dentry->d_inode); old_dentry->d_inode->i_nlink = ecryptfs_inode_to_lower(old_dentry->d_inode)->i_nlink; i_size_write(new_dentry->d_inode, file_size_save); out_lock: unlock_dir(lower_dir_dentry); dput(lower_new_dentry); dput(lower_old_dentry); d_drop(lower_old_dentry); d_drop(new_dentry); d_drop(old_dentry); return rc; }
static int unionfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) { int err = 0; struct dentry *lower_old_dentry = NULL; struct dentry *lower_new_dentry = NULL; struct dentry *lower_dir_dentry = NULL; struct dentry *old_parent, *new_parent; char *name = NULL; bool valid; unionfs_read_lock(old_dentry->d_sb, UNIONFS_SMUTEX_CHILD); old_parent = dget_parent(old_dentry); new_parent = dget_parent(new_dentry); unionfs_double_lock_parents(old_parent, new_parent); unionfs_double_lock_dentry(old_dentry, new_dentry); valid = __unionfs_d_revalidate(old_dentry, old_parent, false, 0); if (unlikely(!valid)) { err = -ESTALE; goto out; } if (new_dentry->d_inode) { valid = __unionfs_d_revalidate(new_dentry, new_parent, false, 0); if (unlikely(!valid)) { err = -ESTALE; goto out; } } lower_new_dentry = unionfs_lower_dentry(new_dentry); /* check for a whiteout in new dentry branch, and delete it */ err = check_unlink_whiteout(new_dentry, lower_new_dentry, dbstart(new_dentry)); if (err > 0) { /* whiteout found and removed successfully */ lower_dir_dentry = dget_parent(lower_new_dentry); fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode); dput(lower_dir_dentry); set_nlink(dir, unionfs_get_nlinks(dir)); err = 0; } if (err) goto out; /* check if parent hierachy is needed, then link in same branch */ if (dbstart(old_dentry) != dbstart(new_dentry)) { lower_new_dentry = create_parents(dir, new_dentry, new_dentry->d_name.name, dbstart(old_dentry)); err = PTR_ERR(lower_new_dentry); if (IS_COPYUP_ERR(err)) goto docopyup; if (!lower_new_dentry || IS_ERR(lower_new_dentry)) goto out; } lower_new_dentry = unionfs_lower_dentry(new_dentry); lower_old_dentry = unionfs_lower_dentry(old_dentry); BUG_ON(dbstart(old_dentry) != dbstart(new_dentry)); lower_dir_dentry = lock_parent(lower_new_dentry); err = is_robranch(old_dentry); if (!err) { /* see Documentation/filesystems/unionfs/issues.txt */ lockdep_off(); err = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode, lower_new_dentry); lockdep_on(); } unlock_dir(lower_dir_dentry); docopyup: if (IS_COPYUP_ERR(err)) { int old_bstart = dbstart(old_dentry); int bindex; for (bindex = old_bstart - 1; bindex >= 0; bindex--) { err = copyup_dentry(old_parent->d_inode, old_dentry, old_bstart, bindex, old_dentry->d_name.name, old_dentry->d_name.len, NULL, i_size_read(old_dentry->d_inode)); if (err) continue; lower_new_dentry = create_parents(dir, new_dentry, new_dentry->d_name.name, bindex); lower_old_dentry = unionfs_lower_dentry(old_dentry); lower_dir_dentry = lock_parent(lower_new_dentry); /* see Documentation/filesystems/unionfs/issues.txt */ lockdep_off(); /* do vfs_link */ err = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode, lower_new_dentry); lockdep_on(); unlock_dir(lower_dir_dentry); goto check_link; } goto out; } check_link: if (err || !lower_new_dentry->d_inode) goto out; /* Its a hard link, so use the same inode */ new_dentry->d_inode = igrab(old_dentry->d_inode); d_add(new_dentry, new_dentry->d_inode); unionfs_copy_attr_all(dir, lower_new_dentry->d_parent->d_inode); fsstack_copy_inode_size(dir, lower_new_dentry->d_parent->d_inode); /* propagate number of hard-links */ set_nlink(old_dentry->d_inode, unionfs_get_nlinks(old_dentry->d_inode)); /* new dentry's ctime may have changed due to hard-link counts */ unionfs_copy_attr_times(new_dentry->d_inode); out: if (!new_dentry->d_inode) d_drop(new_dentry); kfree(name); if (!err) unionfs_postcopyup_setmnt(new_dentry); unionfs_check_inode(dir); unionfs_check_dentry(new_dentry); unionfs_check_dentry(old_dentry); unionfs_double_unlock_dentry(old_dentry, new_dentry); unionfs_double_unlock_parents(old_parent, new_parent); dput(new_parent); dput(old_parent); unionfs_read_unlock(old_dentry->d_sb); return err; }
static int u2fs_unlink(struct inode *dir, struct dentry *dentry) { int err=0; struct dentry *lower_dentry = NULL; struct inode *lower_dir_inode; struct inode *lower_inode; struct dentry *lower_dir_dentry = NULL; struct path lower_path; /* creating whiteout if file unlinked from read-only branch */ if((U2FS_D(dentry)->lower_path[LEFT].dentry) == NULL && (U2FS_D(dentry)->lower_path[LEFT].mnt) == NULL){ err = create_whiteout(dentry); if(err) err = -EIO; goto out_whiteout; } else{ u2fs_get_lower_path(dentry, &lower_path, LEFT); lower_dir_inode = u2fs_lower_inode(dir, LEFT); lower_inode = u2fs_lower_inode(dentry->d_inode, LEFT); } lower_dentry = lower_path.dentry; dget(lower_dentry); lower_dir_dentry = lock_parent(lower_dentry); err = mnt_want_write(lower_path.mnt); if (err) goto out_unlock; err = vfs_unlink(lower_dir_inode, lower_dentry); /* * Note: unlinking on top of NFS can cause silly-renamed files. * Trying to delete such files results in EBUSY from NFS * below. Silly-renamed files will get deleted by NFS later on, so * we just need to detect them here and treat such EBUSY errors as * if the upper file was successfully deleted. */ if (err == -EBUSY && lower_dentry->d_flags & DCACHE_NFSFS_RENAMED) err = 0; if (err) goto out; fsstack_copy_attr_times(dir, lower_dir_inode); fsstack_copy_inode_size(dir, lower_dir_inode); set_nlink(dentry->d_inode, lower_inode->i_nlink); dentry->d_inode->i_ctime = dir->i_ctime; out: mnt_drop_write(lower_path.mnt); out_unlock: unlock_dir(lower_dir_dentry); dput(lower_dentry); u2fs_put_lower_path(dentry, &lower_path); /* checking for same file in right branch */ if((U2FS_D(dentry)->lower_path[RIGHT].dentry) != NULL && (U2FS_D(dentry)->lower_path[RIGHT].mnt) != NULL){ err = create_whiteout(dentry); if(err) err = -EIO; } d_drop(dentry); out_whiteout: return err; }
static int u2fs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) { int err = 0; struct dentry *lower_dentry = NULL; struct dentry *lower_parent_dentry = NULL; struct dentry *parent= NULL; struct dentry *ret=NULL; struct path lower_path, saved_path; const char *name; unsigned int namelen; struct dentry *right_parent_dentry = NULL; struct dentry *right_lower_dentry = NULL; /* creating parent directories if destination is read-only */ if((U2FS_D(dentry)->lower_path[LEFT].dentry) == NULL && (U2FS_D(dentry)->lower_path[LEFT].mnt) == NULL){ parent = dget_parent(dentry); right_parent_dentry = U2FS_D(parent)->lower_path[RIGHT].dentry; ret = create_parents(parent->d_inode, dentry, dentry->d_name.name); if (!ret || IS_ERR(ret)) { err = PTR_ERR(ret); if (!IS_COPYUP_ERR(err)) printk(KERN_ERR "u2fs: create_parents for " "u2fs_create failed" "err=%d\n", err); goto out_copyup; } u2fs_postcopyup_setmnt(dentry); u2fs_put_reset_lower_path(dentry, RIGHT); } u2fs_get_lower_path(dentry, &lower_path, LEFT); lower_dentry = lower_path.dentry; lower_parent_dentry = lock_parent(lower_dentry); err = mnt_want_write(lower_path.mnt); if (err) goto out_unlock; pathcpy(&saved_path, &nd->path); pathcpy(&nd->path, &lower_path); err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode, nd); pathcpy(&nd->path, &saved_path); if (err) goto out; /* looking if the file already exists in right_dir to link inode */ if((U2FS_D(dentry)->lower_path[RIGHT].dentry) != NULL && (U2FS_D(dentry)->lower_path[RIGHT].mnt) != NULL){ name = dentry->d_name.name; namelen = dentry->d_name.len; right_lower_dentry = lookup_one_len(name, lower_parent_dentry, namelen); dentry->d_inode = right_lower_dentry->d_inode; u2fs_set_lower_inode(dentry->d_inode, lower_dentry->d_inode, LEFT); } else err = u2fs_interpose(dentry, dir->i_sb, &lower_path, LEFT); if (err) goto out; fsstack_copy_attr_times(dir, u2fs_lower_inode(dir, LEFT)); fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); out: mnt_drop_write(lower_path.mnt); out_unlock: unlock_dir(lower_parent_dentry); u2fs_put_lower_path(dentry, &lower_path); out_copyup: if(parent != NULL) dput(parent); return err; }
static int u2fs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) { struct dentry *lower_old_dentry; struct dentry *lower_new_dentry; struct dentry *lower_dir_dentry; u64 file_size_save; int err=0; int idx; struct dentry *ret = NULL; struct path lower_old_path, lower_new_path; file_size_save = i_size_read(old_dentry->d_inode); if((U2FS_D(old_dentry)->lower_path[LEFT].dentry != NULL) && (U2FS_D(old_dentry)->lower_path[LEFT].mnt != NULL)){ u2fs_get_lower_path(old_dentry, &lower_old_path, LEFT); idx = LEFT; } else{ u2fs_get_lower_path(old_dentry, &lower_old_path, RIGHT); idx = RIGHT; } /* creating parent directories if destination is read-only */ if((U2FS_D(new_dentry)->lower_path[LEFT].dentry) == NULL && (U2FS_D(new_dentry)->lower_path[LEFT].mnt) == NULL){ ret = create_parents(dir, new_dentry, new_dentry->d_name.name); if (!ret || IS_ERR(ret)) { err = PTR_ERR(ret); if (!IS_COPYUP_ERR(err)) printk(KERN_ERR "u2fs: create_parents for " "u2fs_link failed" "err=%d\n", err); goto out_copyup; } u2fs_postcopyup_setmnt(new_dentry); u2fs_put_reset_lower_path(new_dentry, RIGHT); if(err) goto out_copyup; } u2fs_get_lower_path(new_dentry, &lower_new_path, LEFT); lower_old_dentry = lower_old_path.dentry; lower_new_dentry = lower_new_path.dentry; lower_dir_dentry = lock_parent(lower_new_dentry); err = mnt_want_write(lower_new_path.mnt); if (err) goto out_unlock; err = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode, lower_new_dentry); if (err || !lower_new_dentry->d_inode) goto out; err = u2fs_interpose(new_dentry, dir->i_sb, &lower_new_path, LEFT); if (err) goto out; fsstack_copy_attr_times(dir, lower_new_dentry->d_inode); fsstack_copy_inode_size(dir, lower_new_dentry->d_inode); set_nlink(old_dentry->d_inode, u2fs_lower_inode(old_dentry->d_inode, idx)->i_nlink); i_size_write(new_dentry->d_inode, file_size_save); out: mnt_drop_write(lower_new_path.mnt); out_unlock: unlock_dir(lower_dir_dentry); u2fs_put_lower_path(new_dentry, &lower_new_path); out_copyup: u2fs_put_lower_path(old_dentry, &lower_old_path); return err; }
static int amfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) { struct dentry *lower_old_dentry; struct dentry *lower_new_dentry; struct dentry *lower_dir_dentry; u64 file_size_save; int err; struct path lower_old_path, lower_new_path; char *value = NULL; if (old_dentry->d_inode->i_ino == AMFS_SB(old_dentry->d_sb)->inode_no) { err = -EPERM; goto out_err; } /************XATTR************/ value = kzalloc(5, __GFP_WAIT); if (value == NULL) { err = -ENOMEM; goto out_err; } if (amfs_getxattr(old_dentry, AMFS_XATTR_NAME, value, 5) > 0) { if (!strncmp(value, AMFS_BADFILE, 3)) { err = -EPERM; goto freevalue; } } else if (amfs_getxattr(old_dentry, AMFS_XATTR_NAME, value, 5) != -ENODATA){ err = amfs_getxattr(old_dentry, AMFS_XATTR_NAME, value, 5); goto freevalue; } /************XATTR***********/ file_size_save = i_size_read(old_dentry->d_inode); amfs_get_lower_path(old_dentry, &lower_old_path); amfs_get_lower_path(new_dentry, &lower_new_path); lower_old_dentry = lower_old_path.dentry; lower_new_dentry = lower_new_path.dentry; lower_dir_dentry = lock_parent(lower_new_dentry); err = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode, lower_new_dentry, NULL); if (err || !lower_new_dentry->d_inode) goto out; err = amfs_interpose(new_dentry, dir->i_sb, &lower_new_path); if (err) goto out; fsstack_copy_attr_times(dir, lower_new_dentry->d_inode); fsstack_copy_inode_size(dir, lower_new_dentry->d_inode); set_nlink(old_dentry->d_inode, amfs_lower_inode(old_dentry->d_inode)->i_nlink); i_size_write(new_dentry->d_inode, file_size_save); out: unlock_dir(lower_dir_dentry); amfs_put_lower_path(old_dentry, &lower_old_path); amfs_put_lower_path(new_dentry, &lower_new_path); freevalue: kfree(value); out_err: return err; }
static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { int err = 0; int make_nomedia_in_obb = 0; struct dentry *lower_dentry; struct dentry *lower_parent_dentry = NULL; struct path lower_path; struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); const struct cred *saved_cred = NULL; struct sdcardfs_inode_info *pi = SDCARDFS_I(dir); char *page_buf; char *nomedia_dir_name; char *nomedia_fullpath; int fullpath_namelen; int touch_err = 0; char *(*d_absolute_path_new)(const struct path *, char *, int) = (void *)kallsyms_lookup_name("d_absolute_path"); 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)) { err = -EACCES; goto out_eacces; } /* save current_cred and override it */ OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred); /* check disk space */ if (!check_min_free_space(dentry, 0, 1)) { printk(KERN_INFO "sdcardfs: No minimum free space.\n"); err = -ENOSPC; goto out_revert; } /* the lower_dentry is negative here */ sdcardfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; lower_parent_dentry = lock_parent(lower_dentry); err = mnt_want_write(lower_path.mnt); if (err) goto out_unlock; /* set last 16bytes of mode field to 0775 */ mode = (mode & S_IFMT) | 00775; err = vfs_mkdir(lower_parent_dentry->d_inode, lower_dentry, mode); if (err) goto out; /* if it is a local obb dentry, setup it with the base obbpath */ if(need_graft_path(dentry)) { err = setup_obb_dentry(dentry, &lower_path); if(err) { /* if the sbi->obbpath is not available, the lower_path won't be * changed by setup_obb_dentry() but the lower path is saved to * its orig_path. this dentry will be revalidated later. * but now, the lower_path should be NULL */ sdcardfs_put_reset_lower_path(dentry); /* the newly created lower path which saved to its orig_path or * the lower_path is the base obbpath. * therefore, an additional path_get is required */ path_get(&lower_path); } else make_nomedia_in_obb = 1; } err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path); if (err) goto out; fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir)); fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode); /* update number of links on parent directory */ set_nlink(dir, sdcardfs_lower_inode(dir)->i_nlink); if ((sbi->options.derive == DERIVE_UNIFIED) && (!strcasecmp(dentry->d_name.name, "obb")) && (pi->perm == PERM_ANDROID) && (pi->userid == 0)) make_nomedia_in_obb = 1; /* When creating /Android/data and /Android/obb, mark them as .nomedia */ if (make_nomedia_in_obb || ((pi->perm == PERM_ANDROID) && (!strcasecmp(dentry->d_name.name, "data")))) { page_buf = (char *)__get_free_page(GFP_KERNEL); if (!page_buf) { printk(KERN_ERR "sdcardfs: failed to allocate page buf\n"); goto out; } nomedia_dir_name = d_absolute_path_new(&lower_path, page_buf, PAGE_SIZE); if (IS_ERR(nomedia_dir_name)) { free_page((unsigned long)page_buf); printk(KERN_ERR "sdcardfs: failed to get .nomedia dir name\n"); goto out; } fullpath_namelen = page_buf + PAGE_SIZE - nomedia_dir_name - 1; fullpath_namelen += strlen("/.nomedia"); nomedia_fullpath = kzalloc(fullpath_namelen + 1, GFP_KERNEL); if (!nomedia_fullpath) { free_page((unsigned long)page_buf); printk(KERN_ERR "sdcardfs: failed to allocate .nomedia fullpath buf\n"); goto out; } strcpy(nomedia_fullpath, nomedia_dir_name); free_page((unsigned long)page_buf); strcat(nomedia_fullpath, "/.nomedia"); touch_err = touch(nomedia_fullpath, 0664); if (touch_err) { printk(KERN_ERR "sdcardfs: failed to touch(%s): %d\n", nomedia_fullpath, touch_err); kfree(nomedia_fullpath); goto out; } kfree(nomedia_fullpath); } out: mnt_drop_write(lower_path.mnt); out_unlock: unlock_dir(lower_parent_dentry); sdcardfs_put_lower_path(dentry, &lower_path); out_revert: REVERT_CRED(saved_cred); out_eacces: return err; }
/* * This function replicates the directory structure up-to given dentry * in the bindex branch. */ struct dentry *create_parents(struct inode *dir, struct dentry *dentry, const char *name, int bindex) { int err; struct dentry *child_dentry; struct dentry *parent_dentry; struct dentry *lower_parent_dentry = NULL; struct dentry *lower_dentry = NULL; const char *childname; unsigned int childnamelen; int nr_dentry; int count = 0; int old_bstart; int old_bend; struct dentry **path = NULL; struct super_block *sb; verify_locked(dentry); err = is_robranch_super(dir->i_sb, bindex); if (err) { lower_dentry = ERR_PTR(err); goto out; } old_bstart = dbstart(dentry); old_bend = dbend(dentry); lower_dentry = ERR_PTR(-ENOMEM); /* There is no sense allocating any less than the minimum. */ nr_dentry = 1; path = kmalloc(nr_dentry * sizeof(struct dentry *), GFP_KERNEL); if (unlikely(!path)) goto out; /* assume the negative dentry of unionfs as the parent dentry */ parent_dentry = dentry; /* * This loop finds the first parent that exists in the given branch. * We start building the directory structure from there. At the end * of the loop, the following should hold: * - child_dentry is the first nonexistent child * - parent_dentry is the first existent parent * - path[0] is the = deepest child * - path[count] is the first child to create */ do { child_dentry = parent_dentry; /* find the parent directory dentry in unionfs */ parent_dentry = dget_parent(child_dentry); /* find out the lower_parent_dentry in the given branch */ lower_parent_dentry = unionfs_lower_dentry_idx(parent_dentry, bindex); /* grow path table */ if (count == nr_dentry) { void *p; nr_dentry *= 2; p = krealloc(path, nr_dentry * sizeof(struct dentry *), GFP_KERNEL); if (unlikely(!p)) { lower_dentry = ERR_PTR(-ENOMEM); goto out; } path = p; } /* store the child dentry */ path[count++] = child_dentry; } while (!lower_parent_dentry); count--; sb = dentry->d_sb; /* * This code goes between the begin/end labels and basically * emulates a while(child_dentry != dentry), only cleaner and * shorter than what would be a much longer while loop. */ begin: /* get lower parent dir in the current branch */ lower_parent_dentry = unionfs_lower_dentry_idx(parent_dentry, bindex); dput(parent_dentry); /* init the values to lookup */ childname = child_dentry->d_name.name; childnamelen = child_dentry->d_name.len; if (child_dentry != dentry) { /* lookup child in the underlying file system */ lower_dentry = lookup_one_len(childname, lower_parent_dentry, childnamelen); if (IS_ERR(lower_dentry)) goto out; } else { /* * Is the name a whiteout of the child name ? lookup the * whiteout child in the underlying file system */ lower_dentry = lookup_one_len(name, lower_parent_dentry, strlen(name)); if (IS_ERR(lower_dentry)) goto out; /* Replace the current dentry (if any) with the new one */ dput(unionfs_lower_dentry_idx(dentry, bindex)); unionfs_set_lower_dentry_idx(dentry, bindex, lower_dentry); __cleanup_dentry(dentry, bindex, old_bstart, old_bend); goto out; } if (lower_dentry->d_inode) { /* * since this already exists we dput to avoid * multiple references on the same dentry */ dput(lower_dentry); } else { struct sioq_args args; /* it's a negative dentry, create a new dir */ lower_parent_dentry = lock_parent(lower_dentry); args.mkdir.parent = lower_parent_dentry->d_inode; args.mkdir.dentry = lower_dentry; args.mkdir.mode = child_dentry->d_inode->i_mode; run_sioq(__unionfs_mkdir, &args); err = args.err; if (!err) err = copyup_permissions(dir->i_sb, child_dentry, lower_dentry); unlock_dir(lower_parent_dentry); if (err) { dput(lower_dentry); lower_dentry = ERR_PTR(err); goto out; } } __set_inode(child_dentry, lower_dentry, bindex); __set_dentry(child_dentry, lower_dentry, bindex); /* * update times of this dentry, but also the parent, because if * we changed, the parent may have changed too. */ fsstack_copy_attr_times(parent_dentry->d_inode, lower_parent_dentry->d_inode); unionfs_copy_attr_times(child_dentry->d_inode); parent_dentry = child_dentry; child_dentry = path[--count]; goto begin; out: /* cleanup any leftover locks from the do/while loop above */ if (IS_ERR(lower_dentry)) while (count) dput(path[count--]); kfree(path); return lower_dentry; }