diff options
| author | Konstantin Komarov <almaz.alexandrovich@paragon-software.com> | 2026-05-22 14:36:13 +0200 |
|---|---|---|
| committer | Konstantin Komarov <almaz.alexandrovich@paragon-software.com> | 2026-05-28 15:41:52 +0200 |
| commit | 245bbdd2b9d6540ef228626b08af55c748d81550 (patch) | |
| tree | c1a5e83739b8f90c63fd49cdb84177ca575a5209 /fs | |
| parent | 8559e84d4e53ea7470cba3febe416882e358cb82 (diff) | |
| download | linux-next-history-245bbdd2b9d6540ef228626b08af55c748d81550.tar.gz | |
fs/ntfs3: add fileattr support
Implement fileattr_get() and fileattr_set() to fix a problem found
during the internal testing.
This allows ntfs3 to expose and modify inode flags through the generic
file attribute interface used by FS_IOC_GETFLAGS and FS_IOC_SETFLAGS.
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/ntfs3/file.c | 79 | ||||
| -rw-r--r-- | fs/ntfs3/inode.c | 2 | ||||
| -rw-r--r-- | fs/ntfs3/namei.c | 4 | ||||
| -rw-r--r-- | fs/ntfs3/ntfs_fs.h | 6 |
4 files changed, 91 insertions, 0 deletions
diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c index b041639ab406f..f421a36b1ed63 100644 --- a/fs/ntfs3/file.c +++ b/fs/ntfs3/file.c @@ -89,6 +89,80 @@ static int ntfs_ioctl_fitrim(struct ntfs_sb_info *sbi, unsigned long arg) return 0; } +/* + * ntfs_fileattr_get - inode_operations::fileattr_get + */ +int ntfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa) +{ + struct inode *inode = d_inode(dentry); + struct ntfs_inode *ni = ntfs_i(inode); + u32 flags = 0; + + /* Avoid any operation if inode is bad. */ + if (unlikely(is_bad_ni(ni))) + return -EINVAL; + + if (inode->i_flags & S_IMMUTABLE) + flags |= FS_IMMUTABLE_FL; + + if (inode->i_flags & S_APPEND) + flags |= FS_APPEND_FL; + + if (is_compressed(ni)) + flags |= FS_COMPR_FL; + + if (is_encrypted(ni)) + flags |= FS_ENCRYPT_FL; + + if (ni->nodump) + flags |= FS_NODUMP_FL; + + fileattr_fill_flags(fa, flags); + + return 0; +} + +/* + * ntfs_fileattr_set - inode_operations::fileattr_set + */ +int ntfs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry, + struct file_kattr *fa) +{ + struct inode *inode = d_inode(dentry); + struct ntfs_inode *ni = ntfs_i(inode); + u32 flags = fa->flags; + unsigned int new_fl = 0; + + /* Avoid any operation if inode is bad. */ + if (unlikely(is_bad_ni(ni))) + return -EINVAL; + + if (fileattr_has_fsx(fa)) + return -EOPNOTSUPP; + + if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL)) + return -EOPNOTSUPP; + + if (flags & FS_IMMUTABLE_FL) + new_fl |= S_IMMUTABLE; + + if (flags & FS_APPEND_FL) + new_fl |= S_APPEND; + + inode_set_flags(inode, new_fl, S_IMMUTABLE | S_APPEND); + + /* Save nodump flag to return in ntfs_getattr. */ + if (flags & FS_NODUMP_FL) + ni->nodump = 1; + else + ni->nodump = 0; + + inode_set_ctime_current(inode); + mark_inode_dirty(inode); + + return 0; +} + static int ntfs_ioctl_get_volume_label(struct ntfs_sb_info *sbi, u8 __user *buf) { if (copy_to_user(buf, sbi->volume.label, FSLABEL_MAX)) @@ -203,6 +277,9 @@ int ntfs_getattr(struct mnt_idmap *idmap, const struct path *path, if (inode->i_flags & S_APPEND) stat->attributes |= STATX_ATTR_APPEND; + if (ni->nodump) + stat->attributes |= STATX_ATTR_NODUMP; + if (is_compressed(ni)) stat->attributes |= STATX_ATTR_COMPRESSED; @@ -1547,6 +1624,8 @@ const struct inode_operations ntfs_file_inode_operations = { .get_acl = ntfs_get_acl, .set_acl = ntfs_set_acl, .fiemap = ntfs_fiemap, + .fileattr_get = ntfs_fileattr_get, + .fileattr_set = ntfs_fileattr_set, }; const struct file_operations ntfs_file_operations = { diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index 42af1abe17f88..356fc94c5a180 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -2095,6 +2095,8 @@ const struct inode_operations ntfs_link_inode_operations = { .get_link = ntfs_get_link, .setattr = ntfs_setattr, .listxattr = ntfs_listxattr, + .fileattr_get = ntfs_fileattr_get, + .fileattr_set = ntfs_fileattr_set, }; const struct address_space_operations ntfs_aops = { diff --git a/fs/ntfs3/namei.c b/fs/ntfs3/namei.c index 64cde1a856f44..c59de5f2fa977 100644 --- a/fs/ntfs3/namei.c +++ b/fs/ntfs3/namei.c @@ -518,6 +518,8 @@ const struct inode_operations ntfs_dir_inode_operations = { .getattr = ntfs_getattr, .listxattr = ntfs_listxattr, .fiemap = ntfs_fiemap, + .fileattr_get = ntfs_fileattr_get, + .fileattr_set = ntfs_fileattr_set, }; const struct inode_operations ntfs_special_inode_operations = { @@ -526,6 +528,8 @@ const struct inode_operations ntfs_special_inode_operations = { .listxattr = ntfs_listxattr, .get_acl = ntfs_get_acl, .set_acl = ntfs_set_acl, + .fileattr_get = ntfs_fileattr_get, + .fileattr_set = ntfs_fileattr_set, }; const struct dentry_operations ntfs_dentry_ops = { diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index d53febc2559c0..9939556dcdc1e 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -392,6 +392,9 @@ struct ntfs_inode { */ u8 ni_bad; + /* Keep track of FS_NODUMP_FL. */ + u8 nodump; + union { struct ntfs_index dir; struct { @@ -529,6 +532,9 @@ bool dir_is_empty(struct inode *dir); extern const struct file_operations ntfs_dir_operations; /* Globals from file.c */ +int ntfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa); +int ntfs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry, + struct file_kattr *fa); int ntfs_getattr(struct mnt_idmap *idmap, const struct path *path, struct kstat *stat, u32 request_mask, u32 flags); int ntfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, |
