mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
five cifs/smb3 fixes
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmVioPcACgkQiiy9cAdy T1Gf7wv/bbwvRAhPi2m51Iv/LZn+XzY639rtvl2RvfuwxzdEsJzmzXHEU4SFYj7w 9d4vcVndwTzcD8sE9jf6tSgkFd96U9ZEoias+nUdU2CY02DW7C/PVlTckiC4brHD 2ZOOYqn5w3k8mJGN1dP7+1yw1OtXJeOr65/8JbP12z0eru3lzNn91blbW3faeQSt P+dqFTYFygBLiB3AFqlrtXh6TeUpT88UkfYpDrhT+TIiY+BwYKyQBcgfW9Ho12Cx FcD5Bc8QhXT2IM0+igjNJgLwqhko6KGz585m/ojABJwIvstl6gtPhT+r07VLAl8K 87rNuKvIXfdmbaWEcUgOBX9KTa8fduTgVi6s4wj/1jP8NxihOXjDtpRO5xGyTudh w3HooLC8SajEzH76MbLRPnmrG07IG+ZRPiYkMIB65sZvXh/rlAM/59k8K+2WMtEN cDZ53EO1Y2qd5C/wto/dg3e3eWEC2wxu94x5uWYaXHxAmdDCfoZ4Qj1kSkgSXHd5 FoMd4xAJ =6aLE -----END PGP SIGNATURE----- Merge tag '6.7-rc2-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6 Pull smb client fixes from Steve French: - use after free fix in releasing multichannel interfaces - fixes for special file types (report char, block, FIFOs properly when created e.g. by NFS to Windows) - fixes for reporting various special file types and symlinks properly when using SMB1 * tag '6.7-rc2-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: smb: client: introduce cifs_sfu_make_node() smb: client: set correct file type from NFS reparse points smb: client: introduce ->parse_reparse_point() smb: client: implement ->query_reparse_point() for SMB1 cifs: fix use after free for iface while disabling secondary channels
This commit is contained in:
commit
4515866db1
@ -191,7 +191,13 @@ struct cifs_open_info_data {
|
||||
bool reparse_point;
|
||||
bool symlink;
|
||||
};
|
||||
__u32 reparse_tag;
|
||||
struct {
|
||||
__u32 tag;
|
||||
union {
|
||||
struct reparse_data_buffer *buf;
|
||||
struct reparse_posix_data *posix;
|
||||
};
|
||||
} reparse;
|
||||
char *symlink_target;
|
||||
union {
|
||||
struct smb2_file_all_info fi;
|
||||
@ -395,8 +401,7 @@ struct smb_version_operations {
|
||||
struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
char **target_path,
|
||||
struct kvec *rsp_iov);
|
||||
char **target_path);
|
||||
/* open a file for non-posix mounts */
|
||||
int (*open)(const unsigned int xid, struct cifs_open_parms *oparms, __u32 *oplock,
|
||||
void *buf);
|
||||
@ -551,6 +556,9 @@ struct smb_version_operations {
|
||||
bool (*is_status_io_timeout)(char *buf);
|
||||
/* Check for STATUS_NETWORK_NAME_DELETED */
|
||||
bool (*is_network_name_deleted)(char *buf, struct TCP_Server_Info *srv);
|
||||
int (*parse_reparse_point)(struct cifs_sb_info *cifs_sb,
|
||||
struct kvec *rsp_iov,
|
||||
struct cifs_open_info_data *data);
|
||||
};
|
||||
|
||||
struct smb_version_values {
|
||||
|
@ -1356,7 +1356,7 @@ typedef struct smb_com_transaction_ioctl_rsp {
|
||||
__le32 DataDisplacement;
|
||||
__u8 SetupCount; /* 1 */
|
||||
__le16 ReturnedDataLen;
|
||||
__u16 ByteCount;
|
||||
__le16 ByteCount;
|
||||
} __attribute__((packed)) TRANSACT_IOCTL_RSP;
|
||||
|
||||
#define CIFS_ACL_OWNER 1
|
||||
@ -1509,7 +1509,7 @@ struct reparse_posix_data {
|
||||
__le16 ReparseDataLength;
|
||||
__u16 Reserved;
|
||||
__le64 InodeType; /* LNK, FIFO, CHR etc. */
|
||||
char PathBuffer[];
|
||||
__u8 DataBuffer[];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct cifs_quota_data {
|
||||
|
@ -210,7 +210,7 @@ int cifs_get_inode_info(struct inode **inode, const char *full_path,
|
||||
const struct cifs_fid *fid);
|
||||
bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
|
||||
struct cifs_fattr *fattr,
|
||||
u32 tag);
|
||||
struct cifs_open_info_data *data);
|
||||
extern int smb311_posix_get_inode_info(struct inode **pinode, const char *search_path,
|
||||
struct super_block *sb, unsigned int xid);
|
||||
extern int cifs_get_inode_info_unix(struct inode **pinode,
|
||||
@ -458,6 +458,12 @@ extern int CIFSSMBUnixQuerySymLink(const unsigned int xid,
|
||||
struct cifs_tcon *tcon,
|
||||
const unsigned char *searchName, char **syminfo,
|
||||
const struct nls_table *nls_codepage, int remap);
|
||||
extern int cifs_query_reparse_point(const unsigned int xid,
|
||||
struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
u32 *tag, struct kvec *rsp,
|
||||
int *rsp_buftype);
|
||||
extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
__u16 fid, char **symlinkinfo,
|
||||
const struct nls_table *nls_codepage);
|
||||
@ -659,6 +665,12 @@ void cifs_put_tcp_super(struct super_block *sb);
|
||||
int cifs_update_super_prepath(struct cifs_sb_info *cifs_sb, char *prefix);
|
||||
char *extract_hostname(const char *unc);
|
||||
char *extract_sharename(const char *unc);
|
||||
int parse_reparse_point(struct reparse_data_buffer *buf,
|
||||
u32 plen, struct cifs_sb_info *cifs_sb,
|
||||
bool unicode, struct cifs_open_info_data *data);
|
||||
int cifs_sfu_make_node(unsigned int xid, struct inode *inode,
|
||||
struct dentry *dentry, struct cifs_tcon *tcon,
|
||||
const char *full_path, umode_t mode, dev_t dev);
|
||||
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,
|
||||
|
@ -2690,136 +2690,97 @@ querySymLinkRetry:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Recent Windows versions now create symlinks more frequently
|
||||
* and they use the "reparse point" mechanism below. We can of course
|
||||
* do symlinks nicely to Samba and other servers which support the
|
||||
* CIFS Unix Extensions and we can also do SFU symlinks and "client only"
|
||||
* "MF" symlinks optionally, but for recent Windows we really need to
|
||||
* reenable the code below and fix the cifs_symlink callers to handle this.
|
||||
* In the interim this code has been moved to its own config option so
|
||||
* it is not compiled in by default until callers fixed up and more tested.
|
||||
*/
|
||||
int
|
||||
CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
__u16 fid, char **symlinkinfo,
|
||||
const struct nls_table *nls_codepage)
|
||||
int cifs_query_reparse_point(const unsigned int xid,
|
||||
struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
u32 *tag, struct kvec *rsp,
|
||||
int *rsp_buftype)
|
||||
{
|
||||
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_symlink_data *reparse_buf;
|
||||
struct reparse_posix_data *posix_buf;
|
||||
struct cifs_open_parms oparms;
|
||||
TRANSACT_IOCTL_REQ *io_req = NULL;
|
||||
TRANSACT_IOCTL_RSP *io_rsp = NULL;
|
||||
struct cifs_fid fid;
|
||||
__u32 data_offset, data_count;
|
||||
char *end_of_smb;
|
||||
__u8 *start, *end;
|
||||
int io_rsp_len;
|
||||
int oplock = 0;
|
||||
int rc;
|
||||
|
||||
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);
|
||||
cifs_tcon_dbg(FYI, "%s: path=%s\n", __func__, full_path);
|
||||
|
||||
if (cap_unix(tcon->ses))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
oparms = (struct cifs_open_parms) {
|
||||
.tcon = tcon,
|
||||
.cifs_sb = cifs_sb,
|
||||
.desired_access = FILE_READ_ATTRIBUTES,
|
||||
.create_options = cifs_create_options(cifs_sb,
|
||||
OPEN_REPARSE_POINT),
|
||||
.disposition = FILE_OPEN,
|
||||
.path = full_path,
|
||||
.fid = &fid,
|
||||
};
|
||||
|
||||
rc = CIFS_open(xid, &oparms, &oplock, NULL);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
pSMB->TotalParameterCount = 0 ;
|
||||
pSMB->TotalDataCount = 0;
|
||||
pSMB->MaxParameterCount = cpu_to_le32(2);
|
||||
rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon,
|
||||
(void **)&io_req, (void **)&io_rsp);
|
||||
if (rc)
|
||||
goto error;
|
||||
|
||||
io_req->TotalParameterCount = 0;
|
||||
io_req->TotalDataCount = 0;
|
||||
io_req->MaxParameterCount = cpu_to_le32(2);
|
||||
/* BB find exact data count max from sess structure BB */
|
||||
pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
|
||||
pSMB->MaxSetupCount = 4;
|
||||
pSMB->Reserved = 0;
|
||||
pSMB->ParameterOffset = 0;
|
||||
pSMB->DataCount = 0;
|
||||
pSMB->DataOffset = 0;
|
||||
pSMB->SetupCount = 4;
|
||||
pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
|
||||
pSMB->ParameterCount = pSMB->TotalParameterCount;
|
||||
pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
|
||||
pSMB->IsFsctl = 1; /* FSCTL */
|
||||
pSMB->IsRootFlag = 0;
|
||||
pSMB->Fid = fid; /* file handle always le */
|
||||
pSMB->ByteCount = 0;
|
||||
io_req->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
|
||||
io_req->MaxSetupCount = 4;
|
||||
io_req->Reserved = 0;
|
||||
io_req->ParameterOffset = 0;
|
||||
io_req->DataCount = 0;
|
||||
io_req->DataOffset = 0;
|
||||
io_req->SetupCount = 4;
|
||||
io_req->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
|
||||
io_req->ParameterCount = io_req->TotalParameterCount;
|
||||
io_req->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
|
||||
io_req->IsFsctl = 1;
|
||||
io_req->IsRootFlag = 0;
|
||||
io_req->Fid = fid.netfid;
|
||||
io_req->ByteCount = 0;
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
||||
if (rc) {
|
||||
cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
|
||||
goto qreparse_out;
|
||||
}
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)io_req,
|
||||
(struct smb_hdr *)io_rsp, &io_rsp_len, 0);
|
||||
if (rc)
|
||||
goto error;
|
||||
|
||||
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)) {
|
||||
data_offset = le32_to_cpu(io_rsp->DataOffset);
|
||||
data_count = le32_to_cpu(io_rsp->DataCount);
|
||||
if (get_bcc(&io_rsp->hdr) < 2 || data_offset > 512 ||
|
||||
!data_count || data_count > 2048) {
|
||||
rc = -EIO;
|
||||
cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
|
||||
goto qreparse_out;
|
||||
goto error;
|
||||
}
|
||||
end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
|
||||
reparse_buf = (struct reparse_symlink_data *)
|
||||
((char *)&pSMBr->hdr.Protocol + data_offset);
|
||||
if ((char *)reparse_buf >= end_of_smb) {
|
||||
|
||||
end = 2 + get_bcc(&io_rsp->hdr) + (__u8 *)&io_rsp->ByteCount;
|
||||
start = (__u8 *)&io_rsp->hdr.Protocol + data_offset;
|
||||
if (start >= end) {
|
||||
rc = -EIO;
|
||||
goto qreparse_out;
|
||||
}
|
||||
if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
|
||||
cifs_dbg(FYI, "NFS style reparse tag\n");
|
||||
posix_buf = (struct reparse_posix_data *)reparse_buf;
|
||||
|
||||
if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
|
||||
cifs_dbg(FYI, "unsupported file type 0x%llx\n",
|
||||
le64_to_cpu(posix_buf->InodeType));
|
||||
rc = -EOPNOTSUPP;
|
||||
goto qreparse_out;
|
||||
}
|
||||
is_unicode = true;
|
||||
sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
|
||||
if (posix_buf->PathBuffer + sub_len > end_of_smb) {
|
||||
cifs_dbg(FYI, "reparse buf beyond SMB\n");
|
||||
rc = -EIO;
|
||||
goto qreparse_out;
|
||||
}
|
||||
*symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
|
||||
sub_len, is_unicode, nls_codepage);
|
||||
goto qreparse_out;
|
||||
} else if (reparse_buf->ReparseTag !=
|
||||
cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
|
||||
rc = -EOPNOTSUPP;
|
||||
goto qreparse_out;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Reparse tag is NTFS symlink */
|
||||
sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
|
||||
reparse_buf->PathBuffer;
|
||||
sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
|
||||
if (sub_start + sub_len > end_of_smb) {
|
||||
cifs_dbg(FYI, "reparse buf beyond SMB\n");
|
||||
rc = -EIO;
|
||||
goto qreparse_out;
|
||||
}
|
||||
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
|
||||
is_unicode = true;
|
||||
else
|
||||
is_unicode = false;
|
||||
*tag = le32_to_cpu(((struct reparse_data_buffer *)start)->ReparseTag);
|
||||
rsp->iov_base = io_rsp;
|
||||
rsp->iov_len = io_rsp_len;
|
||||
*rsp_buftype = CIFS_LARGE_BUFFER;
|
||||
CIFSSMBClose(xid, tcon, fid.netfid);
|
||||
return 0;
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
error:
|
||||
cifs_buf_release(io_req);
|
||||
CIFSSMBClose(xid, tcon, fid.netfid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -459,8 +459,7 @@ static int cifs_get_unix_fattr(const unsigned char *full_path,
|
||||
return -EOPNOTSUPP;
|
||||
rc = server->ops->query_symlink(xid, tcon,
|
||||
cifs_sb, full_path,
|
||||
&fattr->cf_symlink_target,
|
||||
NULL);
|
||||
&fattr->cf_symlink_target);
|
||||
cifs_dbg(FYI, "%s: query_symlink: %d\n", __func__, rc);
|
||||
}
|
||||
return rc;
|
||||
@ -722,10 +721,51 @@ static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr,
|
||||
fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink);
|
||||
}
|
||||
|
||||
static inline dev_t nfs_mkdev(struct reparse_posix_data *buf)
|
||||
{
|
||||
u64 v = le64_to_cpu(*(__le64 *)buf->DataBuffer);
|
||||
|
||||
return MKDEV(v >> 32, v & 0xffffffff);
|
||||
}
|
||||
|
||||
bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
|
||||
struct cifs_fattr *fattr,
|
||||
u32 tag)
|
||||
struct cifs_open_info_data *data)
|
||||
{
|
||||
struct reparse_posix_data *buf = data->reparse.posix;
|
||||
u32 tag = data->reparse.tag;
|
||||
|
||||
if (tag == IO_REPARSE_TAG_NFS && buf) {
|
||||
switch (le64_to_cpu(buf->InodeType)) {
|
||||
case NFS_SPECFILE_CHR:
|
||||
fattr->cf_mode |= S_IFCHR | cifs_sb->ctx->file_mode;
|
||||
fattr->cf_dtype = DT_CHR;
|
||||
fattr->cf_rdev = nfs_mkdev(buf);
|
||||
break;
|
||||
case NFS_SPECFILE_BLK:
|
||||
fattr->cf_mode |= S_IFBLK | cifs_sb->ctx->file_mode;
|
||||
fattr->cf_dtype = DT_BLK;
|
||||
fattr->cf_rdev = nfs_mkdev(buf);
|
||||
break;
|
||||
case NFS_SPECFILE_FIFO:
|
||||
fattr->cf_mode |= S_IFIFO | cifs_sb->ctx->file_mode;
|
||||
fattr->cf_dtype = DT_FIFO;
|
||||
break;
|
||||
case NFS_SPECFILE_SOCK:
|
||||
fattr->cf_mode |= S_IFSOCK | cifs_sb->ctx->file_mode;
|
||||
fattr->cf_dtype = DT_SOCK;
|
||||
break;
|
||||
case NFS_SPECFILE_LNK:
|
||||
fattr->cf_mode = S_IFLNK | cifs_sb->ctx->file_mode;
|
||||
fattr->cf_dtype = DT_LNK;
|
||||
break;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (tag) {
|
||||
case IO_REPARSE_TAG_LX_SYMLINK:
|
||||
fattr->cf_mode |= S_IFLNK | cifs_sb->ctx->file_mode;
|
||||
@ -791,7 +831,7 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
|
||||
fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
|
||||
|
||||
if (cifs_open_data_reparse(data) &&
|
||||
cifs_reparse_point_to_fattr(cifs_sb, fattr, data->reparse_tag))
|
||||
cifs_reparse_point_to_fattr(cifs_sb, fattr, data))
|
||||
goto out_reparse;
|
||||
|
||||
if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
|
||||
@ -856,7 +896,7 @@ cifs_get_file_info(struct file *filp)
|
||||
data.adjust_tz = false;
|
||||
if (data.symlink_target) {
|
||||
data.symlink = true;
|
||||
data.reparse_tag = IO_REPARSE_TAG_SYMLINK;
|
||||
data.reparse.tag = IO_REPARSE_TAG_SYMLINK;
|
||||
}
|
||||
cifs_open_info_to_fattr(&fattr, &data, inode->i_sb);
|
||||
break;
|
||||
@ -1025,7 +1065,7 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data,
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||
struct kvec rsp_iov, *iov = NULL;
|
||||
int rsp_buftype = CIFS_NO_BUFFER;
|
||||
u32 tag = data->reparse_tag;
|
||||
u32 tag = data->reparse.tag;
|
||||
int rc = 0;
|
||||
|
||||
if (!tag && server->ops->query_reparse_point) {
|
||||
@ -1035,22 +1075,28 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data,
|
||||
if (!rc)
|
||||
iov = &rsp_iov;
|
||||
}
|
||||
switch ((data->reparse_tag = tag)) {
|
||||
|
||||
rc = -EOPNOTSUPP;
|
||||
switch ((data->reparse.tag = tag)) {
|
||||
case 0: /* SMB1 symlink */
|
||||
iov = NULL;
|
||||
fallthrough;
|
||||
case IO_REPARSE_TAG_NFS:
|
||||
case IO_REPARSE_TAG_SYMLINK:
|
||||
if (!data->symlink_target && server->ops->query_symlink) {
|
||||
if (server->ops->query_symlink) {
|
||||
rc = server->ops->query_symlink(xid, tcon,
|
||||
cifs_sb, full_path,
|
||||
&data->symlink_target,
|
||||
iov);
|
||||
&data->symlink_target);
|
||||
}
|
||||
break;
|
||||
case IO_REPARSE_TAG_MOUNT_POINT:
|
||||
cifs_create_junction_fattr(fattr, sb);
|
||||
rc = 0;
|
||||
goto out;
|
||||
default:
|
||||
if (data->symlink_target) {
|
||||
rc = 0;
|
||||
} else if (server->ops->parse_reparse_point) {
|
||||
rc = server->ops->parse_reparse_point(cifs_sb,
|
||||
iov, data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
cifs_open_info_to_fattr(fattr, data, sb);
|
||||
|
@ -153,6 +153,10 @@ static bool reparse_file_needs_reval(const struct cifs_fattr *fattr)
|
||||
static void
|
||||
cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
|
||||
{
|
||||
struct cifs_open_info_data data = {
|
||||
.reparse = { .tag = fattr->cf_cifstag, },
|
||||
};
|
||||
|
||||
fattr->cf_uid = cifs_sb->ctx->linux_uid;
|
||||
fattr->cf_gid = cifs_sb->ctx->linux_gid;
|
||||
|
||||
@ -165,7 +169,7 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
|
||||
* reasonably map some of them to directories vs. files vs. symlinks
|
||||
*/
|
||||
if ((fattr->cf_cifsattrs & ATTR_REPARSE) &&
|
||||
cifs_reparse_point_to_fattr(cifs_sb, fattr, fattr->cf_cifstag))
|
||||
cifs_reparse_point_to_fattr(cifs_sb, fattr, &data))
|
||||
goto out_reparse;
|
||||
|
||||
if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
|
||||
|
@ -332,10 +332,10 @@ cifs_disable_secondary_channels(struct cifs_ses *ses)
|
||||
|
||||
if (iface) {
|
||||
spin_lock(&ses->iface_lock);
|
||||
kref_put(&iface->refcount, release_iface);
|
||||
iface->num_channels--;
|
||||
if (iface->weight_fulfilled)
|
||||
iface->weight_fulfilled--;
|
||||
kref_put(&iface->refcount, release_iface);
|
||||
spin_unlock(&ses->iface_lock);
|
||||
}
|
||||
|
||||
|
@ -976,64 +976,37 @@ static int cifs_query_symlink(const unsigned int xid,
|
||||
struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
char **target_path,
|
||||
struct kvec *rsp_iov)
|
||||
char **target_path)
|
||||
{
|
||||
int rc;
|
||||
int oplock = 0;
|
||||
bool is_reparse_point = !!rsp_iov;
|
||||
struct cifs_fid fid;
|
||||
struct cifs_open_parms oparms;
|
||||
|
||||
cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
|
||||
cifs_tcon_dbg(FYI, "%s: path=%s\n", __func__, full_path);
|
||||
|
||||
if (is_reparse_point) {
|
||||
cifs_dbg(VFS, "reparse points not handled for SMB1 symlinks\n");
|
||||
if (!cap_unix(tcon->ses))
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* Check for unix extensions */
|
||||
if (cap_unix(tcon->ses)) {
|
||||
rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, target_path,
|
||||
cifs_sb->local_nls,
|
||||
cifs_remap(cifs_sb));
|
||||
if (rc == -EREMOTE)
|
||||
rc = cifs_unix_dfs_readlink(xid, tcon, full_path,
|
||||
target_path,
|
||||
cifs_sb->local_nls);
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
oparms = (struct cifs_open_parms) {
|
||||
.tcon = tcon,
|
||||
.cifs_sb = cifs_sb,
|
||||
.desired_access = FILE_READ_ATTRIBUTES,
|
||||
.create_options = cifs_create_options(cifs_sb,
|
||||
OPEN_REPARSE_POINT),
|
||||
.disposition = FILE_OPEN,
|
||||
.path = full_path,
|
||||
.fid = &fid,
|
||||
};
|
||||
|
||||
rc = CIFS_open(xid, &oparms, &oplock, NULL);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
rc = CIFSSMBQuerySymLink(xid, tcon, fid.netfid, target_path,
|
||||
cifs_sb->local_nls);
|
||||
if (rc)
|
||||
goto out_close;
|
||||
|
||||
convert_delimiter(*target_path, '/');
|
||||
out_close:
|
||||
CIFSSMBClose(xid, tcon, fid.netfid);
|
||||
out:
|
||||
if (!rc)
|
||||
cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path);
|
||||
rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, target_path,
|
||||
cifs_sb->local_nls, cifs_remap(cifs_sb));
|
||||
if (rc == -EREMOTE)
|
||||
rc = cifs_unix_dfs_readlink(xid, tcon, full_path,
|
||||
target_path, cifs_sb->local_nls);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cifs_parse_reparse_point(struct cifs_sb_info *cifs_sb,
|
||||
struct kvec *rsp_iov,
|
||||
struct cifs_open_info_data *data)
|
||||
{
|
||||
struct reparse_data_buffer *buf;
|
||||
TRANSACT_IOCTL_RSP *io = rsp_iov->iov_base;
|
||||
bool unicode = !!(io->hdr.Flags2 & SMBFLG2_UNICODE);
|
||||
u32 plen = le16_to_cpu(io->ByteCount);
|
||||
|
||||
buf = (struct reparse_data_buffer *)((__u8 *)&io->hdr.Protocol +
|
||||
le32_to_cpu(io->DataOffset));
|
||||
return parse_reparse_point(buf, plen, cifs_sb, unicode, data);
|
||||
}
|
||||
|
||||
static bool
|
||||
cifs_is_read_op(__u32 oplock)
|
||||
{
|
||||
@ -1068,15 +1041,7 @@ cifs_make_node(unsigned int xid, struct inode *inode,
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||
struct inode *newinode = NULL;
|
||||
int rc = -EPERM;
|
||||
struct cifs_open_info_data buf = {};
|
||||
struct cifs_io_parms io_parms;
|
||||
__u32 oplock = 0;
|
||||
struct cifs_fid fid;
|
||||
struct cifs_open_parms oparms;
|
||||
unsigned int bytes_written;
|
||||
struct win_dev *pdev;
|
||||
struct kvec iov[2];
|
||||
int rc;
|
||||
|
||||
if (tcon->unix_ext) {
|
||||
/*
|
||||
@ -1110,74 +1075,18 @@ cifs_make_node(unsigned int xid, struct inode *inode,
|
||||
d_instantiate(dentry, newinode);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* SMB1 SFU emulation: should work with all servers, but only
|
||||
* support block and char device (no socket & fifo)
|
||||
* Check if mounted with mount parm 'sfu' mount parm.
|
||||
* SFU emulation should work with all servers, but only
|
||||
* supports block and char device (no socket & fifo),
|
||||
* and was used by default in earlier versions of Windows
|
||||
*/
|
||||
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL))
|
||||
return rc;
|
||||
|
||||
if (!S_ISCHR(mode) && !S_ISBLK(mode))
|
||||
return rc;
|
||||
|
||||
cifs_dbg(FYI, "sfu compat create special file\n");
|
||||
|
||||
oparms = (struct cifs_open_parms) {
|
||||
.tcon = tcon,
|
||||
.cifs_sb = cifs_sb,
|
||||
.desired_access = GENERIC_WRITE,
|
||||
.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR |
|
||||
CREATE_OPTION_SPECIAL),
|
||||
.disposition = FILE_CREATE,
|
||||
.path = full_path,
|
||||
.fid = &fid,
|
||||
};
|
||||
|
||||
if (tcon->ses->server->oplocks)
|
||||
oplock = REQ_OPLOCK;
|
||||
else
|
||||
oplock = 0;
|
||||
rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, &buf);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/*
|
||||
* BB Do not bother to decode buf since no local inode yet to put
|
||||
* timestamps in, but we can reuse it safely.
|
||||
*/
|
||||
|
||||
pdev = (struct win_dev *)&buf.fi;
|
||||
io_parms.pid = current->tgid;
|
||||
io_parms.tcon = tcon;
|
||||
io_parms.offset = 0;
|
||||
io_parms.length = sizeof(struct win_dev);
|
||||
iov[1].iov_base = &buf.fi;
|
||||
iov[1].iov_len = sizeof(struct win_dev);
|
||||
if (S_ISCHR(mode)) {
|
||||
memcpy(pdev->type, "IntxCHR", 8);
|
||||
pdev->major = cpu_to_le64(MAJOR(dev));
|
||||
pdev->minor = cpu_to_le64(MINOR(dev));
|
||||
rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms,
|
||||
&bytes_written, iov, 1);
|
||||
} else if (S_ISBLK(mode)) {
|
||||
memcpy(pdev->type, "IntxBLK", 8);
|
||||
pdev->major = cpu_to_le64(MAJOR(dev));
|
||||
pdev->minor = cpu_to_le64(MINOR(dev));
|
||||
rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms,
|
||||
&bytes_written, iov, 1);
|
||||
}
|
||||
tcon->ses->server->ops->close(xid, tcon, &fid);
|
||||
d_drop(dentry);
|
||||
|
||||
/* FIXME: add code here to set EAs */
|
||||
|
||||
cifs_free_open_info(&buf);
|
||||
return rc;
|
||||
return -EPERM;
|
||||
return cifs_sfu_make_node(xid, inode, dentry, tcon,
|
||||
full_path, mode, dev);
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct smb_version_operations smb1_operations = {
|
||||
.send_cancel = send_nt_cancel,
|
||||
.compare_fids = cifs_compare_fids,
|
||||
@ -1214,6 +1123,7 @@ struct smb_version_operations smb1_operations = {
|
||||
.is_path_accessible = cifs_is_path_accessible,
|
||||
.can_echo = cifs_can_echo,
|
||||
.query_path_info = cifs_query_path_info,
|
||||
.query_reparse_point = cifs_query_reparse_point,
|
||||
.query_file_info = cifs_query_file_info,
|
||||
.get_srv_inum = cifs_get_srv_inum,
|
||||
.set_path_size = CIFSSMBSetEOF,
|
||||
@ -1229,6 +1139,7 @@ struct smb_version_operations smb1_operations = {
|
||||
.rename = CIFSSMBRename,
|
||||
.create_hardlink = CIFSCreateHardLink,
|
||||
.query_symlink = cifs_query_symlink,
|
||||
.parse_reparse_point = cifs_parse_reparse_point,
|
||||
.open = cifs_open_file,
|
||||
.set_fid = cifs_set_fid,
|
||||
.close = cifs_close_file,
|
||||
|
@ -555,7 +555,7 @@ static int parse_create_response(struct cifs_open_info_data *data,
|
||||
break;
|
||||
}
|
||||
data->reparse_point = reparse_point;
|
||||
data->reparse_tag = tag;
|
||||
data->reparse.tag = tag;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -2866,115 +2866,119 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_reparse_posix(struct reparse_posix_data *symlink_buf,
|
||||
u32 plen, char **target_path,
|
||||
struct cifs_sb_info *cifs_sb)
|
||||
/* See MS-FSCC 2.1.2.6 for the 'NFS' style reparse tags */
|
||||
static int parse_reparse_posix(struct reparse_posix_data *buf,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
struct cifs_open_info_data *data)
|
||||
{
|
||||
unsigned int len;
|
||||
u64 type;
|
||||
|
||||
/* See MS-FSCC 2.1.2.6 for the 'NFS' style reparse tags */
|
||||
len = le16_to_cpu(symlink_buf->ReparseDataLength);
|
||||
|
||||
if (le64_to_cpu(symlink_buf->InodeType) != NFS_SPECFILE_LNK) {
|
||||
cifs_dbg(VFS, "%lld not a supported symlink type\n",
|
||||
le64_to_cpu(symlink_buf->InodeType));
|
||||
switch ((type = le64_to_cpu(buf->InodeType))) {
|
||||
case NFS_SPECFILE_LNK:
|
||||
len = le16_to_cpu(buf->ReparseDataLength);
|
||||
data->symlink_target = cifs_strndup_from_utf16(buf->DataBuffer,
|
||||
len, true,
|
||||
cifs_sb->local_nls);
|
||||
if (!data->symlink_target)
|
||||
return -ENOMEM;
|
||||
convert_delimiter(data->symlink_target, '/');
|
||||
cifs_dbg(FYI, "%s: target path: %s\n",
|
||||
__func__, data->symlink_target);
|
||||
break;
|
||||
case NFS_SPECFILE_CHR:
|
||||
case NFS_SPECFILE_BLK:
|
||||
case NFS_SPECFILE_FIFO:
|
||||
case NFS_SPECFILE_SOCK:
|
||||
break;
|
||||
default:
|
||||
cifs_dbg(VFS, "%s: unhandled inode type: 0x%llx\n",
|
||||
__func__, type);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
*target_path = cifs_strndup_from_utf16(
|
||||
symlink_buf->PathBuffer,
|
||||
len, true, cifs_sb->local_nls);
|
||||
if (!(*target_path))
|
||||
return -ENOMEM;
|
||||
|
||||
convert_delimiter(*target_path, '/');
|
||||
cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_reparse_symlink(struct reparse_symlink_data_buffer *symlink_buf,
|
||||
u32 plen, char **target_path,
|
||||
struct cifs_sb_info *cifs_sb)
|
||||
static int parse_reparse_symlink(struct reparse_symlink_data_buffer *sym,
|
||||
u32 plen, bool unicode,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
struct cifs_open_info_data *data)
|
||||
{
|
||||
unsigned int sub_len;
|
||||
unsigned int sub_offset;
|
||||
unsigned int len;
|
||||
unsigned int offs;
|
||||
|
||||
/* We handle Symbolic Link reparse tag here. See: MS-FSCC 2.1.2.4 */
|
||||
|
||||
sub_offset = le16_to_cpu(symlink_buf->SubstituteNameOffset);
|
||||
sub_len = le16_to_cpu(symlink_buf->SubstituteNameLength);
|
||||
if (sub_offset + 20 > plen ||
|
||||
sub_offset + sub_len + 20 > plen) {
|
||||
offs = le16_to_cpu(sym->SubstituteNameOffset);
|
||||
len = le16_to_cpu(sym->SubstituteNameLength);
|
||||
if (offs + 20 > plen || offs + len + 20 > plen) {
|
||||
cifs_dbg(VFS, "srv returned malformed symlink buffer\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
*target_path = cifs_strndup_from_utf16(
|
||||
symlink_buf->PathBuffer + sub_offset,
|
||||
sub_len, true, cifs_sb->local_nls);
|
||||
if (!(*target_path))
|
||||
data->symlink_target = cifs_strndup_from_utf16(sym->PathBuffer + offs,
|
||||
len, unicode,
|
||||
cifs_sb->local_nls);
|
||||
if (!data->symlink_target)
|
||||
return -ENOMEM;
|
||||
|
||||
convert_delimiter(*target_path, '/');
|
||||
cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path);
|
||||
convert_delimiter(data->symlink_target, '/');
|
||||
cifs_dbg(FYI, "%s: target path: %s\n", __func__, data->symlink_target);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_reparse_point(struct reparse_data_buffer *buf,
|
||||
u32 plen, char **target_path,
|
||||
struct cifs_sb_info *cifs_sb)
|
||||
int parse_reparse_point(struct reparse_data_buffer *buf,
|
||||
u32 plen, struct cifs_sb_info *cifs_sb,
|
||||
bool unicode, struct cifs_open_info_data *data)
|
||||
{
|
||||
if (plen < sizeof(struct reparse_data_buffer)) {
|
||||
cifs_dbg(VFS, "reparse buffer is too small. Must be at least 8 bytes but was %d\n",
|
||||
plen);
|
||||
if (plen < sizeof(*buf)) {
|
||||
cifs_dbg(VFS, "%s: reparse buffer is too small. Must be at least 8 bytes but was %d\n",
|
||||
__func__, plen);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (plen < le16_to_cpu(buf->ReparseDataLength) +
|
||||
sizeof(struct reparse_data_buffer)) {
|
||||
cifs_dbg(VFS, "srv returned invalid reparse buf length: %d\n",
|
||||
plen);
|
||||
if (plen < le16_to_cpu(buf->ReparseDataLength) + sizeof(*buf)) {
|
||||
cifs_dbg(VFS, "%s: invalid reparse buf length: %d\n",
|
||||
__func__, plen);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
data->reparse.buf = buf;
|
||||
|
||||
/* See MS-FSCC 2.1.2 */
|
||||
switch (le32_to_cpu(buf->ReparseTag)) {
|
||||
case IO_REPARSE_TAG_NFS:
|
||||
return parse_reparse_posix(
|
||||
(struct reparse_posix_data *)buf,
|
||||
plen, target_path, cifs_sb);
|
||||
return parse_reparse_posix((struct reparse_posix_data *)buf,
|
||||
cifs_sb, data);
|
||||
case IO_REPARSE_TAG_SYMLINK:
|
||||
return parse_reparse_symlink(
|
||||
(struct reparse_symlink_data_buffer *)buf,
|
||||
plen, target_path, cifs_sb);
|
||||
plen, unicode, cifs_sb, data);
|
||||
case IO_REPARSE_TAG_LX_SYMLINK:
|
||||
case IO_REPARSE_TAG_AF_UNIX:
|
||||
case IO_REPARSE_TAG_LX_FIFO:
|
||||
case IO_REPARSE_TAG_LX_CHR:
|
||||
case IO_REPARSE_TAG_LX_BLK:
|
||||
return 0;
|
||||
default:
|
||||
cifs_dbg(VFS, "srv returned unknown symlink buffer tag:0x%08x\n",
|
||||
le32_to_cpu(buf->ReparseTag));
|
||||
cifs_dbg(VFS, "%s: unhandled reparse tag: 0x%08x\n",
|
||||
__func__, le32_to_cpu(buf->ReparseTag));
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int smb2_query_symlink(const unsigned int xid,
|
||||
struct cifs_tcon *tcon,
|
||||
struct cifs_sb_info *cifs_sb,
|
||||
const char *full_path,
|
||||
char **target_path,
|
||||
struct kvec *rsp_iov)
|
||||
static int smb2_parse_reparse_point(struct cifs_sb_info *cifs_sb,
|
||||
struct kvec *rsp_iov,
|
||||
struct cifs_open_info_data *data)
|
||||
{
|
||||
struct reparse_data_buffer *buf;
|
||||
struct smb2_ioctl_rsp *io = rsp_iov->iov_base;
|
||||
u32 plen = le32_to_cpu(io->OutputCount);
|
||||
|
||||
cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
|
||||
|
||||
buf = (struct reparse_data_buffer *)((u8 *)io +
|
||||
le32_to_cpu(io->OutputOffset));
|
||||
return parse_reparse_point(buf, plen, target_path, cifs_sb);
|
||||
return parse_reparse_point(buf, plen, cifs_sb, true, data);
|
||||
}
|
||||
|
||||
static int smb2_query_reparse_point(const unsigned int xid,
|
||||
@ -5064,41 +5068,24 @@ smb2_next_header(char *buf)
|
||||
return le32_to_cpu(hdr->NextCommand);
|
||||
}
|
||||
|
||||
static int
|
||||
smb2_make_node(unsigned int xid, struct inode *inode,
|
||||
struct dentry *dentry, struct cifs_tcon *tcon,
|
||||
const char *full_path, umode_t mode, dev_t dev)
|
||||
int cifs_sfu_make_node(unsigned int xid, struct inode *inode,
|
||||
struct dentry *dentry, struct cifs_tcon *tcon,
|
||||
const char *full_path, umode_t mode, dev_t dev)
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||
int rc = -EPERM;
|
||||
struct cifs_open_info_data buf = {};
|
||||
struct cifs_io_parms io_parms = {0};
|
||||
__u32 oplock = 0;
|
||||
struct cifs_fid fid;
|
||||
struct TCP_Server_Info *server = tcon->ses->server;
|
||||
struct cifs_open_parms oparms;
|
||||
struct cifs_io_parms io_parms = {};
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||
struct cifs_fid fid;
|
||||
unsigned int bytes_written;
|
||||
struct win_dev *pdev;
|
||||
struct kvec iov[2];
|
||||
|
||||
/*
|
||||
* Check if mounted with mount parm 'sfu' mount parm.
|
||||
* SFU emulation should work with all servers, but only
|
||||
* supports block and char device (no socket & fifo),
|
||||
* and was used by default in earlier versions of Windows
|
||||
*/
|
||||
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL))
|
||||
return rc;
|
||||
|
||||
/*
|
||||
* TODO: Add ability to create instead via reparse point. Windows (e.g.
|
||||
* their current NFS server) uses this approach to expose special files
|
||||
* over SMB2/SMB3 and Samba will do this with SMB3.1.1 POSIX Extensions
|
||||
*/
|
||||
__u32 oplock = server->oplocks ? REQ_OPLOCK : 0;
|
||||
int rc;
|
||||
|
||||
if (!S_ISCHR(mode) && !S_ISBLK(mode) && !S_ISFIFO(mode))
|
||||
return rc;
|
||||
|
||||
cifs_dbg(FYI, "sfu compat create special file\n");
|
||||
return -EPERM;
|
||||
|
||||
oparms = (struct cifs_open_parms) {
|
||||
.tcon = tcon,
|
||||
@ -5111,11 +5098,7 @@ smb2_make_node(unsigned int xid, struct inode *inode,
|
||||
.fid = &fid,
|
||||
};
|
||||
|
||||
if (tcon->ses->server->oplocks)
|
||||
oplock = REQ_OPLOCK;
|
||||
else
|
||||
oplock = 0;
|
||||
rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, &buf);
|
||||
rc = server->ops->open(xid, &oparms, &oplock, &buf);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
@ -5123,42 +5106,56 @@ smb2_make_node(unsigned int xid, struct inode *inode,
|
||||
* BB Do not bother to decode buf since no local inode yet to put
|
||||
* timestamps in, but we can reuse it safely.
|
||||
*/
|
||||
|
||||
pdev = (struct win_dev *)&buf.fi;
|
||||
io_parms.pid = current->tgid;
|
||||
io_parms.tcon = tcon;
|
||||
io_parms.offset = 0;
|
||||
io_parms.length = sizeof(struct win_dev);
|
||||
iov[1].iov_base = &buf.fi;
|
||||
iov[1].iov_len = sizeof(struct win_dev);
|
||||
io_parms.length = sizeof(*pdev);
|
||||
iov[1].iov_base = pdev;
|
||||
iov[1].iov_len = sizeof(*pdev);
|
||||
if (S_ISCHR(mode)) {
|
||||
memcpy(pdev->type, "IntxCHR", 8);
|
||||
pdev->major = cpu_to_le64(MAJOR(dev));
|
||||
pdev->minor = cpu_to_le64(MINOR(dev));
|
||||
rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms,
|
||||
&bytes_written, iov, 1);
|
||||
} else if (S_ISBLK(mode)) {
|
||||
memcpy(pdev->type, "IntxBLK", 8);
|
||||
pdev->major = cpu_to_le64(MAJOR(dev));
|
||||
pdev->minor = cpu_to_le64(MINOR(dev));
|
||||
rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms,
|
||||
&bytes_written, iov, 1);
|
||||
} else if (S_ISFIFO(mode)) {
|
||||
memcpy(pdev->type, "LnxFIFO", 8);
|
||||
pdev->major = 0;
|
||||
pdev->minor = 0;
|
||||
rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms,
|
||||
&bytes_written, iov, 1);
|
||||
}
|
||||
tcon->ses->server->ops->close(xid, tcon, &fid);
|
||||
|
||||
rc = server->ops->sync_write(xid, &fid, &io_parms,
|
||||
&bytes_written, iov, 1);
|
||||
server->ops->close(xid, tcon, &fid);
|
||||
d_drop(dentry);
|
||||
|
||||
/* FIXME: add code here to set EAs */
|
||||
|
||||
cifs_free_open_info(&buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int smb2_make_node(unsigned int xid, struct inode *inode,
|
||||
struct dentry *dentry, struct cifs_tcon *tcon,
|
||||
const char *full_path, umode_t mode, dev_t dev)
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||
|
||||
/*
|
||||
* Check if mounted with mount parm 'sfu' mount parm.
|
||||
* SFU emulation should work with all servers, but only
|
||||
* supports block and char device (no socket & fifo),
|
||||
* and was used by default in earlier versions of Windows
|
||||
*/
|
||||
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL))
|
||||
return -EPERM;
|
||||
/*
|
||||
* TODO: Add ability to create instead via reparse point. Windows (e.g.
|
||||
* their current NFS server) uses this approach to expose special files
|
||||
* over SMB2/SMB3 and Samba will do this with SMB3.1.1 POSIX Extensions
|
||||
*/
|
||||
return cifs_sfu_make_node(xid, inode, dentry, tcon,
|
||||
full_path, mode, dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
|
||||
struct smb_version_operations smb20_operations = {
|
||||
.compare_fids = smb2_compare_fids,
|
||||
@ -5209,7 +5206,7 @@ struct smb_version_operations smb20_operations = {
|
||||
.unlink = smb2_unlink,
|
||||
.rename = smb2_rename_path,
|
||||
.create_hardlink = smb2_create_hardlink,
|
||||
.query_symlink = smb2_query_symlink,
|
||||
.parse_reparse_point = smb2_parse_reparse_point,
|
||||
.query_mf_symlink = smb3_query_mf_symlink,
|
||||
.create_mf_symlink = smb3_create_mf_symlink,
|
||||
.open = smb2_open_file,
|
||||
@ -5311,7 +5308,7 @@ struct smb_version_operations smb21_operations = {
|
||||
.unlink = smb2_unlink,
|
||||
.rename = smb2_rename_path,
|
||||
.create_hardlink = smb2_create_hardlink,
|
||||
.query_symlink = smb2_query_symlink,
|
||||
.parse_reparse_point = smb2_parse_reparse_point,
|
||||
.query_mf_symlink = smb3_query_mf_symlink,
|
||||
.create_mf_symlink = smb3_create_mf_symlink,
|
||||
.open = smb2_open_file,
|
||||
@ -5416,7 +5413,7 @@ struct smb_version_operations smb30_operations = {
|
||||
.unlink = smb2_unlink,
|
||||
.rename = smb2_rename_path,
|
||||
.create_hardlink = smb2_create_hardlink,
|
||||
.query_symlink = smb2_query_symlink,
|
||||
.parse_reparse_point = smb2_parse_reparse_point,
|
||||
.query_mf_symlink = smb3_query_mf_symlink,
|
||||
.create_mf_symlink = smb3_create_mf_symlink,
|
||||
.open = smb2_open_file,
|
||||
@ -5530,7 +5527,7 @@ struct smb_version_operations smb311_operations = {
|
||||
.unlink = smb2_unlink,
|
||||
.rename = smb2_rename_path,
|
||||
.create_hardlink = smb2_create_hardlink,
|
||||
.query_symlink = smb2_query_symlink,
|
||||
.parse_reparse_point = smb2_parse_reparse_point,
|
||||
.query_mf_symlink = smb3_query_mf_symlink,
|
||||
.create_mf_symlink = smb3_create_mf_symlink,
|
||||
.open = smb2_open_file,
|
||||
|
Loading…
Reference in New Issue
Block a user