Loading fs/cifs/cifspdu.h +6 −5 Original line number Diff line number Diff line Loading @@ -1495,11 +1495,12 @@ struct reparse_data { __u32 ReparseTag; __u16 ReparseDataLength; __u16 Reserved; __u16 AltNameOffset; __u16 AltNameLen; __u16 TargetNameOffset; __u16 TargetNameLen; char LinkNamesBuf[1]; __u16 SubstituteNameOffset; __u16 SubstituteNameLength; __u16 PrintNameOffset; __u16 PrintNameLength; __u32 Flags; char PathBuffer[0]; } __attribute__((packed)); struct cifs_quota_data { Loading fs/cifs/cifsproto.h +3 −7 Original line number Diff line number Diff line Loading @@ -357,13 +357,9 @@ extern int CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, const unsigned char *searchName, char **syminfo, const struct nls_table *nls_codepage); #ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL extern int CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon, const unsigned char *searchName, char *symlinkinfo, const int buflen, __u16 fid, extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid, char **symlinkinfo, const struct nls_table *nls_codepage); #endif /* temporarily unused until cifs_symlink fixed */ extern int CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon, const char *fileName, const int disposition, const int access_flags, const int omode, Loading fs/cifs/cifssmb.c +51 −59 Original line number Diff line number Diff line Loading @@ -3067,7 +3067,6 @@ CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, 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 Loading @@ -3079,18 +3078,22 @@ CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, * 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, 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) Loading Loading @@ -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); goto qreparse_out; } 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)) { 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) { if (!data_count || (data_count > 2048)) { rc = -EIO; cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n"); goto qreparse_out; } if ((reparse_buf->LinkNamesBuf + reparse_buf->TargetNameOffset + reparse_buf->TargetNameLen) > end_of_smb) { cifs_dbg(FYI, "reparse buf beyond SMB\n"); 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 (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 { if ((reparse_buf->PathBuffer + reparse_buf->PrintNameOffset + reparse_buf->PrintNameLength) > end_of_smb) { cifs_dbg(FYI, "reparse buf beyond SMB\n"); 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); 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 Loading fs/cifs/smb1ops.c +32 −0 Original line number Diff line number Diff line Loading @@ -881,6 +881,37 @@ cifs_mand_lock(const unsigned int xid, struct cifsFileInfo *cfile, __u64 offset, (__u8)type, wait, 0); } static int cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, const char *full_path, char **target_path, struct cifs_sb_info *cifs_sb) { int rc; int oplock = 0; __u16 netfid; cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN, FILE_READ_ATTRIBUTES, OPEN_REPARSE_POINT, &netfid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) return rc; rc = CIFSSMBQuerySymLink(xid, tcon, netfid, target_path, cifs_sb->local_nls); if (rc) { CIFSSMBClose(xid, tcon, netfid); return rc; } convert_delimiter(*target_path, '/'); CIFSSMBClose(xid, tcon, netfid); cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path); return rc; } struct smb_version_operations smb1_operations = { .send_cancel = send_nt_cancel, .compare_fids = cifs_compare_fids, Loading Loading @@ -927,6 +958,7 @@ struct smb_version_operations smb1_operations = { .rename_pending_delete = cifs_rename_pending_delete, .rename = CIFSSMBRename, .create_hardlink = CIFSCreateHardLink, .query_symlink = cifs_query_symlink, .open = cifs_open_file, .set_fid = cifs_set_fid, .close = cifs_close_file, Loading Loading
fs/cifs/cifspdu.h +6 −5 Original line number Diff line number Diff line Loading @@ -1495,11 +1495,12 @@ struct reparse_data { __u32 ReparseTag; __u16 ReparseDataLength; __u16 Reserved; __u16 AltNameOffset; __u16 AltNameLen; __u16 TargetNameOffset; __u16 TargetNameLen; char LinkNamesBuf[1]; __u16 SubstituteNameOffset; __u16 SubstituteNameLength; __u16 PrintNameOffset; __u16 PrintNameLength; __u32 Flags; char PathBuffer[0]; } __attribute__((packed)); struct cifs_quota_data { Loading
fs/cifs/cifsproto.h +3 −7 Original line number Diff line number Diff line Loading @@ -357,13 +357,9 @@ extern int CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, const unsigned char *searchName, char **syminfo, const struct nls_table *nls_codepage); #ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL extern int CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon, const unsigned char *searchName, char *symlinkinfo, const int buflen, __u16 fid, extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid, char **symlinkinfo, const struct nls_table *nls_codepage); #endif /* temporarily unused until cifs_symlink fixed */ extern int CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon, const char *fileName, const int disposition, const int access_flags, const int omode, Loading
fs/cifs/cifssmb.c +51 −59 Original line number Diff line number Diff line Loading @@ -3067,7 +3067,6 @@ CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, 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 Loading @@ -3079,18 +3078,22 @@ CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, * 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, 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) Loading Loading @@ -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); goto qreparse_out; } 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)) { 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) { if (!data_count || (data_count > 2048)) { rc = -EIO; cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n"); goto qreparse_out; } if ((reparse_buf->LinkNamesBuf + reparse_buf->TargetNameOffset + reparse_buf->TargetNameLen) > end_of_smb) { cifs_dbg(FYI, "reparse buf beyond SMB\n"); 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 (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 { if ((reparse_buf->PathBuffer + reparse_buf->PrintNameOffset + reparse_buf->PrintNameLength) > end_of_smb) { cifs_dbg(FYI, "reparse buf beyond SMB\n"); 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); 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 Loading
fs/cifs/smb1ops.c +32 −0 Original line number Diff line number Diff line Loading @@ -881,6 +881,37 @@ cifs_mand_lock(const unsigned int xid, struct cifsFileInfo *cfile, __u64 offset, (__u8)type, wait, 0); } static int cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, const char *full_path, char **target_path, struct cifs_sb_info *cifs_sb) { int rc; int oplock = 0; __u16 netfid; cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN, FILE_READ_ATTRIBUTES, OPEN_REPARSE_POINT, &netfid, &oplock, NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) return rc; rc = CIFSSMBQuerySymLink(xid, tcon, netfid, target_path, cifs_sb->local_nls); if (rc) { CIFSSMBClose(xid, tcon, netfid); return rc; } convert_delimiter(*target_path, '/'); CIFSSMBClose(xid, tcon, netfid); cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path); return rc; } struct smb_version_operations smb1_operations = { .send_cancel = send_nt_cancel, .compare_fids = cifs_compare_fids, Loading Loading @@ -927,6 +958,7 @@ struct smb_version_operations smb1_operations = { .rename_pending_delete = cifs_rename_pending_delete, .rename = CIFSSMBRename, .create_hardlink = CIFSCreateHardLink, .query_symlink = cifs_query_symlink, .open = cifs_open_file, .set_fid = cifs_set_fid, .close = cifs_close_file, Loading