2626#include "cached_dir.h"
2727#include "smb2status.h"
2828
29+ static struct reparse_data_buffer * reparse_buf_ptr (struct kvec * iov )
30+ {
31+ struct reparse_data_buffer * buf ;
32+ struct smb2_ioctl_rsp * io = iov -> iov_base ;
33+ u32 off , count , len ;
34+
35+ count = le32_to_cpu (io -> OutputCount );
36+ off = le32_to_cpu (io -> OutputOffset );
37+ if (check_add_overflow (off , count , & len ) || len > iov -> iov_len )
38+ return ERR_PTR (- EIO );
39+
40+ buf = (struct reparse_data_buffer * )((u8 * )io + off );
41+ len = sizeof (* buf );
42+ if (count < len || count < le16_to_cpu (buf -> ReparseDataLength ) + len )
43+ return ERR_PTR (- EIO );
44+ return buf ;
45+ }
46+
2947/*
3048 * note: If cfile is passed, the reference to it is dropped here.
3149 * So make sure that you do not reuse cfile after return from this func.
@@ -42,8 +60,10 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
4260 __u8 * * extbuf , size_t * extbuflen ,
4361 struct kvec * out_iov , int * out_buftype )
4462{
63+
64+ struct reparse_data_buffer * rbuf ;
4565 struct smb2_compound_vars * vars = NULL ;
46- struct kvec * rsp_iov ;
66+ struct kvec * rsp_iov , * iov ;
4767 struct smb_rqst * rqst ;
4868 int rc ;
4969 __le16 * utf16_path = NULL ;
@@ -363,6 +383,21 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
363383 trace_smb3_set_reparse_compound_enter (xid , ses -> Suid ,
364384 tcon -> tid , full_path );
365385 break ;
386+ case SMB2_OP_GET_REPARSE :
387+ rqst [num_rqst ].rq_iov = vars -> io_iov ;
388+ rqst [num_rqst ].rq_nvec = ARRAY_SIZE (vars -> io_iov );
389+
390+ rc = SMB2_ioctl_init (tcon , server , & rqst [num_rqst ],
391+ COMPOUND_FID , COMPOUND_FID ,
392+ FSCTL_GET_REPARSE_POINT ,
393+ NULL , 0 , CIFSMaxBufSize );
394+ if (rc )
395+ goto finished ;
396+ smb2_set_next_command (tcon , & rqst [num_rqst ]);
397+ smb2_set_related (& rqst [num_rqst ++ ]);
398+ trace_smb3_get_reparse_compound_enter (xid , ses -> Suid ,
399+ tcon -> tid , full_path );
400+ break ;
366401 default :
367402 cifs_dbg (VFS , "Invalid command\n" );
368403 rc = - EINVAL ;
@@ -529,6 +564,30 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
529564 }
530565 SMB2_ioctl_free (& rqst [num_rqst ++ ]);
531566 break ;
567+ case SMB2_OP_GET_REPARSE :
568+ if (!rc ) {
569+ iov = & rsp_iov [i + 1 ];
570+ idata = in_iov [i ].iov_base ;
571+ idata -> reparse .io .iov = * iov ;
572+ idata -> reparse .io .buftype = resp_buftype [i + 1 ];
573+ rbuf = reparse_buf_ptr (iov );
574+ if (IS_ERR (rbuf )) {
575+ rc = PTR_ERR (rbuf );
576+ trace_smb3_set_reparse_compound_err (xid , ses -> Suid ,
577+ tcon -> tid , rc );
578+ } else {
579+ idata -> reparse .tag = le32_to_cpu (rbuf -> ReparseTag );
580+ trace_smb3_set_reparse_compound_done (xid , ses -> Suid ,
581+ tcon -> tid );
582+ }
583+ memset (iov , 0 , sizeof (* iov ));
584+ resp_buftype [i + 1 ] = CIFS_NO_BUFFER ;
585+ } else {
586+ trace_smb3_set_reparse_compound_err (xid , ses -> Suid ,
587+ tcon -> tid , rc );
588+ }
589+ SMB2_ioctl_free (& rqst [num_rqst ++ ]);
590+ break ;
532591 }
533592 }
534593 SMB2_close_free (& rqst [num_rqst ]);
@@ -589,10 +648,11 @@ int smb2_query_path_info(const unsigned int xid,
589648 struct cifsFileInfo * cfile ;
590649 struct cached_fid * cfid = NULL ;
591650 struct smb2_hdr * hdr ;
592- struct kvec in_iov , out_iov [3 ] = {};
651+ struct kvec in_iov [ 2 ] , out_iov [3 ] = {};
593652 int out_buftype [3 ] = {};
653+ int cmds [2 ] = { SMB2_OP_QUERY_INFO , };
594654 bool islink ;
595- int cmd = SMB2_OP_QUERY_INFO ;
655+ int i , num_cmds ;
596656 int rc , rc2 ;
597657
598658 data -> adjust_tz = false;
@@ -614,14 +674,16 @@ int smb2_query_path_info(const unsigned int xid,
614674 return rc ;
615675 }
616676
617- in_iov .iov_base = data ;
618- in_iov .iov_len = sizeof (* data );
677+ in_iov [0 ].iov_base = data ;
678+ in_iov [0 ].iov_len = sizeof (* data );
679+ in_iov [1 ] = in_iov [0 ];
619680
620681 cifs_get_readable_path (tcon , full_path , & cfile );
621682 rc = smb2_compound_op (xid , tcon , cifs_sb , full_path ,
622683 FILE_READ_ATTRIBUTES , FILE_OPEN ,
623- create_options , ACL_NO_MODE , & in_iov ,
624- & cmd , 1 , cfile , NULL , NULL , out_iov , out_buftype );
684+ create_options , ACL_NO_MODE ,
685+ in_iov , cmds , 1 , cfile ,
686+ NULL , NULL , out_iov , out_buftype );
625687 hdr = out_iov [0 ].iov_base ;
626688 /*
627689 * If first iov is unset, then SMB session was dropped or we've got a
@@ -637,13 +699,19 @@ int smb2_query_path_info(const unsigned int xid,
637699 if (rc || !data -> reparse_point )
638700 goto out ;
639701
702+ if (data -> reparse .tag == IO_REPARSE_TAG_SYMLINK ) {
703+ /* symlink already parsed in create response */
704+ num_cmds = 1 ;
705+ } else {
706+ cmds [1 ] = SMB2_OP_GET_REPARSE ;
707+ num_cmds = 2 ;
708+ }
640709 create_options |= OPEN_REPARSE_POINT ;
641- /* Failed on a symbolic link - query a reparse point info */
642710 cifs_get_readable_path (tcon , full_path , & cfile );
643711 rc = smb2_compound_op (xid , tcon , cifs_sb , full_path ,
644712 FILE_READ_ATTRIBUTES , FILE_OPEN ,
645- create_options , ACL_NO_MODE , & in_iov ,
646- & cmd , 1 , cfile , NULL , NULL , NULL , NULL );
713+ create_options , ACL_NO_MODE , in_iov , cmds ,
714+ num_cmds , cfile , NULL , NULL , NULL , NULL );
647715 break ;
648716 case - EREMOTE :
649717 break ;
@@ -661,9 +729,8 @@ int smb2_query_path_info(const unsigned int xid,
661729 }
662730
663731out :
664- free_rsp_buf (out_buftype [0 ], out_iov [0 ].iov_base );
665- free_rsp_buf (out_buftype [1 ], out_iov [1 ].iov_base );
666- free_rsp_buf (out_buftype [2 ], out_iov [2 ].iov_base );
732+ for (i = 0 ; i < ARRAY_SIZE (out_buftype ); i ++ )
733+ free_rsp_buf (out_buftype [i ], out_iov [i ].iov_base );
667734 return rc ;
668735}
669736
@@ -678,13 +745,14 @@ int smb311_posix_query_path_info(const unsigned int xid,
678745 int rc ;
679746 __u32 create_options = 0 ;
680747 struct cifsFileInfo * cfile ;
681- struct kvec in_iov , out_iov [3 ] = {};
748+ struct kvec in_iov [ 2 ] , out_iov [3 ] = {};
682749 int out_buftype [3 ] = {};
683750 __u8 * sidsbuf = NULL ;
684751 __u8 * sidsbuf_end = NULL ;
685752 size_t sidsbuflen = 0 ;
686753 size_t owner_len , group_len ;
687- int cmd = SMB2_OP_POSIX_QUERY_INFO ;
754+ int cmds [2 ] = { SMB2_OP_POSIX_QUERY_INFO , };
755+ int i , num_cmds ;
688756
689757 data -> adjust_tz = false;
690758 data -> reparse_point = false;
@@ -695,13 +763,14 @@ int smb311_posix_query_path_info(const unsigned int xid,
695763 * when we already have an open file handle for this. For now this is fast enough
696764 * (always using the compounded version).
697765 */
698- in_iov .iov_base = data ;
699- in_iov .iov_len = sizeof (* data );
766+ in_iov [0 ].iov_base = data ;
767+ in_iov [0 ].iov_len = sizeof (* data );
768+ in_iov [1 ] = in_iov [0 ];
700769
701770 cifs_get_readable_path (tcon , full_path , & cfile );
702771 rc = smb2_compound_op (xid , tcon , cifs_sb , full_path ,
703772 FILE_READ_ATTRIBUTES , FILE_OPEN ,
704- create_options , ACL_NO_MODE , & in_iov , & cmd , 1 ,
773+ create_options , ACL_NO_MODE , in_iov , cmds , 1 ,
705774 cfile , & sidsbuf , & sidsbuflen , out_iov , out_buftype );
706775 /*
707776 * If first iov is unset, then SMB session was dropped or we've got a
@@ -718,13 +787,19 @@ int smb311_posix_query_path_info(const unsigned int xid,
718787 if (rc || !data -> reparse_point )
719788 goto out ;
720789
790+ if (data -> reparse .tag == IO_REPARSE_TAG_SYMLINK ) {
791+ /* symlink already parsed in create response */
792+ num_cmds = 1 ;
793+ } else {
794+ cmds [1 ] = SMB2_OP_GET_REPARSE ;
795+ num_cmds = 2 ;
796+ }
721797 create_options |= OPEN_REPARSE_POINT ;
722- /* Failed on a symbolic link - query a reparse point info */
723798 cifs_get_readable_path (tcon , full_path , & cfile );
724799 rc = smb2_compound_op (xid , tcon , cifs_sb , full_path ,
725800 FILE_READ_ATTRIBUTES , FILE_OPEN ,
726- create_options , ACL_NO_MODE , & in_iov , & cmd , 1 ,
727- cfile , & sidsbuf , & sidsbuflen , NULL , NULL );
801+ create_options , ACL_NO_MODE , in_iov , cmds ,
802+ num_cmds , cfile , & sidsbuf , & sidsbuflen , NULL , NULL );
728803 break ;
729804 }
730805
@@ -749,9 +824,8 @@ int smb311_posix_query_path_info(const unsigned int xid,
749824 }
750825
751826 kfree (sidsbuf );
752- free_rsp_buf (out_buftype [0 ], out_iov [0 ].iov_base );
753- free_rsp_buf (out_buftype [1 ], out_iov [1 ].iov_base );
754- free_rsp_buf (out_buftype [2 ], out_iov [2 ].iov_base );
827+ for (i = 0 ; i < ARRAY_SIZE (out_buftype ); i ++ )
828+ free_rsp_buf (out_buftype [i ], out_iov [i ].iov_base );
755829 return rc ;
756830}
757831
0 commit comments