aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/cifspdu.h11
-rw-r--r--fs/cifs/cifsproto.h10
-rw-r--r--fs/cifs/cifssmb.c110
-rw-r--r--fs/cifs/smb1ops.c32
4 files changed, 92 insertions, 71 deletions
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 11ca24a8e054..948676db8e2e 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -1495,11 +1495,12 @@ struct reparse_data {
1495 __u32 ReparseTag; 1495 __u32 ReparseTag;
1496 __u16 ReparseDataLength; 1496 __u16 ReparseDataLength;
1497 __u16 Reserved; 1497 __u16 Reserved;
1498 __u16 AltNameOffset; 1498 __u16 SubstituteNameOffset;
1499 __u16 AltNameLen; 1499 __u16 SubstituteNameLength;
1500 __u16 TargetNameOffset; 1500 __u16 PrintNameOffset;
1501 __u16 TargetNameLen; 1501 __u16 PrintNameLength;
1502 char LinkNamesBuf[1]; 1502 __u32 Flags;
1503 char PathBuffer[0];
1503} __attribute__((packed)); 1504} __attribute__((packed));
1504 1505
1505struct cifs_quota_data { 1506struct cifs_quota_data {
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index b29a012bed33..5b05eb082a41 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -357,13 +357,9 @@ extern int CIFSSMBUnixQuerySymLink(const unsigned int xid,
357 struct cifs_tcon *tcon, 357 struct cifs_tcon *tcon,
358 const unsigned char *searchName, char **syminfo, 358 const unsigned char *searchName, char **syminfo,
359 const struct nls_table *nls_codepage); 359 const struct nls_table *nls_codepage);
360#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL 360extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
361extern int CIFSSMBQueryReparseLinkInfo(const unsigned int xid, 361 __u16 fid, char **symlinkinfo,
362 struct cifs_tcon *tcon, 362 const struct nls_table *nls_codepage);
363 const unsigned char *searchName,
364 char *symlinkinfo, const int buflen, __u16 fid,
365 const struct nls_table *nls_codepage);
366#endif /* temporarily unused until cifs_symlink fixed */
367extern int CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon, 363extern int CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
368 const char *fileName, const int disposition, 364 const char *fileName, const int disposition,
369 const int access_flags, const int omode, 365 const int access_flags, const int omode,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index a89c4cb4e6cf..a3d74fea1623 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -3067,7 +3067,6 @@ querySymLinkRetry:
3067 return rc; 3067 return rc;
3068} 3068}
3069 3069
3070#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3071/* 3070/*
3072 * Recent Windows versions now create symlinks more frequently 3071 * Recent Windows versions now create symlinks more frequently
3073 * and they use the "reparse point" mechanism below. We can of course 3072 * and they use the "reparse point" mechanism below. We can of course
@@ -3079,18 +3078,22 @@ querySymLinkRetry:
3079 * it is not compiled in by default until callers fixed up and more tested. 3078 * it is not compiled in by default until callers fixed up and more tested.
3080 */ 3079 */
3081int 3080int
3082CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon, 3081CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3083 const unsigned char *searchName, 3082 __u16 fid, char **symlinkinfo,
3084 char *symlinkinfo, const int buflen, __u16 fid, 3083 const struct nls_table *nls_codepage)
3085 const struct nls_table *nls_codepage)
3086{ 3084{
3087 int rc = 0; 3085 int rc = 0;
3088 int bytes_returned; 3086 int bytes_returned;
3089 struct smb_com_transaction_ioctl_req *pSMB; 3087 struct smb_com_transaction_ioctl_req *pSMB;
3090 struct smb_com_transaction_ioctl_rsp *pSMBr; 3088 struct smb_com_transaction_ioctl_rsp *pSMBr;
3089 bool is_unicode;
3090 unsigned int sub_len;
3091 char *sub_start;
3092 struct reparse_data *reparse_buf;
3093 __u32 data_offset, data_count;
3094 char *end_of_smb;
3091 3095
3092 cifs_dbg(FYI, "In Windows reparse style QueryLink for path %s\n", 3096 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
3093 searchName);
3094 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, 3097 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3095 (void **) &pSMBr); 3098 (void **) &pSMBr);
3096 if (rc) 3099 if (rc)
@@ -3119,66 +3122,55 @@ CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
3119 (struct smb_hdr *) pSMBr, &bytes_returned, 0); 3122 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3120 if (rc) { 3123 if (rc) {
3121 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc); 3124 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
3122 } else { /* decode response */ 3125 goto qreparse_out;
3123 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset); 3126 }
3124 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
3125 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3126 /* BB also check enough total bytes returned */
3127 rc = -EIO; /* bad smb */
3128 goto qreparse_out;
3129 }
3130 if (data_count && (data_count < 2048)) {
3131 char *end_of_smb = 2 /* sizeof byte count */ +
3132 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
3133
3134 struct reparse_data *reparse_buf =
3135 (struct reparse_data *)
3136 ((char *)&pSMBr->hdr.Protocol
3137 + data_offset);
3138 if ((char *)reparse_buf >= end_of_smb) {
3139 rc = -EIO;
3140 goto qreparse_out;
3141 }
3142 if ((reparse_buf->LinkNamesBuf +
3143 reparse_buf->TargetNameOffset +
3144 reparse_buf->TargetNameLen) > end_of_smb) {
3145 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3146 rc = -EIO;
3147 goto qreparse_out;
3148 }
3149 3127
3150 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { 3128 data_offset = le32_to_cpu(pSMBr->DataOffset);
3151 cifs_from_ucs2(symlinkinfo, (__le16 *) 3129 data_count = le32_to_cpu(pSMBr->DataCount);
3152 (reparse_buf->LinkNamesBuf + 3130 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3153 reparse_buf->TargetNameOffset), 3131 /* BB also check enough total bytes returned */
3154 buflen, 3132 rc = -EIO; /* bad smb */
3155 reparse_buf->TargetNameLen, 3133 goto qreparse_out;
3156 nls_codepage, 0); 3134 }
3157 } else { /* ASCII names */ 3135 if (!data_count || (data_count > 2048)) {
3158 strncpy(symlinkinfo, 3136 rc = -EIO;
3159 reparse_buf->LinkNamesBuf + 3137 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3160 reparse_buf->TargetNameOffset, 3138 goto qreparse_out;
3161 min_t(const int, buflen, 3139 }
3162 reparse_buf->TargetNameLen)); 3140 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
3163 } 3141 reparse_buf = (struct reparse_data *)
3164 } else { 3142 ((char *)&pSMBr->hdr.Protocol + data_offset);
3165 rc = -EIO; 3143 if ((char *)reparse_buf >= end_of_smb) {
3166 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n"); 3144 rc = -EIO;
3167 } 3145 goto qreparse_out;
3168 symlinkinfo[buflen] = 0; /* just in case so the caller
3169 does not go off the end of the buffer */
3170 cifs_dbg(FYI, "readlink result - %s\n", symlinkinfo);
3171 } 3146 }
3147 if ((reparse_buf->PathBuffer + reparse_buf->PrintNameOffset +
3148 reparse_buf->PrintNameLength) > end_of_smb) {
3149 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3150 rc = -EIO;
3151 goto qreparse_out;
3152 }
3153 sub_start = reparse_buf->SubstituteNameOffset + reparse_buf->PathBuffer;
3154 sub_len = reparse_buf->SubstituteNameLength;
3155 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3156 is_unicode = true;
3157 else
3158 is_unicode = false;
3172 3159
3160 /* BB FIXME investigate remapping reserved chars here */
3161 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3162 nls_codepage);
3163 if (!*symlinkinfo)
3164 rc = -ENOMEM;
3173qreparse_out: 3165qreparse_out:
3174 cifs_buf_release(pSMB); 3166 cifs_buf_release(pSMB);
3175 3167
3176 /* Note: On -EAGAIN error only caller can retry on handle based calls 3168 /*
3177 since file handle passed in no longer valid */ 3169 * Note: On -EAGAIN error only caller can retry on handle based calls
3178 3170 * since file handle passed in no longer valid.
3171 */
3179 return rc; 3172 return rc;
3180} 3173}
3181#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
3182 3174
3183#ifdef CONFIG_CIFS_POSIX 3175#ifdef CONFIG_CIFS_POSIX
3184 3176
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 60943978aec3..8fe19c973ee4 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -881,6 +881,37 @@ cifs_mand_lock(const unsigned int xid, struct cifsFileInfo *cfile, __u64 offset,
881 (__u8)type, wait, 0); 881 (__u8)type, wait, 0);
882} 882}
883 883
884static int
885cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
886 const char *full_path, char **target_path,
887 struct cifs_sb_info *cifs_sb)
888{
889 int rc;
890 int oplock = 0;
891 __u16 netfid;
892
893 cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
894
895 rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
896 FILE_READ_ATTRIBUTES, OPEN_REPARSE_POINT, &netfid,
897 &oplock, NULL, cifs_sb->local_nls,
898 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
899 if (rc)
900 return rc;
901
902 rc = CIFSSMBQuerySymLink(xid, tcon, netfid, target_path,
903 cifs_sb->local_nls);
904 if (rc) {
905 CIFSSMBClose(xid, tcon, netfid);
906 return rc;
907 }
908
909 convert_delimiter(*target_path, '/');
910 CIFSSMBClose(xid, tcon, netfid);
911 cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path);
912 return rc;
913}
914
884struct smb_version_operations smb1_operations = { 915struct smb_version_operations smb1_operations = {
885 .send_cancel = send_nt_cancel, 916 .send_cancel = send_nt_cancel,
886 .compare_fids = cifs_compare_fids, 917 .compare_fids = cifs_compare_fids,
@@ -927,6 +958,7 @@ struct smb_version_operations smb1_operations = {
927 .rename_pending_delete = cifs_rename_pending_delete, 958 .rename_pending_delete = cifs_rename_pending_delete,
928 .rename = CIFSSMBRename, 959 .rename = CIFSSMBRename,
929 .create_hardlink = CIFSCreateHardLink, 960 .create_hardlink = CIFSCreateHardLink,
961 .query_symlink = cifs_query_symlink,
930 .open = cifs_open_file, 962 .open = cifs_open_file,
931 .set_fid = cifs_set_fid, 963 .set_fid = cifs_set_fid,
932 .close = cifs_close_file, 964 .close = cifs_close_file,