Skip to content

Commit 057ac50

Browse files
palismfrench
authored andcommitted
cifs: Query EA $LXMOD in cifs_query_path_info() for WSL reparse points
EA $LXMOD is required for WSL non-symlink reparse points. Fixes: ef86ab1 ("cifs: Fix querying of WSL CHR and BLK reparse points over SMB1") Signed-off-by: Pali Rohár <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 7ae6152 commit 057ac50

File tree

1 file changed

+60
-2
lines changed

1 file changed

+60
-2
lines changed

fs/smb/client/smb1ops.c

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -651,14 +651,72 @@ static int cifs_query_path_info(const unsigned int xid,
651651
}
652652

653653
#ifdef CONFIG_CIFS_XATTR
654+
/*
655+
* For non-symlink WSL reparse points it is required to fetch
656+
* EA $LXMOD which contains in its S_DT part the mandatory file type.
657+
*/
658+
if (!rc && data->reparse_point) {
659+
struct smb2_file_full_ea_info *ea;
660+
u32 next = 0;
661+
662+
ea = (struct smb2_file_full_ea_info *)data->wsl.eas;
663+
do {
664+
ea = (void *)((u8 *)ea + next);
665+
next = le32_to_cpu(ea->next_entry_offset);
666+
} while (next);
667+
if (le16_to_cpu(ea->ea_value_length)) {
668+
ea->next_entry_offset = cpu_to_le32(ALIGN(sizeof(*ea) +
669+
ea->ea_name_length + 1 +
670+
le16_to_cpu(ea->ea_value_length), 4));
671+
ea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
672+
}
673+
674+
rc = CIFSSMBQAllEAs(xid, tcon, full_path, SMB2_WSL_XATTR_MODE,
675+
&ea->ea_data[SMB2_WSL_XATTR_NAME_LEN + 1],
676+
SMB2_WSL_XATTR_MODE_SIZE, cifs_sb);
677+
if (rc == SMB2_WSL_XATTR_MODE_SIZE) {
678+
ea->next_entry_offset = cpu_to_le32(0);
679+
ea->flags = 0;
680+
ea->ea_name_length = SMB2_WSL_XATTR_NAME_LEN;
681+
ea->ea_value_length = cpu_to_le16(SMB2_WSL_XATTR_MODE_SIZE);
682+
memcpy(&ea->ea_data[0], SMB2_WSL_XATTR_MODE, SMB2_WSL_XATTR_NAME_LEN + 1);
683+
data->wsl.eas_len += ALIGN(sizeof(*ea) + SMB2_WSL_XATTR_NAME_LEN + 1 +
684+
SMB2_WSL_XATTR_MODE_SIZE, 4);
685+
rc = 0;
686+
} else if (rc >= 0) {
687+
/* It is an error if EA $LXMOD has wrong size. */
688+
rc = -EINVAL;
689+
} else {
690+
/*
691+
* In all other cases ignore error if fetching
692+
* of EA $LXMOD failed. It is needed only for
693+
* non-symlink WSL reparse points and wsl_to_fattr()
694+
* handle the case when EA is missing.
695+
*/
696+
rc = 0;
697+
}
698+
}
699+
654700
/*
655701
* For WSL CHR and BLK reparse points it is required to fetch
656702
* EA $LXDEV which contains major and minor device numbers.
657703
*/
658704
if (!rc && data->reparse_point) {
659705
struct smb2_file_full_ea_info *ea;
706+
u32 next = 0;
660707

661708
ea = (struct smb2_file_full_ea_info *)data->wsl.eas;
709+
do {
710+
ea = (void *)((u8 *)ea + next);
711+
next = le32_to_cpu(ea->next_entry_offset);
712+
} while (next);
713+
if (le16_to_cpu(ea->ea_value_length)) {
714+
ea->next_entry_offset = cpu_to_le32(ALIGN(sizeof(*ea) +
715+
ea->ea_name_length + 1 +
716+
le16_to_cpu(ea->ea_value_length), 4));
717+
ea = (void *)((u8 *)ea + le32_to_cpu(ea->next_entry_offset));
718+
}
719+
662720
rc = CIFSSMBQAllEAs(xid, tcon, full_path, SMB2_WSL_XATTR_DEV,
663721
&ea->ea_data[SMB2_WSL_XATTR_NAME_LEN + 1],
664722
SMB2_WSL_XATTR_DEV_SIZE, cifs_sb);
@@ -668,8 +726,8 @@ static int cifs_query_path_info(const unsigned int xid,
668726
ea->ea_name_length = SMB2_WSL_XATTR_NAME_LEN;
669727
ea->ea_value_length = cpu_to_le16(SMB2_WSL_XATTR_DEV_SIZE);
670728
memcpy(&ea->ea_data[0], SMB2_WSL_XATTR_DEV, SMB2_WSL_XATTR_NAME_LEN + 1);
671-
data->wsl.eas_len = sizeof(*ea) + SMB2_WSL_XATTR_NAME_LEN + 1 +
672-
SMB2_WSL_XATTR_DEV_SIZE;
729+
data->wsl.eas_len += ALIGN(sizeof(*ea) + SMB2_WSL_XATTR_NAME_LEN + 1 +
730+
SMB2_WSL_XATTR_MODE_SIZE, 4);
673731
rc = 0;
674732
} else if (rc >= 0) {
675733
/* It is an error if EA $LXDEV has wrong size. */

0 commit comments

Comments
 (0)