Loading fs/ntfs3/attrib.c +71 −0 Original line number Diff line number Diff line Loading @@ -2605,3 +2605,74 @@ int attr_force_nonresident(struct ntfs_inode *ni) return err; } /* * Change the compression of data attribute */ int attr_set_compress(struct ntfs_inode *ni, bool compr) { struct ATTRIB *attr; struct mft_inode *mi; attr = ni_find_attr(ni, NULL, NULL, ATTR_DATA, NULL, 0, NULL, &mi); if (!attr) return -ENOENT; if (is_attr_compressed(attr) == !!compr) { /* Already required compressed state. */ return 0; } if (attr->non_res) { u16 run_off; u32 run_size; char *run; if (attr->nres.data_size) { /* * There are rare cases when it possible to change * compress state without big changes. * TODO: Process these cases. */ return -EOPNOTSUPP; } run_off = le16_to_cpu(attr->nres.run_off); run_size = le32_to_cpu(attr->size) - run_off; run = Add2Ptr(attr, run_off); if (!compr) { /* remove field 'attr->nres.total_size'. */ memmove(run - 8, run, run_size); run_off -= 8; } if (!mi_resize_attr(mi, attr, compr ? +8 : -8)) { /* * Ignore rare case when there are no 8 bytes in record with attr. * TODO: split attribute. */ return -EOPNOTSUPP; } if (compr) { /* Make a gap for 'attr->nres.total_size'. */ memmove(run + 8, run, run_size); run_off += 8; attr->nres.total_size = attr->nres.alloc_size; } attr->nres.run_off = cpu_to_le16(run_off); } /* Update data attribute flags. */ if (compr) { attr->flags |= ATTR_FLAG_COMPRESSED; attr->nres.c_unit = NTFS_LZNT_CUNIT; } else { attr->flags &= ~ATTR_FLAG_COMPRESSED; attr->nres.c_unit = 0; } mi->dirty = true; return 0; } fs/ntfs3/file.c +11 −1 Original line number Diff line number Diff line Loading @@ -82,13 +82,14 @@ int ntfs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry, struct fileattr *fa) { struct inode *inode = d_inode(dentry); struct ntfs_inode *ni = ntfs_i(inode); u32 flags = fa->flags; unsigned int new_fl = 0; if (fileattr_has_fsx(fa)) return -EOPNOTSUPP; if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL)) if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | FS_COMPR_FL)) return -EOPNOTSUPP; if (flags & FS_IMMUTABLE_FL) Loading @@ -97,6 +98,15 @@ int ntfs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry, if (flags & FS_APPEND_FL) new_fl |= S_APPEND; /* Allowed to change compression for empty files and for directories only. */ if (!is_dedup(ni) && !is_encrypted(ni) && (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) { /* Change compress state. */ int err = ni_set_compress(inode, flags & FS_COMPR_FL); if (err) return err; } inode_set_flags(inode, new_fl, S_IMMUTABLE | S_APPEND); inode_set_ctime_current(inode); Loading fs/ntfs3/frecord.c +72 −0 Original line number Diff line number Diff line Loading @@ -3450,3 +3450,75 @@ int ni_write_inode(struct inode *inode, int sync, const char *hint) return 0; } /* * ni_set_compress * * Helper for 'ntfs_fileattr_set'. * Changes compression for empty files and directories only. */ int ni_set_compress(struct inode *inode, bool compr) { int err; struct ntfs_inode *ni = ntfs_i(inode); struct ATTR_STD_INFO *std; const char *bad_inode; if (is_compressed(ni) == !!compr) return 0; if (is_sparsed(ni)) { /* sparse and compress not compatible. */ return -EOPNOTSUPP; } if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) { /*Skip other inodes. (symlink,fifo,...) */ return -EOPNOTSUPP; } bad_inode = NULL; ni_lock(ni); std = ni_std(ni); if (!std) { bad_inode = "no std"; goto out; } if (S_ISREG(inode->i_mode)) { err = attr_set_compress(ni, compr); if (err) { if (err == -ENOENT) { /* Fix on the fly? */ /* Each file must contain data attribute. */ bad_inode = "no data attribute"; } goto out; } } ni->std_fa = std->fa; if (compr) std->fa |= FILE_ATTRIBUTE_COMPRESSED; else std->fa &= ~FILE_ATTRIBUTE_COMPRESSED; if (ni->std_fa != std->fa) { ni->std_fa = std->fa; ni->mi.dirty = true; } /* update duplicate information and directory entries in ni_write_inode.*/ ni->ni_flags |= NI_FLAG_UPDATE_PARENT; err = 0; out: ni_unlock(ni); if (bad_inode) { ntfs_bad_inode(inode, bad_inode); err = -EINVAL; } return err; } fs/ntfs3/ntfs_fs.h +2 −0 Original line number Diff line number Diff line Loading @@ -453,6 +453,7 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes); int attr_insert_range(struct ntfs_inode *ni, u64 vbo, u64 bytes); int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size); int attr_force_nonresident(struct ntfs_inode *ni); int attr_set_compress(struct ntfs_inode *ni, bool compr); /* Functions from attrlist.c */ void al_destroy(struct ntfs_inode *ni); Loading Loading @@ -588,6 +589,7 @@ int ni_rename(struct ntfs_inode *dir_ni, struct ntfs_inode *new_dir_ni, bool *is_bad); bool ni_is_dirty(struct inode *inode); int ni_set_compress(struct inode *inode, bool compr); /* Globals from fslog.c */ bool check_index_header(const struct INDEX_HDR *hdr, size_t bytes); Loading Loading
fs/ntfs3/attrib.c +71 −0 Original line number Diff line number Diff line Loading @@ -2605,3 +2605,74 @@ int attr_force_nonresident(struct ntfs_inode *ni) return err; } /* * Change the compression of data attribute */ int attr_set_compress(struct ntfs_inode *ni, bool compr) { struct ATTRIB *attr; struct mft_inode *mi; attr = ni_find_attr(ni, NULL, NULL, ATTR_DATA, NULL, 0, NULL, &mi); if (!attr) return -ENOENT; if (is_attr_compressed(attr) == !!compr) { /* Already required compressed state. */ return 0; } if (attr->non_res) { u16 run_off; u32 run_size; char *run; if (attr->nres.data_size) { /* * There are rare cases when it possible to change * compress state without big changes. * TODO: Process these cases. */ return -EOPNOTSUPP; } run_off = le16_to_cpu(attr->nres.run_off); run_size = le32_to_cpu(attr->size) - run_off; run = Add2Ptr(attr, run_off); if (!compr) { /* remove field 'attr->nres.total_size'. */ memmove(run - 8, run, run_size); run_off -= 8; } if (!mi_resize_attr(mi, attr, compr ? +8 : -8)) { /* * Ignore rare case when there are no 8 bytes in record with attr. * TODO: split attribute. */ return -EOPNOTSUPP; } if (compr) { /* Make a gap for 'attr->nres.total_size'. */ memmove(run + 8, run, run_size); run_off += 8; attr->nres.total_size = attr->nres.alloc_size; } attr->nres.run_off = cpu_to_le16(run_off); } /* Update data attribute flags. */ if (compr) { attr->flags |= ATTR_FLAG_COMPRESSED; attr->nres.c_unit = NTFS_LZNT_CUNIT; } else { attr->flags &= ~ATTR_FLAG_COMPRESSED; attr->nres.c_unit = 0; } mi->dirty = true; return 0; }
fs/ntfs3/file.c +11 −1 Original line number Diff line number Diff line Loading @@ -82,13 +82,14 @@ int ntfs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry, struct fileattr *fa) { struct inode *inode = d_inode(dentry); struct ntfs_inode *ni = ntfs_i(inode); u32 flags = fa->flags; unsigned int new_fl = 0; if (fileattr_has_fsx(fa)) return -EOPNOTSUPP; if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL)) if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | FS_COMPR_FL)) return -EOPNOTSUPP; if (flags & FS_IMMUTABLE_FL) Loading @@ -97,6 +98,15 @@ int ntfs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry, if (flags & FS_APPEND_FL) new_fl |= S_APPEND; /* Allowed to change compression for empty files and for directories only. */ if (!is_dedup(ni) && !is_encrypted(ni) && (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) { /* Change compress state. */ int err = ni_set_compress(inode, flags & FS_COMPR_FL); if (err) return err; } inode_set_flags(inode, new_fl, S_IMMUTABLE | S_APPEND); inode_set_ctime_current(inode); Loading
fs/ntfs3/frecord.c +72 −0 Original line number Diff line number Diff line Loading @@ -3450,3 +3450,75 @@ int ni_write_inode(struct inode *inode, int sync, const char *hint) return 0; } /* * ni_set_compress * * Helper for 'ntfs_fileattr_set'. * Changes compression for empty files and directories only. */ int ni_set_compress(struct inode *inode, bool compr) { int err; struct ntfs_inode *ni = ntfs_i(inode); struct ATTR_STD_INFO *std; const char *bad_inode; if (is_compressed(ni) == !!compr) return 0; if (is_sparsed(ni)) { /* sparse and compress not compatible. */ return -EOPNOTSUPP; } if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) { /*Skip other inodes. (symlink,fifo,...) */ return -EOPNOTSUPP; } bad_inode = NULL; ni_lock(ni); std = ni_std(ni); if (!std) { bad_inode = "no std"; goto out; } if (S_ISREG(inode->i_mode)) { err = attr_set_compress(ni, compr); if (err) { if (err == -ENOENT) { /* Fix on the fly? */ /* Each file must contain data attribute. */ bad_inode = "no data attribute"; } goto out; } } ni->std_fa = std->fa; if (compr) std->fa |= FILE_ATTRIBUTE_COMPRESSED; else std->fa &= ~FILE_ATTRIBUTE_COMPRESSED; if (ni->std_fa != std->fa) { ni->std_fa = std->fa; ni->mi.dirty = true; } /* update duplicate information and directory entries in ni_write_inode.*/ ni->ni_flags |= NI_FLAG_UPDATE_PARENT; err = 0; out: ni_unlock(ni); if (bad_inode) { ntfs_bad_inode(inode, bad_inode); err = -EINVAL; } return err; }
fs/ntfs3/ntfs_fs.h +2 −0 Original line number Diff line number Diff line Loading @@ -453,6 +453,7 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes); int attr_insert_range(struct ntfs_inode *ni, u64 vbo, u64 bytes); int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size); int attr_force_nonresident(struct ntfs_inode *ni); int attr_set_compress(struct ntfs_inode *ni, bool compr); /* Functions from attrlist.c */ void al_destroy(struct ntfs_inode *ni); Loading Loading @@ -588,6 +589,7 @@ int ni_rename(struct ntfs_inode *dir_ni, struct ntfs_inode *new_dir_ni, bool *is_bad); bool ni_is_dirty(struct inode *inode); int ni_set_compress(struct inode *inode, bool compr); /* Globals from fslog.c */ bool check_index_header(const struct INDEX_HDR *hdr, size_t bytes); Loading