Package: kernel-source-2.6.11
Version: 2.6.11-1
Tags: patch
This patch adds national language support to asfs filesystem for Linux kernel.
It introduces iocharset and codepage arguments.
Apply it to a kernel with ASFS already applied.
Tested on 2.6.11.1 (with asfs 1.0b8 applied) and 2.6.8-10 (from Debian
package) kernels.
--
Best regards,
Pavel Fedin,
mailto:[EMAIL PROTECTED]
--- linux-2.6.11.1/fs/asfs/asfs_fs.h.orig 2005-03-09 11:25:34.000000000
-0500
+++ linux-2.6.11.1/fs/asfs/asfs_fs.h 2005-03-09 11:25:56.000000000 -0500
@@ -66,6 +66,10 @@
u16 flags;
char *prefix;
char *root_volume; /* Volume prefix for absolute symlinks.
*/
+ char *iocharset;
+ int codepage;
+ struct nls_table *nls_io;
+ struct nls_table *nls_disk;
};
/* short cut to get to the asfs specific sb data */
@@ -180,8 +184,9 @@
/* namei */
u8 asfs_lowerchar(u8 c);
-int asfs_namecmp(u8 *s, u8 *ct, int casesensitive);
+int asfs_namecmp(u8 *s, u8 *ct, int casesensitive, struct nls_table *t);
u16 asfs_hash(u8 *name, int casesensitive);
+void asfs_translate(u8 *to, u8 *from, struct nls_table *nls_to, struct
nls_table *nls_from);
/* nodes */
int asfs_getnode(struct super_block *sb, u32 nodeno,
--- linux-2.6.11.1/fs/asfs/dir.c.orig 2005-03-09 11:25:34.000000000 -0500
+++ linux-2.6.11.1/fs/asfs/dir.c 2005-03-09 12:53:06.000000000 -0500
@@ -29,6 +29,9 @@
{
struct inode *dir = filp->f_dentry->d_inode;
struct super_block *sb = dir->i_sb;
+ struct nls_table *nls_io = ASFS_SB(sb)->nls_io;
+ struct nls_table *nls_disk = ASFS_SB(sb)->nls_disk;
+ u8 buf[512];
unsigned long f_pos;
int stored = 0;
@@ -93,8 +96,9 @@
if (add && !(obj->bits & OTYPE_HIDDEN)) {
unsigned int type;
+ asfs_translate(buf, obj->name, nls_io,
nls_disk);
asfs_debug("ASFS: DirFilling: entry #%d \"%s\"
(node %u offset %u), type %x\n", \
- stored, obj->name,
be32_to_cpu(obj->objectnode), block, obj->bits);
+ stored, buf,
be32_to_cpu(obj->objectnode), block, obj->bits);
filp->f_pos = block;
if (obj->bits & OTYPE_DIR)
@@ -104,7 +108,7 @@
else
type = DT_REG;
- if (filldir(dirent, obj->name,
strlen(obj->name), block, be32_to_cpu(obj->objectnode), type) < 0) {
+ if (filldir(dirent, buf, strlen(buf), block,
be32_to_cpu(obj->objectnode), type) < 0) {
filp->private_data = (void
*)be32_to_cpu(obj->objectnode);
ASFS_I(dir)->modified = 0;
asfs_debug("ASFS: DirFilling: to be
continued...\n");
@@ -134,12 +138,15 @@
u8 *name = (u8 *) dentry->d_name.name;
struct buffer_head *bh;
struct fsObject *obj;
+ struct nls_table *nls_io = ASFS_SB(sb)->nls_io;
+ struct nls_table *nls_disk = ASFS_SB(sb)->nls_disk;
+ u8 buf[108];
asfs_debug("asfs_lookup: (searching \"%s\"...) ", name);
lock_super(sb);
- if (ASFS_I(dir)->hashtable != 0) { /* hashtable block is
available, quick search */
+ if ((!strchr(name, '?')) && (ASFS_I(dir)->hashtable != 0)) { /*
hashtable block is available and name can be reverse translated, quick search */
struct fsObjectNode *node_p;
struct buffer_head *node_bh;
u32 node;
@@ -151,7 +158,8 @@
unlock_super(sb);
return ERR_PTR(res);
}
- hash16 = asfs_hash(name, ASFS_SB(sb)->flags &
ASFS_ROOTBITS_CASESENSITIVE);
+ asfs_translate(buf, name, nls_disk, nls_io);
+ hash16 = asfs_hash(buf, ASFS_SB(sb)->flags &
ASFS_ROOTBITS_CASESENSITIVE);
node = be32_to_cpu(((struct fsHashTable *)
bh->b_data)->hashentry[HASHCHAIN(hash16)]);
asfs_brelse(bh);
@@ -173,7 +181,7 @@
node = be32_to_cpu(node_p->next);
asfs_brelse(node_bh);
}
- } else { /* hashtable not available, long search */
+ } else { /* hashtable not available or name can't be
reverse-translated, long search */
struct fsObjectContainer *objcont;
u32 block;
--- linux-2.6.11.1/fs/asfs/namei.c.orig 2005-03-09 11:25:34.000000000 -0500
+++ linux-2.6.11.1/fs/asfs/namei.c 2005-03-09 11:25:56.000000000 -0500
@@ -21,6 +21,7 @@
#include <linux/buffer_head.h>
#include <linux/vfs.h>
#include <linux/string.h>
+#include <linux/nls.h>
#include "asfs_fs.h"
static inline u8 asfs_upperchar(u8 c)
@@ -37,6 +38,12 @@
return (c);
}
+static inline u8 asfs_nls_upperchar(u8 c, struct nls_table *t)
+{
+ u8 nc = t->charset2upper[c];
+ return nc ? nc : c;
+}
+
/* Check if the name is valid for a asfs object. */
static inline int asfs_check_name(const u8 *name, int len)
@@ -61,6 +68,7 @@
const u8 *name = qstr->name;
unsigned long hash;
int i;
+ struct nls_table *nls_io = ASFS_SB(sb)->nls_io;
i = asfs_check_name(qstr->name,qstr->len);
if (i)
@@ -73,7 +81,7 @@
hash = partial_name_hash(*name, hash);
else
for (i=qstr->len; i > 0; name++, i--)
- hash = partial_name_hash(asfs_upperchar(*name), hash);
+ hash = partial_name_hash(asfs_nls_upperchar(*name,
nls_io), hash);
qstr->hash = end_name_hash(hash);
@@ -86,6 +94,7 @@
const u8 *aname = a->name;
const u8 *bname = b->name;
int len;
+ struct nls_table *nls_io = ASFS_SB(sb)->nls_io;
/* 'a' is the qstr of an already existing dentry, so the name
* must be valid. 'b' must be validated first.
@@ -103,7 +112,7 @@
return 1;
} else {
for (len=a->len; len > 0; len--)
- if (asfs_upperchar(*aname++) !=
asfs_upperchar(*bname++))
+ if (asfs_nls_upperchar(*aname++, nls_io) !=
asfs_nls_upperchar(*bname++, nls_io))
return 1;
}
@@ -115,7 +124,7 @@
d_compare: asfs_compare_dentry,
};
-int asfs_namecmp(u8 *s, u8 *ct, int casesensitive)
+int asfs_namecmp(u8 *s, u8 *ct, int casesensitive, struct nls_table *t)
{
if (casesensitive) {
while (*s == *ct && *ct != '\0' && *ct != '/') {
@@ -123,7 +132,7 @@
ct++;
}
} else {
- while (asfs_upperchar(*s) == asfs_upperchar(*ct) && *ct != '\0'
+ while (asfs_nls_upperchar(*s, t) == asfs_nls_upperchar(*ct, t)
&& *ct != '\0'
&& *ct != '/') {
s++;
ct++;
@@ -153,3 +162,23 @@
return hashval;
}
+void asfs_translate(u8 *to, u8 *from, struct nls_table *nls_to, struct
nls_table *nls_from)
+{
+ wchar_t uni;
+ int i, len;
+ int from_len = strlen(from);
+
+ for (i=0;i<from_len;) {
+ len = nls_from->char2uni(&from[i], from_len-i, &uni);
+ if (len > 0) {
+ i += len;
+ len = nls_to->uni2char(uni, to, NLS_MAX_CHARSET_SIZE);
+ if (len > 0)
+ to += len;
+ } else
+ i++;
+ if (len < 0)
+ *to++ = '?';
+ }
+ *to = '\0';
+}
--- linux-2.6.11.1/fs/asfs/objects.c.orig 2005-03-09 11:25:34.000000000
-0500
+++ linux-2.6.11.1/fs/asfs/objects.c 2005-03-09 12:55:53.000000000 -0500
@@ -39,11 +39,15 @@
struct fsObject *asfs_find_obj_by_name(struct super_block *sb, struct
fsObjectContainer *objcont, u8 * name)
{
+ struct nls_table *nls_io = ASFS_SB(sb)->nls_io;
+ struct nls_table *nls_disk = ASFS_SB(sb)->nls_disk;
+ u8 buf[512];
struct fsObject *obj;
obj = &(objcont->object[0]);
while (be32_to_cpu(obj->objectnode) > 0 && ((char *) obj - (char *)
objcont) + sizeof(struct fsObject) + 2 < sb->s_blocksize) {
- if (asfs_namecmp(obj->name, name, ASFS_SB(sb)->flags &
ASFS_ROOTBITS_CASESENSITIVE) == 0) {
+ asfs_translate(buf, obj->name, nls_io, nls_disk);
+ if (asfs_namecmp(buf, name, ASFS_SB(sb)->flags &
ASFS_ROOTBITS_CASESENSITIVE, nls_io) == 0) {
asfs_debug("Object found! Node %u, Name %s, Type %x,
inCont %u\n", be32_to_cpu(obj->objectnode), obj->name, obj->bits,
be32_to_cpu(objcont->bheader.ownblock));
return obj;
}
@@ -201,7 +205,7 @@
static int dehashobjectquick(struct super_block *sb, u32 objectnode, u8 *name,
u32 parentobjectnode)
{
struct fsObject *o;
- int errorcode;
+ int errorcode = 0;
struct buffer_head *block;
asfs_debug("dehashobject: Delinking object %d (=ObjectNode) from
hashchain. Parentnode = %d\n", objectnode, parentobjectnode);
@@ -461,6 +465,9 @@
int errorcode;
u32 object_size;
u32 hashblock = be32_to_cpu((*io_o)->object.dir.hashtable);
+ struct nls_table *nls_io = ASFS_SB(sb)->nls_io;
+ struct nls_table *nls_disk = ASFS_SB(sb)->nls_disk;
+ char bufname[108];
asfs_debug("createobject: Creating object '%s' in dir '%s'.\n",
objectname, (*io_o)->name);
@@ -470,12 +477,13 @@
if (!force && be32_to_cpu((*io_o)->objectnode) == ASFS_RECYCLEDNODE)
return -EINVAL;
- object_size = sizeof(struct fsObject) + strlen(objectname) + 2;
+ asfs_translate(bufname, objectname, nls_disk, nls_io);
+ object_size = sizeof(struct fsObject) + strlen(bufname) + 2;
if ((errorcode = findobjectspace(sb, io_bh, io_o, object_size)) == 0) {
struct fsObject *o2 = *io_o;
u8 *name = o2->name;
- u8 *objname = objectname;
+ u8 *objname = bufname;
struct buffer_head *node_bh;
struct fsObjectNode *on;
u32 nodeno;
@@ -500,7 +508,7 @@
if (errorcode == 0) { /* in io_bh there is a container with
created object */
on->node.data = ((struct fsBlockHeader *)
(*io_bh)->b_data)->ownblock;
- if ((errorcode = hashobject(sb, hashblock, on,
be32_to_cpu(o2->objectnode), objectname)) == 0) {
+ if ((errorcode = hashobject(sb, hashblock, on,
be32_to_cpu(o2->objectnode), bufname)) == 0) {
asfs_bstore(sb, node_bh);
asfs_brelse(node_bh);
} else
--- linux-2.6.11.1/fs/asfs/super.c.orig 2005-03-09 11:25:34.000000000 -0500
+++ linux-2.6.11.1/fs/asfs/super.c 2005-03-09 11:25:57.000000000 -0500
@@ -56,11 +56,14 @@
#include <linux/buffer_head.h>
#include <linux/vfs.h>
#include <linux/parser.h>
+#include <linux/nls.h>
#include "asfs_fs.h"
#include <asm/byteorder.h>
#include <asm/uaccess.h>
+static char asfs_default_iocharset[] = CONFIG_ASFS_DEFAULT_IOCHARSET;
+
u32 asfs_calcchecksum(void *block, u32 blocksize)
{
u32 *data = block, checksum = 1;
@@ -86,7 +89,7 @@
enum {
Opt_mode, Opt_setgid, Opt_setuid, Opt_prefix, Opt_volume,
- Opt_lcvol, Opt_ignore, Opt_err,
+ Opt_lcvol, Opt_ignore, Opt_err, Opt_iocharset, Opt_codepage
};
static match_table_t tokens = {
@@ -100,6 +103,8 @@
{Opt_ignore, "noquota"},
{Opt_ignore, "quota"},
{Opt_ignore, "usrquota"},
+ {Opt_iocharset, "iocharset=%s"},
+ {Opt_codepage, "codepage=%u"},
{Opt_err, NULL},
};
@@ -153,6 +158,17 @@
case Opt_lcvol:
ASFS_SB(sb)->flags |= ASFS_VOL_LOWERCASE;
break;
+ case Opt_iocharset:
+ if (ASFS_SB(sb)->iocharset != asfs_default_iocharset)
+ kfree(ASFS_SB(sb)->iocharset);
+ ASFS_SB(sb)->iocharset = match_strdup(&args[0]);
+ if (!ASFS_SB(sb))
+ return 0;
+ break;
+ case Opt_codepage:
+ if (match_int(&args[0], &option))
+ goto no_arg;
+ ASFS_SB(sb)->codepage = option;
case Opt_ignore:
/* Silently ignore the quota options */
break;
@@ -172,6 +188,7 @@
struct buffer_head *bh;
struct fsRootBlock *rootblock;
struct inode *rootinode;
+ char buf[50];
sbi = kmalloc(sizeof(struct asfs_sb_info), GFP_KERNEL);
if (!sbi)
@@ -185,6 +202,8 @@
ASFS_SB(sb)->prefix = NULL;
ASFS_SB(sb)->root_volume = NULL;
ASFS_SB(sb)->flags = 0;
+ ASFS_SB(sb)->iocharset = asfs_default_iocharset;
+ ASFS_SB(sb)->codepage = CONFIG_ASFS_DEFAULT_CODEPAGE;
if (!asfs_parse_options(data, sb)) {
printk(KERN_ERR "ASFS: Error parsing options\n");
@@ -280,6 +299,23 @@
if (ASFS_SB(sb)->flags & ASFS_READONLY)
sb->s_flags |= MS_RDONLY;
sb->s_op = &asfs_ops;
+ asfs_debug("Case sensitive: ");
+ if (ASFS_SB(sb)->flags & ASFS_ROOTBITS_CASESENSITIVE)
+ asfs_debug("yes\n");
+ else
+ asfs_debug("No\n");
+
+ sprintf(buf,"cp%d",ASFS_SB(sb)->codepage);
+ ASFS_SB(sb)->nls_disk = load_nls(buf);
+ if (!ASFS_SB(sb)->nls_disk) {
+ printk(KERN_ERR "ASFS: codepage %s not found\n", buf);
+ return -EINVAL;
+ }
+ ASFS_SB(sb)->nls_io = load_nls(ASFS_SB(sb)->iocharset);
+ if (!ASFS_SB(sb)->nls_io) {
+ printk(KERN_ERR "ASFS: IO charset %s not found\n",
ASFS_SB(sb)->iocharset);
+ goto out2;
+ }
if ((rootinode = asfs_get_root_inode(sb))) {
if ((sb->s_root = d_alloc_root(rootinode))) {
@@ -288,6 +324,9 @@
}
iput(rootinode);
}
+ unload_nls(ASFS_SB(sb)->nls_io);
+out2:
+ unload_nls(ASFS_SB(sb)->nls_disk);
return -EINVAL;
out:
@@ -327,6 +366,12 @@
kfree(ASFS_SB(sb)->prefix);
if (ASFS_SB(sb)->root_volume)
kfree(ASFS_SB(sb)->root_volume);
+ if (ASFS_SB(sb)->nls_disk)
+ unload_nls(ASFS_SB(sb)->nls_disk);
+ if (ASFS_SB(sb)->nls_io)
+ unload_nls(ASFS_SB(sb)->nls_io);
+ if (ASFS_SB(sb)->iocharset != asfs_default_iocharset)
+ kfree(ASFS_SB(sb)->iocharset);
kfree(sbi);
sb->s_fs_info = NULL;
--- linux-2.6.11.1/fs/asfs/symlink.c.orig 2005-03-09 11:25:34.000000000
-0500
+++ linux-2.6.11.1/fs/asfs/symlink.c 2005-03-09 11:25:57.000000000 -0500
@@ -20,6 +20,7 @@
#include <linux/buffer_head.h>
#include <linux/vfs.h>
#include <linux/pagemap.h>
+#include <linux/nls.h>
#include "asfs_fs.h"
#include <asm/byteorder.h>
@@ -31,9 +32,13 @@
struct fsSoftLink *slinkcont;
struct inode *inode = page->mapping->host;
struct super_block *sb = inode->i_sb;
+ struct nls_table *nls_io = ASFS_SB(sb)->nls_io;
+ struct nls_table *nls_disk = ASFS_SB(sb)->nls_disk;
char *link = kmap(page);
int i = 0, j = 0;
char c, lc = 0, *prefix, *lf, *p;
+ wchar_t uni;
+ int clen;
if (!(bh = asfs_breadcheck(sb, ASFS_I(inode)->firstblock,
ASFS_SOFTLINK_ID))) {
SetPageError(page);
@@ -56,12 +61,19 @@
/* adding volume prefix */
while (i < 1023 && (c = prefix[i]))
link[i++] = c;
- if (ASFS_SB(sb)->flags & ASFS_VOL_LOWERCASE) {
- while (i < 1023 && lf[j] != ':')
- link[i++] = asfs_lowerchar(lf[j++]);
- } else {
- while (i < 1023 && lf[j] != ':')
- link[i++] = lf[j++];
+ while (i < 1023 && lf[j] != ':')
+ {
+ c = lf[j++];
+ if (ASFS_SB(sb)->flags & ASFS_VOL_LOWERCASE)
+ c = asfs_lowerchar(c);
+ clen = nls_disk->char2uni(&c, 1, &uni);
+ if (clen>0) {
+ clen = nls_io->uni2char(uni, &link[i],
NLS_MAX_CHARSET_SIZE);
+ if (clen>0)
+ i += clen;
+ }
+ if (clen<0)
+ link[i++] = '?';
}
if (i < 1023)
link[i++] = '/';
@@ -75,8 +87,15 @@
link[i++] = '.';
link[i++] = '.';
}
- link[i++] = c;
lc = c;
+ clen = nls_disk->char2uni(&c, 1, &uni);
+ if (clen>0) {
+ clen = nls_io->uni2char(uni, &link[i],
NLS_MAX_CHARSET_SIZE);
+ if (clen>0)
+ i += clen;
+ }
+ if (clen<0)
+ link[i++] = '?';
j++;
}
link[i] = '\0';
@@ -94,8 +113,12 @@
struct super_block *sb = symfile->i_sb;
struct buffer_head *bh;
struct fsSoftLink *slinkcont;
+ struct nls_table *nls_io = ASFS_SB(sb)->nls_io;
+ struct nls_table *nls_disk = ASFS_SB(sb)->nls_disk;
char *p, c, lc;
int i, maxlen, pflen;
+ wchar_t uni;
+ int clen, blen;
asfs_debug("asfs_write_symlink %s to node %d\n", symname,
(int)symfile->i_ino);
@@ -119,10 +142,26 @@
strncmp(symname-1, ASFS_SB(sb)->prefix, (pflen =
strlen(ASFS_SB(sb)->prefix))) == 0) {
/* found volume prefix, ommiting it */
symname += pflen;
- while ((c = *symname++) != '/' && c != '\0') {
- *p++ = c;
+ blen = strlen(symname);
+ while (*symname != '/' && *symname != '\0') {
+ clen = nls_io->char2uni(symname, blen, &uni);
+ if (clen>0) {
+ symname += clen;
+ blen -= clen;
+ clen = nls_disk->uni2char(uni, p,
NLS_MAX_CHARSET_SIZE);
+ if (clen>0)
+ p += clen;
+ }
+ else
+ {
+ symname++;
+ blen--;
+ }
+ if (clen<0)
+ *p++ = '?';
i++;
}
+ symname++;
*p++ = ':';
} else if (ASFS_SB(sb)->root_volume) { /* adding root volume
name */
while (ASFS_SB(sb)->root_volume[i])
@@ -134,23 +173,46 @@
i++;
}
- while (i < maxlen && (c = *symname++)) {
- if (c == '.' && lc == '/' && *symname == '.' && symname[1] ==
'/') {
+ blen = strlen(symname);
+ while (i < maxlen && (c = *symname)) {
+ if (c == '.' && lc == '/' && symname[1] == '.' && symname[2] ==
'/') {
*p++ = '/';
i++;
- symname += 2;
+ symname += 3;
+ blen -= 3;
lc = '/';
- } else if (c == '.' && lc == '/' && *symname == '/') {
- symname++;
+ } else if (c == '.' && lc == '/' && symname[1] == '/') {
+ symname += 2;
+ blen -= 2;
lc = '/';
} else {
- *p++ = c;
- lc = c;
+ clen = nls_io->char2uni(symname, blen, &uni);
+ if (clen>0) {
+ symname += clen;
+ blen -= clen;
+ clen = nls_disk->uni2char(uni, p,
NLS_MAX_CHARSET_SIZE);
+ if (clen>0)
+ lc = *p;
+ p += clen;
+ }
+ else
+ {
+ symname++;
+ blen--;
+ }
+ if (clen<0)
+ {
+ *p++ = '?';
+ lc = '?';
+ }
i++;
}
if (lc == '/')
while (*symname == '/')
+ {
symname++;
+ blen--;
+ }
}
*p = 0;
--- linux-2.6.11.1/fs/Kconfig.orig 2005-03-09 11:25:34.000000000 -0500
+++ linux-2.6.11.1/fs/Kconfig 2005-03-09 13:31:40.606066992 -0500
@@ -938,6 +938,24 @@
If unsure, say N.
+config ASFS_DEFAULT_CODEPAGE
+ int "Default codepage for SFS"
+ depends on ASFS_FS
+ default 437
+ help
+ This option should be set to the codepage of your SFS filesystems.
+ It can be overridden with the 'codepage' mount option.
+
+config ASFS_DEFAULT_IOCHARSET
+ string "Default iocharset for SFS"
+ depends on ASFS_FS
+ default "iso8859-1"
+ help
+ Set this to the default I/O character set you'd like SFS to use.
+ It should probably match the character set that most of your
+ SFS filesystems use, and can be overridded with the 'iocharset'
+ mount option for SFS filesystems.
+
config ASFS_RW
bool "Amiga SFS write support (DANGEROUS)"
depends on ASFS_FS
--- linux-2.6.11.1/Documentation/filesystems/asfs.txt.orig 2005-03-09
11:25:34.000000000 -0500
+++ linux-2.6.11.1/Documentation/filesystems/asfs.txt 2005-03-09
13:23:31.934356384 -0500
@@ -76,6 +76,14 @@
Translate all volume names in symlinks to lower case.
Disabled by default. (See below.)
+iocharset=name
+ Character set to use for converting file names. Specifies
character
+ set used by your Linux system.
+
+codepage=###
+ Set the codepage number for converting file names. Specifies
+ character set used by your Amiga.
+
Symbolic links
==============