📄 inode.c
字号:
loff_t num_extents; num_extents = upper_size >> crypt_stat->extent_shift; if (upper_size & ~crypt_stat->extent_mask) num_extents++; lower_size += (num_extents * crypt_stat->extent_size); } return lower_size;}/** * ecryptfs_truncate * @dentry: The ecryptfs layer dentry * @new_length: The length to expand the file to * * Function to handle truncations modifying the size of the file. Note * that the file sizes are interpolated. When expanding, we are simply * writing strings of 0's out. When truncating, we need to modify the * underlying file size according to the page index interpolations. * * Returns zero on success; non-zero otherwise */int ecryptfs_truncate(struct dentry *dentry, loff_t new_length){ int rc = 0; struct inode *inode = dentry->d_inode; struct dentry *lower_dentry; struct file fake_ecryptfs_file; struct ecryptfs_crypt_stat *crypt_stat; loff_t i_size = i_size_read(inode); loff_t lower_size_before_truncate; loff_t lower_size_after_truncate; if (unlikely((new_length == i_size))) goto out; crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat; /* Set up a fake ecryptfs file, this is used to interface with * the file in the underlying filesystem so that the * truncation has an effect there as well. */ memset(&fake_ecryptfs_file, 0, sizeof(fake_ecryptfs_file)); fake_ecryptfs_file.f_path.dentry = dentry; /* Released at out_free: label */ ecryptfs_set_file_private(&fake_ecryptfs_file, kmem_cache_alloc(ecryptfs_file_info_cache, GFP_KERNEL)); if (unlikely(!ecryptfs_file_to_private(&fake_ecryptfs_file))) { rc = -ENOMEM; goto out; } lower_dentry = ecryptfs_dentry_to_lower(dentry); ecryptfs_set_file_lower( &fake_ecryptfs_file, ecryptfs_inode_to_private(dentry->d_inode)->lower_file); /* Switch on growing or shrinking file */ if (new_length > i_size) { char zero[] = { 0x00 }; /* Write a single 0 at the last position of the file; * this triggers code that will fill in 0's throughout * the intermediate portion of the previous end of the * file and the new and of the file */ rc = ecryptfs_write(&fake_ecryptfs_file, zero, (new_length - 1), 1); } else { /* new_length < i_size_read(inode) */ /* We're chopping off all the pages down do the page * in which new_length is located. Fill in the end of * that page from (new_length & ~PAGE_CACHE_MASK) to * PAGE_CACHE_SIZE with zeros. */ size_t num_zeros = (PAGE_CACHE_SIZE - (new_length & ~PAGE_CACHE_MASK)); if (num_zeros) { char *zeros_virt; zeros_virt = kzalloc(num_zeros, GFP_KERNEL); if (!zeros_virt) { rc = -ENOMEM; goto out_free; } rc = ecryptfs_write(&fake_ecryptfs_file, zeros_virt, new_length, num_zeros); kfree(zeros_virt); if (rc) { printk(KERN_ERR "Error attempting to zero out " "the remainder of the end page on " "reducing truncate; rc = [%d]\n", rc); goto out_free; } } vmtruncate(inode, new_length); rc = ecryptfs_write_inode_size_to_metadata(inode); if (rc) { printk(KERN_ERR "Problem with " "ecryptfs_write_inode_size_to_metadata; " "rc = [%d]\n", rc); goto out_free; } /* We are reducing the size of the ecryptfs file, and need to * know if we need to reduce the size of the lower file. */ lower_size_before_truncate = upper_size_to_lower_size(crypt_stat, i_size); lower_size_after_truncate = upper_size_to_lower_size(crypt_stat, new_length); if (lower_size_after_truncate < lower_size_before_truncate) vmtruncate(lower_dentry->d_inode, lower_size_after_truncate); }out_free: if (ecryptfs_file_to_private(&fake_ecryptfs_file)) kmem_cache_free(ecryptfs_file_info_cache, ecryptfs_file_to_private(&fake_ecryptfs_file));out: return rc;}static intecryptfs_permission(struct inode *inode, int mask, struct nameidata *nd){ int rc; if (nd) { struct vfsmount *vfsmnt_save = nd->mnt; struct dentry *dentry_save = nd->dentry; nd->mnt = ecryptfs_dentry_to_lower_mnt(nd->dentry); nd->dentry = ecryptfs_dentry_to_lower(nd->dentry); rc = permission(ecryptfs_inode_to_lower(inode), mask, nd); nd->mnt = vfsmnt_save; nd->dentry = dentry_save; } else rc = permission(ecryptfs_inode_to_lower(inode), mask, NULL); return rc;}/** * ecryptfs_setattr * @dentry: dentry handle to the inode to modify * @ia: Structure with flags of what to change and values * * Updates the metadata of an inode. If the update is to the size * i.e. truncation, then ecryptfs_truncate will handle the size modification * of both the ecryptfs inode and the lower inode. * * All other metadata changes will be passed right to the lower filesystem, * and we will just update our inode to look like the lower. */static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia){ int rc = 0; struct dentry *lower_dentry; struct inode *inode; struct inode *lower_inode; struct ecryptfs_crypt_stat *crypt_stat; 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); lower_dentry = ecryptfs_dentry_to_lower(dentry); mutex_lock(&crypt_stat->cs_mutex); if (S_ISDIR(dentry->d_inode->i_mode)) crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); else if (S_ISREG(dentry->d_inode->i_mode) && (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED) || !(crypt_stat->flags & ECRYPTFS_KEY_VALID))) { struct ecryptfs_mount_crypt_stat *mount_crypt_stat; mount_crypt_stat = &ecryptfs_superblock_to_private( dentry->d_sb)->mount_crypt_stat; rc = ecryptfs_read_metadata(dentry); if (rc) { if (!(mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) { rc = -EIO; printk(KERN_WARNING "Attempt to read file that " "is not in a valid eCryptfs format, " "and plaintext passthrough mode is not " "enabled; returning -EIO\n"); mutex_unlock(&crypt_stat->cs_mutex); goto out; } rc = 0; crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); mutex_unlock(&crypt_stat->cs_mutex); goto out; } } mutex_unlock(&crypt_stat->cs_mutex); if (ia->ia_valid & ATTR_SIZE) { ecryptfs_printk(KERN_DEBUG, "ia->ia_valid = [0x%x] ATTR_SIZE" " = [0x%x]\n", ia->ia_valid, ATTR_SIZE); rc = ecryptfs_truncate(dentry, ia->ia_size); /* ecryptfs_truncate handles resizing of the lower file */ ia->ia_valid &= ~ATTR_SIZE; ecryptfs_printk(KERN_DEBUG, "ia->ia_valid = [%x]\n", 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, NULL); return rc;}intecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags){ int rc = 0; struct dentry *lower_dentry; lower_dentry = ecryptfs_dentry_to_lower(dentry); if (!lower_dentry->d_inode->i_op->setxattr) { rc = -ENOSYS; goto out; } mutex_lock(&lower_dentry->d_inode->i_mutex); rc = lower_dentry->d_inode->i_op->setxattr(lower_dentry, name, value, size, flags); mutex_unlock(&lower_dentry->d_inode->i_mutex);out: return rc;}ssize_tecryptfs_getxattr_lower(struct dentry *lower_dentry, const char *name, void *value, size_t size){ int rc = 0; if (!lower_dentry->d_inode->i_op->getxattr) { rc = -ENOSYS; goto out; } mutex_lock(&lower_dentry->d_inode->i_mutex); rc = lower_dentry->d_inode->i_op->getxattr(lower_dentry, name, value, size); mutex_unlock(&lower_dentry->d_inode->i_mutex);out: return rc;}ssize_tecryptfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size){ return ecryptfs_getxattr_lower(ecryptfs_dentry_to_lower(dentry), name, value, size);}static ssize_tecryptfs_listxattr(struct dentry *dentry, char *list, size_t size){ int rc = 0; struct dentry *lower_dentry; lower_dentry = ecryptfs_dentry_to_lower(dentry); if (!lower_dentry->d_inode->i_op->listxattr) { rc = -ENOSYS; goto out; } mutex_lock(&lower_dentry->d_inode->i_mutex); rc = lower_dentry->d_inode->i_op->listxattr(lower_dentry, list, size); mutex_unlock(&lower_dentry->d_inode->i_mutex);out: return rc;}static int ecryptfs_removexattr(struct dentry *dentry, const char *name){ int rc = 0; struct dentry *lower_dentry; lower_dentry = ecryptfs_dentry_to_lower(dentry); if (!lower_dentry->d_inode->i_op->removexattr) { rc = -ENOSYS; goto out; } mutex_lock(&lower_dentry->d_inode->i_mutex); rc = lower_dentry->d_inode->i_op->removexattr(lower_dentry, name); mutex_unlock(&lower_dentry->d_inode->i_mutex);out: return rc;}int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode){ if ((ecryptfs_inode_to_lower(inode) == (struct inode *)candidate_lower_inode)) return 1; else return 0;}int ecryptfs_inode_set(struct inode *inode, void *lower_inode){ ecryptfs_init_inode(inode, (struct inode *)lower_inode); return 0;}const struct inode_operations ecryptfs_symlink_iops = { .readlink = ecryptfs_readlink, .follow_link = ecryptfs_follow_link, .put_link = ecryptfs_put_link, .permission = ecryptfs_permission, .setattr = ecryptfs_setattr, .setxattr = ecryptfs_setxattr, .getxattr = ecryptfs_getxattr, .listxattr = ecryptfs_listxattr, .removexattr = ecryptfs_removexattr};const struct inode_operations ecryptfs_dir_iops = { .create = ecryptfs_create, .lookup = ecryptfs_lookup, .link = ecryptfs_link, .unlink = ecryptfs_unlink, .symlink = ecryptfs_symlink, .mkdir = ecryptfs_mkdir, .rmdir = ecryptfs_rmdir, .mknod = ecryptfs_mknod, .rename = ecryptfs_rename, .permission = ecryptfs_permission, .setattr = ecryptfs_setattr, .setxattr = ecryptfs_setxattr, .getxattr = ecryptfs_getxattr, .listxattr = ecryptfs_listxattr, .removexattr = ecryptfs_removexattr};const struct inode_operations ecryptfs_main_iops = { .permission = ecryptfs_permission, .setattr = ecryptfs_setattr, .setxattr = ecryptfs_setxattr, .getxattr = ecryptfs_getxattr, .listxattr = ecryptfs_listxattr, .removexattr = ecryptfs_removexattr};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -