From 6a0b48245a135cd132e747815854e3999967f8a7 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Apr 2005 22:41:05 -0700 Subject: [PATCH] [PATCH] cifs: Add new mount parm mapchars For handling seven special characters that shells use for filenames. This first parts implements conversions from Unicode. Signed-off-by: Steve French Signed-off-by: Linus Torvalds --- fs/cifs/CHANGES | 4 ++- fs/cifs/README | 11 +++++++ fs/cifs/TODO | 19 ++++++------ fs/cifs/cifs_fs_sb.h | 1 + fs/cifs/cifsproto.h | 2 ++ fs/cifs/connect.c | 7 +++++ fs/cifs/misc.c | 69 ++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/readdir.c | 15 ++++++++-- 8 files changed, 116 insertions(+), 12 deletions(-) diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index ce16b0ae772e..412b6d243d53 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -7,7 +7,9 @@ as new protocol extensions. Do not send Get/Set calls for POSIX ACLs unless server explicitly claims to support them in CIFS Unix extensions POSIX ACL capability bit. Fix packet signing when multiuser mounting with different users from the same client to the same server. Fix oops in -cifs_close. +cifs_close. Add mount option for remapping reserved characters in +filenames (also allow recognizing files with created by SFU which have any +of these seven reserved characters to be recognized). Version 1.31 ------------ diff --git a/fs/cifs/README b/fs/cifs/README index 0f20edc935b5..83e054576258 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -376,6 +376,17 @@ A partial list of the supported mount options follows: attributes) to the server (default) e.g. via setfattr and getfattr utilities. nouser_xattr Do not allow getfattr/setfattr to get/set xattrs + mapchars Translate the seven reserved characters + *?<>|:\ + to the remap range (above 0xF000), which also + allows the CIFS client to recognize files created with + such characters by Windows's POSIX emulation. This can + also be useful when mounting to most versions of Samba + (which also forbids creating and opening files + whose names contain any of these seven characters). + This has no effect if the server does not support + Unicode on the wire. + nomapchars Do not translate any of these seven characters (default). The mount.cifs mount helper also accepts a few mount options before -o including: diff --git a/fs/cifs/TODO b/fs/cifs/TODO index f4e3e1f67ee4..a69227415a73 100644 --- a/fs/cifs/TODO +++ b/fs/cifs/TODO @@ -1,4 +1,4 @@ -version 1.22 July 30, 2004 +version 1.32 April 3, 2005 A Partial List of Missing Features ================================== @@ -14,7 +14,7 @@ b) Better pam/winbind integration (e.g. to handle uid mapping better) c) multi-user mounts - multiplexed sessionsetups over single vc -(ie tcp session) - prettying up needed, and more testing needed +(ie tcp session) - more testing needed d) Kerberos/SPNEGO session setup support - (started) @@ -67,12 +67,15 @@ q) implement support for security and trusted categories of xattrs r) Implement O_DIRECT flag on open (already supported on mount) -KNOWN BUGS (updated December 10, 2004) +KNOWN BUGS (updated April 3, 2005) ==================================== +See http://bugzilla.samba.org - search on product "CifsVFS" for +current bug list. + 1) existing symbolic links (Windows reparse points) are recognized but can not be created remotely. They are implemented for Samba and those that -support the CIFS Unix extensions but Samba has a bug currently handling -symlink text beginning with slash +support the CIFS Unix extensions, although earlier versions of Samba +overly restrict the pathnames. 2) follow_link and readdir code does not follow dfs junctions but recognizes them 3) create of new files to FAT partitions on Windows servers can @@ -98,7 +101,5 @@ there are some easy changes that can be done to parallelize sequential writes, and when signing is disabled to request larger read sizes (larger than negotiated size) and send larger write sizes to modern servers. -4) More exhaustively test the recently added NT4 support against various -NT4 service pack levels, and fix cifs_setattr for setting file times and -size to fall back to level 1 when error invalid level returned. - +4) More exhaustively test against less common servers. More testing +against Windows 9x, Windows ME servers. diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 77da902d8f32..ec00d61d5308 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -23,6 +23,7 @@ #define CIFS_MOUNT_SERVER_INUM 4 /* inode numbers from uniqueid from server */ #define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */ #define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */ +#define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */ struct cifs_sb_info { struct cifsTconInfo *tcon; /* primary mount */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index dd95c2bcbc25..b486ba738d95 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -212,6 +212,8 @@ extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, __u64 * inode_number, const struct nls_table *nls_codepage); +extern int cifs_convertUCSpath(char *target, const __u16 *source, int maxlen, + const struct nls_table * codepage); #endif /* CONFIG_CIFS_EXPERIMENTAL */ extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 814e709ca0ca..3d036bf689d8 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -72,6 +72,7 @@ struct smb_vol { unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/ unsigned server_ino:1; /* use inode numbers from server ie UniqueId */ unsigned direct_io:1; + unsigned remap:1; /* set to remap seven reserved chars in filenames */ unsigned int rsize; unsigned int wsize; unsigned int sockopt; @@ -771,6 +772,10 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) vol->noperm = 0; } else if (strnicmp(data, "noperm", 6) == 0) { vol->noperm = 1; + } else if (strnicmp(data, "mapchars", 8) == 0) { + vol->remap = 1; + } else if (strnicmp(data, "nomapchars", 10) == 0) { + vol->remap = 0; } else if (strnicmp(data, "setuids", 7) == 0) { vol->setuids = 1; } else if (strnicmp(data, "nosetuids", 9) == 0) { @@ -1421,6 +1426,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID; if(volume_info.server_ino) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM; + if(volume_info.remap) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; if(volume_info.no_xattr) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; if(volume_info.direct_io) { diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 7b38d3059a83..f2a026073b62 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -514,3 +514,72 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length) printk( " | %s\n", debug_line); return; } + +#ifdef CONFIG_CIFS_EXPERIMENTAL +/* Windows maps these to the user defined 16 bit Unicode range since they are + reserved symbols (along with \ and /), otherwise illegal to store + in filenames in NTFS */ +#define UNI_ASTERIK cpu_to_le16('*' + 0xF000) +#define UNI_QUESTION cpu_to_le16('?' + 0xF000) +#define UNI_COLON cpu_to_le16(':' + 0xF000) +#define UNI_GRTRTHAN cpu_to_le16('>' + 0xF000) +#define UNI_LESSTHAN cpu_to_le16('<' + 0xF000) +#define UNI_PIPE cpu_to_le16('|' + 0xF000) +#define UNI_SLASH cpu_to_le16('\\' + 0xF000) + +/* Convert 16 bit Unicode pathname from wire format to string in current code + page. Conversion may involve remapping up the seven characters that are + only legal in POSIX-like OS (if they are present in the string). Path + names are little endian 16 bit Unicode on the wire */ +int +cifs_convertUCSpath(char *target, const __le16 * source, int maxlen, + const struct nls_table * cp) +{ + int i,j,len; + wchar_t src_char; + + for(i = 0, j = 0; i < maxlen; i++) { + src_char = le16_to_cpu(source[i]); + switch (src_char) { + case 0: + goto cUCS_out; /* BB check this BB */ + case UNI_COLON: + target[j] = ':'; + break; + case UNI_ASTERIK: + target[j] = '*'; + break; + case UNI_QUESTION: + target[j] = '?'; + break; + case UNI_SLASH: + target[j] = '\\'; /* BB check this - is there risk here of converting path sep BB */ + break; + case UNI_PIPE: + target[j] = '|'; + break; + case UNI_GRTRTHAN: + target[j] = '>'; + break; + case UNI_LESSTHAN: + target[j] = '<'; + default: + len = cp->uni2char(src_char, &target[j], + NLS_MAX_CHARSET_SIZE); + if(len > 0) { + j += len; + continue; + } else { + target[j] = '?'; + } + } + j++; + /* check to make sure we do not overrun callers allocated temp buffer */ + if(j >= (2 * NAME_MAX)) + break; + } +cUCS_out: + target[j] = 0; + return j; +} +#endif /* CIFS_EXPERIMENTAL */ diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 07838a5ba3a1..4a33add24d53 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -600,7 +600,14 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, if(unicode) { /* BB fixme - test with long names */ /* Note converted filename can be longer than in unicode */ - pqst->len = cifs_strfromUCS_le((char *)pqst->name,(wchar_t *)filename,len/2,nlt); +#ifdef CONFIG_CIFS_EXPERIMENTAL + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) + pqst->len = cifs_convertUCSpath((char *)pqst->name, + (__le16 *)filename, len/2, nlt); + else +#endif /* CIFS_EXPERIMENTAL */ + pqst->len = cifs_strfromUCS_le((char *)pqst->name, + (wchar_t *)filename,len/2,nlt); } else { pqst->name = filename; pqst->len = len; @@ -829,7 +836,11 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + smbCalcSize((struct smb_hdr *) cifsFile->srch_inf.ntwrk_buf_start); - tmp_buf = kmalloc(NAME_MAX+1,GFP_KERNEL); + /* To be safe - for UCS to UTF-8 with strings loaded + with the rare long characters alloc more to account for + such multibyte target UTF-8 characters. cifs_unicode.c, + which actually does the conversion, has the same limit */ + tmp_buf = kmalloc((2 * NAME_MAX) + 4, GFP_KERNEL); for(i=0;(i