Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUrban Widmark <urban@teststation.com>2002-03-07 00:55:56 -0800
committerLinus Torvalds <torvalds@penguin.transmeta.com>2002-03-07 00:55:56 -0800
commit63547b0604f68b7b75d5943afefae02dee1bc132 (patch)
tree914da6ad0850203a04feb43230aadc509002213d
parentde8999dc14d432088098f1790c679a537b42a7ff (diff)
[PATCH] smbfs unicode support
This patch adds unicode support and wants to be applied on top of the LFS one. It uses a fake nls module to do the (little endian) unicode translation.
-rw-r--r--fs/smbfs/ChangeLog4
-rw-r--r--fs/smbfs/proc.c137
-rw-r--r--include/linux/smb_fs.h4
-rw-r--r--include/linux/smb_mount.h1
-rw-r--r--include/linux/smbno.h18
5 files changed, 133 insertions, 31 deletions
diff --git a/fs/smbfs/ChangeLog b/fs/smbfs/ChangeLog
index 33569124eca8..4b6dec14564b 100644
--- a/fs/smbfs/ChangeLog
+++ b/fs/smbfs/ChangeLog
@@ -1,5 +1,9 @@
ChangeLog for smbfs.
+2001-08-03 Urban Widmark <urban@teststation.com>
+
+ * *.c: Unicode support
+
2001-08-23 Jochen Dolze <dolze@epcnet.de>
* proc.c: Correct rsize/wsize computation for readX/writeX
diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c
index b0380ebf43af..336619bf6ec1 100644
--- a/fs/smbfs/proc.c
+++ b/fs/smbfs/proc.c
@@ -111,8 +111,8 @@ static void reverse_string(char *buf, int len)
}
/* no conversion, just a wrapper for memcpy. */
-static int convert_memcpy(char *output, int olen,
- const char *input, int ilen,
+static int convert_memcpy(unsigned char *output, int olen,
+ const unsigned char *input, int ilen,
struct nls_table *nls_from,
struct nls_table *nls_to)
{
@@ -139,8 +139,8 @@ static inline int write_unichar(wchar_t ch, char *output, int olen)
}
/* convert from one "codepage" to another (possibly being utf8). */
-static int convert_cp(char *output, int olen,
- const char *input, int ilen,
+static int convert_cp(unsigned char *output, int olen,
+ const unsigned char *input, int ilen,
struct nls_table *nls_from,
struct nls_table *nls_to)
{
@@ -150,7 +150,7 @@ static int convert_cp(char *output, int olen,
while (ilen > 0) {
/* convert by changing to unicode and back to the new cp */
- n = nls_from->char2uni((unsigned char *)input, ilen, &ch);
+ n = nls_from->char2uni(input, ilen, &ch);
if (n == -EINVAL) {
ilen--;
n = write_char(*input++, output, olen);
@@ -180,6 +180,42 @@ fail:
return n;
}
+/* ----------------------------------------------------------- */
+
+/*
+ * nls_unicode
+ *
+ * This encodes/decodes little endian unicode format
+ */
+
+static int uni2char(wchar_t uni, unsigned char *out, int boundlen)
+{
+ if (boundlen < 2)
+ return -EINVAL;
+ *out++ = uni & 0xff;
+ *out++ = uni >> 8;
+ return 2;
+}
+
+static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni)
+{
+ if (boundlen < 2)
+ return -EINVAL;
+ *uni = (rawstring[1] << 8) | rawstring[0];
+ return 2;
+}
+
+static struct nls_table unicode_table = {
+ "unicode",
+ uni2char,
+ char2uni,
+ NULL, /* not used by smbfs */
+ NULL,
+ NULL, /* not a module */
+};
+
+/* ----------------------------------------------------------- */
+
static int setcodepage(struct nls_table **p, char *name)
{
struct nls_table *nls;
@@ -192,7 +228,7 @@ static int setcodepage(struct nls_table **p, char *name)
}
/* if already set, unload the previous one. */
- if (*p)
+ if (*p && *p != &unicode_table)
unload_nls(*p);
*p = nls;
@@ -210,12 +246,19 @@ int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp)
if (!*cp->remote_name)
goto out;
+ /* local */
n = setcodepage(&server->local_nls, cp->local_name);
if (n != 0)
goto out;
- n = setcodepage(&server->remote_nls, cp->remote_name);
- if (n != 0)
- setcodepage(&server->local_nls, NULL);
+
+ /* remote */
+ if (!strcmp(cp->remote_name, "unicode")) {
+ server->remote_nls = &unicode_table;
+ } else {
+ n = setcodepage(&server->remote_nls, cp->remote_name);
+ if (n != 0)
+ setcodepage(&server->local_nls, NULL);
+ }
out:
if (server->local_nls != NULL && server->remote_nls != NULL)
@@ -252,13 +295,15 @@ smb_encode_smb_length(__u8 * p, __u32 len)
* smb_build_path: build the path to entry and name storing it in buf.
* The path returned will have the trailing '\0'.
*/
-static int smb_build_path(struct smb_sb_info *server, char * buf, int maxlen,
- struct dentry * entry, struct qstr * name)
+static int smb_build_path(struct smb_sb_info *server, unsigned char *buf,
+ int maxlen,
+ struct dentry *entry, struct qstr *name)
{
- char *path = buf;
+ unsigned char *path = buf;
int len;
+ int unicode = (server->mnt->flags & SMB_MOUNT_UNICODE) != 0;
- if (maxlen < 2)
+ if (maxlen < (2<<unicode))
return -ENAMETOOLONG;
if (maxlen > SMB_MAXPATHLEN + 1)
@@ -272,8 +317,10 @@ static int smb_build_path(struct smb_sb_info *server, char * buf, int maxlen,
*/
if (IS_ROOT(entry) && !name) {
*path++ = '\\';
+ if (unicode) *path++ = '\0';
*path++ = '\0';
- return 2;
+ if (unicode) *path++ = '\0';
+ return path-buf;
}
/*
@@ -282,7 +329,7 @@ static int smb_build_path(struct smb_sb_info *server, char * buf, int maxlen,
*/
read_lock(&dparent_lock);
while (!IS_ROOT(entry)) {
- if (maxlen < 3) {
+ if (maxlen < (3<<unicode)) {
read_unlock(&dparent_lock);
return -ENAMETOOLONG;
}
@@ -296,22 +343,29 @@ static int smb_build_path(struct smb_sb_info *server, char * buf, int maxlen,
}
reverse_string(path, len);
path += len;
+ if (unicode) {
+ /* Note: reverse order */
+ *path++ = '\0';
+ maxlen--;
+ }
*path++ = '\\';
maxlen -= len+1;
entry = entry->d_parent;
- if (IS_ROOT(entry))
- break;
}
read_unlock(&dparent_lock);
reverse_string(buf, path-buf);
- /* maxlen is at least 1 */
+ /* maxlen has space for at least one char */
test_name_and_out:
if (name) {
- if (maxlen < 3)
+ if (maxlen < (3<<unicode))
return -ENAMETOOLONG;
*path++ = '\\';
+ if (unicode) {
+ *path++ = '\0';
+ maxlen--;
+ }
len = server->ops->convert(path, maxlen-2,
name->name, name->len,
server->local_nls, server->remote_nls);
@@ -320,8 +374,9 @@ test_name_and_out:
path += len;
maxlen -= len+1;
}
- /* maxlen is at least 1 */
+ /* maxlen has space for at least one char */
*path++ = '\0';
+ if (unicode) *path++ = '\0';
return path-buf;
}
@@ -339,16 +394,31 @@ out:
return result;
}
+/* encode_path for non-trans2 request SMBs */
static int smb_simple_encode_path(struct smb_sb_info *server, char **p,
struct dentry * entry, struct qstr * name)
{
char *s = *p;
int res;
int maxlen = ((char *)server->packet + server->packet_size) - s;
+ int unicode = (server->mnt->flags & SMB_MOUNT_UNICODE);
if (!maxlen)
return -ENAMETOOLONG;
- *s++ = 4;
+ *s++ = 4; /* ASCII data format */
+
+ /*
+ * SMB Unicode strings must be 16bit aligned relative the start of the
+ * packet. If they are not they must be padded with 0.
+ */
+ if (unicode) {
+ int align = s - (char *)server->packet;
+ if (align & 1) {
+ *s++ = '\0';
+ maxlen--;
+ }
+ }
+
res = smb_encode_path(server, s, maxlen-1, entry, name);
if (res < 0)
return res;
@@ -908,11 +978,14 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt)
SB_of(server)->s_maxbytes = ~0ULL >> 1;
VERBOSE("LFS enabled\n");
}
-#if 0
- /* flags we will test for other patches ... */
if (server->opt.capabilities & SMB_CAP_UNICODE) {
+ server->mnt->flags |= SMB_MOUNT_UNICODE;
VERBOSE("Unicode enabled\n");
+ } else {
+ server->mnt->flags &= ~SMB_MOUNT_UNICODE;
}
+#if 0
+ /* flags we may test for other patches ... */
if (server->opt.capabilities & SMB_CAP_LARGE_READX) {
VERBOSE("Large reads enabled\n");
}
@@ -997,10 +1070,15 @@ smb_setup_header(struct smb_sb_info * server, __u8 command, __u16 wct, __u16 bcc
WSET(buf, smb_uid, server->opt.server_uid);
WSET(buf, smb_mid, 1);
- if (server->opt.protocol > SMB_PROTOCOL_CORE)
- {
- *(buf+smb_flg) = 0x8;
- WSET(buf, smb_flg2, 0x3);
+ if (server->opt.protocol > SMB_PROTOCOL_CORE) {
+ int flags = SMB_FLAGS_CASELESS_PATHNAMES;
+ int flags2 = SMB_FLAGS2_LONG_PATH_COMPONENTS |
+ SMB_FLAGS2_EXTENDED_ATTRIBUTES; /* EA? not really ... */
+
+ *(buf+smb_flg) = flags;
+ if (server->mnt->flags & SMB_MOUNT_UNICODE)
+ flags2 |= SMB_FLAGS2_UNICODE_STRINGS;
+ WSET(buf, smb_flg2, flags2);
}
*p++ = wct; /* wct */
p += 2 * wct;
@@ -1953,6 +2031,7 @@ smb_decode_long_dirent(struct smb_sb_info *server, char *p, int level,
unsigned int len = 0;
int n;
__u16 date, time;
+ int unicode = (server->mnt->flags & SMB_MOUNT_UNICODE);
/*
* SMB doesn't have a concept of inode numbers ...
@@ -1988,9 +2067,9 @@ smb_decode_long_dirent(struct smb_sb_info *server, char *p, int level,
result = p + WVAL(p, 0);
len = DVAL(p, 60);
if (len > 255) len = 255;
- /* NT4 null terminates */
+ /* NT4 null terminates, unless we are using unicode ... */
qname->name = p + 94;
- if (len && qname->name[len-1] == '\0')
+ if (!unicode && len && qname->name[len-1] == '\0')
len--;
fattr->f_ctime = smb_ntutc2unixutc(LVAL(p, 8));
diff --git a/include/linux/smb_fs.h b/include/linux/smb_fs.h
index ce6aa41fdac1..62c079d5a44b 100644
--- a/include/linux/smb_fs.h
+++ b/include/linux/smb_fs.h
@@ -178,8 +178,8 @@ struct smb_ops {
/* --- --- --- end of "static" entries --- --- --- */
- int (*convert)(char *output, int olen,
- const char *input, int ilen,
+ int (*convert)(unsigned char *output, int olen,
+ const unsigned char *input, int ilen,
struct nls_table *nls_from,
struct nls_table *nls_to);
};
diff --git a/include/linux/smb_mount.h b/include/linux/smb_mount.h
index fe65cdb6c6d6..f4435d7459f0 100644
--- a/include/linux/smb_mount.h
+++ b/include/linux/smb_mount.h
@@ -37,6 +37,7 @@ struct smb_mount_data {
#define SMB_MOUNT_OLDATTR 0x0002 /* Use core getattr (Win 95 speedup) */
#define SMB_MOUNT_DIRATTR 0x0004 /* Use find_first for getattr */
#define SMB_MOUNT_CASE 0x0008 /* Be case sensitive */
+#define SMB_MOUNT_UNICODE 0x0010 /* Server talks unicode */
struct smb_mount_data_kernel {
diff --git a/include/linux/smbno.h b/include/linux/smbno.h
index 654a8937ab03..c1495bba359f 100644
--- a/include/linux/smbno.h
+++ b/include/linux/smbno.h
@@ -310,4 +310,22 @@
#define SMB_SET_FILE_ALLOCATION_INFO 0x103
#define SMB_SET_FILE_END_OF_FILE_INFO 0x104
+/* smb_flg field flags */
+#define SMB_FLAGS_SUPPORT_LOCKREAD 0x01
+#define SMB_FLAGS_CLIENT_BUF_AVAIL 0x02
+#define SMB_FLAGS_RESERVED 0x04
+#define SMB_FLAGS_CASELESS_PATHNAMES 0x08
+#define SMB_FLAGS_CANONICAL_PATHNAMES 0x10
+#define SMB_FLAGS_REQUEST_OPLOCK 0x20
+#define SMB_FLAGS_REQUEST_BATCH_OPLOCK 0x40
+#define SMB_FLAGS_REPLY 0x80
+
+/* smb_flg2 field flags (samba-2.2.0/source/include/smb.h) */
+#define SMB_FLAGS2_LONG_PATH_COMPONENTS 0x0001
+#define SMB_FLAGS2_EXTENDED_ATTRIBUTES 0x0002
+#define SMB_FLAGS2_DFS_PATHNAMES 0x1000
+#define SMB_FLAGS2_READ_PERMIT_NO_EXECUTE 0x2000
+#define SMB_FLAGS2_32_BIT_ERROR_CODES 0x4000
+#define SMB_FLAGS2_UNICODE_STRINGS 0x8000
+
#endif /* _SMBNO_H_ */