[PATCH 4/8] ntfs: parse REPARSE_TAG_WOF
Hyunchul Lee <[email protected]>
| Newsgroups | dev.linux.lists.ntfs |
|---|---|
| Message-ID | <[email protected]> |
Introduce parsing support for REPARSE_TAG_WOF reparse points. Rename ntfs_make_symlink() to ntfs_parse_reparse() since it now handles both symlinks and WOF reparse tags. Introduce NI_WofCompressed flag to indicate files compressed via Windows System Compression (WOF), and configure compressed block size accordingly (12 to 15 bits based on the format). Signed-off-by: Hyunchul Lee <[email protected]> --- fs/ntfs/inode.c | 5 ++-- fs/ntfs/inode.h | 11 ++++++++ fs/ntfs/reparse.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- fs/ntfs/reparse.h | 2 +- 4 files changed, 90 insertions(+), 5 deletions(-) diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 39c7fd8c1149..8d9bbc151309 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -869,7 +869,7 @@ static int ntfs_read_locked_inode(struct inode *vi) if (ni->flags & FILE_ATTR_REPARSE_POINT) { unsigned int mode; - mode = ntfs_make_symlink(ni); + mode = ntfs_parse_reparse(ni); if (mode) vi->i_mode |= mode; else { @@ -1214,7 +1214,8 @@ static int ntfs_read_locked_inode(struct inode *vi) * sizes of all non-resident attributes present to give us the Linux * correct size that should go into i_blocks (after division by 512). */ - if (S_ISREG(vi->i_mode) && (NInoCompressed(ni) || NInoSparse(ni))) + if (S_ISREG(vi->i_mode) && + (NInoCompressed(ni) || (NInoSparse(ni) && !NInoWofCompressed(ni)))) vi->i_blocks = ni->itype.compressed.size >> 9; else vi->i_blocks = ni->allocated_size >> 9; diff --git a/fs/ntfs/inode.h b/fs/ntfs/inode.h index c6d065aaecd5..943a2960f029 100644 --- a/fs/ntfs/inode.h +++ b/fs/ntfs/inode.h @@ -189,6 +189,9 @@ enum { NI_NonResident, NI_IndexAllocPresent, NI_Compressed, +#ifdef CONFIG_NTFS_FS_WOF_COMPRESSION + NI_WofCompressed, +#endif NI_Encrypted, NI_Sparse, NI_SparseDisabled, @@ -248,6 +251,14 @@ NINO_FNS(MstProtected) NINO_FNS(NonResident) NINO_FNS(IndexAllocPresent) NINO_FNS(Compressed) +#ifdef CONFIG_NTFS_FS_WOF_COMPRESSION +NINO_FNS(WofCompressed) +#else +static inline int NInoWofCompressed(struct ntfs_inode *ni) +{ + return 0; +} +#endif NINO_FNS(Encrypted) NINO_FNS(Sparse) NINO_FNS(SparseDisabled) diff --git a/fs/ntfs/reparse.c b/fs/ntfs/reparse.c index 0d3988992119..8269fab33f38 100644 --- a/fs/ntfs/reparse.c +++ b/fs/ntfs/reparse.c @@ -24,6 +24,27 @@ struct wsl_link_reparse_data { char link[]; }; +#ifdef CONFIG_NTFS_FS_WOF_COMPRESSION +struct wof_reparse_data { + __le32 version; + __le32 provider; + __le32 provider_version; + __le32 compression_format; +} __packed; + +#define WOF_CURRENT_VERSION cpu_to_le32(1) + +#define WOF_PROVIDER_WIM cpu_to_le32(1) +#define WOF_PROVIDER_FILE cpu_to_le32(2) + +#define WOF_PROVIDER_CURRENT_VERSION cpu_to_le32(1) + +#define WOF_COMPRESSION_XPRESS4K cpu_to_le32(0) +#define WOF_COMPRESSION_LZX cpu_to_le32(1) +#define WOF_COMPRESSION_XPRESS8K cpu_to_le32(2) +#define WOF_COMPRESSION_XPRESS16K cpu_to_le32(3) +#endif + static bool reparse_name_is_valid(size_t size, size_t name_off, u16 len) { if ((name_off | len) & 1) @@ -203,6 +224,30 @@ static bool valid_reparse_data(struct ntfs_inode *ni, !(ni->flags & FILE_ATTRIBUTE_RECALL_ON_OPEN)) return false; break; +#ifdef CONFIG_NTFS_FS_WOF_COMPRESSION + case IO_REPARSE_TAG_WOF: { + const struct wof_reparse_data *wof_data = + (const struct wof_reparse_data *)reparse_attr->reparse_data; + + if (!valid_reparse_buffer(ni, reparse_attr, size, + sizeof(struct wof_reparse_data))) + return false; + + if (le16_to_cpu(reparse_attr->reparse_data_length) < + sizeof(struct wof_reparse_data) || + wof_data->version != WOF_CURRENT_VERSION || + wof_data->provider != WOF_PROVIDER_FILE || + wof_data->provider_version != + WOF_PROVIDER_CURRENT_VERSION) + return false; + if (wof_data->compression_format != WOF_COMPRESSION_XPRESS4K && + wof_data->compression_format != WOF_COMPRESSION_XPRESS8K && + wof_data->compression_format != WOF_COMPRESSION_XPRESS16K && + wof_data->compression_format != WOF_COMPRESSION_LZX) + return false; + break; + } +#endif default: if (!valid_reparse_buffer(ni, reparse_attr, size, 0)) return false; @@ -239,9 +284,9 @@ static unsigned int ntfs_reparse_tag_mode(__le32 reparse_tag) } /* - * Get the target for symbolic link + * Parse reparse point data and initialize its in-memory representation. */ -unsigned int ntfs_make_symlink(struct ntfs_inode *ni) +unsigned int ntfs_parse_reparse(struct ntfs_inode *ni) { s64 attr_size = 0; int err; @@ -306,6 +351,34 @@ unsigned int ntfs_make_symlink(struct ntfs_inode *ni) } break; } +#ifdef CONFIG_NTFS_FS_WOF_COMPRESSION + case IO_REPARSE_TAG_WOF: + { + const struct wof_reparse_data *wof_data = + (const struct wof_reparse_data *)reparse_attr->reparse_data; + + switch (wof_data->compression_format) { + case WOF_COMPRESSION_XPRESS4K: + ni->itype.compressed.block_size_bits = 12; + break; + case WOF_COMPRESSION_XPRESS8K: + ni->itype.compressed.block_size_bits = 13; + break; + case WOF_COMPRESSION_XPRESS16K: + ni->itype.compressed.block_size_bits = 14; + break; + case WOF_COMPRESSION_LZX: + ni->itype.compressed.block_size_bits = 15; + break; + } + ni->itype.compressed.block_size = + 1 << ni->itype.compressed.block_size_bits; + NInoSetWofCompressed(ni); + VFS_I(ni)->i_mode &= ~0222; + err = 0; + break; + } +#endif default: err = 0; } diff --git a/fs/ntfs/reparse.h b/fs/ntfs/reparse.h index c11a5bb7e6a5..3bd30cb36561 100644 --- a/fs/ntfs/reparse.h +++ b/fs/ntfs/reparse.h @@ -9,7 +9,7 @@ extern __le16 reparse_index_name[]; -unsigned int ntfs_make_symlink(struct ntfs_inode *ni); +unsigned int ntfs_parse_reparse(struct ntfs_inode *ni); unsigned int ntfs_reparse_tag_dt_types(struct ntfs_volume *vol, unsigned long mref); int ntfs_translate_symlink_path(struct dentry *dentry, const char *target, char **translated); -- 2.43.0