Skip to content

Commit ed3e0a1

Browse files
Paulo AlcantaraSteve French
authored andcommitted
smb: client: implement ->query_reparse_point() for SMB1
Reparse points are not limited to symlinks, so implement ->query_reparse_point() in order to handle different file types. Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com> Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent a15ccef commit ed3e0a1

File tree

5 files changed

+113
-175
lines changed

5 files changed

+113
-175
lines changed

fs/smb/client/cifspdu.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1356,7 +1356,7 @@ typedef struct smb_com_transaction_ioctl_rsp {
13561356
__le32 DataDisplacement;
13571357
__u8 SetupCount; /* 1 */
13581358
__le16 ReturnedDataLen;
1359-
__u16 ByteCount;
1359+
__le16 ByteCount;
13601360
} __attribute__((packed)) TRANSACT_IOCTL_RSP;
13611361

13621362
#define CIFS_ACL_OWNER 1

fs/smb/client/cifsproto.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,12 @@ extern int CIFSSMBUnixQuerySymLink(const unsigned int xid,
458458
struct cifs_tcon *tcon,
459459
const unsigned char *searchName, char **syminfo,
460460
const struct nls_table *nls_codepage, int remap);
461+
extern int cifs_query_reparse_point(const unsigned int xid,
462+
struct cifs_tcon *tcon,
463+
struct cifs_sb_info *cifs_sb,
464+
const char *full_path,
465+
u32 *tag, struct kvec *rsp,
466+
int *rsp_buftype);
461467
extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
462468
__u16 fid, char **symlinkinfo,
463469
const struct nls_table *nls_codepage);
@@ -659,6 +665,9 @@ void cifs_put_tcp_super(struct super_block *sb);
659665
int cifs_update_super_prepath(struct cifs_sb_info *cifs_sb, char *prefix);
660666
char *extract_hostname(const char *unc);
661667
char *extract_sharename(const char *unc);
668+
int parse_reparse_point(struct reparse_data_buffer *buf,
669+
u32 plen, struct cifs_sb_info *cifs_sb,
670+
bool unicode, char **target_path);
662671

663672
#ifdef CONFIG_CIFS_DFS_UPCALL
664673
static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,

fs/smb/client/cifssmb.c

Lines changed: 77 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -2690,136 +2690,97 @@ CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
26902690
return rc;
26912691
}
26922692

2693-
/*
2694-
* Recent Windows versions now create symlinks more frequently
2695-
* and they use the "reparse point" mechanism below. We can of course
2696-
* do symlinks nicely to Samba and other servers which support the
2697-
* CIFS Unix Extensions and we can also do SFU symlinks and "client only"
2698-
* "MF" symlinks optionally, but for recent Windows we really need to
2699-
* reenable the code below and fix the cifs_symlink callers to handle this.
2700-
* In the interim this code has been moved to its own config option so
2701-
* it is not compiled in by default until callers fixed up and more tested.
2702-
*/
2703-
int
2704-
CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
2705-
__u16 fid, char **symlinkinfo,
2706-
const struct nls_table *nls_codepage)
2693+
int cifs_query_reparse_point(const unsigned int xid,
2694+
struct cifs_tcon *tcon,
2695+
struct cifs_sb_info *cifs_sb,
2696+
const char *full_path,
2697+
u32 *tag, struct kvec *rsp,
2698+
int *rsp_buftype)
27072699
{
2708-
int rc = 0;
2709-
int bytes_returned;
2710-
struct smb_com_transaction_ioctl_req *pSMB;
2711-
struct smb_com_transaction_ioctl_rsp *pSMBr;
2712-
bool is_unicode;
2713-
unsigned int sub_len;
2714-
char *sub_start;
2715-
struct reparse_symlink_data *reparse_buf;
2716-
struct reparse_posix_data *posix_buf;
2700+
struct cifs_open_parms oparms;
2701+
TRANSACT_IOCTL_REQ *io_req = NULL;
2702+
TRANSACT_IOCTL_RSP *io_rsp = NULL;
2703+
struct cifs_fid fid;
27172704
__u32 data_offset, data_count;
2718-
char *end_of_smb;
2705+
__u8 *start, *end;
2706+
int io_rsp_len;
2707+
int oplock = 0;
2708+
int rc;
27192709

2720-
cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
2721-
rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2722-
(void **) &pSMBr);
2710+
cifs_tcon_dbg(FYI, "%s: path=%s\n", __func__, full_path);
2711+
2712+
if (cap_unix(tcon->ses))
2713+
return -EOPNOTSUPP;
2714+
2715+
oparms = (struct cifs_open_parms) {
2716+
.tcon = tcon,
2717+
.cifs_sb = cifs_sb,
2718+
.desired_access = FILE_READ_ATTRIBUTES,
2719+
.create_options = cifs_create_options(cifs_sb,
2720+
OPEN_REPARSE_POINT),
2721+
.disposition = FILE_OPEN,
2722+
.path = full_path,
2723+
.fid = &fid,
2724+
};
2725+
2726+
rc = CIFS_open(xid, &oparms, &oplock, NULL);
27232727
if (rc)
27242728
return rc;
27252729

2726-
pSMB->TotalParameterCount = 0 ;
2727-
pSMB->TotalDataCount = 0;
2728-
pSMB->MaxParameterCount = cpu_to_le32(2);
2729-
/* BB find exact data count max from sess structure BB */
2730-
pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
2731-
pSMB->MaxSetupCount = 4;
2732-
pSMB->Reserved = 0;
2733-
pSMB->ParameterOffset = 0;
2734-
pSMB->DataCount = 0;
2735-
pSMB->DataOffset = 0;
2736-
pSMB->SetupCount = 4;
2737-
pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2738-
pSMB->ParameterCount = pSMB->TotalParameterCount;
2739-
pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2740-
pSMB->IsFsctl = 1; /* FSCTL */
2741-
pSMB->IsRootFlag = 0;
2742-
pSMB->Fid = fid; /* file handle always le */
2743-
pSMB->ByteCount = 0;
2730+
rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon,
2731+
(void **)&io_req, (void **)&io_rsp);
2732+
if (rc)
2733+
goto error;
27442734

2745-
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2746-
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
2747-
if (rc) {
2748-
cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
2749-
goto qreparse_out;
2750-
}
2735+
io_req->TotalParameterCount = 0;
2736+
io_req->TotalDataCount = 0;
2737+
io_req->MaxParameterCount = cpu_to_le32(2);
2738+
/* BB find exact data count max from sess structure BB */
2739+
io_req->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
2740+
io_req->MaxSetupCount = 4;
2741+
io_req->Reserved = 0;
2742+
io_req->ParameterOffset = 0;
2743+
io_req->DataCount = 0;
2744+
io_req->DataOffset = 0;
2745+
io_req->SetupCount = 4;
2746+
io_req->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2747+
io_req->ParameterCount = io_req->TotalParameterCount;
2748+
io_req->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2749+
io_req->IsFsctl = 1;
2750+
io_req->IsRootFlag = 0;
2751+
io_req->Fid = fid.netfid;
2752+
io_req->ByteCount = 0;
2753+
2754+
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)io_req,
2755+
(struct smb_hdr *)io_rsp, &io_rsp_len, 0);
2756+
if (rc)
2757+
goto error;
27512758

2752-
data_offset = le32_to_cpu(pSMBr->DataOffset);
2753-
data_count = le32_to_cpu(pSMBr->DataCount);
2754-
if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
2755-
/* BB also check enough total bytes returned */
2756-
rc = -EIO; /* bad smb */
2757-
goto qreparse_out;
2758-
}
2759-
if (!data_count || (data_count > 2048)) {
2759+
data_offset = le32_to_cpu(io_rsp->DataOffset);
2760+
data_count = le32_to_cpu(io_rsp->DataCount);
2761+
if (get_bcc(&io_rsp->hdr) < 2 || data_offset > 512 ||
2762+
!data_count || data_count > 2048) {
27602763
rc = -EIO;
2761-
cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
2762-
goto qreparse_out;
2763-
}
2764-
end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
2765-
reparse_buf = (struct reparse_symlink_data *)
2766-
((char *)&pSMBr->hdr.Protocol + data_offset);
2767-
if ((char *)reparse_buf >= end_of_smb) {
2768-
rc = -EIO;
2769-
goto qreparse_out;
2770-
}
2771-
if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
2772-
cifs_dbg(FYI, "NFS style reparse tag\n");
2773-
posix_buf = (struct reparse_posix_data *)reparse_buf;
2774-
2775-
if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
2776-
cifs_dbg(FYI, "unsupported file type 0x%llx\n",
2777-
le64_to_cpu(posix_buf->InodeType));
2778-
rc = -EOPNOTSUPP;
2779-
goto qreparse_out;
2780-
}
2781-
is_unicode = true;
2782-
sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
2783-
if (posix_buf->PathBuffer + sub_len > end_of_smb) {
2784-
cifs_dbg(FYI, "reparse buf beyond SMB\n");
2785-
rc = -EIO;
2786-
goto qreparse_out;
2787-
}
2788-
*symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
2789-
sub_len, is_unicode, nls_codepage);
2790-
goto qreparse_out;
2791-
} else if (reparse_buf->ReparseTag !=
2792-
cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
2793-
rc = -EOPNOTSUPP;
2794-
goto qreparse_out;
2764+
goto error;
27952765
}
27962766

2797-
/* Reparse tag is NTFS symlink */
2798-
sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
2799-
reparse_buf->PathBuffer;
2800-
sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
2801-
if (sub_start + sub_len > end_of_smb) {
2802-
cifs_dbg(FYI, "reparse buf beyond SMB\n");
2767+
end = 2 + get_bcc(&io_rsp->hdr) + (__u8 *)&io_rsp->ByteCount;
2768+
start = (__u8 *)&io_rsp->hdr.Protocol + data_offset;
2769+
if (start >= end) {
28032770
rc = -EIO;
2804-
goto qreparse_out;
2771+
goto error;
28052772
}
2806-
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2807-
is_unicode = true;
2808-
else
2809-
is_unicode = false;
2810-
2811-
/* BB FIXME investigate remapping reserved chars here */
2812-
*symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
2813-
nls_codepage);
2814-
if (!*symlinkinfo)
2815-
rc = -ENOMEM;
2816-
qreparse_out:
2817-
cifs_buf_release(pSMB);
28182773

2819-
/*
2820-
* Note: On -EAGAIN error only caller can retry on handle based calls
2821-
* since file handle passed in no longer valid.
2822-
*/
2774+
*tag = le32_to_cpu(((struct reparse_data_buffer *)start)->ReparseTag);
2775+
rsp->iov_base = io_rsp;
2776+
rsp->iov_len = io_rsp_len;
2777+
*rsp_buftype = CIFS_LARGE_BUFFER;
2778+
CIFSSMBClose(xid, tcon, fid.netfid);
2779+
return 0;
2780+
2781+
error:
2782+
cifs_buf_release(io_req);
2783+
CIFSSMBClose(xid, tcon, fid.netfid);
28232784
return rc;
28242785
}
28252786

fs/smb/client/smb1ops.c

Lines changed: 10 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -979,18 +979,13 @@ static int cifs_query_symlink(const unsigned int xid,
979979
char **target_path,
980980
struct kvec *rsp_iov)
981981
{
982+
struct reparse_data_buffer *buf;
983+
TRANSACT_IOCTL_RSP *io = rsp_iov->iov_base;
984+
bool unicode = !!(io->hdr.Flags2 & SMBFLG2_UNICODE);
985+
u32 plen = le16_to_cpu(io->ByteCount);
982986
int rc;
983-
int oplock = 0;
984-
bool is_reparse_point = !!rsp_iov;
985-
struct cifs_fid fid;
986-
struct cifs_open_parms oparms;
987987

988-
cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
989-
990-
if (is_reparse_point) {
991-
cifs_dbg(VFS, "reparse points not handled for SMB1 symlinks\n");
992-
return -EOPNOTSUPP;
993-
}
988+
cifs_tcon_dbg(FYI, "%s: path=%s\n", __func__, full_path);
994989

995990
/* Check for unix extensions */
996991
if (cap_unix(tcon->ses)) {
@@ -1001,37 +996,12 @@ static int cifs_query_symlink(const unsigned int xid,
1001996
rc = cifs_unix_dfs_readlink(xid, tcon, full_path,
1002997
target_path,
1003998
cifs_sb->local_nls);
1004-
1005-
goto out;
999+
return rc;
10061000
}
10071001

1008-
oparms = (struct cifs_open_parms) {
1009-
.tcon = tcon,
1010-
.cifs_sb = cifs_sb,
1011-
.desired_access = FILE_READ_ATTRIBUTES,
1012-
.create_options = cifs_create_options(cifs_sb,
1013-
OPEN_REPARSE_POINT),
1014-
.disposition = FILE_OPEN,
1015-
.path = full_path,
1016-
.fid = &fid,
1017-
};
1018-
1019-
rc = CIFS_open(xid, &oparms, &oplock, NULL);
1020-
if (rc)
1021-
goto out;
1022-
1023-
rc = CIFSSMBQuerySymLink(xid, tcon, fid.netfid, target_path,
1024-
cifs_sb->local_nls);
1025-
if (rc)
1026-
goto out_close;
1027-
1028-
convert_delimiter(*target_path, '/');
1029-
out_close:
1030-
CIFSSMBClose(xid, tcon, fid.netfid);
1031-
out:
1032-
if (!rc)
1033-
cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path);
1034-
return rc;
1002+
buf = (struct reparse_data_buffer *)((__u8 *)&io->hdr.Protocol +
1003+
le32_to_cpu(io->DataOffset));
1004+
return parse_reparse_point(buf, plen, cifs_sb, unicode, target_path);
10351005
}
10361006

10371007
static bool
@@ -1214,6 +1184,7 @@ struct smb_version_operations smb1_operations = {
12141184
.is_path_accessible = cifs_is_path_accessible,
12151185
.can_echo = cifs_can_echo,
12161186
.query_path_info = cifs_query_path_info,
1187+
.query_reparse_point = cifs_query_reparse_point,
12171188
.query_file_info = cifs_query_file_info,
12181189
.get_srv_inum = cifs_get_srv_inum,
12191190
.set_path_size = CIFSSMBSetEOF,

0 commit comments

Comments
 (0)