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

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
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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,
+8 −72
Original line number Diff line number Diff line
@@ -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,
+41 −48
Original line number Diff line number Diff line
@@ -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,
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);
	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 */

	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,