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

Commit 2baa2682 authored by Steve French's avatar Steve French
Browse files

Remap reserved posix characters by default (part 3/3)



This is a bigger patch, but its size is mostly due to
a single change for how we check for remapping illegal characters
in file names - a lot of repeated, small changes to
the way callers request converting file names.

The final patch in the series does the following:

1) changes default behavior for cifs to be more intuitive.
Currently we do not map by default to seven reserved characters,
ie those valid in POSIX but not in NTFS/CIFS/SMB3/Windows,
unless a mount option (mapchars) is specified.  Change this
to by default always map and map using the SFM maping
(like the Mac uses) unless the server negotiates the CIFS Unix
Extensions (like Samba does when mounting with the cifs protocol)
when the remapping of the characters is unnecessary.  This should
help SMB3 mounts in particular since Samba will likely be
able to implement this mapping with its new "vfs_fruit" module
as it will be doing for the Mac.
2) if the user specifies the existing "mapchars" mount option then
use the "SFU" (Microsoft Services for Unix, SUA) style mapping of
the seven characters instead.
3) if the user specifies "nomapposix" then disable SFM/MAC style mapping
(so no character remapping would be used unless the user specifies
"mapchars" on mount as well, as above).
4) change all the places in the code that check for the superblock
flag on the mount which is set by mapchars and passed in on all
path based operation and change it to use a small function call
instead to set the mapping type properly (and check for the
mapping type in the cifs unicode functions)

Signed-off-by: default avatarSteve French <smfrench@gmail.com>
parent a4153cb1
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
 */
#include <linux/fs.h>
#include <linux/slab.h>
#include "cifs_fs_sb.h"
#include "cifs_unicode.h"
#include "cifs_uniupr.h"
#include "cifspdu.h"
@@ -61,6 +62,20 @@ cifs_utf16_bytes(const __le16 *from, int maxbytes,
	return outlen;
}

int cifs_remap(struct cifs_sb_info *cifs_sb)
{
	int map_type;

	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SFM_CHR)
		map_type = SFM_MAP_UNI_RSVD;
	else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
		map_type = SFU_MAP_UNI_RSVD;
	else
		map_type = NO_MAP_UNI_RSVD;

	return map_type;
}

/* Convert character using the SFU - "Services for Unix" remapping range */
static bool
convert_sfu_char(const __u16 src_char, char *target)
+1 −0
Original line number Diff line number Diff line
@@ -112,6 +112,7 @@ char *cifs_strndup_from_utf16(const char *src, const int maxlen,
			      const struct nls_table *codepage);
extern int cifsConvertToUTF16(__le16 *target, const char *source, int maxlen,
			      const struct nls_table *cp, int mapChars);
extern int cifs_remap(struct cifs_sb_info *cifs_sb);
#ifdef CONFIG_CIFS_SMB2
extern __le16 *cifs_strndup_to_utf16(const char *src, const int maxlen,
				     int *utf16_len, const struct nls_table *cp,
+2 −0
Original line number Diff line number Diff line
@@ -466,6 +466,7 @@ struct smb_vol {
	bool direct_io:1;
	bool strict_io:1; /* strict cache behavior */
	bool remap:1;      /* set to remap seven reserved chars in filenames */
	bool sfu_remap:1;  /* remap seven reserved chars ala SFU */
	bool posix_paths:1; /* unset to not ask for posix pathnames. */
	bool no_linux_ext:1;
	bool sfu_emul:1;
@@ -499,6 +500,7 @@ struct smb_vol {
#define CIFS_MOUNT_MASK (CIFS_MOUNT_NO_PERM | CIFS_MOUNT_SET_UID | \
			 CIFS_MOUNT_SERVER_INUM | CIFS_MOUNT_DIRECT_IO | \
			 CIFS_MOUNT_NO_XATTR | CIFS_MOUNT_MAP_SPECIAL_CHR | \
			 CIFS_MOUNT_MAP_SFM_CHR | \
			 CIFS_MOUNT_UNX_EMUL | CIFS_MOUNT_NO_BRL | \
			 CIFS_MOUNT_CIFS_ACL | CIFS_MOUNT_OVERR_UID | \
			 CIFS_MOUNT_OVERR_GID | CIFS_MOUNT_DYNPERM | \
+8 −8
Original line number Diff line number Diff line
@@ -867,7 +867,7 @@ CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
	int rc = 0;
	int bytes_returned;
	int name_len;
	int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
	int remap = cifs_remap(cifs_sb);

DelFileRetry:
	rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
@@ -913,7 +913,7 @@ CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
	int rc = 0;
	int bytes_returned;
	int name_len;
	int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
	int remap = cifs_remap(cifs_sb);

	cifs_dbg(FYI, "In CIFSSMBRmDir\n");
RmDirRetry:
@@ -958,7 +958,7 @@ CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
	CREATE_DIRECTORY_RSP *pSMBr = NULL;
	int bytes_returned;
	int name_len;
	int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
	int remap = cifs_remap(cifs_sb);

	cifs_dbg(FYI, "In CIFSSMBMkDir\n");
MkDirRetry:
@@ -1280,7 +1280,7 @@ CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
	__u16 count;
	struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
	struct cifs_tcon *tcon = oparms->tcon;
	int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
	int remap = cifs_remap(cifs_sb);
	const struct nls_table *nls = cifs_sb->local_nls;
	int create_options = oparms->create_options;
	int desired_access = oparms->desired_access;
@@ -2572,7 +2572,7 @@ CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
	int bytes_returned;
	int name_len, name_len2;
	__u16 count;
	int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
	int remap = cifs_remap(cifs_sb);

	cifs_dbg(FYI, "In CIFSSMBRename\n");
renameRetry:
@@ -2968,7 +2968,7 @@ CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
	int bytes_returned;
	int name_len, name_len2;
	__u16 count;
	int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
	int remap = cifs_remap(cifs_sb);

	cifs_dbg(FYI, "In CIFSCreateHardLink\n");
winCreateHardLinkRetry:
@@ -4367,7 +4367,7 @@ CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
		return rc;

	nls_codepage = cifs_sb->local_nls;
	remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
	remap = cifs_remap(cifs_sb);

	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
		name_len =
@@ -5527,7 +5527,7 @@ CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
	int name_len;
	int rc = 0;
	int bytes_returned = 0;
	int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
	int remap = cifs_remap(cifs_sb);

	__u16 params, byte_count, data_count, param_offset, offset;

+25 −5
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ enum {
	Opt_forcegid, Opt_noforcegid,
	Opt_noblocksend, Opt_noautotune,
	Opt_hard, Opt_soft, Opt_perm, Opt_noperm,
	Opt_mapposix, Opt_nomapposix,
	Opt_mapchars, Opt_nomapchars, Opt_sfu,
	Opt_nosfu, Opt_nodfs, Opt_posixpaths,
	Opt_noposixpaths, Opt_nounix,
@@ -124,8 +125,10 @@ static const match_table_t cifs_mount_option_tokens = {
	{ Opt_soft, "soft" },
	{ Opt_perm, "perm" },
	{ Opt_noperm, "noperm" },
	{ Opt_mapchars, "mapchars" },
	{ Opt_mapchars, "mapchars" }, /* SFU style */
	{ Opt_nomapchars, "nomapchars" },
	{ Opt_mapposix, "mapposix" }, /* SFM style */
	{ Opt_nomapposix, "nomapposix" },
	{ Opt_sfu, "sfu" },
	{ Opt_nosfu, "nosfu" },
	{ Opt_nodfs, "nodfs" },
@@ -1231,6 +1234,14 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
	vol->linux_uid = current_uid();
	vol->linux_gid = current_gid();

	/*
	 * default to SFM style remapping of seven reserved characters
	 * unless user overrides it or we negotiate CIFS POSIX where
	 * it is unnecessary.  Can not simultaneously use more than one mapping
	 * since then readdir could list files that open could not open
	 */
	vol->remap = true;

	/* default to only allowing write access to owner of the mount */
	vol->dir_mode = vol->file_mode = S_IRUGO | S_IXUGO | S_IWUSR;

@@ -1338,10 +1349,18 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
			vol->noperm = 1;
			break;
		case Opt_mapchars:
			vol->remap = 1;
			vol->sfu_remap = true;
			vol->remap = false; /* disable SFM mapping */
			break;
		case Opt_nomapchars:
			vol->remap = 0;
			vol->sfu_remap = false;
			break;
		case Opt_mapposix:
			vol->remap = true;
			vol->sfu_remap = false; /* disable SFU mapping */
			break;
		case Opt_nomapposix:
			vol->remap = false;
			break;
		case Opt_sfu:
			vol->sfu_emul = 1;
@@ -3197,6 +3216,8 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
	if (pvolume_info->server_ino)
		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
	if (pvolume_info->remap)
		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SFM_CHR;
	if (pvolume_info->sfu_remap)
		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
	if (pvolume_info->no_xattr)
		cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
@@ -3340,8 +3361,7 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses,
	ref_path = check_prefix ? full_path + 1 : volume_info->UNC + 1;

	rc = get_dfs_path(xid, ses, ref_path, cifs_sb->local_nls,
			  &num_referrals, &referrals,
			  cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
			  &num_referrals, &referrals, cifs_remap(cifs_sb));

	if (!rc && num_referrals > 0) {
		char *fake_devname = NULL;
Loading