[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 <torvalds@osdl.org>
This commit is contained in:
Steve French 2005-04-28 22:41:05 -07:00 committed by Linus Torvalds
parent cbe0476fa6
commit 6a0b48245a
8 changed files with 116 additions and 12 deletions

View file

@ -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 unless server explicitly claims to support them in CIFS Unix extensions
POSIX ACL capability bit. Fix packet signing when multiuser mounting with POSIX ACL capability bit. Fix packet signing when multiuser mounting with
different users from the same client to the same server. Fix oops in 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 Version 1.31
------------ ------------

View file

@ -376,6 +376,17 @@ A partial list of the supported mount options follows:
attributes) to the server (default) e.g. via setfattr attributes) to the server (default) e.g. via setfattr
and getfattr utilities. and getfattr utilities.
nouser_xattr Do not allow getfattr/setfattr to get/set xattrs 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 The mount.cifs mount helper also accepts a few mount options before -o
including: including:

View file

@ -1,4 +1,4 @@
version 1.22 July 30, 2004 version 1.32 April 3, 2005
A Partial List of Missing Features A Partial List of Missing Features
================================== ==================================
@ -14,7 +14,7 @@ b) Better pam/winbind integration (e.g. to handle uid mapping
better) better)
c) multi-user mounts - multiplexed sessionsetups over single vc 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) 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) 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 1) existing symbolic links (Windows reparse points) are recognized but
can not be created remotely. They are implemented for Samba and those that 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 support the CIFS Unix extensions, although earlier versions of Samba
symlink text beginning with slash overly restrict the pathnames.
2) follow_link and readdir code does not follow dfs junctions 2) follow_link and readdir code does not follow dfs junctions
but recognizes them but recognizes them
3) create of new files to FAT partitions on Windows servers can 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 and when signing is disabled to request larger read sizes (larger than
negotiated size) and send larger write sizes to modern servers. negotiated size) and send larger write sizes to modern servers.
4) More exhaustively test the recently added NT4 support against various 4) More exhaustively test against less common servers. More testing
NT4 service pack levels, and fix cifs_setattr for setting file times and against Windows 9x, Windows ME servers.
size to fall back to level 1 when error invalid level returned.

View file

@ -23,6 +23,7 @@
#define CIFS_MOUNT_SERVER_INUM 4 /* inode numbers from uniqueid from server */ #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_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_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 cifs_sb_info {
struct cifsTconInfo *tcon; /* primary mount */ struct cifsTconInfo *tcon; /* primary mount */

View file

@ -212,6 +212,8 @@ extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName, __u64 * inode_number, const unsigned char *searchName, __u64 * inode_number,
const struct nls_table *nls_codepage); 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 */ #endif /* CONFIG_CIFS_EXPERIMENTAL */
extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,

View file

@ -72,6 +72,7 @@ struct smb_vol {
unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/ unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/
unsigned server_ino:1; /* use inode numbers from server ie UniqueId */ unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
unsigned direct_io:1; unsigned direct_io:1;
unsigned remap:1; /* set to remap seven reserved chars in filenames */
unsigned int rsize; unsigned int rsize;
unsigned int wsize; unsigned int wsize;
unsigned int sockopt; unsigned int sockopt;
@ -771,6 +772,10 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
vol->noperm = 0; vol->noperm = 0;
} else if (strnicmp(data, "noperm", 6) == 0) { } else if (strnicmp(data, "noperm", 6) == 0) {
vol->noperm = 1; 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) { } else if (strnicmp(data, "setuids", 7) == 0) {
vol->setuids = 1; vol->setuids = 1;
} else if (strnicmp(data, "nosetuids", 9) == 0) { } 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; cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
if(volume_info.server_ino) if(volume_info.server_ino)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM; 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) if(volume_info.no_xattr)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
if(volume_info.direct_io) { if(volume_info.direct_io) {

View file

@ -514,3 +514,72 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length)
printk( " | %s\n", debug_line); printk( " | %s\n", debug_line);
return; 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 */

View file

@ -600,7 +600,14 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst,
if(unicode) { if(unicode) {
/* BB fixme - test with long names */ /* BB fixme - test with long names */
/* Note converted filename can be longer than in unicode */ /* 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 { } else {
pqst->name = filename; pqst->name = filename;
pqst->len = len; 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 + end_of_smb = cifsFile->srch_inf.ntwrk_buf_start +
smbCalcSize((struct smb_hdr *) smbCalcSize((struct smb_hdr *)
cifsFile->srch_inf.ntwrk_buf_start); 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<num_to_fill) && (rc == 0);i++) { for(i=0;(i<num_to_fill) && (rc == 0);i++) {
if(current_entry == NULL) { if(current_entry == NULL) {
/* evaluate whether this case is an error */ /* evaluate whether this case is an error */