@@ -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