#include <linux/file.h>
#include <linux/poll.h>
+#include <linux/slab.h>
#include <linux/mount.h>
#include <linux/pagemap.h>
#include <linux/security.h>
const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
- int rc;
+ ssize_t rc;
struct dentry *lower_dentry;
struct vfsmount *lower_vfsmount;
struct file *file = iocb->ki_filp;
void *dirent;
struct dentry *dentry;
filldir_t filldir;
- int err;
int filldir_called;
int entries_written;
};
-/* Inspired by generic filldir in fs/readir.c */
+/* Inspired by generic filldir in fs/readdir.c */
static int
-ecryptfs_filldir(void *dirent, const char *name, int namelen, loff_t offset,
- u64 ino, unsigned int d_type)
+ecryptfs_filldir(void *dirent, const char *lower_name, int lower_namelen,
+ loff_t offset, u64 ino, unsigned int d_type)
{
- struct ecryptfs_crypt_stat *crypt_stat;
struct ecryptfs_getdents_callback *buf =
(struct ecryptfs_getdents_callback *)dirent;
+ size_t name_size;
+ char *name;
int rc;
- int decoded_length;
- char *decoded_name;
- crypt_stat = ecryptfs_dentry_to_private(buf->dentry)->crypt_stat;
buf->filldir_called++;
- decoded_length = ecryptfs_decode_filename(crypt_stat, name, namelen,
- &decoded_name);
- if (decoded_length < 0) {
- rc = decoded_length;
+ rc = ecryptfs_decode_and_decrypt_filename(&name, &name_size,
+ buf->dentry, lower_name,
+ lower_namelen);
+ if (rc) {
+ printk(KERN_ERR "%s: Error attempting to decode and decrypt "
+ "filename [%s]; rc = [%d]\n", __func__, lower_name,
+ rc);
goto out;
}
- rc = buf->filldir(buf->dirent, decoded_name, decoded_length, offset,
- ino, d_type);
- kfree(decoded_name);
+ rc = buf->filldir(buf->dirent, name, name_size, offset, ino, d_type);
+ kfree(name);
if (rc >= 0)
buf->entries_written++;
out:
/**
* ecryptfs_readdir
- * @file: The ecryptfs file struct
- * @dirent: Directory entry
+ * @file: The eCryptfs directory file
+ * @dirent: Directory entry handle
* @filldir: The filldir callback function
*/
static int ecryptfs_readdir(struct file *file, void *dirent, filldir_t filldir)
buf.dirent = dirent;
buf.dentry = file->f_path.dentry;
buf.filldir = filldir;
-retry:
buf.filldir_called = 0;
buf.entries_written = 0;
- buf.err = 0;
rc = vfs_readdir(lower_file, ecryptfs_filldir, (void *)&buf);
- if (buf.err)
- rc = buf.err;
- if (buf.filldir_called && !buf.entries_written)
- goto retry;
file->f_pos = lower_file->f_pos;
+ if (rc < 0)
+ goto out;
+ if (buf.filldir_called && !buf.entries_written)
+ goto out;
if (rc >= 0)
- fsstack_copy_attr_atime(inode, lower_file->f_path.dentry->d_inode);
+ fsstack_copy_attr_atime(inode,
+ lower_file->f_path.dentry->d_inode);
+out:
return rc;
}
struct dentry *ecryptfs_dentry = file->f_path.dentry;
/* Private value of ecryptfs_dentry allocated in
* ecryptfs_lookup() */
- struct dentry *lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
+ struct dentry *lower_dentry;
struct ecryptfs_file_info *file_info;
mount_crypt_stat = &ecryptfs_superblock_to_private(
| ECRYPTFS_ENCRYPTED);
}
mutex_unlock(&crypt_stat->cs_mutex);
+ rc = ecryptfs_init_persistent_file(ecryptfs_dentry);
+ if (rc) {
+ printk(KERN_ERR "%s: Error attempting to initialize "
+ "the persistent file for the dentry with name "
+ "[%s]; rc = [%d]\n", __func__,
+ ecryptfs_dentry->d_name.name, rc);
+ goto out_free;
+ }
+ if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_ACCMODE)
+ == O_RDONLY && (file->f_flags & O_ACCMODE) != O_RDONLY) {
+ rc = -EPERM;
+ printk(KERN_WARNING "%s: Lower persistent file is RO; eCryptfs "
+ "file must hence be opened RO\n", __func__);
+ goto out_free;
+ }
ecryptfs_set_file_lower(
file, ecryptfs_inode_to_private(inode)->lower_file);
if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) {
}
}
mutex_unlock(&crypt_stat->cs_mutex);
- ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = [0x%.16x] "
- "size: [0x%.16x]\n", inode, inode->i_ino,
- i_size_read(inode));
+ ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = "
+ "[0x%.16lx] size: [0x%.16llx]\n", inode, inode->i_ino,
+ (unsigned long long)i_size_read(inode));
goto out;
out_free:
kmem_cache_free(ecryptfs_file_info_cache,
}
static int
-ecryptfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+ecryptfs_fsync(struct file *file, int datasync)
{
- struct file *lower_file = ecryptfs_file_to_lower(file);
- struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
- struct inode *lower_inode = lower_dentry->d_inode;
- int rc = -EINVAL;
-
- if (lower_inode->i_fop->fsync) {
- mutex_lock(&lower_inode->i_mutex);
- rc = lower_inode->i_fop->fsync(lower_file, lower_dentry,
- datasync);
- mutex_unlock(&lower_inode->i_mutex);
- }
- return rc;
+ return vfs_fsync(ecryptfs_file_to_lower(file), datasync);
}
static int ecryptfs_fasync(int fd, struct file *file, int flag)
return rc;
}
-static int ecryptfs_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg);
+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)
+ rc = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg);
+ return rc;
+}
+
+#ifdef CONFIG_COMPAT
+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)
+ rc = lower_file->f_op->compat_ioctl(lower_file, cmd, arg);
+ return rc;
+}
+#endif
const struct file_operations ecryptfs_dir_fops = {
.readdir = ecryptfs_readdir,
- .ioctl = ecryptfs_ioctl,
- .mmap = generic_file_mmap,
+ .read = generic_read_dir,
+ .unlocked_ioctl = ecryptfs_unlocked_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ecryptfs_compat_ioctl,
+#endif
.open = ecryptfs_open,
.flush = ecryptfs_flush,
.release = ecryptfs_release,
.fsync = ecryptfs_fsync,
.fasync = ecryptfs_fasync,
.splice_read = generic_file_splice_read,
+ .llseek = default_llseek,
};
const struct file_operations ecryptfs_main_fops = {
.write = do_sync_write,
.aio_write = generic_file_aio_write,
.readdir = ecryptfs_readdir,
- .ioctl = ecryptfs_ioctl,
+ .unlocked_ioctl = ecryptfs_unlocked_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ecryptfs_compat_ioctl,
+#endif
.mmap = generic_file_mmap,
.open = ecryptfs_open,
.flush = ecryptfs_flush,
.fasync = ecryptfs_fasync,
.splice_read = generic_file_splice_read,
};
-
-static int
-ecryptfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- int rc = 0;
- struct file *lower_file = NULL;
-
- if (ecryptfs_file_to_private(file))
- lower_file = ecryptfs_file_to_lower(file);
- if (lower_file && lower_file->f_op && lower_file->f_op->ioctl)
- rc = lower_file->f_op->ioctl(ecryptfs_inode_to_lower(inode),
- lower_file, cmd, arg);
- else
- rc = -ENOTTY;
- return rc;
-}