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