@@ -3034,6 +3034,133 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
30343034 return rc ;
30353035}
30363036
3037+ int
3038+ smb2_query_reparse_tag (const unsigned int xid , struct cifs_tcon * tcon ,
3039+ struct cifs_sb_info * cifs_sb , const char * full_path ,
3040+ __u32 * tag )
3041+ {
3042+ int rc ;
3043+ __le16 * utf16_path = NULL ;
3044+ __u8 oplock = SMB2_OPLOCK_LEVEL_NONE ;
3045+ struct cifs_open_parms oparms ;
3046+ struct cifs_fid fid ;
3047+ struct TCP_Server_Info * server = cifs_pick_channel (tcon -> ses );
3048+ int flags = 0 ;
3049+ struct smb_rqst rqst [3 ];
3050+ int resp_buftype [3 ];
3051+ struct kvec rsp_iov [3 ];
3052+ struct kvec open_iov [SMB2_CREATE_IOV_SIZE ];
3053+ struct kvec io_iov [SMB2_IOCTL_IOV_SIZE ];
3054+ struct kvec close_iov [1 ];
3055+ struct smb2_ioctl_rsp * ioctl_rsp ;
3056+ struct reparse_data_buffer * reparse_buf ;
3057+ u32 plen ;
3058+
3059+ cifs_dbg (FYI , "%s: path: %s\n" , __func__ , full_path );
3060+
3061+ if (smb3_encryption_required (tcon ))
3062+ flags |= CIFS_TRANSFORM_REQ ;
3063+
3064+ memset (rqst , 0 , sizeof (rqst ));
3065+ resp_buftype [0 ] = resp_buftype [1 ] = resp_buftype [2 ] = CIFS_NO_BUFFER ;
3066+ memset (rsp_iov , 0 , sizeof (rsp_iov ));
3067+
3068+ utf16_path = cifs_convert_path_to_utf16 (full_path , cifs_sb );
3069+ if (!utf16_path )
3070+ return - ENOMEM ;
3071+
3072+ /*
3073+ * setup smb2open - TODO add optimization to call cifs_get_readable_path
3074+ * to see if there is a handle already open that we can use
3075+ */
3076+ memset (& open_iov , 0 , sizeof (open_iov ));
3077+ rqst [0 ].rq_iov = open_iov ;
3078+ rqst [0 ].rq_nvec = SMB2_CREATE_IOV_SIZE ;
3079+
3080+ memset (& oparms , 0 , sizeof (oparms ));
3081+ oparms .tcon = tcon ;
3082+ oparms .desired_access = FILE_READ_ATTRIBUTES ;
3083+ oparms .disposition = FILE_OPEN ;
3084+ oparms .create_options = cifs_create_options (cifs_sb , OPEN_REPARSE_POINT );
3085+ oparms .fid = & fid ;
3086+ oparms .reconnect = false;
3087+
3088+ rc = SMB2_open_init (tcon , server ,
3089+ & rqst [0 ], & oplock , & oparms , utf16_path );
3090+ if (rc )
3091+ goto query_rp_exit ;
3092+ smb2_set_next_command (tcon , & rqst [0 ]);
3093+
3094+
3095+ /* IOCTL */
3096+ memset (& io_iov , 0 , sizeof (io_iov ));
3097+ rqst [1 ].rq_iov = io_iov ;
3098+ rqst [1 ].rq_nvec = SMB2_IOCTL_IOV_SIZE ;
3099+
3100+ rc = SMB2_ioctl_init (tcon , server ,
3101+ & rqst [1 ], fid .persistent_fid ,
3102+ fid .volatile_fid , FSCTL_GET_REPARSE_POINT ,
3103+ true /* is_fctl */ , NULL , 0 ,
3104+ CIFSMaxBufSize -
3105+ MAX_SMB2_CREATE_RESPONSE_SIZE -
3106+ MAX_SMB2_CLOSE_RESPONSE_SIZE );
3107+ if (rc )
3108+ goto query_rp_exit ;
3109+
3110+ smb2_set_next_command (tcon , & rqst [1 ]);
3111+ smb2_set_related (& rqst [1 ]);
3112+
3113+
3114+ /* Close */
3115+ memset (& close_iov , 0 , sizeof (close_iov ));
3116+ rqst [2 ].rq_iov = close_iov ;
3117+ rqst [2 ].rq_nvec = 1 ;
3118+
3119+ rc = SMB2_close_init (tcon , server ,
3120+ & rqst [2 ], COMPOUND_FID , COMPOUND_FID , false);
3121+ if (rc )
3122+ goto query_rp_exit ;
3123+
3124+ smb2_set_related (& rqst [2 ]);
3125+
3126+ rc = compound_send_recv (xid , tcon -> ses , server ,
3127+ flags , 3 , rqst ,
3128+ resp_buftype , rsp_iov );
3129+
3130+ ioctl_rsp = rsp_iov [1 ].iov_base ;
3131+
3132+ /*
3133+ * Open was successful and we got an ioctl response.
3134+ */
3135+ if (rc == 0 ) {
3136+ /* See MS-FSCC 2.3.23 */
3137+
3138+ reparse_buf = (struct reparse_data_buffer * )
3139+ ((char * )ioctl_rsp +
3140+ le32_to_cpu (ioctl_rsp -> OutputOffset ));
3141+ plen = le32_to_cpu (ioctl_rsp -> OutputCount );
3142+
3143+ if (plen + le32_to_cpu (ioctl_rsp -> OutputOffset ) >
3144+ rsp_iov [1 ].iov_len ) {
3145+ cifs_tcon_dbg (FYI , "srv returned invalid ioctl len: %d\n" ,
3146+ plen );
3147+ rc = - EIO ;
3148+ goto query_rp_exit ;
3149+ }
3150+ * tag = le32_to_cpu (reparse_buf -> ReparseTag );
3151+ }
3152+
3153+ query_rp_exit :
3154+ kfree (utf16_path );
3155+ SMB2_open_free (& rqst [0 ]);
3156+ SMB2_ioctl_free (& rqst [1 ]);
3157+ SMB2_close_free (& rqst [2 ]);
3158+ free_rsp_buf (resp_buftype [0 ], rsp_iov [0 ].iov_base );
3159+ free_rsp_buf (resp_buftype [1 ], rsp_iov [1 ].iov_base );
3160+ free_rsp_buf (resp_buftype [2 ], rsp_iov [2 ].iov_base );
3161+ return rc ;
3162+ }
3163+
30373164static struct cifs_ntsd *
30383165get_smb2_acl_by_fid (struct cifs_sb_info * cifs_sb ,
30393166 const struct cifs_fid * cifsfid , u32 * pacllen )
@@ -4986,6 +5113,8 @@ struct smb_version_operations smb30_operations = {
49865113 .can_echo = smb2_can_echo ,
49875114 .echo = SMB2_echo ,
49885115 .query_path_info = smb2_query_path_info ,
5116+ /* WSL tags introduced long after smb2.1, enable for SMB3, 3.11 only */
5117+ .query_reparse_tag = smb2_query_reparse_tag ,
49895118 .get_srv_inum = smb2_get_srv_inum ,
49905119 .query_file_info = smb2_query_file_info ,
49915120 .set_path_size = smb2_set_path_size ,
@@ -5097,6 +5226,7 @@ struct smb_version_operations smb311_operations = {
50975226 .can_echo = smb2_can_echo ,
50985227 .echo = SMB2_echo ,
50995228 .query_path_info = smb2_query_path_info ,
5229+ .query_reparse_tag = smb2_query_reparse_tag ,
51005230 .get_srv_inum = smb2_get_srv_inum ,
51015231 .query_file_info = smb2_query_file_info ,
51025232 .set_path_size = smb2_set_path_size ,
0 commit comments