Loading fs/cifs/cifspdu.h +6 −5 Original line number Original line Diff line number Diff line Loading @@ -1495,11 +1495,12 @@ struct reparse_data { __u32 ReparseTag; __u32 ReparseTag; __u16 ReparseDataLength; __u16 ReparseDataLength; __u16 Reserved; __u16 Reserved; __u16 AltNameOffset; __u16 SubstituteNameOffset; __u16 AltNameLen; __u16 SubstituteNameLength; __u16 TargetNameOffset; __u16 PrintNameOffset; __u16 TargetNameLen; __u16 PrintNameLength; char LinkNamesBuf[1]; __u32 Flags; char PathBuffer[0]; } __attribute__((packed)); } __attribute__((packed)); struct cifs_quota_data { struct cifs_quota_data { Loading fs/cifs/cifsproto.h +3 −7 Original line number Original line Diff line number Diff line Loading @@ -357,13 +357,9 @@ extern int CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_tcon *tcon, const unsigned char *searchName, char **syminfo, const unsigned char *searchName, char **syminfo, const struct nls_table *nls_codepage); const struct nls_table *nls_codepage); #ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, extern int CIFSSMBQueryReparseLinkInfo(const unsigned int xid, __u16 fid, char **symlinkinfo, struct cifs_tcon *tcon, const unsigned char *searchName, char *symlinkinfo, const int buflen, __u16 fid, const struct nls_table *nls_codepage); const struct nls_table *nls_codepage); #endif /* temporarily unused until cifs_symlink fixed */ extern int CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon, extern int CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon, const char *fileName, const int disposition, const char *fileName, const int disposition, const int access_flags, const int omode, const int access_flags, const int omode, Loading fs/cifs/cifssmb.c +51 −59 Original line number Original line Diff line number Diff line Loading @@ -3067,7 +3067,6 @@ CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, return rc; return rc; } } #ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL /* /* * Recent Windows versions now create symlinks more frequently * Recent Windows versions now create symlinks more frequently * and they use the "reparse point" mechanism below. We can of course * 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. * it is not compiled in by default until callers fixed up and more tested. */ */ int int CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon, CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, const unsigned char *searchName, __u16 fid, char **symlinkinfo, char *symlinkinfo, const int buflen, __u16 fid, const struct nls_table *nls_codepage) const struct nls_table *nls_codepage) { { int rc = 0; int rc = 0; int bytes_returned; int bytes_returned; struct smb_com_transaction_ioctl_req *pSMB; struct smb_com_transaction_ioctl_req *pSMB; struct smb_com_transaction_ioctl_rsp *pSMBr; 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", cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid); searchName); rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, (void **) &pSMBr); (void **) &pSMBr); if (rc) if (rc) Loading Loading @@ -3119,66 +3122,55 @@ CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon, (struct smb_hdr *) pSMBr, &bytes_returned, 0); (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { if (rc) { cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc); cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc); } else { /* decode response */ goto qreparse_out; __u32 data_offset = le32_to_cpu(pSMBr->DataOffset); } __u32 data_count = le32_to_cpu(pSMBr->DataCount); data_offset = le32_to_cpu(pSMBr->DataOffset); data_count = le32_to_cpu(pSMBr->DataCount); if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) { if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) { /* BB also check enough total bytes returned */ /* BB also check enough total bytes returned */ rc = -EIO; /* bad smb */ rc = -EIO; /* bad smb */ goto qreparse_out; goto qreparse_out; } } if (data_count && (data_count < 2048)) { 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; rc = -EIO; cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n"); goto qreparse_out; goto qreparse_out; } } if ((reparse_buf->LinkNamesBuf + end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount; reparse_buf->TargetNameOffset + reparse_buf = (struct reparse_data *) reparse_buf->TargetNameLen) > end_of_smb) { ((char *)&pSMBr->hdr.Protocol + data_offset); cifs_dbg(FYI, "reparse buf beyond SMB\n"); if ((char *)reparse_buf >= end_of_smb) { rc = -EIO; rc = -EIO; goto qreparse_out; goto qreparse_out; } } if ((reparse_buf->PathBuffer + reparse_buf->PrintNameOffset + if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { reparse_buf->PrintNameLength) > end_of_smb) { cifs_from_ucs2(symlinkinfo, (__le16 *) cifs_dbg(FYI, "reparse buf beyond SMB\n"); (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; rc = -EIO; cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n"); goto qreparse_out; } 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); } } 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: qreparse_out: cifs_buf_release(pSMB); 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; return rc; } } #endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */ #ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX Loading fs/cifs/smb1ops.c +32 −0 Original line number Original line 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); (__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 = { struct smb_version_operations smb1_operations = { .send_cancel = send_nt_cancel, .send_cancel = send_nt_cancel, .compare_fids = cifs_compare_fids, .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_pending_delete = cifs_rename_pending_delete, .rename = CIFSSMBRename, .rename = CIFSSMBRename, .create_hardlink = CIFSCreateHardLink, .create_hardlink = CIFSCreateHardLink, .query_symlink = cifs_query_symlink, .open = cifs_open_file, .open = cifs_open_file, .set_fid = cifs_set_fid, .set_fid = cifs_set_fid, .close = cifs_close_file, .close = cifs_close_file, Loading Loading
fs/cifs/cifspdu.h +6 −5 Original line number Original line Diff line number Diff line Loading @@ -1495,11 +1495,12 @@ struct reparse_data { __u32 ReparseTag; __u32 ReparseTag; __u16 ReparseDataLength; __u16 ReparseDataLength; __u16 Reserved; __u16 Reserved; __u16 AltNameOffset; __u16 SubstituteNameOffset; __u16 AltNameLen; __u16 SubstituteNameLength; __u16 TargetNameOffset; __u16 PrintNameOffset; __u16 TargetNameLen; __u16 PrintNameLength; char LinkNamesBuf[1]; __u32 Flags; char PathBuffer[0]; } __attribute__((packed)); } __attribute__((packed)); struct cifs_quota_data { struct cifs_quota_data { Loading
fs/cifs/cifsproto.h +3 −7 Original line number Original line Diff line number Diff line Loading @@ -357,13 +357,9 @@ extern int CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_tcon *tcon, const unsigned char *searchName, char **syminfo, const unsigned char *searchName, char **syminfo, const struct nls_table *nls_codepage); const struct nls_table *nls_codepage); #ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, extern int CIFSSMBQueryReparseLinkInfo(const unsigned int xid, __u16 fid, char **symlinkinfo, struct cifs_tcon *tcon, const unsigned char *searchName, char *symlinkinfo, const int buflen, __u16 fid, const struct nls_table *nls_codepage); const struct nls_table *nls_codepage); #endif /* temporarily unused until cifs_symlink fixed */ extern int CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon, extern int CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon, const char *fileName, const int disposition, const char *fileName, const int disposition, const int access_flags, const int omode, const int access_flags, const int omode, Loading
fs/cifs/cifssmb.c +51 −59 Original line number Original line Diff line number Diff line Loading @@ -3067,7 +3067,6 @@ CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, return rc; return rc; } } #ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL /* /* * Recent Windows versions now create symlinks more frequently * Recent Windows versions now create symlinks more frequently * and they use the "reparse point" mechanism below. We can of course * 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. * it is not compiled in by default until callers fixed up and more tested. */ */ int int CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon, CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon, const unsigned char *searchName, __u16 fid, char **symlinkinfo, char *symlinkinfo, const int buflen, __u16 fid, const struct nls_table *nls_codepage) const struct nls_table *nls_codepage) { { int rc = 0; int rc = 0; int bytes_returned; int bytes_returned; struct smb_com_transaction_ioctl_req *pSMB; struct smb_com_transaction_ioctl_req *pSMB; struct smb_com_transaction_ioctl_rsp *pSMBr; 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", cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid); searchName); rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, (void **) &pSMBr); (void **) &pSMBr); if (rc) if (rc) Loading Loading @@ -3119,66 +3122,55 @@ CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon, (struct smb_hdr *) pSMBr, &bytes_returned, 0); (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc) { if (rc) { cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc); cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc); } else { /* decode response */ goto qreparse_out; __u32 data_offset = le32_to_cpu(pSMBr->DataOffset); } __u32 data_count = le32_to_cpu(pSMBr->DataCount); data_offset = le32_to_cpu(pSMBr->DataOffset); data_count = le32_to_cpu(pSMBr->DataCount); if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) { if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) { /* BB also check enough total bytes returned */ /* BB also check enough total bytes returned */ rc = -EIO; /* bad smb */ rc = -EIO; /* bad smb */ goto qreparse_out; goto qreparse_out; } } if (data_count && (data_count < 2048)) { 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; rc = -EIO; cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n"); goto qreparse_out; goto qreparse_out; } } if ((reparse_buf->LinkNamesBuf + end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount; reparse_buf->TargetNameOffset + reparse_buf = (struct reparse_data *) reparse_buf->TargetNameLen) > end_of_smb) { ((char *)&pSMBr->hdr.Protocol + data_offset); cifs_dbg(FYI, "reparse buf beyond SMB\n"); if ((char *)reparse_buf >= end_of_smb) { rc = -EIO; rc = -EIO; goto qreparse_out; goto qreparse_out; } } if ((reparse_buf->PathBuffer + reparse_buf->PrintNameOffset + if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { reparse_buf->PrintNameLength) > end_of_smb) { cifs_from_ucs2(symlinkinfo, (__le16 *) cifs_dbg(FYI, "reparse buf beyond SMB\n"); (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; rc = -EIO; cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n"); goto qreparse_out; } 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); } } 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: qreparse_out: cifs_buf_release(pSMB); 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; return rc; } } #endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */ #ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX Loading
fs/cifs/smb1ops.c +32 −0 Original line number Original line 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); (__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 = { struct smb_version_operations smb1_operations = { .send_cancel = send_nt_cancel, .send_cancel = send_nt_cancel, .compare_fids = cifs_compare_fids, .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_pending_delete = cifs_rename_pending_delete, .rename = CIFSSMBRename, .rename = CIFSSMBRename, .create_hardlink = CIFSCreateHardLink, .create_hardlink = CIFSCreateHardLink, .query_symlink = cifs_query_symlink, .open = cifs_open_file, .open = cifs_open_file, .set_fid = cifs_set_fid, .set_fid = cifs_set_fid, .close = cifs_close_file, .close = cifs_close_file, Loading