diff options
-rw-r--r-- | fs/cifs/cifspdu.h | 11 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 10 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 110 | ||||
-rw-r--r-- | fs/cifs/smb1ops.c | 32 |
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 | ||
1505 | struct cifs_quota_data { | 1506 | struct 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 | 360 | extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, |
361 | extern 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 */ | ||
367 | extern int CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon, | 363 | extern 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 | */ |
3081 | int | 3080 | int |
3082 | CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon, | 3081 | CIFSSMBQuerySymLink(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; | ||
3173 | qreparse_out: | 3165 | qreparse_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 | ||
884 | static int | ||
885 | cifs_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 | |||
884 | struct smb_version_operations smb1_operations = { | 915 | struct 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, |