Skip to content

Commit 6b39bfa

Browse files
fs/ntfs3: Add support for the compression attribute
Support added for empty files and directories only. Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
1 parent 9a2d6a4 commit 6b39bfa

File tree

4 files changed

+156
-1
lines changed

4 files changed

+156
-1
lines changed

fs/ntfs3/attrib.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2605,3 +2605,74 @@ int attr_force_nonresident(struct ntfs_inode *ni)
26052605

26062606
return err;
26072607
}
2608+
2609+
/*
2610+
* Change the compression of data attribute
2611+
*/
2612+
int attr_set_compress(struct ntfs_inode *ni, bool compr)
2613+
{
2614+
struct ATTRIB *attr;
2615+
struct mft_inode *mi;
2616+
2617+
attr = ni_find_attr(ni, NULL, NULL, ATTR_DATA, NULL, 0, NULL, &mi);
2618+
if (!attr)
2619+
return -ENOENT;
2620+
2621+
if (is_attr_compressed(attr) == !!compr) {
2622+
/* Already required compressed state. */
2623+
return 0;
2624+
}
2625+
2626+
if (attr->non_res) {
2627+
u16 run_off;
2628+
u32 run_size;
2629+
char *run;
2630+
2631+
if (attr->nres.data_size) {
2632+
/*
2633+
* There are rare cases when it possible to change
2634+
* compress state without big changes.
2635+
* TODO: Process these cases.
2636+
*/
2637+
return -EOPNOTSUPP;
2638+
}
2639+
2640+
run_off = le16_to_cpu(attr->nres.run_off);
2641+
run_size = le32_to_cpu(attr->size) - run_off;
2642+
run = Add2Ptr(attr, run_off);
2643+
2644+
if (!compr) {
2645+
/* remove field 'attr->nres.total_size'. */
2646+
memmove(run - 8, run, run_size);
2647+
run_off -= 8;
2648+
}
2649+
2650+
if (!mi_resize_attr(mi, attr, compr ? +8 : -8)) {
2651+
/*
2652+
* Ignore rare case when there are no 8 bytes in record with attr.
2653+
* TODO: split attribute.
2654+
*/
2655+
return -EOPNOTSUPP;
2656+
}
2657+
2658+
if (compr) {
2659+
/* Make a gap for 'attr->nres.total_size'. */
2660+
memmove(run + 8, run, run_size);
2661+
run_off += 8;
2662+
attr->nres.total_size = attr->nres.alloc_size;
2663+
}
2664+
attr->nres.run_off = cpu_to_le16(run_off);
2665+
}
2666+
2667+
/* Update data attribute flags. */
2668+
if (compr) {
2669+
attr->flags |= ATTR_FLAG_COMPRESSED;
2670+
attr->nres.c_unit = NTFS_LZNT_CUNIT;
2671+
} else {
2672+
attr->flags &= ~ATTR_FLAG_COMPRESSED;
2673+
attr->nres.c_unit = 0;
2674+
}
2675+
mi->dirty = true;
2676+
2677+
return 0;
2678+
}

fs/ntfs3/file.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,14 @@ int ntfs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry,
8282
struct fileattr *fa)
8383
{
8484
struct inode *inode = d_inode(dentry);
85+
struct ntfs_inode *ni = ntfs_i(inode);
8586
u32 flags = fa->flags;
8687
unsigned int new_fl = 0;
8788

8889
if (fileattr_has_fsx(fa))
8990
return -EOPNOTSUPP;
9091

91-
if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL))
92+
if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | FS_COMPR_FL))
9293
return -EOPNOTSUPP;
9394

9495
if (flags & FS_IMMUTABLE_FL)
@@ -97,6 +98,15 @@ int ntfs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry,
9798
if (flags & FS_APPEND_FL)
9899
new_fl |= S_APPEND;
99100

101+
/* Allowed to change compression for empty files and for directories only. */
102+
if (!is_dedup(ni) && !is_encrypted(ni) &&
103+
(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) {
104+
/* Change compress state. */
105+
int err = ni_set_compress(inode, flags & FS_COMPR_FL);
106+
if (err)
107+
return err;
108+
}
109+
100110
inode_set_flags(inode, new_fl, S_IMMUTABLE | S_APPEND);
101111

102112
inode_set_ctime_current(inode);

fs/ntfs3/frecord.c

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3450,3 +3450,75 @@ int ni_write_inode(struct inode *inode, int sync, const char *hint)
34503450

34513451
return 0;
34523452
}
3453+
3454+
/*
3455+
* ni_set_compress
3456+
*
3457+
* Helper for 'ntfs_fileattr_set'.
3458+
* Changes compression for empty files and directories only.
3459+
*/
3460+
int ni_set_compress(struct inode *inode, bool compr)
3461+
{
3462+
int err;
3463+
struct ntfs_inode *ni = ntfs_i(inode);
3464+
struct ATTR_STD_INFO *std;
3465+
const char *bad_inode;
3466+
3467+
if (is_compressed(ni) == !!compr)
3468+
return 0;
3469+
3470+
if (is_sparsed(ni)) {
3471+
/* sparse and compress not compatible. */
3472+
return -EOPNOTSUPP;
3473+
}
3474+
3475+
if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) {
3476+
/*Skip other inodes. (symlink,fifo,...) */
3477+
return -EOPNOTSUPP;
3478+
}
3479+
3480+
bad_inode = NULL;
3481+
3482+
ni_lock(ni);
3483+
3484+
std = ni_std(ni);
3485+
if (!std) {
3486+
bad_inode = "no std";
3487+
goto out;
3488+
}
3489+
3490+
if (S_ISREG(inode->i_mode)) {
3491+
err = attr_set_compress(ni, compr);
3492+
if (err) {
3493+
if (err == -ENOENT) {
3494+
/* Fix on the fly? */
3495+
/* Each file must contain data attribute. */
3496+
bad_inode = "no data attribute";
3497+
}
3498+
goto out;
3499+
}
3500+
}
3501+
3502+
ni->std_fa = std->fa;
3503+
if (compr)
3504+
std->fa |= FILE_ATTRIBUTE_COMPRESSED;
3505+
else
3506+
std->fa &= ~FILE_ATTRIBUTE_COMPRESSED;
3507+
3508+
if (ni->std_fa != std->fa) {
3509+
ni->std_fa = std->fa;
3510+
ni->mi.dirty = true;
3511+
}
3512+
/* update duplicate information and directory entries in ni_write_inode.*/
3513+
ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
3514+
err = 0;
3515+
3516+
out:
3517+
ni_unlock(ni);
3518+
if (bad_inode) {
3519+
ntfs_bad_inode(inode, bad_inode);
3520+
err = -EINVAL;
3521+
}
3522+
3523+
return err;
3524+
}

fs/ntfs3/ntfs_fs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,7 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes);
453453
int attr_insert_range(struct ntfs_inode *ni, u64 vbo, u64 bytes);
454454
int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size);
455455
int attr_force_nonresident(struct ntfs_inode *ni);
456+
int attr_set_compress(struct ntfs_inode *ni, bool compr);
456457

457458
/* Functions from attrlist.c */
458459
void al_destroy(struct ntfs_inode *ni);
@@ -588,6 +589,7 @@ int ni_rename(struct ntfs_inode *dir_ni, struct ntfs_inode *new_dir_ni,
588589
bool *is_bad);
589590

590591
bool ni_is_dirty(struct inode *inode);
592+
int ni_set_compress(struct inode *inode, bool compr);
591593

592594
/* Globals from fslog.c */
593595
bool check_index_header(const struct INDEX_HDR *hdr, size_t bytes);

0 commit comments

Comments
 (0)