mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-11 15:49:56 +00:00
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: Paulo Alcantara (SUSE) <pc@manguebit.com> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
45e724022e
commit
b0348e459c
@ -668,6 +668,9 @@ 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,
|
||||
|
@ -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 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) {
|
||||
/*
|
||||
@ -1083,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,
|
||||
|
@ -5068,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,
|
||||
@ -5115,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;
|
||||
|
||||
@ -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
|
||||
* 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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user