/**
* ecryptfs_create_underlying_file
* @lower_dir_inode: inode of the parent in the lower fs of the new file
- * @lower_dentry: New file's dentry in the lower fs
- * @ecryptfs_dentry: New file's dentry in ecryptfs
+ * @dentry: New file's dentry
* @mode: The mode of the new file
* @nd: nameidata of ecryptfs' parent's dentry & vfsmount
*
*/
int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
struct dentry *lower_dentry,
- struct ecryptfs_crypt_stat *crypt_stat,
struct inode *ecryptfs_dir_inode,
struct nameidata *ecryptfs_nd)
{
struct vfsmount *lower_mnt;
struct inode *lower_inode;
struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
+ struct ecryptfs_crypt_stat *crypt_stat;
char *page_virt = NULL;
u64 file_size;
int rc = 0;
goto out_free_kmem;
}
}
+ crypt_stat = &ecryptfs_inode_to_private(
+ ecryptfs_dentry->d_inode)->crypt_stat;
+ /* TODO: lock for crypt_stat comparison */
+ if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED))
+ ecryptfs_set_default_sizes(crypt_stat);
rc = ecryptfs_read_and_validate_header_region(page_virt,
ecryptfs_dentry->d_inode);
if (rc) {
struct nameidata *ecryptfs_nd)
{
char *encrypted_and_encoded_name = NULL;
- int encrypted_and_encoded_name_size;
- struct ecryptfs_crypt_stat *crypt_stat = NULL;
+ size_t encrypted_and_encoded_name_size;
struct ecryptfs_mount_crypt_stat *mount_crypt_stat = NULL;
- struct ecryptfs_inode_info *inode_info;
struct dentry *lower_dir_dentry, *lower_dentry;
int rc = 0;
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,
lower_dir_dentry,
ecryptfs_dentry->d_name.len);
+ mutex_unlock(&lower_dir_dentry->d_inode->i_mutex);
if (IS_ERR(lower_dentry)) {
rc = PTR_ERR(lower_dentry);
printk(KERN_ERR "%s: lookup_one_len() returned [%d] on "
}
if (lower_dentry->d_inode)
goto lookup_and_interpose;
- inode_info = ecryptfs_inode_to_private(ecryptfs_dentry->d_inode);
- if (inode_info) {
- crypt_stat = &inode_info->crypt_stat;
- /* TODO: lock for crypt_stat comparison */
- if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED))
- ecryptfs_set_default_sizes(crypt_stat);
- }
- if (crypt_stat)
- mount_crypt_stat = crypt_stat->mount_crypt_stat;
- else
- mount_crypt_stat = &ecryptfs_superblock_to_private(
- ecryptfs_dentry->d_sb)->mount_crypt_stat;
- if (!(crypt_stat && (crypt_stat->flags & ECRYPTFS_ENCRYPT_FILENAMES))
- && !(mount_crypt_stat && (mount_crypt_stat->flags
- & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)))
+ mount_crypt_stat = &ecryptfs_superblock_to_private(
+ ecryptfs_dentry->d_sb)->mount_crypt_stat;
+ if (!(mount_crypt_stat
+ && (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)))
goto lookup_and_interpose;
dput(lower_dentry);
rc = ecryptfs_encrypt_and_encode_filename(
&encrypted_and_encoded_name, &encrypted_and_encoded_name_size,
- crypt_stat, mount_crypt_stat, ecryptfs_dentry->d_name.name,
+ NULL, mount_crypt_stat, ecryptfs_dentry->d_name.name,
ecryptfs_dentry->d_name.len);
if (rc) {
printk(KERN_ERR "%s: Error attempting to encrypt and encode "
"filename; rc = [%d]\n", __func__, rc);
goto out_d_drop;
}
+ mutex_lock(&lower_dir_dentry->d_inode->i_mutex);
lower_dentry = lookup_one_len(encrypted_and_encoded_name,
lower_dir_dentry,
encrypted_and_encoded_name_size - 1);
+ mutex_unlock(&lower_dir_dentry->d_inode->i_mutex);
if (IS_ERR(lower_dentry)) {
rc = PTR_ERR(lower_dentry);
printk(KERN_ERR "%s: lookup_one_len() returned [%d] on "
}
lookup_and_interpose:
rc = ecryptfs_lookup_and_interpose_lower(ecryptfs_dentry, lower_dentry,
- crypt_stat, ecryptfs_dir_inode,
+ ecryptfs_dir_inode,
ecryptfs_nd);
goto out;
out_d_drop:
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) {
d_drop(dentry);
out_unlock:
unlock_dir(lower_dir_dentry);
+ dput(lower_dentry);
return rc;
}
ecryptfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
{
char *lower_buf;
+ size_t lower_bufsiz;
struct dentry *lower_dentry;
- struct ecryptfs_crypt_stat *crypt_stat;
+ struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
char *plaintext_name;
size_t plaintext_name_size;
mm_segment_t old_fs;
rc = -EINVAL;
goto out;
}
- crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;
+ mount_crypt_stat = &ecryptfs_superblock_to_private(
+ dentry->d_sb)->mount_crypt_stat;
+ /*
+ * If the lower filename is encrypted, it will result in a significantly
+ * longer name. If needed, truncate the name after decode and decrypt.
+ */
+ if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)
+ lower_bufsiz = PATH_MAX;
+ else
+ lower_bufsiz = bufsiz;
/* Released in this function */
- lower_buf = kmalloc(bufsiz, GFP_KERNEL);
+ lower_buf = kmalloc(lower_bufsiz, GFP_KERNEL);
if (lower_buf == NULL) {
printk(KERN_ERR "%s: Out of memory whilst attempting to "
- "kmalloc [%d] bytes\n", __func__, bufsiz);
+ "kmalloc [%zd] bytes\n", __func__, lower_bufsiz);
rc = -ENOMEM;
goto out;
}
set_fs(get_ds());
rc = lower_dentry->d_inode->i_op->readlink(lower_dentry,
(char __user *)lower_buf,
- bufsiz);
+ lower_bufsiz);
set_fs(old_fs);
if (rc >= 0) {
rc = ecryptfs_decode_and_decrypt_filename(&plaintext_name,
rc);
goto out_free_lower_buf;
}
- rc = copy_to_user(buf, plaintext_name, plaintext_name_size);
+ /* Check for bufsiz <= 0 done in sys_readlinkat() */
+ rc = copy_to_user(buf, plaintext_name,
+ min((size_t) bufsiz, plaintext_name_size));
if (rc)
rc = -EFAULT;
else
size_t num_zeros = (PAGE_CACHE_SIZE
- (new_length & ~PAGE_CACHE_MASK));
+ if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
+ rc = vmtruncate(inode, new_length);
+ if (rc)
+ goto out_free;
+ rc = vmtruncate(lower_dentry->d_inode, new_length);
+ goto out_free;
+ }
if (num_zeros) {
char *zeros_virt;
}
rc = 0;
crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
- mutex_unlock(&crypt_stat->cs_mutex);
- goto out;
}
}
mutex_unlock(&crypt_stat->cs_mutex);