diff options
Diffstat (limited to 'fs/ecryptfs/inode.c')
| -rw-r--r-- | fs/ecryptfs/inode.c | 109 | 
1 files changed, 53 insertions, 56 deletions
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index a07441a0a87..cc7709e7c50 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -143,6 +143,31 @@ static int ecryptfs_interpose(struct dentry *lower_dentry,  	return 0;  } +static int ecryptfs_do_unlink(struct inode *dir, struct dentry *dentry, +			      struct inode *inode) +{ +	struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); +	struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir); +	struct dentry *lower_dir_dentry; +	int rc; + +	dget(lower_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); +	set_nlink(inode, ecryptfs_inode_to_lower(inode)->i_nlink); +	inode->i_ctime = dir->i_ctime; +	d_drop(dentry); +out_unlock: +	unlock_dir(lower_dir_dentry); +	dput(lower_dentry); +	return rc; +} +  /**   * ecryptfs_do_create   * @directory_inode: inode of the new file's dentry's parent in ecryptfs @@ -173,7 +198,7 @@ ecryptfs_do_create(struct inode *directory_inode,  		inode = ERR_CAST(lower_dir_dentry);  		goto out;  	} -	rc = vfs_create(lower_dir_dentry->d_inode, lower_dentry, mode, NULL); +	rc = vfs_create(lower_dir_dentry->d_inode, lower_dentry, mode, true);  	if (rc) {  		printk(KERN_ERR "%s: Failure to create dentry in lower fs; "  		       "rc = [%d]\n", __func__, rc); @@ -182,8 +207,10 @@ ecryptfs_do_create(struct inode *directory_inode,  	}  	inode = __ecryptfs_get_inode(lower_dentry->d_inode,  				     directory_inode->i_sb); -	if (IS_ERR(inode)) +	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: @@ -200,8 +227,8 @@ out:   *   * Returns zero on success   */ -static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry, -				    struct inode *ecryptfs_inode) +int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry, +			     struct inode *ecryptfs_inode)  {  	struct ecryptfs_crypt_stat *crypt_stat =  		&ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat; @@ -240,7 +267,6 @@ out:   * @dir: The inode of the directory in which to create the file.   * @dentry: The eCryptfs dentry   * @mode: The mode of the new file. - * @nd: nameidata   *   * Creates a new file.   * @@ -248,7 +274,7 @@ out:   */  static int  ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry, -		umode_t mode, struct nameidata *nd) +		umode_t mode, bool excl)  {  	struct inode *ecryptfs_inode;  	int rc; @@ -265,13 +291,15 @@ ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry,  	 * that this on disk file is prepared to be an ecryptfs file */  	rc = ecryptfs_initialize_file(ecryptfs_dentry, ecryptfs_inode);  	if (rc) { -		drop_nlink(ecryptfs_inode); +		ecryptfs_do_unlink(directory_inode, ecryptfs_dentry, +				   ecryptfs_inode); +		make_bad_inode(ecryptfs_inode);  		unlock_new_inode(ecryptfs_inode);  		iput(ecryptfs_inode);  		goto out;  	} -	d_instantiate(ecryptfs_dentry, ecryptfs_inode);  	unlock_new_inode(ecryptfs_inode); +	d_instantiate(ecryptfs_dentry, ecryptfs_inode);  out:  	return rc;  } @@ -319,21 +347,20 @@ static int ecryptfs_lookup_interpose(struct dentry *dentry,  	struct vfsmount *lower_mnt;  	int rc = 0; -	lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(dentry->d_parent)); -	fsstack_copy_attr_atime(dir_inode, lower_dentry->d_parent->d_inode); -	BUG_ON(!lower_dentry->d_count); -  	dentry_info = kmem_cache_alloc(ecryptfs_dentry_info_cache, GFP_KERNEL); -	ecryptfs_set_dentry_private(dentry, dentry_info);  	if (!dentry_info) {  		printk(KERN_ERR "%s: Out of memory whilst attempting "  		       "to allocate ecryptfs_dentry_info struct\n",  			__func__);  		dput(lower_dentry); -		mntput(lower_mnt); -		d_drop(dentry);  		return -ENOMEM;  	} + +	lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(dentry->d_parent)); +	fsstack_copy_attr_atime(dir_inode, lower_dentry->d_parent->d_inode); +	BUG_ON(!lower_dentry->d_count); + +	ecryptfs_set_dentry_private(dentry, dentry_info);  	ecryptfs_set_dentry_lower(dentry, lower_dentry);  	ecryptfs_set_dentry_lower_mnt(dentry, lower_mnt); @@ -374,7 +401,7 @@ static int ecryptfs_lookup_interpose(struct dentry *dentry,   */  static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,  				      struct dentry *ecryptfs_dentry, -				      struct nameidata *ecryptfs_nd) +				      unsigned int flags)  {  	char *encrypted_and_encoded_name = NULL;  	size_t encrypted_and_encoded_name_size; @@ -382,12 +409,6 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,  	struct dentry *lower_dir_dentry, *lower_dentry;  	int rc = 0; -	if ((ecryptfs_dentry->d_name.len == 1 -	     && !strcmp(ecryptfs_dentry->d_name.name, ".")) -	    || (ecryptfs_dentry->d_name.len == 2 -		&& !strcmp(ecryptfs_dentry->d_name.name, ".."))) { -		goto out_d_drop; -	}  	lower_dir_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry->d_parent);  	mutex_lock(&lower_dir_dentry->d_inode->i_mutex);  	lower_dentry = lookup_one_len(ecryptfs_dentry->d_name.name, @@ -398,8 +419,8 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,  		rc = PTR_ERR(lower_dentry);  		ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned "  				"[%d] on lower_dentry = [%s]\n", __func__, rc, -				encrypted_and_encoded_name); -		goto out_d_drop; +				ecryptfs_dentry->d_name.name); +		goto out;  	}  	if (lower_dentry->d_inode)  		goto interpose; @@ -416,7 +437,7 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,  	if (rc) {  		printk(KERN_ERR "%s: Error attempting to encrypt and encode "  		       "filename; rc = [%d]\n", __func__, rc); -		goto out_d_drop; +		goto out;  	}  	mutex_lock(&lower_dir_dentry->d_inode->i_mutex);  	lower_dentry = lookup_one_len(encrypted_and_encoded_name, @@ -428,14 +449,11 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,  		ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned "  				"[%d] on lower_dentry = [%s]\n", __func__, rc,  				encrypted_and_encoded_name); -		goto out_d_drop; +		goto out;  	}  interpose:  	rc = ecryptfs_lookup_interpose(ecryptfs_dentry, lower_dentry,  				       ecryptfs_dir_inode); -	goto out; -out_d_drop: -	d_drop(ecryptfs_dentry);  out:  	kfree(encrypted_and_encoded_name);  	return ERR_PTR(rc); @@ -477,27 +495,7 @@ out_lock:  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; - -	dget(lower_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); -	set_nlink(dentry->d_inode, -		  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); -	dput(lower_dentry); -	return rc; +	return ecryptfs_do_unlink(dir, dentry, dentry->d_inode);  }  static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry, @@ -621,6 +619,7 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,  	struct dentry *lower_old_dir_dentry;  	struct dentry *lower_new_dir_dentry;  	struct dentry *trap = NULL; +	struct inode *target_inode;  	lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);  	lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry); @@ -628,6 +627,7 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *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) { @@ -643,6 +643,9 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *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); @@ -972,12 +975,6 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)  			goto out;  	} -	if (S_ISREG(inode->i_mode)) { -		rc = filemap_write_and_wait(inode->i_mapping); -		if (rc) -			goto out; -		fsstack_copy_attr_all(inode, lower_inode); -	}  	memcpy(&lower_ia, ia, sizeof(lower_ia));  	if (ia->ia_valid & ATTR_FILE)  		lower_ia.ia_file = ecryptfs_file_to_lower(ia->ia_file);  |