|
@@ -3067,7 +3067,6 @@ querySymLinkRetry:
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
-#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
|
|
|
/*
|
|
|
* Recent Windows versions now create symlinks more frequently
|
|
|
* and they use the "reparse point" mechanism below. We can of course
|
|
@@ -3079,18 +3078,22 @@ querySymLinkRetry:
|
|
|
* it is not compiled in by default until callers fixed up and more tested.
|
|
|
*/
|
|
|
int
|
|
|
-CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
- const unsigned char *searchName,
|
|
|
- char *symlinkinfo, const int buflen, __u16 fid,
|
|
|
- const struct nls_table *nls_codepage)
|
|
|
+CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
+ __u16 fid, char **symlinkinfo,
|
|
|
+ const struct nls_table *nls_codepage)
|
|
|
{
|
|
|
int rc = 0;
|
|
|
int bytes_returned;
|
|
|
struct smb_com_transaction_ioctl_req *pSMB;
|
|
|
struct smb_com_transaction_ioctl_rsp *pSMBr;
|
|
|
+ bool is_unicode;
|
|
|
+ unsigned int sub_len;
|
|
|
+ char *sub_start;
|
|
|
+ struct reparse_data *reparse_buf;
|
|
|
+ __u32 data_offset, data_count;
|
|
|
+ char *end_of_smb;
|
|
|
|
|
|
- cifs_dbg(FYI, "In Windows reparse style QueryLink for path %s\n",
|
|
|
- searchName);
|
|
|
+ cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
|
|
|
rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
|
|
|
(void **) &pSMBr);
|
|
|
if (rc)
|
|
@@ -3119,66 +3122,55 @@ CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
|
|
if (rc) {
|
|
|
cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
|
|
|
- } else { /* decode response */
|
|
|
- __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
|
|
|
- __u32 data_count = le32_to_cpu(pSMBr->DataCount);
|
|
|
- if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
|
|
|
- /* BB also check enough total bytes returned */
|
|
|
- rc = -EIO; /* bad smb */
|
|
|
- goto qreparse_out;
|
|
|
- }
|
|
|
- if (data_count && (data_count < 2048)) {
|
|
|
- char *end_of_smb = 2 /* sizeof byte count */ +
|
|
|
- get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
|
|
|
-
|
|
|
- struct reparse_data *reparse_buf =
|
|
|
- (struct reparse_data *)
|
|
|
- ((char *)&pSMBr->hdr.Protocol
|
|
|
- + data_offset);
|
|
|
- if ((char *)reparse_buf >= end_of_smb) {
|
|
|
- rc = -EIO;
|
|
|
- goto qreparse_out;
|
|
|
- }
|
|
|
- if ((reparse_buf->LinkNamesBuf +
|
|
|
- reparse_buf->TargetNameOffset +
|
|
|
- reparse_buf->TargetNameLen) > end_of_smb) {
|
|
|
- cifs_dbg(FYI, "reparse buf beyond SMB\n");
|
|
|
- rc = -EIO;
|
|
|
- goto qreparse_out;
|
|
|
- }
|
|
|
+ goto qreparse_out;
|
|
|
+ }
|
|
|
|
|
|
- if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
|
|
|
- cifs_from_ucs2(symlinkinfo, (__le16 *)
|
|
|
- (reparse_buf->LinkNamesBuf +
|
|
|
- reparse_buf->TargetNameOffset),
|
|
|
- buflen,
|
|
|
- reparse_buf->TargetNameLen,
|
|
|
- nls_codepage, 0);
|
|
|
- } else { /* ASCII names */
|
|
|
- strncpy(symlinkinfo,
|
|
|
- reparse_buf->LinkNamesBuf +
|
|
|
- reparse_buf->TargetNameOffset,
|
|
|
- min_t(const int, buflen,
|
|
|
- reparse_buf->TargetNameLen));
|
|
|
- }
|
|
|
- } else {
|
|
|
- rc = -EIO;
|
|
|
- cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
|
|
|
- }
|
|
|
- symlinkinfo[buflen] = 0; /* just in case so the caller
|
|
|
- does not go off the end of the buffer */
|
|
|
- cifs_dbg(FYI, "readlink result - %s\n", symlinkinfo);
|
|
|
+ data_offset = le32_to_cpu(pSMBr->DataOffset);
|
|
|
+ data_count = le32_to_cpu(pSMBr->DataCount);
|
|
|
+ if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
|
|
|
+ /* BB also check enough total bytes returned */
|
|
|
+ rc = -EIO; /* bad smb */
|
|
|
+ goto qreparse_out;
|
|
|
+ }
|
|
|
+ if (!data_count || (data_count > 2048)) {
|
|
|
+ rc = -EIO;
|
|
|
+ cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
|
|
|
+ goto qreparse_out;
|
|
|
+ }
|
|
|
+ end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
|
|
|
+ reparse_buf = (struct reparse_data *)
|
|
|
+ ((char *)&pSMBr->hdr.Protocol + data_offset);
|
|
|
+ if ((char *)reparse_buf >= end_of_smb) {
|
|
|
+ rc = -EIO;
|
|
|
+ goto qreparse_out;
|
|
|
}
|
|
|
+ if ((reparse_buf->PathBuffer + reparse_buf->PrintNameOffset +
|
|
|
+ reparse_buf->PrintNameLength) > end_of_smb) {
|
|
|
+ cifs_dbg(FYI, "reparse buf beyond SMB\n");
|
|
|
+ rc = -EIO;
|
|
|
+ goto qreparse_out;
|
|
|
+ }
|
|
|
+ sub_start = reparse_buf->SubstituteNameOffset + reparse_buf->PathBuffer;
|
|
|
+ sub_len = reparse_buf->SubstituteNameLength;
|
|
|
+ if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
|
|
|
+ is_unicode = true;
|
|
|
+ else
|
|
|
+ is_unicode = false;
|
|
|
|
|
|
+ /* BB FIXME investigate remapping reserved chars here */
|
|
|
+ *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
|
|
|
+ nls_codepage);
|
|
|
+ if (!*symlinkinfo)
|
|
|
+ rc = -ENOMEM;
|
|
|
qreparse_out:
|
|
|
cifs_buf_release(pSMB);
|
|
|
|
|
|
- /* Note: On -EAGAIN error only caller can retry on handle based calls
|
|
|
- since file handle passed in no longer valid */
|
|
|
-
|
|
|
+ /*
|
|
|
+ * Note: On -EAGAIN error only caller can retry on handle based calls
|
|
|
+ * since file handle passed in no longer valid.
|
|
|
+ */
|
|
|
return rc;
|
|
|
}
|
|
|
-#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
|
|
|
|
|
|
#ifdef CONFIG_CIFS_POSIX
|
|
|
|