Commit b0348e45 authored by Paulo Alcantara's avatar Paulo Alcantara Committed by Steve French

smb: client: introduce cifs_sfu_make_node()

Remove duplicate code and add new helper for creating special files in
SFU (Services for UNIX) format that can be shared by SMB1+ code.
Signed-off-by: default avatarPaulo Alcantara (SUSE) <pc@manguebit.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 45e72402
...@@ -668,6 +668,9 @@ char *extract_sharename(const char *unc); ...@@ -668,6 +668,9 @@ char *extract_sharename(const char *unc);
int parse_reparse_point(struct reparse_data_buffer *buf, int parse_reparse_point(struct reparse_data_buffer *buf,
u32 plen, struct cifs_sb_info *cifs_sb, u32 plen, struct cifs_sb_info *cifs_sb,
bool unicode, struct cifs_open_info_data *data); 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 #ifdef CONFIG_CIFS_DFS_UPCALL
static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses, static inline int get_dfs_path(const unsigned int xid, struct cifs_ses *ses,
......
...@@ -1041,15 +1041,7 @@ cifs_make_node(unsigned int xid, struct inode *inode, ...@@ -1041,15 +1041,7 @@ cifs_make_node(unsigned int xid, struct inode *inode,
{ {
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct inode *newinode = NULL; struct inode *newinode = NULL;
int rc = -EPERM; int rc;
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];
if (tcon->unix_ext) { if (tcon->unix_ext) {
/* /*
...@@ -1083,74 +1075,18 @@ cifs_make_node(unsigned int xid, struct inode *inode, ...@@ -1083,74 +1075,18 @@ cifs_make_node(unsigned int xid, struct inode *inode,
d_instantiate(dentry, newinode); d_instantiate(dentry, newinode);
return rc; return rc;
} }
/* /*
* SMB1 SFU emulation: should work with all servers, but only * Check if mounted with mount parm 'sfu' mount parm.
* support block and char device (no socket & fifo) * 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)) if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL))
return rc; return -EPERM;
return cifs_sfu_make_node(xid, inode, dentry, tcon,
if (!S_ISCHR(mode) && !S_ISBLK(mode)) full_path, mode, dev);
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;
} }
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,
......
...@@ -5068,41 +5068,24 @@ smb2_next_header(char *buf) ...@@ -5068,41 +5068,24 @@ smb2_next_header(char *buf)
return le32_to_cpu(hdr->NextCommand); return le32_to_cpu(hdr->NextCommand);
} }
static int int cifs_sfu_make_node(unsigned int xid, struct inode *inode,
smb2_make_node(unsigned int xid, struct inode *inode, struct dentry *dentry, struct cifs_tcon *tcon,
struct dentry *dentry, struct cifs_tcon *tcon, const char *full_path, umode_t mode, dev_t dev)
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_open_info_data buf = {};
struct cifs_io_parms io_parms = {0}; struct TCP_Server_Info *server = tcon->ses->server;
__u32 oplock = 0;
struct cifs_fid fid;
struct cifs_open_parms oparms; 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; unsigned int bytes_written;
struct win_dev *pdev; struct win_dev *pdev;
struct kvec iov[2]; struct kvec iov[2];
__u32 oplock = server->oplocks ? REQ_OPLOCK : 0;
/* int rc;
* 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
*/
if (!S_ISCHR(mode) && !S_ISBLK(mode) && !S_ISFIFO(mode)) if (!S_ISCHR(mode) && !S_ISBLK(mode) && !S_ISFIFO(mode))
return rc; return -EPERM;
cifs_dbg(FYI, "sfu compat create special file\n");
oparms = (struct cifs_open_parms) { oparms = (struct cifs_open_parms) {
.tcon = tcon, .tcon = tcon,
...@@ -5115,11 +5098,7 @@ smb2_make_node(unsigned int xid, struct inode *inode, ...@@ -5115,11 +5098,7 @@ smb2_make_node(unsigned int xid, struct inode *inode,
.fid = &fid, .fid = &fid,
}; };
if (tcon->ses->server->oplocks) rc = server->ops->open(xid, &oparms, &oplock, &buf);
oplock = REQ_OPLOCK;
else
oplock = 0;
rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, &buf);
if (rc) if (rc)
return rc; return rc;
...@@ -5127,42 +5106,56 @@ smb2_make_node(unsigned int xid, struct inode *inode, ...@@ -5127,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 * BB Do not bother to decode buf since no local inode yet to put
* timestamps in, but we can reuse it safely. * timestamps in, but we can reuse it safely.
*/ */
pdev = (struct win_dev *)&buf.fi; pdev = (struct win_dev *)&buf.fi;
io_parms.pid = current->tgid; io_parms.pid = current->tgid;
io_parms.tcon = tcon; io_parms.tcon = tcon;
io_parms.offset = 0; io_parms.length = sizeof(*pdev);
io_parms.length = sizeof(struct win_dev); iov[1].iov_base = pdev;
iov[1].iov_base = &buf.fi; iov[1].iov_len = sizeof(*pdev);
iov[1].iov_len = sizeof(struct win_dev);
if (S_ISCHR(mode)) { if (S_ISCHR(mode)) {
memcpy(pdev->type, "IntxCHR", 8); memcpy(pdev->type, "IntxCHR", 8);
pdev->major = cpu_to_le64(MAJOR(dev)); pdev->major = cpu_to_le64(MAJOR(dev));
pdev->minor = cpu_to_le64(MINOR(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)) { } else if (S_ISBLK(mode)) {
memcpy(pdev->type, "IntxBLK", 8); memcpy(pdev->type, "IntxBLK", 8);
pdev->major = cpu_to_le64(MAJOR(dev)); pdev->major = cpu_to_le64(MAJOR(dev));
pdev->minor = cpu_to_le64(MINOR(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)) { } else if (S_ISFIFO(mode)) {
memcpy(pdev->type, "LnxFIFO", 8); 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);
d_drop(dentry);
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 */ /* FIXME: add code here to set EAs */
cifs_free_open_info(&buf); cifs_free_open_info(&buf);
return rc; 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 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
struct smb_version_operations smb20_operations = { struct smb_version_operations smb20_operations = {
.compare_fids = smb2_compare_fids, .compare_fids = smb2_compare_fids,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment