Commit d244bf2dfbebfded05f494ffd53659fa7b1e32c1

Authored by Pavel Shilovsky
Committed by Steve French
1 parent b42bf88828

CIFS: Implement follow_link for nounix CIFS mounts

by using a query reparse ioctl request.

Acked-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Pavel Shilovsky <pshilovsky@samba.org>
Signed-off-by: Steve French <smfrench@gmail.com>

Showing 4 changed files with 92 additions and 71 deletions Side-by-side Diff

... ... @@ -1495,11 +1495,12 @@
1495 1495 __u32 ReparseTag;
1496 1496 __u16 ReparseDataLength;
1497 1497 __u16 Reserved;
1498   - __u16 AltNameOffset;
1499   - __u16 AltNameLen;
1500   - __u16 TargetNameOffset;
1501   - __u16 TargetNameLen;
1502   - char LinkNamesBuf[1];
  1498 + __u16 SubstituteNameOffset;
  1499 + __u16 SubstituteNameLength;
  1500 + __u16 PrintNameOffset;
  1501 + __u16 PrintNameLength;
  1502 + __u32 Flags;
  1503 + char PathBuffer[0];
1503 1504 } __attribute__((packed));
1504 1505  
1505 1506 struct cifs_quota_data {
... ... @@ -357,13 +357,9 @@
357 357 struct cifs_tcon *tcon,
358 358 const unsigned char *searchName, char **syminfo,
359 359 const struct nls_table *nls_codepage);
360   -#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
361   -extern int CIFSSMBQueryReparseLinkInfo(const unsigned int xid,
362   - struct cifs_tcon *tcon,
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 */
  360 +extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
  361 + __u16 fid, char **symlinkinfo,
  362 + const struct nls_table *nls_codepage);
367 363 extern int CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
368 364 const char *fileName, const int disposition,
369 365 const int access_flags, const int omode,
... ... @@ -3067,7 +3067,6 @@
3067 3067 return rc;
3068 3068 }
3069 3069  
3070   -#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3071 3070 /*
3072 3071 * Recent Windows versions now create symlinks more frequently
3073 3072 * and they use the "reparse point" mechanism below. We can of course
3074 3073  
3075 3074  
... ... @@ -3079,18 +3078,22 @@
3079 3078 * it is not compiled in by default until callers fixed up and more tested.
3080 3079 */
3081 3080 int
3082   -CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
3083   - const unsigned char *searchName,
3084   - char *symlinkinfo, const int buflen, __u16 fid,
3085   - const struct nls_table *nls_codepage)
  3081 +CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
  3082 + __u16 fid, char **symlinkinfo,
  3083 + const struct nls_table *nls_codepage)
3086 3084 {
3087 3085 int rc = 0;
3088 3086 int bytes_returned;
3089 3087 struct smb_com_transaction_ioctl_req *pSMB;
3090 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",
3093   - searchName);
  3096 + cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
3094 3097 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3095 3098 (void **) &pSMBr);
3096 3099 if (rc)
3097 3100  
3098 3101  
3099 3102  
3100 3103  
3101 3104  
... ... @@ -3119,66 +3122,55 @@
3119 3122 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3120 3123 if (rc) {
3121 3124 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
3122   - } else { /* decode response */
3123   - __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
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;
  3125 + goto qreparse_out;
  3126 + }
3133 3127  
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   -
3150   - if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3151   - cifs_from_ucs2(symlinkinfo, (__le16 *)
3152   - (reparse_buf->LinkNamesBuf +
3153   - reparse_buf->TargetNameOffset),
3154   - buflen,
3155   - reparse_buf->TargetNameLen,
3156   - nls_codepage, 0);
3157   - } else { /* ASCII names */
3158   - strncpy(symlinkinfo,
3159   - reparse_buf->LinkNamesBuf +
3160   - reparse_buf->TargetNameOffset,
3161   - min_t(const int, buflen,
3162   - reparse_buf->TargetNameLen));
3163   - }
3164   - } else {
3165   - rc = -EIO;
3166   - cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3167   - }
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);
  3128 + data_offset = le32_to_cpu(pSMBr->DataOffset);
  3129 + data_count = le32_to_cpu(pSMBr->DataCount);
  3130 + if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
  3131 + /* BB also check enough total bytes returned */
  3132 + rc = -EIO; /* bad smb */
  3133 + goto qreparse_out;
3171 3134 }
  3135 + if (!data_count || (data_count > 2048)) {
  3136 + rc = -EIO;
  3137 + cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
  3138 + goto qreparse_out;
  3139 + }
  3140 + end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
  3141 + reparse_buf = (struct reparse_data *)
  3142 + ((char *)&pSMBr->hdr.Protocol + data_offset);
  3143 + if ((char *)reparse_buf >= end_of_smb) {
  3144 + rc = -EIO;
  3145 + goto qreparse_out;
  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 3165 qreparse_out:
3174 3166 cifs_buf_release(pSMB);
3175 3167  
3176   - /* Note: On -EAGAIN error only caller can retry on handle based calls
3177   - since file handle passed in no longer valid */
3178   -
  3168 + /*
  3169 + * Note: On -EAGAIN error only caller can retry on handle based calls
  3170 + * since file handle passed in no longer valid.
  3171 + */
3179 3172 return rc;
3180 3173 }
3181   -#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
3182 3174  
3183 3175 #ifdef CONFIG_CIFS_POSIX
3184 3176  
... ... @@ -881,6 +881,37 @@
881 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 915 struct smb_version_operations smb1_operations = {
885 916 .send_cancel = send_nt_cancel,
886 917 .compare_fids = cifs_compare_fids,
... ... @@ -927,6 +958,7 @@
927 958 .rename_pending_delete = cifs_rename_pending_delete,
928 959 .rename = CIFSSMBRename,
929 960 .create_hardlink = CIFSCreateHardLink,
  961 + .query_symlink = cifs_query_symlink,
930 962 .open = cifs_open_file,
931 963 .set_fid = cifs_set_fid,
932 964 .close = cifs_close_file,