Ban writes to compressed files explicitly

The official implementation doesn't seem to truly support writes to
compressed files: when it's attempted, the file gets decompressed
transparently instead. I don't intend to that in this driver, unless
someone actually requests it. Users can just make a decompressed copy of
the file and replace the original.

By mistake, truncating compressed files is currently allowed, but since
compressed reads don't depend on the vfs-reported size, nothing seems to
happen. Other writes fail, but the error code is confusing and there is
no output on dmesg. Ban all writes explicitly, and explain the problem
in the console.

Signed-off-by: Ernesto A. Fernández <ernesto@corellium.com>
This commit is contained in:
Ernesto A. Fernández
2023-09-21 19:50:09 -03:00
parent e4bb06ecef
commit 31df49c6d8
2 changed files with 25 additions and 0 deletions
+18
View File
@@ -521,11 +521,29 @@ static int apfs_compress_file_release(struct inode *inode, struct file *filp)
return 0;
}
static ssize_t apfs_compress_file_write(struct file *filp, const char __user *buf, size_t size, loff_t *off)
{
struct apfs_compress_file_data *fd = filp->private_data;
struct super_block *sb = fd->sb;
/*
* The official implementation seems to transparently decompress files
* when you write to them. Doing that atomically inside the kernel is
* probably a chore, so for now I'll just leave it to the user to make
* an uncompressed copy themselves and replace the original. I might
* fix this in the future, but only if people complain (TODO).
*/
apfs_warn(sb, "writes to compressed files are not supported");
apfs_warn(sb, "you can work with a copy of the file instead");
return -EOPNOTSUPP;
}
const struct file_operations apfs_compress_file_operations = {
.open = apfs_compress_file_open,
.llseek = generic_file_llseek,
.read = apfs_compress_file_read,
.release = apfs_compress_file_release,
.write = apfs_compress_file_write,
};
int apfs_compress_get_size(struct inode *inode, loff_t *size)
+7
View File
@@ -1788,11 +1788,18 @@ int apfs_setattr(struct mnt_idmap *idmap,
#endif
{
struct inode *inode = d_inode(dentry);
struct apfs_inode_info *ai = APFS_I(inode);
struct super_block *sb = inode->i_sb;
struct apfs_max_ops maxops;
bool resizing = S_ISREG(inode->i_mode) && (iattr->ia_valid & ATTR_SIZE);
int err;
if (resizing && (ai->i_bsd_flags & APFS_INOBSD_COMPRESSED)) {
apfs_warn(sb, "resizing compressed files is not supported");
apfs_warn(sb, "you can work with a copy of the file instead");
return -EOPNOTSUPP;
}
if (resizing && iattr->ia_size > APFS_MAX_FILE_SIZE)
return -EFBIG;