mirror of
https://github.com/torvalds/linux.git
synced 2026-10-06 10:36:03 +02:00
smb/client: decode reparse metadata using its payload type
cifs_open_info_data stores FILE_ALL_INFORMATION and SMB3 POSIX query
information in a union. reparse_info_to_fattr() selects a union member
from the mount mode, while several directory checks always read
fi.Attributes.
The metadata can instead come from an SMB2 CREATE response on a POSIX
mount, or from a POSIX query while processing a reparse point. In those
cases the mount mode and hard-coded fi accesses select the wrong union
member.
See the procedures below:
cifs_nt_open
smb2_open_file
SMB2_open
data->fi = SMB2 CREATE response
data->contains_posix_file_info = false
cifs_get_inode_info
reparse_info_to_fattr
if (tcon->posix_extensions) // true
smb311_posix_info_to_fattr
data->posix_fi // wrong union member
smb311_posix_get_fattr
smb2_query_path_info
smb2_compound_op
data->posix_fi = SMB3 POSIX query response
data->contains_posix_file_info = true
reparse_info_to_fattr
data->fi.Attributes // wrong union member
Add a common DOS attribute accessor and use contains_posix_file_info
both for attribute reads and for the final fattr conversion.
Signed-off-by: Ze Tan <tanze@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Paulo Alcantara <pc@manguebit.org>
This commit is contained in:
parent
9437f2113b
commit
43549eb842
|
|
@ -1215,7 +1215,7 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data,
|
|||
break;
|
||||
case IO_REPARSE_TAG_INTERNAL:
|
||||
rc = 0;
|
||||
if (le32_to_cpu(data->fi.Attributes) & ATTR_DIRECTORY) {
|
||||
if (cifs_open_data_attrs(data) & ATTR_DIRECTORY) {
|
||||
cifs_create_junction_fattr(fattr, sb);
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -1239,7 +1239,7 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data,
|
|||
*/
|
||||
if (rc == -EOPNOTSUPP &&
|
||||
IS_REPARSE_TAG_NAME_SURROGATE(data->reparse.tag) &&
|
||||
(le32_to_cpu(data->fi.Attributes) & ATTR_DIRECTORY)) {
|
||||
(cifs_open_data_attrs(data) & ATTR_DIRECTORY)) {
|
||||
rc = 0;
|
||||
cifs_create_junction_fattr(fattr, sb);
|
||||
goto out;
|
||||
|
|
@ -1257,13 +1257,14 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data,
|
|||
}
|
||||
|
||||
if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK && !rc) {
|
||||
bool directory = le32_to_cpu(data->fi.Attributes) & ATTR_DIRECTORY;
|
||||
bool directory = cifs_open_data_attrs(data) & ATTR_DIRECTORY;
|
||||
|
||||
rc = smb2_fix_symlink_target_type(&data->symlink_target, directory, cifs_sb);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (tcon->posix_extensions)
|
||||
if (data->contains_posix_file_info)
|
||||
smb311_posix_info_to_fattr(fattr, data, sb);
|
||||
else
|
||||
cifs_open_info_to_fattr(fattr, data, sb);
|
||||
|
|
|
|||
|
|
@ -98,15 +98,21 @@ static inline bool reparse_inode_match(struct inode *inode,
|
|||
timespec64_equal(&ctime, &fattr->cf_ctime);
|
||||
}
|
||||
|
||||
static inline u32 cifs_open_data_attrs(const struct cifs_open_info_data *data)
|
||||
{
|
||||
if (data->contains_posix_file_info)
|
||||
return le32_to_cpu(data->posix_fi.DosAttributes);
|
||||
|
||||
return le32_to_cpu(data->fi.Attributes);
|
||||
}
|
||||
|
||||
static inline bool cifs_open_data_reparse(struct cifs_open_info_data *data)
|
||||
{
|
||||
u32 attrs;
|
||||
bool ret;
|
||||
u32 attrs = cifs_open_data_attrs(data);
|
||||
|
||||
if (data->contains_posix_file_info) {
|
||||
struct smb311_posix_qinfo *fi = &data->posix_fi;
|
||||
|
||||
attrs = le32_to_cpu(fi->DosAttributes);
|
||||
if (data->reparse_point) {
|
||||
attrs |= ATTR_REPARSE_POINT;
|
||||
fi->DosAttributes = cpu_to_le32(attrs);
|
||||
|
|
@ -115,16 +121,13 @@ static inline bool cifs_open_data_reparse(struct cifs_open_info_data *data)
|
|||
} else {
|
||||
struct smb2_file_all_info *fi = &data->fi;
|
||||
|
||||
attrs = le32_to_cpu(fi->Attributes);
|
||||
if (data->reparse_point) {
|
||||
attrs |= ATTR_REPARSE_POINT;
|
||||
fi->Attributes = cpu_to_le32(attrs);
|
||||
}
|
||||
}
|
||||
|
||||
ret = attrs & ATTR_REPARSE_POINT;
|
||||
|
||||
return ret;
|
||||
return attrs & ATTR_REPARSE_POINT;
|
||||
}
|
||||
|
||||
bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "smb2glob.h"
|
||||
#include "smb2proto.h"
|
||||
#include "cached_dir.h"
|
||||
#include "reparse.h"
|
||||
#include "../common/smb2status.h"
|
||||
#include "../common/smbfsctl.h"
|
||||
|
||||
|
|
@ -1002,12 +1003,13 @@ int smb2_query_path_info(const unsigned int xid,
|
|||
/*
|
||||
* If the symlink was already parsed in create response then it is needed to fix
|
||||
* its type now (after the second call with OPEN_REPARSE_POINT which filled the
|
||||
* data->fi.Attributes). If the symlink was not parsed in create response then
|
||||
* metadata attributes). If the symlink was not parsed in create response then
|
||||
* the data->symlink_target was not filled yet and then the type will be fixed
|
||||
* later after data->symlink_target is filled.
|
||||
*/
|
||||
if (data->reparse.tag == IO_REPARSE_TAG_SYMLINK && !rc && data->symlink_target) {
|
||||
bool directory = le32_to_cpu(data->fi.Attributes) & ATTR_DIRECTORY;
|
||||
bool directory = cifs_open_data_attrs(data) & ATTR_DIRECTORY;
|
||||
|
||||
rc = smb2_fix_symlink_target_type(&data->symlink_target, directory, cifs_sb);
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user