mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 03:15:31 +09:00
cifs: Query EA $LXMOD in cifs_query_path_info() for WSL reparse points
[ Upstream commit 057ac50638bcece64b3b436d3a61b70ed6c01a34 ]
EA $LXMOD is required for WSL non-symlink reparse points.
Fixes: ef86ab131d91 ("cifs: Fix querying of WSL CHR and BLK reparse points over SMB1")
Signed-off-by: Pali Rohár <pali@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
a133e2699f
commit
436cfdbc57
@@ -671,14 +671,72 @@ static int cifs_query_path_info(const unsigned int xid,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_XATTR
|
||||
/*
|
||||
* For non-symlink WSL reparse points it is required to fetch
|
||||
* EA $LXMOD which contains in its S_DT part the mandatory file type.
|
||||
*/
|
||||
if (!rc && data->reparse_point) {
|
||||
struct smb2_file_full_ea_info *ea;
|
||||
u32 next = 0;
|
||||
|
||||
ea = (struct smb2_file_full_ea_info *)data->wsl.eas;
|
||||
do {
|
||||
ea = (void *)((u8 *)ea + next);
|
||||
next = le32_to_cpu(ea->next_entry_offset);
|
||||
} while (next);
|
||||
if (le16_to_cpu(ea->ea_value_length)) {
|
||||
ea->next_entry_offset = cpu_to_le32(ALIGN(sizeof(*ea) +
|
||||
ea->ea_name_length + 1 +
|
||||
le16_to_cpu(ea->ea_value_length), 4));
|
||||
ea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
|
||||
}
|
||||
|
||||
rc = CIFSSMBQAllEAs(xid, tcon, full_path, SMB2_WSL_XATTR_MODE,
|
||||
&ea->ea_data[SMB2_WSL_XATTR_NAME_LEN + 1],
|
||||
SMB2_WSL_XATTR_MODE_SIZE, cifs_sb);
|
||||
if (rc == SMB2_WSL_XATTR_MODE_SIZE) {
|
||||
ea->next_entry_offset = cpu_to_le32(0);
|
||||
ea->flags = 0;
|
||||
ea->ea_name_length = SMB2_WSL_XATTR_NAME_LEN;
|
||||
ea->ea_value_length = cpu_to_le16(SMB2_WSL_XATTR_MODE_SIZE);
|
||||
memcpy(&ea->ea_data[0], SMB2_WSL_XATTR_MODE, SMB2_WSL_XATTR_NAME_LEN + 1);
|
||||
data->wsl.eas_len += ALIGN(sizeof(*ea) + SMB2_WSL_XATTR_NAME_LEN + 1 +
|
||||
SMB2_WSL_XATTR_MODE_SIZE, 4);
|
||||
rc = 0;
|
||||
} else if (rc >= 0) {
|
||||
/* It is an error if EA $LXMOD has wrong size. */
|
||||
rc = -EINVAL;
|
||||
} else {
|
||||
/*
|
||||
* In all other cases ignore error if fetching
|
||||
* of EA $LXMOD failed. It is needed only for
|
||||
* non-symlink WSL reparse points and wsl_to_fattr()
|
||||
* handle the case when EA is missing.
|
||||
*/
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For WSL CHR and BLK reparse points it is required to fetch
|
||||
* EA $LXDEV which contains major and minor device numbers.
|
||||
*/
|
||||
if (!rc && data->reparse_point) {
|
||||
struct smb2_file_full_ea_info *ea;
|
||||
u32 next = 0;
|
||||
|
||||
ea = (struct smb2_file_full_ea_info *)data->wsl.eas;
|
||||
do {
|
||||
ea = (void *)((u8 *)ea + next);
|
||||
next = le32_to_cpu(ea->next_entry_offset);
|
||||
} while (next);
|
||||
if (le16_to_cpu(ea->ea_value_length)) {
|
||||
ea->next_entry_offset = cpu_to_le32(ALIGN(sizeof(*ea) +
|
||||
ea->ea_name_length + 1 +
|
||||
le16_to_cpu(ea->ea_value_length), 4));
|
||||
ea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
|
||||
}
|
||||
|
||||
rc = CIFSSMBQAllEAs(xid, tcon, full_path, SMB2_WSL_XATTR_DEV,
|
||||
&ea->ea_data[SMB2_WSL_XATTR_NAME_LEN + 1],
|
||||
SMB2_WSL_XATTR_DEV_SIZE, cifs_sb);
|
||||
@@ -688,8 +746,8 @@ static int cifs_query_path_info(const unsigned int xid,
|
||||
ea->ea_name_length = SMB2_WSL_XATTR_NAME_LEN;
|
||||
ea->ea_value_length = cpu_to_le16(SMB2_WSL_XATTR_DEV_SIZE);
|
||||
memcpy(&ea->ea_data[0], SMB2_WSL_XATTR_DEV, SMB2_WSL_XATTR_NAME_LEN + 1);
|
||||
data->wsl.eas_len = sizeof(*ea) + SMB2_WSL_XATTR_NAME_LEN + 1 +
|
||||
SMB2_WSL_XATTR_DEV_SIZE;
|
||||
data->wsl.eas_len += ALIGN(sizeof(*ea) + SMB2_WSL_XATTR_NAME_LEN + 1 +
|
||||
SMB2_WSL_XATTR_MODE_SIZE, 4);
|
||||
rc = 0;
|
||||
} else if (rc >= 0) {
|
||||
/* It is an error if EA $LXDEV has wrong size. */
|
||||
|
||||
Reference in New Issue
Block a user