[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.