Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b42bf888 authored by Pavel Shilovsky's avatar Pavel Shilovsky Committed by Steve French
Browse files

CIFS: Implement follow_link for SMB2



that allows to access files through symlink created on a server.

Acked-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarPavel Shilovsky <pshilovsky@samba.org>
Signed-off-by: default avatarSteve French <smfrench@gmail.com>
parent 3ae35cde
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -308,6 +308,9 @@ struct smb_version_operations {
	int (*create_hardlink)(const unsigned int, struct cifs_tcon *,
	int (*create_hardlink)(const unsigned int, struct cifs_tcon *,
			       const char *, const char *,
			       const char *, const char *,
			       struct cifs_sb_info *);
			       struct cifs_sb_info *);
	/* query symlink target */
	int (*query_symlink)(const unsigned int, struct cifs_tcon *,
			     const char *, char **, struct cifs_sb_info *);
	/* open a file for non-posix mounts */
	/* open a file for non-posix mounts */
	int (*open)(const unsigned int, struct cifs_open_parms *,
	int (*open)(const unsigned int, struct cifs_open_parms *,
		    __u32 *, FILE_ALL_INFO *);
		    __u32 *, FILE_ALL_INFO *);
+4 −0
Original line number Original line Diff line number Diff line
@@ -549,6 +549,10 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
		 * when Unix extensions are disabled - fake it.
		 * when Unix extensions are disabled - fake it.
		 */
		 */
		fattr->cf_nlink = 2;
		fattr->cf_nlink = 2;
	} else if (fattr->cf_cifsattrs & ATTR_REPARSE) {
		fattr->cf_mode = S_IFLNK;
		fattr->cf_dtype = DT_LNK;
		fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
	} else {
	} else {
		fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
		fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
		fattr->cf_dtype = DT_REG;
		fattr->cf_dtype = DT_REG;
+5 −19
Original line number Original line Diff line number Diff line
@@ -509,6 +509,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
	struct tcon_link *tlink = NULL;
	struct tcon_link *tlink = NULL;
	struct cifs_tcon *tcon;
	struct cifs_tcon *tcon;
	struct TCP_Server_Info *server;


	xid = get_xid();
	xid = get_xid();


@@ -519,25 +520,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
		goto out;
		goto out;
	}
	}
	tcon = tlink_tcon(tlink);
	tcon = tlink_tcon(tlink);

	server = tcon->ses->server;
	/*
	 * For now, we just handle symlinks with unix extensions enabled.
	 * Eventually we should handle NTFS reparse points, and MacOS
	 * symlink support. For instance...
	 *
	 * rc = CIFSSMBQueryReparseLinkInfo(...)
	 *
	 * For now, just return -EACCES when the server doesn't support posix
	 * extensions. Note that we still allow querying symlinks when posix
	 * extensions are manually disabled. We could disable these as well
	 * but there doesn't seem to be any harm in allowing the client to
	 * read them.
	 */
	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) &&
	    !cap_unix(tcon->ses)) {
		rc = -EACCES;
		goto out;
	}


	full_path = build_path_from_dentry(direntry);
	full_path = build_path_from_dentry(direntry);
	if (!full_path)
	if (!full_path)
@@ -559,6 +542,9 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
	if ((rc != 0) && cap_unix(tcon->ses))
	if ((rc != 0) && cap_unix(tcon->ses))
		rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path,
		rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path,
					     cifs_sb->local_nls);
					     cifs_sb->local_nls);
	else if (rc != 0 && server->ops->query_symlink)
		rc = server->ops->query_symlink(xid, tcon, full_path,
						&target_path, cifs_sb);


	kfree(full_path);
	kfree(full_path);
out:
out:
+3 −0
Original line number Original line Diff line number Diff line
@@ -172,6 +172,9 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
		if (cifs_dfs_is_possible(cifs_sb) &&
		if (cifs_dfs_is_possible(cifs_sb) &&
		    (fattr->cf_cifsattrs & ATTR_REPARSE))
		    (fattr->cf_cifsattrs & ATTR_REPARSE))
			fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
			fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
	} else if (fattr->cf_cifsattrs & ATTR_REPARSE) {
		fattr->cf_mode = S_IFLNK;
		fattr->cf_dtype = DT_LNK;
	} else {
	} else {
		fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
		fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
		fattr->cf_dtype = DT_REG;
		fattr->cf_dtype = DT_REG;
+1 −1
Original line number Original line Diff line number Diff line
@@ -86,7 +86,7 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
	if (oparms->tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING)
	if (oparms->tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING)
		memcpy(smb2_oplock + 1, fid->lease_key, SMB2_LEASE_KEY_SIZE);
		memcpy(smb2_oplock + 1, fid->lease_key, SMB2_LEASE_KEY_SIZE);


	rc = SMB2_open(xid, oparms, smb2_path, smb2_oplock, smb2_data);
	rc = SMB2_open(xid, oparms, smb2_path, smb2_oplock, smb2_data, NULL);
	if (rc)
	if (rc)
		goto out;
		goto out;


Loading