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>
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
------------
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:
-version 1.22 July 30, 2004
+version 1.32 April 3, 2005
A Partial List of Missing Features
==================================
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)
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
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.
#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 */
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,
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;
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) {
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) {
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 */
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;
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<num_to_fill) && (rc == 0);i++) {
if(current_entry == NULL) {
/* evaluate whether this case is an error */