@@ -542,6 +542,33 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
542542 return rc ;
543543}
544544
545+ static int parse_create_response (struct cifs_open_info_data * data ,
546+ struct cifs_sb_info * cifs_sb ,
547+ const struct kvec * iov )
548+ {
549+ struct smb2_create_rsp * rsp = iov -> iov_base ;
550+ bool reparse_point = false;
551+ u32 tag = 0 ;
552+ int rc = 0 ;
553+
554+ switch (rsp -> hdr .Status ) {
555+ case STATUS_STOPPED_ON_SYMLINK :
556+ rc = smb2_parse_symlink_response (cifs_sb , iov ,
557+ & data -> symlink_target );
558+ if (rc )
559+ return rc ;
560+ tag = IO_REPARSE_TAG_SYMLINK ;
561+ reparse_point = true;
562+ break ;
563+ case STATUS_SUCCESS :
564+ reparse_point = !!(rsp -> Flags & SMB2_CREATE_FLAG_REPARSEPOINT );
565+ break ;
566+ }
567+ data -> reparse_point = reparse_point ;
568+ data -> reparse_tag = tag ;
569+ return rc ;
570+ }
571+
545572int smb2_query_path_info (const unsigned int xid ,
546573 struct cifs_tcon * tcon ,
547574 struct cifs_sb_info * cifs_sb ,
@@ -551,6 +578,7 @@ int smb2_query_path_info(const unsigned int xid,
551578 __u32 create_options = 0 ;
552579 struct cifsFileInfo * cfile ;
553580 struct cached_fid * cfid = NULL ;
581+ struct smb2_hdr * hdr ;
554582 struct kvec out_iov [3 ] = {};
555583 int out_buftype [3 ] = {};
556584 bool islink ;
@@ -579,39 +607,43 @@ int smb2_query_path_info(const unsigned int xid,
579607 rc = smb2_compound_op (xid , tcon , cifs_sb , full_path , FILE_READ_ATTRIBUTES , FILE_OPEN ,
580608 create_options , ACL_NO_MODE , data , SMB2_OP_QUERY_INFO , cfile ,
581609 NULL , NULL , out_iov , out_buftype );
582- if (rc ) {
583- struct smb2_hdr * hdr = out_iov [0 ].iov_base ;
584-
585- if (unlikely (!hdr || out_buftype [0 ] == CIFS_NO_BUFFER ))
610+ hdr = out_iov [0 ].iov_base ;
611+ /*
612+ * If first iov is unset, then SMB session was dropped or we've got a
613+ * cached open file (@cfile).
614+ */
615+ if (!hdr || out_buftype [0 ] == CIFS_NO_BUFFER )
616+ goto out ;
617+
618+ switch (rc ) {
619+ case 0 :
620+ case - EOPNOTSUPP :
621+ rc = parse_create_response (data , cifs_sb , & out_iov [0 ]);
622+ if (rc || !data -> reparse_point )
586623 goto out ;
587- if (rc == - EOPNOTSUPP && hdr -> Command == SMB2_CREATE &&
588- hdr -> Status == STATUS_STOPPED_ON_SYMLINK ) {
589- rc = smb2_parse_symlink_response (cifs_sb , out_iov ,
590- & data -> symlink_target );
591- if (rc )
592- goto out ;
593-
594- data -> reparse_point = true;
595- create_options |= OPEN_REPARSE_POINT ;
596-
597- /* Failed on a symbolic link - query a reparse point info */
598- cifs_get_readable_path (tcon , full_path , & cfile );
599- rc = smb2_compound_op (xid , tcon , cifs_sb , full_path ,
600- FILE_READ_ATTRIBUTES , FILE_OPEN ,
601- create_options , ACL_NO_MODE , data ,
602- SMB2_OP_QUERY_INFO , cfile , NULL , NULL ,
603- NULL , NULL );
624+
625+ create_options |= OPEN_REPARSE_POINT ;
626+ /* Failed on a symbolic link - query a reparse point info */
627+ cifs_get_readable_path (tcon , full_path , & cfile );
628+ rc = smb2_compound_op (xid , tcon , cifs_sb , full_path ,
629+ FILE_READ_ATTRIBUTES , FILE_OPEN ,
630+ create_options , ACL_NO_MODE , data ,
631+ SMB2_OP_QUERY_INFO , cfile , NULL , NULL ,
632+ NULL , NULL );
633+ break ;
634+ case - EREMOTE :
635+ break ;
636+ default :
637+ if (hdr -> Status != STATUS_OBJECT_NAME_INVALID )
638+ break ;
639+ rc2 = cifs_inval_name_dfs_link_error (xid , tcon , cifs_sb ,
640+ full_path , & islink );
641+ if (rc2 ) {
642+ rc = rc2 ;
604643 goto out ;
605- } else if (rc != - EREMOTE && hdr -> Status == STATUS_OBJECT_NAME_INVALID ) {
606- rc2 = cifs_inval_name_dfs_link_error (xid , tcon , cifs_sb ,
607- full_path , & islink );
608- if (rc2 ) {
609- rc = rc2 ;
610- goto out ;
611- }
612- if (islink )
613- rc = - EREMOTE ;
614644 }
645+ if (islink )
646+ rc = - EREMOTE ;
615647 }
616648
617649out :
@@ -653,26 +685,32 @@ int smb311_posix_query_path_info(const unsigned int xid,
653685 rc = smb2_compound_op (xid , tcon , cifs_sb , full_path , FILE_READ_ATTRIBUTES , FILE_OPEN ,
654686 create_options , ACL_NO_MODE , data , SMB2_OP_POSIX_QUERY_INFO , cfile ,
655687 & sidsbuf , & sidsbuflen , out_iov , out_buftype );
656- if (rc == - EOPNOTSUPP ) {
688+ /*
689+ * If first iov is unset, then SMB session was dropped or we've got a
690+ * cached open file (@cfile).
691+ */
692+ if (!out_iov [0 ].iov_base || out_buftype [0 ] == CIFS_NO_BUFFER )
693+ goto out ;
694+
695+ switch (rc ) {
696+ case 0 :
697+ case - EOPNOTSUPP :
657698 /* BB TODO: When support for special files added to Samba re-verify this path */
658- if (out_iov [0 ].iov_base && out_buftype [0 ] != CIFS_NO_BUFFER &&
659- ((struct smb2_hdr * )out_iov [0 ].iov_base )-> Command == SMB2_CREATE &&
660- ((struct smb2_hdr * )out_iov [0 ].iov_base )-> Status == STATUS_STOPPED_ON_SYMLINK ) {
661- rc = smb2_parse_symlink_response (cifs_sb , out_iov , & data -> symlink_target );
662- if (rc )
663- goto out ;
664- }
665- data -> reparse_point = true;
666- create_options |= OPEN_REPARSE_POINT ;
699+ rc = parse_create_response (data , cifs_sb , & out_iov [0 ]);
700+ if (rc || !data -> reparse_point )
701+ goto out ;
667702
703+ create_options |= OPEN_REPARSE_POINT ;
668704 /* Failed on a symbolic link - query a reparse point info */
669705 cifs_get_readable_path (tcon , full_path , & cfile );
670706 rc = smb2_compound_op (xid , tcon , cifs_sb , full_path , FILE_READ_ATTRIBUTES ,
671707 FILE_OPEN , create_options , ACL_NO_MODE , data ,
672708 SMB2_OP_POSIX_QUERY_INFO , cfile ,
673709 & sidsbuf , & sidsbuflen , NULL , NULL );
710+ break ;
674711 }
675712
713+ out :
676714 if (rc == 0 ) {
677715 sidsbuf_end = sidsbuf + sidsbuflen ;
678716
@@ -692,7 +730,6 @@ int smb311_posix_query_path_info(const unsigned int xid,
692730 memcpy (group , sidsbuf + owner_len , group_len );
693731 }
694732
695- out :
696733 kfree (sidsbuf );
697734 free_rsp_buf (out_buftype [0 ], out_iov [0 ].iov_base );
698735 free_rsp_buf (out_buftype [1 ], out_iov [1 ].iov_base );
0 commit comments