summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-12-06 23:51:34 +0000
committerRalf Baechle <ralf@linux-mips.org>1997-12-06 23:51:34 +0000
commit230e5ab6a084ed50470f101934782dbf54b0d06b (patch)
tree5dd821c8d33f450470588e7a543f74bf74306e9e /fs
parentc9b1c8a64c6444d189856f1e26bdcb8b4cd0113a (diff)
Merge with Linux 2.1.67.
Diffstat (limited to 'fs')
-rw-r--r--fs/Config.in8
-rw-r--r--fs/Makefile14
-rw-r--r--fs/affs/dir.c8
-rw-r--r--fs/affs/file.c67
-rw-r--r--fs/autofs/root.c27
-rw-r--r--fs/autofs/waitq.c2
-rw-r--r--fs/bad_inode.c11
-rw-r--r--fs/binfmt_aout.c11
-rw-r--r--fs/binfmt_elf.c12
-rw-r--r--fs/binfmt_misc.c85
-rw-r--r--fs/block_dev.c39
-rw-r--r--fs/buffer.c198
-rw-r--r--fs/dcache.c472
-rw-r--r--fs/dquot.c27
-rw-r--r--fs/exec.c56
-rw-r--r--fs/ext2/dir.c4
-rw-r--r--fs/ext2/file.c17
-rw-r--r--fs/ext2/fsync.c197
-rw-r--r--fs/ext2/namei.c126
-rw-r--r--fs/fat/buffer.c18
-rw-r--r--fs/fat/cache.c49
-rw-r--r--fs/fat/dir.c69
-rw-r--r--fs/fat/fatfs_syms.c9
-rw-r--r--fs/fat/file.c59
-rw-r--r--fs/fat/inode.c490
-rw-r--r--fs/fat/misc.c81
-rw-r--r--fs/fat/mmap.c7
-rw-r--r--fs/fat/tables.c212
-rw-r--r--fs/fcntl.c2
-rw-r--r--fs/fifo.c4
-rw-r--r--fs/file_table.c49
-rw-r--r--fs/filesystems.c5
-rw-r--r--fs/hpfs/hpfs_fs.c56
-rw-r--r--fs/inode.c156
-rw-r--r--fs/isofs/Makefile5
-rw-r--r--fs/isofs/dir.c87
-rw-r--r--fs/isofs/inode.c199
-rw-r--r--fs/isofs/joliet.c110
-rw-r--r--fs/isofs/namei.c88
-rw-r--r--fs/isofs/rock.c26
-rw-r--r--fs/isofs/symlink.c2
-rw-r--r--fs/isofs/util.c8
-rw-r--r--fs/lockd/clntproc.c8
-rw-r--r--fs/lockd/svc.c141
-rw-r--r--fs/lockd/svcsubs.c17
-rw-r--r--fs/locks.c28
-rw-r--r--fs/minix/dir.c4
-rw-r--r--fs/minix/file.c13
-rw-r--r--fs/msdos/namei.c154
-rw-r--r--fs/namei.c66
-rw-r--r--fs/ncpfs/dir.c1314
-rw-r--r--fs/ncpfs/file.c196
-rw-r--r--fs/ncpfs/inode.c371
-rw-r--r--fs/ncpfs/ioctl.c23
-rw-r--r--fs/ncpfs/mmap.c7
-rw-r--r--fs/ncpfs/ncplib_kernel.c249
-rw-r--r--fs/ncpfs/ncplib_kernel.h80
-rw-r--r--fs/ncpfs/sock.c132
-rw-r--r--fs/nfs/dir.c858
-rw-r--r--fs/nfs/file.c112
-rw-r--r--fs/nfs/inode.c384
-rw-r--r--fs/nfs/nfs2xdr.c48
-rw-r--r--fs/nfs/nfs3xdr.c48
-rw-r--r--fs/nfs/proc.c35
-rw-r--r--fs/nfs/write.c231
-rw-r--r--fs/nfsd/export.c140
-rw-r--r--fs/nfsd/nfsctl.c20
-rw-r--r--fs/nfsd/nfsfh.c1244
-rw-r--r--fs/nfsd/nfsproc.c15
-rw-r--r--fs/nfsd/nfsxdr.c17
-rw-r--r--fs/nfsd/stats.c10
-rw-r--r--fs/nfsd/vfs.c203
-rw-r--r--fs/nls/.cvsignore1
-rw-r--r--fs/nls/Config.in44
-rw-r--r--fs/nls/Makefile300
-rw-r--r--fs/nls/nls_base.c497
-rw-r--r--fs/nls/nls_cp437.c447
-rw-r--r--fs/nls/nls_cp737.c375
-rw-r--r--fs/nls/nls_cp775.c375
-rw-r--r--fs/nls/nls_cp850.c339
-rw-r--r--fs/nls/nls_cp852.c339
-rw-r--r--fs/nls/nls_cp855.c339
-rw-r--r--fs/nls/nls_cp857.c303
-rw-r--r--fs/nls/nls_cp860.c411
-rw-r--r--fs/nls/nls_cp861.c447
-rw-r--r--fs/nls/nls_cp862.c483
-rw-r--r--fs/nls/nls_cp863.c447
-rw-r--r--fs/nls/nls_cp864.c438
-rw-r--r--fs/nls/nls_cp865.c447
-rw-r--r--fs/nls/nls_cp866.c375
-rw-r--r--fs/nls/nls_cp869.c339
-rw-r--r--fs/nls/nls_cp874.c303
-rw-r--r--fs/nls/nls_iso8859-1.c227
-rw-r--r--fs/nls/nls_iso8859-2.c299
-rw-r--r--fs/nls/nls_iso8859-3.c299
-rw-r--r--fs/nls/nls_iso8859-4.c299
-rw-r--r--fs/nls/nls_iso8859-5.c303
-rw-r--r--fs/nls/nls_iso8859-6.c263
-rw-r--r--fs/nls/nls_iso8859-7.c339
-rw-r--r--fs/nls/nls_iso8859-8.c303
-rw-r--r--fs/nls/nls_iso8859-9.c263
-rw-r--r--fs/nls/nls_koi8-r.c375
-rw-r--r--fs/pipe.c43
-rw-r--r--fs/proc/array.c186
-rw-r--r--fs/proc/base.c8
-rw-r--r--fs/proc/generic.c139
-rw-r--r--fs/proc/inode.c142
-rw-r--r--fs/proc/kmsg.c4
-rw-r--r--fs/proc/mem.c42
-rw-r--r--fs/proc/root.c99
-rw-r--r--fs/proc/scsi.c34
-rw-r--r--fs/read_write.c300
-rw-r--r--fs/readdir.c12
-rw-r--r--fs/select.c19
-rw-r--r--fs/smbfs/Makefile2
-rw-r--r--fs/smbfs/cache.c316
-rw-r--r--fs/smbfs/dir.c553
-rw-r--r--fs/smbfs/file.c275
-rw-r--r--fs/smbfs/inode.c348
-rw-r--r--fs/smbfs/ioctl.c25
-rw-r--r--fs/smbfs/proc.c1454
-rw-r--r--fs/smbfs/sock.c379
-rw-r--r--fs/super.c135
-rw-r--r--fs/sysv/dir.c4
-rw-r--r--fs/sysv/file.c30
-rw-r--r--fs/sysv/inode.c5
-rw-r--r--fs/vfat/Makefile4
-rw-r--r--fs/vfat/namei.c360
-rw-r--r--fs/vfat/vfatfs_syms.c37
129 files changed, 19367 insertions, 4947 deletions
diff --git a/fs/Config.in b/fs/Config.in
index 5f53913ee..d7826af19 100644
--- a/fs/Config.in
+++ b/fs/Config.in
@@ -9,11 +9,16 @@ bool 'Quota support' CONFIG_QUOTA
tristate 'Minix fs support' CONFIG_MINIX_FS
tristate 'Second extended fs support' CONFIG_EXT2_FS
+tristate 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS
+if [ "$CONFIG_ISO9660_FS" != "n" ]; then
+ bool 'Microsoft Joliet cdrom extensions' CONFIG_JOLIET
+fi
+
# msdos filesystems
tristate 'DOS FAT fs support' CONFIG_FAT_FS
dep_tristate 'MSDOS fs support' CONFIG_MSDOS_FS $CONFIG_FAT_FS
-dep_tristate 'VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS
dep_tristate 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
+dep_tristate 'VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS
bool '/proc filesystem support' CONFIG_PROC_FS
if [ "$CONFIG_INET" = "y" ]; then
@@ -46,7 +51,6 @@ fi
if [ "$CONFIG_IPX" != "n" ]; then
tristate 'NCP filesystem support (to mount NetWare volumes)' CONFIG_NCP_FS
fi
-tristate 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS
tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS
tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS
tristate 'Amiga FFS filesystem support' CONFIG_AFFS_FS
diff --git a/fs/Makefile b/fs/Makefile
index 871524350..0b0f5f5ee 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -17,7 +17,7 @@ O_OBJS = open.o read_write.o devices.o file_table.o buffer.o \
MOD_LIST_NAME := FS_MODULES
ALL_SUB_DIRS = minix ext2 fat msdos vfat proc isofs nfs umsdos \
- hpfs sysv smbfs ncpfs ufs affs romfs autofs lockd nfsd
+ hpfs sysv smbfs ncpfs ufs affs romfs autofs lockd nfsd nls
ifeq ($(CONFIG_QUOTA),y)
O_OBJS += dquot.o
@@ -110,6 +110,18 @@ else
endif
endif
+# Since CONFIG_NLS might be set to y while there are modules
+# to be build in the nls/ directory, we need to enter the nls
+# directory every time, but with different rules.
+ifeq ($(CONFIG_NLS),y)
+SUB_DIRS += nls
+MOD_IN_SUB_DIRS += nls
+else
+ ifeq ($(CONFIG_NLS),m)
+ MOD_SUB_DIRS += nls
+ endif
+endif
+
ifeq ($(CONFIG_UMSDOS_FS),y)
SUB_DIRS += umsdos
else
diff --git a/fs/affs/dir.c b/fs/affs/dir.c
index cfd05640b..95bf3080c 100644
--- a/fs/affs/dir.c
+++ b/fs/affs/dir.c
@@ -24,8 +24,8 @@
#include <linux/amigaffs.h>
static int affs_readdir(struct file *, void *, filldir_t);
-static long affs_dir_read(struct inode * inode, struct file * filp, char * buf,
- unsigned long count);
+static ssize_t affs_dir_read(struct file * filp, char * buf,
+ size_t count, loff_t *ppos);
static struct file_operations affs_dir_operations = {
NULL, /* lseek - default */
@@ -62,8 +62,8 @@ struct inode_operations affs_dir_inode_operations = {
NULL /* permissions */
};
-static long
-affs_dir_read(struct inode *inode, struct file *filp, char *buf, unsigned long count)
+static ssize_t
+affs_dir_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
{
return -EISDIR;
}
diff --git a/fs/affs/file.c b/fs/affs/file.c
index eb7bfbf48..273de8ebe 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -37,12 +37,12 @@
static int affs_bmap(struct inode *inode, int block);
static struct buffer_head * affs_getblock(struct inode *inode, s32 block);
-static long affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf,
- unsigned long count);
-static long affs_file_write(struct inode *inode, struct file *filp, const char *buf,
- unsigned long count);
-static long affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf,
- unsigned long count);
+static ssize_t affs_file_read_ofs(struct file *filp, char *buf,
+ size_t count, loff_t *ppos);
+static ssize_t affs_file_write(struct file *filp, const char *buf,
+ size_t count, loff_t *ppos);
+static ssize_t affs_file_write_ofs(struct file *filp, const char *buf,
+ size_t count, loff_t *ppos);
static int affs_release_file(struct inode *inode, struct file *filp);
static int alloc_ext_cache(struct inode *inode);
@@ -496,16 +496,17 @@ affs_getblock(struct inode *inode, s32 block)
return affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
}
-static long
-affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf, unsigned long count)
+static ssize_t
+affs_file_read_ofs(struct file *filp, char *buf, size_t count, loff_t *ppos)
{
+ struct inode *inode = filp->f_dentry->d_inode;
char *start;
- int left, offset, size, sector;
- int blocksize;
+ ssize_t left, offset, size, sector;
+ ssize_t blocksize;
struct buffer_head *bh;
void *data;
- pr_debug("AFFS: file_read_ofs(ino=%lu,pos=%lu,%d)\n",inode->i_ino,(long)filp->f_pos,count);
+ pr_debug("AFFS: file_read_ofs(ino=%lu,pos=%lu,%d)\n",inode->i_ino,(long)*ppos,count);
if (!inode) {
affs_error(inode->i_sb,"file_read_ofs","Inode = NULL");
@@ -516,24 +517,24 @@ affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf, unsigned l
pr_debug("affs_file_read: mode = %07o",inode->i_mode);
return -EINVAL;
}
- if (filp->f_pos >= inode->i_size || count <= 0)
+ if (*ppos >= inode->i_size || count <= 0)
return 0;
start = buf;
for (;;) {
- left = MIN (inode->i_size - filp->f_pos,count - (buf - start));
+ left = MIN (inode->i_size - *ppos,count - (buf - start));
if (!left)
break;
- sector = affs_bmap(inode,(u32)filp->f_pos / blocksize);
+ sector = affs_bmap(inode,(u32)*ppos / blocksize);
if (!sector)
break;
- offset = (u32)filp->f_pos % blocksize;
+ offset = (u32)*ppos % blocksize;
bh = affs_bread(inode->i_dev,sector,AFFS_I2BSIZE(inode));
if (!bh)
break;
data = bh->b_data + 24;
size = MIN(blocksize - offset,left);
- filp->f_pos += size;
+ *ppos += size;
copy_to_user(buf,data + offset,size);
buf += size;
affs_brelse(bh);
@@ -543,13 +544,14 @@ affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf, unsigned l
return buf - start;
}
-static long
-affs_file_write(struct inode *inode, struct file *filp, const char *buf, unsigned long count)
+static ssize_t
+affs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos)
{
+ struct inode *inode = filp->f_dentry->d_inode;
off_t pos;
- int written;
- int c;
- int blocksize;
+ ssize_t written;
+ ssize_t c;
+ ssize_t blocksize;
struct buffer_head *bh;
struct inode *ino;
char *p;
@@ -558,7 +560,7 @@ affs_file_write(struct inode *inode, struct file *filp, const char *buf, unsigne
if (!count)
return 0;
pr_debug("AFFS: file_write(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino,
- (unsigned long)filp->f_pos,count);
+ (unsigned long)*ppos,count);
ino = NULL;
if (!inode) {
@@ -591,7 +593,7 @@ affs_file_write(struct inode *inode, struct file *filp, const char *buf, unsigne
if (filp->f_flags & O_APPEND) {
pos = inode->i_size;
} else
- pos = filp->f_pos;
+ pos = *ppos;
written = 0;
blocksize = AFFS_I2BSIZE(inode);
@@ -628,25 +630,26 @@ affs_file_write(struct inode *inode, struct file *filp, const char *buf, unsigne
if (pos > inode->i_size)
inode->i_size = pos;
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- filp->f_pos = pos;
+ *ppos = pos;
mark_inode_dirty(inode);
iput(ino);
return written;
}
-static long
-affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, unsigned long count)
+static ssize_t
+affs_file_write_ofs(struct file *filp, const char *buf, size_t count, loff_t *ppos)
{
+ struct inode *inode = filp->f_dentry->d_inode;
off_t pos;
- int written;
- int c;
- int blocksize;
+ ssize_t written;
+ ssize_t c;
+ ssize_t blocksize;
struct buffer_head *bh;
struct inode *ino;
char *p;
pr_debug("AFFS: file_write_ofs(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino,
- (unsigned long)filp->f_pos,count);
+ (unsigned long)*ppos,count);
if (!count)
return 0;
@@ -675,7 +678,7 @@ affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, uns
if (filp->f_flags & O_APPEND)
pos = inode->i_size;
else
- pos = filp->f_pos;
+ pos = *ppos;
bh = NULL;
blocksize = AFFS_I2BSIZE(inode) - 24;
@@ -715,7 +718,7 @@ affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, uns
}
if (pos > inode->i_size)
inode->i_size = pos;
- filp->f_pos = pos;
+ *ppos = pos;
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
iput(ino);
diff --git a/fs/autofs/root.c b/fs/autofs/root.c
index d2b121b18..541f7fba3 100644
--- a/fs/autofs/root.c
+++ b/fs/autofs/root.c
@@ -100,7 +100,7 @@ static int autofs_root_readdir(struct file *filp, void *dirent, filldir_t filldi
return 0;
}
-static int try_to_fill_dentry(struct dentry * dentry, struct super_block * sb, struct autofs_sb_info *sbi)
+static int try_to_fill_dentry(struct dentry *dentry, struct super_block *sb, struct autofs_sb_info *sbi)
{
struct inode * inode;
struct autofs_dir_ent *ent;
@@ -132,9 +132,10 @@ static int try_to_fill_dentry(struct dentry * dentry, struct super_block * sb, s
dentry->d_inode = inode;
}
- if (S_ISDIR(dentry->d_inode->i_mode)) {
- while (dentry == dentry->d_mounts)
- schedule();
+ /* If this is a directory that isn't a mount point, bitch at the
+ daemon and fix it in user space */
+ if ( S_ISDIR(dentry->d_inode->i_mode) && dentry->d_mounts == dentry ) {
+ return !autofs_wait(sbi, &dentry->d_name);
}
autofs_update_usage(&sbi->dirhash,ent);
@@ -159,16 +160,24 @@ static int autofs_revalidate(struct dentry * dentry)
sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
/* Pending dentry */
- if (dentry->d_flags & DCACHE_AUTOFS_PENDING) {
+ if ( dentry->d_flags & DCACHE_AUTOFS_PENDING ) {
if (autofs_oz_mode(sbi))
return 1;
-
- return try_to_fill_dentry(dentry, dir->i_sb, sbi);
+ else
+ return try_to_fill_dentry(dentry, dir->i_sb, sbi);
}
/* Negative dentry.. invalidate if "old" */
if (!dentry->d_inode)
return (dentry->d_time - jiffies <= AUTOFS_NEGATIVE_TIMEOUT);
+
+ /* Check for a non-mountpoint directory */
+ if ( S_ISDIR(dentry->d_inode->i_mode) && dentry->d_mounts == dentry ) {
+ if (autofs_oz_mode(sbi))
+ return 1;
+ else
+ return try_to_fill_dentry(dentry, dir->i_sb, sbi);
+ }
/* Update the usage list */
ent = (struct autofs_dir_ent *) dentry->d_time;
@@ -177,7 +186,7 @@ static int autofs_revalidate(struct dentry * dentry)
}
static struct dentry_operations autofs_dentry_operations = {
- autofs_revalidate,
+ autofs_revalidate, /* d_revalidate */
NULL, /* d_hash */
NULL, /* d_compare */
};
@@ -223,7 +232,7 @@ static int autofs_root_lookup(struct inode *dir, struct dentry * dentry)
* a signal. If so we can force a restart..
*/
if (dentry->d_flags & DCACHE_AUTOFS_PENDING) {
- if (current->signal & ~current->blocked)
+ if (signal_pending(current))
return -ERESTARTNOINTR;
}
diff --git a/fs/autofs/waitq.c b/fs/autofs/waitq.c
index e56825d5e..7e4558d9d 100644
--- a/fs/autofs/waitq.c
+++ b/fs/autofs/waitq.c
@@ -55,7 +55,7 @@ static int autofs_write(struct file *file, const void *addr, int bytes)
old_signal = current->signal;
- while ( bytes && (written = file->f_op->write(file->f_dentry->d_inode,file,data,bytes)) > 0 ) {
+ while ( bytes && (written = file->f_op->write(file,data,bytes,&file->f_pos)) > 0 ) {
data += written;
bytes -= written;
}
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index 562a5d8b7..4d17002ab 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -19,7 +19,7 @@ static struct dentry * bad_follow_link(struct inode * ino, struct dentry *base)
return ERR_PTR(-EIO);
}
-static int return_EIO()
+static int return_EIO(void)
{
return -EIO;
}
@@ -81,3 +81,12 @@ void make_bad_inode(struct inode * inode)
inode->i_op = &bad_inode_ops;
}
+/*
+ * This tests whether an inode has been flagged as bad. The test uses
+ * &bad_inode_ops to cover the case of invalidated inodes as well as
+ * those created by make_bad_inode() above.
+ */
+int is_bad_inode(struct inode * inode)
+{
+ return (inode->i_op == &bad_inode_ops);
+}
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index 2e9733706..511dca04a 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -58,7 +58,7 @@ static void set_brk(unsigned long start, unsigned long end)
* macros to write out all the necessary info.
*/
#define DUMP_WRITE(addr,nr) \
-while (file.f_op->write(inode,&file,(char *)(addr),(nr)) != (nr)) goto close_coredump
+while (file.f_op->write(&file,(char *)(addr),(nr),&file.f_pos) != (nr)) goto close_coredump
#define DUMP_SEEK(offset) \
if (file.f_op->llseek) { \
@@ -306,6 +306,7 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
unsigned long p = bprm->p;
unsigned long fd_offset;
unsigned long rlim;
+ int retval;
ex = *((struct exec *) bprm->buf); /* exec-header */
if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC &&
@@ -341,8 +342,12 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
if (ex.a_data + ex.a_bss > rlim)
return -ENOMEM;
+ /* Flush all traces of the currently running executable */
+ retval = flush_old_exec(bprm);
+ if (retval)
+ return retval;
+
/* OK, This is the point of no return */
- flush_old_exec(bprm);
#ifdef __sparc__
memcpy(&current->tss.core_exec, &ex, sizeof(struct exec));
#endif
@@ -498,7 +503,7 @@ do_load_aout_library(int fd)
file->f_pos = 0;
set_fs(KERNEL_DS);
- error = file->f_op->read(inode, file, (char *) &ex, sizeof(ex));
+ error = file->f_op->read(file, (char *) &ex, sizeof(ex), &file->f_pos);
set_fs(USER_DS);
if (error != sizeof(ex))
return -ENOEXEC;
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 5187ae1cb..bb59cdfaf 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -621,9 +621,12 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
}
}
- /* OK, This is the point of no return */
- flush_old_exec(bprm);
+ /* Flush all traces of the currently running executable */
+ retval = flush_old_exec(bprm);
+ if (retval)
+ return retval;
+ /* OK, This is the point of no return */
current->mm->end_data = 0;
current->mm->end_code = 0;
current->mm->start_mmap = ELF_START_MMAP;
@@ -858,7 +861,8 @@ do_load_elf_library(int fd){
file->f_pos = 0;
set_fs(KERNEL_DS);
- error = file->f_op->read(inode, file, (char *) &elf_ex, sizeof(elf_ex));
+ error = file->f_op->read(file, (char *) &elf_ex,
+ sizeof(elf_ex), &file->f_pos);
set_fs(USER_DS);
if (error != sizeof(elf_ex))
return -ENOEXEC;
@@ -955,7 +959,7 @@ static int load_elf_library(int fd)
*/
static int dump_write(struct file *file, const void *addr, int nr)
{
- return file->f_op->write(file->f_dentry->d_inode, file, addr, nr) == nr;
+ return file->f_op->write(file, addr, nr, &file->f_pos) == nr;
}
static int dump_seek(struct file *file, off_t off)
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 469f52898..8f8579d7c 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -281,21 +281,19 @@ static int proc_write_register(struct file *file, const char *buffer,
const char *sp;
char del, *dp;
struct binfmt_entry *e;
- int memsize, cnt = count - 1, err = 0;
+ int memsize, cnt = count - 1, err;
- MOD_INC_USE_COUNT;
/* some sanity checks */
- if ((count < 11) || (count > 256)) {
- err = -EINVAL;
+ err = -EINVAL;
+ if ((count < 11) || (count > 256))
goto _err;
- }
+ err = -ENOMEM;
memsize = sizeof(struct binfmt_entry) + count;
- if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER))) {
- err = -ENOMEM;
+ if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER)))
goto _err;
- }
+ err = 0;
sp = buffer + 1;
del = buffer[0];
dp = (char *)e + sizeof(struct binfmt_entry);
@@ -327,12 +325,8 @@ static int proc_write_register(struct file *file, const char *buffer,
/* more sanity checks */
if (err || !(!cnt || (!(--cnt) && (*sp == '\n'))) ||
(e->size < 1) || ((e->size + e->offset) > 127) ||
- !(e->proc_name) || !(e->interpreter) ||
- entry_proc_setup(e)) {
- kfree(e);
- err = -EINVAL;
- goto _err;
- }
+ !(e->proc_name) || !(e->interpreter) || entry_proc_setup(e))
+ goto free_err;
write_lock(&entries_lock);
e->next = entries;
@@ -341,8 +335,11 @@ static int proc_write_register(struct file *file, const char *buffer,
err = count;
_err:
- MOD_DEC_USE_COUNT;
return err;
+free_err:
+ kfree(e);
+ err = -EINVAL;
+ goto _err;
}
/*
@@ -357,7 +354,6 @@ static int proc_read_status(char *page, char **start, off_t off,
char *dp;
int elen, i, err;
- MOD_INC_USE_COUNT;
#ifndef VERBOSE_STATUS
if (data) {
if (!(e = get_entry((int) data))) {
@@ -415,7 +411,6 @@ static int proc_read_status(char *page, char **start, off_t off,
err = elen;
_err:
- MOD_DEC_USE_COUNT;
return err;
}
@@ -429,7 +424,6 @@ static int proc_write_status(struct file *file, const char *buffer,
struct binfmt_entry *e;
int res = count;
- MOD_INC_USE_COUNT;
if (buffer[count-1] == '\n')
count--;
if ((count == 1) && !(buffer[0] & ~('0' | '1'))) {
@@ -449,7 +443,6 @@ static int proc_write_status(struct file *file, const char *buffer,
} else {
res = -EINVAL;
}
- MOD_DEC_USE_COUNT;
return res;
}
@@ -477,29 +470,57 @@ static int entry_proc_setup(struct binfmt_entry *e)
return 0;
}
+#ifdef MODULE
+/*
+ * This is called as the fill_inode function when an inode
+ * is going into (fill = 1) or out of service (fill = 0).
+ * We use it here to manage the module use counts.
+ *
+ * Note: only the top-level directory needs to do this; if
+ * a lower level is referenced, the parent will be as well.
+ */
+static void bm_modcount(struct inode *inode, int fill)
+{
+ if (fill)
+ MOD_INC_USE_COUNT;
+ else
+ MOD_DEC_USE_COUNT;
+}
+#endif
__initfunc(int init_misc_binfmt(void))
{
struct proc_dir_entry *status = NULL, *reg;
+ int error = -ENOMEM;
- if (!(bm_dir = create_proc_entry("sys/fs/binfmt_misc", S_IFDIR,
- NULL)) ||
- !(status = create_proc_entry("status", S_IFREG | S_IRUGO | S_IWUSR,
- bm_dir)) ||
- !(reg = create_proc_entry("register", S_IFREG | S_IWUSR,
- bm_dir))) {
- if (status)
- remove_proc_entry("status", bm_dir);
- if (bm_dir)
- remove_proc_entry("sys/fs/binfmt_misc", NULL);
- return -ENOMEM;
- }
+ bm_dir = create_proc_entry("sys/fs/binfmt_misc", S_IFDIR, NULL);
+ if (!bm_dir)
+ goto out;
+#ifdef MODULE
+ bm_dir->fill_inode = bm_modcount;
+#endif
+
+ status = create_proc_entry("status", S_IFREG | S_IRUGO | S_IWUSR,
+ bm_dir);
+ if (!status)
+ goto cleanup_bm;
status->read_proc = proc_read_status;
status->write_proc = proc_write_status;
+ reg = create_proc_entry("register", S_IFREG | S_IWUSR, bm_dir);
+ if (!reg)
+ goto cleanup_status;
reg->write_proc = proc_write_register;
- return register_binfmt(&misc_format);
+ error = register_binfmt(&misc_format);
+out:
+ return error;
+
+cleanup_status:
+ remove_proc_entry("status", bm_dir);
+cleanup_bm:
+ remove_proc_entry("sys/fs/binfmt_misc", NULL);
+ goto out;
}
#ifdef MODULE
diff --git a/fs/block_dev.c b/fs/block_dev.c
index dbb9d14dc..1598e3bf9 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -20,16 +20,17 @@ extern int *blksize_size[];
#define MAX_BUF_PER_PAGE (PAGE_SIZE / 512)
#define NBUF 64
-long block_write(struct inode * inode, struct file * filp,
- const char * buf, unsigned long count)
+ssize_t block_write(struct file * filp, const char * buf,
+ size_t count, loff_t *ppos)
{
- int blocksize, blocksize_bits, i, buffercount,write_error;
- int block, blocks;
+ struct inode * inode = filp->f_dentry->d_inode;
+ ssize_t blocksize, blocksize_bits, i, buffercount, write_error;
+ ssize_t block, blocks;
loff_t offset;
- int chars;
- int written = 0;
+ ssize_t chars;
+ ssize_t written = 0;
struct buffer_head * bhlist[NBUF];
- unsigned int size;
+ size_t size;
kdev_t dev;
struct buffer_head * bh, *bufferlist[NBUF];
register char * p;
@@ -49,8 +50,8 @@ long block_write(struct inode * inode, struct file * filp,
i >>= 1;
}
- block = filp->f_pos >> blocksize_bits;
- offset = filp->f_pos & (blocksize-1);
+ block = *ppos >> blocksize_bits;
+ offset = *ppos & (blocksize-1);
if (blk_size[MAJOR(dev)])
size = ((loff_t) blk_size[MAJOR(dev)][MINOR(dev)] << BLOCK_SIZE_BITS) >> blocksize_bits;
@@ -105,7 +106,7 @@ long block_write(struct inode * inode, struct file * filp,
return written ? written : -EIO;
p = offset + bh->b_data;
offset = 0;
- filp->f_pos += chars;
+ *ppos += chars;
written += chars;
count -= chars;
copy_from_user(p,buf,chars);
@@ -145,14 +146,14 @@ long block_write(struct inode * inode, struct file * filp,
return written;
}
-long block_read(struct inode * inode, struct file * filp,
- char * buf, unsigned long count)
+ssize_t block_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
{
- unsigned int block;
+ struct inode * inode = filp->f_dentry->d_inode;
+ size_t block;
loff_t offset;
- int blocksize;
- int blocksize_bits, i;
- unsigned int blocks, rblocks, left;
+ ssize_t blocksize;
+ ssize_t blocksize_bits, i;
+ size_t blocks, rblocks, left;
int bhrequest, uptodate;
struct buffer_head ** bhb, ** bhe;
struct buffer_head * buflist[NBUF];
@@ -160,7 +161,7 @@ long block_read(struct inode * inode, struct file * filp,
unsigned int chars;
loff_t size;
kdev_t dev;
- int read;
+ ssize_t read;
dev = inode->i_rdev;
blocksize = BLOCK_SIZE;
@@ -173,7 +174,7 @@ long block_read(struct inode * inode, struct file * filp,
i >>= 1;
}
- offset = filp->f_pos;
+ offset = *ppos;
if (blk_size[MAJOR(dev)])
size = (loff_t) blk_size[MAJOR(dev)][MINOR(dev)] << BLOCK_SIZE_BITS;
else
@@ -258,7 +259,7 @@ long block_read(struct inode * inode, struct file * filp,
chars = left;
else
chars = blocksize - offset;
- filp->f_pos += chars;
+ *ppos += chars;
left -= chars;
read += chars;
if (*bhe) {
diff --git a/fs/buffer.c b/fs/buffer.c
index 6025dcd31..1c8ab164e 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -196,7 +196,7 @@ repeat:
*/
if (wait && buffer_req(bh) && !buffer_locked(bh) &&
!buffer_dirty(bh) && !buffer_uptodate(bh)) {
- err = 1;
+ err = -EIO;
continue;
}
@@ -288,7 +288,22 @@ asmlinkage int sys_sync(void)
int file_fsync(struct file *filp, struct dentry *dentry)
{
- return fsync_dev(dentry->d_inode->i_dev);
+ struct inode * inode = dentry->d_inode;
+ struct super_block * sb;
+ kdev_t dev;
+
+ /* sync the inode to buffers */
+ write_inode_now(inode);
+
+ /* sync the superblock to buffers */
+ sb = inode->i_sb;
+ wait_on_super(sb);
+ if (sb->s_op && sb->s_op->write_super)
+ sb->s_op->write_super(sb);
+
+ /* .. finally sync the buffers to disk */
+ dev = inode->i_dev;
+ return sync_buffers(dev, 1);
}
asmlinkage int sys_fsync(unsigned int fd)
@@ -553,6 +568,11 @@ static inline struct buffer_head * find_buffer(kdev_t dev, int block, int size)
return next;
}
+struct buffer_head *efind_buffer(kdev_t dev, int block, int size)
+{
+ return find_buffer(dev, block, size);
+}
+
/*
* Why like this, I hear you say... The reason is race-conditions.
* As we don't lock buffers (unless we are reading them, that is),
@@ -817,6 +837,24 @@ printk("refill_freelist: waking bdflush\n");
goto repeat;
}
+void init_buffer(struct buffer_head *bh, kdev_t dev, int block,
+ bh_end_io_t *handler, void *dev_id)
+{
+ bh->b_count = 1;
+ bh->b_list = BUF_CLEAN;
+ bh->b_flushtime = 0;
+ bh->b_dev = dev;
+ bh->b_blocknr = block;
+ bh->b_end_io = handler;
+ bh->b_dev_id = dev_id;
+}
+
+static void end_buffer_io_sync(struct buffer_head *bh, int uptodate)
+{
+ mark_buffer_uptodate(bh, uptodate);
+ unlock_buffer(bh);
+}
+
/*
* Ok, this is getblk, and it isn't very clear, again to hinder
* race-conditions. Most of the code is seldom used, (ie repeating),
@@ -854,13 +892,9 @@ get_free:
/* OK, FINALLY we know that this buffer is the only one of its kind,
* and that it's unused (b_count=0), unlocked, and clean.
*/
- bh->b_count=1;
- bh->b_list = BUF_CLEAN;
+ init_buffer(bh, dev, block, end_buffer_io_sync, NULL);
bh->b_lru_time = jiffies;
- bh->b_flushtime=0;
bh->b_state=(1<<BH_Touched);
- bh->b_dev=dev;
- bh->b_blocknr=block;
insert_into_queues(bh);
return bh;
@@ -1254,18 +1288,75 @@ static inline void free_async_buffers (struct buffer_head * bh)
tmp = bh;
do {
- if (!test_bit(BH_FreeOnIO, &tmp->b_state)) {
- printk ("Whoops: unlock_buffer: "
- "async IO mismatch on page.\n");
- return;
- }
tmp->b_next_free = xchg(&reuse_list, NULL);
reuse_list = tmp;
- clear_bit(BH_FreeOnIO, &tmp->b_state);
tmp = tmp->b_this_page;
} while (tmp != bh);
}
+static void end_buffer_io_async(struct buffer_head * bh, int uptodate)
+{
+ unsigned long flags;
+ struct buffer_head *tmp;
+ struct page *page;
+
+ mark_buffer_uptodate(bh, uptodate);
+ unlock_buffer(bh);
+
+ /* This is a temporary buffer used for page I/O. */
+ page = mem_map + MAP_NR(bh->b_data);
+ if (!PageLocked(page))
+ goto not_locked;
+ if (bh->b_count != 1)
+ goto bad_count;
+
+ if (!test_bit(BH_Uptodate, &bh->b_state))
+ set_bit(PG_error, &page->flags);
+
+ /*
+ * Be _very_ careful from here on. Bad things can happen if
+ * two buffer heads end IO at almost the same time and both
+ * decide that the page is now completely done.
+ *
+ * Async buffer_heads are here only as labels for IO, and get
+ * thrown away once the IO for this page is complete. IO is
+ * deemed complete once all buffers have been visited
+ * (b_count==0) and are now unlocked. We must make sure that
+ * only the _last_ buffer that decrements its count is the one
+ * that free's the page..
+ */
+ save_flags(flags);
+ cli();
+ bh->b_count--;
+ tmp = bh;
+ do {
+ if (tmp->b_count)
+ goto still_busy;
+ tmp = tmp->b_this_page;
+ } while (tmp != bh);
+
+ /* OK, the async IO on this page is complete. */
+ free_async_buffers(bh);
+ restore_flags(flags);
+ clear_bit(PG_locked, &page->flags);
+ wake_up(&page->wait);
+ after_unlock_page(page);
+ wake_up(&buffer_wait);
+ return;
+
+still_busy:
+ restore_flags(flags);
+ return;
+
+not_locked:
+ printk ("Whoops: end_buffer_io_async: async io complete on unlocked page\n");
+ return;
+
+bad_count:
+ printk ("Whoops: end_buffer_io_async: b_count != 1 on async io.\n");
+ return;
+}
+
/*
* Start I/O on a page.
* This function expects the page to be locked and may return before I/O is complete.
@@ -1298,12 +1389,7 @@ int brw_page(int rw, struct page *page, kdev_t dev, int b[], int size, int bmap)
struct buffer_head * tmp;
block = *(b++);
- set_bit(BH_FreeOnIO, &next->b_state);
- next->b_list = BUF_CLEAN;
- next->b_dev = dev;
- next->b_blocknr = block;
- next->b_count = 1;
- next->b_flushtime = 0;
+ init_buffer(next, dev, block, end_buffer_io_async, NULL);
set_bit(BH_Uptodate, &next->b_state);
/*
@@ -1383,74 +1469,6 @@ void mark_buffer_uptodate(struct buffer_head * bh, int on)
}
/*
- * This is called by end_request() when I/O has completed.
- */
-void unlock_buffer(struct buffer_head * bh)
-{
- unsigned long flags;
- struct buffer_head *tmp;
- struct page *page;
-
- clear_bit(BH_Lock, &bh->b_state);
- wake_up(&bh->b_wait);
-
- if (!test_bit(BH_FreeOnIO, &bh->b_state))
- return;
- /* This is a temporary buffer used for page I/O. */
- page = mem_map + MAP_NR(bh->b_data);
- if (!PageLocked(page))
- goto not_locked;
- if (bh->b_count != 1)
- goto bad_count;
-
- if (!test_bit(BH_Uptodate, &bh->b_state))
- set_bit(PG_error, &page->flags);
-
- /*
- * Be _very_ careful from here on. Bad things can happen if
- * two buffer heads end IO at almost the same time and both
- * decide that the page is now completely done.
- *
- * Async buffer_heads are here only as labels for IO, and get
- * thrown away once the IO for this page is complete. IO is
- * deemed complete once all buffers have been visited
- * (b_count==0) and are now unlocked. We must make sure that
- * only the _last_ buffer that decrements its count is the one
- * that free's the page..
- */
- save_flags(flags);
- cli();
- bh->b_count--;
- tmp = bh;
- do {
- if (tmp->b_count)
- goto still_busy;
- tmp = tmp->b_this_page;
- } while (tmp != bh);
-
- /* OK, the async IO on this page is complete. */
- free_async_buffers(bh);
- restore_flags(flags);
- clear_bit(PG_locked, &page->flags);
- wake_up(&page->wait);
- after_unlock_page(page);
- wake_up(&buffer_wait);
- return;
-
-still_busy:
- restore_flags(flags);
- return;
-
-not_locked:
- printk ("Whoops: unlock_buffer: async io complete on unlocked page\n");
- return;
-
-bad_count:
- printk ("Whoops: unlock_buffer: b_count != 1 on async io.\n");
- return;
-}
-
-/*
* Generic "readpage" function for block devices that have the normal
* bmap functionality. This is most of the block device filesystems.
* Reads the page asynchronously --- the unlock_buffer() and
@@ -1755,7 +1773,7 @@ asmlinkage int sync_old_buffers(void)
if (ncount) printk("sync_old_buffers: %d dirty buffers not on dirty list\n", ncount);
printk("Wrote %d/%d buffers\n", nwritten, ndirty);
#endif
-
+ run_task_queue(&tq_disk);
return 0;
}
@@ -1916,7 +1934,7 @@ int bdflush(void * unused)
* dirty buffers, then make the next write to a
* loop device to be a blocking write.
* This lets us block--which we _must_ do! */
- if (ndirty == 0 && nr_buffers_type[BUF_DIRTY] > 0) {
+ if (ndirty == 0 && nr_buffers_type[BUF_DIRTY] > 0 && wrta_cmd != WRITE) {
wrta_cmd = WRITE;
continue;
}
@@ -1925,7 +1943,7 @@ int bdflush(void * unused)
/* If there are still a lot of dirty buffers around, skip the sleep
and flush some more */
- if(nr_buffers_type[BUF_DIRTY] <= nr_buffers * bdf_prm.b_un.nfract/100) {
+ if(ndirty == 0 || nr_buffers_type[BUF_DIRTY] <= nr_buffers * bdf_prm.b_un.nfract/100) {
current->signal = 0;
interruptible_sleep_on(&bdflush_wait);
}
diff --git a/fs/dcache.c b/fs/dcache.c
index 600e5b0e3..6c59851c3 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -19,8 +19,13 @@
#include <linux/malloc.h>
#include <linux/init.h>
+#define DCACHE_PARANOIA 1
+/* #define DCACHE_DEBUG 1 */
+
/* For managing the dcache */
-extern int nr_free_pages, free_pages_low;
+extern unsigned long num_physpages, page_cache_size;
+extern int inodes_stat[];
+#define nr_inodes (inodes_stat[0])
/*
* This is the single most critical data structure when it comes
@@ -37,6 +42,14 @@ extern int nr_free_pages, free_pages_low;
static struct list_head dentry_hashtable[D_HASHSIZE];
static LIST_HEAD(dentry_unused);
+struct {
+ int nr_dentry;
+ int nr_unused;
+ int age_limit; /* age in seconds */
+ int want_pages; /* pages requested by system */
+ int dummy[2];
+} dentry_stat = {0, 0, 45, 0,};
+
static inline void d_free(struct dentry *dentry)
{
kfree(dentry->d_name.name);
@@ -61,51 +74,78 @@ static inline void d_free(struct dentry *dentry)
*/
void dput(struct dentry *dentry)
{
- if (dentry) {
- int count;
+ int count;
+
+ if (!dentry)
+ return;
+
repeat:
- count = dentry->d_count-1;
- if (count < 0) {
- printk("Negative d_count (%d) for %s/%s\n",
- count,
- dentry->d_parent->d_name.name,
- dentry->d_name.name);
- *(int *)0 = 0;
+ count = dentry->d_count - 1;
+ if (count != 0)
+ goto out;
+
+ /*
+ * Note that if d_op->d_delete blocks,
+ * the dentry could go back in use.
+ * Each fs will have to watch for this.
+ */
+ if (dentry->d_op && dentry->d_op->d_delete) {
+ dentry->d_op->d_delete(dentry);
+
+ count = dentry->d_count - 1;
+ if (count != 0)
+ goto out;
+ }
+
+ if (!list_empty(&dentry->d_lru)) {
+ dentry_stat.nr_unused--;
+ list_del(&dentry->d_lru);
+ }
+ if (list_empty(&dentry->d_hash)) {
+ struct inode *inode = dentry->d_inode;
+ struct dentry * parent;
+ list_del(&dentry->d_child);
+ if (inode) {
+ dentry->d_inode = NULL;
+ iput(inode);
}
+ parent = dentry->d_parent;
+ d_free(dentry);
+ if (dentry == parent)
+ return;
+ dentry = parent;
+ goto repeat;
+ }
+ list_add(&dentry->d_lru, &dentry_unused);
+ dentry_stat.nr_unused++;
+ /*
+ * Update the timestamp
+ */
+ dentry->d_reftime = jiffies;
+
+out:
+ if (count >= 0) {
dentry->d_count = count;
- if (!count) {
- list_del(&dentry->d_lru);
- if (dentry->d_op && dentry->d_op->d_delete)
- dentry->d_op->d_delete(dentry);
- if (list_empty(&dentry->d_hash)) {
- struct inode *inode = dentry->d_inode;
- struct dentry * parent;
- if (inode)
- iput(inode);
- parent = dentry->d_parent;
- d_free(dentry);
- if (dentry == parent)
- return;
- dentry = parent;
- goto repeat;
- }
- list_add(&dentry->d_lru, &dentry_unused);
- }
+ return;
}
+
+ printk("Negative d_count (%d) for %s/%s\n",
+ count,
+ dentry->d_parent->d_name.name,
+ dentry->d_name.name);
+ *(int *)0 = 0;
}
/*
* Try to invalidate the dentry if it turns out to be
* possible. If there are other users of the dentry we
* can't invalidate it.
- *
- * This is currently incorrect. We should try to see if
- * we can invalidate any unused children - right now we
- * refuse to invalidate way too much.
*/
int d_invalidate(struct dentry * dentry)
{
- /* We should do a partial shrink_dcache here */
+ /* Check whether to do a partial shrink_dcache */
+ if (dentry->d_count > 1 && !list_empty(&dentry->d_subdirs))
+ shrink_dcache_parent(dentry);
if (dentry->d_count != 1)
return -EBUSY;
@@ -114,6 +154,121 @@ int d_invalidate(struct dentry * dentry)
}
/*
+ * Select less valuable dentries to be pruned when we need
+ * inodes or memory. The selected dentries are moved to the
+ * old end of the list where prune_dcache() can find them.
+ *
+ * Negative dentries are included in the selection so that
+ * they don't accumulate at the end of the list. The count
+ * returned is the total number of dentries selected, which
+ * may be much larger than the requested number of inodes.
+ */
+int select_dcache(int inode_count, int page_count)
+{
+ struct list_head *next, *tail = &dentry_unused;
+ int found = 0, forward = 0, young = 8;
+ int depth = dentry_stat.nr_unused >> 1;
+ unsigned long min_value = 0, max_value = 4;
+
+ if (page_count)
+ max_value = -1;
+
+ next = tail->prev;
+ while (next != &dentry_unused && depth--) {
+ struct list_head *tmp = next;
+ struct dentry *dentry = list_entry(tmp, struct dentry, d_lru);
+ struct inode *inode = dentry->d_inode;
+ unsigned long value = 0;
+
+ next = tmp->prev;
+ if (forward)
+ next = tmp->next;
+ if (dentry->d_count) {
+ dentry_stat.nr_unused--;
+ list_del(tmp);
+ INIT_LIST_HEAD(tmp);
+ continue;
+ }
+ /*
+ * Check the dentry's age to see whether to change direction.
+ */
+ if (!forward) {
+ int age = (jiffies - dentry->d_reftime) / HZ;
+ if (age < dentry_stat.age_limit) {
+ if (!--young) {
+ forward = 1;
+ next = dentry_unused.next;
+ /*
+ * Update the limits -- we don't want
+ * files with too few or too many pages.
+ */
+ if (page_count) {
+ min_value = 3;
+ max_value = 15;
+ }
+#ifdef DCACHE_DEBUG
+printk("select_dcache: %s/%s age=%d, scanning forward\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, age);
+#endif
+ }
+ continue;
+ }
+ }
+
+ /*
+ * Select dentries based on the page cache count ...
+ * should factor in number of uses as well. We take
+ * all negative dentries so that they don't accumulate.
+ * (We skip inodes that aren't immediately available.)
+ */
+ if (inode) {
+ value = inode->i_nrpages;
+ if (value >= max_value || value < min_value)
+ continue;
+ if (inode->i_state || inode->i_count > 1)
+ continue;
+ }
+
+ /*
+ * Move the selected dentries behind the tail.
+ */
+ if (tmp != tail->prev) {
+ list_del(tmp);
+ list_add(tmp, tail->prev);
+ }
+ tail = tmp;
+ found++;
+ if (inode && --inode_count <= 0)
+ break;
+ if (page_count && (page_count -= value) <= 0)
+ break;
+ }
+ return found;
+}
+
+/*
+ * Throw away a dentry - free the inode, dput the parent.
+ * This requires that the LRU list has already been
+ * removed.
+ */
+static inline void prune_one_dentry(struct dentry * dentry)
+{
+ struct dentry * parent;
+
+ list_del(&dentry->d_hash);
+ list_del(&dentry->d_child);
+ if (dentry->d_inode) {
+ struct inode * inode = dentry->d_inode;
+
+ dentry->d_inode = NULL;
+ iput(inode);
+ }
+ parent = dentry->d_parent;
+ d_free(dentry);
+ dput(parent);
+}
+
+/*
* Shrink the dcache. This is done when we need
* more memory, or simply when we need to unmount
* something (at which point we need to unuse
@@ -127,24 +282,169 @@ void prune_dcache(int count)
if (tmp == &dentry_unused)
break;
+ dentry_stat.nr_unused--;
list_del(tmp);
INIT_LIST_HEAD(tmp);
dentry = list_entry(tmp, struct dentry, d_lru);
if (!dentry->d_count) {
- struct dentry * parent;
+ prune_one_dentry(dentry);
+ if (!--count)
+ break;
+ }
+ }
+}
- list_del(&dentry->d_hash);
- if (dentry->d_inode) {
- struct inode * inode = dentry->d_inode;
+/*
+ * Shrink the dcache for the specified super block.
+ * This allows us to unmount a device without disturbing
+ * the dcache for the other devices.
+ *
+ * This implementation makes just two traversals of the
+ * unused list. On the first pass we move the selected
+ * dentries to the most recent end, and on the second
+ * pass we free them. The second pass must restart after
+ * each dput(), but since the target dentries are all at
+ * the end, it's really just a single traversal.
+ */
+void shrink_dcache_sb(struct super_block * sb)
+{
+ struct list_head *tmp, *next;
+ struct dentry *dentry;
+
+ /*
+ * Pass one ... move the dentries for the specified
+ * superblock to the most recent end of the unused list.
+ */
+ next = dentry_unused.next;
+ while (next != &dentry_unused) {
+ tmp = next;
+ next = tmp->next;
+ dentry = list_entry(tmp, struct dentry, d_lru);
+ if (dentry->d_sb != sb)
+ continue;
+ list_del(tmp);
+ list_add(tmp, &dentry_unused);
+ }
+
+ /*
+ * Pass two ... free the dentries for this superblock.
+ */
+repeat:
+ next = dentry_unused.next;
+ while (next != &dentry_unused) {
+ tmp = next;
+ next = tmp->next;
+ dentry = list_entry(tmp, struct dentry, d_lru);
+ if (dentry->d_sb != sb)
+ continue;
+ if (dentry->d_count)
+ continue;
+ dentry_stat.nr_unused--;
+ list_del(tmp);
+ INIT_LIST_HEAD(tmp);
+ prune_one_dentry(dentry);
+ goto repeat;
+ }
+}
+
+/*
+ * Search the dentry child list for the specified parent,
+ * and move any unused dentries to the end of the unused
+ * list for prune_dcache(). We descend to the next level
+ * whenever the d_subdirs list is non-empty and continue
+ * searching.
+ */
+static int select_parent(struct dentry * parent)
+{
+ struct dentry *this_parent = parent;
+ struct list_head *next;
+ int found = 0;
+
+repeat:
+ next = this_parent->d_subdirs.next;
+resume:
+ while (next != &this_parent->d_subdirs) {
+ struct list_head *tmp = next;
+ struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
+ next = tmp->next;
+ if (!dentry->d_count) {
+ list_del(&dentry->d_lru);
+ list_add(&dentry->d_lru, dentry_unused.prev);
+ found++;
+ }
+ /*
+ * Descend a level if the d_subdirs list is non-empty.
+ */
+ if (!list_empty(&dentry->d_subdirs)) {
+ this_parent = dentry;
+#ifdef DCACHE_DEBUG
+printk("select_parent: descending to %s/%s, found=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, found);
+#endif
+ goto repeat;
+ }
+ }
+ /*
+ * All done at this level ... ascend and resume the search.
+ */
+ if (this_parent != parent) {
+ next = this_parent->d_child.next;
+ this_parent = this_parent->d_parent;
+#ifdef DCACHE_DEBUG
+printk("select_parent: ascending to %s/%s, found=%d\n",
+this_parent->d_parent->d_name.name, this_parent->d_name.name, found);
+#endif
+ goto resume;
+ }
+ return found;
+}
+
+/*
+ * Prune the dcache to remove unused children of the parent dentry.
+ */
+void shrink_dcache_parent(struct dentry * parent)
+{
+ int found;
- dentry->d_inode = NULL;
- iput(inode);
+ while ((found = select_parent(parent)) != 0)
+ prune_dcache(found);
+}
+
+/*
+ * This is called from do_try_to_free_page() to indicate
+ * that we should reduce the dcache and inode cache memory.
+ */
+void shrink_dcache_memory()
+{
+ dentry_stat.want_pages++;
+}
+
+/*
+ * This carries out the request received by the above routine.
+ */
+void check_dcache_memory()
+{
+ if (dentry_stat.want_pages) {
+ unsigned int count, goal = 0;
+ /*
+ * Set the page goal. We don't necessarily need to trim
+ * the dcache just because the system needs memory ...
+ */
+ if (page_cache_size > (num_physpages >> 1))
+ goal = (dentry_stat.want_pages * page_cache_size)
+ / num_physpages;
+ dentry_stat.want_pages = 0;
+ if (goal) {
+ if (goal > 50)
+ goal = 50;
+ count = select_dcache(32, goal);
+#ifdef DCACHE_DEBUG
+printk("check_dcache_memory: goal=%d, count=%d\n", goal, count);
+#endif
+ if (count) {
+ prune_dcache(count);
+ free_inode_memory(count);
}
- parent = dentry->d_parent;
- d_free(dentry);
- dput(parent);
- if (!--count)
- break;
}
}
}
@@ -157,11 +457,15 @@ struct dentry * d_alloc(struct dentry * parent, const struct qstr *name)
struct dentry *dentry;
/*
- * Check whether to shrink the dcache ... this greatly reduces
- * the likelyhood that kmalloc() will need additional memory.
+ * Prune the dcache if there are too many unused dentries.
*/
- if (nr_free_pages < free_pages_low)
- shrink_dcache();
+ if (dentry_stat.nr_unused > 3*(nr_inodes >> 1)) {
+#ifdef DCACHE_DEBUG
+printk("d_alloc: %d unused, pruning dcache\n", dentry_stat.nr_unused);
+#endif
+ prune_dcache(8);
+ free_inode_memory(8);
+ }
dentry = kmalloc(sizeof(struct dentry), GFP_KERNEL);
if (!dentry)
@@ -184,11 +488,15 @@ struct dentry * d_alloc(struct dentry * parent, const struct qstr *name)
if (parent) {
dentry->d_parent = dget(parent);
dentry->d_sb = parent->d_sb;
- }
+ list_add(&dentry->d_child, &parent->d_subdirs);
+ } else
+ INIT_LIST_HEAD(&dentry->d_child);
+
dentry->d_mounts = dentry;
dentry->d_covers = dentry;
INIT_LIST_HEAD(&dentry->d_hash);
INIT_LIST_HEAD(&dentry->d_lru);
+ INIT_LIST_HEAD(&dentry->d_subdirs);
dentry->d_name.name = str;
dentry->d_name.len = name->len;
@@ -234,12 +542,13 @@ static inline struct list_head * d_hash(struct dentry * parent, unsigned long ha
return dentry_hashtable + (hash & D_HASHMASK);
}
-static inline struct dentry * __dlookup(struct list_head *head, struct dentry * parent, struct qstr * name)
+struct dentry * d_lookup(struct dentry * parent, struct qstr * name)
{
- struct list_head *tmp = head->next;
- int len = name->len;
- int hash = name->hash;
+ unsigned int len = name->len;
+ unsigned int hash = name->hash;
const unsigned char *str = name->name;
+ struct list_head *head = d_hash(parent,hash);
+ struct list_head *tmp = head->next;
while (tmp != head) {
struct dentry * dentry = list_entry(tmp, struct dentry, d_hash);
@@ -258,16 +567,11 @@ static inline struct dentry * __dlookup(struct list_head *head, struct dentry *
if (memcmp(dentry->d_name.name, str, len))
continue;
}
- return dget(dentry->d_mounts);
+ return dget(dentry);
}
return NULL;
}
-struct dentry * d_lookup(struct dentry * dir, struct qstr * name)
-{
- return __dlookup(d_hash(dir, name->hash), dir, name);
-}
-
/*
* An insecure source has sent us a dentry, here we verify it.
*
@@ -282,30 +586,33 @@ struct dentry * d_lookup(struct dentry * dir, struct qstr * name)
int d_validate(struct dentry *dentry, struct dentry *dparent,
unsigned int hash, unsigned int len)
{
- struct list_head *base = d_hash(dparent, hash);
- struct list_head *lhp = base;
-
- while ((lhp = lhp->next) != base) {
- if (dentry == list_entry(lhp, struct dentry, d_hash))
- goto found_it;
- }
-
- /* Special case, local mount points don't live in the hashes.
- * So if we exhausted the chain, search the super blocks.
- */
- if (dentry && dentry == dparent) {
- struct super_block *sb;
-
- for (sb = super_blocks + 0; sb < super_blocks + NR_SUPER; sb++) {
+ struct list_head *base, *lhp;
+ int valid = 1;
+
+ if (dentry != dparent) {
+ base = d_hash(dparent, hash);
+ lhp = base;
+ while ((lhp = lhp->next) != base) {
+ if (dentry == list_entry(lhp, struct dentry, d_hash))
+ goto out;
+ }
+ } else {
+ /*
+ * Special case: local mount points don't live in
+ * the hashes, so we search the super blocks.
+ */
+ struct super_block *sb = super_blocks + 0;
+
+ for (; sb < super_blocks + NR_SUPER; sb++) {
+ if (!sb->s_dev)
+ continue;
if (sb->s_root == dentry)
- goto found_it;
+ goto out;
}
}
- return 0;
-found_it:
- return (dentry->d_parent == dparent) &&
- (dentry->d_name.hash == hash) &&
- (dentry->d_name.len == len);
+ valid = 0;
+out:
+ return valid;
}
/*
@@ -381,11 +688,16 @@ void d_move(struct dentry * dentry, struct dentry * target)
list_del(&target->d_hash);
INIT_LIST_HEAD(&target->d_hash);
+ list_del(&dentry->d_child);
+ list_del(&target->d_child);
+
/* Switch the parents and the names.. */
switch(dentry->d_parent, target->d_parent);
switch(dentry->d_name.name, target->d_name.name);
switch(dentry->d_name.len, target->d_name.len);
switch(dentry->d_name.hash, target->d_name.hash);
+ list_add(&target->d_child, &target->d_parent->d_subdirs);
+ list_add(&dentry->d_child, &dentry->d_parent->d_subdirs);
}
/*
diff --git a/fs/dquot.c b/fs/dquot.c
index 3b59ef828..cf2b91c0a 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -223,25 +223,17 @@ static void write_dquot(struct dquot *dquot)
short type = dquot->dq_type;
struct file *filp = dquot->dq_mnt->mnt_quotas[type];
unsigned long fs;
+ loff_t offset;
if (!(dquot->dq_flags & DQ_MOD) || (filp == (struct file *)NULL))
return;
lock_dquot(dquot);
down(&dquot->dq_mnt->mnt_sem);
- if (filp->f_op->llseek) {
- if (filp->f_op->llseek(filp->f_dentry->d_inode, filp,
- dqoff(dquot->dq_id), 0) != dqoff(dquot->dq_id)) {
- up(&dquot->dq_mnt->mnt_sem);
- unlock_dquot(dquot);
- return;
- }
- } else
- filp->f_pos = dqoff(dquot->dq_id);
+ offset = dqoff(dquot->dq_id);
fs = get_fs();
set_fs(KERNEL_DS);
- if (filp->f_op->write(filp->f_dentry->d_inode, filp,
- (char *)&dquot->dq_dqb, sizeof(struct dqblk)) == sizeof(struct dqblk))
+ if (filp->f_op->write(filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk), &offset) == sizeof(struct dqblk))
dquot->dq_flags &= ~DQ_MOD;
up(&dquot->dq_mnt->mnt_sem);
@@ -255,23 +247,16 @@ static void read_dquot(struct dquot *dquot)
short type = dquot->dq_type;
struct file *filp = dquot->dq_mnt->mnt_quotas[type];
unsigned long fs;
+ loff_t offset;
if (filp == (struct file *)NULL)
return;
lock_dquot(dquot);
down(&dquot->dq_mnt->mnt_sem);
- if (filp->f_op->llseek) {
- if (filp->f_op->llseek(filp->f_dentry->d_inode, filp,
- dqoff(dquot->dq_id), 0) != dqoff(dquot->dq_id)) {
- up(&dquot->dq_mnt->mnt_sem);
- unlock_dquot(dquot);
- return;
- }
- } else
- filp->f_pos = dqoff(dquot->dq_id);
+ offset = dqoff(dquot->dq_id);
fs = get_fs();
set_fs(KERNEL_DS);
- filp->f_op->read(filp->f_dentry->d_inode, filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk));
+ filp->f_op->read(filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk), &offset);
up(&dquot->dq_mnt->mnt_sem);
set_fs(fs);
if (dquot->dq_bhardlimit == 0 && dquot->dq_bsoftlimit == 0 &&
diff --git a/fs/exec.c b/fs/exec.c
index 027d8ceb6..731d678aa 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -376,13 +376,13 @@ int read_exec(struct dentry *dentry, unsigned long offset,
if (to_kmem) {
unsigned long old_fs = get_fs();
set_fs(get_ds());
- result = file.f_op->read(inode, &file, addr, count);
+ result = file.f_op->read(&file, addr, count, &file.f_pos);
set_fs(old_fs);
} else {
result = verify_area(VERIFY_WRITE, addr, count);
if (result)
goto close_readexec;
- result = file.f_op->read(inode, &file, addr, count);
+ result = file.f_op->read(&file, addr, count, &file.f_pos);
}
close_readexec:
if (file.f_op->release)
@@ -431,16 +431,34 @@ fail_restore:
current->mm = old_mm;
mmput(mm);
- /*
- * N.B. binfmt_xxx needs to handle the error instead of oom()
- */
fail_nomem:
- /* this is wrong, I think. */
- oom(current);
return retval;
}
/*
+ * This function makes sure the current process has its own signal table,
+ * so that flush_old_signals can later reset the signals without disturbing
+ * other processes. (Other processes might share the signal table via
+ * the CLONE_SIGHAND option to clone().)
+ */
+
+static inline int make_private_signals(void)
+{
+ struct signal_struct * newsig;
+
+ if (atomic_read(&current->sig->count) <= 1)
+ return 0;
+ newsig = kmalloc(sizeof(*newsig), GFP_KERNEL);
+ if (newsig == NULL)
+ return -ENOMEM;
+ spin_lock_init(&newsig->siglock);
+ atomic_set(&newsig->count, 1);
+ memcpy(newsig->action, current->sig->action, sizeof(newsig->action));
+ current->sig = newsig;
+ return 0;
+}
+
+/*
* These functions flushes out all traces of the currently running executable
* so that a new one can be started
*/
@@ -480,18 +498,24 @@ static inline void flush_old_files(struct files_struct * files)
}
}
-void flush_old_exec(struct linux_binprm * bprm)
+int flush_old_exec(struct linux_binprm * bprm)
{
char * name;
int i, ch, retval;
+ struct signal_struct * oldsig;
+
+ /*
+ * Make sure we have a private signal table
+ */
+ oldsig = current->sig;
+ retval = make_private_signals();
+ if (retval) goto flush_failed;
/*
- * Release all of the old mmap stuff ... do this first
- * so we can bail out on failure.
+ * Release all of the old mmap stuff
*/
retval = exec_mmap();
- if (retval)
- goto out;
+ if (retval) goto flush_failed;
if (current->euid == current->uid && current->egid == current->gid)
current->dumpable = 1;
@@ -513,8 +537,12 @@ void flush_old_exec(struct linux_binprm * bprm)
flush_old_signals(current->sig);
flush_old_files(current->files);
-out:
- return; /* retval; FIXME. */
+
+ return 0;
+
+flush_failed:
+ current->sig = oldsig;
+ return retval;
}
/*
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 9f7af4e12..6560d511d 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -26,8 +26,8 @@
#include <linux/sched.h>
#include <linux/stat.h>
-static long ext2_dir_read (struct inode * inode, struct file * filp,
- char * buf, unsigned long count)
+static ssize_t ext2_dir_read (struct file * filp, char * buf,
+ size_t count, loff_t *ppos)
{
return -EISDIR;
}
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index b5f55efd6..2b4b7130b 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -37,7 +37,7 @@
#include <linux/ext2_fs.h>
static long long ext2_file_lseek(struct file *, long long, int);
-static long ext2_file_write (struct inode *, struct file *, const char *, unsigned long);
+static ssize_t ext2_file_write (struct file *, const char *, size_t, loff_t *);
static int ext2_release_file (struct inode *, struct file *);
/*
@@ -127,9 +127,10 @@ static inline void remove_suid(struct inode *inode)
}
}
-static long ext2_file_write (struct inode * inode, struct file * filp,
- const char * buf, unsigned long count)
+static ssize_t ext2_file_write (struct file * filp, const char * buf,
+ size_t count, loff_t *ppos)
{
+ struct inode * inode = filp->f_dentry->d_inode;
__u32 pos;
long block;
int offset;
@@ -163,8 +164,12 @@ static long ext2_file_write (struct inode * inode, struct file * filp,
if (filp->f_flags & O_APPEND)
pos = inode->i_size;
- else
- pos = filp->f_pos;
+ else {
+ pos = *ppos;
+ if (pos != *ppos)
+ return -EINVAL;
+ }
+
/* Check for overflow.. */
if (pos > (__u32) (pos + count)) {
count = ~pos; /* == 0xFFFFFFFF - pos */
@@ -251,7 +256,7 @@ static long ext2_file_write (struct inode * inode, struct file * filp,
if (filp->f_flags & O_SYNC)
inode->u.ext2_i.i_osync--;
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
- filp->f_pos = pos;
+ *ppos = pos;
mark_inode_dirty(inode);
return written;
}
diff --git a/fs/ext2/fsync.c b/fs/ext2/fsync.c
index 8a9bdf902..b5b531d8c 100644
--- a/fs/ext2/fsync.c
+++ b/fs/ext2/fsync.c
@@ -57,72 +57,6 @@ static int sync_block (struct inode * inode, u32 * block, int wait)
return 0;
}
-#ifndef __LITTLE_ENDIAN
-static int sync_block_swab32 (struct inode * inode, u32 * block, int wait)
-{
- struct buffer_head * bh;
-
- if (!le32_to_cpu(*block))
- return 0;
- bh = get_hash_table (inode->i_dev, le32_to_cpu(*block), blocksize);
- if (!bh)
- return 0;
- if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
- brelse (bh);
- return -1;
- }
- if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) {
- brelse (bh);
- return 0;
- }
- ll_rw_block (WRITE, 1, &bh);
- bh->b_count--;
- return 0;
-}
-#else
-#define sync_block_swab32 sync_block
-#endif
-
-
-static int sync_iblock (struct inode * inode, u32 * iblock,
- struct buffer_head ** bh, int wait)
-{
- int rc, tmp;
-
- *bh = NULL;
- tmp = *iblock;
- if (!tmp)
- return 0;
- rc = sync_block (inode, iblock, wait);
- if (rc)
- return rc;
- *bh = bread (inode->i_dev, tmp, blocksize);
- if (!*bh)
- return -1;
- return 0;
-}
-
-#ifndef __LITTLE_ENDIAN
-static int sync_iblock_swab32 (struct inode * inode, u32 * iblock,
- struct buffer_head ** bh, int wait)
-{
- int rc, tmp;
-
- *bh = NULL;
- tmp = le32_to_cpu(*iblock);
- if (!tmp)
- return 0;
- rc = sync_block_swab32 (inode, iblock, wait);
- if (rc)
- return rc;
- *bh = bread (inode->i_dev, tmp, blocksize);
- if (!*bh)
- return -1;
- return 0;
-}
-#else
-#define sync_iblock_swab32 sync_iblock
-#endif
static int sync_direct (struct inode * inode, int wait)
{
@@ -137,122 +71,15 @@ static int sync_direct (struct inode * inode, int wait)
return err;
}
-static int sync_indirect (struct inode * inode, u32 * iblock, int wait)
-{
- int i;
- struct buffer_head * ind_bh;
- int rc, err = 0;
-
- rc = sync_iblock (inode, iblock, &ind_bh, wait);
- if (rc || !ind_bh)
- return rc;
-
- for (i = 0; i < addr_per_block; i++) {
- rc = sync_block_swab32 (inode,
- ((u32 *) ind_bh->b_data) + i,
- wait);
- if (rc)
- err = rc;
- }
- brelse (ind_bh);
- return err;
-}
-
-#ifndef __LITTLE_ENDIAN
-static __inline__ int sync_indirect_swab32 (struct inode * inode, u32 * iblock, int wait)
-{
- int i;
- struct buffer_head * ind_bh;
- int rc, err = 0;
-
- rc = sync_iblock_swab32 (inode, iblock, &ind_bh, wait);
- if (rc || !ind_bh)
- return rc;
-
- for (i = 0; i < addr_per_block; i++) {
- rc = sync_block_swab32 (inode,
- ((u32 *) ind_bh->b_data) + i,
- wait);
- if (rc)
- err = rc;
- }
- brelse (ind_bh);
- return err;
-}
-#else
-#define sync_indirect_swab32 sync_indirect
-#endif
-
-static int sync_dindirect (struct inode * inode, u32 * diblock, int wait)
-{
- int i;
- struct buffer_head * dind_bh;
- int rc, err = 0;
-
- rc = sync_iblock (inode, diblock, &dind_bh, wait);
- if (rc || !dind_bh)
- return rc;
-
- for (i = 0; i < addr_per_block; i++) {
- rc = sync_indirect_swab32 (inode,
- ((u32 *) dind_bh->b_data) + i,
- wait);
- if (rc)
- err = rc;
- }
- brelse (dind_bh);
- return err;
-}
-
-#ifndef __LITTLE_ENDIAN
-static __inline__ int sync_dindirect_swab32 (struct inode * inode, u32 * diblock, int wait)
-{
- int i;
- struct buffer_head * dind_bh;
- int rc, err = 0;
-
- rc = sync_iblock_swab32 (inode, diblock, &dind_bh, wait);
- if (rc || !dind_bh)
- return rc;
-
- for (i = 0; i < addr_per_block; i++) {
- rc = sync_indirect_swab32 (inode,
- ((u32 *) dind_bh->b_data) + i,
- wait);
- if (rc)
- err = rc;
- }
- brelse (dind_bh);
- return err;
-}
-#else
-#define sync_dindirect_swab32 sync_dindirect
-#endif
-
-static int sync_tindirect (struct inode * inode, u32 * tiblock, int wait)
-{
- int i;
- struct buffer_head * tind_bh;
- int rc, err = 0;
-
- rc = sync_iblock (inode, tiblock, &tind_bh, wait);
- if (rc || !tind_bh)
- return rc;
-
- for (i = 0; i < addr_per_block; i++) {
- rc = sync_dindirect_swab32 (inode,
- ((u32 *) tind_bh->b_data) + i,
- wait);
- if (rc)
- err = rc;
- }
- brelse (tind_bh);
- return err;
-}
-
/*
* File may be NULL when we are called. Perhaps we shouldn't
* even pass file to fsync ?
+ *
+ * This currently falls back to synching the whole device when
+ * the file is larger than can fit directly in the inode. This
+ * is because dirty-buffer handling is indexed by the device
+ * of the buffer, which makes it much faster to sync the whole
+ * device than to sync just one large file.
*/
int ext2_sync_file(struct file * file, struct dentry *dentry)
@@ -269,18 +96,12 @@ int ext2_sync_file(struct file * file, struct dentry *dentry)
*/
goto skip;
+ if (inode->i_size > EXT2_NDIR_BLOCKS*blocksize)
+ return file_fsync(file, dentry);
+
for (wait=0; wait<=1; wait++)
{
err |= sync_direct (inode, wait);
- err |= sync_indirect (inode,
- inode->u.ext2_i.i_data+EXT2_IND_BLOCK,
- wait);
- err |= sync_dindirect (inode,
- inode->u.ext2_i.i_data+EXT2_DIND_BLOCK,
- wait);
- err |= sync_tindirect (inode,
- inode->u.ext2_i.i_data+EXT2_TIND_BLOCK,
- wait);
}
skip:
err |= ext2_sync_inode (inode);
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 62f19eaa1..0ca8a74c7 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -353,8 +353,6 @@ int ext2_create (struct inode * dir, struct dentry * dentry, int mode)
struct ext2_dir_entry * de;
int err = -EIO;
- if (!dir)
- return -ENOENT;
/*
* N.B. Several error exits in ext2_new_inode don't set err.
*/
@@ -391,15 +389,13 @@ int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
struct ext2_dir_entry * de;
int err = -EIO;
- if (!dir)
- return -ENOENT;
-
+ err = -ENAMETOOLONG;
if (dentry->d_name.len > EXT2_NAME_LEN)
- return -ENAMETOOLONG;
+ goto out;
inode = ext2_new_inode (dir, mode, &err);
if (!inode)
- return err;
+ goto out;
inode->i_uid = current->fsuid;
inode->i_mode = mode;
@@ -423,12 +419,8 @@ int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
inode->i_rdev = to_kdev_t(rdev);
mark_inode_dirty(inode);
bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
- if (!bh) {
- inode->i_nlink--;
- mark_inode_dirty(inode);
- iput(inode);
- return err;
- }
+ if (!bh)
+ goto out_no_entry;
de->inode = cpu_to_le32(inode->i_ino);
dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
@@ -436,9 +428,17 @@ int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
- brelse(bh);
d_instantiate(dentry, inode);
- return 0;
+ brelse(bh);
+ err = 0;
+out:
+ return err;
+
+out_no_entry:
+ inode->i_nlink--;
+ mark_inode_dirty(inode);
+ iput(inode);
+ goto out;
}
int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
@@ -446,23 +446,26 @@ int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
struct inode * inode;
struct buffer_head * bh, * dir_block;
struct ext2_dir_entry * de;
- int err = -EIO;
+ int err;
+ err = -ENAMETOOLONG;
if (dentry->d_name.len > EXT2_NAME_LEN)
- return -ENAMETOOLONG;
+ goto out;
+ err = -EMLINK;
if (dir->i_nlink >= EXT2_LINK_MAX)
- return -EMLINK;
+ goto out;
+ err = -EIO;
inode = ext2_new_inode (dir, S_IFDIR, &err);
if (!inode)
- return err;
+ goto out;
inode->i_op = &ext2_dir_inode_operations;
inode->i_size = inode->i_sb->s_blocksize;
dir_block = ext2_bread (inode, 0, 1, &err);
if (!dir_block) {
- inode->i_nlink--;
+ inode->i_nlink--; /* is this nlink == 0? */
mark_inode_dirty(inode);
iput (inode);
return err;
@@ -486,12 +489,8 @@ int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
inode->i_mode |= S_ISGID;
mark_inode_dirty(inode);
bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
- if (!bh) {
- inode->i_nlink = 0;
- mark_inode_dirty(inode);
- iput (inode);
- return err;
- }
+ if (!bh)
+ goto out_no_entry;
de->inode = cpu_to_le32(inode->i_ino);
dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
@@ -503,7 +502,15 @@ int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
mark_inode_dirty(dir);
d_instantiate(dentry, inode);
brelse (bh);
- return 0;
+ err = 0;
+out:
+ return err;
+
+out_no_entry:
+ inode->i_nlink = 0;
+ mark_inode_dirty(inode);
+ iput (inode);
+ goto out;
}
/*
@@ -572,25 +579,23 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry)
struct buffer_head * bh;
struct ext2_dir_entry * de;
- if (!dir)
- return -ENOENT;
- inode = NULL;
+ retval = -ENAMETOOLONG;
if (dentry->d_name.len > EXT2_NAME_LEN)
- return -ENAMETOOLONG;
+ goto out;
- bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
retval = -ENOENT;
+ bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
if (!bh)
goto end_rmdir;
- retval = -EPERM;
- inode = dentry->d_inode;
+ inode = dentry->d_inode;
if (inode->i_sb->dq_op)
inode->i_sb->dq_op->initialize (inode, -1);
- if ((dir->i_mode & S_ISVTX) && !fsuser() &&
- current->fsuid != inode->i_uid &&
- current->fsuid != dir->i_uid)
+ retval = -EPERM;
+ if ((dir->i_mode & S_ISVTX) &&
+ current->fsuid != inode->i_uid &&
+ current->fsuid != dir->i_uid && !fsuser())
goto end_rmdir;
if (inode == dir) /* we may not delete ".", but "../dir" is ok */
goto end_rmdir;
@@ -606,12 +611,18 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry)
goto end_rmdir;
down(&inode->i_sem);
+ /*
+ * Prune any child dentries so that this dentry becomes negative.
+ */
+ if (dentry->d_count > 1)
+ shrink_dcache_parent(dentry);
+
if (!empty_dir (inode))
retval = -ENOTEMPTY;
else if (le32_to_cpu(de->inode) != inode->i_ino)
retval = -ENOENT;
else {
- if (inode->i_count > 1) {
+ if (dentry->d_count > 1) {
/*
* Are we deleting the last instance of a busy directory?
* Better clean up if so.
@@ -646,6 +657,7 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry)
end_rmdir:
brelse (bh);
+out:
return retval;
}
@@ -656,11 +668,11 @@ int ext2_unlink(struct inode * dir, struct dentry *dentry)
struct buffer_head * bh;
struct ext2_dir_entry * de;
- retval = -ENOENT;
- inode = NULL;
+ retval = -ENAMETOOLONG;
if (dentry->d_name.len > EXT2_NAME_LEN)
- return -ENAMETOOLONG;
+ goto out;
+ retval = -ENOENT;
bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
if (!bh)
goto end_unlink;
@@ -674,9 +686,9 @@ int ext2_unlink(struct inode * dir, struct dentry *dentry)
goto end_unlink;
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
goto end_unlink;
- if ((dir->i_mode & S_ISVTX) && !fsuser() &&
+ if ((dir->i_mode & S_ISVTX) &&
current->fsuid != inode->i_uid &&
- current->fsuid != dir->i_uid)
+ current->fsuid != dir->i_uid && !fsuser())
goto end_unlink;
retval = -EIO;
@@ -708,13 +720,14 @@ int ext2_unlink(struct inode * dir, struct dentry *dentry)
end_unlink:
brelse (bh);
+out:
return retval;
}
int ext2_symlink (struct inode * dir, struct dentry *dentry, const char * symname)
{
struct ext2_dir_entry * de;
- struct inode * inode = NULL;
+ struct inode * inode;
struct buffer_head * bh = NULL, * name_block = NULL;
char * link;
int i, l, err = -EIO;
@@ -758,12 +771,8 @@ int ext2_symlink (struct inode * dir, struct dentry *dentry, const char * symnam
mark_inode_dirty(inode);
bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
- if (!bh) {
- inode->i_nlink--;
- mark_inode_dirty(inode);
- iput (inode);
- return err;
- }
+ if (!bh)
+ goto out_no_entry;
de->inode = cpu_to_le32(inode->i_ino);
dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
@@ -773,7 +782,15 @@ int ext2_symlink (struct inode * dir, struct dentry *dentry, const char * symnam
}
brelse (bh);
d_instantiate(dentry, inode);
- return 0;
+ err = 0;
+out:
+ return err;
+
+out_no_entry:
+ inode->i_nlink--;
+ mark_inode_dirty(inode);
+ iput (inode);
+ goto out;
}
int ext2_link (struct inode * inode, struct inode * dir, struct dentry *dentry)
@@ -888,10 +905,9 @@ static int do_ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
new_inode->i_sb->dq_op->initialize (new_inode, -1);
}
}
- if (new_inode == old_inode) {
- retval = 0;
+ retval = 0;
+ if (new_inode == old_inode)
goto end_rename;
- }
if (new_inode && S_ISDIR(new_inode->i_mode)) {
retval = -EISDIR;
if (!S_ISDIR(old_inode->i_mode))
@@ -903,7 +919,7 @@ static int do_ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
if (!empty_dir (new_inode))
goto end_rename;
retval = -EBUSY;
- if (new_inode->i_count > 1)
+ if (new_dentry->d_count > 1)
goto end_rename;
}
retval = -EPERM;
diff --git a/fs/fat/buffer.c b/fs/fat/buffer.c
index 2a6fc6b74..4c827711d 100644
--- a/fs/fat/buffer.c
+++ b/fs/fat/buffer.c
@@ -10,22 +10,31 @@
#include <linux/fs.h>
#include <linux/msdos_fs.h>
+#if 0
+# define PRINTK(x) printk x
+#else
+# define PRINTK(x)
+#endif
+
struct buffer_head *fat_bread (
struct super_block *sb,
int block)
{
struct buffer_head *ret = NULL;
- /* Note that the blocksize is 512, 1024 or 2048, but the first read
- is always of size 1024 (or 2048). Doing readahead may be counterproductive
- or just plain wrong. */
+ PRINTK(("fat_bread: block=0x%x\n", block));
+ /*
+ * Note that the blocksize is 512, 1024 or 2048, but the first read
+ * is always of size 1024 (or 2048). Doing readahead may be
+ * counterproductive or just plain wrong.
+ */
if (sb->s_blocksize == 512) {
ret = bread (sb->s_dev,block,512);
} else {
struct buffer_head *real;
if (sb->s_blocksize == 1024){
real = bread (sb->s_dev,block>>1,1024);
- }else{
+ } else {
real = bread (sb->s_dev,block>>2,2048);
}
@@ -82,6 +91,7 @@ struct buffer_head *fat_getblk (
int block)
{
struct buffer_head *ret = NULL;
+ PRINTK(("fat_getblk: block=0x%x\n", block));
if (sb->s_blocksize == 512){
ret = getblk (sb->s_dev,block,512);
}else{
diff --git a/fs/fat/cache.c b/fs/fat/cache.c
index 5fdcb772e..ece255ca1 100644
--- a/fs/fat/cache.c
+++ b/fs/fat/cache.c
@@ -12,6 +12,11 @@
#include "msbuffer.h"
+#if 0
+# define PRINTK(x) printk x
+#else
+# define PRINTK(x)
+#endif
static struct fat_cache *fat_cache,cache[FAT_CACHE];
@@ -22,11 +27,13 @@ int fat_access(struct super_block *sb,int nr,int new_value)
{
struct buffer_head *bh,*bh2,*c_bh,*c_bh2;
unsigned char *p_first,*p_last;
- int first,last,next,copy,b;
+ int copy,first,last,next,b;
if ((unsigned) (nr-2) >= MSDOS_SB(sb)->clusters)
return 0;
- if (MSDOS_SB(sb)->fat_bits == 16) {
+ if (MSDOS_SB(sb)->fat_bits == 32) {
+ first = last = nr*4;
+ } else if (MSDOS_SB(sb)->fat_bits == 16) {
first = last = nr*2;
} else {
first = nr*3/2;
@@ -46,13 +53,19 @@ int fat_access(struct super_block *sb,int nr,int new_value)
return 0;
}
}
- if (MSDOS_SB(sb)->fat_bits == 16) {
+ if (MSDOS_SB(sb)->fat_bits == 32) {
+ p_first = p_last = NULL; /* GCC needs that stuff */
+ next = CF_LE_L(((unsigned long *) bh->b_data)[(first &
+ (SECTOR_SIZE-1)) >> 2]);
+ if (next >= 0xffffff7) next = -1;
+ PRINTK(("fat_bread: 0x%x, nr=0x%x, first=0x%x, next=0x%d\n", b, nr, first, next));
+
+ } else if (MSDOS_SB(sb)->fat_bits == 16) {
p_first = p_last = NULL; /* GCC needs that stuff */
next = CF_LE_W(((unsigned short *) bh->b_data)[(first &
(SECTOR_SIZE-1)) >> 1]);
if (next >= 0xfff7) next = -1;
- }
- else {
+ } else {
p_first = &((unsigned char *) bh->b_data)[first & (SECTOR_SIZE-1)];
p_last = &((unsigned char *) bh2->b_data)[(first+1) &
(SECTOR_SIZE-1)];
@@ -61,10 +74,13 @@ int fat_access(struct super_block *sb,int nr,int new_value)
if (next >= 0xff7) next = -1;
}
if (new_value != -1) {
- if (MSDOS_SB(sb)->fat_bits == 16)
+ if (MSDOS_SB(sb)->fat_bits == 32) {
+ ((unsigned long *) bh->b_data)[(first & (SECTOR_SIZE-1)) >>
+ 2] = CT_LE_L(new_value);
+ } else if (MSDOS_SB(sb)->fat_bits == 16) {
((unsigned short *) bh->b_data)[(first & (SECTOR_SIZE-1)) >>
1] = CT_LE_W(new_value);
- else {
+ } else {
if (nr & 1) {
*p_first = (*p_first & 0xf) | (new_value << 4);
*p_last = new_value >> 4;
@@ -172,7 +188,8 @@ printk("cache add: <%s,%d> %d (%d)\n", kdevname(inode->i_dev),
&& walk->ino == inode->i_ino
&& walk->file_cluster == f_clu) {
if (walk->disk_cluster != d_clu) {
- printk("FAT cache corruption");
+ printk("FAT cache corruption inode=%ld\n",
+ inode->i_ino);
fat_cache_inval_inode(inode);
return;
}
@@ -239,16 +256,17 @@ int get_cluster(struct inode *inode,int cluster)
return nr;
}
-
int fat_smap(struct inode *inode,int sector)
{
struct msdos_sb_info *sb;
int cluster,offset;
sb = MSDOS_SB(inode->i_sb);
- if (inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) &&
- !MSDOS_I(inode)->i_start)) {
- if (sector >= sb->dir_entries >> MSDOS_DPS_BITS) return 0;
+ if ((sb->fat_bits != 32) &&
+ (inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) &&
+ !MSDOS_I(inode)->i_start))) {
+ if (sector >= sb->dir_entries >> MSDOS_DPS_BITS)
+ return 0;
return sector+sb->dir_start;
}
cluster = sector/sb->cluster_size;
@@ -279,6 +297,7 @@ int fat_free(struct inode *inode,int skip)
fat_access(inode->i_sb,last,EOF_FAT(inode->i_sb));
else {
MSDOS_I(inode)->i_start = 0;
+ MSDOS_I(inode)->i_logstart = 0;
mark_inode_dirty(inode);
}
lock_fat(inode->i_sb);
@@ -287,8 +306,12 @@ int fat_free(struct inode *inode,int skip)
fat_fs_panic(inode->i_sb,"fat_free: deleting beyond EOF");
break;
}
- if (MSDOS_SB(inode->i_sb)->free_clusters != -1)
+ if (MSDOS_SB(inode->i_sb)->free_clusters != -1) {
MSDOS_SB(inode->i_sb)->free_clusters++;
+ if (MSDOS_SB(inode->i_sb)->fat_bits == 32) {
+ fat_clusters_flush(inode->i_sb);
+ }
+ }
inode->i_blocks -= MSDOS_SB(inode->i_sb)->cluster_size;
}
unlock_fat(inode->i_sb);
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 494f7781b..7568f876a 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -11,8 +11,12 @@
* Merged with msdos fs by Henrik Storner <storner@osiris.ping.dk>
*/
+#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S))
+
+#include <linux/version.h>
#include <linux/fs.h>
#include <linux/msdos_fs.h>
+#include <linux/nls.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/stat.h>
@@ -24,13 +28,11 @@
#include <asm/uaccess.h>
#include "msbuffer.h"
-#include "tables.h"
-
#define PRINTK(X)
-static long fat_dir_read(struct inode * inode,struct file * filp,
- char * buf, unsigned long count)
+static ssize_t fat_dir_read(struct file * filp, char * buf,
+ size_t count, loff_t *ppos)
{
return -EISDIR;
}
@@ -40,7 +42,7 @@ struct file_operations fat_dir_operations = {
fat_dir_read, /* read */
NULL, /* write - bad */
fat_readdir, /* readdir */
- NULL, /* poll - default */
+ NULL, /* select v2.0.x/poll v2.1.x - default */
fat_dir_ioctl, /* ioctl - default */
NULL, /* mmap */
NULL, /* no special open code */
@@ -48,7 +50,9 @@ struct file_operations fat_dir_operations = {
file_fsync /* fsync */
};
-/* Convert Unicode string to ASCII. If uni_xlate is enabled and we
+/*
+ * Convert Unicode 16 to UTF8, translated unicode, or ascii.
+ * If uni_xlate is enabled and we
* can't get a 1:1 conversion, use a colon as an escape character since
* it is normally invalid on the vfat filesystem. The following three
* characters are a sort of uuencoded 16 bit Unicode value. This lets
@@ -56,10 +60,11 @@ struct file_operations fat_dir_operations = {
* into some trouble with long Unicode names, but ignore that right now.
*/
static int
-uni2ascii(unsigned char *uni, unsigned char *ascii, int uni_xlate)
+uni16_to_x8(unsigned char *ascii, unsigned char *uni, int uni_xlate,
+ struct nls_table *nls)
{
unsigned char *ip, *op;
- unsigned char page, pg_off;
+ unsigned char ch, cl;
unsigned char *uni_page;
unsigned short val;
@@ -67,21 +72,21 @@ uni2ascii(unsigned char *uni, unsigned char *ascii, int uni_xlate)
op = ascii;
while (*ip || ip[1]) {
- pg_off = *ip++;
- page = *ip++;
-
- uni_page = fat_uni2asc_pg[page];
- if (uni_page && uni_page[pg_off]) {
- *op++ = uni_page[pg_off];
+ cl = *ip++;
+ ch = *ip++;
+
+ uni_page = nls->page_uni2charset[ch];
+ if (uni_page && uni_page[cl]) {
+ *op++ = uni_page[cl];
} else {
if (uni_xlate == 1) {
*op++ = ':';
- val = (pg_off << 8) + page;
- op[2] = fat_uni2code[val & 0x3f];
+ val = (cl << 8) + ch;
+ op[2] = fat_uni2esc[val & 0x3f];
val >>= 6;
- op[1] = fat_uni2code[val & 0x3f];
+ op[1] = fat_uni2esc[val & 0x3f];
val >>= 6;
- *op = fat_uni2code[val & 0x3f];
+ *op = fat_uni2esc[val & 0x3f];
op += 3;
} else {
*op++ = '?';
@@ -92,6 +97,19 @@ uni2ascii(unsigned char *uni, unsigned char *ascii, int uni_xlate)
return (op - ascii);
}
+#if 0
+static void dump_de(struct msdos_dir_entry *de)
+{
+ int i;
+ unsigned char *p = (unsigned char *) de;
+ printk("[");
+
+ for (i = 0; i < 32; i++, p++) {
+ printk("%02x ", *p);
+ }
+ printk("]\n");
+}
+#endif
int fat_readdirx(
struct inode *inode,
struct file *filp,
@@ -115,7 +133,9 @@ int fat_readdirx(
unsigned char alias_checksum = 0; /* Make compiler warning go away */
unsigned char long_slots = 0;
int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
+ int utf8 = MSDOS_SB(sb)->options.utf8;
unsigned char *unicode = NULL;
+ struct nls_table *nls = MSDOS_SB(sb)->nls_io;
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
@@ -138,6 +158,9 @@ int fat_readdirx(
is_long = 0;
ino = fat_get_entry(inode,&filp->f_pos,&bh,&de);
while (ino > -1) {
+#if 0
+ dump_de(de);
+#endif
/* Check for long filename entry */
if (MSDOS_SB(sb)->options.isvfat && (de->name[0] == (__s8) DELETED_FLAG)) {
is_long = 0;
@@ -217,7 +240,6 @@ int fat_readdirx(
if (is_long) {
unsigned char sum;
- long_len = uni2ascii(unicode, longname, uni_xlate);
for (sum = 0, i = 0; i < 11; i++) {
sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
}
@@ -226,6 +248,11 @@ int fat_readdirx(
PRINTK(("Checksums don't match %d != %d\n", sum, alias_checksum));
is_long = 0;
}
+ if (utf8) {
+ long_len = utf8_wcstombs(longname, (__u16 *) unicode, sizeof(longname));
+ } else {
+ long_len = uni16_to_x8(longname, unicode, uni_xlate, nls);
+ }
}
if ((de->attr & ATTR_HIDDEN) && MSDOS_SB(sb)->options.dotsOK) {
@@ -390,7 +417,7 @@ int fat_dir_ioctl(struct inode * inode, struct file * filp,
switch (cmd) {
case VFAT_IOCTL_READDIR_BOTH: {
struct dirent *d1 = (struct dirent *)arg;
- err = verify_area(VERIFY_WRITE, d1, sizeof (*d1));
+ err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2]));
if (err)
return err;
put_user(0, &d1->d_reclen);
@@ -400,7 +427,7 @@ int fat_dir_ioctl(struct inode * inode, struct file * filp,
case VFAT_IOCTL_READDIR_SHORT: {
struct dirent *d1 = (struct dirent *)arg;
put_user(0, &d1->d_reclen);
- err = verify_area(VERIFY_WRITE, d1, sizeof (*d1));
+ err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2]));
if (err)
return err;
return fat_readdirx(inode,filp,(void *)arg,
diff --git a/fs/fat/fatfs_syms.c b/fs/fat/fatfs_syms.c
index c7ec96030..60e71ed98 100644
--- a/fs/fat/fatfs_syms.c
+++ b/fs/fat/fatfs_syms.c
@@ -4,6 +4,8 @@
* Exported kernel symbols for the low-level FAT-based fs support.
*
*/
+#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S))
+#include <linux/version.h>
#include <linux/config.h>
#include <linux/module.h>
@@ -15,16 +17,14 @@
extern struct file_operations fat_dir_operations;
-EXPORT_SYMBOL(fat_a2alias);
-EXPORT_SYMBOL(fat_a2uni);
EXPORT_SYMBOL(fat_add_cluster);
EXPORT_SYMBOL(fat_bmap);
EXPORT_SYMBOL(fat_brelse);
EXPORT_SYMBOL(fat_cache_inval_inode);
-EXPORT_SYMBOL(fat_code2uni);
EXPORT_SYMBOL(fat_date_unix2dos);
EXPORT_SYMBOL(fat_delete_inode);
EXPORT_SYMBOL(fat_dir_operations);
+EXPORT_SYMBOL(fat_esc2uni);
EXPORT_SYMBOL(fat_file_read);
EXPORT_SYMBOL(fat_file_write);
EXPORT_SYMBOL(fat_fs_panic);
@@ -44,8 +44,7 @@ EXPORT_SYMBOL(fat_scan);
EXPORT_SYMBOL(fat_smap);
EXPORT_SYMBOL(fat_statfs);
EXPORT_SYMBOL(fat_truncate);
-EXPORT_SYMBOL(fat_uni2asc_pg);
-EXPORT_SYMBOL(fat_uni2code);
+EXPORT_SYMBOL(fat_uni2esc);
EXPORT_SYMBOL(fat_unlock_creation);
EXPORT_SYMBOL(fat_write_inode);
diff --git a/fs/fat/file.c b/fs/fat/file.c
index ca35cc28f..f3a4f6cec 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -6,6 +6,8 @@
* regular file handling primitives for fat-based filesystems
*/
+#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S))
+#include <linux/version.h>
#include <linux/sched.h>
#include <linux/locks.h>
#include <linux/fs.h>
@@ -32,7 +34,7 @@ static struct file_operations fat_file_operations = {
fat_file_read, /* read */
fat_file_write, /* write */
NULL, /* readdir - bad */
- NULL, /* poll - default */
+ NULL, /* select v2.0.x/poll v2.1.x - default */
NULL, /* ioctl - default */
generic_file_mmap, /* mmap */
NULL, /* no special open is needed */
@@ -60,6 +62,7 @@ struct inode_operations fat_file_inode_operations = {
NULL, /* permission */
NULL /* smap */
};
+
/* #Specification: msdos / special devices / mmap
Mmapping does work because a special mmap is provide in that case.
Note that it is much less efficient than the generic_file_mmap normally
@@ -71,7 +74,7 @@ static struct file_operations fat_file_operations_1024 = {
fat_file_read, /* read */
fat_file_write, /* write */
NULL, /* readdir - bad */
- NULL, /* poll - default */
+ NULL, /* select v2.0.x/poll v2.1.x - default */
NULL, /* ioctl - default */
fat_mmap, /* mmap */
NULL, /* no special open is needed */
@@ -152,12 +155,13 @@ static void fat_prefetch (
/*
Read a file into user space
*/
-long fat_file_read(
- struct inode *inode,
+ssize_t fat_file_read(
struct file *filp,
char *buf,
- unsigned long count)
+ size_t count,
+ loff_t *ppos)
{
+ struct inode *inode = filp->f_dentry->d_inode;
struct super_block *sb = inode->i_sb;
char *start = buf;
char *end = buf + count;
@@ -175,7 +179,7 @@ long fat_file_read(
printk("fat_file_read: mode = %07o\n",inode->i_mode);
return -EINVAL;
}
- if (filp->f_pos >= inode->i_size || count == 0) return 0;
+ if (*ppos >= inode->i_size || count == 0) return 0;
/*
Tell the buffer cache which block we expect to read in advance
Since we are limited with the stack, we preread only MSDOS_PREFETCH
@@ -185,15 +189,15 @@ long fat_file_read(
Each time we process one block in bhlist, we replace
it by a new prefetch block if needed.
*/
- PRINTK (("#### ino %ld pos %ld size %ld count %d\n",inode->i_ino,filp->f_pos,inode->i_size,count));
+ PRINTK (("#### ino %ld pos %ld size %ld count %d\n",inode->i_ino,*ppos,inode->i_size,count));
{
/*
We must prefetch complete block, so we must
take in account the offset in the first block.
*/
- int count_max = (filp->f_pos & (SECTOR_SIZE-1)) + count;
+ int count_max = (*ppos & (SECTOR_SIZE-1)) + count;
int to_reada; /* How many block to read all at once */
- pre.file_sector = filp->f_pos >> SECTOR_BITS;
+ pre.file_sector = *ppos >> SECTOR_BITS;
to_reada = count_max / SECTOR_SIZE;
if (count_max & (SECTOR_SIZE-1)) to_reada++;
if (filp->f_reada || !MSDOS_I(inode)->i_binary){
@@ -211,7 +215,7 @@ long fat_file_read(
}
pre.nolist = 0;
PRINTK (("count %d ahead %d nblist %d\n",count,read_ahead[MAJOR(inode->i_dev)],pre.nblist));
- while ((left_in_file = inode->i_size - filp->f_pos) > 0
+ while ((left_in_file = inode->i_size - *ppos) > 0
&& buf < end){
struct buffer_head *bh = pre.bhlist[pre.nolist];
char *data;
@@ -226,27 +230,27 @@ long fat_file_read(
fat_prefetch (inode,&pre,MSDOS_PREFETCH/2);
pre.nolist = 0;
}
- PRINTK (("file_read pos %ld nblist %d %d %d\n",filp->f_pos,pre.nblist,pre.fetched,count));
+ PRINTK (("file_read pos %ld nblist %d %d %d\n",*ppos,pre.nblist,pre.fetched,count));
wait_on_buffer(bh);
if (!fat_is_uptodate(sb,bh)){
/* read error ? */
fat_brelse (sb, bh);
break;
}
- offset = filp->f_pos & (SECTOR_SIZE-1);
+ offset = *ppos & (SECTOR_SIZE-1);
data = bh->b_data + offset;
size = MIN(SECTOR_SIZE-offset,left_in_file);
if (MSDOS_I(inode)->i_binary) {
size = MIN(size,end-buf);
copy_to_user(buf,data,size);
buf += size;
- filp->f_pos += size;
+ *ppos += size;
}else{
for (; size && buf < end; size--) {
char ch = *data++;
- filp->f_pos++;
+ ++*ppos;
if (ch == 26){
- filp->f_pos = inode->i_size;
+ *ppos = inode->i_size;
break;
}else if (ch != '\r'){
put_user(ch,buf++);
@@ -269,12 +273,13 @@ long fat_file_read(
/*
Write to a file either from user space
*/
-long fat_file_write(
- struct inode *inode,
+ssize_t fat_file_write(
struct file *filp,
const char *buf,
- unsigned long count)
+ size_t count,
+ loff_t *ppos)
{
+ struct inode *inode = filp->f_dentry->d_inode;
struct super_block *sb = inode->i_sb;
int sector,offset,size,left,written;
int error,carry;
@@ -300,23 +305,23 @@ long fat_file_write(
* but so what. That way leads to madness anyway.
*/
if (filp->f_flags & O_APPEND)
- filp->f_pos = inode->i_size;
+ *ppos = inode->i_size;
if (count == 0)
return 0;
error = carry = 0;
for (start = buf; count || carry; count -= size) {
- while (!(sector = fat_smap(inode,filp->f_pos >> SECTOR_BITS)))
+ while (!(sector = fat_smap(inode,*ppos >> SECTOR_BITS)))
if ((error = fat_add_cluster(inode)) < 0) break;
if (error) {
fat_truncate(inode);
break;
}
- offset = filp->f_pos & (SECTOR_SIZE-1);
+ offset = *ppos & (SECTOR_SIZE-1);
size = MIN(SECTOR_SIZE-offset,MAX(carry,count));
if (binary_mode
&& offset == 0
&& (size == SECTOR_SIZE
- || filp->f_pos + size >= inode->i_size)){
+ || *ppos + size >= inode->i_size)){
/* No need to read the block first since we will */
/* completely overwrite it */
/* or at least write past the end of file */
@@ -333,7 +338,7 @@ long fat_file_write(
buf += size;
} else {
written = left = SECTOR_SIZE-offset;
- to = (char *) bh->b_data+(filp->f_pos & (SECTOR_SIZE-1));
+ to = (char *) bh->b_data+(*ppos & (SECTOR_SIZE-1));
if (carry) {
*to++ = '\n';
left--;
@@ -353,10 +358,10 @@ long fat_file_write(
}
written -= left;
}
- update_vm_cache(inode, filp->f_pos, bh->b_data + (filp->f_pos & (SECTOR_SIZE-1)), written);
- filp->f_pos += written;
- if (filp->f_pos > inode->i_size) {
- inode->i_size = filp->f_pos;
+ update_vm_cache(inode, *ppos, bh->b_data + (*ppos & (SECTOR_SIZE-1)), written);
+ *ppos += written;
+ if (*ppos > inode->i_size) {
+ inode->i_size = *ppos;
mark_inode_dirty(inode);
}
fat_set_uptodate(sb, bh, 1);
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 8ffd91e3d..732d0b9ba 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -5,10 +5,12 @@
* VFAT extensions by Gordon Chaffee, merged with msdos fs by Henrik Storner
*/
+#include <linux/version.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/msdos_fs.h>
+#include <linux/nls.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
@@ -18,76 +20,137 @@
#include <linux/fs.h>
#include <linux/stat.h>
#include <linux/locks.h>
+#include <linux/malloc.h>
#include "msbuffer.h"
-#include "tables.h"
#include <asm/uaccess.h>
#include <asm/unaligned.h>
+/* #define FAT_PARANOIA 1 */
+#ifdef FAT_DEBUG
+# define PRINTK(x) printk x
+#else
+# define PRINTK(x)
+#endif
-
-void fat_put_inode(struct inode *inode)
-{
- struct inode *depend, *linked;
- struct super_block *sb;
-
- depend = MSDOS_I(inode)->i_depend;
- linked = MSDOS_I(inode)->i_linked;
- sb = inode->i_sb;
- if (inode->i_nlink) {
- if (depend) {
- iput(depend);
- }
- if (linked) {
- iput(linked);
- MSDOS_I(inode)->i_linked = NULL;
- }
- if (MSDOS_I(inode)->i_busy) fat_cache_inval_inode(inode);
- }
-}
-
-void fat_delete_inode(struct inode *inode)
+/*
+ * Free any dependent inodes at the (effective) last use.
+ */
+static int fat_free_links(struct inode *inode)
{
- struct inode *depend, *linked;
- struct super_block *sb;
+ struct inode *depend, *linked, *old_inode;
+ int success = 0;
+ /*
+ * Clear the fields first to avoid races
+ */
depend = MSDOS_I(inode)->i_depend;
+ MSDOS_I(inode)->i_depend = NULL;
linked = MSDOS_I(inode)->i_linked;
- sb = inode->i_sb;
+ MSDOS_I(inode)->i_linked = NULL;
- inode->i_size = 0;
- fat_truncate(inode);
if (depend) {
- if (MSDOS_I(depend)->i_old != inode) {
- printk("Invalid link (0x%p): expected 0x%p, got 0x%p\n",
- depend, inode, MSDOS_I(depend)->i_old);
- fat_fs_panic(sb,"...");
- goto done;
+#ifdef FAT_PARANOIA
+printk("fat_put_inode: depend inode is %ld, i_count=%d\n",
+depend->i_ino, depend->i_count);
+#endif
+ old_inode = MSDOS_I(depend)->i_old;
+ if (old_inode != inode) {
+ printk("fat_free_link: Invalid depend for inode %ld: "
+ "expected 0x%p, got 0x%p\n",
+ depend->i_ino, inode, old_inode);
+ goto out;
}
MSDOS_I(depend)->i_old = NULL;
iput(depend);
}
+
if (linked) {
- if (MSDOS_I(linked)->i_oldlink != inode) {
- printk("Invalid link (0x%p): expected 0x%p, got 0x%p\n",
- linked, inode, MSDOS_I(linked)->i_oldlink);
- fat_fs_panic(sb,"...");
- goto done;
+#ifdef FAT_PARANOIA
+printk("fat_put_inode: linked inode is %ld, i_count=%d\n",
+linked->i_ino, linked->i_count);
+#endif
+ old_inode = MSDOS_I(linked)->i_oldlink;
+ if (old_inode != inode) {
+ printk("fat_free_link: Invalid link for inode %ld: "
+ "expected 0x%p, got 0x%p\n",
+ linked->i_ino, inode, old_inode);
+ goto out;
}
MSDOS_I(linked)->i_oldlink = NULL;
iput(linked);
}
-done:
+ success = 1;
+out:
+ return success;
+}
+
+/*
+ * This is a little tricky, as we may have links and may be linked
+ * by other inodes. Also, we're subject to race conditions ...
+ */
+void fat_put_inode(struct inode *inode)
+{
+ int last_use = 1;
+
+ /*
+ * Check whether we're a dependent of other inodes ...
+ */
+ if (MSDOS_I(inode)->i_oldlink)
+ last_use++;
+ if (MSDOS_I(inode)->i_old)
+ last_use++;
+
+ if (inode->i_count <= last_use) {
+#ifdef FAT_PARANOIA
+printk("fat_put_inode: last use for %ld, i_count=%d\n",
+inode->i_ino, inode->i_count);
+#endif
+ if (inode->i_nlink) {
+ if (MSDOS_I(inode)->i_busy)
+ fat_cache_inval_inode(inode);
+ fat_free_links(inode);
+ }
+ }
+}
+
+void fat_delete_inode(struct inode *inode)
+{
+ fat_cache_inval_inode(inode);
+ inode->i_size = 0;
+ fat_truncate(inode);
+ if (!fat_free_links(inode))
+ fat_fs_panic(inode->i_sb,"..."); /* is this necessary? */
clear_inode(inode);
}
void fat_put_super(struct super_block *sb)
{
+ lock_super(sb);
+ if (MSDOS_SB(sb)->fat_bits == 32) {
+ fat_clusters_flush(sb);
+ }
fat_cache_inval_dev(sb->s_dev);
set_blocksize (sb->s_dev,BLOCK_SIZE);
- lock_super(sb);
+ if (MSDOS_SB(sb)->nls_disk) {
+ unload_nls(MSDOS_SB(sb)->nls_disk);
+ MSDOS_SB(sb)->nls_disk = NULL;
+ MSDOS_SB(sb)->options.codepage = 0;
+ }
+ if (MSDOS_SB(sb)->nls_io) {
+ unload_nls(MSDOS_SB(sb)->nls_io);
+ MSDOS_SB(sb)->nls_io = NULL;
+ }
+ /*
+ * Note: the iocharset option might have been specified
+ * without enabling nls_io, so check for it here.
+ */
+ if (MSDOS_SB(sb)->options.iocharset) {
+ kfree(MSDOS_SB(sb)->options.iocharset);
+ MSDOS_SB(sb)->options.iocharset = NULL;
+ }
sb->s_dev = 0;
unlock_super(sb);
MOD_DEC_USE_COUNT;
@@ -98,35 +161,53 @@ void fat_put_super(struct super_block *sb)
static int parse_options(char *options,int *fat, int *blksize, int *debug,
struct fat_mount_options *opts)
{
- char *this_char,*value;
+ char *this_char,*value,save,*savep;
+ char *p;
+ int ret = 1, len;
opts->name_check = 'n';
opts->conversion = 'b';
opts->fs_uid = current->uid;
opts->fs_gid = current->gid;
opts->fs_umask = current->fs->umask;
- opts->quiet = opts->sys_immutable = opts->dotsOK = opts->showexec = opts->isvfat = 0;
+ opts->quiet = opts->sys_immutable = opts->dotsOK = opts->showexec = 0;
+ opts->codepage = 0;
+ opts->utf8 = 0;
+ opts->iocharset = NULL;
*debug = *fat = 0;
- if (!options) return 1;
- for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
- if ((value = strchr(this_char,'=')) != NULL)
+ if (!options)
+ goto out;
+ save = 0;
+ savep = NULL;
+ for (this_char = strtok(options,","); this_char;
+ this_char = strtok(NULL,",")) {
+ if ((value = strchr(this_char,'=')) != NULL) {
+ save = *value;
+ savep = value;
*value++ = 0;
+ }
if (!strcmp(this_char,"check") && value) {
if (value[0] && !value[1] && strchr("rns",*value))
opts->name_check = *value;
- else if (!strcmp(value,"relaxed")) opts->name_check = 'r';
- else if (!strcmp(value,"normal")) opts->name_check = 'n';
- else if (!strcmp(value,"strict")) opts->name_check = 's';
- else return 0;
+ else if (!strcmp(value,"relaxed"))
+ opts->name_check = 'r';
+ else if (!strcmp(value,"normal"))
+ opts->name_check = 'n';
+ else if (!strcmp(value,"strict"))
+ opts->name_check = 's';
+ else ret = 0;
}
else if (!strcmp(this_char,"conv") && value) {
if (value[0] && !value[1] && strchr("bta",*value))
opts->conversion = *value;
- else if (!strcmp(value,"binary")) opts->conversion = 'b';
- else if (!strcmp(value,"text")) opts->conversion = 't';
- else if (!strcmp(value,"auto")) opts->conversion = 'a';
- else return 0;
+ else if (!strcmp(value,"binary"))
+ opts->conversion = 'b';
+ else if (!strcmp(value,"text"))
+ opts->conversion = 't';
+ else if (!strcmp(value,"auto"))
+ opts->conversion = 'a';
+ else ret = 0;
}
else if (!strcmp(this_char,"dots")) {
opts->dotsOK = 1;
@@ -140,73 +221,110 @@ static int parse_options(char *options,int *fat, int *blksize, int *debug,
else if (!strcmp(this_char,"dotsOK") && value) {
if (!strcmp(value,"yes")) opts->dotsOK = 1;
else if (!strcmp(value,"no")) opts->dotsOK = 0;
- else return 0;
+ else ret = 0;
}
else if (!strcmp(this_char,"uid")) {
- if (!value || !*value)
- return 0;
- opts->fs_uid = simple_strtoul(value,&value,0);
- if (*value)
- return 0;
+ if (!value || !*value) ret = 0;
+ else {
+ opts->fs_uid = simple_strtoul(value,&value,0);
+ if (*value) ret = 0;
+ }
}
else if (!strcmp(this_char,"gid")) {
- if (!value || !*value)
- return 0;
- opts->fs_gid = simple_strtoul(value,&value,0);
- if (*value)
- return 0;
+ if (!value || !*value) ret= 0;
+ else {
+ opts->fs_gid = simple_strtoul(value,&value,0);
+ if (*value) ret = 0;
+ }
}
else if (!strcmp(this_char,"umask")) {
- if (!value || !*value)
- return 0;
- opts->fs_umask = simple_strtoul(value,&value,8);
- if (*value)
- return 0;
+ if (!value || !*value) ret = 0;
+ else {
+ opts->fs_umask = simple_strtoul(value,&value,8);
+ if (*value) ret = 0;
+ }
}
else if (!strcmp(this_char,"debug")) {
- if (value) return 0;
- *debug = 1;
+ if (value) ret = 0;
+ else *debug = 1;
}
else if (!strcmp(this_char,"fat")) {
- if (!value || !*value)
- return 0;
- *fat = simple_strtoul(value,&value,0);
- if (*value || (*fat != 12 && *fat != 16))
- return 0;
+ if (!value || !*value) ret = 0;
+ else {
+ *fat = simple_strtoul(value,&value,0);
+ if (*value || (*fat != 12 && *fat != 16 &&
+ *fat != 32))
+ ret = 0;
+ }
}
else if (!strcmp(this_char,"quiet")) {
- if (value) return 0;
- opts->quiet = 1;
+ if (value) ret = 0;
+ else opts->quiet = 1;
}
else if (!strcmp(this_char,"blocksize")) {
- *blksize = simple_strtoul(value,&value,0);
- if (*value)
- return 0;
- if (*blksize != 512 && *blksize != 1024 && *blksize != 2048){
- printk ("MSDOS FS: Invalid blocksize (512, 1024 or 2048)\n");
+ if (*value) ret = 0;
+ else if (*blksize != 512 &&
+ *blksize != 1024 &&
+ *blksize != 2048) {
+ printk ("MSDOS FS: Invalid blocksize "
+ "(512, 1024, or 2048)\n");
}
}
else if (!strcmp(this_char,"sys_immutable")) {
- if (value)
- return 0;
- opts->sys_immutable = 1;
+ if (value) ret = 0;
+ else opts->sys_immutable = 1;
+ }
+ else if (!strcmp(this_char,"codepage")) {
+ opts->codepage = simple_strtoul(value,&value,0);
+ if (*value) ret = 0;
+ else printk ("MSDOS FS: Using codepage %d\n",
+ opts->codepage);
}
+ else if (!strcmp(this_char,"iocharset")) {
+ p = value;
+ while (*value && *value != ',') value++;
+ len = value - p;
+ if (len) {
+ char * buffer = kmalloc(len+1, GFP_KERNEL);
+ if (buffer) {
+ opts->iocharset = buffer;
+ memcpy(buffer, p, len);
+ buffer[len] = 0;
+ printk("MSDOS FS: IO charset %s\n",
+ buffer);
+ } else
+ ret = 0;
+ }
+ }
+
+ if (this_char != options) *(this_char-1) = ',';
+ if (value) *savep = save;
+ if (ret == 0)
+ break;
}
- return 1;
+out:
+ return ret;
}
-
-/* Read the super block of an MS-DOS FS. */
-
-struct super_block *fat_read_super(struct super_block *sb,void *data, int silent)
+/*
+ * Read the super block of an MS-DOS FS.
+ *
+ * Note that this may be called from vfat_read_super
+ * with some fields already initialized.
+ */
+struct super_block *
+fat_read_super(struct super_block *sb, void *data, int silent)
{
+ struct inode *root_inode;
struct buffer_head *bh;
- struct msdos_boot_sector *b;
+ struct fat_boot_sector *b;
+ char *p;
int data_sectors,logical_sector_size,sector_mult,fat_clusters=0;
- int debug,error,fat;
+ int debug,error,fat,cp;
int blksize = 512;
+ int fat32;
struct fat_mount_options opts;
- struct inode *root_inode;
+ char buf[50];
MOD_INC_USE_COUNT;
if (hardsect_size[MAJOR(sb->s_dev)] != NULL){
@@ -215,13 +333,14 @@ struct super_block *fat_read_super(struct super_block *sb,void *data, int silent
printk ("MSDOS: Hardware sector size is %d\n",blksize);
}
}
+
+ opts.isvfat = MSDOS_SB(sb)->options.isvfat;
if (!parse_options((char *) data, &fat, &blksize, &debug, &opts)
- || (blksize != 512 && blksize != 1024 && blksize != 2048))
- {
- sb->s_dev = 0;
- MOD_DEC_USE_COUNT;
- return NULL;
- }
+ || (blksize != 512 && blksize != 1024 && blksize != 2048))
+ goto out_fail;
+ /* N.B. we should parse directly into the sb structure */
+ memcpy(&(MSDOS_SB(sb)->options), &opts, sizeof(struct fat_mount_options));
+
cache_init();
lock_super(sb);
if( blksize > 1024 )
@@ -240,13 +359,10 @@ struct super_block *fat_read_super(struct super_block *sb,void *data, int silent
unlock_super(sb);
if (bh == NULL || !fat_is_uptodate(sb,bh)) {
fat_brelse (sb, bh);
- sb->s_dev = 0;
- printk("FAT bread failed\n");
- MOD_DEC_USE_COUNT;
- return NULL;
+ goto out_no_bread;
}
- b = (struct msdos_boot_sector *) bh->b_data;
set_blocksize(sb->s_dev, blksize);
+
/*
* The DOS3 partition size limit is *not* 32M as many people think.
* Instead, it is 64K sectors (with the usual sector size being
@@ -265,15 +381,39 @@ struct super_block *fat_read_super(struct super_block *sb,void *data, int silent
#define ROUND_TO_MULTIPLE(n,m) ((n) && (m) ? (n)+(m)-1-((n)-1)%(m) : 0)
/* don't divide by zero */
+ b = (struct fat_boot_sector *) bh->b_data;
logical_sector_size =
CF_LE_W(get_unaligned((unsigned short *) &b->sector_size));
sector_mult = logical_sector_size >> SECTOR_BITS;
MSDOS_SB(sb)->cluster_size = b->cluster_size*sector_mult;
MSDOS_SB(sb)->fats = b->fats;
MSDOS_SB(sb)->fat_start = CF_LE_W(b->reserved)*sector_mult;
- MSDOS_SB(sb)->fat_length = CF_LE_W(b->fat_length)*sector_mult;
- MSDOS_SB(sb)->dir_start = (CF_LE_W(b->reserved)+b->fats*CF_LE_W(
- b->fat_length))*sector_mult;
+ if (!b->fat_length && b->fat32_length) {
+ struct fat_boot_fsinfo *fsinfo;
+
+ /* Must be FAT32 */
+ fat32 = 1;
+ MSDOS_SB(sb)->fat_length= CF_LE_W(b->fat32_length)*sector_mult;
+ MSDOS_SB(sb)->root_cluster = CF_LE_L(b->root_cluster);
+ MSDOS_SB(sb)->fsinfo_offset =
+ CF_LE_W(b->info_sector) * logical_sector_size + 0x1e0;
+ fsinfo = (struct fat_boot_fsinfo *)
+ &bh->b_data[MSDOS_SB(sb)->fsinfo_offset];
+ if (CF_LE_L(fsinfo->signature) != 0x61417272) {
+ printk("fat_read_super: Did not find valid FSINFO "
+ "signature. Found 0x%x\n",
+ CF_LE_L(fsinfo->signature));
+ } else {
+ MSDOS_SB(sb)->free_clusters = CF_LE_L(fsinfo->free_clusters);
+ }
+ } else {
+ fat32 = 0;
+ MSDOS_SB(sb)->fat_length = CF_LE_W(b->fat_length)*sector_mult;
+ MSDOS_SB(sb)->root_cluster = 0;
+ MSDOS_SB(sb)->free_clusters = -1; /* Don't know yet */
+ }
+ MSDOS_SB(sb)->dir_start= CF_LE_W(b->reserved)*sector_mult+
+ b->fats*MSDOS_SB(sb)->fat_length;
MSDOS_SB(sb)->dir_entries =
CF_LE_W(get_unaligned((unsigned short *) &b->dir_entries));
MSDOS_SB(sb)->data_start = MSDOS_SB(sb)->dir_start+ROUND_TO_MULTIPLE((
@@ -288,8 +428,9 @@ struct super_block *fat_read_super(struct super_block *sb,void *data, int silent
if (!error) {
MSDOS_SB(sb)->clusters = b->cluster_size ? data_sectors/
b->cluster_size/sector_mult : 0;
- MSDOS_SB(sb)->fat_bits = fat ? fat : MSDOS_SB(sb)->clusters >
- MSDOS_FAT12 ? 16 : 12;
+ MSDOS_SB(sb)->fat_bits = fat32 ? 32 :
+ (fat ? fat :
+ (MSDOS_SB(sb)->clusters > MSDOS_FAT12 ? 16 : 12));
fat_clusters = MSDOS_SB(sb)->fat_length*SECTOR_SIZE*8/
MSDOS_SB(sb)->fat_bits;
error = !MSDOS_SB(sb)->fats || (MSDOS_SB(sb)->dir_entries &
@@ -315,43 +456,83 @@ struct super_block *fat_read_super(struct super_block *sb,void *data, int silent
opts.conversion,opts.fs_uid,opts.fs_gid,opts.fs_umask,
MSDOS_CAN_BMAP(MSDOS_SB(sb)) ? ",bmap" : "");
printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d,"
- "se=%d,ts=%d,ls=%d]\n",b->media,MSDOS_SB(sb)->cluster_size,
- MSDOS_SB(sb)->fats,MSDOS_SB(sb)->fat_start,MSDOS_SB(sb)->fat_length,
+ "se=%d,ts=%ld,ls=%d,rc=%ld,fc=%u]\n",
+ b->media,MSDOS_SB(sb)->cluster_size,
+ MSDOS_SB(sb)->fats,MSDOS_SB(sb)->fat_start,
+ MSDOS_SB(sb)->fat_length,
MSDOS_SB(sb)->dir_start,MSDOS_SB(sb)->dir_entries,
MSDOS_SB(sb)->data_start,
- CF_LE_W(get_unaligned((unsigned short *) &b->sectors)),
- CF_LE_L(b->total_sect),logical_sector_size);
+ CF_LE_W(*(unsigned short *) &b->sectors),
+ (unsigned long)b->total_sect,logical_sector_size,
+ MSDOS_SB(sb)->root_cluster,MSDOS_SB(sb)->free_clusters);
printk ("Transaction block size = %d\n",blksize);
}
if (MSDOS_SB(sb)->clusters+2 > fat_clusters)
MSDOS_SB(sb)->clusters = fat_clusters-2;
- if (error) {
- if (!silent)
- printk("VFS: Can't find a valid MSDOS filesystem on dev "
- "%s.\n", kdevname(sb->s_dev));
- sb->s_dev = 0;
- MOD_DEC_USE_COUNT;
- return NULL;
- }
+ if (error)
+ goto out_invalid;
+
sb->s_magic = MSDOS_SUPER_MAGIC;
/* set up enough so that it can read an inode */
- MSDOS_SB(sb)->free_clusters = -1; /* don't know yet */
MSDOS_SB(sb)->fat_wait = NULL;
MSDOS_SB(sb)->fat_lock = 0;
MSDOS_SB(sb)->prev_free = 0;
- memcpy(&(MSDOS_SB(sb)->options), &opts, sizeof(struct fat_mount_options));
- root_inode = iget(sb,MSDOS_ROOT_INO);
- sb->s_root = d_alloc_root(root_inode, NULL);
- if (!sb->s_root) {
- sb->s_dev = 0;
- printk("get root inode failed\n");
- MOD_DEC_USE_COUNT;
- return NULL;
+ cp = opts.codepage ? opts.codepage : 437;
+ sprintf(buf, "cp%d", cp);
+ MSDOS_SB(sb)->nls_disk = load_nls(buf);
+ if (! MSDOS_SB(sb)->nls_disk) {
+ /* Fail only if explicit charset specified */
+ if (opts.codepage != 0)
+ goto out_fail;
+ MSDOS_SB(sb)->options.codepage = 0; /* already 0?? */
+ MSDOS_SB(sb)->nls_disk = load_nls_default();
+ }
+
+ MSDOS_SB(sb)->nls_io = NULL;
+ if (MSDOS_SB(sb)->options.isvfat && !opts.utf8) {
+ p = opts.iocharset ? opts.iocharset : "iso8859-1";
+ MSDOS_SB(sb)->nls_io = load_nls(p);
+ if (! MSDOS_SB(sb)->nls_io) {
+ /* Fail only if explicit charset specified */
+ if (opts.iocharset)
+ goto out_unload_nls;
+ MSDOS_SB(sb)->nls_io = load_nls_default();
+ }
}
+
+ root_inode = iget(sb, MSDOS_ROOT_INO);
+ if (!root_inode)
+ goto out_no_root;
+ sb->s_root = d_alloc_root(root_inode, NULL);
+ if (!sb->s_root)
+ goto out_no_root;
return sb;
-}
+out_no_root:
+ printk("get root inode failed\n");
+ iput(root_inode);
+ if (MSDOS_SB(sb)->nls_io)
+ unload_nls(MSDOS_SB(sb)->nls_io);
+out_unload_nls:
+ unload_nls(MSDOS_SB(sb)->nls_disk);
+ goto out_fail;
+out_invalid:
+ if (!silent)
+ printk("VFS: Can't find a valid MSDOS filesystem on dev %s.\n",
+ kdevname(sb->s_dev));
+ goto out_fail;
+out_no_bread:
+ printk("FAT bread failed\n");
+out_fail:
+ if (opts.iocharset) {
+ printk("VFS: freeing iocharset=%s\n", opts.iocharset);
+ kfree(opts.iocharset);
+ }
+ sb->s_dev = 0;
+ MOD_DEC_USE_COUNT;
+ return NULL;
+}
int fat_statfs(struct super_block *sb,struct statfs *buf, int bufsiz)
{
@@ -386,7 +567,7 @@ int fat_bmap(struct inode *inode,int block)
int cluster,offset;
sb = MSDOS_SB(inode->i_sb);
- if (inode->i_ino == MSDOS_ROOT_INO) {
+ if ((inode->i_ino == MSDOS_ROOT_INO) && (sb->fat_bits != 32)) {
return sb->dir_start + block;
}
cluster = block/sb->cluster_size;
@@ -412,6 +593,8 @@ void fat_read_inode(struct inode *inode, struct inode_operations *fs_dir_inode_o
struct msdos_dir_entry *raw_entry;
int nr;
+ PRINTK(("fat_read_inode: inode=%p, sb->dir_start=0x%x\n",
+ inode, MSDOS_SB(sb)->dir_start));
MSDOS_I(inode)->i_busy = 0;
MSDOS_I(inode)->i_depend = MSDOS_I(inode)->i_old = NULL;
MSDOS_I(inode)->i_linked = MSDOS_I(inode)->i_oldlink = NULL;
@@ -423,17 +606,33 @@ void fat_read_inode(struct inode *inode, struct inode_operations *fs_dir_inode_o
inode->i_mode = (S_IRWXUGO & ~MSDOS_SB(sb)->options.fs_umask) |
S_IFDIR;
inode->i_op = fs_dir_inode_ops;
- inode->i_nlink = fat_subdirs(inode)+2;
- /* subdirs (neither . nor ..) plus . and "self" */
- inode->i_size = MSDOS_SB(sb)->dir_entries*
- sizeof(struct msdos_dir_entry);
+ if (MSDOS_SB(sb)->fat_bits == 32) {
+ MSDOS_I(inode)->i_start = MSDOS_SB(sb)->root_cluster;
+ if ((nr = MSDOS_I(inode)->i_start) != 0) {
+ while (nr != -1) {
+ inode->i_size += SECTOR_SIZE*MSDOS_SB(sb)->cluster_size;
+ if (!(nr = fat_access(sb,nr,-1))) {
+ printk("Directory %ld: bad FAT\n",
+ inode->i_ino);
+ break;
+ }
+ }
+ }
+ } else {
+ MSDOS_I(inode)->i_start = 0;
+ inode->i_size = MSDOS_SB(sb)->dir_entries*
+ sizeof(struct msdos_dir_entry);
+ }
inode->i_blksize = MSDOS_SB(sb)->cluster_size*
SECTOR_SIZE;
inode->i_blocks = (inode->i_size+inode->i_blksize-1)/
inode->i_blksize*MSDOS_SB(sb)->cluster_size;
- MSDOS_I(inode)->i_start = 0;
+ MSDOS_I(inode)->i_logstart = 0;
+
MSDOS_I(inode)->i_attrs = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = 0;
+ inode->i_nlink = fat_subdirs(inode)+2;
+ /* subdirs (neither . nor ..) plus . and "self" */
return;
}
if (!(bh = fat_bread(sb, inode->i_ino >> MSDOS_DPB_BITS))) {
@@ -449,6 +648,11 @@ void fat_read_inode(struct inode *inode, struct inode_operations *fs_dir_inode_o
inode->i_op = fs_dir_inode_ops;
MSDOS_I(inode)->i_start = CF_LE_W(raw_entry->start);
+ if (MSDOS_SB(sb)->fat_bits == 32) {
+ MSDOS_I(inode)->i_start |=
+ (CF_LE_W(raw_entry->starthi) << 16);
+ }
+ MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;
inode->i_nlink = fat_subdirs(inode);
/* includes .., compensating for "self" */
#ifdef DEBUG
@@ -458,7 +662,7 @@ void fat_read_inode(struct inode *inode, struct inode_operations *fs_dir_inode_o
}
#endif
inode->i_size = 0;
- if ((nr = CF_LE_W(raw_entry->start)) != 0)
+ if ((nr = MSDOS_I(inode)->i_start) != 0)
while (nr != -1) {
inode->i_size += SECTOR_SIZE*MSDOS_SB(inode->
i_sb)->cluster_size;
@@ -479,6 +683,11 @@ void fat_read_inode(struct inode *inode, struct inode_operations *fs_dir_inode_o
? &fat_file_inode_operations_1024
: &fat_file_inode_operations;
MSDOS_I(inode)->i_start = CF_LE_W(raw_entry->start);
+ if (MSDOS_SB(sb)->fat_bits == 32) {
+ MSDOS_I(inode)->i_start |=
+ (CF_LE_W(raw_entry->starthi) << 16);
+ }
+ MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start;
inode->i_nlink = 1;
inode->i_size = CF_LE_L(raw_entry->size);
}
@@ -549,7 +758,8 @@ void fat_write_inode(struct inode *inode)
}
raw_entry->attr |= MSDOS_MKATTR(inode->i_mode) |
MSDOS_I(inode)->i_attrs;
- raw_entry->start = CT_LE_W(MSDOS_I(inode)->i_start);
+ raw_entry->start = CT_LE_W(MSDOS_I(inode)->i_logstart);
+ raw_entry->starthi = CT_LE_W(MSDOS_I(inode)->i_logstart >> 16);
fat_date_unix2dos(inode->i_mtime,&raw_entry->time,&raw_entry->date);
raw_entry->time = CT_LE_W(raw_entry->time);
raw_entry->date = CT_LE_W(raw_entry->date);
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index 5b71573b3..0fb7791ec 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -14,7 +14,11 @@
#include "msbuffer.h"
-#define PRINTK(x)
+#if 0
+# define PRINTK(x) printk x
+#else
+# define PRINTK(x)
+#endif
#define Printk(x) printk x
/* Well-known binary file extensions - of course there are many more */
@@ -106,6 +110,34 @@ void unlock_fat(struct super_block *sb)
wake_up(&MSDOS_SB(sb)->fat_wait);
}
+/* Flushes the number of free clusters on FAT32 */
+/* XXX: Need to write one per FSINFO block. Currently only writes 1 */
+void fat_clusters_flush(struct super_block *sb)
+{
+ int offset;
+ struct buffer_head *bh;
+ struct fat_boot_fsinfo *fsinfo;
+
+ /* The fat32 boot fs info is at offset 0x3e0 by observation */
+ offset = MSDOS_SB(sb)->fsinfo_offset;
+ bh = fat_bread(sb, (offset >> SECTOR_BITS));
+ if (bh == NULL) {
+ printk("FAT bread failed in fat_clusters_flush\n");
+ return;
+ }
+ fsinfo = (struct fat_boot_fsinfo *)
+ &bh->b_data[offset & (SECTOR_SIZE-1)];
+
+ /* Sanity check */
+ if (CF_LE_L(fsinfo->signature) != 0x61417272) {
+ printk("fat_clusters_flush: Did not find valid FSINFO signature. Found 0x%x. offset=0x%x\n", CF_LE_L(fsinfo->signature), offset);
+ fat_brelse(sb, bh);
+ return;
+ }
+ fsinfo->free_clusters = CF_LE_L(MSDOS_SB(sb)->free_clusters);
+ fat_mark_buffer_dirty(sb, bh, 1);
+ fat_brelse(sb, bh);
+}
/*
* fat_add_cluster tries to allocate a new cluster and adds it to the file
@@ -119,7 +151,9 @@ int fat_add_cluster(struct inode *inode)
struct buffer_head *bh;
int cluster_size = MSDOS_SB(sb)->cluster_size;
- if (inode->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
+ if (MSDOS_SB(sb)->fat_bits != 32) {
+ if (inode->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
+ }
if (!MSDOS_SB(sb)->free_clusters) return -ENOSPC;
lock_fat(sb);
limit = MSDOS_SB(sb)->clusters;
@@ -141,6 +175,8 @@ printk("free cluster: %d\n",nr);
fat_access(sb,nr,EOF_FAT(sb));
if (MSDOS_SB(sb)->free_clusters != -1)
MSDOS_SB(sb)->free_clusters--;
+ if (MSDOS_SB(sb)->fat_bits == 32)
+ fat_clusters_flush(sb);
unlock_fat(sb);
#ifdef DEBUG
printk("set to %x\n",fat_access(sb,nr,-1));
@@ -177,6 +213,7 @@ printk("last = %d\n",last);
if (last) fat_access(sb,last,nr);
else {
MSDOS_I(inode)->i_start = nr;
+ MSDOS_I(inode)->i_logstart = nr;
mark_inode_dirty(inode);
}
#ifdef DEBUG
@@ -260,6 +297,8 @@ void fat_date_unix2dos(int unix_date,unsigned short *time,
unix_date += 3600;
}
unix_date -= sys_tz.tz_minuteswest*60;
+ if (sys_tz.tz_dsttime) unix_date += 3600;
+
*time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
(((unix_date/3600) % 24) << 11);
day = unix_date/86400-3652;
@@ -302,7 +341,7 @@ int fat_get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh,
fat_brelse(sb, *bh);
PRINTK (("get_entry sector apres brelse\n"));
if (!(*bh = fat_bread(sb, sector))) {
- printk("Directory sread (sector %d) failed\n",sector);
+ printk("Directory sread (sector 0x%x) failed\n",sector);
continue;
}
PRINTK (("get_entry apres sread\n"));
@@ -344,7 +383,13 @@ int fat_get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh,
!(data[entry].attr & ATTR_VOLUME);
#define RSS_START /* search for start cluster */ \
- done = !IS_FREE(data[entry].name) && CF_LE_W(data[entry].start) == *number;
+ done = !IS_FREE(data[entry].name) \
+ && ( \
+ ( \
+ (MSDOS_SB(sb)->fat_bits != 32) ? 0 : (CF_LE_W(data[entry].starthi) << 16) \
+ ) \
+ | CF_LE_W(data[entry].start) \
+ ) == *number;
#define RSS_FREE /* search for free entry */ \
{ \
@@ -397,6 +442,9 @@ static int raw_scan_sector(struct super_block *sb,int sector,const char *name,
if (done) {
if (ino) *ino = sector*MSDOS_DPS+entry;
start = CF_LE_W(data[entry].start);
+ if (MSDOS_SB(sb)->fat_bits == 32) {
+ start |= (CF_LE_W(data[entry].starthi) << 16);
+ }
if (!res_bh)
fat_brelse(sb, bh);
else {
@@ -492,6 +540,7 @@ int fat_parent_ino(struct inode *dir,int locked)
static int zero = 0;
int error,curr,prev,nr;
+ PRINTK(("fat_parent_ino: Debug 0\n"));
if (!S_ISDIR(dir->i_mode)) panic("Non-directory fed to m_p_i");
if (dir->i_ino == MSDOS_ROOT_INO) return dir->i_ino;
if (!locked) fat_lock_creation(); /* prevent renames */
@@ -500,18 +549,27 @@ int fat_parent_ino(struct inode *dir,int locked)
if (!locked) fat_unlock_creation();
return curr;
}
+ PRINTK(("fat_parent_ino: Debug 1 curr=%d\n", curr));
if (!curr) nr = MSDOS_ROOT_INO;
else {
+ PRINTK(("fat_parent_ino: Debug 2\n"));
if ((prev = raw_scan(dir->i_sb,curr,MSDOS_DOTDOT,&zero,NULL,
NULL,NULL,SCAN_ANY)) < 0) {
+ PRINTK(("fat_parent_ino: Debug 3 prev=%d\n", prev));
if (!locked) fat_unlock_creation();
return prev;
}
+ PRINTK(("fat_parent_ino: Debug 4 prev=%d\n", prev));
+ if (prev == 0 && MSDOS_SB(dir->i_sb)->fat_bits == 32) {
+ prev = MSDOS_SB(dir->i_sb)->root_cluster;
+ }
if ((error = raw_scan(dir->i_sb,prev,NULL,&curr,&nr,NULL,
NULL,SCAN_ANY)) < 0) {
+ PRINTK(("fat_parent_ino: Debug 5 error=%d\n", error));
if (!locked) fat_unlock_creation();
return error;
}
+ PRINTK(("fat_parent_ino: Debug 6 nr=%d\n", nr));
}
if (!locked) fat_unlock_creation();
return nr;
@@ -528,10 +586,12 @@ int fat_subdirs(struct inode *dir)
int count;
count = 0;
- if (dir->i_ino == MSDOS_ROOT_INO)
+ if ((dir->i_ino == MSDOS_ROOT_INO) &&
+ (MSDOS_SB(dir->i_sb)->fat_bits != 32)) {
(void) raw_scan_root(dir->i_sb,NULL,&count,NULL,NULL,NULL,SCAN_ANY);
- else {
- if (!MSDOS_I(dir)->i_start) return 0; /* in mkdir */
+ } else {
+ if ((dir->i_ino != MSDOS_ROOT_INO) &&
+ !MSDOS_I(dir)->i_start) return 0; /* in mkdir */
else (void) raw_scan_nonroot(dir->i_sb,MSDOS_I(dir)->i_start,
NULL,&count,NULL,NULL,NULL,SCAN_ANY);
}
@@ -549,10 +609,7 @@ int fat_scan(struct inode *dir,const char *name,struct buffer_head **res_bh,
{
int res;
- res = (name)
- ? raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,
- name, NULL, ino, res_bh, res_de, scantype)
- : raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,
- NULL, NULL, ino, res_bh, res_de, scantype);
+ res = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,
+ name, NULL, ino, res_bh, res_de, scantype);
return res<0 ? res : 0;
}
diff --git a/fs/fat/mmap.c b/fs/fat/mmap.c
index fd66e51d1..545874a04 100644
--- a/fs/fat/mmap.c
+++ b/fs/fat/mmap.c
@@ -7,6 +7,9 @@
* mmap handling for fat-based filesystems
*/
+#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S))
+#include <linux/version.h>
+
#include <linux/stat.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -59,8 +62,8 @@ static unsigned long fat_file_mmap_nopage(
{
unsigned long cur_fs = get_fs();
set_fs (KERNEL_DS);
- cur_read = fat_file_read (inode,&filp,(char*)page
- ,need_read);
+ cur_read = fat_file_read (&filp, (char*)page,
+ need_read, &filp.f_pos);
set_fs (cur_fs);
}
if (cur_read != need_read){
diff --git a/fs/fat/tables.c b/fs/fat/tables.c
index 3e8379374..c4ad91c3c 100644
--- a/fs/fat/tables.c
+++ b/fs/fat/tables.c
@@ -1,7 +1,7 @@
/*
* linux/fs/fat/tables.c
*
- * ASCII / Unicode translation tables for VFAT filename handling.
+ * Unicode escape translation tables for VFAT filename handling.
* By Gordon Chaffee.
*
* Note: This file is used by all fat-based filesystems.
@@ -9,10 +9,9 @@
#include <linux/kernel.h>
#include <linux/string.h>
+#include <linux/msdos_fs.h>
-#include "tables.h"
-
-unsigned char fat_uni2code[64] = {
+unsigned char fat_uni2esc[64] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
@@ -23,7 +22,7 @@ unsigned char fat_uni2code[64] = {
'u', 'v', 'w', 'x', 'y', 'z', '+', '-'
};
-unsigned char fat_code2uni[256] = {
+unsigned char fat_esc2uni[256] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
@@ -58,209 +57,6 @@ unsigned char fat_code2uni[256] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
-static unsigned char page00[256] = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 0x08-0x0F */
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
- 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, /* 0x18-0x1F */
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
- 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, /* 0x28-0x2F */
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
- 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, /* 0x38-0x3F */
- 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
- 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, /* 0x48-0x4F */
- 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
- 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, /* 0x58-0x5F */
- 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
- 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, /* 0x68-0x6F */
- 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
- 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, /* 0x78-0x7F */
-
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8F */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, /* 0x98-0x9F */
- 0xFF, 0xAD, 0xBD, 0x9C, 0xCF, 0xBE, 0xDD, 0xF5, /* 0xA0-0xA7 */
- 0xF9, 0xB8, 0x00, 0xAE, 0xAA, 0xF0, 0x00, 0xEE, /* 0xA8-0xAF */
- 0xF8, 0xF1, 0xFD, 0xFC, 0xEF, 0xE6, 0xF4, 0xFA, /* 0xB0-0xB7 */
- 0xF7, 0xFB, 0x00, 0xAF, 0xAC, 0xAB, 0xF3, 0x00, /* 0xB8-0xBF */
- 0xB7, 0xB5, 0xB6, 0xC7, 0x8E, 0x8F, 0x92, 0x80, /* 0xC0-0xC7 */
- 0xD4, 0x90, 0xD2, 0xD3, 0xDE, 0xD6, 0xD7, 0xD8, /* 0xC8-0xCF */
- 0x00, 0xA5, 0xE3, 0xE0, 0xE2, 0xE5, 0x99, 0x9E, /* 0xD0-0xD7 */
- 0x9D, 0xEB, 0xE9, 0xEA, 0x9A, 0xED, 0xE8, 0xE1, /* 0xD8-0xDF */
- 0xA1, 0xA0, 0x83, 0xC6, 0x84, 0x86, 0x91, 0x87, /* 0xE0-0xE7 */
- 0x8A, 0x82, 0x88, 0x89, 0x8D, 0x00, 0x8C, 0x8B, /* 0xE8-0xEF */
- 0xD0, 0xA4, 0x95, 0xA2, 0x93, 0xE4, 0x94, 0xF6, /* 0xF0-0xF7 */
- 0x9B, 0x97, 0xA3, 0x96, 0x81, 0xEC, 0xE7, 0x98 /* 0xF8-0xFF */
-};
-
-
-static unsigned char page25[256] = {
- 0xC4, 0x00, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
- 0x00, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x00, 0x00, /* 0x08-0x0F */
- 0xBF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
- 0xD9, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, /* 0x18-0x1F */
- 0x00, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
- 0x00, 0x00, 0x00, 0x00, 0xC2, 0x00, 0x00, 0x00, /* 0x28-0x2F */
- 0x00, 0x00, 0x00, 0x00, 0xC1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
- 0x00, 0x00, 0x00, 0x00, 0xC5, 0x00, 0x00, 0x00, /* 0x38-0x3F */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4F */
- 0xCD, 0xBA, 0x00, 0x00, 0xC9, 0x00, 0x00, 0xBB, /* 0x50-0x57 */
- 0x00, 0x00, 0xC8, 0x00, 0x00, 0xBC, 0x00, 0x00, /* 0x58-0x5F */
- 0xCC, 0x00, 0x00, 0xB9, 0x00, 0x00, 0xCB, 0x00, /* 0x60-0x67 */
- 0x00, 0xCA, 0x00, 0x00, 0xCE, 0x00, 0x00, 0x00, /* 0x68-0x6F */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7F */
-
- 0xDF, 0x00, 0x00, 0x00, 0xDC, 0x00, 0x00, 0x00, /* 0x80-0x87 */
- 0xDB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8F */
- 0x00, 0xB0, 0xB1, 0xB2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9F */
- 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA7 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAF */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB7 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBF */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC7 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCF */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD7 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDF */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE7 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEF */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF7 */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* 0xF8-0xFF */
-};
-
-
-unsigned char *fat_uni2asc_pg[256] = {
- page00, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, page25
-};
-
-/* Conversion from ASCII name characters to the shortname character
- * should probably just just use XXX
- */
-unsigned char fat_a2alias[256] =
-{
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* 0x08-0x0F */
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
- 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, /* 0x18-0x1F */
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
- 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, /* 0x28-0x2F */
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
- 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, /* 0x38-0x3F */
- 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
- 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, /* 0x48-0x4F */
- 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
- 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, /* 0x58-0x5F */
- 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
- 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, /* 0x68-0x6F */
- 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
- 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, /* 0x78-0x7F */
-
- 0x80, 0x9A, 0x90, 0xB6, 0x8E, 0xB7, 0x8F, 0x80, /* 0x80-0x87 */
- 0xD2, 0xD3, 0xD4, 0xD8, 0xD7, 0xDE, 0x8E, 0x8F, /* 0x88-0x8F */
- 0x90, 0x92, 0x92, 0xE2, 0x99, 0xE3, 0xEA, 0xEB, /* 0x90-0x97 */
-/*_~1*/ 0x98, 0x99, 0x9A, 0x9D, 0x9C, 0x9D, 0x9E, 0x9F, /* 0x98-0x9F */
- 0xB5, 0xD6, 0xE0, 0xE9, 0xA5, 0xA5, 0xA6, 0xA7, /* 0xA0-0xA7 */
- 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, /* 0xA8-0xAF */
- 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, /* 0xB0-0xB7 */
- 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, /* 0xB8-0xBF */
- 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, /* 0xC0-0xC7 */
- 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, /* 0xC8-0xCF */
- 0xD1, 0xD1, 0xD2, 0xD3, 0xD4, 0x49, 0xD6, 0xD7, /* 0xD0-0xD7 */
- 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, /* 0xD8-0xDF */
- 0xE0, 0xE1, 0xE2, 0xE3, 0x05, 0x05, 0xE6, 0xE8, /* 0xE0-0xE7 */
- 0xE8, 0xE9, 0xEA, 0xEB, 0xED, 0xED, 0xEE, 0xEF, /* 0xE8-0xEF */
- 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, /* 0xF0-0xF7 */
- 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF /* 0xF8-0xFF */
-};
-
-struct unicode_value fat_a2uni[256] = {
-/* 0x00 */
-{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
-{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
-{0x08, 0x00}, {0x09, 0x00}, {0x0A, 0x00}, {0x0B, 0x00},
-{0x0C, 0x00}, {0x0D, 0x00}, {0x0E, 0x00}, {0x0F, 0x00},
-/* 0x10 */
-{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
-{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
-{0x18, 0x00}, {0x19, 0x00}, {0x1A, 0x00}, {0x1B, 0x00},
-{0x1C, 0x00}, {0x1D, 0x00}, {0x1E, 0x00}, {0x1F, 0x00},
-/* 0x20 */
-{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
-{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
-{0x28, 0x00}, {0x29, 0x00}, {0x2A, 0x00}, {0x2B, 0x00},
-{0x2C, 0x00}, {0x2D, 0x00}, {0x2E, 0x00}, {0x2F, 0x00},
-/* 0x30 */
-{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
-{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
-{0x38, 0x00}, {0x39, 0x00}, {0x3A, 0x00}, {0x3B, 0x00},
-{0x3C, 0x00}, {0x3D, 0x00}, {0x3E, 0x00}, {0x3F, 0x00},
-/* 0x40 */
-{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
-{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
-{0x48, 0x00}, {0x49, 0x00}, {0x4A, 0x00}, {0x4B, 0x00},
-{0x4C, 0x00}, {0x4D, 0x00}, {0x4E, 0x00}, {0x4F, 0x00},
-/* 0x50 */
-{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
-{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
-{0x58, 0x00}, {0x59, 0x00}, {0x5A, 0x00}, {0x5B, 0x00},
-{0x5C, 0x00}, {0x5D, 0x00}, {0x5E, 0x00}, {0x5F, 0x00},
-/* 0x60 */
-{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
-{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
-{0x68, 0x00}, {0x69, 0x00}, {0x6A, 0x00}, {0x6B, 0x00},
-{0x6C, 0x00}, {0x6D, 0x00}, {0x6E, 0x00}, {0x6F, 0x00},
-/* 0x70 */
-{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
-{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
-{0x78, 0x00}, {0x79, 0x00}, {0x7A, 0x00}, {0x7B, 0x00},
-{0x7C, 0x00}, {0x7D, 0x00}, {0x7E, 0x00}, {0x7F, 0x00},
-/* 0x80 */
-{0xC7, 0x00}, {0xFC, 0x00}, {0xE9, 0x00}, {0xE2, 0x00},
-{0xE4, 0x00}, {0xE0, 0x00}, {0xE5, 0x00}, {0xE7, 0x00},
-{0xEA, 0x00}, {0xEB, 0x00}, {0xE8, 0x00}, {0xEF, 0x00},
-{0xEE, 0x00}, {0xEC, 0x00}, {0xC4, 0x00}, {0xC5, 0x00},
-/* 0x90 */
-{0xC9, 0x00}, {0xE6, 0x00}, {0xC6, 0x00}, {0xF4, 0x00},
-{0xF6, 0x00}, {0xF2, 0x00}, {0xFB, 0x00}, {0xF9, 0x00},
-{0xFF, 0x00}, {0xD6, 0x00}, {0xDC, 0x00}, {0xF8, 0x00},
-{0xA3, 0x00}, {0xD8, 0x00}, {0xD7, 0x00}, {0x92, 0x00},
-/* 0xA0 */
-{0xE1, 0x00}, {0xE0, 0x00}, {0xF3, 0x00}, {0xFA, 0x00},
-{0xF1, 0x00}, {0xD1, 0x00}, {0xAA, 0x00}, {0xBA, 0x00},
-{0xBF, 0x00}, {0xAE, 0x00}, {0xAC, 0x00}, {0xBD, 0x00},
-{0xBC, 0x00}, {0xA1, 0x00}, {0xAB, 0x00}, {0xBB, 0x00},
-/* 0xB0 */
-{0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
-{0x24, 0x25}, {0xC1, 0x00}, {0xC2, 0x00}, {0xC0, 0x00},
-{0xA9, 0x00}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
-{0x5D, 0x25}, {0xA2, 0x00}, {0xA5, 0x00}, {0x10, 0x25},
-/* 0xC0 */
-{0x14, 0x25}, {0x34, 0x25}, {0x2C, 0x25}, {0x1C, 0x25},
-{0x00, 0x25}, {0x3C, 0x25}, {0xE3, 0x00}, {0xC3, 0x00},
-{0x5A, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
-{0x60, 0x25}, {0x50, 0x25}, {0x6C, 0x25}, {0xA4, 0x00},
-/* 0xD0 */
-{0xF0, 0x00}, {0xD0, 0x00}, {0xCA, 0x00}, {0xCB, 0x00},
-{0xC8, 0x00}, {0x31, 0x01}, {0xCD, 0x00}, {0xCE, 0x00},
-{0xCF, 0x00}, {0x18, 0x25}, {0x0C, 0x25}, {0x88, 0x25},
-{0x84, 0x25}, {0xA6, 0x00}, {0xCC, 0x00}, {0x80, 0x25},
-/* 0xE0 */
-{0xD3, 0x00}, {0xDF, 0x00}, {0xD4, 0x00}, {0xD2, 0x00},
-{0xF5, 0x00}, {0xD5, 0x00}, {0xB5, 0x00}, {0xFE, 0x00},
-{0xDE, 0x00}, {0xDA, 0x00}, {0xDB, 0x00}, {0xD9, 0x00},
-{0xFD, 0x00}, {0xDD, 0x00}, {0xAF, 0x00}, {0xB4, 0x00},
-/* 0xF0 */
-{0xAD, 0x00}, {0xB1, 0x00}, {0x17, 0x20}, {0xBE, 0x00},
-{0xB6, 0x00}, {0xA7, 0x00}, {0xF7, 0x00}, {0xB8, 0x00},
-{0xB0, 0x00}, {0xA8, 0x00}, {0xB7, 0x00}, {0xB9, 0x00},
-{0xB3, 0x00}, {0xB2, 0x00}, {0xA0, 0x25}, {0xA0, 0x00}};
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/fs/fcntl.c b/fs/fcntl.c
index ce00e439f..99561051d 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -179,7 +179,7 @@ static void send_sigio(int pid, uid_t uid, uid_t euid)
(uid ^ p->suid) && (uid ^ p->uid))
continue;
p->signal |= 1 << (SIGIO-1);
- if (p->state == TASK_INTERRUPTIBLE && (p->signal & ~p->blocked))
+ if (p->state == TASK_INTERRUPTIBLE && signal_pending(p))
wake_up_process(p);
}
read_unlock(&tasklist_lock);
diff --git a/fs/fifo.c b/fs/fifo.c
index d2eb7a80e..76fb7a530 100644
--- a/fs/fifo.c
+++ b/fs/fifo.c
@@ -29,7 +29,7 @@ static int fifo_open(struct inode * inode,struct file * filp)
if (!(filp->f_flags & O_NONBLOCK) && !PIPE_WRITERS(*inode)) {
PIPE_RD_OPENERS(*inode)++;
while (!PIPE_WRITERS(*inode)) {
- if (current->signal & ~current->blocked) {
+ if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
}
@@ -62,7 +62,7 @@ static int fifo_open(struct inode * inode,struct file * filp)
if (!PIPE_READERS(*inode)) {
PIPE_WR_OPENERS(*inode)++;
while (!PIPE_READERS(*inode)) {
- if (current->signal & ~current->blocked) {
+ if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
}
diff --git a/fs/file_table.c b/fs/file_table.c
index 42f9255d2..1dc6bf3fd 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -18,8 +18,9 @@
static kmem_cache_t *filp_cache;
/* sysctl tunables... */
-int nr_files = 0;
-int max_files = NR_FILE;
+int nr_files = 0; /* read only */
+int nr_free_files = 0; /* read only */
+int max_files = NR_FILE;/* tunable */
/* Free list management, if you are here you must have f_count == 0 */
static struct file * free_filps = NULL;
@@ -30,6 +31,7 @@ void insert_file_free(struct file *file)
free_filps->f_pprev = &file->f_next;
free_filps = file;
file->f_pprev = &free_filps;
+ nr_free_files++;
}
/* The list of in-use filp's must be exported (ugh...) */
@@ -43,6 +45,7 @@ static inline void put_inuse(struct file *file)
file->f_pprev = &inuse_filps;
}
+/* N.B. This should be an __initfunc ... */
void file_table_init(void)
{
filp_cache = kmem_cache_create("filp", sizeof(struct file),
@@ -50,6 +53,11 @@ void file_table_init(void)
SLAB_HWCACHE_ALIGN, NULL, NULL);
if(!filp_cache)
panic("VFS: Cannot alloc filp SLAB cache.");
+ /*
+ * We could allocate the reserved files here, but really
+ * shouldn't need to: the normal boot process will create
+ * plenty of free files.
+ */
}
/* Find an unused file structure and return a pointer to it.
@@ -61,24 +69,31 @@ struct file * get_empty_filp(void)
static int old_max = 0;
struct file * f;
- f = free_filps;
- if (!f)
- goto get_more;
- remove_filp(f);
-got_one:
- memset(f, 0, sizeof(*f));
- f->f_count = 1;
- f->f_version = ++event;
- put_inuse(f);
- return f;
-
-get_more:
- /* Reserve a few files for the super-user.. */
- if (nr_files < (current->euid ? max_files - 10 : max_files)) {
+ if (nr_free_files > NR_RESERVED_FILES) {
+ used_one:
+ f = free_filps;
+ remove_filp(f);
+ nr_free_files--;
+ new_one:
+ memset(f, 0, sizeof(*f));
+ f->f_count = 1;
+ f->f_version = ++event;
+ put_inuse(f);
+ return f;
+ }
+ /*
+ * Use a reserved one if we're the superuser
+ */
+ if (nr_free_files && !current->euid)
+ goto used_one;
+ /*
+ * Allocate a new one if we're below the limit.
+ */
+ if (nr_files < max_files) {
f = kmem_cache_alloc(filp_cache, SLAB_KERNEL);
if (f) {
nr_files++;
- goto got_one;
+ goto new_one;
}
/* Big problems... */
printk("VFS: filp allocation failed\n");
diff --git a/fs/filesystems.c b/fs/filesystems.c
index 348ad7bb7..7e9c5bf3f 100644
--- a/fs/filesystems.c
+++ b/fs/filesystems.c
@@ -34,6 +34,7 @@
#include <linux/lockd/bind.h>
#include <linux/lockd/xdr.h>
#include <linux/init.h>
+#include <linux/nls.h>
extern void device_setup(void);
extern void binfmt_setup(void);
@@ -121,6 +122,10 @@ __initfunc(static void do_sys_setup(void))
init_efs_fs();
#endif
+#ifdef CONFIG_NLS
+ init_nls();
+#endif
+
mount_root();
}
diff --git a/fs/hpfs/hpfs_fs.c b/fs/hpfs/hpfs_fs.c
index 1d9117337..667492fcd 100644
--- a/fs/hpfs/hpfs_fs.c
+++ b/fs/hpfs/hpfs_fs.c
@@ -146,7 +146,7 @@ static const struct super_operations hpfs_sops =
/* file ops */
-static long hpfs_file_read(struct inode *, struct file *, char *, unsigned long);
+static ssize_t hpfs_file_read(struct file *, char *, size_t, loff_t *);
static secno hpfs_bmap(struct inode *, unsigned);
static const struct file_operations hpfs_file_ops =
@@ -187,8 +187,8 @@ static const struct inode_operations hpfs_file_iops =
/* directory ops */
-static long hpfs_dir_read(struct inode *inode, struct file *filp,
- char *buf, unsigned long count);
+static ssize_t hpfs_dir_read(struct file *filp, char *buf,
+ size_t count, loff_t *ppos);
static int hpfs_readdir(struct file *filp,
void *dirent, filldir_t filldir);
static int hpfs_lookup(struct inode *, struct dentry *);
@@ -881,10 +881,11 @@ static unsigned count_one_bitmap(kdev_t dev, secno secno)
* read. Read the bytes, put them in buf, return the count.
*/
-static long hpfs_file_read(struct inode *inode, struct file *filp,
- char *buf, unsigned long count)
+static ssize_t hpfs_file_read(struct file *filp, char *buf,
+ size_t count, loff_t *ppos)
{
- unsigned q, r, n, n0;
+ struct inode *inode = filp->f_dentry->d_inode;
+ size_t q, r, n, n0;
struct buffer_head *bh;
char *block;
char *start;
@@ -895,8 +896,8 @@ static long hpfs_file_read(struct inode *inode, struct file *filp,
/*
* truncate count at EOF
*/
- if (count > inode->i_size - (off_t) filp->f_pos)
- count = inode->i_size - filp->f_pos;
+ if (count > inode->i_size - (off_t) *ppos)
+ count = inode->i_size - *ppos;
start = buf;
while (count > 0) {
@@ -904,8 +905,8 @@ static long hpfs_file_read(struct inode *inode, struct file *filp,
* get file sector number, offset in sector, length to end of
* sector
*/
- q = filp->f_pos >> 9;
- r = filp->f_pos & 511;
+ q = *ppos >> 9;
+ r = *ppos & 511;
n = 512 - r;
/*
@@ -941,8 +942,8 @@ static long hpfs_file_read(struct inode *inode, struct file *filp,
* squeeze out \r, output length varies
*/
n0 = convcpy_tofs(buf, block + r, n);
- if (count > inode->i_size - (off_t) filp->f_pos - n + n0)
- count = inode->i_size - filp->f_pos - n + n0;
+ if (count > inode->i_size - (off_t) *ppos - n + n0)
+ count = inode->i_size - *ppos - n + n0;
}
brelse(bh);
@@ -950,7 +951,7 @@ static long hpfs_file_read(struct inode *inode, struct file *filp,
/*
* advance input n bytes, output n0 bytes
*/
- filp->f_pos += n;
+ *ppos += n;
buf += n0;
count -= n0;
}
@@ -1121,20 +1122,21 @@ static secno bplus_lookup(struct inode *inode, struct bplus_header *b,
static int hpfs_lookup(struct inode *dir, struct dentry *dentry)
{
- struct quad_buffer_head qbh;
+ const char *name = dentry->d_name.name;
+ int len = dentry->d_name.len;
struct hpfs_dirent *de;
struct inode *inode;
ino_t ino;
- const char *name = dentry->d_name.name;
- int len = dentry->d_name.len;
int retval;
+ struct quad_buffer_head qbh;
/* In case of madness */
+ retval = -ENOTDIR;
if (dir == 0)
- return -ENOENT;
+ goto out;
if (!S_ISDIR(dir->i_mode))
- return -ENOENT;
+ goto out;
/*
* Read in the directory entry. "." is there under the name ^A^A .
@@ -1154,9 +1156,11 @@ static int hpfs_lookup(struct inode *dir, struct dentry *dentry)
* This is not really a bailout, just means file not found.
*/
- inode = NULL;
- if (!de)
- goto add_dentry;
+ if (!de) {
+ d_add(dentry, NULL);
+ retval = 0;
+ goto out;
+ }
/*
* Get inode number, what we're after.
@@ -1198,15 +1202,13 @@ static int hpfs_lookup(struct inode *dir, struct dentry *dentry)
}
}
- /*
- * Add the dentry, negative or otherwise.
- */
- add_dentry:
d_add(dentry, inode);
retval = 0;
free4:
brelse4(&qbh);
+
+ out:
return retval;
}
@@ -1578,8 +1580,8 @@ static struct hpfs_dirent *map_nth_dirent(kdev_t dev, dnode_secno dno,
return 0;
}
-static long hpfs_dir_read(struct inode *inode, struct file *filp,
- char *buf, unsigned long count)
+static ssize_t hpfs_dir_read(struct file *filp, char *buf,
+ size_t count, loff_t *ppos)
{
return -EISDIR;
}
diff --git a/fs/inode.c b/fs/inode.c
index 6a8423c39..88dd09ad7 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -7,6 +7,7 @@
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/mm.h>
+#include <linux/dcache.h>
/*
* New inode.c implementation.
@@ -18,6 +19,9 @@
* Famous last words.
*/
+#define INODE_PARANOIA 1
+/* #define INODE_DEBUG 1 */
+
/*
* Inode lookup is no longer as critical as it used to be:
* most of the lookups are going to be through the dcache.
@@ -51,13 +55,14 @@ static struct list_head inode_hashtable[HASH_SIZE];
spinlock_t inode_lock = SPIN_LOCK_UNLOCKED;
/*
- * Statistics gathering.. Not actually done yet.
+ * Statistics gathering..
*/
struct {
int nr_inodes;
int nr_free_inodes;
- int dummy[10];
-} inodes_stat;
+ int preshrink; /* pre-shrink dcache? */
+ int dummy[4];
+} inodes_stat = {0, 0, 0,};
int max_inodes = NR_INODE;
@@ -138,8 +143,11 @@ static inline void sync_one(struct inode *inode)
__wait_on_inode(inode);
spin_lock(&inode_lock);
} else {
+ struct list_head *insert = &inode_in_use;
+ if (!inode->i_count)
+ insert = inode_in_use.prev;
list_del(&inode->i_list);
- list_add(&inode->i_list, &inode_in_use);
+ list_add(&inode->i_list, insert);
/* Set I_LOCK, reset I_DIRTY */
inode->i_state ^= I_DIRTY | I_LOCK;
@@ -196,7 +204,7 @@ void write_inode_now(struct inode *inode)
if (sb) {
spin_lock(&inode_lock);
- if (inode->i_state & I_DIRTY)
+ while (inode->i_state & I_DIRTY)
sync_one(inode);
spin_unlock(&inode_lock);
}
@@ -307,6 +315,9 @@ int invalidate_inodes(struct super_block * sb)
* the in-use for the specified number of freeable inodes.
* Freeable inodes are moved to a temporary list and then
* placed on the unused list by dispose_list.
+ *
+ * Note that we do not expect to have to search very hard:
+ * the freeable inodes will be at the old end of the list.
*
* N.B. The spinlock is released to call dispose_list.
*/
@@ -314,18 +325,15 @@ int invalidate_inodes(struct super_block * sb)
(((inode)->i_count == 0) && \
(!(inode)->i_state))
-static void try_to_free_inodes(int goal)
+static int free_inodes(int goal)
{
- struct list_head * tmp;
- struct list_head *head = &inode_in_use;
+ struct list_head *tmp, *head = &inode_in_use;
LIST_HEAD(freeable);
- int found = 0, search = goal << 1;
-
- while ((tmp = head->prev) != head && search--) {
- struct inode * inode;
+ int found = 0, depth = goal << 1;
+ while ((tmp = head->prev) != head && depth--) {
+ struct inode * inode = list_entry(tmp, struct inode, i_list);
list_del(tmp);
- inode = list_entry(tmp, struct inode, i_list);
if (CAN_UNUSE(inode)) {
list_del(&inode->i_hash);
INIT_LIST_HEAD(&inode->i_hash);
@@ -336,18 +344,58 @@ static void try_to_free_inodes(int goal)
}
list_add(tmp, head);
}
+ if (found) {
+ spin_unlock(&inode_lock);
+ dispose_list(&freeable);
+ spin_lock(&inode_lock);
+ }
+ return found;
+}
+
+/*
+ * Searches the inodes list for freeable inodes,
+ * possibly shrinking the dcache before or after.
+ */
+static void try_to_free_inodes(int goal)
+{
+ int retry = 1, found;
+
/*
- * If we didn't free any inodes, do a limited
- * pruning of the dcache to help the next time.
+ * Check whether to preshrink the dcache ...
*/
- spin_unlock(&inode_lock);
- if (found)
- dispose_list(&freeable);
- else
- prune_dcache(goal);
+ if (inodes_stat.preshrink)
+ goto preshrink;
+
+ retry = 0;
+ do {
+ if (free_inodes(goal))
+ break;
+ /*
+ * If we didn't free any inodes, do a limited
+ * pruning of the dcache to help the next time.
+ */
+ preshrink:
+ spin_unlock(&inode_lock);
+ found = select_dcache(goal, 0);
+ if (found < goal)
+ found = goal;
+ prune_dcache(found);
+ spin_lock(&inode_lock);
+ } while (retry--);
+}
+
+/*
+ * This is the externally visible routine for
+ * inode memory management.
+ */
+void free_inode_memory(int goal)
+{
spin_lock(&inode_lock);
+ free_inodes(goal);
+ spin_unlock(&inode_lock);
}
+#define INODES_PER_PAGE PAGE_SIZE/sizeof(struct inode)
/*
* This is called with the spinlock held, but releases
* the lock when freeing or allocating inodes.
@@ -358,27 +406,6 @@ static struct inode * grow_inodes(void)
{
struct inode * inode;
- /*
- * Check whether to shrink the dcache ... if we've
- * allocated more than half of the nominal maximum,
- * try shrinking before allocating more.
- */
- if (inodes_stat.nr_inodes >= (max_inodes >> 1)) {
- struct list_head * tmp;
-
- spin_unlock(&inode_lock);
- prune_dcache(128);
- spin_lock(&inode_lock);
- try_to_free_inodes(128);
- tmp = inode_unused.next;
- if (tmp != &inode_unused) {
- inodes_stat.nr_free_inodes--;
- list_del(tmp);
- inode = list_entry(tmp, struct inode, i_list);
- return inode;
- }
- }
-
spin_unlock(&inode_lock);
inode = (struct inode *)__get_free_page(GFP_KERNEL);
if (inode) {
@@ -392,13 +419,42 @@ static struct inode * grow_inodes(void)
tmp++;
init_once(tmp);
list_add(&tmp->i_list, &inode_unused);
- inodes_stat.nr_free_inodes++;
size -= sizeof(struct inode);
} while (size >= 0);
init_once(inode);
- inodes_stat.nr_inodes += PAGE_SIZE / sizeof(struct inode);
+ /*
+ * Update the inode statistics
+ */
+ inodes_stat.nr_inodes += INODES_PER_PAGE;
+ inodes_stat.nr_free_inodes += INODES_PER_PAGE - 1;
+ inodes_stat.preshrink = 0;
+ if (inodes_stat.nr_inodes > max_inodes)
+ inodes_stat.preshrink = 1;
+ return inode;
}
- return inode;
+
+ /*
+ * If the allocation failed, do an extensive pruning of
+ * the dcache and then try again to free some inodes.
+ */
+ prune_dcache(inodes_stat.nr_inodes >> 2);
+ inodes_stat.preshrink = 1;
+
+ spin_lock(&inode_lock);
+ free_inodes(inodes_stat.nr_inodes >> 2);
+ {
+ struct list_head *tmp = inode_unused.next;
+ if (tmp != &inode_unused) {
+ inodes_stat.nr_free_inodes--;
+ list_del(tmp);
+ inode = list_entry(tmp, struct inode, i_list);
+ return inode;
+ }
+ }
+ spin_unlock(&inode_lock);
+
+ printk("grow_inodes: allocation failed\n");
+ return NULL;
}
/*
@@ -627,6 +683,18 @@ void iput(struct inode *inode)
list_add(&inode->i_list, &inode_unused);
inodes_stat.nr_free_inodes++;
}
+ else if (!(inode->i_state & I_DIRTY)) {
+ list_del(&inode->i_list);
+ list_add(&inode->i_list, inode_in_use.prev);
+ }
+#ifdef INODE_PARANOIA
+if (inode->i_count)
+printk("iput: device %s inode %ld count changed, count=%d\n",
+kdevname(inode->i_dev), inode->i_ino, inode->i_count);
+if (atomic_read(&inode->i_sem.count) != 1)
+printk("iput: Aieee, semaphore in use device %s, count=%d\n",
+kdevname(inode->i_dev), atomic_read(&inode->i_sem.count));
+#endif
}
if (inode->i_count > (1<<15)) {
printk("iput: device %s inode %ld count wrapped\n",
diff --git a/fs/isofs/Makefile b/fs/isofs/Makefile
index 8dd4cc9ec..10a4404f8 100644
--- a/fs/isofs/Makefile
+++ b/fs/isofs/Makefile
@@ -9,6 +9,11 @@
O_TARGET := isofs.o
O_OBJS := namei.o inode.o file.o dir.o util.o rock.o symlink.o
+
+ifdef CONFIG_JOLIET
+O_OBJS += joliet.o
+endif
+
M_OBJS := $(O_TARGET)
include $(TOPDIR)/Rules.make
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
index a198141d8..67ff77bd9 100644
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -20,6 +20,7 @@
#include <linux/malloc.h>
#include <linux/sched.h>
#include <linux/locks.h>
+#include <linux/config.h>
#include <asm/uaccess.h>
@@ -102,15 +103,14 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
unsigned int block, offset;
int inode_number;
struct buffer_head *bh;
- int len, rrflag;
+ int len;
+ int map;
int high_sierra = 0;
- char *name;
+ char *p = NULL; /* Quiet GCC */
struct iso_directory_record *de;
- if( filp->f_pos >= inode->i_size ) {
- return 0;
-
- }
+ if (filp->f_pos >= inode->i_size)
+ return 0;
offset = filp->f_pos & (bufsize - 1);
block = isofs_bmap(inode, filp->f_pos >> bufbits);
@@ -141,15 +141,19 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
CDROM sector. If we are at the end of the directory, we
kick out of the while loop. */
- if ((de_len == 0) || (offset == bufsize) ) {
+ if ((de_len == 0) || (offset >= bufsize) ) {
brelse(bh);
- filp->f_pos = ((filp->f_pos & ~(ISOFS_BLOCK_SIZE - 1))
- + ISOFS_BLOCK_SIZE);
- offset = 0;
- if( filp->f_pos >= inode->i_size )
- {
- return 0;
- }
+ if (de_len == 0) {
+ filp->f_pos = ((filp->f_pos & ~(ISOFS_BLOCK_SIZE - 1))
+ + ISOFS_BLOCK_SIZE);
+ offset = 0;
+ } else {
+ offset -= bufsize;
+ filp->f_pos += offset;
+ }
+
+ if (filp->f_pos >= inode->i_size)
+ return 0;
block = isofs_bmap(inode, (filp->f_pos) >> bufbits);
if (!block)
@@ -181,6 +185,8 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
continue;
}
+ len = 0;
+
/* Handle the case of the '..' directory */
if (de->name_len[0] == 1 && de->name[0] == 1) {
inode_number = filp->f_dentry->d_parent->d_inode->i_ino;
@@ -192,7 +198,6 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
/* Handle everything else. Do name translation if there
is no Rock Ridge NM field. */
-
if (inode->i_sb->u.isofs_sb.s_unhide == 'n') {
/* Do not report hidden or associated files */
high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
@@ -202,34 +207,38 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
}
}
- /* Check Rock Ridge name translation.. */
- len = de->name_len[0];
- name = de->name;
- rrflag = get_rock_ridge_filename(de, &name, &len, inode);
- if (rrflag) {
- /* rrflag == 1 means that we have a new name (kmalloced) */
- if (rrflag == 1) {
- rrflag = filldir(dirent, name, len, filp->f_pos, inode_number);
- kfree(name); /* this was allocated in get_r_r_filename.. */
- if (rrflag < 0)
- break;
+#ifdef CONFIG_JOLIET
+ if (inode->i_sb->u.isofs_sb.s_joliet_level) {
+ len = get_joliet_filename(de, inode, tmpname);
+ p = tmpname;
+ } else
+#endif
+ /* if not joliet */ {
+ map = 1;
+ if (inode->i_sb->u.isofs_sb.s_rock) {
+ len = get_rock_ridge_filename(de, tmpname, inode);
+ if (len != 0) {
+ p = tmpname;
+ map = 0;
+ }
+ }
+ if (map) {
+ if (inode->i_sb->u.isofs_sb.s_mapping == 'n') {
+ len = isofs_name_translate(de->name, de->name_len[0],
+ tmpname);
+ p = tmpname;
+ } else {
+ p = de->name;
+ len = de->name_len[0];
+ }
}
- filp->f_pos += de_len;
- continue;
}
-
- if (inode->i_sb->u.isofs_sb.s_mapping == 'n') {
- len = isofs_name_translate(name, len, tmpname);
- if (filldir(dirent, tmpname, len, filp->f_pos, inode_number) < 0)
+ if (len > 0) {
+ if (filldir(dirent, p, len, filp->f_pos, inode_number) < 0)
break;
- filp->f_pos += de_len;
- continue;
}
-
- if (filldir(dirent, name, len, filp->f_pos, inode_number) < 0)
- break;
-
filp->f_pos += de_len;
+
continue;
}
brelse(bh);
@@ -255,7 +264,7 @@ static int isofs_readdir(struct file *filp,
tmpname = (char *) __get_free_page(GFP_KERNEL);
if (!tmpname)
return -ENOMEM;
- tmpde = (struct iso_directory_record *) (tmpname+256);
+ tmpde = (struct iso_directory_record *) (tmpname+1024);
result = do_isofs_readdir(inode, filp, dirent, filldir, tmpname, tmpde);
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index a925159bf..b77e9facd 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -23,6 +23,7 @@
#include <linux/errno.h>
#include <linux/cdrom.h>
#include <linux/init.h>
+#include <linux/nls.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -40,6 +41,12 @@ static int check_bread = 0;
void isofs_put_super(struct super_block *sb)
{
+#ifdef CONFIG_JOLIET
+ if (sb->u.isofs_sb.s_nls_iocharset) {
+ unload_nls(sb->u.isofs_sb.s_nls_iocharset);
+ sb->u.isofs_sb.s_nls_iocharset = NULL;
+ }
+#endif
lock_super(sb);
#ifdef LEAK_CHECK
@@ -67,6 +74,7 @@ static struct super_operations isofs_sops = {
struct iso9660_options{
char map;
char rock;
+ char joliet;
char cruft;
char unhide;
unsigned char check;
@@ -75,6 +83,8 @@ struct iso9660_options{
mode_t mode;
gid_t gid;
uid_t uid;
+ char *iocharset;
+ unsigned char utf8;
};
static int parse_options(char *options, struct iso9660_options * popt)
@@ -83,6 +93,7 @@ static int parse_options(char *options, struct iso9660_options * popt)
popt->map = 'n';
popt->rock = 'y';
+ popt->joliet = 'y';
popt->cruft = 'n';
popt->unhide = 'n';
popt->check = 's'; /* default: strict */
@@ -94,12 +105,18 @@ static int parse_options(char *options, struct iso9660_options * popt)
a valid executable. */
popt->gid = 0;
popt->uid = 0;
+ popt->iocharset = NULL;
+ popt->utf8 = 0;
if (!options) return 1;
for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
if (strncmp(this_char,"norock",6) == 0) {
popt->rock = 'n';
continue;
}
+ if (strncmp(this_char,"nojoliet",8) == 0) {
+ popt->joliet = 'n';
+ continue;
+ }
if (strncmp(this_char,"unhide",6) == 0) {
popt->unhide = 'y';
continue;
@@ -108,8 +125,31 @@ static int parse_options(char *options, struct iso9660_options * popt)
popt->cruft = 'y';
continue;
}
+ if (strncmp(this_char,"utf8",4) == 0) {
+ popt->utf8 = 1;
+ continue;
+ }
if ((value = strchr(this_char,'=')) != NULL)
*value++ = 0;
+
+#ifdef CONFIG_JOLIET
+ if (!strcmp(this_char,"iocharset")) {
+ char *p;
+ int len;
+
+ p = value;
+ while (*value && *value != ',') value++;
+ len = value - p;
+ if (len) {
+ popt->iocharset = kmalloc(len+1, GFP_KERNEL);
+ memcpy(popt->iocharset, p, len);
+ popt->iocharset[len] = 0;
+ } else {
+ popt->iocharset = NULL;
+ return 0;
+ }
+ } else
+#endif
if (!strcmp(this_char,"map") && value) {
if (value[0] && !value[1] && strchr("on",*value))
popt->map = *value;
@@ -234,10 +274,12 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
struct hs_primary_descriptor * h_pri = NULL;
int high_sierra;
int iso_blknum;
+ int joliet_level = 0;
struct iso9660_options opt;
int orig_zonesize;
struct iso_primary_descriptor * pri = NULL;
struct iso_directory_record * rootp;
+ struct iso_supplementary_descriptor *sec = NULL;
struct iso_volume_descriptor * vdp;
unsigned int vol_desc_start;
@@ -254,6 +296,7 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
#if 0
printk("map = %c\n", opt.map);
printk("rock = %c\n", opt.rock);
+ printk("joliet = %c\n", opt.joliet);
printk("check = %c\n", opt.check);
printk("cruft = %c\n", opt.cruft);
printk("unhide = %c\n", opt.unhide);
@@ -297,57 +340,93 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
vol_desc_start = isofs_get_last_session(dev);
- for (iso_blknum = vol_desc_start+16;
- iso_blknum < vol_desc_start+100; iso_blknum++) {
- int b = iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits);
-
- if (!(bh = bread(dev,b,opt.blocksize))) {
- s->s_dev = 0;
- printk("isofs_read_super: bread failed, dev "
- "%s iso_blknum %d block %d\n",
- kdevname(dev), iso_blknum, b);
- unlock_super(s);
- MOD_DEC_USE_COUNT;
- return NULL;
- }
-
- vdp = (struct iso_volume_descriptor *)bh->b_data;
- hdp = (struct hs_volume_descriptor *)bh->b_data;
+ for (iso_blknum = vol_desc_start+16;
+ iso_blknum < vol_desc_start+100; iso_blknum++)
+ {
+ int b = iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits);
+ if (!(bh = bread(dev,b,opt.blocksize))) {
+ s->s_dev = 0;
+ printk("isofs_read_super: bread failed, dev "
+ "%s iso_blknum %d block %d\n",
+ kdevname(dev), iso_blknum, b);
+ unlock_super(s);
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ }
- if (strncmp (hdp->id, HS_STANDARD_ID, sizeof hdp->id) == 0) {
- if (isonum_711 (hdp->type) != ISO_VD_PRIMARY)
- goto out;
- if (isonum_711 (hdp->type) == ISO_VD_END)
- goto out;
+ vdp = (struct iso_volume_descriptor *)bh->b_data;
+ hdp = (struct hs_volume_descriptor *)bh->b_data;
+
+ if (strncmp (hdp->id, HS_STANDARD_ID, sizeof hdp->id) == 0) {
+ if (isonum_711 (hdp->type) != ISO_VD_PRIMARY)
+ goto out;
+ if (isonum_711 (hdp->type) == ISO_VD_END)
+ goto out;
+
+ s->u.isofs_sb.s_high_sierra = 1;
+ high_sierra = 1;
+ opt.rock = 'n';
+ h_pri = (struct hs_primary_descriptor *)vdp;
+ break;
+ }
- s->u.isofs_sb.s_high_sierra = 1;
- high_sierra = 1;
- opt.rock = 'n';
- h_pri = (struct hs_primary_descriptor *)vdp;
+ if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) {
+ if (isonum_711 (vdp->type) == ISO_VD_END)
+ break;
+ if (isonum_711 (vdp->type) == ISO_VD_PRIMARY) {
+ if (pri == NULL) {
+ pri = (struct iso_primary_descriptor *)vdp;
+ }
+#ifdef CONFIG_JOLIET
+ } else if (isonum_711 (vdp->type) == ISO_VD_SUPPLEMENTARY) {
+ sec = (struct iso_supplementary_descriptor *)vdp;
+ if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) {
+ if (opt.joliet == 'y') {
+ opt.rock = 'n';
+ if (sec->escape[2] == 0x40) {
+ joliet_level = 1;
+ } else if (sec->escape[2] == 0x43) {
+ joliet_level = 2;
+ } else if (sec->escape[2] == 0x45) {
+ joliet_level = 3;
+ }
+ printk("ISO9660 Extensions: Microsoft Joliet Level %d\n",
+ joliet_level);
+ }
break;
+ } else {
+ /* Unknown supplementary volume descriptor */
+ sec = NULL;
+ }
+#endif
}
+ /* Just skip any volume descriptors we don't recognize */
+ }
- if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) {
- if (isonum_711 (vdp->type) != ISO_VD_PRIMARY)
- goto out;
- if (isonum_711 (vdp->type) == ISO_VD_END)
- goto out;
+ brelse(bh);
+ }
+ if ((pri == NULL) && (sec == NULL) && (h_pri == NULL)) {
+ if (!silent)
+ printk("Unable to identify CD-ROM format.\n");
+ s->s_dev = 0;
+ unlock_super(s);
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ }
- pri = (struct iso_primary_descriptor *)vdp;
- break;
- }
+ s->u.isofs_sb.s_joliet_level = joliet_level;
- brelse(bh);
- }
- if(iso_blknum == vol_desc_start + 100) {
- if (!silent)
- printk("Unable to identify CD-ROM format.\n");
- s->s_dev = 0;
- unlock_super(s);
- MOD_DEC_USE_COUNT;
- return NULL;
+#ifdef CONFIG_JOLIET
+ if (joliet_level) {
+ /* Note: In theory, it is possible to have Rock Ridge
+ * extensions mixed with Joliet. All character strings
+ * would just be saved as Unicode. Until someone sees such
+ * a disc, do not allow the two to be mixed
+ */
+ pri = (struct iso_primary_descriptor *) sec;
}
+#endif
if(high_sierra){
rootp = (struct iso_directory_record *) h_pri->root_directory_record;
@@ -465,6 +544,28 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
printk(KERN_DEBUG "Forcing new log zone size:%d\n", opt.blocksize);
}
+#ifdef CONFIG_JOLIET
+ s->u.isofs_sb.s_nls_iocharset = NULL;
+ if (joliet_level == 0) {
+ if (opt.iocharset) {
+ kfree(opt.iocharset);
+ opt.iocharset = NULL;
+ }
+ } else if (opt.utf8 == 0) {
+ char * p;
+ p = opt.iocharset ? opt.iocharset : "iso8859-1";
+ s->u.isofs_sb.s_nls_iocharset = load_nls(p);
+ if (! s->u.isofs_sb.s_nls_iocharset) {
+ /* Fail only if explicit charset specified */
+ if (opt.iocharset) {
+ kfree(opt.iocharset);
+ goto out;
+ } else {
+ s->u.isofs_sb.s_nls_iocharset = load_nls_default();
+ }
+ }
+ }
+#endif
s->s_dev = dev;
s->s_op = &isofs_sops;
s->u.isofs_sb.s_mapping = opt.map;
@@ -475,6 +576,7 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
s->u.isofs_sb.s_unhide = opt.unhide;
s->u.isofs_sb.s_uid = opt.uid;
s->u.isofs_sb.s_gid = opt.gid;
+ s->u.isofs_sb.s_utf8 = opt.utf8;
/*
* It would be incredibly stupid to allow people to mark every file on the disk
* as suid, so we merely allow them to set the default permissions.
@@ -490,13 +592,24 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
if (!(s->s_root)) {
s->s_dev = 0;
printk("get root inode failed\n");
+#ifdef CONFIG_JOLIET
+ if (s->u.isofs_sb.s_nls_iocharset)
+ unload_nls(s->u.isofs_sb.s_nls_iocharset);
+ if (opt.iocharset) kfree(opt.iocharset);
+#endif
MOD_DEC_USE_COUNT;
return NULL;
}
if(!check_disk_change(s->s_dev)) {
- return s;
+ return s;
}
+#ifdef CONFIG_JOLIET
+ if (s->u.isofs_sb.s_nls_iocharset)
+ unload_nls(s->u.isofs_sb.s_nls_iocharset);
+#endif
+ if (opt.iocharset) kfree(opt.iocharset);
+
out: /* Kick out for various error conditions */
brelse(bh);
s->s_dev = 0;
diff --git a/fs/isofs/joliet.c b/fs/isofs/joliet.c
new file mode 100644
index 000000000..c34bfef76
--- /dev/null
+++ b/fs/isofs/joliet.c
@@ -0,0 +1,110 @@
+/*
+ * linux/fs/isofs/joliet.c
+ *
+ * (C) 1996 Gordon Chaffee
+ *
+ * Joliet: Microsoft's Unicode extensions to iso9660
+ */
+
+#include <linux/string.h>
+#include <linux/nls.h>
+#include <linux/malloc.h>
+#include <linux/iso_fs.h>
+
+/*
+ * Convert Unicode 16 to UTF8 or ascii.
+ */
+static int
+uni16_to_x8(unsigned char *ascii, unsigned char *uni, int len,
+ struct nls_table *nls)
+{
+ unsigned char *ip, *op;
+ unsigned char ch, cl;
+ unsigned char *uni_page;
+
+ ip = uni;
+ op = ascii;
+
+ while ((*ip || ip[1]) && len) {
+ ch = *ip++;
+ cl = *ip++;
+
+ uni_page = nls->page_uni2charset[ch];
+ if (uni_page && uni_page[cl]) {
+ *op++ = uni_page[cl];
+ } else {
+ *op++ = '?';
+ }
+ len--;
+ }
+ *op = 0;
+ return (op - ascii);
+}
+
+/* Convert big endian wide character string to utf8 */
+static int
+wcsntombs_be(__u8 *s, const __u8 *pwcs, int inlen, int maxlen)
+{
+ const __u8 *ip;
+ __u8 *op;
+ int size;
+ __u16 c;
+
+ op = s;
+ ip = pwcs;
+ while ((*ip || ip[1]) && (maxlen > 0) && (inlen > 0)) {
+ c = (*ip << 8) | ip[1];
+ if (c > 0x7f) {
+ size = utf8_wctomb(op, c, maxlen);
+ if (size == -1) {
+ /* Ignore character and move on */
+ maxlen--;
+ } else {
+ op += size;
+ maxlen -= size;
+ }
+ } else {
+ *op++ = (__u8) c;
+ }
+ ip += 2;
+ inlen--;
+ }
+ return (op - s);
+}
+
+int
+get_joliet_filename(struct iso_directory_record * de, struct inode * inode,
+ unsigned char *outname)
+{
+ unsigned char utf8;
+ struct nls_table *nls;
+ unsigned char len = 0;
+ int i;
+ char c;
+
+ utf8 = inode->i_sb->u.isofs_sb.s_utf8;
+ nls = inode->i_sb->u.isofs_sb.s_nls_iocharset;
+
+ if (utf8) {
+ len = wcsntombs_be(outname, de->name,
+ de->name_len[0] >> 1, PAGE_SIZE);
+ } else {
+ len = uni16_to_x8(outname, de->name,
+ de->name_len[0] >> 1, nls);
+ }
+ if ((len > 2) && (outname[len-2] == ';') && (outname[len-1] == '1')) {
+ len -= 2;
+ }
+
+ if (inode->i_sb->u.isofs_sb.s_name_check == 'r') {
+ for (i = 0; i < len; i++) {
+ c = outname[i];
+ /* lower case */
+ if (c >= 'A' && c <= 'Z') c |= 0x20;
+ if (c == ';') c = '.';
+ outname[i] = c;
+ }
+ }
+
+ return len;
+}
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c
index 99555835b..1bedcf9be 100644
--- a/fs/isofs/namei.c
+++ b/fs/isofs/namei.c
@@ -12,10 +12,11 @@
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
-#include <asm/uaccess.h>
#include <linux/malloc.h>
-
#include <linux/errno.h>
+#include <linux/config.h> /* Joliet? */
+
+#include <asm/uaccess.h>
/*
* ok, we cannot use strncmp, as the name is not in our data space.
@@ -67,8 +68,9 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
inode_number = 0; /* shut gcc up */
struct buffer_head * bh;
unsigned int old_offset;
- int dlen, rrflag, match;
+ int dlen, match;
char * dpnt;
+ unsigned char *page = NULL;
struct iso_directory_record * de = NULL; /* shut gcc up */
char de_not_in_buf = 0; /* true if de is in kmalloc'd memory */
char c;
@@ -92,9 +94,8 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
if(!de_not_in_buf) {
de = (struct iso_directory_record *)
(bh->b_data + offset);
- inode_number = (block << bufbits)
- + (offset & (bufsize - 1));
}
+ inode_number = (block << bufbits) + (offset & (bufsize - 1));
/* If byte is zero, or we had to fetch this de past
the end of the buffer, this is the end of file, or
@@ -109,22 +110,22 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
one */
de_not_in_buf = 0;
kfree(de);
- offset -= bufsize;
+ f_pos += offset;
}
- else
+ else {
offset = 0;
+ f_pos = ((f_pos & ~(ISOFS_BLOCK_SIZE - 1))
+ + ISOFS_BLOCK_SIZE);
+ }
brelse(bh);
- f_pos = ((f_pos & ~(ISOFS_BLOCK_SIZE - 1))
- + ISOFS_BLOCK_SIZE) + offset;
- if( f_pos >= dir->i_size )
- {
- return 0;
- }
+ if (f_pos >= dir->i_size)
+ return 0;
block = isofs_bmap(dir,f_pos>>bufbits);
if (!block || !(bh = bread(dir->i_dev,block,bufsize)))
- return 0;
+ return NULL;
+
continue; /* Will kick out if past end of directory */
}
@@ -154,31 +155,44 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
bh_next->b_data, offset - bufsize);
brelse(bh_next);
de_not_in_buf = 1;
+ offset -= bufsize;
}
-
dlen = de->name_len[0];
dpnt = de->name;
- /* Now convert the filename in the buffer to lower case */
- rrflag = get_rock_ridge_filename(de, &dpnt, &dlen, dir);
- if (rrflag) {
- if (rrflag == -1) goto out; /* Relocated deep directory */
- } else {
- if(dir->i_sb->u.isofs_sb.s_mapping == 'n') {
- for (i = 0; i < dlen; i++) {
- c = dpnt[i];
- if (c >= 'A' && c <= 'Z') c |= 0x20; /* lower case */
- if (c == ';' && i == dlen-2 && dpnt[i+1] == '1') {
- dlen -= 2;
- break;
- }
- if (c == ';') c = '.';
- de->name[i] = c;
- }
- /* This allows us to match with and without a trailing
- period. */
- if(dpnt[dlen-1] == '.' && namelen == dlen-1)
- dlen--;
- }
+
+ if (dir->i_sb->u.isofs_sb.s_rock ||
+ dir->i_sb->u.isofs_sb.s_joliet_level) {
+ page = (unsigned char *)
+ __get_free_page(GFP_KERNEL);
+ if (!page) return NULL;
+ }
+ if (dir->i_sb->u.isofs_sb.s_rock &&
+ ((i = get_rock_ridge_filename(de, page, dir)))) {
+ if (i == -1)
+ goto out;/* Relocated deep directory */
+ dlen = i;
+ dpnt = page;
+#ifdef CONFIG_JOLIET
+ } else if (dir->i_sb->u.isofs_sb.s_joliet_level) {
+ dlen = get_joliet_filename(de, dir, page);
+ dpnt = page;
+#endif
+ } else if (dir->i_sb->u.isofs_sb.s_mapping == 'n') {
+ for (i = 0; i < dlen; i++) {
+ c = dpnt[i];
+ /* lower case */
+ if (c >= 'A' && c <= 'Z') c |= 0x20;
+ if (c == ';' && i == dlen-2 && dpnt[i+1] == '1') {
+ dlen -= 2;
+ break;
+ }
+ if (c == ';') c = '.';
+ dpnt[i] = c;
+ }
+ /* This allows us to match with and without
+ * a trailing period. */
+ if(dpnt[dlen-1] == '.' && namelen == dlen-1)
+ dlen--;
}
/*
* Skip hidden or associated files unless unhide is set
@@ -190,7 +204,7 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
match = isofs_match(namelen,name,dpnt,dlen);
}
- if(rrflag) kfree(dpnt);
+ if (page) free_page((unsigned long) page);
if (match) {
if(inode_number == -1) {
/* Should only happen for the '..' entry */
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c
index a9bb95f52..e006ac3ee 100644
--- a/fs/isofs/rock.c
+++ b/fs/isofs/rock.c
@@ -153,15 +153,16 @@ int find_rock_ridge_relocation(struct iso_directory_record * de,
}
int get_rock_ridge_filename(struct iso_directory_record * de,
- char ** name, int * namlen, struct inode * inode)
+ char * retname, struct inode * inode)
{
int len;
unsigned char * chr;
CONTINUE_DECLS;
- char * retname = NULL;
int retnamlen = 0, truncate=0;
if (!inode->i_sb->u.isofs_sb.s_rock) return 0;
+ *retname = 0;
+ retnamlen = 0;
SETUP_ROCK_RIDGE(de, chr, len);
repeat:
@@ -203,18 +204,6 @@ int get_rock_ridge_filename(struct iso_directory_record * de,
printk("Unsupported NM flag settings (%d)\n",rr->u.NM.flags);
break;
};
- if (!retname){
- retname = (char *) kmalloc (255,GFP_KERNEL);
- /* This may be a waste, but we only
- need this for a moment. The layers
- that call this function should
- deallocate the mem fairly soon
- after control is returned */
-
- if (!retname) goto out;
- *retname = 0; /* Zero length string */
- retnamlen = 0;
- };
if((strlen(retname) + rr->len - 5) >= 254) {
truncate = 1;
break;
@@ -227,7 +216,6 @@ int get_rock_ridge_filename(struct iso_directory_record * de,
printk("RR: RE (%x)\n", inode->i_ino);
#endif
if (buffer) kfree(buffer);
- if (retname) kfree(retname);
return -1;
default:
break;
@@ -235,15 +223,9 @@ int get_rock_ridge_filename(struct iso_directory_record * de,
};
}
MAYBE_CONTINUE(repeat,inode);
- if(retname){
- *name = retname;
- *namlen = retnamlen;
- return 1;
- };
- return 0; /* This file did not have a NM field */
+ return retnamlen; /* If 0, this file did not have a NM field */
out:
if(buffer) kfree(buffer);
- if (retname) kfree(retname);
return 0;
}
diff --git a/fs/isofs/symlink.c b/fs/isofs/symlink.c
index c88c56760..5321e011a 100644
--- a/fs/isofs/symlink.c
+++ b/fs/isofs/symlink.c
@@ -56,7 +56,7 @@ static int isofs_readlink(struct inode * inode, char * buffer, int buflen)
if (!pnt)
return 0;
- i = strlen(pnt)+1;
+ i = strlen(pnt);
if (i > buflen)
i = buflen;
if (copy_to_user(buffer, pnt, i))
diff --git a/fs/isofs/util.c b/fs/isofs/util.c
index 75183cc8f..2d578fb8b 100644
--- a/fs/isofs/util.c
+++ b/fs/isofs/util.c
@@ -9,6 +9,8 @@
* the 386bsd iso9660 filesystem, by Pace Willisson <pace@blitz.com>.
*/
+#include <linux/time.h>
+
int
isonum_711 (char * p)
{
@@ -112,6 +114,8 @@ int iso_date(char * p, int flag)
crtime = 0;
} else {
int monlen[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
+ extern struct timezone sys_tz;
+
days = year * 365;
if (year > 2)
days += (year+1) / 4;
@@ -122,7 +126,9 @@ int iso_date(char * p, int flag)
days += day - 1;
crtime = ((((days * 24) + hour) * 60 + minute) * 60)
+ second;
-
+ if (sys_tz.tz_dsttime)
+ crtime -= 3600;
+
/* sign extend */
if (tz & 0x80)
tz |= (-1 << 8);
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index d219de5ea..c25a19c97 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -160,8 +160,9 @@ static inline int
nlmclnt_grace_wait(struct nlm_host *host)
{
if (!host->h_reclaiming)
- current->timeout = 10 * HZ;
+ current->timeout = jiffies + 10 * HZ;
interruptible_sleep_on(&host->h_gracewait);
+ current->timeout = 0;
return signalled()? -ERESTARTSYS : 0;
}
@@ -178,9 +179,11 @@ nlmclnt_alloc_call(void)
sizeof(struct nlm_rqst));
if (call)
return call;
- current->timeout = 5 * HZ;
+ printk("nlmclnt_alloc_call: failed, waiting for memory\n");
+ current->timeout = jiffies + 5 * HZ;
current->state = TASK_INTERRUPTIBLE;
schedule();
+ current->timeout = 0;
}
return NULL;
}
@@ -232,6 +235,7 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc)
/* Back off a little and try again */
current->timeout = jiffies + 15 * HZ;
interruptible_sleep_on(&host->h_gracewait);
+ current->timeout = 0;
} while (!signalled());
return -ERESTARTSYS;
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index fc133b51e..c5f77ef89 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -42,11 +42,15 @@
extern struct svc_program nlmsvc_program;
struct nlmsvc_binding * nlmsvc_ops = NULL;
-static int nlmsvc_sema = 0;
-static int nlmsvc_pid = 0;
+static struct semaphore nlmsvc_sema = MUTEX;
+static unsigned int nlmsvc_users = 0;
+static pid_t nlmsvc_pid = 0;
unsigned long nlmsvc_grace_period = 0;
unsigned long nlmsvc_timeout = 0;
+static struct wait_queue * lockd_start = NULL;
+static struct wait_queue * lockd_exit = NULL;
+
/*
* Currently the following can be set only at insmod time.
* Ideally, they would be accessible through the sysctl interface.
@@ -64,10 +68,16 @@ lockd(struct svc_rqst *rqstp)
sigset_t oldsigmask;
int err = 0;
- lock_kernel();
/* Lock module and set up kernel thread */
MOD_INC_USE_COUNT;
- /* exit_files(current); */
+ lock_kernel();
+
+ /*
+ * Let our maker know we're running.
+ */
+ nlmsvc_pid = current->pid;
+ wake_up(&lockd_start);
+
exit_mm(current);
current->session = 1;
current->pgrp = 1;
@@ -76,6 +86,12 @@ lockd(struct svc_rqst *rqstp)
/* kick rpciod */
rpciod_up();
+ /*
+ * N.B. current do_fork() doesn't like NULL task->files,
+ * so we defer closing files until forking rpciod.
+ */
+ exit_files(current);
+
dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");
if (!nlm_timeout)
@@ -94,14 +110,14 @@ lockd(struct svc_rqst *rqstp)
nlmsvc_grace_period += jiffies;
nlmsvc_timeout = nlm_timeout * HZ;
- nlmsvc_pid = current->pid;
/*
* The main request loop. We don't terminate until the last
* NFS mount or NFS daemon has gone away, and we've been sent a
- * signal.
+ * signal, or else another process has taken over our job.
*/
- while (nlmsvc_sema || !signalled()) {
+ while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid)
+ {
if (signalled())
current->signal = 0;
@@ -156,8 +172,17 @@ lockd(struct svc_rqst *rqstp)
nlmsvc_ops->exp_unlock();
}
- nlm_shutdown_hosts();
-
+ /*
+ * Check whether there's a new lockd process before
+ * shutting down the hosts and clearing the slot.
+ */
+ if (!nlmsvc_pid || current->pid == nlmsvc_pid) {
+ nlm_shutdown_hosts();
+ nlmsvc_pid = 0;
+ } else
+ printk("lockd: new process, skipping host shutdown\n");
+ wake_up(&lockd_exit);
+
/* Exit the RPC thread */
svc_exit_thread(rqstp);
@@ -166,7 +191,6 @@ lockd(struct svc_rqst *rqstp)
/* Release module */
MOD_DEC_USE_COUNT;
- nlmsvc_pid = 0;
}
/*
@@ -185,42 +209,100 @@ lockd_makesock(struct svc_serv *serv, int protocol, unsigned short port)
return svc_create_socket(serv, protocol, &sin);
}
+/*
+ * Bring up the lockd process if it's not already up.
+ */
int
lockd_up(void)
{
struct svc_serv * serv;
- int error;
+ int error = 0;
- if (nlmsvc_pid || nlmsvc_sema++)
- return 0;
+ down(&nlmsvc_sema);
+ /*
+ * Unconditionally increment the user count ... this is
+ * the number of clients who _want_ a lockd process.
+ */
+ nlmsvc_users++;
+ /*
+ * Check whether we're already up and running.
+ */
+ if (nlmsvc_pid)
+ goto out;
- dprintk("lockd: creating service\n");
- if ((serv = svc_create(&nlmsvc_program, 0, NLMSVC_XDRSIZE)) == NULL)
- return -ENOMEM;
+ /*
+ * Sanity check: if there's no pid,
+ * we should be the first user ...
+ */
+ if (nlmsvc_users > 1)
+ printk("lockd_up: no pid, %d users??\n", nlmsvc_users);
+
+ error = -ENOMEM;
+ serv = svc_create(&nlmsvc_program, 0, NLMSVC_XDRSIZE);
+ if (!serv) {
+ printk("lockd_up: create service failed\n");
+ goto out;
+ }
- if ((error = lockd_makesock(serv, IPPROTO_UDP, 0)) < 0
+ if ((error = lockd_makesock(serv, IPPROTO_UDP, 0)) < 0
|| (error = lockd_makesock(serv, IPPROTO_TCP, 0)) < 0) {
- svc_destroy(serv);
- return error;
+ printk("lockd_up: makesock failed, error=%d\n", error);
+ goto destroy_and_out;
}
- if ((error = svc_create_thread(lockd, serv)) < 0)
- nlmsvc_sema--;
+ /*
+ * Create the kernel thread and wait for it to start.
+ */
+ error = svc_create_thread(lockd, serv);
+ if (error) {
+ printk("lockd_up: create thread failed, error=%d\n", error);
+ goto destroy_and_out;
+ }
+ sleep_on(&lockd_start);
- /* Release server */
+ /*
+ * Note: svc_serv structures have an initial use count of 1,
+ * so we exit through here on both success and failure.
+ */
+destroy_and_out:
svc_destroy(serv);
- return 0;
+out:
+ up(&nlmsvc_sema);
+ return error;
}
+/*
+ * Decrement the user count and bring down lockd if we're the last.
+ */
void
lockd_down(void)
{
- if (!nlmsvc_pid || --nlmsvc_sema > 0)
- return;
+ down(&nlmsvc_sema);
+ if (nlmsvc_users) {
+ if (--nlmsvc_users)
+ goto out;
+ } else
+ printk("lockd_down: no users! pid=%d\n", nlmsvc_pid);
+
+ if (!nlmsvc_pid) {
+ printk("lockd_down: nothing to do!\n");
+ goto out;
+ }
kill_proc(nlmsvc_pid, SIGKILL, 1);
- nlmsvc_sema = 0;
- nlmsvc_pid = 0;
+ /*
+ * Wait for the lockd process to exit, but since we're holding
+ * the lockd semaphore, we can't wait around forever ...
+ */
+ current->timeout = jiffies + 5 * HZ;
+ interruptible_sleep_on(&lockd_exit);
+ current->timeout = 0;
+ if (nlmsvc_pid) {
+ printk("lockd_down: lockd failed to exit, clearing pid\n");
+ nlmsvc_pid = 0;
+ }
+out:
+ up(&nlmsvc_sema);
}
#ifdef MODULE
@@ -235,6 +317,11 @@ lockd_down(void)
int
init_module(void)
{
+ /* Init the static variables */
+ nlmsvc_sema = MUTEX;
+ nlmsvc_users = 0;
+ nlmsvc_pid = 0;
+ lockd_exit = NULL;
nlmxdr_init();
return 0;
}
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index 3526867ca..0c2380de3 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -32,10 +32,16 @@ static struct semaphore nlm_file_sema = MUTEX;
* Lookup file info. If it doesn't exist, create a file info struct
* and open a (VFS) file for the given inode.
*
+ * The NFS filehandle must have been validated prior to this call,
+ * as we assume that the dentry pointer is valid.
+ *
* FIXME:
* Note that we open the file O_RDONLY even when creating write locks.
* This is not quite right, but for now, we assume the client performs
* the proper R/W checking.
+ *
+ * The dentry in the FH may not be validated .. can we call this with
+ * the full svc_fh?
*/
u32
nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
@@ -43,21 +49,24 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
{
struct nlm_file *file;
struct knfs_fh *fh = (struct knfs_fh *) f;
- unsigned int hash = FILE_HASH(fh->fh_dhash);
+ struct dentry *dentry = fh->fh_dcookie;
+ unsigned int hash = FILE_HASH(dentry->d_name.hash);
u32 nfserr;
- dprintk("lockd: nlm_file_lookup(%p)\n", fh->fh_dentry);
+ dprintk("lockd: nlm_file_lookup(%s/%s)\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
/* Lock file table */
down(&nlm_file_sema);
for (file = nlm_files[hash]; file; file = file->f_next) {
- if (file->f_handle.fh_dentry == fh->fh_dentry
+ if (file->f_handle.fh_dcookie == dentry
&& !memcmp(&file->f_handle, fh, sizeof(*fh)))
goto found;
}
- dprintk("lockd: creating file for %p\n", fh->fh_dentry);
+ dprintk("lockd: creating file for %s/%s\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
if (!(file = (struct nlm_file *) kmalloc(sizeof(*file), GFP_KERNEL))) {
up(&nlm_file_sema);
return nlm_lck_denied_nolocks;
diff --git a/fs/locks.c b/fs/locks.c
index 738fa0bca..3f4c2c287 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -503,7 +503,7 @@ int locks_verify_locked(struct inode *inode)
}
int locks_verify_area(int read_write, struct inode *inode, struct file *filp,
- unsigned int offset, unsigned int count)
+ loff_t offset, size_t count)
{
/* Candidates for mandatory locking have the setgid bit set
* but no group execute bit - an otherwise meaningless combination.
@@ -531,8 +531,8 @@ int locks_mandatory_locked(struct inode *inode)
}
int locks_mandatory_area(int read_write, struct inode *inode,
- struct file *filp, unsigned int offset,
- unsigned int count)
+ struct file *filp, loff_t offset,
+ size_t count)
{
struct file_lock *fl;
struct file_lock tfl;
@@ -560,7 +560,7 @@ repeat:
if (posix_locks_conflict(fl, &tfl)) {
if (filp && (filp->f_flags & O_NONBLOCK))
return (-EAGAIN);
- if (current->signal & ~current->blocked)
+ if (signal_pending(current))
return (-ERESTARTSYS);
if (posix_locks_deadlock(&tfl, fl))
return (-EDEADLK);
@@ -569,7 +569,7 @@ repeat:
interruptible_sleep_on(&tfl.fl_wait);
locks_delete_block(fl, &tfl);
- if (current->signal & ~current->blocked)
+ if (signal_pending(current))
return (-ERESTARTSYS);
/* If we've been sleeping someone might have
* changed the permissions behind our back.
@@ -822,7 +822,7 @@ search:
repeat:
/* Check signals each time we start */
error = -ERESTARTSYS;
- if (current->signal & ~current->blocked)
+ if (signal_pending(current))
goto out;
for (fl = inode->i_flock; (fl != NULL) && (fl->fl_flags & FL_FLOCK);
fl = fl->fl_next) {
@@ -881,9 +881,6 @@ int posix_lock_file(struct file *filp, struct file_lock *caller,
if (caller->fl_type != F_UNLCK) {
repeat:
- error = -ERESTARTSYS;
- if (current->signal & ~current->blocked)
- goto out;
for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
if (!(fl->fl_flags & FL_POSIX))
continue;
@@ -895,6 +892,9 @@ int posix_lock_file(struct file *filp, struct file_lock *caller,
error = -EDEADLK;
if (posix_locks_deadlock(caller, fl))
goto out;
+ error = -ERESTARTSYS;
+ if (signal_pending(current))
+ goto out;
locks_insert_block(fl, caller);
interruptible_sleep_on(&caller->fl_wait);
locks_delete_block(fl, caller);
@@ -1147,9 +1147,9 @@ static char *lock_get_status(struct file_lock *fl, int id, char *pfx)
}
static inline int copy_lock_status(char *p, char **q, off_t pos, int len,
- off_t offset, int length)
+ off_t offset, off_t length)
{
- int i;
+ off_t i;
i = pos - offset;
if (i > 0) {
@@ -1171,15 +1171,13 @@ static inline int copy_lock_status(char *p, char **q, off_t pos, int len,
return (1);
}
-int get_locks_status(char *buffer, char **start, off_t offset, int length)
+int get_locks_status(char *buffer, char **start, off_t offset, off_t length)
{
struct file_lock *fl;
struct file_lock *bfl;
char *p;
char *q = buffer;
- int i;
- int len;
- off_t pos = 0;
+ off_t i, len, pos = 0;
for (fl = file_lock_table, i = 1; fl != NULL; fl = fl->fl_nextlink, i++) {
p = lock_get_status(fl, i, "");
diff --git a/fs/minix/dir.c b/fs/minix/dir.c
index 11ebef00f..4c407817b 100644
--- a/fs/minix/dir.c
+++ b/fs/minix/dir.c
@@ -14,8 +14,8 @@
#include <asm/uaccess.h>
-static long minix_dir_read(struct inode * inode, struct file * filp,
- char * buf, unsigned long count)
+static ssize_t minix_dir_read(struct file * filp, char * buf,
+ size_t count, loff_t *ppos)
{
return -EISDIR;
}
diff --git a/fs/minix/file.c b/fs/minix/file.c
index ecd0d24d9..5aaef83b2 100644
--- a/fs/minix/file.c
+++ b/fs/minix/file.c
@@ -27,7 +27,7 @@
#include <linux/fs.h>
#include <linux/minix_fs.h>
-static long minix_file_write(struct inode *, struct file *, const char *, unsigned long);
+static ssize_t minix_file_write(struct file *, const char *, size_t, loff_t *);
/*
* We have mostly NULL's here: the current defaults are ok for
@@ -66,11 +66,12 @@ struct inode_operations minix_file_inode_operations = {
NULL /* permission */
};
-static long minix_file_write(struct inode * inode, struct file * filp,
- const char * buf, unsigned long count)
+static ssize_t minix_file_write(struct file * filp, const char * buf,
+ size_t count, loff_t *ppos)
{
+ struct inode * inode = filp->f_dentry->d_inode;
off_t pos;
- int written,c;
+ ssize_t written, c;
struct buffer_head * bh;
char * p;
@@ -85,7 +86,7 @@ static long minix_file_write(struct inode * inode, struct file * filp,
if (filp->f_flags & O_APPEND)
pos = inode->i_size;
else
- pos = filp->f_pos;
+ pos = *ppos;
written = 0;
while (written < count) {
bh = minix_getblk(inode,pos/BLOCK_SIZE,1);
@@ -126,7 +127,7 @@ static long minix_file_write(struct inode * inode, struct file * filp,
if (pos > inode->i_size)
inode->i_size = pos;
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- filp->f_pos = pos;
+ *ppos = pos;
mark_inode_dirty(inode);
return written;
}
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index d1404cdca..a0eb8165a 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -21,9 +21,10 @@
#include "../fat/msbuffer.h"
+#define MSDOS_PARANOIA 1
+/* #define MSDOS_DEBUG 1 */
#define PRINTK(x)
-
/* MS-DOS "device special files" */
static const char *reserved_names[] = {
@@ -230,6 +231,7 @@ struct super_block *msdos_read_super(struct super_block *sb,void *data, int sile
MOD_INC_USE_COUNT;
+ MSDOS_SB(sb)->options.isvfat = 0;
sb->s_op = &msdos_sops;
res = fat_read_super(sb, data, silent);
if (res == NULL) {
@@ -255,7 +257,7 @@ int msdos_lookup(struct inode *dir,struct dentry *dentry)
dentry->d_op = &msdos_dentry_operations;
- if(!dir) {
+ if(!dir) { /* N.B. This test is bogus -- should never happen */
d_add(dentry, NULL);
return 0;
}
@@ -282,7 +284,7 @@ int msdos_lookup(struct inode *dir,struct dentry *dentry)
}
if (MSDOS_I(inode)->i_busy) { /* mkdir in progress */
iput(inode);
- d_add(dentry, NULL);
+ d_add(dentry, NULL); /* N.B. Do we really want a negative? */
return 0;
}
PRINTK (("msdos_lookup 6\n"));
@@ -291,8 +293,7 @@ int msdos_lookup(struct inode *dir,struct dentry *dentry)
iput(inode);
if (!(inode = iget(next->i_sb,next->i_ino))) {
fat_fs_panic(dir->i_sb,"msdos_lookup: Can't happen");
- d_add(dentry, NULL);
- return -ENOENT;
+ return -ENOENT; /* N.B. Maybe ENOMEM is better? */
}
}
PRINTK (("msdos_lookup 7\n"));
@@ -317,7 +318,9 @@ static int msdos_create_entry(struct inode *dir, const char *name,
*result = NULL;
if ((res = fat_scan(dir,NULL,&bh,&de,&ino,SCAN_ANY)) < 0) {
if (res != -ENOENT) return res;
- if (dir->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
+ if ((dir->i_ino == MSDOS_ROOT_INO) &&
+ (MSDOS_SB(sb)->fat_bits != 32))
+ return -ENOSPC;
if ((res = fat_add_cluster(dir)) < 0) return res;
if ((res = fat_scan(dir,NULL,&bh,&de,&ino,SCAN_ANY)) < 0) return res;
}
@@ -327,10 +330,10 @@ static int msdos_create_entry(struct inode *dir, const char *name,
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
mark_inode_dirty(dir);
memcpy(de->name,name,MSDOS_NAME);
- memset(de->unused, 0, sizeof(de->unused));
de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
de->attr = is_hid ? (de->attr|ATTR_HIDDEN) : (de->attr&~ATTR_HIDDEN);
de->start = 0;
+ de->starthi = 0;
fat_date_unix2dos(dir->i_mtime,&de->time,&de->date);
de->size = 0;
fat_mark_buffer_dirty(sb, bh, 1);
@@ -379,7 +382,8 @@ int msdos_create(struct inode *dir,struct dentry *dentry,int mode)
res = msdos_create_entry(dir,msdos_name,S_ISDIR(mode),is_hid,
&inode);
fat_unlock_creation();
- d_instantiate(dentry, inode);
+ if (!res)
+ d_instantiate(dentry, inode);
return res;
}
@@ -406,61 +410,77 @@ static void dump_fat(struct super_block *sb,int start)
/***** See if directory is empty */
static int msdos_empty(struct inode *dir)
{
- struct super_block *sb = dir->i_sb;
loff_t pos;
struct buffer_head *bh;
struct msdos_dir_entry *de;
+ int result = 0;
- if (dir->i_count > 1)
- return -EBUSY;
if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */
pos = 0;
bh = NULL;
- while (fat_get_entry(dir,&pos,&bh,&de) > -1)
- if (!IS_FREE(de->name) && strncmp(de->name,MSDOS_DOT,
- MSDOS_NAME) && strncmp(de->name,MSDOS_DOTDOT,
- MSDOS_NAME)) {
- fat_brelse(sb, bh);
- return -ENOTEMPTY;
+ while (fat_get_entry(dir,&pos,&bh,&de) > -1) {
+ if (!IS_FREE(de->name) &&
+ strncmp(de->name,MSDOS_DOT , MSDOS_NAME) &&
+ strncmp(de->name,MSDOS_DOTDOT, MSDOS_NAME)) {
+ result = -ENOTEMPTY;
+ break;
}
+ }
if (bh)
- fat_brelse(sb, bh);
+ fat_brelse(dir->i_sb, bh);
}
- return 0;
+ return result;
}
/***** Remove a directory */
-int msdos_rmdir(struct inode *dir,struct dentry *dentry)
+int msdos_rmdir(struct inode *dir, struct dentry *dentry)
{
+ struct inode *inode = dentry->d_inode;
struct super_block *sb = dir->i_sb;
int res,ino;
struct buffer_head *bh;
struct msdos_dir_entry *de;
- struct inode *inode;
bh = NULL;
- inode = NULL;
- res = -EPERM;
- if ((res = msdos_find(dir,dentry->d_name.name,dentry->d_name.len,
- &bh,&de,&ino)) < 0)
+ res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
+ &bh, &de, &ino);
+ if (res < 0)
goto rmdir_done;
- inode = dentry->d_inode;
res = -ENOTDIR;
- if (!S_ISDIR(inode->i_mode)) goto rmdir_done;
- res = -EBUSY;
+ if (!S_ISDIR(inode->i_mode))
+ goto rmdir_done;
if (dir->i_dev != inode->i_dev || dir == inode)
- goto rmdir_done;
+ printk("msdos_rmdir: impossible condition\n");
+ /*
+ * Prune any child dentries, then verify that
+ * the directory is empty and not in use.
+ */
+ shrink_dcache_parent(dentry);
res = msdos_empty(inode);
if (res)
goto rmdir_done;
+ res = -EBUSY;
+ if (dentry->d_count > 1) {
+#ifdef MSDOS_DEBUG
+printk("rename_diff_dir: %s/%s busy, d_count=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
+#endif
+ goto rmdir_done;
+ }
+
inode->i_nlink = 0;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->i_nlink--;
mark_inode_dirty(inode);
mark_inode_dirty(dir);
+ /*
+ * Do the d_delete before any blocking operations.
+ * We must make a negative dentry, as the FAT code
+ * apparently relies on the inode being iput().
+ */
+ d_delete(dentry);
de->name[0] = DELETED_FLAG;
fat_mark_buffer_dirty(sb, bh, 1);
- d_delete(dentry);
res = 0;
rmdir_done:
fat_brelse(sb, bh);
@@ -486,22 +506,23 @@ int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode)
fat_lock_creation();
if (fat_scan(dir,msdos_name,&bh,&de,&ino,SCAN_ANY) >= 0) {
fat_unlock_creation();
+ /* N.B. does this need to be released on the other path? */
fat_brelse(sb, bh);
return -EEXIST;
}
- if ((res = msdos_create_entry(dir,msdos_name,1,is_hid,
- &inode)) < 0) {
- fat_unlock_creation();
- return res;
- }
+ res = msdos_create_entry(dir,msdos_name,1,is_hid, &inode);
+ if (res < 0)
+ goto out_unlock;
dir->i_nlink++;
inode->i_nlink = 2; /* no need to mark them dirty */
MSDOS_I(inode)->i_busy = 1; /* prevent lookups */
- if ((res = fat_add_cluster(inode)) < 0) goto mkdir_error;
+ if ((res = fat_add_cluster(inode)) < 0)
+ goto mkdir_error;
if ((res = msdos_create_entry(inode,MSDOS_DOT,1,0,&dot)) < 0)
goto mkdir_error;
dot->i_size = inode->i_size; /* doesn't grow in the 2nd create_entry */
MSDOS_I(dot)->i_start = MSDOS_I(inode)->i_start;
+ MSDOS_I(dot)->i_logstart = MSDOS_I(inode)->i_logstart;
dot->i_nlink = inode->i_nlink;
mark_inode_dirty(dot);
iput(dot);
@@ -510,6 +531,7 @@ int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode)
fat_unlock_creation();
dot->i_size = dir->i_size;
MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
+ MSDOS_I(dot)->i_logstart = MSDOS_I(dir)->i_logstart;
dot->i_nlink = dir->i_nlink;
mark_inode_dirty(dot);
MSDOS_I(inode)->i_busy = 0;
@@ -519,6 +541,7 @@ int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode)
mkdir_error:
if (msdos_rmdir(dir,dentry) < 0)
fat_fs_panic(dir->i_sb,"rmdir in mkdir failed");
+out_unlock:
fat_unlock_creation();
return res;
}
@@ -530,25 +553,20 @@ static int msdos_unlinkx(
int nospc) /* Flag special file ? */
{
struct super_block *sb = dir->i_sb;
+ struct inode *inode = dentry->d_inode;
int res,ino;
struct buffer_head *bh;
struct msdos_dir_entry *de;
- struct inode *inode;
bh = NULL;
- inode = NULL;
if ((res = msdos_find(dir,dentry->d_name.name,dentry->d_name.len,
&bh,&de,&ino)) < 0)
goto unlink_done;
- inode = dentry->d_inode;
- if (!S_ISREG(inode->i_mode) && nospc){
- res = -EPERM;
+ res = -EPERM;
+ if (!S_ISREG(inode->i_mode) && nospc)
goto unlink_done;
- }
- if (IS_IMMUTABLE(inode)){
- res = -EPERM;
+ if (IS_IMMUTABLE(inode))
goto unlink_done;
- }
inode->i_nlink = 0;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
MSDOS_I(inode)->i_busy = 1;
@@ -557,6 +575,7 @@ static int msdos_unlinkx(
de->name[0] = DELETED_FLAG;
fat_mark_buffer_dirty(sb, bh, 1);
d_delete(dentry); /* This also frees the inode */
+ res = 0;
unlink_done:
fat_brelse(sb, bh);
return res;
@@ -702,7 +721,10 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,
: (free_de->attr&~ATTR_HIDDEN);
if (!(free_inode = iget(new_dir->i_sb,free_ino))) {
free_de->name[0] = DELETED_FLAG;
-/* Don't mark free_bh as dirty. Both states are supposed to be equivalent. */
+ /*
+ * Don't mark free_bh as dirty. Both states
+ * are supposed to be equivalent.
+ */
fat_brelse(sb, free_bh);
if (exists)
fat_brelse(sb, new_bh);
@@ -713,19 +735,53 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,
mark_inode_dirty(new_dir);
}
msdos_read_inode(free_inode);
+ /*
+ * Check whether there's already a linked inode ...
+ */
+ if (MSDOS_I(old_inode)->i_linked) {
+ struct inode *linked = MSDOS_I(old_inode)->i_linked;
+#ifdef MSDOS_PARANOIA
+printk("rename_diff_dir: inode %ld already has link %ld, freeing it\n",
+old_inode->i_ino, linked->i_ino);
+#endif
+ MSDOS_I(old_inode)->i_linked = NULL;
+ MSDOS_I(linked)->i_oldlink = NULL;
+ iput(linked);
+ }
MSDOS_I(old_inode)->i_busy = 1;
MSDOS_I(old_inode)->i_linked = free_inode;
MSDOS_I(free_inode)->i_oldlink = old_inode;
+#ifdef MSDOS_DEBUG
+printk("rename_diff_dir: inode %ld added as link of %ld\n",
+free_inode->i_ino, old_inode->i_ino);
+#endif
fat_cache_inval_inode(old_inode);
mark_inode_dirty(old_inode);
old_de->name[0] = DELETED_FLAG;
fat_mark_buffer_dirty(sb, old_bh, 1);
fat_mark_buffer_dirty(sb, free_bh, 1);
if (exists) {
+ /*
+ * Check whether there's already a depend inode ...
+ */
+ if (MSDOS_I(new_inode)->i_depend) {
+ struct inode *depend = MSDOS_I(new_inode)->i_depend;
+#ifdef MSDOS_PARANOIA
+printk("rename_diff_dir: inode %ld already has depend %ld, freeing it\n",
+new_inode->i_ino, depend->i_ino);
+#endif
+ MSDOS_I(new_inode)->i_depend = NULL;
+ MSDOS_I(depend)->i_old = NULL;
+ iput(depend);
+ }
MSDOS_I(new_inode)->i_depend = free_inode;
MSDOS_I(free_inode)->i_old = new_inode;
/* Two references now exist to free_inode so increase count */
free_inode->i_count++;
+#ifdef MSDOS_DEBUG
+printk("rename_diff_dir: inode %ld added as depend of %ld\n",
+free_inode->i_ino, new_inode->i_ino);
+#endif
/* free_inode is put after putting new_inode and old_inode */
fat_brelse(sb, new_bh);
}
@@ -737,8 +793,10 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,
error = -EIO;
goto rename_done;
}
- dotdot_de->start = MSDOS_I(dotdot_inode)->i_start =
- MSDOS_I(new_dir)->i_start;
+ MSDOS_I(dotdot_inode)->i_start = MSDOS_I(new_dir)->i_start;
+ MSDOS_I(dotdot_inode)->i_logstart = MSDOS_I(new_dir)->i_logstart;
+ dotdot_de->start = CT_LE_W(MSDOS_I(new_dir)->i_logstart);
+ dotdot_de->starthi = CT_LE_W((MSDOS_I(new_dir)->i_logstart) >> 16);
mark_inode_dirty(dotdot_inode);
fat_mark_buffer_dirty(sb, dotdot_bh, 1);
old_dir->i_nlink--;
diff --git a/fs/namei.c b/fs/namei.c
index 54714754d..242363824 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -232,11 +232,15 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name)
result = d_lookup(parent, name);
if (!result) {
struct dentry * dentry = d_alloc(parent, name);
- int error = dir->i_op->lookup(dir, dentry);
- result = ERR_PTR(error);
- if (!error)
- result = dget(dentry->d_mounts);
- dput(dentry);
+ result = ERR_PTR(-ENOMEM);
+ if (dentry) {
+ int error = dir->i_op->lookup(dir, dentry);
+ result = dentry;
+ if (error) {
+ dput(dentry);
+ result = ERR_PTR(error);
+ }
+ }
}
up(&dir->i_sem);
return result;
@@ -290,25 +294,6 @@ static struct dentry * reserved_lookup(struct dentry * parent, struct qstr * nam
return dget(result);
}
-/* In difference to the former version, lookup() no longer eats the dir. */
-static inline struct dentry * lookup(struct dentry * dir, struct qstr * name)
-{
- struct dentry * result;
-
- result = reserved_lookup(dir, name);
- if (result)
- goto done;
-
- result = cached_lookup(dir, name);
- if (result)
- goto done;
-
- result = real_lookup(dir, name);
-
-done:
- return result;
-}
-
static struct dentry * do_follow_link(struct dentry *base, struct dentry *dentry)
{
struct inode * inode = dentry->d_inode;
@@ -331,6 +316,18 @@ static struct dentry * do_follow_link(struct dentry *base, struct dentry *dentry
return dentry;
}
+static inline struct dentry * follow_mount(struct dentry * dentry)
+{
+ struct dentry * mnt = dentry->d_mounts;
+
+ if (mnt != dentry) {
+ dget(mnt);
+ dput(dentry);
+ dentry = mnt;
+ }
+ return dentry;
+}
+
/*
* Name resolution.
*
@@ -412,9 +409,19 @@ struct dentry * lookup_dentry(const char * name, struct dentry * base, int follo
}
}
- dentry = lookup(base, &this);
- if (IS_ERR(dentry))
- break;
+ /* This does the actual lookups.. */
+ dentry = reserved_lookup(base, &this);
+ if (!dentry) {
+ dentry = cached_lookup(base, &this);
+ if (!dentry) {
+ dentry = real_lookup(base, &this);
+ if (IS_ERR(dentry))
+ break;
+ }
+ }
+
+ /* Check mountpoints.. */
+ dentry = follow_mount(dentry);
if (!follow)
break;
@@ -445,6 +452,7 @@ struct dentry * __namei(const char *pathname, int follow_link)
char *name;
struct dentry *dentry;
+ check_dcache_memory();
name = getname(pathname);
dentry = (struct dentry *) name;
if (!IS_ERR(name)) {
@@ -518,6 +526,7 @@ struct dentry * open_namei(const char * pathname, int flag, int mode)
struct inode *inode;
struct dentry *dentry;
+ check_dcache_memory();
mode &= S_IALLUGO & ~current->fs->umask;
mode |= S_IFREG;
@@ -1170,7 +1179,8 @@ static inline int do_rename(const char * oldname, const char * newname)
if (new_dir->d_inode->i_sb && new_dir->d_inode->i_sb->dq_op)
new_dir->d_inode->i_sb->dq_op->initialize(new_dir->d_inode, -1);
- error = old_dir->d_inode->i_op->rename(old_dir->d_inode, old_dentry, new_dir->d_inode, new_dentry);
+ error = old_dir->d_inode->i_op->rename(old_dir->d_inode, old_dentry,
+ new_dir->d_inode, new_dentry);
exit_lock:
double_unlock(new_dir, old_dir);
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index 58e1bd187..005431485 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 1995, 1996 by Volker Lendecke
* Modified for big endian by J.F. Chadima and David S. Miller
+ * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
*
*/
@@ -13,13 +14,18 @@
#include <linux/malloc.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
-#include <linux/ncp_fs.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
#include <linux/errno.h>
#include <linux/locks.h>
+
+#include <linux/ncp_fs.h>
#include "ncplib_kernel.h"
+#ifndef shrink_dcache_parent
+#define shrink_dcache_parent(dentry) shrink_dcache_sb((dentry)->d_sb)
+#endif
+
struct ncp_dirent {
struct nw_info_struct i;
@@ -27,79 +33,30 @@ struct ncp_dirent {
unsigned long f_pos;
};
-static long
- ncp_dir_read(struct inode *inode, struct file *filp, char *buf, unsigned long count);
-
-static int
- ncp_readdir(struct file *filp,
- void *dirent, filldir_t filldir);
-
-static int
- ncp_read_volume_list(struct ncp_server *server, int start_with,
- int cache_size);
-
-static int
- ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,
- int cache_size, struct ncp_dirent *entry);
-
-static struct inode *
- ncp_iget(struct inode *dir, struct nw_file_info *finfo);
-
-static struct ncp_inode_info *
- ncp_find_dir_inode(struct inode *dir, const char *name);
-
-static int
- ncp_lookup(struct inode *dir, const char *__name,
- int len, struct inode **result);
-
-static int
- ncp_create(struct inode *dir, const char *name, int len, int mode,
- struct inode **result);
-
-static int
- ncp_mkdir(struct inode *dir, const char *name, int len, int mode);
-
-static int
- ncp_rmdir(struct inode *dir, const char *name, int len);
-
-static int
- ncp_unlink(struct inode *dir, const char *name, int len);
+static kdev_t c_dev = 0;
+static unsigned long c_ino = 0;
+static int c_size;
+static int c_seen_eof;
+static int c_last_returned_index;
+static struct ncp_dirent *c_entry = NULL;
+static int c_lock = 0;
+static struct wait_queue *c_wait = NULL;
-static int
- ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
- struct inode *new_dir, const char *new_name, int new_len);
+static int ncp_read_volume_list(struct ncp_server *, int, int,
+ struct ncp_dirent *);
+static int ncp_do_readdir(struct ncp_server *, struct dentry *, int, int,
+ struct ncp_dirent *);
-static inline void str_upper(char *name)
-{
- while (*name) {
- if (*name >= 'a' && *name <= 'z') {
- *name -= ('a' - 'A');
- }
- name++;
- }
-}
-
-static inline void str_lower(char *name)
-{
- while (*name) {
- if (*name >= 'A' && *name <= 'Z') {
- *name += ('a' - 'A');
- }
- name++;
- }
-}
+static ssize_t ncp_dir_read(struct file *, char *, size_t, loff_t *);
+static int ncp_readdir(struct file *, void *, filldir_t);
-static inline int ncp_namespace(struct inode *i)
-{
- struct ncp_server *server = NCP_SERVER(i);
- struct nw_info_struct *info = NCP_ISTRUCT(i);
- return server->name_space[info->volNumber];
-}
-
-static inline int ncp_preserve_case(struct inode *i)
-{
- return (ncp_namespace(i) == NW_NS_OS2);
-}
+static int ncp_create(struct inode *, struct dentry *, int);
+static int ncp_lookup(struct inode *, struct dentry *);
+static int ncp_unlink(struct inode *, struct dentry *);
+static int ncp_mkdir(struct inode *, struct dentry *, int);
+static int ncp_rmdir(struct inode *, struct dentry *);
+static int ncp_rename(struct inode *, struct dentry *,
+ struct inode *, struct dentry *);
static struct file_operations ncp_dir_operations =
{
@@ -128,74 +85,173 @@ struct inode_operations ncp_dir_inode_operations =
NULL, /* mknod */
ncp_rename, /* rename */
NULL, /* readlink */
+ NULL, /* follow link */
+ NULL, /* readpage */
+ NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL, /* permission */
- NULL /* smap */
+ NULL, /* smap */
+ NULL, /* updatepage */
+ NULL, /* revalidate */
};
+static ssize_t
+ncp_dir_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
+{
+ return -EISDIR;
+}
-/* Here we encapsulate the inode number handling that depends upon the
- * mount mode: When we mount a complete server, the memory address of
- * the ncp_inode_info is used as the inode number. When only a single
- * volume is mounted, then the dirEntNum is used as the inode
- * number. As this is unique for the complete volume, this should
- * enable the NFS exportability of a ncpfs-mounted volume.
+/*
+ * Dentry operations routines
*/
+static int ncp_lookup_validate(struct dentry *);
+static void ncp_delete_dentry(struct dentry *);
+static int ncp_hash_dentry(struct dentry *, struct qstr *);
+static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *);
-static inline int ncp_single_volume(struct ncp_server *server)
+static struct dentry_operations ncp_dentry_operations =
{
- return (server->m.mounted_vol[0] != '\0');
-}
+ ncp_lookup_validate, /* d_validate(struct dentry *) */
+ ncp_hash_dentry, /* d_hash */
+ ncp_compare_dentry, /* d_compare */
+ ncp_delete_dentry /* d_delete(struct dentry *) */
+};
+
+
+/*
+ * XXX: It would be better to use the tolower from linux/ctype.h,
+ * but _ctype is needed and it is not exported.
+ */
+#define tolower(c) (((c) >= 'A' && (c) <= 'Z') ? (c)-('A'-'a') : (c))
+
-inline ino_t
- ncp_info_ino(struct ncp_server * server, struct ncp_inode_info * info)
+static int
+ncp_hash_dentry(struct dentry *dentry, struct qstr *this)
{
- return ncp_single_volume(server)
- ? info->finfo.i.dirEntNum : (ino_t) info;
+ unsigned long hash;
+ int i;
+
+ hash = init_name_hash();
+ for (i=0; i<this->len ; i++)
+ hash = partial_name_hash(tolower(this->name[i]),hash);
+ this->hash = end_name_hash(hash);
+
+ return 0;
}
-static inline int ncp_is_server_root(struct inode *inode)
+static int
+ncp_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
{
- struct ncp_server *s = NCP_SERVER(inode);
+ int i;
+
+ if (a->len != b->len) return 1;
+
+ if (ncp_case_sensitive(dentry->d_inode))
+ return strncmp(a->name, b->name, a->len);
+
+ for (i=0; i<a->len; i++)
+ if (tolower(a->name[i]) != tolower(b->name[i]))
+ return 1;
- return ((!ncp_single_volume(s))
- && (inode->i_ino == ncp_info_ino(s, &(s->root))));
+ return 0;
}
-struct ncp_inode_info *
- ncp_find_inode(struct inode *inode)
+/*
+ * This is the callback from dput() when d_count is going to 0.
+ * We use this to unhash dentries with bad inodes and close files.
+ */
+static void
+ncp_delete_dentry(struct dentry * dentry)
{
- struct ncp_server *server = NCP_SERVER(inode);
- struct ncp_inode_info *root = &(server->root);
- struct ncp_inode_info *this = root;
-
- ino_t ino = inode->i_ino;
+ struct inode *inode = dentry->d_inode;
- do {
- if (ino == ncp_info_ino(server, this)) {
- return this;
+ if (inode)
+ {
+ if (is_bad_inode(inode))
+ {
+ d_drop(dentry);
}
- this = this->next;
+ /*
+ * Lock the superblock, then recheck the dentry count.
+ * (Somebody might have used it again ...)
+ */
+ if (dentry->d_count == 1 && NCP_FINFO(inode)->opened) {
+#ifdef NCPFS_PARANOIA
+printk(KERN_DEBUG "ncp_delete_dentry: closing file %s/%s\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
+ ncp_make_closed(inode);
+ }
+ } else
+ {
+ /* N.B. Unhash negative dentries? */
+ }
+}
+
+/* Here we encapsulate the inode number handling that depends upon the
+ * mount mode: When we mount a complete server, the memory address of
+ * the ncp_inode_info is used as the inode number. When only a single
+ * volume is mounted, then the dirEntNum is used as the inode
+ * number. As this is unique for the complete volume, this should
+ * enable the NFS exportability of a ncpfs-mounted volume.
+ */
+
+/*
+ * Generate a unique inode number.
+ */
+ino_t ncp_invent_inos(unsigned long n)
+{
+ static ino_t ino = 1;
+
+ if (ino + 2*n < ino)
+ {
+ /* wrap around */
+ ino += n;
}
- while (this != root);
+ ino += n;
+ return ino;
+}
- return NULL;
+/*
+ * Check whether a dentry already exists for the given name,
+ * and return the inode number if it has an inode. This is
+ * needed to keep getcwd() working.
+ */
+static ino_t
+find_inode_number(struct dentry *dir, struct qstr *name)
+{
+ unsigned long hash;
+ int i;
+ struct dentry * dentry;
+ ino_t ino = 0;
+
+ hash = init_name_hash();
+ for (i=0; i<name->len ; i++)
+ hash = partial_name_hash(tolower(name->name[i]),hash);
+ name->hash = end_name_hash(hash);
+
+ dentry = d_lookup(dir, name);
+ if (dentry)
+ {
+ if (dentry->d_inode)
+ ino = dentry->d_inode->i_ino;
+ dput(dentry);
+ }
+ return ino;
}
-static long ncp_dir_read(struct inode *inode, struct file *filp, char *buf, unsigned long count)
+static inline int
+ncp_single_volume(struct ncp_server *server)
{
- return -EISDIR;
+ return (server->m.mounted_vol[0] != '\0');
}
-static kdev_t c_dev = 0;
-static unsigned long c_ino = 0;
-static int c_size;
-static int c_seen_eof;
-static int c_last_returned_index;
-static struct ncp_dirent *c_entry = NULL;
-static int c_lock = 0;
-static struct wait_queue *c_wait = NULL;
+static inline int ncp_is_server_root(struct inode *inode)
+{
+ return (!ncp_single_volume(NCP_SERVER(inode)) &&
+ inode == inode->i_sb->s_root->d_inode);
+}
static inline void ncp_lock_dircache(void)
{
@@ -210,54 +266,146 @@ static inline void ncp_unlock_dircache(void)
wake_up(&c_wait);
}
-static int ncp_readdir(struct file *filp,
- void *dirent, filldir_t filldir)
+
+/*
+ * This is the callback when the dcache has a lookup hit.
+ */
+
+static int
+ncp_lookup_validate(struct dentry * dentry)
{
- int result = 0;
- int i = 0;
- int index = 0;
- struct inode *inode = file->f_dentry->d_inode;
- struct ncp_dirent *entry = NULL;
+ struct ncp_server *server;
+ struct inode *dir = dentry->d_parent->d_inode;
+ int down_case = 0;
+ int val = 0,res;
+ int len = dentry->d_name.len;
+ struct ncpfs_inode_info finfo;
+ __u8 __name[dentry->d_name.len + 1];
+
+ if (!dentry->d_inode) {
+ DPRINTK(KERN_DEBUG "ncp_lookup_validate: called with dentry->d_inode already NULL.\n");
+ return 0;
+ }
+
+ if (!dir || !S_ISDIR(dir->i_mode)) {
+ printk(KERN_WARNING "ncp_lookup_validate: inode is NULL or not a directory.\n");
+ goto finished;
+ }
+ server = NCP_SERVER(dir);
+
+ if (!ncp_conn_valid(server))
+ goto finished;
+
+ strncpy(__name, dentry->d_name.name, len);
+ __name[len] = '\0';
+#ifdef NCPFS_PARANOIA
+printk(KERN_DEBUG "ncp_lookup_validate: %s, len %d\n", __name, len);
+#endif
+
+ if (!ncp_preserve_case(dir)) {
+ str_lower(__name);
+ down_case = 1;
+ }
+
+ /* If the file is in the dir cache, we do not have to ask the
+ server. */
+
+#ifdef NCPFS_PARANOIA
+printk(KERN_DEBUG "ncp_lookup_validate: server lookup for %s/%s\n",
+dentry->d_parent->d_name.name, __name);
+#endif
+ if (ncp_is_server_root(dir))
+ {
+ str_upper(__name);
+ down_case = 1;
+ res = ncp_lookup_volume(server, __name,
+ &(finfo.nw_info.i));
+ } else
+ {
+ if (!ncp_preserve_case(dir))
+ {
+ str_upper(__name);
+ down_case = 1;
+ }
+ res = ncp_obtain_info(server, dir, __name,
+ &(finfo.nw_info.i));
+ }
+#ifdef NCPFS_PARANOIA
+printk(KERN_DEBUG "ncp_lookup_validate: looked for %s/%s, res=%d\n",
+dentry->d_parent->d_name.name, __name, res);
+#endif
+ /*
+ * If we didn't find it, or if it has a different dirEntNum to
+ * what we remember, it's not valid any more.
+ */
+ if (!res)
+ if (finfo.nw_info.i.dirEntNum == NCP_FINFO(dentry->d_inode)->dirEntNum)
+ val=1;
+#ifdef NCPFS_PARANOIA
+ else
+ printk(KERN_DEBUG "ncp_lookup_validate: found, but dirEntNum changed\n");
+#endif
+ if (!val) ncp_invalid_dir_cache(dir);
+
+finished:
+#ifdef NCPFS_PARANOIA
+printk(KERN_DEBUG "ncp_lookup_validate: result=%d\n", val);
+#endif
+
+ return val;
+}
+
+
+static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+ struct dentry *dentry = filp->f_dentry;
+ struct inode *inode = dentry->d_inode;
struct ncp_server *server = NCP_SERVER(inode);
- struct ncp_inode_info *dir = NCP_INOP(inode);
+ struct ncp_dirent *entry = NULL;
+ int result, i, index = 0;
- DDPRINTK("ncp_readdir: filp->f_pos = %d\n", (int) filp->f_pos);
- DDPRINTK("ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n",
+ DDPRINTK(KERN_DEBUG "ncp_readdir: reading %s/%s, pos=%d\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name,
+ (int) filp->f_pos);
+ DDPRINTK(KERN_DEBUG "ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n",
inode->i_ino, c_ino);
+ result = -EBADF;
if (!inode || !S_ISDIR(inode->i_mode)) {
- printk("ncp_readdir: inode is NULL or not a directory\n");
- return -EBADF;
- }
- if (!ncp_conn_valid(server)) {
- return -EIO;
+ printk(KERN_WARNING "ncp_readdir: inode is NULL or not a directory\n");
+ goto out;
}
- ncp_lock_dircache();
+ result = -EIO;
+ if (!ncp_conn_valid(server))
+ goto out;
+ ncp_lock_dircache();
+ result = -ENOMEM;
if (c_entry == NULL) {
i = sizeof(struct ncp_dirent) * NCP_READDIR_CACHE_SIZE;
c_entry = (struct ncp_dirent *) vmalloc(i);
if (c_entry == NULL) {
- printk("ncp_readdir: no MEMORY for cache\n");
- result = -ENOMEM;
+ printk(KERN_WARNING "ncp_readdir: no MEMORY for cache\n");
goto finished;
}
}
+
+ result = 0;
if (filp->f_pos == 0) {
ncp_invalid_dir_cache(inode);
- if (filldir(dirent, ".", 1, filp->f_pos,
- ncp_info_ino(server, dir)) < 0) {
+ if (filldir(dirent, ".", 1, 0, inode->i_ino) < 0) {
goto finished;
}
- filp->f_pos += 1;
+ filp->f_pos = 1;
}
if (filp->f_pos == 1) {
- if (filldir(dirent, "..", 2, filp->f_pos,
- ncp_info_ino(server, dir->dir)) < 0) {
+ if (filldir(dirent, "..", 2, 1,
+ dentry->d_parent->d_inode->i_ino) < 0) {
goto finished;
}
- filp->f_pos += 1;
+ filp->f_pos = 2;
}
+
if ((inode->i_dev == c_dev) && (inode->i_ino == c_ino)) {
for (i = 0; i < c_size; i++) {
if (filp->f_pos == c_entry[i].f_pos) {
@@ -273,18 +421,17 @@ static int ncp_readdir(struct file *filp,
}
if (entry == NULL) {
int entries;
- DDPRINTK("ncp_readdir: Not found in cache.\n");
+ DDPRINTK(KERN_DEBUG "ncp_readdir: Not found in cache.\n");
if (ncp_is_server_root(inode)) {
entries = ncp_read_volume_list(server, filp->f_pos,
- NCP_READDIR_CACHE_SIZE);
- DPRINTK("ncp_read_volume_list returned %d\n", entries);
+ NCP_READDIR_CACHE_SIZE, c_entry);
+ DPRINTK(KERN_DEBUG "ncp_read_volume_list returned %d\n", entries);
} else {
- entries = ncp_do_readdir(server, inode, filp->f_pos,
- NCP_READDIR_CACHE_SIZE,
- c_entry);
- DPRINTK("ncp_readdir returned %d\n", entries);
+ entries = ncp_do_readdir(server, dentry, filp->f_pos,
+ NCP_READDIR_CACHE_SIZE, c_entry);
+ DPRINTK(KERN_DEBUG "ncp_readdir: returned %d\n", entries);
}
if (entries < 0) {
@@ -313,31 +460,24 @@ static int ncp_readdir(struct file *filp,
/* Nothing found, even from a ncp call */
goto finished;
}
+
while (index < c_size) {
ino_t ino;
-
- if (ncp_single_volume(server)) {
- ino = (ino_t) (entry->i.dirEntNum);
- } else {
- /* For getwd() we have to return the correct
- * inode in d_ino if the inode is currently in
- * use. Otherwise the inode number does not
- * matter. (You can argue a lot about this..) */
- struct ncp_inode_info *ino_info;
- ino_info = ncp_find_dir_inode(inode,
- entry->i.entryName);
-
- /* Some programs seem to be confused about a
- * zero inode number, so we set it to one.
- * Thanks to Gordon Chaffee for this one. */
- if (ino_info == NULL) {
- ino_info = (struct ncp_inode_info *) 1;
- }
- ino = (ino_t) (ino_info);
- }
-
- DDPRINTK("ncp_readdir: entry->path= %s\n", entry->i.entryName);
- DDPRINTK("ncp_readdir: entry->f_pos = %ld\n", entry->f_pos);
+ struct qstr qname;
+
+ DDPRINTK(KERN_DEBUG "ncp_readdir: entry->path= %s\n", entry->i.entryName);
+ DDPRINTK(KERN_DEBUG "ncp_readdir: entry->f_pos = %ld\n", entry->f_pos);
+
+ /* For getwd() we have to return the correct
+ * inode in d_ino if the inode is currently in
+ * use. Otherwise the inode number does not
+ * matter. (You can argue a lot about this..)
+ */
+ qname.name = entry->i.entryName;
+ qname.len = entry->i.nameLen;
+ ino = find_inode_number(dentry, &qname);
+ if (!ino)
+ ino = ncp_invent_inos(1);
if (filldir(dirent, entry->i.entryName, entry->i.nameLen,
entry->f_pos, ino) < 0) {
@@ -356,103 +496,114 @@ static int ncp_readdir(struct file *filp,
}
finished:
ncp_unlock_dircache();
+out:
return result;
}
-static int ncp_read_volume_list(struct ncp_server *server, int fpos, int cache_size)
+static int
+ncp_read_volume_list(struct ncp_server *server, int fpos,
+ int cache_size, struct ncp_dirent *entry)
{
- struct ncp_dirent *entry = c_entry;
-
- int total_count = 2;
- int i;
+ int i, total_count = 2;
+ struct ncp_volume_info info;
+ DPRINTK(KERN_DEBUG "ncp_read_volume_list: pos=%d\n", fpos);
#if 1
if (fpos < 2) {
- printk("OOPS, we expect fpos >= 2");
+ printk(KERN_ERR "OOPS, we expect fpos >= 2");
fpos = 2;
}
#endif
for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
- struct ncp_volume_info info;
- if (ncp_get_volume_info_with_number(server, i, &info) != 0) {
- return (total_count - fpos);
- }
- if (strlen(info.volume_name) > 0) {
- if (total_count < fpos) {
- DPRINTK("ncp_read_volumes: skipped vol: %s\n",
- info.volume_name);
- } else if (total_count >= fpos + cache_size) {
- return (total_count - fpos);
- } else {
- DPRINTK("ncp_read_volumes: found vol: %s\n",
- info.volume_name);
+ if (ncp_get_volume_info_with_number(server, i, &info) != 0)
+ goto out;
+ if (!strlen(info.volume_name))
+ continue;
- if (ncp_lookup_volume(server,
- info.volume_name,
- &(entry->i)) != 0) {
- DPRINTK("ncpfs: could not lookup vol "
- "%s\n", info.volume_name);
- continue;
- }
- entry->f_pos = total_count;
- entry += 1;
+ if (total_count < fpos) {
+ DPRINTK(KERN_DEBUG "ncp_read_volume_list: skipped vol: %s\n",
+ info.volume_name);
+ } else if (total_count >= fpos + cache_size) {
+ goto out;
+ } else {
+ DPRINTK(KERN_DEBUG "ncp_read_volume_list: found vol: %s\n",
+ info.volume_name);
+
+ if (ncp_lookup_volume(server, info.volume_name,
+ &(entry->i)) != 0) {
+ DPRINTK(KERN_DEBUG "ncpfs: could not lookup vol %s\n",
+ info.volume_name);
+ continue;
}
- total_count += 1;
+ entry->f_pos = total_count;
+ entry += 1;
}
+ total_count += 1;
}
+out:
return (total_count - fpos);
}
-static int ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,
- int cache_size, struct ncp_dirent *entry)
+static int ncp_do_readdir(struct ncp_server *server, struct dentry *dentry,
+ int fpos, int cache_size, struct ncp_dirent *entry)
{
- static struct nw_search_sequence seq;
+ struct inode *dir = dentry->d_inode;
static struct inode *last_dir;
static int total_count;
+ static struct nw_search_sequence seq;
+ int err;
#if 1
if (fpos < 2) {
- printk("OOPS, we expect fpos >= 2");
+ printk(KERN_ERR "OOPS, we expect fpos >= 2");
fpos = 2;
}
#endif
- DPRINTK("ncp_do_readdir: fpos = %d\n", fpos);
+ DPRINTK(KERN_DEBUG "ncp_do_readdir: %s/%s, fpos=%d\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name, fpos);
if (fpos == 2) {
last_dir = NULL;
total_count = 2;
}
- if ((fpos != total_count) || (dir != last_dir)) {
+ if ((fpos != total_count) || (dir != last_dir))
+ {
total_count = 2;
last_dir = dir;
-
- DPRINTK("ncp_do_readdir: re-used seq for %s\n",
- NCP_ISTRUCT(dir)->entryName);
-
- if (ncp_initialize_search(server, NCP_ISTRUCT(dir), &seq) != 0) {
- DPRINTK("ncp_init_search failed\n");
- return total_count - fpos;
+
+#ifdef NCPFS_PARANOIA
+printk(KERN_DEBUG "ncp_do_readdir: init %s, volnum=%d, dirent=%u\n",
+dentry->d_name.name, NCP_FINFO(dir)->volNumber, NCP_FINFO(dir)->dirEntNum);
+#endif
+ err = ncp_initialize_search(server, dir, &seq);
+ if (err)
+ {
+ DPRINTK(KERN_DEBUG "ncp_do_readdir: init failed, err=%d\n", err);
+ goto out;
}
}
+
while (total_count < fpos + cache_size) {
- if (ncp_search_for_file_or_subdir(server, &seq,
- &(entry->i)) != 0) {
- return total_count - fpos;
+ err = ncp_search_for_file_or_subdir(server, &seq, &(entry->i));
+ if (err) {
+ DPRINTK(KERN_DEBUG "ncp_do_readdir: search failed, err=%d\n", err);
+ goto out;
}
if (total_count < fpos) {
- DPRINTK("ncp_do_readdir: skipped file: %s\n",
- entry->i.entryName);
+ DPRINTK(KERN_DEBUG "ncp_do_readdir: skipped file: %s/%s\n",
+ dentry->d_name.name, entry->i.entryName);
} else {
- DDPRINTK("ncp_do_r: file: %s, f_pos=%d,total_count=%d",
- entry->i.entryName, fpos, total_count);
+ DDPRINTK(KERN_DEBUG "ncp_do_r: file: %s, f_pos=%d,total_count=%d",
+ entry->i.entryName, fpos, total_count);
entry->s = seq;
entry->f_pos = total_count;
entry += 1;
}
total_count += 1;
}
+out:
return (total_count - fpos);
}
@@ -474,7 +625,7 @@ void ncp_invalid_dir_cache(struct inode *ino)
void ncp_free_dir_cache(void)
{
- DPRINTK("ncp_free_dir_cache: enter\n");
+ DPRINTK(KERN_DEBUG "ncp_free_dir_cache: enter\n");
if (c_entry == NULL) {
return;
@@ -482,540 +633,398 @@ void ncp_free_dir_cache(void)
vfree(c_entry);
c_entry = NULL;
- DPRINTK("ncp_free_dir_cache: exit\n");
-}
-
-
-static struct inode *
- ncp_iget(struct inode *dir, struct nw_file_info *finfo)
-{
- struct inode *inode;
- struct ncp_inode_info *new_inode_info;
- struct ncp_inode_info *root;
-
- if (dir == NULL) {
- printk("ncp_iget: dir is NULL\n");
- return NULL;
- }
- if (finfo == NULL) {
- printk("ncp_iget: finfo is NULL\n");
- return NULL;
- }
- new_inode_info = ncp_kmalloc(sizeof(struct ncp_inode_info),
- GFP_KERNEL);
-
- if (new_inode_info == NULL) {
- printk("ncp_iget: could not alloc mem for %s\n",
- finfo->i.entryName);
- return NULL;
- }
- new_inode_info->state = NCP_INODE_LOOKED_UP;
- new_inode_info->nused = 0;
- new_inode_info->dir = NCP_INOP(dir);
- new_inode_info->finfo = *finfo;
-
- NCP_INOP(dir)->nused += 1;
-
- /* We have to link the new inode_info into the doubly linked
- list of inode_infos to make a complete linear search
- possible. */
-
- root = &(NCP_SERVER(dir)->root);
-
- new_inode_info->prev = root;
- new_inode_info->next = root->next;
- root->next->prev = new_inode_info;
- root->next = new_inode_info;
-
- if (!(inode = iget(dir->i_sb, ncp_info_ino(NCP_SERVER(dir),
- new_inode_info)))) {
- printk("ncp_iget: iget failed!");
- return NULL;
- }
- return inode;
-}
-
-void ncp_free_inode_info(struct ncp_inode_info *i)
-{
- if (i == NULL) {
- printk("ncp_free_inode: i == NULL\n");
- return;
- }
- i->state = NCP_INODE_CACHED;
- while ((i->nused == 0) && (i->state == NCP_INODE_CACHED)) {
- struct ncp_inode_info *dir = i->dir;
-
- i->next->prev = i->prev;
- i->prev->next = i->next;
-
- DDPRINTK("ncp_free_inode_info: freeing %s\n",
- i->finfo.i.entryName);
-
- ncp_kfree_s(i, sizeof(struct ncp_inode_info));
-
- if (dir == i)
- return;
-
- (dir->nused)--;
- i = dir;
- }
-}
-
-void ncp_init_root(struct ncp_server *server)
-{
- struct ncp_inode_info *root = &(server->root);
- struct nw_info_struct *i = &(root->finfo.i);
- unsigned short dummy;
-
- DPRINTK("ncp_init_root: i = %x\n", (int) i);
-
- root->finfo.opened = 0;
- i->attributes = aDIR;
- i->dataStreamSize = 1024;
- i->dirEntNum = i->DosDirNum = 0;
- i->volNumber = NCP_NUMBER_OF_VOLUMES + 1; /* illegal volnum */
- ncp_date_unix2dos(0, &(i->creationTime), &(i->creationDate));
- ncp_date_unix2dos(0, &(i->modifyTime), &(i->modifyDate));
- ncp_date_unix2dos(0, &dummy, &(i->lastAccessDate));
- i->creationTime = le16_to_cpu(i->creationTime);
- i->creationDate = le16_to_cpu(i->creationDate);
- i->modifyTime = le16_to_cpu(i->modifyTime);
- i->modifyDate = le16_to_cpu(i->modifyDate);
- i->lastAccessDate = le16_to_cpu(i->lastAccessDate);
- i->nameLen = 0;
- i->entryName[0] = '\0';
-
- root->state = NCP_INODE_LOOKED_UP;
- root->nused = 1;
- root->dir = root;
- root->next = root->prev = root;
- return;
+ DPRINTK(KERN_DEBUG "ncp_free_dir_cache: exit\n");
}
int ncp_conn_logged_in(struct ncp_server *server)
{
- if (server->m.mounted_vol[0] == '\0') {
- return 0;
- }
- str_upper(server->m.mounted_vol);
- if (ncp_lookup_volume(server, server->m.mounted_vol,
- &(server->root.finfo.i)) != 0) {
- return -ENOENT;
- }
- str_lower(server->root.finfo.i.entryName);
-
- return 0;
-}
-
-void ncp_free_all_inodes(struct ncp_server *server)
-{
- /* Here nothing should be to do. I do not know whether it's
- better to leave some memory allocated or be stuck in an
- endless loop */
-#if 1
- struct ncp_inode_info *root = &(server->root);
-
- if (root->next != root) {
- printk("ncp_free_all_inodes: INODES LEFT!!!\n");
- }
- while (root->next != root) {
- printk("ncp_free_all_inodes: freeing inode\n");
- ncp_free_inode_info(root->next);
- /* In case we have an endless loop.. */
- schedule();
- }
+ int result;
+
+ if (ncp_single_volume(server)) {
+ result = -ENOENT;
+ str_upper(server->m.mounted_vol);
+ if (ncp_lookup_volume(server, server->m.mounted_vol,
+ &(server->root.finfo.i)) != 0) {
+#ifdef NCPFS_PARANOIA
+printk(KERN_DEBUG "ncp_conn_logged_in: %s not found\n", server->m.mounted_vol);
#endif
-
- return;
-}
-
-/* We will search the inode that belongs to this name, currently by a
- complete linear search through the inodes belonging to this
- filesystem. This has to be fixed. */
-static struct ncp_inode_info *
- ncp_find_dir_inode(struct inode *dir, const char *name)
-{
- struct ncp_server *server = NCP_SERVER(dir);
- struct nw_info_struct *dir_info = NCP_ISTRUCT(dir);
- struct ncp_inode_info *result = &(server->root);
-
- if (name == NULL) {
- return NULL;
- }
- do {
- if ((result->dir->finfo.i.dirEntNum == dir_info->dirEntNum)
- && (result->dir->finfo.i.volNumber == dir_info->volNumber)
- && (strcmp(result->finfo.i.entryName, name) == 0)
- /* The root dir is never looked up using this
- * routine. Without the following test a root
- * directory 'sys' in a volume named 'sys' could
- * never be looked up, because
- * server->root->dir==server->root. */
- && (result != &(server->root))) {
- return result;
+ goto out;
}
- result = result->next;
-
+ str_lower(server->root.finfo.i.entryName);
}
- while (result != &(server->root));
+ result = 0;
- return NULL;
+out:
+ return result;
}
-static int ncp_lookup(struct inode *dir, const char *__name, int len,
- struct inode **result)
+static int ncp_lookup(struct inode *dir, struct dentry *dentry)
{
- struct nw_file_info finfo;
struct ncp_server *server;
- struct ncp_inode_info *result_info;
- int found_in_cache;
- int down_case = 0;
- char name[len + 1];
-
- *result = NULL;
-
+ struct inode *inode = NULL;
+ int found_in_cache, down_case = 0;
+ int error;
+ int len = dentry->d_name.len;
+ struct ncpfs_inode_info finfo;
+ __u8 __name[dentry->d_name.len + 1];
+
+ error = -ENOENT;
if (!dir || !S_ISDIR(dir->i_mode)) {
- printk("ncp_lookup: inode is NULL or not a directory.\n");
- iput(dir);
- return -ENOENT;
+ printk(KERN_WARNING "ncp_lookup: inode is NULL or not a directory.\n");
+ goto finished;
}
server = NCP_SERVER(dir);
- if (!ncp_conn_valid(server)) {
- iput(dir);
- return -EIO;
- }
- DPRINTK("ncp_lookup: %s, len %d\n", __name, len);
-
- /* Fast cheat for . */
- if (len == 0 || (len == 1 && __name[0] == '.')) {
- *result = dir;
- return 0;
- }
- /* ..and for .. */
- if (len == 2 && __name[0] == '.' && __name[1] == '.') {
- struct ncp_inode_info *parent = NCP_INOP(dir)->dir;
-
- if (parent->state == NCP_INODE_CACHED) {
- parent->state = NCP_INODE_LOOKED_UP;
- }
- *result = iget(dir->i_sb, ncp_info_ino(server, parent));
- iput(dir);
- if (*result == 0) {
- return -EACCES;
- } else {
- return 0;
- }
- }
- memcpy(name, __name, len);
- name[len] = 0;
- lock_super(dir->i_sb);
- result_info = ncp_find_dir_inode(dir, name);
-
- if (result_info != 0) {
- if (result_info->state == NCP_INODE_CACHED) {
- result_info->state = NCP_INODE_LOOKED_UP;
- }
- /* Here we convert the inode_info address into an
- inode number */
+ error = -EIO;
+ if (!ncp_conn_valid(server))
+ goto finished;
- *result = iget(dir->i_sb, ncp_info_ino(server, result_info));
- unlock_super(dir->i_sb);
- iput(dir);
+ strncpy(__name, dentry->d_name.name, len);
+ __name[len] = '\0';
+#ifdef NCPFS_PARANOIA
+printk(KERN_DEBUG "ncp_lookup: %s, len %d\n", __name, len);
+#endif
- if (*result == NULL) {
- return -EACCES;
- }
- return 0;
+ if (!ncp_preserve_case(dir)) {
+ str_lower(__name);
+ down_case = 1;
}
+
/* If the file is in the dir cache, we do not have to ask the
server. */
found_in_cache = 0;
ncp_lock_dircache();
- if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino)) {
+ if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino))
+ {
int first = c_last_returned_index;
int i;
-
+
i = first;
do {
- DDPRINTK("ncp_lookup: trying index: %d, name: %s\n",
- i, c_entry[i].i.entryName);
-
- if (strcmp(c_entry[i].i.entryName, name) == 0) {
- DPRINTK("ncp_lookup: found in cache!\n");
- finfo.i = c_entry[i].i;
+#ifdef NCPFS_PARANOIA
+printk(KERN_DEBUG "ncp_lookup: trying index: %d, name: %s\n", i, c_entry[i].i.entryName);
+#endif
+ if (strcmp(c_entry[i].i.entryName, __name) == 0) {
+#ifdef NCPFS_PARANOIA
+printk(KERN_DEBUG "ncp_lookup: found in cache!\n");
+#endif
+ finfo.nw_info.i = c_entry[i].i;
found_in_cache = 1;
break;
}
i = (i + 1) % c_size;
- }
- while (i != first);
+ } while (i != first);
}
ncp_unlock_dircache();
- if (found_in_cache == 0) {
+ if (found_in_cache == 0)
+ {
int res;
-
- DDPRINTK("ncp_lookup: do_lookup on %s/%s\n",
- NCP_ISTRUCT(dir)->entryName, name);
-
- if (ncp_is_server_root(dir)) {
- str_upper(name);
+
+#ifdef NCPFS_PARANOIA
+printk(KERN_DEBUG "ncp_lookup: server lookup for %s/%s\n",
+dentry->d_parent->d_name.name, __name);
+#endif
+ if (ncp_is_server_root(dir))
+ {
+ str_upper(__name);
down_case = 1;
- res = ncp_lookup_volume(server, name, &(finfo.i));
- } else {
- if (!ncp_preserve_case(dir)) {
- str_upper(name);
+ res = ncp_lookup_volume(server, __name,
+ &(finfo.nw_info.i));
+ } else
+ {
+ if (!ncp_preserve_case(dir))
+ {
+ str_upper(__name);
down_case = 1;
}
- res = ncp_obtain_info(server,
- NCP_ISTRUCT(dir)->volNumber,
- NCP_ISTRUCT(dir)->dirEntNum,
- name, &(finfo.i));
- }
- if (res != 0) {
- unlock_super(dir->i_sb);
- iput(dir);
- return -ENOENT;
+ res = ncp_obtain_info(server, dir, __name,
+ &(finfo.nw_info.i));
}
+#ifdef NCPFS_PARANOIA
+printk(KERN_DEBUG "ncp_lookup: looked for %s/%s, res=%d\n",
+dentry->d_parent->d_name.name, __name, res);
+#endif
+ /*
+ * If we didn't find an entry, make a negative dentry.
+ */
+ if (res != 0)
+ goto add_entry;
+ }
+
+ /*
+ * Create an inode for the entry.
+ */
+ finfo.nw_info.opened = 0;
+ finfo.ino = ncp_invent_inos(1);
+ error = -EACCES;
+ inode = ncp_iget(dir->i_sb, &finfo);
+ if (inode)
+ {
+ add_entry:
+ dentry->d_op = &ncp_dentry_operations;
+ d_add(dentry, inode);
+ error = 0;
}
- finfo.opened = 0;
- if (down_case != 0) {
- str_lower(finfo.i.entryName);
- }
- if (!(*result = ncp_iget(dir, &finfo))) {
- unlock_super(dir->i_sb);
- iput(dir);
- return -EACCES;
- }
- unlock_super(dir->i_sb);
- iput(dir);
- return 0;
+finished:
+#ifdef NCPFS_PARANOIA
+printk(KERN_DEBUG "ncp_lookup: result=%d\n", error);
+#endif
+ return error;
}
-static int ncp_create(struct inode *dir, const char *name, int len, int mode,
- struct inode **result)
+/*
+ * This code is common to create, mkdir, and mknod.
+ */
+static int ncp_instantiate(struct inode *dir, struct dentry *dentry,
+ struct ncpfs_inode_info *finfo)
{
- struct nw_file_info finfo;
- __u8 _name[len + 1];
+ struct inode *inode;
+ int error = -EINVAL;
+
+ ncp_invalid_dir_cache(dir);
+
+ finfo->ino = ncp_invent_inos(1);
+ inode = ncp_iget(dir->i_sb, finfo);
+ if (!inode)
+ goto out_close;
+ d_instantiate(dentry,inode);
+ error = 0;
+out:
+ return error;
- *result = NULL;
+out_close:
+#ifdef NCPFS_PARANOIA
+printk(KERN_DEBUG "ncp_instantiate: %s/%s failed, closing file\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
+ ncp_close_file(NCP_SERVER(dir), finfo->nw_info.file_handle);
+ goto out;
+}
+static int ncp_create(struct inode *dir, struct dentry *dentry, int mode)
+{
+ int error, result;
+ struct ncpfs_inode_info finfo;
+ __u8 _name[dentry->d_name.len + 1];
+
+#ifdef NCPFS_PARANOIA
+printk(KERN_DEBUG "ncp_create: creating %s/%s, mode=%x\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, mode);
+#endif
if (!dir || !S_ISDIR(dir->i_mode)) {
- printk("ncp_create: inode is NULL or not a directory\n");
- iput(dir);
+ printk(KERN_WARNING "ncp_create: inode is NULL or not a directory\n");
return -ENOENT;
}
- if (!ncp_conn_valid(NCP_SERVER(dir))) {
- iput(dir);
- return -EIO;
- }
- strncpy(_name, name, len);
- _name[len] = '\0';
+ error = -EIO;
+ if (!ncp_conn_valid(NCP_SERVER(dir)))
+ goto out;
+
+ strncpy(_name, dentry->d_name.name, dentry->d_name.len);
+ _name[dentry->d_name.len] = '\0';
if (!ncp_preserve_case(dir)) {
str_upper(_name);
}
- lock_super(dir->i_sb);
- if (ncp_open_create_file_or_subdir(NCP_SERVER(dir),
- NCP_ISTRUCT(dir), _name,
- OC_MODE_CREATE | OC_MODE_OPEN |
- OC_MODE_REPLACE,
- 0, AR_READ | AR_WRITE,
- &finfo) != 0) {
- unlock_super(dir->i_sb);
- iput(dir);
- return -EACCES;
- }
- ncp_invalid_dir_cache(dir);
- if (!ncp_preserve_case(dir)) {
- str_lower(finfo.i.entryName);
+ error = -EACCES;
+ result = ncp_open_create_file_or_subdir(NCP_SERVER(dir), dir, _name,
+ OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
+ 0, AR_READ | AR_WRITE, &finfo.nw_info);
+ if (!result) {
+ finfo.nw_info.access = O_RDWR;
+ error = ncp_instantiate(dir, dentry, &finfo);
+ } else {
+ DPRINTK(KERN_DEBUG "ncp_create: %s/%s failed\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
}
- finfo.access = O_RDWR;
- if (!(*result = ncp_iget(dir, &finfo)) < 0) {
- ncp_close_file(NCP_SERVER(dir), finfo.file_handle);
- unlock_super(dir->i_sb);
- iput(dir);
- return -EINVAL;
- }
- unlock_super(dir->i_sb);
- iput(dir);
- return 0;
+out:
+ return error;
}
-static int ncp_mkdir(struct inode *dir, const char *name, int len, int mode)
+static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
int error;
- struct nw_file_info new_dir;
- __u8 _name[len + 1];
-
- if ((name[0] == '.')
- && ((len == 1)
- || ((len == 2)
- && (name[1] == '.')))) {
- iput(dir);
- return -EEXIST;
+ struct ncpfs_inode_info finfo;
+ __u8 _name[dentry->d_name.len + 1];
+
+ DPRINTK(KERN_DEBUG "ncp_mkdir: making %s/%s\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
+ error = -ENOTDIR;
+ if (!dir || !S_ISDIR(dir->i_mode)) {
+ printk(KERN_WARNING "ncp_mkdir: inode is NULL or not a directory\n");
+ goto out;
}
- strncpy(_name, name, len);
- _name[len] = '\0';
+ error = -EIO;
+ if (!ncp_conn_valid(NCP_SERVER(dir)))
+ goto out;
+ strncpy(_name, dentry->d_name.name, dentry->d_name.len);
+ _name[dentry->d_name.len] = '\0';
if (!ncp_preserve_case(dir)) {
str_upper(_name);
}
- if (!dir || !S_ISDIR(dir->i_mode)) {
- printk("ncp_mkdir: inode is NULL or not a directory\n");
- iput(dir);
- return -ENOENT;
- }
- if (!ncp_conn_valid(NCP_SERVER(dir))) {
- iput(dir);
- return -EIO;
- }
- if (ncp_open_create_file_or_subdir(NCP_SERVER(dir),
- NCP_ISTRUCT(dir), _name,
+
+ error = -EACCES;
+ if (ncp_open_create_file_or_subdir(NCP_SERVER(dir), dir, _name,
OC_MODE_CREATE, aDIR, 0xffff,
- &new_dir) != 0) {
- error = -EACCES;
- } else {
- error = 0;
- ncp_invalid_dir_cache(dir);
+ &finfo.nw_info) == 0)
+ {
+ error = ncp_instantiate(dir, dentry, &finfo);
}
-
- iput(dir);
+out:
return error;
}
-static int ncp_rmdir(struct inode *dir, const char *name, int len)
+static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
{
- int error;
- __u8 _name[len + 1];
-
- if (!dir || !S_ISDIR(dir->i_mode)) {
- printk("ncp_rmdir: inode is NULL or not a directory\n");
- iput(dir);
- return -ENOENT;
- }
- if (!ncp_conn_valid(NCP_SERVER(dir))) {
- iput(dir);
- return -EIO;
- }
- if (ncp_find_dir_inode(dir, name) != NULL) {
- iput(dir);
+ int error, result;
+ __u8 _name[dentry->d_name.len + 1];
+
+ DPRINTK(KERN_DEBUG "ncp_rmdir: removing %s/%s\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
+
+ error = -ENOENT;
+ if (!dir || !S_ISDIR(dir->i_mode))
+ {
+ printk(KERN_WARNING "ncp_rmdir: inode is NULL or not a directory\n");
+ goto out;
+ }
+ error = -EIO;
+ if (!ncp_conn_valid(NCP_SERVER(dir)))
+ goto out;
+
+ if (dentry->d_count > 1)
+ {
+ shrink_dcache_parent(dentry);
error = -EBUSY;
- } else {
-
- strncpy(_name, name, len);
- _name[len] = '\0';
+ if (dentry->d_count > 1)
+ goto out;
+ }
- if (!ncp_preserve_case(dir)) {
- str_upper(_name);
- }
- if ((error = ncp_del_file_or_subdir(NCP_SERVER(dir),
- NCP_ISTRUCT(dir),
- _name)) == 0) {
- ncp_invalid_dir_cache(dir);
- } else {
- error = -EACCES;
- }
+ strncpy(_name, dentry->d_name.name, dentry->d_name.len);
+ _name[dentry->d_name.len] = '\0';
+
+ if (!ncp_preserve_case(dir))
+ {
+ str_upper(_name);
}
- iput(dir);
+ error = -EACCES;
+ result = ncp_del_file_or_subdir(NCP_SERVER(dir), dir, _name);
+ if (!result)
+ {
+ ncp_invalid_dir_cache(dir);
+ d_delete(dentry);
+ error = 0;
+ }
+out:
return error;
}
-static int ncp_unlink(struct inode *dir, const char *name, int len)
+static int ncp_unlink(struct inode *dir, struct dentry *dentry)
{
- int error;
- __u8 _name[len + 1];
-
+ struct inode *inode = dentry->d_inode;
+ int error, result;
+ __u8 _name[dentry->d_name.len + 1];
+
+ DPRINTK(KERN_DEBUG "ncp_unlink: unlinking %s/%s\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
+
+ error = -ENOTDIR;
if (!dir || !S_ISDIR(dir->i_mode)) {
- printk("ncp_unlink: inode is NULL or not a directory\n");
- iput(dir);
- return -ENOENT;
- }
- if (!ncp_conn_valid(NCP_SERVER(dir))) {
- iput(dir);
- return -EIO;
+ printk(KERN_WARNING "ncp_unlink: inode is NULL or not a directory\n");
+ goto out;
+ }
+ error = -EIO;
+ if (!ncp_conn_valid(NCP_SERVER(dir)))
+ goto out;
+
+ /*
+ * Check whether to close the file ...
+ */
+ if (inode && NCP_FINFO(inode)->opened) {
+#ifdef NCPFS_PARANOIA
+printk(KERN_DEBUG "ncp_unlink: closing file\n");
+#endif
+ ncp_make_closed(inode);
}
- if (ncp_find_dir_inode(dir, name) != NULL) {
- iput(dir);
- error = -EBUSY;
- } else {
- strncpy(_name, name, len);
- _name[len] = '\0';
- if (!ncp_preserve_case(dir)) {
- str_upper(_name);
- }
- if ((error = ncp_del_file_or_subdir(NCP_SERVER(dir),
- NCP_ISTRUCT(dir),
- _name)) == 0) {
- ncp_invalid_dir_cache(dir);
- } else {
- error = -EACCES;
- }
+ strncpy(_name, dentry->d_name.name, dentry->d_name.len);
+ _name[dentry->d_name.len] = '\0';
+ if (!ncp_preserve_case(dir))
+ {
+ str_upper(_name);
+ }
+ error = -EACCES;
+ result = ncp_del_file_or_subdir(NCP_SERVER(dir), dir, _name);
+ if (!result) {
+ DPRINTK(KERN_DEBUG "ncp: removed %s/%s\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
+ ncp_invalid_dir_cache(dir);
+ d_delete(dentry);
+ error = 0;
}
- iput(dir);
+out:
return error;
}
-static int ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
- struct inode *new_dir, const char *new_name, int new_len)
+static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry)
{
- int res;
- char _old_name[old_len + 1];
- char _new_name[new_len + 1];
+ int old_len = old_dentry->d_name.len;
+ int new_len = new_dentry->d_name.len;
+ int error, result;
+ char _old_name[old_dentry->d_name.len + 1];
+ char _new_name[new_dentry->d_name.len + 1];
+
+ DPRINTK(KERN_DEBUG "ncp_rename: %s/%s to %s/%s\n",
+ old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
+ new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
+ error = -ENOTDIR;
if (!old_dir || !S_ISDIR(old_dir->i_mode)) {
- printk("ncp_rename: old inode is NULL or not a directory\n");
- res = -ENOENT;
- goto finished;
- }
- if (!ncp_conn_valid(NCP_SERVER(old_dir))) {
- res = -EIO;
- goto finished;
+ printk(KERN_WARNING "ncp_rename: old inode is NULL or not a directory\n");
+ goto out;
}
if (!new_dir || !S_ISDIR(new_dir->i_mode)) {
- printk("ncp_rename: new inode is NULL or not a directory\n");
- res = -ENOENT;
- goto finished;
- }
- if ((ncp_find_dir_inode(old_dir, old_name) != NULL)
- || (ncp_find_dir_inode(new_dir, new_name) != NULL)) {
- res = -EBUSY;
- goto finished;
+ printk(KERN_WARNING "ncp_rename: new inode is NULL or not a directory\n");
+ goto out;
}
- strncpy(_old_name, old_name, old_len);
- _old_name[old_len] = '\0';
+ error = -EIO;
+ if (!ncp_conn_valid(NCP_SERVER(old_dir)))
+ goto out;
+ strncpy(_old_name, old_dentry->d_name.name, old_len);
+ _old_name[old_len] = '\0';
if (!ncp_preserve_case(old_dir)) {
str_upper(_old_name);
}
- strncpy(_new_name, new_name, new_len);
- _new_name[new_len] = '\0';
+ strncpy(_new_name, new_dentry->d_name.name, new_len);
+ _new_name[new_len] = '\0';
if (!ncp_preserve_case(new_dir)) {
str_upper(_new_name);
}
- res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
- NCP_ISTRUCT(old_dir), _old_name,
- NCP_ISTRUCT(new_dir), _new_name);
- if (res == 0) {
+ error = -EACCES;
+ result = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
+ old_dir, _old_name,
+ new_dir, _new_name);
+ if (result == 0)
+ {
+ DPRINTK(KERN_DEBUG "ncp renamed %s -> %s.\n",
+ old_dentry->d_name.name,new_dentry->d_name.name);
ncp_invalid_dir_cache(old_dir);
ncp_invalid_dir_cache(new_dir);
- } else {
- res = -EACCES;
+ d_move(old_dentry,new_dentry);
+ error = 0;
}
-
- finished:
- iput(old_dir);
- iput(new_dir);
- return res;
+out:
+ return error;
}
/* The following routines are taken directly from msdos-fs */
@@ -1024,7 +1033,7 @@ static int ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
static int day_n[] =
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
- /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
+/* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
extern struct timezone sys_tz;
@@ -1042,23 +1051,24 @@ static int local2utc(int time)
}
/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
-
-int ncp_date_dos2unix(unsigned short time, unsigned short date)
+int
+ncp_date_dos2unix(unsigned short time, unsigned short date)
{
int month, year, secs;
month = ((date >> 5) & 15) - 1;
year = date >> 9;
- secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 + 86400 *
- ((date & 31) - 1 + day_n[month] + (year / 4) + year * 365 - ((year & 3) == 0 &&
- month < 2 ? 1 : 0) + 3653);
+ secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 +
+ 86400 * ((date & 31) - 1 + day_n[month] + (year / 4) +
+ year * 365 - ((year & 3) == 0 && month < 2 ? 1 : 0) + 3653);
/* days since 1.1.70 plus 80's leap day */
return local2utc(secs);
}
/* Convert linear UNIX date to a MS-DOS time/date pair. */
-void ncp_date_unix2dos(int unix_date, unsigned short *time, unsigned short *date)
+void
+ncp_date_unix2dos(int unix_date, unsigned short *time, unsigned short *date)
{
int day, year, nl_day, month;
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index 9a2067848..2f22f25d1 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -2,6 +2,7 @@
* file.c
*
* Copyright (C) 1995, 1996 by Volker Lendecke
+ * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
*
*/
@@ -29,82 +30,113 @@ static int ncp_fsync(struct file *file, struct dentry *dentry)
return 0;
}
-int ncp_make_open(struct inode *i, int right)
+/*
+ * Open a file with the specified read/write mode.
+ */
+int ncp_make_open(struct inode *inode, int right)
{
- struct nw_file_info *finfo;
-
- if (i == NULL) {
- printk("ncp_make_open: got NULL inode\n");
- return -EINVAL;
+ int error, result;
+ int access;
+ struct nw_file_info finfo;
+
+ error = -EINVAL;
+ if (!inode) {
+ printk(KERN_ERR "ncp_make_open: got NULL inode\n");
+ goto out;
}
- finfo = NCP_FINFO(i);
-
- DPRINTK("ncp_make_open: dirent->opened = %d\n", finfo->opened);
- lock_super(i->i_sb);
- if (finfo->opened == 0) {
- finfo->access = -1;
+ DPRINTK(KERN_DEBUG "ncp_make_open: opened=%d, volume # %u, dir entry # %u\n",
+ NCP_FINFO(inode)->opened,
+ NCP_FINFO(inode)->volNumber,
+ NCP_FINFO(inode)->dirEntNum);
+ error = -EACCES;
+ lock_super(inode->i_sb);
+ if (!NCP_FINFO(inode)->opened) {
+ finfo.i.dirEntNum = NCP_FINFO(inode)->dirEntNum;
+ finfo.i.volNumber = NCP_FINFO(inode)->volNumber;
/* tries max. rights */
- if (ncp_open_create_file_or_subdir(NCP_SERVER(i),
- NULL, NULL,
- OC_MODE_OPEN, 0,
- AR_READ | AR_WRITE,
- finfo) == 0) {
- finfo->access = O_RDWR;
- } else if (ncp_open_create_file_or_subdir(NCP_SERVER(i),
- NULL, NULL,
- OC_MODE_OPEN, 0,
- AR_READ,
- finfo) == 0) {
- finfo->access = O_RDONLY;
+ finfo.access = O_RDWR;
+ result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
+ NULL, NULL, OC_MODE_OPEN,
+ 0, AR_READ | AR_WRITE, &finfo);
+ if (!result)
+ goto update;
+ finfo.access = O_RDONLY;
+ result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
+ NULL, NULL, OC_MODE_OPEN,
+ 0, AR_READ, &finfo);
+ if (!result) {
+#ifdef NCPFS_PARANOIA
+printk(KERN_DEBUG "ncp_make_open: failed, result=%d\n", result);
+#endif
+ goto out_unlock;
}
+ /*
+ * Update the inode information.
+ */
+ update:
+ ncp_update_inode(inode, &finfo);
}
- unlock_super(i->i_sb);
- if (((right == O_RDONLY) && ((finfo->access == O_RDONLY)
- || (finfo->access == O_RDWR)))
- || ((right == O_WRONLY) && ((finfo->access == O_WRONLY)
- || (finfo->access == O_RDWR)))
- || ((right == O_RDWR) && (finfo->access == O_RDWR)))
- return 0;
-
- return -EACCES;
+ access = NCP_FINFO(inode)->access;
+#ifdef NCPFS_PARANOIA
+printk(KERN_DEBUG "ncp_make_open: file open, access=%x\n", access);
+#endif
+ if (((right == O_RDONLY) && ((access == O_RDONLY)
+ || (access == O_RDWR)))
+ || ((right == O_WRONLY) && ((access == O_WRONLY)
+ || (access == O_RDWR)))
+ || ((right == O_RDWR) && (access == O_RDWR)))
+ error = 0;
+
+out_unlock:
+ unlock_super(inode->i_sb);
+out:
+ return error;
}
-static long ncp_file_read(struct inode *inode, struct file *file, char *buf, unsigned long count)
+static ssize_t
+ncp_file_read(struct file *file, char *buf, size_t count, loff_t *ppos)
{
- int bufsize, already_read;
+ struct dentry *dentry = file->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ size_t already_read = 0;
off_t pos;
- int errno;
+ int bufsize, error;
- DPRINTK("ncp_file_read: enter %s\n", NCP_ISTRUCT(inode)->entryName);
+ DPRINTK(KERN_DEBUG "ncp_file_read: enter %s/%s\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
+ error = -EINVAL;
if (inode == NULL) {
- DPRINTK("ncp_file_read: inode = NULL\n");
- return -EINVAL;
- }
- if (!ncp_conn_valid(NCP_SERVER(inode))) {
- return -EIO;
+ DPRINTK(KERN_DEBUG "ncp_file_read: inode = NULL\n");
+ goto out;
}
+ error = -EIO;
+ if (!ncp_conn_valid(NCP_SERVER(inode)))
+ goto out;
+ error = -EINVAL;
if (!S_ISREG(inode->i_mode)) {
- DPRINTK("ncp_file_read: read from non-file, mode %07o\n",
+ DPRINTK(KERN_DEBUG "ncp_file_read: read from non-file, mode %07o\n",
inode->i_mode);
- return -EINVAL;
+ goto out;
}
- pos = file->f_pos;
+ pos = file->f_pos;
if (pos + count > inode->i_size) {
count = inode->i_size - pos;
}
- if (count <= 0) {
- return 0;
- }
- if ((errno = ncp_make_open(inode, O_RDONLY)) != 0) {
- return errno;
+ error = 0;
+ if (!count) /* size_t is never < 0 */
+ goto out;
+
+ error = ncp_make_open(inode, O_RDONLY);
+ if (error) {
+ printk(KERN_ERR "ncp_file_read: open failed, error=%d\n", error);
+ goto out;
}
- bufsize = NCP_SERVER(inode)->buffer_size;
- already_read = 0;
+ bufsize = NCP_SERVER(inode)->buffer_size;
/* First read in as much as possible for each bufsize. */
while (already_read < count) {
@@ -112,9 +144,12 @@ static long ncp_file_read(struct inode *inode, struct file *file, char *buf, uns
int to_read = min(bufsize - (pos % bufsize),
count - already_read);
- if (ncp_read(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
- pos, to_read, buf, &read_this_time) != 0) {
- return -EIO; /* This is not exact, i know.. */
+ error = ncp_read(NCP_SERVER(inode),
+ NCP_FINFO(inode)->file_handle,
+ pos, to_read, buf, &read_this_time);
+ if (error) {
+ error = -EIO; /* This is not exact, i know.. */
+ goto out;
}
pos += read_this_time;
buf += read_this_time;
@@ -130,38 +165,43 @@ static long ncp_file_read(struct inode *inode, struct file *file, char *buf, uns
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
}
- mark_inode_dirty(inode);
- DPRINTK("ncp_file_read: exit %s\n", NCP_ISTRUCT(inode)->entryName);
-
- return already_read;
+ DPRINTK(KERN_DEBUG "ncp_file_read: exit %s/%s\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
+out:
+ return already_read ? already_read : error;
}
-static long ncp_file_write(struct inode *inode, struct file *file, const char *buf,
- unsigned long count)
+static ssize_t
+ncp_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
- int bufsize, already_written;
+ struct dentry *dentry = file->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ size_t already_written = 0;
off_t pos;
- int errno;
+ int bufsize, errno;
+ DPRINTK(KERN_DEBUG "ncp_file_write: enter %s/%s\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
if (inode == NULL) {
- DPRINTK("ncp_file_write: inode = NULL\n");
+ DPRINTK(KERN_DEBUG "ncp_file_write: inode = NULL\n");
return -EINVAL;
}
- if (!ncp_conn_valid(NCP_SERVER(inode))) {
- return -EIO;
- }
+ errno = -EIO;
+ if (!ncp_conn_valid(NCP_SERVER(inode)))
+ goto out;
if (!S_ISREG(inode->i_mode)) {
- DPRINTK("ncp_file_write: write to non-file, mode %07o\n",
+ DPRINTK(KERN_DEBUG "ncp_file_write: write to non-file, mode %07o\n",
inode->i_mode);
return -EINVAL;
}
- DPRINTK("ncp_file_write: enter %s\n", NCP_ISTRUCT(inode)->entryName);
- if (count <= 0) {
- return 0;
- }
- if ((errno = ncp_make_open(inode, O_RDWR)) != 0) {
+ errno = 0;
+ if (!count)
+ goto out;
+ errno = ncp_make_open(inode, O_RDWR);
+ if (errno) {
+ printk(KERN_ERR "ncp_file_write: open failed, error=%d\n", errno);
return errno;
}
pos = file->f_pos;
@@ -192,17 +232,17 @@ static long ncp_file_write(struct inode *inode, struct file *file, const char *b
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- mark_inode_dirty(inode);
file->f_pos = pos;
if (pos > inode->i_size) {
inode->i_size = pos;
- ncp_invalid_dir_cache(NCP_INOP(inode)->dir->inode);
+ ncp_invalid_dir_cache(dentry->d_parent->d_inode);
}
- DPRINTK("ncp_file_write: exit %s\n", NCP_ISTRUCT(inode)->entryName);
-
- return already_written;
+ DPRINTK(KERN_DEBUG "ncp_file_write: exit %s/%s\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
+out:
+ return already_written ? already_written : errno;
}
static struct file_operations ncp_file_operations =
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index 2e903151e..61cdd0319 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 1995, 1996 by Volker Lendecke
* Modified for big endian by J.F. Chadima and David S. Miller
+ * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
*
*/
@@ -14,7 +15,6 @@
#include <asm/byteorder.h>
#include <linux/sched.h>
-#include <linux/ncp_fs.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
@@ -28,84 +28,108 @@
#ifdef CONFIG_KERNELD
#include <linux/kerneld.h>
#endif
+
+#include <linux/ncp_fs.h>
#include "ncplib_kernel.h"
extern int close_fp(struct file *filp);
-static void ncp_put_inode(struct inode *);
static void ncp_read_inode(struct inode *);
+static void ncp_put_inode(struct inode *);
+static void ncp_delete_inode(struct inode *);
+static int ncp_notify_change(struct inode *, struct iattr *);
static void ncp_put_super(struct super_block *);
-static void ncp_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
-static int ncp_notify_change(struct inode *inode, struct iattr *attr);
+static int ncp_statfs(struct super_block *, struct statfs *, int);
static struct super_operations ncp_sops =
{
ncp_read_inode, /* read inode */
- ncp_notify_change, /* notify change */
NULL, /* write inode */
ncp_put_inode, /* put inode */
+ ncp_delete_inode, /* delete inode */
+ ncp_notify_change, /* notify change */
ncp_put_super, /* put superblock */
NULL, /* write superblock */
ncp_statfs, /* stat filesystem */
- NULL
+ NULL /* remount */
};
-/* ncp_read_inode: Called from iget, it only traverses the allocated
- ncp_inode_info's and initializes the inode from the data found
- there. It does not allocate or deallocate anything. */
+static struct nw_file_info *read_nwinfo = NULL;
+static struct semaphore read_sem = MUTEX;
-static void ncp_read_inode(struct inode *inode)
+/*
+ * Fill in the ncpfs-specific information in the inode.
+ */
+void ncp_update_inode(struct inode *inode, struct nw_file_info *nwinfo)
{
- /* Our task should be extremely simple here. We only have to
- look up the information somebody else (ncp_iget) put into
- the inode tree. The address of this information is the
- inode->i_ino. Just to make sure everything went well, we
- check it's there. */
-
- struct ncp_inode_info *inode_info = ncp_find_inode(inode);
-
- if (inode_info == NULL) {
- /* Ok, now we're in trouble. The inode info is not there. What
- should we do now??? */
- printk("ncp_read_inode: inode info not found\n");
- return;
- }
- inode_info->state = NCP_INODE_VALID;
+ NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
+ NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
+ NCP_FINFO(inode)->volNumber = nwinfo->i.volNumber;
+
+ NCP_FINFO(inode)->opened = nwinfo->opened;
+ NCP_FINFO(inode)->access = nwinfo->access;
+ NCP_FINFO(inode)->server_file_handle = nwinfo->server_file_handle;
+ memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
+ sizeof(nwinfo->file_handle));
+#ifdef NCPFS_DEBUG_VERBOSE
+printk(KERN_DEBUG "ncp_update_inode: updated %s, volnum=%d, dirent=%u\n",
+nwinfo->i.entryName, NCP_FINFO(inode)->volNumber, NCP_FINFO(inode)->dirEntNum);
+#endif
+}
- NCP_INOP(inode) = inode_info;
- inode_info->inode = inode;
+/*
+ * Fill in the inode based on the nw_file_info structure.
+ */
+static void ncp_set_attr(struct inode *inode, struct nw_file_info *nwinfo)
+{
+ struct nw_info_struct *nwi = &nwinfo->i;
+ struct ncp_server *server = NCP_SERVER(inode);
- if (NCP_ISTRUCT(inode)->attributes & aDIR) {
- inode->i_mode = NCP_SERVER(inode)->m.dir_mode;
+ if (nwi->attributes & aDIR) {
+ inode->i_mode = server->m.dir_mode;
/* for directories dataStreamSize seems to be some
Object ID ??? */
inode->i_size = 512;
} else {
- inode->i_mode = NCP_SERVER(inode)->m.file_mode;
- inode->i_size = le32_to_cpu(NCP_ISTRUCT(inode)->dataStreamSize);
+ inode->i_mode = server->m.file_mode;
+ inode->i_size = le32_to_cpu(nwi->dataStreamSize);
}
- DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
+ DDPRINTK(KERN_DEBUG "ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
inode->i_nlink = 1;
- inode->i_uid = NCP_SERVER(inode)->m.uid;
- inode->i_gid = NCP_SERVER(inode)->m.gid;
+ inode->i_uid = server->m.uid;
+ inode->i_gid = server->m.gid;
inode->i_blksize = 512;
inode->i_rdev = 0;
+ inode->i_blocks = 0;
if ((inode->i_blksize != 0) && (inode->i_size != 0)) {
inode->i_blocks =
(inode->i_size - 1) / inode->i_blksize + 1;
- } else {
- inode->i_blocks = 0;
}
- inode->i_mtime = ncp_date_dos2unix(le16_to_cpu(NCP_ISTRUCT(inode)->modifyTime),
- le16_to_cpu(NCP_ISTRUCT(inode)->modifyDate));
- inode->i_ctime = ncp_date_dos2unix(le16_to_cpu(NCP_ISTRUCT(inode)->creationTime),
- le16_to_cpu(NCP_ISTRUCT(inode)->creationDate));
+ inode->i_mtime = ncp_date_dos2unix(le16_to_cpu(nwi->modifyTime),
+ le16_to_cpu(nwi->modifyDate));
+ inode->i_ctime = ncp_date_dos2unix(le16_to_cpu(nwi->creationTime),
+ le16_to_cpu(nwi->creationDate));
inode->i_atime = ncp_date_dos2unix(0,
- le16_to_cpu(NCP_ISTRUCT(inode)->lastAccessDate));
+ le16_to_cpu(nwi->lastAccessDate));
+ ncp_update_inode(inode, nwinfo);
+}
+
+/*
+ * This is called from iget() with the read semaphore held.
+ * The global ncpfs_file_info structure has been set up by ncp_iget.
+ */
+static void ncp_read_inode(struct inode *inode)
+{
+ if (read_nwinfo == NULL) {
+ printk(KERN_ERR "ncp_read_inode: invalid call\n");
+ return;
+ }
+
+ ncp_set_attr(inode, read_nwinfo);
if (S_ISREG(inode->i_mode)) {
inode->i_op = &ncp_file_inode_operations;
@@ -116,73 +140,103 @@ static void ncp_read_inode(struct inode *inode)
}
}
-static void ncp_put_inode(struct inode *inode)
+/*
+ * Set up the ncpfs_inode_info pointer and get a new inode.
+ */
+struct inode *
+ncp_iget(struct super_block *sb, struct ncpfs_inode_info *info)
{
- struct nw_file_info *finfo = NCP_FINFO(inode);
- struct super_block *sb = inode->i_sb;
+ struct inode *inode;
- lock_super(sb);
- if (finfo->opened != 0) {
- if (ncp_close_file(NCP_SERVER(inode), finfo->file_handle) != 0) {
- /* We can't do anything but complain. */
- printk("ncp_put_inode: could not close\n");
- }
+ if (info == NULL) {
+ printk(KERN_ERR "ncp_iget: info is NULL\n");
+ return NULL;
}
- DDPRINTK("ncp_put_inode: put %s\n",
- finfo->i.entryName);
- ncp_free_inode_info(NCP_INOP(inode));
+ down(&read_sem);
+ read_nwinfo = &info->nw_info;
+ inode = iget(sb, info->ino);
+ read_nwinfo = NULL;
+ up(&read_sem);
+ if (!inode)
+ printk(KERN_ERR "ncp_iget: iget failed!\n");
+ return inode;
+}
+
+static void ncp_put_inode(struct inode *inode)
+{
+ if (inode->i_count == 1)
+ inode->i_nlink = 0;
+}
+static void
+ncp_delete_inode(struct inode *inode)
+{
if (S_ISDIR(inode->i_mode)) {
- DDPRINTK("ncp_put_inode: put directory %ld\n",
- inode->i_ino);
+ DDPRINTK(KERN_DEBUG "ncp_delete_inode: put directory %ld\n", inode->i_ino);
ncp_invalid_dir_cache(inode);
}
+
+ if (NCP_FINFO(inode)->opened && ncp_make_closed(inode) != 0) {
+ /* We can't do anything but complain. */
+ printk(KERN_ERR "ncp_delete_inode: could not close\n");
+ }
clear_inode(inode);
- unlock_super(sb);
+}
+
+static void ncp_init_root(struct ncp_server *server,
+ struct ncpfs_inode_info *info)
+{
+ struct ncp_inode_info *root = &(server->root);
+ struct nw_info_struct *i = &(root->finfo.i);
+ unsigned short dummy;
+
+ DPRINTK(KERN_DEBUG "ncp_init_root: i = %x\n", (int) i);
+
+ i->attributes = aDIR;
+ i->dataStreamSize= 1024;
+ i->dirEntNum = 0;
+ i->DosDirNum = 0;
+ i->volNumber = NCP_NUMBER_OF_VOLUMES + 1; /* illegal volnum */
+ ncp_date_unix2dos(0, &(i->creationTime), &(i->creationDate));
+ ncp_date_unix2dos(0, &(i->modifyTime ), &(i->modifyDate));
+ ncp_date_unix2dos(0, &(dummy ), &(i->lastAccessDate));
+ i->creationTime = le16_to_cpu(i->creationTime);
+ i->creationDate = le16_to_cpu(i->creationDate);
+ i->modifyTime = le16_to_cpu(i->modifyTime);
+ i->modifyDate = le16_to_cpu(i->modifyDate);
+ i->lastAccessDate= le16_to_cpu(i->lastAccessDate);
+ i->nameLen = 0;
+ i->entryName[0] = '\0';
+
+ root->finfo.opened= 0;
+ info->ino = 1;
+ info->nw_info = root->finfo;
}
struct super_block *
- ncp_read_super(struct super_block *sb, void *raw_data, int silent)
+ncp_read_super(struct super_block *sb, void *raw_data, int silent)
{
struct ncp_mount_data *data = (struct ncp_mount_data *) raw_data;
struct ncp_server *server;
struct file *ncp_filp;
+ struct inode *root_inode;
kdev_t dev = sb->s_dev;
int error;
+ struct ncpfs_inode_info finfo;
- if (data == NULL) {
- printk("ncp_read_super: missing data argument\n");
- sb->s_dev = 0;
- return NULL;
- }
- if (data->version != NCP_MOUNT_VERSION) {
- printk("ncp warning: mount version %s than kernel\n",
- (data->version < NCP_MOUNT_VERSION) ?
- "older" : "newer");
- sb->s_dev = 0;
- return NULL;
- }
- if ((data->ncp_fd >= NR_OPEN)
- || ((ncp_filp = current->files->fd[data->ncp_fd]) == NULL)
- || (!S_ISSOCK(ncp_filp->f_dentry->d_inode->i_mode))) {
- printk("ncp_read_super: invalid ncp socket\n");
- sb->s_dev = 0;
- return NULL;
- }
- /* We must malloc our own super-block info */
- server = (struct ncp_server *) ncp_kmalloc(sizeof(struct ncp_server),
- GFP_KERNEL);
-
- if (server == NULL) {
- printk("ncp_read_super: could not alloc ncp_server\n");
- return NULL;
- }
- ncp_filp->f_count++;
+ MOD_INC_USE_COUNT;
+ if (data == NULL)
+ goto out_no_data;
+ if (data->version != NCP_MOUNT_VERSION)
+ goto out_bad_mount;
+ if ((data->ncp_fd >= NR_OPEN) ||
+ ((ncp_filp = current->files->fd[data->ncp_fd]) == NULL) ||
+ !S_ISSOCK(ncp_filp->f_dentry->d_inode->i_mode))
+ goto out_bad_file;
lock_super(sb);
-
- NCP_SBP(sb) = server;
+ ncp_filp->f_count++;
sb->s_blocksize = 1024; /* Eh... Is this correct? */
sb->s_blocksize_bits = 10;
@@ -190,6 +244,13 @@ struct super_block *
sb->s_dev = dev;
sb->s_op = &ncp_sops;
+ /* We must malloc our own super-block info */
+ server = (struct ncp_server *) ncp_kmalloc(sizeof(struct ncp_server),
+ GFP_KERNEL);
+ if (server == NULL)
+ goto out_no_server;
+ NCP_SBP(sb) = server;
+
server->ncp_filp = ncp_filp;
server->lock = 0;
server->wait = NULL;
@@ -202,7 +263,7 @@ struct super_block *
now because of PATH_MAX changes.. */
if (server->m.time_out < 10) {
server->m.time_out = 10;
- printk("You need to recompile your ncpfs utils..\n");
+ printk(KERN_INFO "You need to recompile your ncpfs utils..\n");
}
server->m.file_mode = (server->m.file_mode &
(S_IRWXU | S_IRWXG | S_IRWXO)) | S_IFREG;
@@ -211,54 +272,74 @@ struct super_block *
server->packet_size = NCP_PACKET_SIZE;
server->packet = ncp_kmalloc(NCP_PACKET_SIZE, GFP_KERNEL);
+ if (server->packet == NULL)
+ goto out_no_packet;
- if (server->packet == NULL) {
- printk("ncpfs: could not alloc packet\n");
- error = -ENOMEM;
- unlock_super(sb);
- goto fail;
- }
ncp_lock_server(server);
error = ncp_connect(server);
ncp_unlock_server(server);
- unlock_super(sb);
-
- if (error < 0) {
- sb->s_dev = 0;
- printk("ncp_read_super: Failed connection, bailing out "
- "(error = %d).\n", -error);
- ncp_kfree_s(server->packet, server->packet_size);
- goto fail;
- }
- DPRINTK("ncp_read_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
+ if (error < 0)
+ goto out_no_connect;
+ DPRINTK(KERN_DEBUG "ncp_read_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
+
+ error = ncp_negotiate_buffersize(server, NCP_DEFAULT_BUFSIZE,
+ &(server->buffer_size));
+ if (error)
+ goto out_no_bufsize;
+ DPRINTK(KERN_DEBUG "ncpfs: bufsize = %d\n", server->buffer_size);
+
+ ncp_init_root(server, &finfo);
+ root_inode = ncp_iget(sb, &finfo);
+ if (!root_inode)
+ goto out_no_root;
+ DPRINTK(KERN_DEBUG "ncp_read_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
+ sb->s_root = d_alloc_root(root_inode, NULL);
+ if (!sb->s_root)
+ goto out_no_root;
- ncp_init_root(server);
-
- if (!(sb->s_root = d_alloc_root(iget(sb,ncp_info_ino(server,
- &(server->root))),NULL))) {
- sb->s_dev = 0;
- printk("ncp_read_super: get root inode failed\n");
- goto disconnect;
- }
- if (ncp_negotiate_buffersize(server, NCP_DEFAULT_BUFSIZE,
- &(server->buffer_size)) != 0) {
- sb->s_dev = 0;
- printk("ncp_read_super: could not get bufsize\n");
- goto disconnect;
- }
- DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
-
- MOD_INC_USE_COUNT;
+ unlock_super(sb);
return sb;
- disconnect:
+out_no_root:
+ printk(KERN_ERR "ncp_read_super: get root inode failed\n");
+ iput(root_inode);
+ goto out_disconnect;
+out_no_bufsize:
+ printk(KERN_ERR "ncp_read_super: could not get bufsize\n");
+out_disconnect:
ncp_lock_server(server);
ncp_disconnect(server);
ncp_unlock_server(server);
+ goto out_free_packet;
+out_no_connect:
+ printk(KERN_ERR "ncp_read_super: Failed connection, error=%d\n", error);
+out_free_packet:
ncp_kfree_s(server->packet, server->packet_size);
- fail:
- put_filp(ncp_filp);
+ goto out_free_server;
+out_no_packet:
+ printk(KERN_ERR "ncp_read_super: could not alloc packet\n");
+out_free_server:
ncp_kfree_s(NCP_SBP(sb), sizeof(struct ncp_server));
+ goto out_unlock;
+out_no_server:
+ printk(KERN_ERR "ncp_read_super: could not alloc ncp_server\n");
+out_unlock:
+ put_filp(ncp_filp);
+ unlock_super(sb);
+ goto out;
+
+out_bad_file:
+ printk(KERN_ERR "ncp_read_super: invalid ncp socket\n");
+ goto out;
+out_bad_mount:
+ printk(KERN_INFO "ncp_read_super: kernel requires mount version %d\n",
+ NCP_MOUNT_VERSION);
+ goto out;
+out_no_data:
+ printk(KERN_ERR "ncp_read_super: missing data argument\n");
+out:
+ sb->s_dev = 0;
+ MOD_DEC_USE_COUNT;
return NULL;
}
@@ -275,20 +356,17 @@ static void ncp_put_super(struct super_block *sb)
close_fp(server->ncp_filp);
kill_proc(server->m.wdog_pid, SIGTERM, 0);
- ncp_free_all_inodes(server);
-
ncp_kfree_s(server->packet, server->packet_size);
- sb->s_dev = 0;
ncp_kfree_s(NCP_SBP(sb), sizeof(struct ncp_server));
- NCP_SBP(sb) = NULL;
+ sb->s_dev = 0;
unlock_super(sb);
MOD_DEC_USE_COUNT;
}
-static void ncp_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int ncp_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
{
struct statfs tmp;
@@ -306,7 +384,7 @@ static void ncp_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
tmp.f_files = -1;
tmp.f_ffree = -1;
tmp.f_namelen = 12;
- copy_to_user(buf, &tmp, bufsiz);
+ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
}
static int ncp_notify_change(struct inode *inode, struct iattr *attr)
@@ -359,11 +437,9 @@ static int ncp_notify_change(struct inode *inode, struct iattr *attr)
info.lastAccessDate = le16_to_cpu(info.lastAccessDate);
}
if (info_mask != 0) {
- if ((result =
- ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
- NCP_ISTRUCT(inode),
- info_mask,
- &info)) != 0) {
+ result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
+ inode, info_mask, &info);
+ if (result != 0) {
result = -EACCES;
if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
@@ -379,8 +455,7 @@ static int ncp_notify_change(struct inode *inode, struct iattr *attr)
if ((attr->ia_valid & ATTR_SIZE) != 0) {
int written;
- DPRINTK("ncpfs: trying to change size of %s to %ld\n",
- NCP_ISTRUCT(inode)->entryName, attr->ia_size);
+ DPRINTK(KERN_DEBUG "ncpfs: trying to change size to %ld\n", attr->ia_size);
if ((result = ncp_make_open(inode, O_RDWR)) < 0) {
return -EACCES;
@@ -390,13 +465,12 @@ static int ncp_notify_change(struct inode *inode, struct iattr *attr)
/* According to ndir, the changes only take effect after
closing the file */
- ncp_close_file(NCP_SERVER(inode),
- NCP_FINFO(inode)->file_handle);
- NCP_FINFO(inode)->opened = 0;
-
- result = 0;
+ result = ncp_make_closed(inode);
}
- ncp_invalid_dir_cache(NCP_INOP(inode)->dir->inode);
+ /*
+ * We need a dentry here ...
+ */
+ /* ncp_invalid_dir_cache(NCP_INOP(inode)->dir->inode); */
return result;
}
@@ -423,7 +497,10 @@ EXPORT_NO_SYMBOLS;
int init_module(void)
{
- DPRINTK("ncpfs: init_module called\n");
+ DPRINTK(KERN_DEBUG "ncpfs: init_module called\n");
+
+ read_sem = MUTEX;
+ read_nwinfo = NULL;
#ifdef DEBUG_NCP_MALLOC
ncp_malloced = 0;
@@ -436,12 +513,12 @@ int init_module(void)
void cleanup_module(void)
{
- DPRINTK("ncpfs: cleanup_module called\n");
+ DPRINTK(KERN_DEBUG "ncpfs: cleanup_module called\n");
ncp_free_dir_cache();
unregister_filesystem(&ncp_fs_type);
#ifdef DEBUG_NCP_MALLOC
- printk("ncp_malloced: %d\n", ncp_malloced);
- printk("ncp_current_malloced: %d\n", ncp_current_malloced);
+ printk(KERN_DEBUG "ncp_malloced: %d\n", ncp_malloced);
+ printk(KERN_DEBUG "ncp_current_malloced: %d\n", ncp_current_malloced);
#endif
}
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
index 9b88c3c9f..e9f0ca86c 100644
--- a/fs/ncpfs/ioctl.c
+++ b/fs/ncpfs/ioctl.c
@@ -2,25 +2,27 @@
* ioctl.c
*
* Copyright (C) 1995, 1996 by Volker Lendecke
+ * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
*
*/
#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/fs.h>
-#include <linux/ncp_fs.h>
#include <linux/ioctl.h>
#include <linux/sched.h>
#include <linux/mm.h>
+
#include <linux/ncp.h>
+#include <linux/ncp_fs.h>
int ncp_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
+ struct ncp_server *server = NCP_SERVER(inode);
int result;
struct ncp_ioctl_request request;
struct ncp_fs_info info;
- struct ncp_server *server = NCP_SERVER(inode);
switch (cmd) {
case NCP_IOC_NCPREQUEST:
@@ -56,7 +58,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
ncp_request(server, request.function);
- DPRINTK("ncp_ioctl: copy %d bytes\n",
+ DPRINTK(KERN_DEBUG "ncp_ioctl: copy %d bytes\n",
server->reply_size);
copy_to_user(request.data, server->packet, server->reply_size);
@@ -82,19 +84,18 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
sizeof(info))) != 0) {
return result;
}
- copy_from_user(&info, (struct ncp_fs_info *) arg,
- sizeof(info));
+ copy_from_user(&info, (struct ncp_fs_info *) arg, sizeof(info));
if (info.version != NCP_GET_FS_INFO_VERSION) {
- DPRINTK("info.version invalid: %d\n", info.version);
+ DPRINTK(KERN_DEBUG "info.version invalid: %d\n", info.version);
return -EINVAL;
}
/* TODO: info.addr = server->m.serv_addr; */
- info.mounted_uid = server->m.mounted_uid;
- info.connection = server->connection;
- info.buffer_size = server->buffer_size;
- info.volume_number = NCP_ISTRUCT(inode)->volNumber;
- info.directory_id = NCP_ISTRUCT(inode)->DosDirNum;
+ info.mounted_uid = server->m.mounted_uid;
+ info.connection = server->connection;
+ info.buffer_size = server->buffer_size;
+ info.volume_number = NCP_FINFO(inode)->volNumber;
+ info.directory_id = NCP_FINFO(inode)->DosDirNum;
copy_to_user((struct ncp_fs_info *) arg, &info, sizeof(info));
return 0;
diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c
index 5dfdeb27f..56275034d 100644
--- a/fs/ncpfs/mmap.c
+++ b/fs/ncpfs/mmap.c
@@ -2,6 +2,7 @@
* mmap.c
*
* Copyright (C) 1995, 1996 by Volker Lendecke
+ * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
*
*/
@@ -32,7 +33,8 @@ static inline int min(int a, int b)
static unsigned long ncp_file_mmap_nopage(struct vm_area_struct *area,
unsigned long address, int no_share)
{
- struct inode *inode = area->vm_dentry->d_inode;
+ struct dentry *dentry = area->vm_dentry;
+ struct inode *inode = dentry->d_inode;
unsigned long page;
unsigned int clear;
unsigned long tmp;
@@ -120,7 +122,7 @@ int ncp_mmap(struct file *file, struct vm_area_struct *vma)
{
struct inode *inode = file->f_dentry->d_inode;
- DPRINTK("ncp_mmap: called\n");
+ DPRINTK(KERN_DEBUG "ncp_mmap: called\n");
if (!ncp_conn_valid(NCP_SERVER(inode))) {
return -EIO;
@@ -132,7 +134,6 @@ int ncp_mmap(struct file *file, struct vm_area_struct *vma)
return -EACCES;
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
- mark_inode_dirty(inode);
}
vma->vm_dentry = dget(file->f_dentry);
diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c
index f7d4de4a1..8d60732ef 100644
--- a/fs/ncpfs/ncplib_kernel.c
+++ b/fs/ncpfs/ncplib_kernel.c
@@ -3,9 +3,11 @@
*
* Copyright (C) 1995, 1996 by Volker Lendecke
* Modified for big endian by J.F. Chadima and David S. Miller
+ * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
*
*/
+
#include "ncplib_kernel.h"
static inline int min(int a, int b)
@@ -16,7 +18,7 @@ static inline int min(int a, int b)
static void assert_server_locked(struct ncp_server *server)
{
if (server->lock == 0) {
- DPRINTK("ncpfs: server not locked!\n");
+ DPRINTK(KERN_DEBUG "ncpfs: server not locked!\n");
}
}
@@ -65,7 +67,7 @@ static void ncp_add_pstring(struct ncp_server *server, const char *s)
int len = strlen(s);
assert_server_locked(server);
if (len > 255) {
- DPRINTK("ncpfs: string too long: %s\n", s);
+ DPRINTK(KERN_DEBUG "ncpfs: string too long: %s\n", s);
len = 255;
}
ncp_add_byte(server, len);
@@ -115,8 +117,8 @@ static __u32
return get_unaligned((__u32 *) ncp_reply_data(server, offset));
}
-int ncp_negotiate_buffersize(struct ncp_server *server,
- int size, int *target)
+int
+ncp_negotiate_buffersize(struct ncp_server *server, int size, int *target)
{
int result;
@@ -133,7 +135,8 @@ int ncp_negotiate_buffersize(struct ncp_server *server,
return 0;
}
-int ncp_get_volume_info_with_number(struct ncp_server *server, int n,
+int
+ncp_get_volume_info_with_number(struct ncp_server *server, int n,
struct ncp_volume_info *target)
{
int result;
@@ -143,8 +146,7 @@ int ncp_get_volume_info_with_number(struct ncp_server *server, int n,
ncp_add_byte(server, n);
if ((result = ncp_request(server, 22)) != 0) {
- ncp_unlock_server(server);
- return result;
+ goto out;
}
target->total_blocks = ncp_reply_dword(server, 0);
target->free_blocks = ncp_reply_dword(server, 4);
@@ -156,18 +158,21 @@ int ncp_get_volume_info_with_number(struct ncp_server *server, int n,
memset(&(target->volume_name), 0, sizeof(target->volume_name));
+ result = -EIO;
len = ncp_reply_byte(server, 29);
if (len > NCP_VOLNAME_LEN) {
- DPRINTK("ncpfs: volume name too long: %d\n", len);
- ncp_unlock_server(server);
- return -EIO;
+ DPRINTK(KERN_DEBUG "ncpfs: volume name too long: %d\n", len);
+ goto out;
}
memcpy(&(target->volume_name), ncp_reply_data(server, 30), len);
+ result = 0;
+out:
ncp_unlock_server(server);
- return 0;
+ return result;
}
-int ncp_close_file(struct ncp_server *server, const char *file_id)
+int
+ncp_close_file(struct ncp_server *server, const char *file_id)
{
int result;
@@ -180,10 +185,25 @@ int ncp_close_file(struct ncp_server *server, const char *file_id)
return result;
}
-static void ncp_add_handle_path(struct ncp_server *server,
- __u8 vol_num,
- __u32 dir_base, int have_dir_base,
- char *path)
+/*
+ * Called with the superblock locked.
+ */
+int
+ncp_make_closed(struct inode *inode)
+{
+ int err;
+ NCP_FINFO(inode)->opened = 0;
+ err = ncp_close_file(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle);
+#ifdef NCPFS_PARANOIA
+if (!err)
+printk(KERN_DEBUG "ncp_make_closed: volnum=%d, dirent=%u, error=%d\n",
+NCP_FINFO(inode)->volNumber, NCP_FINFO(inode)->dirEntNum, err);
+#endif
+ return err;
+}
+
+static void ncp_add_handle_path(struct ncp_server *server, __u8 vol_num,
+ __u32 dir_base, int have_dir_base, char *path)
{
ncp_add_byte(server, vol_num);
ncp_add_dword(server, dir_base);
@@ -213,34 +233,40 @@ static void ncp_extract_file_info(void *structure, struct nw_info_struct *target
return;
}
-int ncp_obtain_info(struct ncp_server *server,
- __u8 vol_num, __u32 dir_base,
- char *path, /* At most 1 component */
- struct nw_info_struct *target)
+/*
+ * Returns information for a (one-component) name relative to
+ * the specified directory.
+ */
+int ncp_obtain_info(struct ncp_server *server, struct inode *dir, char *path,
+ struct nw_info_struct *target)
{
+ __u8 volnum = NCP_FINFO(dir)->volNumber;
+ __u32 dirent = NCP_FINFO(dir)->dirEntNum;
int result;
if (target == NULL) {
+ printk(KERN_ERR "ncp_obtain_info: invalid call\n");
return -EINVAL;
}
ncp_init_request(server);
ncp_add_byte(server, 6); /* subfunction */
- ncp_add_byte(server, server->name_space[vol_num]);
- ncp_add_byte(server, server->name_space[vol_num]);
+ ncp_add_byte(server, server->name_space[volnum]);
+ ncp_add_byte(server, server->name_space[volnum]); /* N.B. twice ?? */
ncp_add_word(server, htons(0xff00)); /* get all */
ncp_add_dword(server, RIM_ALL);
- ncp_add_handle_path(server, vol_num, dir_base, 1, path);
+ ncp_add_handle_path(server, volnum, dirent, 1, path);
- if ((result = ncp_request(server, 87)) != 0) {
- ncp_unlock_server(server);
- return result;
- }
+ if ((result = ncp_request(server, 87)) != 0)
+ goto out;
ncp_extract_file_info(ncp_reply_data(server, 0), target);
+
+out:
ncp_unlock_server(server);
- return 0;
+ return result;
}
-static inline int ncp_has_os2_namespace(struct ncp_server *server, __u8 volume)
+static inline int
+ncp_has_os2_namespace(struct ncp_server *server, __u8 volume)
{
int result;
__u8 *namespace;
@@ -253,34 +279,36 @@ static inline int ncp_has_os2_namespace(struct ncp_server *server, __u8 volume)
if ((result = ncp_request(server, 87)) != 0) {
ncp_unlock_server(server);
- return 0;
+ return 0; /* not result ?? */
}
no_namespaces = ncp_reply_word(server, 0);
namespace = ncp_reply_data(server, 2);
+ result = 1;
while (no_namespaces > 0) {
- DPRINTK("get_namespaces: found %d on %d\n", *namespace, volume);
+ DPRINTK(KERN_DEBUG "get_namespaces: found %d on %d\n", *namespace, volume);
if (*namespace == 4) {
- DPRINTK("get_namespaces: found OS2\n");
- ncp_unlock_server(server);
- return 1;
+ DPRINTK(KERN_DEBUG "get_namespaces: found OS2\n");
+ goto out;
}
namespace += 1;
no_namespaces -= 1;
}
+ result = 0;
+out:
ncp_unlock_server(server);
- return 0;
+ return result;
}
-int ncp_lookup_volume(struct ncp_server *server,
- char *volname,
+int
+ncp_lookup_volume(struct ncp_server *server, char *volname,
struct nw_info_struct *target)
{
int result;
int volnum;
- DPRINTK("ncp_lookup_volume: looking up vol %s\n", volname);
+ DPRINTK(KERN_DEBUG "ncp_lookup_volume: looking up vol %s\n", volname);
ncp_init_request(server);
ncp_add_byte(server, 22); /* Subfunction: Generate dir handle */
@@ -306,7 +334,7 @@ int ncp_lookup_volume(struct ncp_server *server,
server->name_space[volnum] = ncp_has_os2_namespace(server, volnum) ? 4 : 0;
- DPRINTK("lookup_vol: namespace[%d] = %d\n",
+ DPRINTK(KERN_DEBUG "lookup_vol: namespace[%d] = %d\n",
volnum, server->name_space[volnum]);
target->nameLen = strlen(volname);
@@ -316,22 +344,22 @@ int ncp_lookup_volume(struct ncp_server *server,
}
int ncp_modify_file_or_subdir_dos_info(struct ncp_server *server,
- struct nw_info_struct *file,
- __u32 info_mask,
+ struct inode *dir, __u32 info_mask,
struct nw_modify_dos_info *info)
{
+ __u8 volnum = NCP_FINFO(dir)->volNumber;
+ __u32 dirent = NCP_FINFO(dir)->dirEntNum;
int result;
ncp_init_request(server);
ncp_add_byte(server, 7); /* subfunction */
- ncp_add_byte(server, server->name_space[file->volNumber]);
+ ncp_add_byte(server, server->name_space[volnum]);
ncp_add_byte(server, 0); /* reserved */
ncp_add_word(server, htons(0x0680)); /* search attribs: all */
ncp_add_dword(server, info_mask);
ncp_add_mem(server, info, sizeof(*info));
- ncp_add_handle_path(server, file->volNumber,
- file->dirEntNum, 1, NULL);
+ ncp_add_handle_path(server, volnum, dirent, 1, NULL);
result = ncp_request(server, 87);
ncp_unlock_server(server);
@@ -339,17 +367,18 @@ int ncp_modify_file_or_subdir_dos_info(struct ncp_server *server,
}
int ncp_del_file_or_subdir(struct ncp_server *server,
- struct nw_info_struct *dir, char *name)
+ struct inode *dir, char *name)
{
+ __u8 volnum = NCP_FINFO(dir)->volNumber;
+ __u32 dirent = NCP_FINFO(dir)->dirEntNum;
int result;
ncp_init_request(server);
ncp_add_byte(server, 8); /* subfunction */
- ncp_add_byte(server, server->name_space[dir->volNumber]);
+ ncp_add_byte(server, server->name_space[volnum]);
ncp_add_byte(server, 0); /* reserved */
ncp_add_word(server, ntohs(0x0680)); /* search attribs: all */
- ncp_add_handle_path(server, dir->volNumber,
- dir->dirEntNum, 1, name);
+ ncp_add_handle_path(server, volnum, dirent, 1, name);
result = ncp_request(server, 87);
ncp_unlock_server(server);
@@ -367,22 +396,29 @@ static inline void ConvertToNWfromDWORD(__u32 sfd, __u8 ret[6])
/* If both dir and name are NULL, then in target there's already a
looked-up entry that wants to be opened. */
int ncp_open_create_file_or_subdir(struct ncp_server *server,
- struct nw_info_struct *dir, char *name,
+ struct inode *dir, char *name,
int open_create_mode,
__u32 create_attributes,
int desired_acc_rights,
struct nw_file_info *target)
{
- int result;
__u16 search_attribs = ntohs(0x0600);
- __u8 volume = (dir != NULL) ? dir->volNumber : target->i.volNumber;
+ __u8 volnum = target->i.volNumber;
+ __u32 dirent = target->i.dirEntNum;
+ int result;
+
+ if (dir)
+ {
+ volnum = NCP_FINFO(dir)->volNumber;
+ dirent = NCP_FINFO(dir)->dirEntNum;
+ }
if ((create_attributes & aDIR) != 0) {
search_attribs |= ntohs(0x0080);
}
ncp_init_request(server);
ncp_add_byte(server, 1); /* subfunction */
- ncp_add_byte(server, server->name_space[volume]);
+ ncp_add_byte(server, server->name_space[volnum]);
ncp_add_byte(server, open_create_mode);
ncp_add_word(server, search_attribs);
ncp_add_dword(server, RIM_ALL);
@@ -390,53 +426,47 @@ int ncp_open_create_file_or_subdir(struct ncp_server *server,
/* The desired acc rights seem to be the inherited rights mask
for directories */
ncp_add_word(server, desired_acc_rights);
+ ncp_add_handle_path(server, volnum, dirent, 1, name);
- if (dir != NULL) {
- ncp_add_handle_path(server, volume, dir->dirEntNum, 1, name);
- } else {
- ncp_add_handle_path(server, volume, target->i.dirEntNum,
- 1, NULL);
- }
-
- if ((result = ncp_request(server, 87)) != 0) {
- ncp_unlock_server(server);
- return result;
- }
+ if ((result = ncp_request(server, 87)) != 0)
+ goto out;
target->opened = 1;
target->server_file_handle = ncp_reply_dword(server, 0);
target->open_create_action = ncp_reply_byte(server, 4);
if (dir != NULL) {
/* in target there's a new finfo to fill */
- ncp_extract_file_info(ncp_reply_data(server, 5), &(target->i));
+ ncp_extract_file_info(ncp_reply_data(server, 6), &(target->i));
}
ConvertToNWfromDWORD(target->server_file_handle, target->file_handle);
+out:
ncp_unlock_server(server);
- return 0;
+ return result;
}
-
-int ncp_initialize_search(struct ncp_server *server,
- struct nw_info_struct *dir,
- struct nw_search_sequence *target)
+int
+ncp_initialize_search(struct ncp_server *server, struct inode *dir,
+ struct nw_search_sequence *target)
{
+ __u8 volnum = NCP_FINFO(dir)->volNumber;
+ __u32 dirent = NCP_FINFO(dir)->dirEntNum;
int result;
ncp_init_request(server);
ncp_add_byte(server, 2); /* subfunction */
- ncp_add_byte(server, server->name_space[dir->volNumber]);
+ ncp_add_byte(server, server->name_space[volnum]);
ncp_add_byte(server, 0); /* reserved */
- ncp_add_handle_path(server, dir->volNumber, dir->dirEntNum, 1, NULL);
+ ncp_add_handle_path(server, volnum, dirent, 1, NULL);
- if ((result = ncp_request(server, 87)) != 0) {
- ncp_unlock_server(server);
- return result;
- }
+ result = ncp_request(server, 87);
+ if (result)
+ goto out;
memcpy(target, ncp_reply_data(server, 0), sizeof(*target));
+out:
ncp_unlock_server(server);
- return 0;
+ return result;
}
/* Search for everything */
@@ -457,42 +487,41 @@ int ncp_search_for_file_or_subdir(struct ncp_server *server,
ncp_add_byte(server, 0xff); /* following is a wildcard */
ncp_add_byte(server, '*');
- if ((result = ncp_request(server, 87)) != 0) {
- ncp_unlock_server(server);
- return result;
- }
+ if ((result = ncp_request(server, 87)) != 0)
+ goto out;
memcpy(seq, ncp_reply_data(server, 0), sizeof(*seq));
ncp_extract_file_info(ncp_reply_data(server, 10), target);
+out:
ncp_unlock_server(server);
- return 0;
+ return result;
}
int ncp_ren_or_mov_file_or_subdir(struct ncp_server *server,
- struct nw_info_struct *old_dir, char *old_name,
- struct nw_info_struct *new_dir, char *new_name)
+ struct inode *old_dir, char *old_name,
+ struct inode *new_dir, char *new_name)
{
- int result;
+ int result = -EINVAL;
- if ((old_dir == NULL) || (old_name == NULL)
- || (new_dir == NULL) || (new_name == NULL))
- return -EINVAL;
+ if ((old_dir == NULL) || (old_name == NULL) ||
+ (new_dir == NULL) || (new_name == NULL))
+ goto out;
ncp_init_request(server);
ncp_add_byte(server, 4); /* subfunction */
- ncp_add_byte(server, server->name_space[old_dir->volNumber]);
+ ncp_add_byte(server, server->name_space[NCP_FINFO(old_dir)->volNumber]);
ncp_add_byte(server, 1); /* rename flag */
ncp_add_word(server, ntohs(0x0680)); /* search attributes */
/* source Handle Path */
- ncp_add_byte(server, old_dir->volNumber);
- ncp_add_dword(server, old_dir->dirEntNum);
+ ncp_add_byte(server, NCP_FINFO(old_dir)->volNumber);
+ ncp_add_dword(server, NCP_FINFO(old_dir)->dirEntNum);
ncp_add_byte(server, 1);
ncp_add_byte(server, 1); /* 1 source component */
/* dest Handle Path */
- ncp_add_byte(server, new_dir->volNumber);
- ncp_add_dword(server, new_dir->dirEntNum);
+ ncp_add_byte(server, NCP_FINFO(new_dir)->volNumber);
+ ncp_add_dword(server, NCP_FINFO(new_dir)->dirEntNum);
ncp_add_byte(server, 1);
ncp_add_byte(server, 1); /* 1 destination component */
@@ -503,15 +532,17 @@ int ncp_ren_or_mov_file_or_subdir(struct ncp_server *server,
result = ncp_request(server, 87);
ncp_unlock_server(server);
+out:
return result;
}
/* We have to transfer to/from user space */
-int ncp_read(struct ncp_server *server, const char *file_id,
- __u32 offset, __u16 to_read,
- char *target, int *bytes_read)
+int
+ncp_read(struct ncp_server *server, const char *file_id,
+ __u32 offset, __u16 to_read, char *target, int *bytes_read)
{
+ char *source;
int result;
ncp_init_request(server);
@@ -521,20 +552,23 @@ int ncp_read(struct ncp_server *server, const char *file_id,
ncp_add_word(server, htons(to_read));
if ((result = ncp_request(server, 72)) != 0) {
- ncp_unlock_server(server);
- return result;
+ goto out;
}
*bytes_read = ntohs(ncp_reply_word(server, 0));
+ source = ncp_reply_data(server, 2 + (offset & 1));
- copy_to_user(target, ncp_reply_data(server, 2 + (offset & 1)), *bytes_read);
-
+ result = -EFAULT;
+ if (!copy_to_user(target, source, *bytes_read))
+ result = 0;
+out:
ncp_unlock_server(server);
- return 0;
+ return result;
}
-int ncp_write(struct ncp_server *server, const char *file_id,
+int
+ncp_write(struct ncp_server *server, const char *file_id,
__u32 offset, __u16 to_write,
- const char *source, int *bytes_written)
+ const char *source, int *bytes_written)
{
int result;
@@ -545,12 +579,11 @@ int ncp_write(struct ncp_server *server, const char *file_id,
ncp_add_word(server, htons(to_write));
ncp_add_mem_fromfs(server, source, to_write);
- if ((result = ncp_request(server, 73)) != 0) {
- ncp_unlock_server(server);
- return result;
- }
+ if ((result = ncp_request(server, 73)) != 0)
+ goto out;
*bytes_written = to_write;
-
+ result = 0;
+out:
ncp_unlock_server(server);
- return 0;
+ return result;
}
diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h
index 48425adb5..69388576b 100644
--- a/fs/ncpfs/ncplib_kernel.h
+++ b/fs/ncpfs/ncplib_kernel.h
@@ -3,6 +3,7 @@
*
* Copyright (C) 1995, 1996 by Volker Lendecke
* Modified for big endian by J.F. Chadima and David S. Miller
+ * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
*
*/
@@ -10,9 +11,6 @@
#define _NCPLIB_H
#include <linux/fs.h>
-#include <linux/ncp.h>
-#include <linux/ncp_fs.h>
-#include <linux/ncp_fs_sb.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/malloc.h>
@@ -24,71 +22,35 @@
#include <asm/string.h>
#include <linux/ncp.h>
+#include <linux/ncp_fs.h>
+#include <linux/ncp_fs_sb.h>
-int
-ncp_negotiate_buffersize(struct ncp_server *server, int size,
- int *target);
-int
-ncp_get_volume_info_with_number(struct ncp_server *server, int n,
- struct ncp_volume_info *target);
-
-int
-ncp_close_file(struct ncp_server *server, const char *file_id);
-
-int
-ncp_read(struct ncp_server *server, const char *file_id,
- __u32 offset, __u16 to_read,
- char *target, int *bytes_read);
-
-int
-ncp_write(struct ncp_server *server, const char *file_id,
- __u32 offset, __u16 to_write,
- const char *source, int *bytes_written);
+int ncp_negotiate_buffersize(struct ncp_server *, int, int *);
+int ncp_get_volume_info_with_number(struct ncp_server *, int,
+ struct ncp_volume_info *);
+int ncp_close_file(struct ncp_server *, const char *);
+int ncp_read(struct ncp_server *, const char *, __u32, __u16, char *, int *);
+int ncp_write(struct ncp_server *, const char *, __u32, __u16,
+ const char *, int *);
-int
-ncp_obtain_info(struct ncp_server *server,
- __u8 vol_num, __u32 dir_base,
- char *path, /* At most 1 component */
+int ncp_obtain_info(struct ncp_server *server, struct inode *, char *,
struct nw_info_struct *target);
+int ncp_lookup_volume(struct ncp_server *, char *, struct nw_info_struct *);
+int ncp_modify_file_or_subdir_dos_info(struct ncp_server *, struct inode *,
+ __u32, struct nw_modify_dos_info *info);
-int
-ncp_lookup_volume(struct ncp_server *server,
- char *volname,
- struct nw_info_struct *target);
-
-
-int
-ncp_modify_file_or_subdir_dos_info(struct ncp_server *server,
- struct nw_info_struct *file,
- __u32 info_mask,
- struct nw_modify_dos_info *info);
+int ncp_del_file_or_subdir(struct ncp_server *, struct inode *, char *);
+int ncp_open_create_file_or_subdir(struct ncp_server *, struct inode *, char *,
+ int, __u32, int, struct nw_file_info *);
-int
-ncp_del_file_or_subdir(struct ncp_server *server,
- struct nw_info_struct *dir, char *name);
-
-int
-ncp_open_create_file_or_subdir(struct ncp_server *server,
- struct nw_info_struct *dir, char *name,
- int open_create_mode,
- __u32 create_attributes,
- int desired_acc_rights,
- struct nw_file_info *target);
-
-int
-ncp_initialize_search(struct ncp_server *server,
- struct nw_info_struct *dir,
+int ncp_initialize_search(struct ncp_server *, struct inode *,
struct nw_search_sequence *target);
-
-int
-ncp_search_for_file_or_subdir(struct ncp_server *server,
+int ncp_search_for_file_or_subdir(struct ncp_server *server,
struct nw_search_sequence *seq,
struct nw_info_struct *target);
-int
-ncp_ren_or_mov_file_or_subdir(struct ncp_server *server,
- struct nw_info_struct *old_dir, char *old_name,
- struct nw_info_struct *new_dir, char *new_name);
+int ncp_ren_or_mov_file_or_subdir(struct ncp_server *server,
+ struct inode *, char *, struct inode *, char *);
#endif /* _NCPLIB_H */
diff --git a/fs/ncpfs/sock.c b/fs/ncpfs/sock.c
index e88176f95..08055ac5e 100644
--- a/fs/ncpfs/sock.c
+++ b/fs/ncpfs/sock.c
@@ -4,11 +4,11 @@
* Copyright (C) 1992, 1993 Rick Sladkey
*
* Modified 1995, 1996 by Volker Lendecke to be usable for ncp
+ * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
*
*/
#include <linux/sched.h>
-#include <linux/ncp_fs.h>
#include <linux/errno.h>
#include <linux/socket.h>
#include <linux/fcntl.h>
@@ -19,13 +19,13 @@
#include <linux/mm.h>
#include <linux/netdevice.h>
#include <net/scm.h>
+#include <net/sock.h>
#include <linux/ipx.h>
+#include <linux/poll.h>
#include <linux/ncp.h>
#include <linux/ncp_fs.h>
#include <linux/ncp_fs_sb.h>
-#include <net/sock.h>
-#include <linux/poll.h>
static int _recv(struct socket *sock, unsigned char *ubuf, int size,
unsigned flags)
@@ -104,10 +104,12 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size)
file = server->ncp_filp;
inode = file->f_dentry->d_inode;
sock = &inode->u.socket_i;
+ /* N.B. this isn't needed ... check socket type? */
if (!sock) {
- printk("ncp_rpc_call: socki_lookup failed\n");
+ printk(KERN_ERR "ncp_rpc_call: socki_lookup failed\n");
return -EBADF;
}
+
init_timeout = server->m.time_out;
max_timeout = NCP_MAX_RPC_TIMEOUT;
retrans = server->m.retry_count;
@@ -127,7 +129,8 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size)
fs = get_fs();
set_fs(get_ds());
for (n = 0, timeout = init_timeout;; n++, timeout <<= 1) {
- DDPRINTK("ncpfs: %08lX:%02X%02X%02X%02X%02X%02X:%04X\n",
+ /*
+ DDPRINTK(KERN_DEBUG "ncpfs: %08lX:%02X%02X%02X%02X%02X%02X:%04X\n",
htonl(server->m.serv_addr.sipx_network),
server->m.serv_addr.sipx_node[0],
server->m.serv_addr.sipx_node[1],
@@ -136,17 +139,18 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size)
server->m.serv_addr.sipx_node[4],
server->m.serv_addr.sipx_node[5],
ntohs(server->m.serv_addr.sipx_port));
- DDPRINTK("ncpfs: req.typ: %04X, con: %d, "
+ */
+ DDPRINTK(KERN_DEBUG "ncpfs: req.typ: %04X, con: %d, "
"seq: %d",
request.type,
(request.conn_high << 8) + request.conn_low,
request.sequence);
- DDPRINTK(" func: %d\n",
+ DDPRINTK(KERN_DEBUG " func: %d\n",
request.function);
result = _send(sock, (void *) start, size);
if (result < 0) {
- printk("ncp_rpc_call: send error = %d\n", result);
+ printk(KERN_ERR "ncp_rpc_call: send error = %d\n", result);
break;
}
re_select:
@@ -159,7 +163,7 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size)
* This is useful to see if the system is
* hanging */
if (acknowledge_seen == 0) {
- printk("NCP max timeout\n");
+ printk(KERN_WARNING "NCP max timeout\n");
}
timeout = max_timeout;
}
@@ -167,7 +171,7 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size)
schedule();
remove_wait_queue(entry.wait_address, &entry.wait);
current->state = TASK_RUNNING;
- if (current->signal & ~current->blocked) {
+ if (signal_pending(current)) {
current->timeout = 0;
result = -ERESTARTSYS;
break;
@@ -176,7 +180,7 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size)
if (n < retrans)
continue;
if (server->m.flags & NCP_MOUNT_SOFT) {
- printk("NCP server not responding\n");
+ printk(KERN_WARNING "NCP server not responding\n");
result = -EIO;
break;
}
@@ -184,7 +188,7 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size)
timeout = init_timeout;
init_timeout <<= 1;
if (!major_timeout_seen) {
- printk("NCP server not responding\n");
+ printk(KERN_WARNING "NCP server not responding\n");
}
major_timeout_seen = 1;
continue;
@@ -201,15 +205,15 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size)
MSG_PEEK | MSG_DONTWAIT);
if (result < 0) {
if (result == -EAGAIN) {
- DPRINTK("ncp_rpc_call: bad select ready\n");
+ DDPRINTK(KERN_DEBUG "ncp_rpc_call: bad select ready\n");
goto re_select;
}
if (result == -ECONNREFUSED) {
- DPRINTK("ncp_rpc_call: server playing coy\n");
+ DPRINTK(KERN_WARNING "ncp_rpc_call: server playing coy\n");
goto re_select;
}
if (result != -ERESTARTSYS) {
- printk("ncp_rpc_call: recv error = %d\n",
+ printk(KERN_ERR "ncp_rpc_call: recv error = %d\n",
-result);
}
break;
@@ -217,7 +221,7 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size)
if ((result == sizeof(reply))
&& (reply.type == NCP_POSITIVE_ACK)) {
/* Throw away the packet */
- DPRINTK("ncp_rpc_call: got positive acknowledge\n");
+ DPRINTK(KERN_DEBUG "ncp_rpc_call: got positive acknowledge\n");
_recv(sock, (void *) &reply, sizeof(reply),
MSG_DONTWAIT);
n = 0;
@@ -225,7 +229,7 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size)
acknowledge_seen = 1;
goto re_select;
}
- DDPRINTK("ncpfs: rep.typ: %04X, con: %d, tsk: %d,"
+ DDPRINTK(KERN_DEBUG "ncpfs: rep.typ: %04X, con: %d, tsk: %d,"
"seq: %d\n",
reply.type,
(reply.conn_high << 8) + reply.conn_low,
@@ -240,7 +244,7 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size)
/* seem to get wrong task from NW311 && (reply.task == request.task) */
&& (reply.conn_high == request.conn_high)))) {
if (major_timeout_seen)
- printk("NCP server OK\n");
+ printk(KERN_NOTICE "NCP server OK\n");
break;
}
/* JEJB/JSP 2/7/94
@@ -249,7 +253,7 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size)
* a null buffer yet. */
_recv(sock, (void *) &reply, sizeof(reply), MSG_DONTWAIT);
- DPRINTK("ncp_rpc_call: reply mismatch\n");
+ DPRINTK(KERN_WARNING "ncp_rpc_call: reply mismatch\n");
goto re_select;
}
/*
@@ -258,11 +262,11 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size)
*/
result = _recv(sock, (void *) start, server->packet_size, MSG_DONTWAIT);
if (result < 0) {
- printk("NCP: notice message: result=%d\n", result);
+ printk(KERN_WARNING "NCP: notice message: result=%d\n", result);
} else if (result < sizeof(struct ncp_reply_header)) {
- printk("NCP: just caught a too small read memory size..., "
+ printk(KERN_ERR "NCP: just caught a too small read memory size..., "
"email to NET channel\n");
- printk("NCP: result=%d\n", result);
+ printk(KERN_ERR "NCP: result=%d\n", result);
result = -EIO;
}
current->blocked = old_mask;
@@ -279,7 +283,7 @@ static int ncp_do_request(struct ncp_server *server, int size)
int result;
if (server->lock == 0) {
- printk("ncpfs: Server not locked!\n");
+ printk(KERN_ERR "ncpfs: Server not locked!\n");
return -EIO;
}
if (!ncp_conn_valid(server)) {
@@ -287,7 +291,7 @@ static int ncp_do_request(struct ncp_server *server, int size)
}
result = do_ncp_rpc_call(server, size);
- DDPRINTK("do_ncp_rpc_call returned %d\n", result);
+ DDPRINTK(KERN_DEBUG "do_ncp_rpc_call returned %d\n", result);
if (result < 0) {
/* There was a problem with I/O, so the connections is
@@ -299,19 +303,17 @@ static int ncp_do_request(struct ncp_server *server, int size)
/* ncp_do_request assures that at least a complete reply header is
* received. It assumes that server->current_size contains the ncp
- * request size */
+ * request size
+ */
int ncp_request(struct ncp_server *server, int function)
{
- struct ncp_request_header *h
- = (struct ncp_request_header *) (server->packet);
- struct ncp_reply_header *reply
- = (struct ncp_reply_header *) (server->packet);
-
+ struct ncp_request_header *h;
+ struct ncp_reply_header *reply;
int request_size = server->current_size
- - sizeof(struct ncp_request_header);
-
+ - sizeof(struct ncp_request_header);
int result;
+ h = (struct ncp_request_header *) (server->packet);
if (server->has_subfunction != 0) {
*(__u16 *) & (h->data[0]) = htons(request_size - 2);
}
@@ -321,13 +323,19 @@ int ncp_request(struct ncp_server *server, int function)
h->sequence = server->sequence;
h->conn_low = (server->connection) & 0xff;
h->conn_high = ((server->connection) & 0xff00) >> 8;
- h->task = (current->pid) & 0xff;
+ /*
+ * The server shouldn't know or care what task is making a
+ * request, so we always use the same task number.
+ */
+ h->task = 2; /* (current->pid) & 0xff; */
h->function = function;
- if ((result = ncp_do_request(server, request_size + sizeof(*h))) < 0) {
- DPRINTK("ncp_request_error: %d\n", result);
- return result;
+ result = ncp_do_request(server, request_size + sizeof(*h));
+ if (result < 0) {
+ DPRINTK(KERN_WARNING "ncp_request_error: %d\n", result);
+ goto out;
}
+ reply = (struct ncp_reply_header *) (server->packet);
server->completion = reply->completion_code;
server->conn_status = reply->connection_state;
server->reply_size = result;
@@ -335,48 +343,52 @@ int ncp_request(struct ncp_server *server, int function)
result = reply->completion_code;
- if (result != 0) {
- DPRINTK("ncp_completion_code: %x\n", result);
- }
+#ifdef NCPFS_PARANOIA
+if (result != 0)
+printk(KERN_DEBUG "ncp_request: completion code=%x\n", result);
+#endif
+out:
return result;
}
int ncp_connect(struct ncp_server *server)
{
- struct ncp_request_header *h
- = (struct ncp_request_header *) (server->packet);
+ struct ncp_request_header *h;
int result;
+ h = (struct ncp_request_header *) (server->packet);
h->type = NCP_ALLOC_SLOT_REQUEST;
server->sequence = 0;
- h->sequence = server->sequence;
- h->conn_low = 0xff;
- h->conn_high = 0xff;
- h->task = (current->pid) & 0xff;
- h->function = 0;
-
- if ((result = ncp_do_request(server, sizeof(*h))) < 0) {
- return result;
- }
+ h->sequence = server->sequence;
+ h->conn_low = 0xff;
+ h->conn_high = 0xff;
+ h->task = 2; /* see above */
+ h->function = 0;
+
+ result = ncp_do_request(server, sizeof(*h));
+ if (result < 0)
+ goto out;
server->sequence = 0;
server->connection = h->conn_low + (h->conn_high * 256);
- return 0;
+ result = 0;
+out:
+ return result;
}
int ncp_disconnect(struct ncp_server *server)
{
- struct ncp_request_header *h
- = (struct ncp_request_header *) (server->packet);
+ struct ncp_request_header *h;
+ h = (struct ncp_request_header *) (server->packet);
h->type = NCP_DEALLOC_SLOT_REQUEST;
server->sequence += 1;
- h->sequence = server->sequence;
- h->conn_low = (server->connection) & 0xff;
- h->conn_high = ((server->connection) & 0xff00) >> 8;
- h->task = (current->pid) & 0xff;
- h->function = 0;
+ h->sequence = server->sequence;
+ h->conn_low = (server->connection) & 0xff;
+ h->conn_high = ((server->connection) & 0xff00) >> 8;
+ h->task = 2; /* see above */
+ h->function = 0;
return ncp_do_request(server, sizeof(*h));
}
@@ -386,7 +398,7 @@ void ncp_lock_server(struct ncp_server *server)
#if 0
/* For testing, only 1 process */
if (server->lock != 0) {
- DPRINTK("ncpfs: server locked!!!\n");
+ DPRINTK(KERN_WARNING "ncpfs: server locked!!!\n");
}
#endif
while (server->lock)
@@ -397,7 +409,7 @@ void ncp_lock_server(struct ncp_server *server)
void ncp_unlock_server(struct ncp_server *server)
{
if (server->lock != 1) {
- printk("ncp_unlock_server: was not locked!\n");
+ printk(KERN_WARNING "ncp_unlock_server: was not locked!\n");
}
server->lock = 0;
wake_up(&server->wait);
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index acee50754..9e1d936dd 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -29,6 +29,13 @@
#include <asm/segment.h> /* for fs functions */
+#define NFS_MAX_AGE 10*HZ /* max age for dentry validation */
+
+/* needed by smbfs as well ... move to dcache? */
+extern void nfs_renew_times(struct dentry *);
+
+#define NFS_PARANOIA 1
+
/*
* Head for a dircache entry. Currently still very simple; when
* the cache grows larger, we will need a LRU list.
@@ -36,18 +43,20 @@
struct nfs_dirent {
dev_t dev; /* device number */
ino_t ino; /* inode number */
- u32 cookie; /* cooke of first entry */
+ u32 cookie; /* cookie of first entry */
unsigned short valid : 1, /* data is valid */
locked : 1; /* entry locked */
unsigned int size; /* # of entries */
unsigned long age; /* last used */
unsigned long mtime; /* last attr stamp */
struct wait_queue * wait;
- struct nfs_entry * entry;
+ __u32 * entry; /* three __u32's per entry */
};
-static int nfs_dir_open(struct inode * inode, struct file * file);
-static long nfs_dir_read(struct inode *, struct file *, char *, unsigned long);
+static int nfs_safe_remove(struct dentry *);
+
+static int nfs_dir_open(struct inode *, struct file *);
+static ssize_t nfs_dir_read(struct file *, char *, size_t, loff_t *);
static int nfs_readdir(struct file *, void *, filldir_t);
static int nfs_lookup(struct inode *, struct dentry *);
static int nfs_create(struct inode *, struct dentry *, int);
@@ -57,7 +66,8 @@ static int nfs_unlink(struct inode *, struct dentry *);
static int nfs_symlink(struct inode *, struct dentry *, const char *);
static int nfs_link(struct inode *, struct inode *, struct dentry *);
static int nfs_mknod(struct inode *, struct dentry *, int, int);
-static int nfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
+static int nfs_rename(struct inode *, struct dentry *,
+ struct inode *, struct dentry *);
static struct file_operations nfs_dir_operations = {
NULL, /* lseek - default */
@@ -102,8 +112,8 @@ nfs_dir_open(struct inode *dir, struct file *file)
return nfs_revalidate_inode(NFS_SERVER(dir), dir);
}
-static long
-nfs_dir_read(struct inode *inode, struct file *filp, char *buf, unsigned long count)
+static ssize_t
+nfs_dir_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
{
return -EISDIR;
}
@@ -123,15 +133,16 @@ static struct nfs_dirent dircache[NFS_MAX_DIRCACHE];
static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
+ struct inode *inode = filp->f_dentry->d_inode;
static struct wait_queue *readdir_wait = NULL;
struct wait_queue **waitp = NULL;
struct nfs_dirent *cache, *free;
- struct nfs_entry *entry;
unsigned long age, dead;
u32 cookie;
int ismydir, result;
int i, j, index = 0;
- struct inode *inode = filp->f_dentry->d_inode;
+ __u32 *entry;
+ char *name, *start;
dfprintk(VFS, "NFS: nfs_readdir(%x/%ld)\n", inode->i_dev, inode->i_ino);
if (!inode || !S_ISDIR(inode->i_mode)) {
@@ -148,7 +159,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
again:
if (waitp) {
interruptible_sleep_on(waitp);
- if (current->signal & ~current->blocked)
+ if (signal_pending(current))
return -ERESTARTSYS;
waitp = NULL;
}
@@ -174,7 +185,7 @@ again:
goto again;
}
- if (ismydir && cache->mtime != NFS_OLDMTIME(inode))
+ if (ismydir && cache->mtime != inode->i_mtime)
cache->valid = 0;
if (!cache->valid || cache->age < dead) {
@@ -194,17 +205,15 @@ again:
break;
}
for (j = 0; j < cache->size; j++) {
- /*
- dprintk("NFS: examing entry %.*s @%d\n",
- (int) cache->entry[j].length,
- cache->entry[j].name,
- cache->entry[j].cookie);
- */
- if (cache->entry[j].cookie != cookie)
+ __u32 *this_ent = cache->entry + j*3;
+
+ if (*(this_ent+1) != cookie)
continue;
if (j < cache->size - 1) {
- entry = cache->entry + (index = j + 1);
- } else if (cache->entry[j].eof) {
+ index = j + 1;
+ entry = this_ent + 3;
+ } else if (*(this_ent+2) & (1 << 15)) {
+ /* eof */
return 0;
}
break;
@@ -235,12 +244,10 @@ again:
cache->dev = inode->i_dev;
cache->ino = inode->i_ino;
if (!cache->entry) {
- cache->entry = (struct nfs_entry *)
- get_free_page(GFP_KERNEL);
- if (!cache->entry) {
- result = -ENOMEM;
+ result = -ENOMEM;
+ cache->entry = (__u32 *) get_free_page(GFP_KERNEL);
+ if (!cache->entry)
goto done;
- }
}
result = nfs_proc_readdir(NFS_SERVER(inode), NFS_FH(inode),
@@ -251,31 +258,35 @@ again:
cache->valid = 1;
entry = cache->entry + (index = 0);
}
- cache->mtime = NFS_OLDMTIME(inode);
+ cache->mtime = inode->i_mtime;
cache->age = jiffies;
/*
* Yowza! We have a cache entry...
*/
+ start = (char *) cache->entry;
while (index < cache->size) {
- int nextpos = entry->cookie;
+ __u32 fileid = *entry++;
+ __u32 nextpos = *entry++; /* cookie */
+ __u32 length = *entry++;
/*
+ * Unpack the eof flag, offset, and length
+ */
+ result = length & (1 << 15); /* eof flag */
+ name = start + ((length >> 16) & 0xFFFF);
+ length &= 0x7FFF;
+ /*
dprintk("NFS: filldir(%p, %.*s, %d, %d, %x, eof %x)\n", entry,
- (int) entry->length, entry->name, entry->length,
+ (int) length, name, length,
(unsigned int) filp->f_pos,
- entry->fileid, entry->eof);
+ fileid, result);
*/
- if (filldir(dirent, entry->name, entry->length, cookie, entry->fileid) < 0)
+ if (filldir(dirent, name, length, cookie, fileid) < 0)
break;
cookie = nextpos;
- if (nextpos != entry->cookie) {
- printk("nfs_readdir: shouldn't happen!\n");
- break;
- }
index++;
- entry++;
}
filp->f_pos = cookie;
result = 0;
@@ -293,47 +304,69 @@ done:
}
/*
- * Invalidate dircache entries for inode
+ * Invalidate dircache entries for an inode.
*/
void
nfs_invalidate_dircache(struct inode *inode)
{
- struct nfs_dirent *cache;
+ struct nfs_dirent *cache = dircache;
dev_t dev = inode->i_dev;
ino_t ino = inode->i_ino;
int i;
dfprintk(DIRCACHE, "NFS: invalidate dircache for %x/%ld\n", dev, (long)ino);
- for (i = 0, cache = dircache; i < NFS_MAX_DIRCACHE; i++, cache++) {
- if (!cache->locked && cache->dev == dev && cache->ino == ino)
- cache->valid = 0; /* brute force */
+ for (i = NFS_MAX_DIRCACHE; i--; cache++) {
+ if (cache->ino != ino)
+ continue;
+ if (cache->dev != dev)
+ continue;
+ if (cache->locked) {
+ printk("NFS: cache locked for %s/%ld\n",
+ kdevname(dev), (long) ino);
+ continue;
+ }
+ cache->valid = 0; /* brute force */
}
}
/*
- * Free directory cache memory
- * Called from cleanup_module
+ * Invalidate the dircache for a super block (or all caches),
+ * and release the cache memory.
*/
void
-nfs_free_dircache(void)
+nfs_invalidate_dircache_sb(struct super_block *sb)
{
- struct nfs_dirent *cache;
+ struct nfs_dirent *cache = dircache;
int i;
- dfprintk(DIRCACHE, "NFS: freeing dircache\n");
- for (i = 0, cache = dircache; i < NFS_MAX_DIRCACHE; i++, cache++) {
- cache->valid = 0;
+ for (i = NFS_MAX_DIRCACHE; i--; cache++) {
+ if (sb && sb->s_dev != cache->dev)
+ continue;
if (cache->locked) {
- printk("nfs_kfree_cache: locked entry in dircache!\n");
+ printk("NFS: cache locked at umount %s\n",
+ (cache->entry ? "(lost a page!)" : ""));
continue;
}
- if (cache->entry)
+ cache->valid = 0; /* brute force */
+ if (cache->entry) {
free_page((unsigned long) cache->entry);
- cache->entry = NULL;
+ cache->entry = NULL;
+ }
}
}
/*
+ * Free directory cache memory
+ * Called from cleanup_module
+ */
+void
+nfs_free_dircache(void)
+{
+ dfprintk(DIRCACHE, "NFS: freeing dircache\n");
+ nfs_invalidate_dircache_sb(NULL);
+}
+
+/*
* This is called every time the dcache has a lookup hit,
* and we should check whether we can really trust that
* lookup.
@@ -350,20 +383,92 @@ static int nfs_lookup_revalidate(struct dentry * dentry)
unsigned long time = jiffies - dentry->d_time;
unsigned long max = 5*HZ;
- if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
- max = 10*HZ;
- return time < max;
+ if (dentry->d_inode) {
+ if (is_bad_inode(dentry->d_inode)) {
+#ifdef NFS_PARANOIA
+printk("nfs_lookup_validate: %s/%s has dud inode\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
+ goto bad;
+ }
+ if (S_ISDIR(dentry->d_inode->i_mode))
+ max = NFS_MAX_AGE;
+ }
+
+ return (time < max) || IS_ROOT(dentry);
+bad:
+ return 0;
}
-static void nfs_silly_delete(struct dentry *);
+/*
+ * This is called from dput() when d_count is going to 0.
+ * We use it to clean up silly-renamed files, and to check
+ * for dentries that have already expired.
+ */
+static void nfs_dentry_delete(struct dentry *dentry)
+{
+ if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
+ int error;
+
+ dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
+#ifdef NFS_DEBUG
+printk("nfs_dentry_delete: unlinking %s/%s\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
+ /* Unhash it first */
+ d_drop(dentry);
+ error = nfs_safe_remove(dentry);
+ if (error)
+ printk("NFS: can't silly-delete %s/%s, error=%d\n",
+ dentry->d_parent->d_name.name,
+ dentry->d_name.name, error);
+ }
+ /*
+ * Check whether to expire the dentry ...
+ */
+ else {
+ unsigned long age = jiffies - dentry->d_time;
+ if (age > NFS_MAX_AGE)
+ d_drop(dentry);
+ }
+
+#ifdef NFS_PARANOIA
+ /*
+ * Sanity check: if the dentry has been unhashed and the
+ * inode still has users, we could have problems ...
+ */
+ if (list_empty(&dentry->d_hash) && dentry->d_inode) {
+ struct inode *inode = dentry->d_inode;
+ if (inode->i_count > 1) {
+printk("nfs_dentry_delete: %s/%s: ino=%ld, count=%d, nlink=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name,
+inode->i_ino, inode->i_count, inode->i_nlink);
+ }
+ }
+#endif
+}
static struct dentry_operations nfs_dentry_operations = {
- nfs_lookup_revalidate,
+ nfs_lookup_revalidate, /* d_validate(struct dentry *) */
0, /* d_hash */
0, /* d_compare */
- nfs_silly_delete,
+ nfs_dentry_delete /* d_delete(struct dentry *) */
};
+/*
+ * Whenever a lookup succeeds, we know the parent directories
+ * are all valid, so we want to update the dentry timestamps.
+ */
+void nfs_renew_times(struct dentry * dentry)
+{
+ for (;;) {
+ dentry->d_time = jiffies;
+ if (dentry == dentry->d_parent)
+ break;
+ dentry = dentry->d_parent;
+ }
+}
+
static int nfs_lookup(struct inode *dir, struct dentry * dentry)
{
struct inode *inode;
@@ -373,38 +478,66 @@ static int nfs_lookup(struct inode *dir, struct dentry * dentry)
int error;
dfprintk(VFS, "NFS: lookup(%x/%ld, %.*s)\n",
- dir->i_dev, dir->i_ino, len, dentry->d_name.name);
+ dir->i_dev, dir->i_ino, len, dentry->d_name.name);
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("nfs_lookup: inode is NULL or not a directory\n");
return -ENOENT;
}
+ error = -ENAMETOOLONG;
if (len > NFS_MAXNAMLEN)
- return -ENAMETOOLONG;
-
- error = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name, &fhandle, &fattr);
+ goto out;
+ error = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dir),
+ dentry->d_name.name, &fhandle, &fattr);
inode = NULL;
+ if (error == -ENOENT)
+ goto no_entry;
if (!error) {
+ error = -EACCES;
inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
- if (!inode)
- return -EACCES;
- } else if (error != -ENOENT)
- return error;
-
- dentry->d_time = jiffies;
- dentry->d_op = &nfs_dentry_operations;
- d_add(dentry, inode);
- return 0;
+ if (inode) {
+ no_entry:
+ dentry->d_op = &nfs_dentry_operations;
+ d_add(dentry, inode);
+ nfs_renew_times(dentry);
+ error = 0;
+ }
+ }
+out:
+ return error;
}
+/*
+ * Code common to create, mkdir, and mknod.
+ */
+static int nfs_instantiate(struct inode *dir, struct dentry *dentry,
+ struct nfs_fattr *fattr, struct nfs_fh *fhandle)
+{
+ struct inode *inode;
+ int error = -EACCES;
+
+ inode = nfs_fhget(dir->i_sb, fhandle, fattr);
+ if (inode) {
+ d_instantiate(dentry, inode);
+ nfs_renew_times(dentry);
+ error = 0;
+ }
+ return error;
+}
+
+/*
+ * Following a failed create operation, we drop the dentry rather
+ * than retain a negative dentry. This avoids a problem in the event
+ * that the operation succeeded on the server, but an error in the
+ * reply path made it appear to have failed.
+ */
static int nfs_create(struct inode *dir, struct dentry * dentry, int mode)
{
struct nfs_sattr sattr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
- struct inode *inode;
int error;
dfprintk(VFS, "NFS: create(%x/%ld, %s\n",
@@ -415,33 +548,41 @@ static int nfs_create(struct inode *dir, struct dentry * dentry, int mode)
return -ENOENT;
}
+ error = -ENAMETOOLONG;
if (dentry->d_name.len > NFS_MAXNAMLEN)
- return -ENAMETOOLONG;
+ goto out;
sattr.mode = mode;
sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
- error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
- dentry->d_name.name, &sattr, &fhandle, &fattr);
-
- if (error)
- return error;
-
- inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
- if (!inode)
- return -EACCES;
+ /*
+ * Invalidate the dir cache before the operation to avoid a race.
+ */
nfs_invalidate_dircache(dir);
- d_instantiate(dentry, inode);
- return 0;
+ error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
+ dentry->d_name.name, &sattr, &fhandle, &fattr);
+ if (!error)
+ error = nfs_instantiate(dir, dentry, &fattr, &fhandle);
+ else {
+#ifdef NFS_PARANOIA
+printk("nfs_create: %s/%s failed, error=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, error);
+#endif
+ d_drop(dentry);
+ }
+out:
+ return error;
}
+/*
+ * See comments for nfs_proc_create regarding failed operations.
+ */
static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
{
struct nfs_sattr sattr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
- struct inode *inode;
int error;
dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n",
@@ -459,29 +600,31 @@ static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rde
sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
if (S_ISCHR(mode) || S_ISBLK(mode))
sattr.size = rdev; /* get out your barf bag */
-
sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
- error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
- dentry->d_name.name, &sattr, &fhandle, &fattr);
-
- if (error)
- return error;
-
- inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
- if (!inode)
- return -EACCES;
nfs_invalidate_dircache(dir);
- d_instantiate(dentry, inode);
- return 0;
+ error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
+ dentry->d_name.name, &sattr, &fhandle, &fattr);
+ if (!error)
+ error = nfs_instantiate(dir, dentry, &fattr, &fhandle);
+ else {
+#ifdef NFS_PARANOIA
+printk("nfs_mknod: %s/%s failed, error=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, error);
+#endif
+ d_drop(dentry);
+ }
+ return error;
}
+/*
+ * See comments for nfs_proc_create regarding failed operations.
+ */
static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
struct nfs_sattr sattr;
struct nfs_fattr fattr;
struct nfs_fh fhandle;
- struct inode * inode;
int error;
dfprintk(VFS, "NFS: mkdir(%x/%ld, %s\n",
@@ -499,21 +642,29 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
- error = nfs_proc_mkdir(NFS_SERVER(dir), NFS_FH(dir),
- dentry->d_name.name, &sattr, &fhandle, &fattr);
-
- if (error)
- return error;
-
- inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
- if (!inode)
- return -EACCES;
-
nfs_invalidate_dircache(dir);
- d_instantiate(dentry, inode);
- return 0;
+ error = nfs_proc_mkdir(NFS_SERVER(dir), NFS_FH(dir),
+ dentry->d_name.name, &sattr, &fhandle, &fattr);
+ if (!error)
+ error = nfs_instantiate(dir, dentry, &fattr, &fhandle);
+ else {
+#ifdef NFS_PARANOIA
+printk("nfs_mkdir: %s/%s failed, error=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, error);
+#endif
+ d_drop(dentry);
+ }
+ return error;
}
+/*
+ * To avoid retaining a stale inode reference, we check the dentry
+ * use count prior to the operation, and return EBUSY if it has
+ * multiple users.
+ *
+ * Update inode->i_nlink immediately after a successful operation.
+ * (See comments for nfs_unlink.)
+ */
static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
{
int error;
@@ -526,16 +677,28 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
return -ENOENT;
}
+ error = -ENAMETOOLONG;
if (dentry->d_name.len > NFS_MAXNAMLEN)
- return -ENAMETOOLONG;
-
+ goto out;
+
+ error = -EBUSY;
+ if (dentry->d_count > 1) {
+ /* Attempt to shrink child dentries ... */
+ shrink_dcache_parent(dentry);
+ if (dentry->d_count > 1)
+ goto out;
+ }
+ /* Drop the dentry to force a new lookup */
+ d_drop(dentry);
error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name);
- if (error)
- return error;
-
- nfs_invalidate_dircache(dir);
- d_delete(dentry);
- return 0;
+ if (!error) {
+ if (dentry->d_inode->i_nlink)
+ dentry->d_inode->i_nlink --;
+ nfs_invalidate_dircache(dir);
+ nfs_renew_times(dentry);
+ }
+out:
+ return error;
}
@@ -551,24 +714,22 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
*
* Concerning my choice of the temp name: it is just nice to have
* i_ino part of the temp name, as this offers another check whether
- * somebody attempts to remove the "silly renamed" dentry
- * itself. Which is something that I consider evil. Your opinion may
- * vary.
+ * somebody attempts to remove the "silly renamed" dentry itself.
+ * Which is something that I consider evil. Your opinion may vary.
* BUT:
* Now that I compute the hash value right, it should be possible to simply
* check for the DCACHE_NFSFS_RENAMED flag in dentry->d_flag instead of
* doing the string compare.
* WHICH MEANS:
* This offers the opportunity to shorten the temp name. Currently, I use
- * the hex representation of i_ino + the hex value of jiffies. This
- * sums up to as much as 36 characters for a 64 bit machine, and needs
- * 20 chars on a 32 bit machine. Have a look at jiffiesize etc.
+ * the hex representation of i_ino + an event counter. This sums up to
+ * as much as 36 characters for a 64 bit machine, and needs 20 chars on
+ * a 32 bit machine.
* QUINTESSENCE
* The use of i_ino is simply cosmetic. All we need is a unique temp
- * file name for the .nfs files. The hex representation of "jiffies"
- * seemed to be adequate. And as we retry in case such a file already
- * exists we are guaranteed to succed (after some jiffies have passed
- * by :)
+ * file name for the .nfs files. The event counter seemed to be adequate.
+ * And as we retry in case such a file already exists, we are guaranteed
+ * to succeed.
*/
static
@@ -576,14 +737,11 @@ struct dentry *nfs_silly_lookup(struct dentry *parent, char *silly, int slen)
{
struct qstr sqstr;
struct dentry *sdentry;
- int i, error;
+ int error;
sqstr.name = silly;
sqstr.len = slen;
- sqstr.hash = init_name_hash();
- for (i= 0; i < slen; i++)
- sqstr.hash = partial_name_hash(silly[i], sqstr.hash);
- sqstr.hash = end_name_hash(sqstr.hash);
+ sqstr.hash = full_name_hash(silly, slen);
sdentry = d_lookup(parent, &sqstr);
if (!sdentry) {
sdentry = d_alloc(parent, &sqstr);
@@ -605,19 +763,29 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
const int countersize = sizeof(sillycounter)*2;
const int slen = strlen(".nfs") + i_inosize + countersize;
char silly[slen+1];
- int error;
struct dentry *sdentry;
+ int error = -EIO;
+ /*
+ * Note that a silly-renamed file can be deleted once it's
+ * no longer in use -- it's just an ordinary file now.
+ */
if (dentry->d_count == 1) {
- return -EIO; /* No need to silly rename. */
+ dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
+ goto out; /* No need to silly rename. */
}
- if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
- return -EBUSY; /* don't allow to unlink silly inode -- nope,
- * think a bit: silly DENTRY, NOT inode --
- * itself
- */
- }
+#ifdef NFS_PARANOIA
+if (!dentry->d_inode)
+printk("NFS: silly-renaming %s/%s, negative dentry??\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
+ /*
+ * We don't allow a dentry to be silly-renamed twice.
+ */
+ error = -EBUSY;
+ if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
+ goto out;
sprintf(silly, ".nfs%*.*lx",
i_inosize, i_inosize, dentry->d_inode->i_ino);
@@ -634,54 +802,109 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
dentry->d_name.name, silly);
sdentry = nfs_silly_lookup(dentry->d_parent, silly, slen);
- if (IS_ERR(sdentry)) {
- return -EIO; /* FIXME ? */
- }
+ /*
+ * N.B. Better to return EBUSY here ... it could be
+ * dangerous to delete the file while it's in use.
+ */
+ if (IS_ERR(sdentry))
+ goto out;
} while(sdentry->d_inode != NULL); /* need negative lookup */
error = nfs_proc_rename(NFS_SERVER(dir),
NFS_FH(dir), dentry->d_name.name,
NFS_FH(dir), silly);
- if (error) {
- dput(sdentry);
- return error;
+ if (!error) {
+ nfs_invalidate_dircache(dir);
+ nfs_renew_times(dentry);
+ d_move(dentry, sdentry);
+ dentry->d_flags |= DCACHE_NFSFS_RENAMED;
+ /* If we return 0 we don't unlink */
}
- nfs_invalidate_dircache(dir);
- d_move(dentry, sdentry);
dput(sdentry);
- dentry->d_flags |= DCACHE_NFSFS_RENAMED;
-
- return 0; /* don't unlink */
+out:
+ return error;
}
-static void nfs_silly_delete(struct dentry *dentry)
+/*
+ * Remove a file after making sure there are no pending writes,
+ * and after checking that the file has only one user.
+ *
+ * Updating inode->i_nlink here rather than waiting for the next
+ * nfs_refresh_inode() is not merely cosmetic; once an object has
+ * been deleted, we want to get rid of the inode locally. The NFS
+ * server may reuse the fileid for a new inode, and we don't want
+ * that to be confused with this inode.
+ */
+static int nfs_safe_remove(struct dentry *dentry)
{
- if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
- struct inode *dir = dentry->d_parent->d_inode;
- int error;
+ struct inode *dir = dentry->d_parent->d_inode;
+ struct inode *inode = dentry->d_inode;
+ int error, rehash = 0;
- dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
+ error = -EBUSY;
+ if (inode) {
+ if (NFS_WRITEBACK(inode)) {
+ nfs_flush_dirty_pages(inode, 0, 0, 0);
+ if (NFS_WRITEBACK(inode)) {
+#ifdef NFS_PARANOIA
+printk("nfs_safe_remove: %s/%s writes pending, d_count=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
+#endif
+ goto out;
+ }
+ }
+ } else {
+#ifdef NFS_PARANOIA
+printk("nfs_safe_remove: %s/%s already negative??\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
+ }
- /* Unhash it first */
+ if (dentry->d_count > 1) {
+#ifdef NFS_PARANOIA
+printk("nfs_safe_remove: %s/%s busy, d_count=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
+#endif
+ goto out;
+ }
+ /*
+ * Unhash the dentry while we remove the file ...
+ */
+ if (!list_empty(&dentry->d_hash)) {
d_drop(dentry);
- dfprintk(VFS, "trying to unlink %s\n", dentry->d_name.name);
- error = nfs_proc_remove(NFS_SERVER(dir),
+ rehash = 1;
+ }
+ error = nfs_proc_remove(NFS_SERVER(dir),
NFS_FH(dir), dentry->d_name.name);
- if (error < 0)
- printk("NFS " __FUNCTION__ " failed (err = %d)\n",
- -error);
- dentry->d_inode->i_nlink --;
+ /*
+ * ... then restore the hashed state. This ensures that the
+ * dentry can't become busy after having its file deleted.
+ */
+ if (rehash) {
+ d_add(dentry, inode);
+ }
+#ifdef NFS_PARANOIA
+if (dentry->d_count > 1)
+printk("nfs_safe_remove: %s/%s busy after delete?? d_count=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
+if (inode && inode->i_count > 1)
+printk("nfs_safe_remove: %s/%s inode busy?? i_count=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_count);
+#endif
+ if (!error) {
nfs_invalidate_dircache(dir);
+ if (inode && inode->i_nlink)
+ inode->i_nlink --;
+ d_delete(dentry);
}
+out:
+ return error;
}
/* We do silly rename. In case sillyrename() returns -EBUSY, the inode
* belongs to an active ".nfs..." file and we return -EBUSY.
*
* If sillyrename() returns 0, we do nothing, otherwise we unlink.
- *
- * inode->i_nlink is updated here rather than waiting for the next
- * nfs_refresh_inode() for cosmetic reasons only.
*/
static int nfs_unlink(struct inode *dir, struct dentry *dentry)
{
@@ -695,70 +918,77 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
return -ENOENT;
}
+ error = -ENAMETOOLONG;
if (dentry->d_name.len > NFS_MAXNAMLEN)
- return -ENAMETOOLONG;
+ goto out;
error = nfs_sillyrename(dir, dentry);
-
- if (error == -EBUSY) {
- return -EBUSY;
- } else if (error < 0) {
- error = nfs_proc_remove(NFS_SERVER(dir),
- NFS_FH(dir), dentry->d_name.name);
- if (error < 0)
- return error;
-
- dentry->d_inode->i_nlink --;
- nfs_invalidate_dircache(dir);
- d_delete(dentry);
+ if (error && error != -EBUSY) {
+ error = nfs_safe_remove(dentry);
+ if (!error) {
+ nfs_renew_times(dentry);
+ }
}
-
- return 0;
+out:
+ return error;
}
-static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
+static int
+nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
{
struct nfs_sattr sattr;
int error;
dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n",
- dir->i_dev, dir->i_ino, dentry->d_name.name, symname);
+ dir->i_dev, dir->i_ino, dentry->d_name.name, symname);
if (!dir || !S_ISDIR(dir->i_mode)) {
printk("nfs_symlink: inode is NULL or not a directory\n");
return -ENOENT;
}
+ error = -ENAMETOOLONG;
if (dentry->d_name.len > NFS_MAXNAMLEN)
- return -ENAMETOOLONG;
+ goto out;
if (strlen(symname) > NFS_MAXPATHLEN)
- return -ENAMETOOLONG;
+ goto out;
- sattr.mode = S_IFLNK | S_IRWXUGO; /* SunOS 4.1.2 crashes without this! */
+#ifdef NFS_PARANOIA
+if (dentry->d_inode)
+printk("nfs_proc_symlink: %s/%s not negative!\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
+ /*
+ * Fill in the sattr for the call.
+ * Note: SunOS 4.1.2 crashes if the mode isn't initialized!
+ */
+ sattr.mode = S_IFLNK | S_IRWXUGO;
sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
- error = nfs_proc_symlink(NFS_SERVER(dir), NFS_FH(dir),
- dentry->d_name.name, symname, &sattr);
-
- if (error)
- return error;
-
- nfs_invalidate_dircache(dir);
- /* this looks _funny_ doesn't it? But: nfs_proc_symlink()
- * only fills in sattr, not fattr. Thus nfs_fhget() cannot be
- * called, it would be pointless, without a valid fattr
- * argument. Other possibility: call nfs_proc_lookup()
- * HERE. But why? If somebody wants to reference this
- * symlink, the cached_lookup() will fail, and
- * nfs_proc_symlink() will be called anyway.
+ /*
+ * Drop the dentry in advance to force a new lookup.
+ * Since nfs_proc_symlink doesn't return a fattr, we
+ * can't instantiate the new inode.
*/
d_drop(dentry);
- return 0;
+ error = nfs_proc_symlink(NFS_SERVER(dir), NFS_FH(dir),
+ dentry->d_name.name, symname, &sattr);
+ if (!error) {
+ nfs_invalidate_dircache(dir);
+ nfs_renew_times(dentry->d_parent);
+ } else if (error == -EEXIST) {
+ printk("nfs_proc_symlink: %s/%s already exists??\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
+ }
+
+out:
+ return error;
}
-static int nfs_link(struct inode *inode, struct inode *dir, struct dentry *dentry)
+static int
+nfs_link(struct inode *inode, struct inode *dir, struct dentry *dentry)
{
int error;
@@ -771,20 +1001,20 @@ static int nfs_link(struct inode *inode, struct inode *dir, struct dentry *dentr
return -ENOENT;
}
+ error = -ENAMETOOLONG;
if (dentry->d_name.len > NFS_MAXNAMLEN)
- return -ENAMETOOLONG;
-
- error = nfs_proc_link(NFS_SERVER(inode), NFS_FH(inode),
- NFS_FH(dir), dentry->d_name.name);
-
- if (error)
- return error;
+ goto out;
- nfs_invalidate_dircache(dir);
- inode->i_count ++;
- inode->i_nlink ++; /* no need to wait for nfs_refresh_inode() */
- d_instantiate(dentry, inode);
- return 0;
+ error = nfs_proc_link(NFS_SERVER(inode), NFS_FH(inode), NFS_FH(dir),
+ dentry->d_name.name);
+ if (!error) {
+ nfs_invalidate_dircache(dir);
+ inode->i_count ++;
+ inode->i_nlink ++; /* no need to wait for nfs_refresh_inode() */
+ d_instantiate(dentry, inode);
+ }
+out:
+ return error;
}
/*
@@ -804,16 +1034,25 @@ static int nfs_link(struct inode *inode, struct inode *dir, struct dentry *dentr
* implementation that only depends on the dcache stuff instead of
* using the inode layer
*
+ * Unfortunately, things are a little more complicated than indicated
+ * above. For a cross-directory move, we want to make sure we can get
+ * rid of the old inode after the operation. This means there must be
+ * no pending writes (if it's a file), and the use count must be 1.
+ * If these conditions are met, we can drop the dentries before doing
+ * the rename.
*/
static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
{
- int error;
-
- dfprintk(VFS, "NFS: rename(%x/%ld, %s -> %x/%ld, %s)\n",
- old_dir->i_dev, old_dir->i_ino, old_dentry->d_name.name,
- new_dir->i_dev, new_dir->i_ino, new_dentry->d_name.name);
-
+ struct inode *old_inode = old_dentry->d_inode;
+ struct inode *new_inode = new_dentry->d_inode;
+ int error, rehash = 0, update = 1;
+
+#ifdef NFS_DEBUG_VERBOSE
+printk("nfs_rename: old %s/%s, count=%d, new %s/%s, count=%d\n",
+old_dentry->d_parent->d_name.name,old_dentry->d_name.name,old_dentry->d_count,
+new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
+#endif
if (!old_dir || !S_ISDIR(old_dir->i_mode)) {
printk("nfs_rename: old inode is NULL or not a directory\n");
return -ENOENT;
@@ -824,98 +1063,109 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
return -ENOENT;
}
- if (old_dentry->d_name.len > NFS_MAXNAMLEN || new_dentry->d_name.len > NFS_MAXNAMLEN)
- return -ENAMETOOLONG;
+ error = -ENAMETOOLONG;
+ if (old_dentry->d_name.len > NFS_MAXNAMLEN ||
+ new_dentry->d_name.len > NFS_MAXNAMLEN)
+ goto out;
- if (new_dir != old_dir) {
- error = nfs_sillyrename(old_dir, old_dentry);
+ /*
+ * First check whether the target is busy ... we can't
+ * safely do _any_ rename if the target is in use.
+ */
+ if (new_dentry->d_count > 1) {
+ if (new_inode && S_ISDIR(new_inode->i_mode))
+ shrink_dcache_parent(new_dentry);
+ }
+ error = -EBUSY;
+ if (new_dentry->d_count > 1) {
+#ifdef NFS_PARANOIA
+printk("nfs_rename: target %s/%s busy, d_count=%d\n",
+new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
+#endif
+ goto out;
+ }
- if (error == -EBUSY) {
- return -EBUSY;
- } else if (error == 0) { /* did silly rename stuff */
- error = nfs_link(old_dentry->d_inode,
- new_dir, new_dentry);
-
- return error;
+ /*
+ * Check for within-directory rename ... no complications.
+ */
+ if (new_dir == old_dir)
+ goto do_rename;
+ /*
+ * Cross-directory move ... check whether it's a file.
+ */
+ if (S_ISREG(old_inode->i_mode)) {
+ if (NFS_WRITEBACK(old_inode)) {
+#ifdef NFS_PARANOIA
+printk("nfs_rename: %s/%s has pending writes\n",
+old_dentry->d_parent->d_name.name, old_dentry->d_name.name);
+#endif
+ nfs_flush_dirty_pages(old_inode, 0, 0, 0);
+ if (NFS_WRITEBACK(old_inode)) {
+#ifdef NFS_PARANOIA
+printk("nfs_rename: %s/%s has pending writes after flush\n",
+old_dentry->d_parent->d_name.name, old_dentry->d_name.name);
+#endif
+ goto out;
+ }
}
- /* no need for silly rename, proceed as usual */
}
- error = nfs_proc_rename(NFS_SERVER(old_dir),
- NFS_FH(old_dir), old_dentry->d_name.name,
- NFS_FH(new_dir), new_dentry->d_name.name);
- if (error)
- return error;
-
- nfs_invalidate_dircache(old_dir);
- nfs_invalidate_dircache(new_dir);
+ /*
+ * Moving a directory ... prune child dentries if needed.
+ */
+ else if (old_dentry->d_count > 1)
+ shrink_dcache_parent(old_dentry);
- /* Update the dcache */
- d_move(old_dentry, new_dentry);
- return 0;
-}
+ /*
+ * Now check the use counts ... we can't safely do the
+ * rename unless we can drop the dentries first.
+ */
+ if (old_dentry->d_count > 1) {
+#ifdef NFS_PARANOIA
+printk("nfs_rename: old dentry %s/%s busy, d_count=%d\n",
+old_dentry->d_parent->d_name.name,old_dentry->d_name.name,old_dentry->d_count);
+#endif
+ goto out;
+ }
+ if (new_dentry->d_count > 1) {
+#ifdef NFS_PARANOIA
+printk("nfs_rename: new dentry %s/%s busy, d_count=%d\n",
+new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
+#endif
+ goto out;
+ }
-/*
- * Many nfs protocol calls return the new file attributes after
- * an operation. Here we update the inode to reflect the state
- * of the server's inode.
- */
+ d_drop(old_dentry);
+ update = 0;
-void nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
-{
- int was_empty;
-
- dfprintk(VFS, "NFS: refresh_inode(%x/%ld ct=%d)\n",
- inode->i_dev, inode->i_ino, inode->i_count);
-
- if (!inode || !fattr) {
- printk("nfs_refresh_inode: inode or fattr is NULL\n");
- return;
- }
- if (inode->i_ino != fattr->fileid) {
- printk("nfs_refresh_inode: inode number mismatch\n");
- return;
- }
- was_empty = (inode->i_mode == 0);
- inode->i_mode = fattr->mode;
- inode->i_nlink = fattr->nlink;
- inode->i_uid = fattr->uid;
- inode->i_gid = fattr->gid;
-
- /* Size changed from outside: invalidate caches on next read */
- if (inode->i_size != fattr->size) {
- dfprintk(PAGECACHE, "NFS: cacheinv(%x/%ld)\n",
- inode->i_dev, inode->i_ino);
- NFS_CACHEINV(inode);
- }
- if (NFS_OLDMTIME(inode) != fattr->mtime.seconds) {
- dfprintk(PAGECACHE, "NFS: mtime change on %x/%ld\n",
- inode->i_dev, inode->i_ino);
- NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
- }
- inode->i_size = fattr->size;
- if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
- inode->i_rdev = to_kdev_t(fattr->rdev);
- else
- inode->i_rdev = 0;
- inode->i_blocks = fattr->blocks;
- inode->i_atime = fattr->atime.seconds;
- inode->i_mtime = fattr->mtime.seconds;
- inode->i_ctime = fattr->ctime.seconds;
- if (S_ISREG(inode->i_mode))
- inode->i_op = &nfs_file_inode_operations;
- else if (S_ISDIR(inode->i_mode))
- inode->i_op = &nfs_dir_inode_operations;
- else if (S_ISLNK(inode->i_mode))
- inode->i_op = &nfs_symlink_inode_operations;
- else if (S_ISCHR(inode->i_mode))
- inode->i_op = &chrdev_inode_operations;
- else if (S_ISBLK(inode->i_mode))
- inode->i_op = &blkdev_inode_operations;
- else if (S_ISFIFO(inode->i_mode)) {
- if (was_empty)
- init_fifo(inode);
- } else
- inode->i_op = NULL;
+do_rename:
+ /*
+ * We must prevent any new references to the target while
+ * the rename is in progress, so we unhash the dentry.
+ */
+ if (!list_empty(&new_dentry->d_hash)) {
+ d_drop(new_dentry);
+ rehash = 1;
+ }
+ error = nfs_proc_rename(NFS_SERVER(old_dir),
+ NFS_FH(old_dir), old_dentry->d_name.name,
+ NFS_FH(new_dir), new_dentry->d_name.name);
+ if (rehash) {
+ d_add(new_dentry, new_inode);
+ }
+#ifdef NFS_PARANOIA
+if (new_dentry->d_count > 1)
+printk("nfs_rename: %s/%s busy after rename, d_count=%d\n",
+new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
+#endif
+ if (!error) {
+ nfs_invalidate_dircache(new_dir);
+ nfs_invalidate_dircache(old_dir);
+ /* Update the dcache if needed */
+ if (update)
+ d_move(old_dentry, new_dentry);
+ }
+out:
+ return error;
}
/*
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 4587950ef..0f3bd5ed3 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -33,9 +33,8 @@
#define NFSDBG_FACILITY NFSDBG_FILE
static int nfs_file_mmap(struct file *, struct vm_area_struct *);
-static long nfs_file_read(struct inode *, struct file *, char *, unsigned long);
-static long nfs_file_write(struct inode *, struct file *,
- const char *, unsigned long);
+static ssize_t nfs_file_read(struct file *, char *, size_t, loff_t *);
+static ssize_t nfs_file_write(struct file *, const char *, size_t, loff_t *);
static int nfs_file_close(struct inode *, struct file *);
static int nfs_fsync(struct file *, struct dentry *dentry);
@@ -84,67 +83,91 @@ struct inode_operations nfs_file_inode_operations = {
# define IS_SWAPFILE(inode) (0)
#endif
-
+/*
+ * Flush all dirty pages, and check for write errors.
+ *
+ * Note that since the file close operation is called only by the
+ * _last_ process to close the file, we need to flush _all_ dirty
+ * pages. This also means that there is little sense in checking
+ * for errors for this specific process -- we should probably just
+ * clear all errors.
+ */
static int
nfs_file_close(struct inode *inode, struct file *file)
{
- int status;
+ int status, error;
dfprintk(VFS, "nfs: close(%x/%ld)\n", inode->i_dev, inode->i_ino);
- if ((status = nfs_flush_dirty_pages(inode, 0, 0)) < 0)
- return status;
- return nfs_write_error(inode);
+ status = nfs_flush_dirty_pages(inode, 0, 0, 0);
+ error = nfs_write_error(inode);
+ if (!status)
+ status = error;
+ return status;
}
-static long
-nfs_file_read(struct inode * inode, struct file * file,
- char * buf, unsigned long count)
+static ssize_t
+nfs_file_read(struct file * file, char * buf, size_t count, loff_t *ppos)
{
- int status;
+ struct inode * inode = file->f_dentry->d_inode;
+ ssize_t result;
dfprintk(VFS, "nfs: read(%x/%ld, %lu@%lu)\n",
inode->i_dev, inode->i_ino, count,
- (unsigned long) file->f_pos);
+ (unsigned long) *ppos);
- if ((status = nfs_revalidate_inode(NFS_SERVER(inode), inode)) < 0)
- return status;
- return generic_file_read(inode, file, buf, count);
+ result = nfs_revalidate_inode(NFS_SERVER(inode), inode);
+ if (!result)
+ result = generic_file_read(file, buf, count, ppos);
+ return result;
}
static int
nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
{
- int status;
struct inode *inode = file->f_dentry->d_inode;
+ int status;
dfprintk(VFS, "nfs: mmap(%x/%ld)\n", inode->i_dev, inode->i_ino);
- if ((status = nfs_revalidate_inode(NFS_SERVER(inode), inode)) < 0)
- return status;
- return generic_file_mmap(file, vma);
+ status = nfs_revalidate_inode(NFS_SERVER(inode), inode);
+ if (!status)
+ status = generic_file_mmap(file, vma);
+ return status;
}
-static int nfs_fsync(struct file *file, struct dentry *dentry)
+/*
+ * Flush any dirty pages for this process, and check for write errors.
+ * The return status from this call provides a reliable indication of
+ * whether any write errors occurred for this process.
+ */
+static int
+nfs_fsync(struct file *file, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
+ int status, error;
+
dfprintk(VFS, "nfs: fsync(%x/%ld)\n", inode->i_dev, inode->i_ino);
- return nfs_flush_dirty_pages(inode, 0, 0);
+ status = nfs_flush_dirty_pages(inode, current->pid, 0, 0);
+ error = nfs_write_error(inode);
+ if (!status)
+ status = error;
+ return status;
}
/*
* Write to a file (through the page cache).
*/
-static long
-nfs_file_write(struct inode *inode, struct file *file,
- const char *buf, unsigned long count)
+static ssize_t
+nfs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
- int result;
+ struct inode * inode = file->f_dentry->d_inode;
+ ssize_t result;
dfprintk(VFS, "nfs: write(%x/%ld (%d), %lu@%lu)\n",
inode->i_dev, inode->i_ino, inode->i_count,
- count, (unsigned long) file->f_pos);
+ count, (unsigned long) *ppos);
if (!inode) {
printk("nfs_file_write: inode = NULL\n");
@@ -154,21 +177,26 @@ nfs_file_write(struct inode *inode, struct file *file,
printk("NFS: attempt to write to active swap file!\n");
return -EBUSY;
}
- if ((result = nfs_revalidate_inode(NFS_SERVER(inode), inode)) < 0)
- return result;
+ result = nfs_revalidate_inode(NFS_SERVER(inode), inode);
+ if (result)
+ goto out;
+
+ /* N.B. This should be impossible now -- inodes can't change mode */
if (!S_ISREG(inode->i_mode)) {
printk("nfs_file_write: write to non-file, mode %07o\n",
inode->i_mode);
return -EINVAL;
}
- if (count <= 0)
- return 0;
-
- /* Return error from previous async call */
- if ((result = nfs_write_error(inode)) < 0)
- return result;
-
- return generic_file_write(inode, file, buf, count);
+ result = count;
+ if (!count)
+ goto out;
+
+ /* Check for an error from a previous async call */
+ result = nfs_write_error(inode);
+ if (!result)
+ result = generic_file_write(file, buf, count, ppos);
+out:
+ return result;
}
/*
@@ -177,15 +205,15 @@ nfs_file_write(struct inode *inode, struct file *file,
int
nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
{
+ struct inode * inode = filp->f_dentry->d_inode;
int status;
- struct inode * inode;
dprintk("NFS: nfs_lock(f=%4x/%ld, t=%x, fl=%x, r=%ld:%ld)\n",
- filp->f_dentry->d_inode->i_dev, filp->f_dentry->d_inode->i_ino,
+ inode->i_dev, inode->i_ino,
fl->fl_type, fl->fl_flags,
fl->fl_start, fl->fl_end);
- if (!(inode = filp->f_dentry->d_inode))
+ if (!inode)
return -EINVAL;
/* No mandatory locks over NFS */
@@ -209,8 +237,8 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
/* If unlocking a file region, flush dirty pages (unless we've
* been killed by a signal, that is). */
if (cmd == F_SETLK && fl->fl_type == F_UNLCK
- && !(current->signal & ~current->blocked)) {
- status = nfs_flush_dirty_pages(inode,
+ && !signal_pending(current)) {
+ status = nfs_flush_dirty_pages(inode, current->pid,
fl->fl_start, fl->fl_end == NLM_OFFSET_MAX? 0 :
fl->fl_end - fl->fl_start + 1);
if (status < 0)
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index e91b34a34..c070d130b 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -33,13 +33,17 @@
#include <asm/uaccess.h>
#define NFSDBG_FACILITY NFSDBG_VFS
+#define NFS_PARANOIA 1
-static int nfs_notify_change(struct inode *, struct iattr *);
+extern void nfs_invalidate_dircache_sb(struct super_block *);
+extern int check_failed_request(struct inode *);
+
+static void nfs_read_inode(struct inode *);
static void nfs_put_inode(struct inode *);
static void nfs_delete_inode(struct inode *);
+static int nfs_notify_change(struct inode *, struct iattr *);
static void nfs_put_super(struct super_block *);
-static void nfs_read_inode(struct inode *);
-static int nfs_statfs(struct super_block *, struct statfs *, int bufsiz);
+static int nfs_statfs(struct super_block *, struct statfs *, int);
static struct super_operations nfs_sops = {
nfs_read_inode, /* read inode */
@@ -67,20 +71,51 @@ nfs_read_inode(struct inode * inode)
{
inode->i_blksize = inode->i_sb->s_blocksize;
inode->i_mode = 0;
+ inode->i_rdev = 0;
inode->i_op = NULL;
NFS_CACHEINV(inode);
+ NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
}
static void
nfs_put_inode(struct inode * inode)
{
dprintk("NFS: put_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
+ /*
+ * We want to get rid of unused inodes ...
+ */
+ if (inode->i_count == 1)
+ inode->i_nlink = 0;
}
static void
nfs_delete_inode(struct inode * inode)
{
+ int failed;
+
dprintk("NFS: delete_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
+ /*
+ * Flush out any pending write requests ...
+ */
+ if (NFS_WRITEBACK(inode) != NULL) {
+ unsigned long timeout = jiffies + 5*HZ;
+ printk("NFS: inode %ld, invalidating pending RPC requests\n",
+ inode->i_ino);
+ nfs_invalidate_pages(inode);
+ while (NFS_WRITEBACK(inode) != NULL && jiffies < timeout) {
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + HZ/10;
+ schedule();
+ }
+ current->state = TASK_RUNNING;
+ if (NFS_WRITEBACK(inode) != NULL)
+ printk("NFS: Arghhh, stuck RPC requests!\n");
+ }
+
+ failed = check_failed_request(inode);
+ if (failed)
+ printk("NFS: inode %ld had %d failed requests\n",
+ inode->i_ino, failed);
clear_inode(inode);
}
@@ -90,13 +125,21 @@ nfs_put_super(struct super_block *sb)
struct nfs_server *server = &sb->u.nfs_sb.s_server;
struct rpc_clnt *rpc;
+ /*
+ * Lock the super block while we bring down the daemons.
+ */
+ lock_super(sb);
if ((rpc = server->client) != NULL)
rpc_shutdown_client(rpc);
if (!(server->flags & NFS_MOUNT_NONLM))
lockd_down(); /* release rpc.lockd */
rpciod_down(); /* release rpciod */
- lock_super(sb);
+ /*
+ * Invalidate the dircache for this superblock.
+ */
+ nfs_invalidate_dircache_sb(sb);
+
sb->s_dev = 0;
unlock_super(sb);
MOD_DEC_USE_COUNT;
@@ -147,14 +190,12 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
unsigned int authflavor;
int tcp;
kdev_t dev = sb->s_dev;
+ struct inode *root_inode;
MOD_INC_USE_COUNT;
- if (!data) {
- printk("nfs_read_super: missing data argument\n");
- sb->s_dev = 0;
- MOD_DEC_USE_COUNT;
- return NULL;
- }
+ if (!data)
+ goto out_miss_args;
+
if (data->version != NFS_MOUNT_VERSION) {
printk("nfs warning: mount version %s than kernel\n",
data->version < NFS_MOUNT_VERSION ? "older" : "newer");
@@ -164,13 +205,19 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
data->bsize = 0;
}
+ /* We now require that the mount process passes the remote address */
+ memcpy(&srvaddr, &data->addr, sizeof(srvaddr));
+ if (srvaddr.sin_addr.s_addr == INADDR_ANY)
+ goto out_no_remote;
+
lock_super(sb);
- server = &sb->u.nfs_sb.s_server;
sb->s_magic = NFS_SUPER_MAGIC;
sb->s_dev = dev;
sb->s_op = &nfs_sops;
sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
+ sb->u.nfs_sb.s_root = data->root;
+ server = &sb->u.nfs_sb.s_server;
server->rsize = nfs_block_size(data->rsize, NULL);
server->wsize = nfs_block_size(data->wsize, NULL);
server->flags = data->flags;
@@ -179,15 +226,6 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
server->acdirmin = data->acdirmin*HZ;
server->acdirmax = data->acdirmax*HZ;
strcpy(server->hostname, data->hostname);
- sb->u.nfs_sb.s_root = data->root;
-
- /* We now require that the mount process passes the remote address */
- memcpy(&srvaddr, &data->addr, sizeof(srvaddr));
- if (srvaddr.sin_addr.s_addr == INADDR_ANY) {
- printk("NFS: mount program didn't pass remote address!\n");
- MOD_DEC_USE_COUNT;
- return NULL;
- }
/* Which protocol do we use? */
tcp = (data->flags & NFS_MOUNT_TCP);
@@ -210,18 +248,13 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
/* Now create transport and client */
xprt = xprt_create_proto(tcp? IPPROTO_TCP : IPPROTO_UDP,
&srvaddr, &timeparms);
- if (xprt == NULL) {
- printk("NFS: cannot create RPC transport.\n");
- goto failure;
- }
+ if (xprt == NULL)
+ goto out_no_xprt;
clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
NFS_VERSION, authflavor);
- if (clnt == NULL) {
- printk("NFS: cannot create RPC client.\n");
- xprt_destroy(xprt);
- goto failure;
- }
+ if (clnt == NULL)
+ goto out_no_client;
clnt->cl_intr = (data->flags & NFS_MOUNT_INTR)? 1 : 0;
clnt->cl_softrtry = (data->flags & NFS_MOUNT_SOFT)? 1 : 0;
@@ -229,29 +262,67 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
server->client = clnt;
/* Fire up rpciod if not yet running */
+#ifdef RPCIOD_RESULT
+ if (rpciod_up())
+ goto out_no_iod;
+#else
rpciod_up();
+#endif
- /* Unlock super block and try to get root fh attributes */
+ /*
+ * Keep the super block locked while we try to get
+ * the root fh attributes.
+ */
+ root_inode = nfs_fhget(sb, &data->root, NULL);
+ if (!root_inode)
+ goto out_no_root;
+ sb->s_root = d_alloc_root(root_inode, NULL);
+ if (!sb->s_root)
+ goto out_no_root;
+ /* We're airborne */
unlock_super(sb);
- sb->s_root = d_alloc_root(nfs_fhget(sb, &data->root, NULL), NULL);
- if (sb->s_root != NULL) {
- /* We're airborne */
- if (!(server->flags & NFS_MOUNT_NONLM))
- lockd_up();
- return sb;
- }
+ /* Check whether to start the lockd process */
+ if (!(server->flags & NFS_MOUNT_NONLM))
+ lockd_up();
+ return sb;
/* Yargs. It didn't work out. */
+out_no_root:
printk("nfs_read_super: get root inode failed\n");
- rpc_shutdown_client(server->client);
+ iput(root_inode);
rpciod_down();
+#ifdef RPCIOD_RESULT
+ goto out_shutdown;
-failure:
- MOD_DEC_USE_COUNT;
- if (sb->s_lock)
- unlock_super(sb);
+out_no_iod:
+ printk("nfs_read_super: couldn't start rpciod!\n");
+out_shutdown:
+#endif
+ rpc_shutdown_client(server->client);
+ goto out_unlock;
+
+out_no_client:
+ printk("NFS: cannot create RPC client.\n");
+ xprt_destroy(xprt);
+ goto out_unlock;
+
+out_no_xprt:
+ printk("NFS: cannot create RPC transport.\n");
+out_unlock:
+ unlock_super(sb);
+ goto out_fail;
+
+out_no_remote:
+ printk("NFS: mount program didn't pass remote address!\n");
+ goto out_fail;
+
+out_miss_args:
+ printk("nfs_read_super: missing data argument\n");
+
+out_fail:
sb->s_dev = 0;
+ MOD_DEC_USE_COUNT;
return NULL;
}
@@ -312,14 +383,48 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fhandle,
printk("nfs_fhget: iget failed\n");
return NULL;
}
- if (inode->i_dev == sb->s_dev) {
- if (inode->i_ino != fattr->fileid) {
- printk("nfs_fhget: unexpected inode from iget\n");
- return inode;
- }
- *NFS_FH(inode) = *fhandle;
- nfs_refresh_inode(inode, fattr);
+#ifdef NFS_PARANOIA
+if (inode->i_dev != sb->s_dev)
+printk("nfs_fhget: impossible\n");
+#endif
+
+ if (inode->i_ino != fattr->fileid) {
+ printk("nfs_fhget: unexpected inode from iget\n");
+ return inode;
}
+
+ /*
+ * Check whether the mode has been set, as we only want to
+ * do this once. (We don't allow inodes to change types.)
+ */
+ if (inode->i_mode == 0) {
+ inode->i_mode = fattr->mode;
+ if (S_ISREG(inode->i_mode))
+ inode->i_op = &nfs_file_inode_operations;
+ else if (S_ISDIR(inode->i_mode))
+ inode->i_op = &nfs_dir_inode_operations;
+ else if (S_ISLNK(inode->i_mode))
+ inode->i_op = &nfs_symlink_inode_operations;
+ else if (S_ISCHR(inode->i_mode)) {
+ inode->i_op = &chrdev_inode_operations;
+ inode->i_rdev = to_kdev_t(fattr->rdev);
+ } else if (S_ISBLK(inode->i_mode)) {
+ inode->i_op = &blkdev_inode_operations;
+ inode->i_rdev = to_kdev_t(fattr->rdev);
+ } else if (S_ISFIFO(inode->i_mode))
+ init_fifo(inode);
+ else
+ inode->i_op = NULL;
+ /*
+ * Preset the size and mtime, as there's no need
+ * to invalidate the caches.
+ */
+ inode->i_size = fattr->size;
+ inode->i_mtime = fattr->mtime.seconds;
+ NFS_OLDMTIME(inode) = fattr->mtime.seconds;
+ }
+ *NFS_FH(inode) = *fhandle;
+ nfs_refresh_inode(inode, fattr);
dprintk("NFS: fhget(%x/%ld ct=%d)\n",
inode->i_dev, inode->i_ino,
inode->i_count);
@@ -334,6 +439,17 @@ nfs_notify_change(struct inode *inode, struct iattr *attr)
struct nfs_fattr fattr;
int error;
+ /*
+ * Make sure the inode is up-to-date.
+ */
+ error = nfs_revalidate(inode);
+ if (error) {
+#ifdef NFS_PARANOIA
+printk("nfs_notify_change: revalidate failed, error=%d\n", error);
+#endif
+ goto out;
+ }
+
sattr.mode = (u32) -1;
if (attr->ia_valid & ATTR_MODE)
sattr.mode = attr->ia_mode;
@@ -346,7 +462,6 @@ nfs_notify_change(struct inode *inode, struct iattr *attr)
if (attr->ia_valid & ATTR_GID)
sattr.gid = attr->ia_gid;
-
sattr.size = (u32) -1;
if ((attr->ia_valid & ATTR_SIZE) && S_ISREG(inode->i_mode))
sattr.size = attr->ia_size;
@@ -364,11 +479,25 @@ nfs_notify_change(struct inode *inode, struct iattr *attr)
}
error = nfs_proc_setattr(NFS_SERVER(inode), NFS_FH(inode),
- &sattr, &fattr);
- if (!error) {
+ &sattr, &fattr);
+ if (error)
+ goto out;
+ /*
+ * If we changed the size or mtime, update the inode
+ * now to avoid invalidating the page cache.
+ */
+ if (sattr.size != (u32) -1) {
+ if (sattr.size != fattr.size)
+ printk("nfs_notify_change: sattr=%d, fattr=%d??\n",
+ sattr.size, fattr.size);
nfs_truncate_dirty_pages(inode, sattr.size);
- nfs_refresh_inode(inode, &fattr);
+ inode->i_size = sattr.size;
+ inode->i_mtime = fattr.mtime.seconds;
}
+ if (sattr.mtime.seconds != (u32) -1)
+ inode->i_mtime = fattr.mtime.seconds;
+ error = nfs_refresh_inode(inode, &fattr);
+out:
return error;
}
@@ -384,57 +513,154 @@ nfs_revalidate(struct inode *inode)
/*
* This function is called whenever some part of NFS notices that
* the cached attributes have to be refreshed.
- *
- * This is a bit tricky because we have to make sure all dirty pages
- * have been sent off to the server before calling invalidate_inode_pages.
- * To make sure no other process adds more write requests while we try
- * our best to flush them, we make them sleep during the attribute refresh.
- *
- * A very similar scenario holds for the dir cache.
*/
int
_nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
{
struct nfs_fattr fattr;
- int status;
+ int status = 0;
if (jiffies - NFS_READTIME(inode) < NFS_ATTRTIMEO(inode))
- return 0;
+ goto out;
dfprintk(PAGECACHE, "NFS: revalidating %x/%ld inode\n",
inode->i_dev, inode->i_ino);
- NFS_READTIME(inode) = jiffies;
- if ((status = nfs_proc_getattr(server, NFS_FH(inode), &fattr)) < 0)
+ status = nfs_proc_getattr(server, NFS_FH(inode), &fattr);
+ if (status) {
+#ifdef NFS_PARANOIA
+printk("nfs_revalidate_inode: getattr failed, error=%d\n", status);
+#endif
goto done;
+ }
- nfs_refresh_inode(inode, &fattr);
- if (fattr.mtime.seconds != NFS_OLDMTIME(inode)) {
- if (!S_ISDIR(inode->i_mode)) {
- /* This sends off all dirty pages off to the server.
- * Note that this function must not sleep. */
- nfs_invalidate_pages(inode);
- invalidate_inode_pages(inode);
- } else {
- nfs_invalidate_dircache(inode);
- }
-
- NFS_OLDMTIME(inode) = fattr.mtime.seconds;
- NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
- } else {
+ status = nfs_refresh_inode(inode, &fattr);
+ if (status)
+ goto done;
+ if (fattr.mtime.seconds == NFS_OLDMTIME(inode)) {
/* Update attrtimeo value */
if ((NFS_ATTRTIMEO(inode) <<= 1) > NFS_MAXATTRTIMEO(inode))
NFS_ATTRTIMEO(inode) = NFS_MAXATTRTIMEO(inode);
}
- status = 0;
+ NFS_OLDMTIME(inode) = fattr.mtime.seconds;
done:
dfprintk(PAGECACHE,
"NFS: inode %x/%ld revalidation complete (status %d).\n",
inode->i_dev, inode->i_ino, status);
+out:
return status;
}
/*
+ * Many nfs protocol calls return the new file attributes after
+ * an operation. Here we update the inode to reflect the state
+ * of the server's inode.
+ *
+ * This is a bit tricky because we have to make sure all dirty pages
+ * have been sent off to the server before calling invalidate_inode_pages.
+ * To make sure no other process adds more write requests while we try
+ * our best to flush them, we make them sleep during the attribute refresh.
+ *
+ * A very similar scenario holds for the dir cache.
+ */
+int
+nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
+{
+ int invalid = 0;
+ int error = -EIO;
+
+ dfprintk(VFS, "NFS: refresh_inode(%x/%ld ct=%d)\n",
+ inode->i_dev, inode->i_ino, inode->i_count);
+
+ if (!inode || !fattr) {
+ printk("nfs_refresh_inode: inode or fattr is NULL\n");
+ goto out;
+ }
+ if (inode->i_ino != fattr->fileid) {
+ printk("nfs_refresh_inode: inode number mismatch\n");
+ goto out;
+ }
+
+ /*
+ * Make sure the inode's type hasn't changed.
+ */
+ if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
+ goto out_changed;
+
+ /*
+ * If the size or mtime changed from outside, we want
+ * to invalidate the local caches immediately.
+ */
+ if (inode->i_size != fattr->size) {
+#ifdef NFS_DEBUG_VERBOSE
+printk("NFS: size change on %x/%ld\n", inode->i_dev, inode->i_ino);
+#endif
+ invalid = 1;
+ }
+ if (inode->i_mtime != fattr->mtime.seconds) {
+#ifdef NFS_DEBUG_VERBOSE
+printk("NFS: mtime change on %x/%ld\n", inode->i_dev, inode->i_ino);
+#endif
+ invalid = 1;
+ }
+
+ inode->i_mode = fattr->mode;
+ inode->i_nlink = fattr->nlink;
+ inode->i_uid = fattr->uid;
+ inode->i_gid = fattr->gid;
+
+ inode->i_size = fattr->size;
+ inode->i_blocks = fattr->blocks;
+ inode->i_atime = fattr->atime.seconds;
+ inode->i_mtime = fattr->mtime.seconds;
+ inode->i_ctime = fattr->ctime.seconds;
+ /*
+ * Update the read time so we don't revalidate too often.
+ */
+ NFS_READTIME(inode) = jiffies;
+ error = 0;
+ if (invalid)
+ goto out_invalid;
+out:
+ return error;
+
+out_changed:
+ /*
+ * Big trouble! The inode has become a different object.
+ */
+#ifdef NFS_PARANOIA
+printk("nfs_refresh_inode: inode %ld mode changed, %07o to %07o\n",
+inode->i_ino, inode->i_mode, fattr->mode);
+#endif
+ fattr->mode = inode->i_mode; /* save mode */
+ make_bad_inode(inode);
+ inode->i_mode = fattr->mode; /* restore mode */
+ /*
+ * No need to worry about unhashing the dentry, as the
+ * lookup validation will know that the inode is bad.
+ * (But we fall through to invalidate the caches.)
+ */
+
+out_invalid:
+ /*
+ * Invalidate the local caches
+ */
+#ifdef NFS_DEBUG_VERBOSE
+printk("nfs_refresh_inode: invalidating %ld pages\n", inode->i_nrpages);
+#endif
+ if (!S_ISDIR(inode->i_mode)) {
+ /* This sends off all dirty pages off to the server.
+ * Note that this function must not sleep. */
+ nfs_invalidate_pages(inode);
+ invalidate_inode_pages(inode);
+ } else
+ nfs_invalidate_dircache(inode);
+ NFS_CACHEINV(inode);
+ NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
+ goto out;
+}
+
+/*
* File system information
*/
static struct file_system_type nfs_fs_type = {
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index 5eec5eb65..0311b7d0b 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -23,6 +23,7 @@
#include <linux/nfs_fs.h>
#define NFSDBG_FACILITY NFSDBG_XDR
+/* #define NFS_PARANOIA 1 */
#define QUADLEN(len) (((len) + 3) >> 2)
static int nfs_stat_to_errno(int stat);
@@ -371,17 +372,18 @@ nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
* to avoid a malloc of NFS_MAXNAMLEN+1 for each file name.
* After decoding, the layout in memory looks like this:
* entry1 entry2 ... entryN <space> stringN ... string2 string1
+ * Each entry consists of three __u32 values, the same space as NFS uses.
* Note that the strings are not null-terminated so that the entire number
* of entries returned by the server should fit into the buffer.
*/
static int
nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
{
- struct nfs_entry *entry;
struct iovec *iov = req->rq_rvec;
int status, nr, len;
- char *string;
+ char *string, *start;
u32 *end;
+ __u32 fileid, cookie, *entry;
if ((status = ntohl(*p++)))
return -nfs_stat_to_errno(status);
@@ -396,10 +398,11 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
end = (u32 *) ((u8 *) p + iov[1].iov_len);
/* Get start and end of dirent buffer */
- entry = (struct nfs_entry *) res->buffer;
+ entry = (__u32 *) res->buffer;
+ start = (char *) res->buffer;
string = (char *) res->buffer + res->bufsiz;
- for (nr = 0; *p++; nr++, entry++) {
- entry->fileid = ntohl(*p++);
+ for (nr = 0; *p++; nr++) {
+ fileid = ntohl(*p++);
len = ntohl(*p++);
if ((p + QUADLEN(len) + 3) > end) {
@@ -413,27 +416,36 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
return -errno_NFSERR_IO;
}
string -= len;
- if ((void *) (entry+1) > (void *) string) {
- /* This may actually happen because an nfs_entry
- * will take up more space than the XDR data. On
- * 32bit machines that's due to 8byte alignment,
- * on 64bit machines that's because the char * takes
- * up 2 longs.
- *
- * THIS IS BAD!
+ if ((void *) (entry+3) > (void *) string) {
+ /*
+ * This error is impossible as long as the temp
+ * buffer is no larger than the user buffer. The
+ * current packing algorithm uses the same amount
+ * of space in the user buffer as in the XDR data,
+ * so it's guaranteed to fit.
*/
- printk(KERN_NOTICE "NFS: should not happen in %s!\n",
+ printk("NFS: incorrect buffer size in %s!\n",
__FUNCTION__);
break;
}
- entry->name = string;
- entry->length = len;
memmove(string, p, len);
p += QUADLEN(len);
- entry->cookie = ntohl(*p++);
- entry->eof = !p[0] && p[1];
+ cookie = ntohl(*p++);
+ /*
+ * To make everything fit, we encode the length, offset,
+ * and eof flag into 32 bits. This works for filenames
+ * up to 32K and PAGE_SIZE up to 64K.
+ */
+ status = !p[0] && p[1] ? (1 << 15) : 0; /* eof flag */
+ *entry++ = fileid;
+ *entry++ = cookie;
+ *entry++ = ((string - start) << 16) | status | (len & 0x7FFF);
}
+#ifdef NFS_PARANOIA
+printk("nfs_xdr_readdirres: %d entries, ent sp=%d, str sp=%d\n",
+nr, ((char *) entry - start), (start + res->bufsiz - string));
+#endif
return nr;
}
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index f48a6217c..94096d928 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -384,17 +384,18 @@ nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
* to avoid a malloc of NFS_MAXNAMLEN+1 for each file name.
* After decoding, the layout in memory looks like this:
* entry1 entry2 ... entryN <space> stringN ... string2 string1
+ * Each entry consists of three __u32 values, the same space as NFS uses.
* Note that the strings are not null-terminated so that the entire number
* of entries returned by the server should fit into the buffer.
*/
static int
nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
{
- struct nfs_entry *entry;
struct iovec *iov = req->rq_rvec;
int status, nr, len;
- char *string;
+ char *string, *start;
u32 *end;
+ __u32 fileid, cookie, *entry;
if ((status = ntohl(*p++)))
return -nfs_stat_to_errno(status);
@@ -413,10 +414,11 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
return -errno_NFSERR_IO;
}
- string = (char *) res->buffer + res->bufsiz;
- entry = (struct nfs_entry *) res->buffer;
- for (nr = 0; *p++; nr++, entry++) {
- entry->fileid = ntohl(*p++);
+ entry = (__u32 *) res->buffer;
+ start = (char *) res->buffer;
+ string = start + res->bufsiz;
+ for (nr = 0; *p++; nr++) {
+ fileid = ntohl(*p++);
len = ntohl(*p++);
if ((p + QUADLEN(len) + 3) > end) {
@@ -430,22 +432,40 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
return -errno_NFSERR_IO;
}
string -= len;
- if ((void *) (entry+1) > (void *) string) {
- dprintk("NFS: shouldnothappen in readdirres_decode!\n");
- break; /* should not happen */
+ if ((void *) (entry+3) > (void *) string) {
+ /*
+ * This error is impossible as long as the temp
+ * buffer is no larger than the user buffer. The
+ * current packing algorithm uses the same amount
+ * of space in the user buffer as in the XDR data,
+ * so it's guaranteed to fit.
+ */
+ printk("NFS: incorrect buffer size in %s!\n",
+ __FUNCTION__);
+ break;
}
- entry->name = string;
- entry->length = len;
memmove(string, p, len);
p += QUADLEN(len);
- entry->cookie = ntohl(*p++);
- entry->eof = !p[0] && p[1];
+ cookie = ntohl(*p++);
+ /*
+ * To make everything fit, we encode the length, offset,
+ * and eof flag into 32 bits. This works for filenames
+ * up to 32K and PAGE_SIZE up to 64K.
+ */
+ status = !p[0] && p[1] ? (1 << 15) : 0; /* eof flag */
+ *entry++ = fileid;
+ *entry++ = cookie;
+ *entry++ = ((string - start) << 16) | status | (len & 0x7FFF);
/*
dprintk("NFS: decoded dirent %.*s cookie %d eof %d\n",
- len, string, entry->cookie, entry->eof);
+ len, string, cookie, status);
*/
}
+#ifdef NFS_PARANOIA
+printk("nfs_xdr_readdirres: %d entries, ent sp=%d, str sp=%d\n",
+nr, ((char *) entry - start), (start + res->bufsiz - string));
+#endif
return nr;
}
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 58dcd95d0..416ed294e 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -250,25 +250,43 @@ nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *name)
*/
int
nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
- u32 cookie, unsigned int size, struct nfs_entry *entry)
+ u32 cookie, unsigned int size, __u32 *entry)
{
struct nfs_readdirargs arg;
struct nfs_readdirres res;
void * buffer;
+ unsigned int buf_size = PAGE_SIZE;
int status;
/* First get a temp buffer for the readdir reply */
- while (!(buffer = (void *) get_free_page(GFP_USER))) {
- need_resched = 1;
- schedule();
- if (signalled())
- return -ERESTARTSYS;
- }
+ /* N.B. does this really need to be cleared? */
+ status = -ENOMEM;
+ buffer = (void *) get_free_page(GFP_KERNEL);
+ if (!buffer)
+ goto out;
+
+ /*
+ * Calculate the effective size the buffer. To make sure
+ * that the returned data will fit into the user's buffer,
+ * we decrease the buffer size as necessary.
+ *
+ * Note: NFS returns three __u32 values for each entry,
+ * and we assume that the data is packed into the user
+ * buffer with the same efficiency.
+ */
+ if (size < buf_size)
+ buf_size = size;
+ if (server->rsize < buf_size)
+ buf_size = server->rsize;
+#if 0
+printk("nfs_proc_readdir: user size=%d, rsize=%d, buf_size=%d\n",
+size, server->rsize, buf_size);
+#endif
arg.fh = fhandle;
arg.cookie = cookie;
arg.buffer = buffer;
- arg.bufsiz = server->rsize < PAGE_SIZE? server->rsize : PAGE_SIZE;
+ arg.bufsiz = buf_size;
res.buffer = entry;
res.bufsiz = size;
@@ -276,6 +294,7 @@ nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
status = rpc_call(server->client, NFSPROC_READDIR, &arg, &res, 0);
dprintk("NFS reply readdir: %d\n", status);
free_page((unsigned long) buffer);
+out:
return status;
}
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index ec5a1f7be..97663cc11 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -68,6 +68,8 @@
#define NFSDBG_FACILITY NFSDBG_PAGECACHE
+int check_failed_request(struct inode *);
+
static void nfs_wback_lock(struct rpc_task *task);
static void nfs_wback_result(struct rpc_task *task);
@@ -120,6 +122,7 @@ struct nfs_wreq {
* Limit number of delayed writes
*/
static int nr_write_requests = 0;
+static int nr_failed_requests = 0;
static struct rpc_wait_queue write_queue = RPC_INIT_WAITQ("write_chain");
struct nfs_wreq * nfs_failed_requests = NULL;
@@ -196,22 +199,44 @@ nfs_writepage_sync(struct inode *inode, struct page *page,
clear_bit(PG_uptodate, &page->flags);
goto io_error;
}
+ if (result != wsize)
+ printk("NFS: short write, wsize=%u, result=%d\n",
+ wsize, result);
refresh = 1;
buffer += wsize;
offset += wsize;
written += wsize;
count -= wsize;
+ /*
+ * If we've extended the file, update the inode
+ * now so we don't invalidate the cache.
+ */
+ if (offset > inode->i_size)
+ inode->i_size = offset;
} while (count);
io_error:
+ /* N.B. do we want to refresh if there was an error?? (fattr valid?) */
if (refresh) {
/* See comments in nfs_wback_result */
+ /* N.B. I don't think this is right -- sync writes in order */
if (fattr.size < inode->i_size)
fattr.size = inode->i_size;
+ if (fattr.mtime.seconds < inode->i_mtime)
+ printk("nfs_writepage_sync: prior time??\n");
/* Solaris 2.5 server seems to send garbled
* fattrs occasionally */
- if (inode->i_ino == fattr.fileid)
+ if (inode->i_ino == fattr.fileid) {
+ /*
+ * We expect the mtime value to change, and
+ * don't want to invalidate the caches.
+ */
+ inode->i_mtime = fattr.mtime.seconds;
nfs_refresh_inode(inode, &fattr);
+ }
+ else
+ printk("nfs_writepage_sync: inode %ld, got %u?\n",
+ inode->i_ino, fattr.fileid);
}
nfs_unlock_page(page);
@@ -260,28 +285,73 @@ find_write_request(struct inode *inode, struct page *page)
/*
* Find a failed write request by pid
*/
-static inline struct nfs_wreq *
+static struct nfs_wreq *
find_failed_request(struct inode *inode, pid_t pid)
{
struct nfs_wreq *head, *req;
- if (!(req = head = nfs_failed_requests))
- return NULL;
- do {
- if (req->wb_inode == inode && req->wb_pid == pid)
+ req = head = nfs_failed_requests;
+ while (req != NULL) {
+ if (req->wb_inode == inode && (pid == 0 || req->wb_pid == pid))
return req;
- } while ((req = WB_NEXT(req)) != head);
+ if ((req = WB_NEXT(req)) == head)
+ break;
+ }
return NULL;
}
/*
+ * Add a request to the failed list.
+ */
+static void
+append_failed_request(struct nfs_wreq * req)
+{
+ static int old_max = 16;
+
+ append_write_request(&nfs_failed_requests, req);
+ nr_failed_requests++;
+ if (nr_failed_requests >= old_max) {
+ printk("NFS: %d failed requests\n", nr_failed_requests);
+ old_max = old_max << 1;
+ }
+}
+
+/*
+ * Remove a request from the failed list and free it.
+ */
+static void
+remove_failed_request(struct nfs_wreq * req)
+{
+ remove_write_request(&nfs_failed_requests, req);
+ kfree(req);
+ nr_failed_requests--;
+}
+
+/*
+ * Find and release all failed requests for this inode.
+ */
+int
+check_failed_request(struct inode * inode)
+{
+ struct nfs_wreq * req;
+ int found = 0;
+
+ while ((req = find_failed_request(inode, 0)) != NULL) {
+ remove_failed_request(req);
+ found++;
+ }
+ return found;
+}
+
+/*
* Try to merge adjacent write requests. This works only for requests
* issued by the same user.
*/
static inline int
-update_write_request(struct nfs_wreq *req, unsigned first, unsigned bytes)
+update_write_request(struct nfs_wreq *req, unsigned int first,
+ unsigned int bytes)
{
- unsigned rqfirst = req->wb_offset,
+ unsigned int rqfirst = req->wb_offset,
rqlast = rqfirst + req->wb_bytes,
last = first + bytes;
@@ -313,7 +383,7 @@ update_write_request(struct nfs_wreq *req, unsigned first, unsigned bytes)
*/
static inline struct nfs_wreq *
create_write_request(struct inode *inode, struct page *page,
- unsigned offset, unsigned bytes)
+ unsigned int offset, unsigned int bytes)
{
struct nfs_wreq *wreq;
struct rpc_clnt *clnt = NFS_CLIENT(inode);
@@ -327,7 +397,7 @@ create_write_request(struct inode *inode, struct page *page,
wreq = (struct nfs_wreq *) kmalloc(sizeof(*wreq), GFP_USER);
if (!wreq)
- return NULL;
+ goto out_fail;
memset(wreq, 0, sizeof(*wreq));
task = &wreq->wb_task;
@@ -336,11 +406,8 @@ create_write_request(struct inode *inode, struct page *page,
task->tk_action = nfs_wback_lock;
rpcauth_lookupcred(task); /* Obtain user creds */
- if (task->tk_status < 0) {
- rpc_release_task(task);
- kfree(wreq);
- return NULL;
- }
+ if (task->tk_status < 0)
+ goto out_req;
/* Put the task on inode's writeback request list. */
wreq->wb_inode = inode;
@@ -357,6 +424,12 @@ create_write_request(struct inode *inode, struct page *page,
rpc_wake_up_next(&write_queue);
return wreq;
+
+out_req:
+ rpc_release_task(task);
+ kfree(wreq);
+out_fail:
+ return NULL;
}
/*
@@ -423,7 +496,9 @@ wait_on_write_request(struct nfs_wreq *req)
}
remove_wait_queue(&page->wait, &wait);
current->state = TASK_RUNNING;
- atomic_dec(&page->count);
+ if (atomic_read(&page->count) == 1)
+ printk("NFS: page unused while waiting\n");
+ free_page(page_address(page));
return retval;
}
@@ -487,12 +562,13 @@ nfs_updatepage(struct inode *inode, struct page *page, const char *buffer,
}
/* Create the write request. */
- if (!(req = create_write_request(inode, page, offset, count))) {
- status = -ENOBUFS;
+ status = -ENOBUFS;
+ req = create_write_request(inode, page, offset, count);
+ if (!req)
goto done;
- }
/* Copy data to page buffer. */
+ /* N.B. should check for fault here ... */
copy_from_user(page_addr + offset, buffer, count);
/* Schedule request */
@@ -519,6 +595,7 @@ done:
transfer_page_lock(req);
/* rpc_execute(&req->wb_task); */
if (sync) {
+ /* N.B. if signalled, result not ready? */
wait_on_write_request(req);
if ((count = nfs_write_error(inode)) < 0)
status = count;
@@ -578,10 +655,20 @@ nfs_flush_pages(struct inode *inode, pid_t pid, off_t offset, off_t len,
if (rqoffset < end && offset < rqend
&& (pid == 0 || req->wb_pid == pid)) {
- if (!WB_HAVELOCK(req))
+ if (!WB_HAVELOCK(req)) {
+#ifdef NFS_PARANOIA
+printk("nfs_flush: flushing inode=%ld, %d @ %lu\n",
+req->wb_inode->i_ino, req->wb_bytes, rqoffset);
+#endif
nfs_flush_request(req);
+ }
last = req;
}
+ } else {
+#ifdef NFS_PARANOIA
+printk("nfs_flush_pages: in progress inode=%ld, %d @ %lu\n",
+req->wb_inode->i_ino, req->wb_bytes, rqoffset);
+#endif
}
if (invalidate)
req->wb_flags |= NFS_WRITE_INVALIDATE;
@@ -593,7 +680,11 @@ nfs_flush_pages(struct inode *inode, pid_t pid, off_t offset, off_t len,
}
/*
- * Cancel all writeback requests, both pending and in process.
+ * Cancel all writeback requests, both pending and in progress.
+ *
+ * N.B. This doesn't seem to wake up the tasks -- are we sure
+ * they will eventually complete? Also, this could overwrite a
+ * failed status code from an already-completed task.
*/
static void
nfs_cancel_dirty(struct inode *inode, pid_t pid)
@@ -602,7 +693,8 @@ nfs_cancel_dirty(struct inode *inode, pid_t pid)
req = head = NFS_WRITEBACK(inode);
while (req != NULL) {
- if (req->wb_pid == pid) {
+ /* N.B. check for task already finished? */
+ if (pid == 0 || req->wb_pid == pid) {
req->wb_flags |= NFS_WRITE_CANCELLED;
rpc_exit(&req->wb_task, 0);
}
@@ -620,36 +712,43 @@ nfs_cancel_dirty(struct inode *inode, pid_t pid)
* this isn't used by the nlm module yet.
*/
int
-nfs_flush_dirty_pages(struct inode *inode, off_t offset, off_t len)
+nfs_flush_dirty_pages(struct inode *inode, pid_t pid, off_t offset, off_t len)
{
struct nfs_wreq *last = NULL;
+ int result = 0, cancel = 0;
dprintk("NFS: flush_dirty_pages(%x/%ld for pid %d %ld/%ld)\n",
inode->i_dev, inode->i_ino, current->pid,
offset, len);
- if (IS_SOFT && signalled())
- nfs_cancel_dirty(inode, current->pid);
+ if (IS_SOFT && signalled()) {
+ nfs_cancel_dirty(inode, pid);
+ cancel = 1;
+ }
for (;;) {
- if (IS_SOFT && signalled())
- return -ERESTARTSYS;
+ if (IS_SOFT && signalled()) {
+ if (!cancel)
+ nfs_cancel_dirty(inode, pid);
+ result = -ERESTARTSYS;
+ break;
+ }
- /* Flush all pending writes for this pid and file region */
- last = nfs_flush_pages(inode, current->pid, offset, len, 0);
+ /* Flush all pending writes for the pid and file region */
+ last = nfs_flush_pages(inode, pid, offset, len, 0);
if (last == NULL)
break;
wait_on_write_request(last);
}
- return 0;
+ return result;
}
/*
* Flush out any pending write requests and flag that they be discarded
* after the write is complete.
*
- * This function is called from nfs_revalidate_inode just before it calls
+ * This function is called from nfs_refresh_inode just before it calls
* invalidate_inode_pages. After nfs_flush_pages returns, we can be sure
* that all dirty pages are locked, so that invalidate_inode_pages does
* not throw away any dirty pages.
@@ -705,15 +804,14 @@ nfs_check_error(struct inode *inode)
dprintk("nfs: checking for write error inode %04x/%ld\n",
inode->i_dev, inode->i_ino);
- if (!(req = find_failed_request(inode, current->pid)))
- return 0;
-
- dprintk("nfs: write error %d inode %04x/%ld\n",
+ req = find_failed_request(inode, current->pid);
+ if (req) {
+ dprintk("nfs: write error %d inode %04x/%ld\n",
req->wb_task.tk_status, inode->i_dev, inode->i_ino);
- status = req->wb_task.tk_status;
- remove_write_request(&nfs_failed_requests, req);
- kfree(req);
+ status = req->wb_task.tk_status;
+ remove_failed_request(req);
+ }
return status;
}
@@ -789,36 +887,45 @@ nfs_wback_result(struct rpc_task *task)
page = req->wb_page;
status = task->tk_status;
- /* Remove request from writeback list and wake up tasks
- * sleeping on it. */
- remove_write_request(&NFS_WRITEBACK(inode), req);
-
if (status < 0) {
/*
* An error occurred. Report the error back to the
- * application by adding the failed request to the
- * inode's error list.
+ * application by adding the request to the failed
+ * requests list.
*/
- if (find_failed_request(inode, req->wb_pid)) {
+ if (find_failed_request(inode, req->wb_pid))
status = 0;
- } else {
- dprintk("NFS: %4d saving write failure code\n",
- task->tk_pid);
- append_write_request(&nfs_failed_requests, req);
- }
clear_bit(PG_uptodate, &page->flags);
} else if (!WB_CANCELLED(req)) {
+ struct nfs_fattr *fattr = req->wb_fattr;
/* Update attributes as result of writeback.
* Beware: when UDP replies arrive out of order, we
* may end up overwriting a previous, bigger file size.
*/
- if (req->wb_fattr->size < inode->i_size)
- req->wb_fattr->size = inode->i_size;
- /* possible Solaris 2.5 server bug workaround */
- if (inode->i_ino == req->wb_fattr->fileid)
- nfs_refresh_inode(inode, req->wb_fattr);
+ if (fattr->mtime.seconds >= inode->i_mtime) {
+ if (fattr->size < inode->i_size)
+ fattr->size = inode->i_size;
+
+ /* possible Solaris 2.5 server bug workaround */
+ if (inode->i_ino == fattr->fileid) {
+ /*
+ * We expect these values to change, and
+ * don't want to invalidate the caches.
+ */
+ inode->i_size = fattr->size;
+ inode->i_mtime = fattr->mtime.seconds;
+ nfs_refresh_inode(inode, fattr);
+ }
+ else
+ printk("nfs_wback_result: inode %ld, got %u?\n",
+ inode->i_ino, fattr->fileid);
+ }
}
+ /*
+ * This call might block, so we defer removing the request
+ * from the inode's writeback list.
+ */
rpc_release_task(task);
if (WB_INVALIDATE(req))
@@ -830,8 +937,20 @@ nfs_wback_result(struct rpc_task *task)
kfree(req->wb_args);
req->wb_args = 0;
}
+
+ /*
+ * Now it's safe to remove the request from the inode's
+ * writeback list and wake up any tasks sleeping on it.
+ * If the request failed, add it to the failed list.
+ */
+ remove_write_request(&NFS_WRITEBACK(inode), req);
+
if (status >= 0)
kfree(req);
+ else {
+ dprintk("NFS: %4d saving write failure code\n", task->tk_pid);
+ append_failed_request(req);
+ }
free_page(page_address(page));
nr_write_requests--;
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 1a0267abe..4ea31ed33 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -26,6 +26,9 @@
#include <linux/nfsd/syscall.h>
#include <linux/lockd/bind.h>
+#define NFSDDBG_FACILITY NFSDDBG_EXPORT
+#define NFSD_PARANOIA 1
+
typedef struct svc_client svc_client;
typedef struct svc_export svc_export;
@@ -37,9 +40,7 @@ static svc_client * exp_getclientbyname(char *name);
static void exp_freeclient(svc_client *clp);
static void exp_unhashclient(svc_client *clp);
static int exp_verify_string(char *cp, int max);
-struct inode * exp_lnamei(char *pathname, int *errp);
-#define NFSDDBG_FACILITY NFSDDBG_EXPORT
#define CLIENT_HASHBITS 6
#define CLIENT_HASHMAX (1 << CLIENT_HASHBITS)
#define CLIENT_HASHMASK (CLIENT_HASHMAX - 1)
@@ -65,7 +66,7 @@ static struct wait_queue * hash_wait = NULL;
#define WRITELOCK 1
/*
- * Find the export entry matching xdev/xino.
+ * Find a client's export for a device.
*/
static inline svc_export *
exp_find(svc_client *clp, dev_t dev)
@@ -78,6 +79,9 @@ exp_find(svc_client *clp, dev_t dev)
return exp;
}
+/*
+ * Find the client's export entry matching xdev/xino.
+ */
svc_export *
exp_get(svc_client *clp, dev_t dev, ino_t ino)
{
@@ -90,8 +94,22 @@ exp_get(svc_client *clp, dev_t dev, ino_t ino)
}
/*
- * Look up the root inode of the parent fs.
- * We have to go through iget in order to allow for wait_on_inode.
+ * Check whether there are any exports for a device.
+ */
+static int
+exp_device_in_use(dev_t dev)
+{
+ struct svc_client *clp;
+
+ for (clp = clients; clp; clp = clp->cl_next) {
+ if (exp_find(clp, dev))
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Look up the device of the parent fs.
*/
static inline int
nfsd_parentdev(dev_t *devp)
@@ -153,13 +171,12 @@ exp_export(struct nfsctl_export *nxp)
/* Try to lock the export table for update */
if ((err = exp_writelock()) < 0)
- return err;
+ goto out;
/* Look up client info */
- if (!(clp = exp_getclientbyname(nxp->ex_client))) {
- err = -EINVAL;
- goto finish;
- }
+ err = -EINVAL;
+ if (!(clp = exp_getclientbyname(nxp->ex_client)))
+ goto out_unlock;
/*
* If there's already an export for this file, assume this
@@ -167,54 +184,54 @@ exp_export(struct nfsctl_export *nxp)
*/
if ((exp = exp_find(clp, dev)) != NULL) {
/* Ensure there's only one export per FS. */
- if (exp->ex_ino != ino) {
- err = -EPERM;
- } else {
+ err = -EPERM;
+ if (exp->ex_ino == ino) {
exp->ex_flags = nxp->ex_flags;
exp->ex_anon_uid = nxp->ex_anon_uid;
exp->ex_anon_gid = nxp->ex_anon_gid;
err = 0;
}
- goto finish;
+ goto out_unlock;
}
/* Look up the dentry */
+ err = -EINVAL;
dentry = lookup_dentry(nxp->ex_path, NULL, 0);
- if (IS_ERR(dentry)) {
- err = -EINVAL;
- goto finish;
- }
+ if (IS_ERR(dentry))
+ goto out_unlock;
+
+ err = -ENOENT;
inode = dentry->d_inode;
- if(!inode) {
- err = -ENOENT;
+ if(!inode)
goto finish;
- }
+ err = -EINVAL;
if(inode->i_dev != nxp->ex_dev || inode->i_ino != nxp->ex_ino) {
/* I'm just being paranoid... */
- err = -EINVAL;
goto finish;
}
/* We currently export only dirs. */
- if (!S_ISDIR(inode->i_mode)) {
- err = -ENOTDIR;
+ err = -ENOTDIR;
+ if (!S_ISDIR(inode->i_mode))
goto finish;
- }
/* If this is a sub-export, must be root of FS */
+ err = -EINVAL;
if ((parent = exp_parent(clp, dev)) != NULL) {
struct super_block *sb = inode->i_sb;
- if (sb && (inode != sb->s_root->d_inode)) {
- err = -EINVAL;
+ if (inode != sb->s_root->d_inode) {
+#ifdef NFSD_PARANOIA
+printk("exp_export: sub-export %s not root of device %s\n",
+nxp->ex_path, kdevname(sb->s_dev));
+#endif
goto finish;
}
}
- if (!(exp = kmalloc(sizeof(*exp), GFP_USER))) {
- err = -ENOMEM;
+ err = -ENOMEM;
+ if (!(exp = kmalloc(sizeof(*exp), GFP_USER)))
goto finish;
- }
dprintk("nfsd: created export entry %p for client %p\n", exp, clp);
strcpy(exp->ex_path, nxp->ex_path);
@@ -246,14 +263,16 @@ exp_export(struct nfsctl_export *nxp)
err = 0;
-finish:
- /* Release dentry */
- if (err < 0 && !IS_ERR(dentry))
- dput(dentry);
-
/* Unlock hashtable */
+out_unlock:
exp_unlock();
+out:
return err;
+
+ /* Release the dentry */
+finish:
+ dput(dentry);
+ goto out_unlock;
}
/*
@@ -277,12 +296,21 @@ exp_do_unexport(svc_export *unexp)
exp->ex_parent = unexp->ex_parent;
}
+ /*
+ * Check whether this is the last export for this device,
+ * and if so flush any cached dentries.
+ */
+ if (!exp_device_in_use(unexp->ex_dev)) {
+printk("exp_do_unexport: %s last use, flushing cache\n",
+kdevname(unexp->ex_dev));
+ nfsd_fh_flush(unexp->ex_dev);
+ }
+
dentry = unexp->ex_dentry;
inode = dentry->d_inode;
if (unexp->ex_dev != inode->i_dev || unexp->ex_ino != inode->i_ino)
printk(KERN_WARNING "nfsd: bad dentry in unexport!\n");
- else
- dput(dentry);
+ dput(dentry);
kfree(unexp);
}
@@ -325,15 +353,19 @@ exp_unexport(struct nfsctl_export *nxp)
return -EINVAL;
if ((err = exp_writelock()) < 0)
- return err;
+ goto out;
err = -EINVAL;
- if ((clp = exp_getclientbyname(nxp->ex_client)) != NULL) {
+ clp = exp_getclientbyname(nxp->ex_client);
+ if (clp) {
+printk("exp_unexport: found client %s\n", nxp->ex_client);
expp = clp->cl_export + EXPORT_HASH(nxp->ex_dev);
while ((exp = *expp) != NULL) {
if (exp->ex_dev == nxp->ex_dev) {
- if (exp->ex_ino != nxp->ex_ino)
+ if (exp->ex_ino != nxp->ex_ino) {
+printk("exp_unexport: ino mismatch, %ld not %ld\n", exp->ex_ino, nxp->ex_ino);
break;
+ }
*expp = exp->ex_next;
exp_do_unexport(exp);
err = 0;
@@ -344,6 +376,7 @@ exp_unexport(struct nfsctl_export *nxp)
}
exp_unlock();
+out:
return err;
}
@@ -404,7 +437,7 @@ exp_writelock(void)
while (hash_count || hash_lock)
interruptible_sleep_on(&hash_wait);
want_lock--;
- if (current->signal & ~current->blocked)
+ if (signal_pending(current))
return -EINTR;
hash_lock = 1;
return 0;
@@ -481,27 +514,27 @@ exp_addclient(struct nfsctl_client *ncp)
int i, err, change = 0, ilen;
/* First, consistency check. */
+ err = -EINVAL;
if (!(ilen = exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX)))
- return -EINVAL;
+ goto out;
if (ncp->cl_naddr > NFSCLNT_ADDRMAX)
- return -EINVAL;
+ goto out;
/* Lock the hashtable */
if ((err = exp_writelock()) < 0)
- return err;
+ goto out;
/* First check if this is a change request for a client. */
for (clp = clients; clp; clp = clp->cl_next)
if (!strcmp(clp->cl_ident, ncp->cl_ident))
break;
+ err = -ENOMEM;
if (clp) {
change = 1;
} else {
- if (!(clp = kmalloc(sizeof(*clp), GFP_KERNEL))) {
- exp_unlock();
- return -ENOMEM;
- }
+ if (!(clp = kmalloc(sizeof(*clp), GFP_KERNEL)))
+ goto out_unlock;
memset(clp, 0, sizeof(*clp));
dprintk("created client %s (%p)\n", ncp->cl_ident, clp);
@@ -512,13 +545,13 @@ exp_addclient(struct nfsctl_client *ncp)
/* Allocate hash buckets */
for (i = 0; i < ncp->cl_naddr; i++) {
- if (!(ch[i] = kmalloc(GFP_KERNEL, sizeof(ch[0])))) {
+ ch[i] = kmalloc(sizeof(struct svc_clnthash), GFP_KERNEL);
+ if (!ch[i]) {
while (i--)
kfree(ch[i]);
if (!change)
kfree(clp);
- exp_unlock();
- return -ENOMEM;
+ goto out_unlock;
}
}
@@ -548,9 +581,12 @@ exp_addclient(struct nfsctl_client *ncp)
clp->cl_next = clients;
clients = clp;
}
+ err = 0;
+out_unlock:
exp_unlock();
- return 0;
+out:
+ return err;
}
/*
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 1db374bc6..d681a92b5 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -17,11 +17,11 @@
#include <linux/fcntl.h>
#include <linux/net.h>
#include <linux/in.h>
-#include <linux/nfs.h>
#include <linux/version.h>
#include <linux/unistd.h>
#include <linux/malloc.h>
+#include <linux/nfs.h>
#include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h>
#include <linux/nfsd/cache.h>
@@ -38,6 +38,7 @@
#include <linux/smp.h>
#include <linux/smp_lock.h>
+extern void nfsd_fh_init(void);
extern long sys_call_table[];
static int nfsctl_svc(struct nfsctl_svc *data);
@@ -64,6 +65,7 @@ nfsd_init(void)
nfsd_export_init(); /* Exports table */
nfsd_lockd_init(); /* lockd->nfsd callbacks */
nfsd_racache_init(); /* Readahead param cache */
+ nfsd_fh_init(); /* FH table */
initialized = 1;
}
@@ -141,31 +143,33 @@ asmlinkage handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp)
union nfsctl_res * res = NULL;
int err;
+ MOD_INC_USE_COUNT;
lock_kernel ();
if (!initialized)
nfsd_init();
+ err = -EPERM;
if (!suser()) {
- err = -EPERM;
goto done;
}
+ err = -EFAULT;
if (!access_ok(VERIFY_READ, argp, sizeof(*argp))
|| (resp && !access_ok(VERIFY_WRITE, resp, sizeof(*resp)))) {
- err = -EFAULT;
goto done;
}
+
+ err = -ENOMEM; /* ??? */
if (!(arg = kmalloc(sizeof(*arg), GFP_USER)) ||
(resp && !(res = kmalloc(sizeof(*res), GFP_USER)))) {
- err = -ENOMEM; /* ??? */
goto done;
}
+
+ err = -EINVAL;
copy_from_user(arg, argp, sizeof(*argp));
if (arg->ca_version != NFSCTL_VERSION) {
printk(KERN_WARNING "nfsd: incompatible version in syscall.\n");
- err = -EINVAL;
goto done;
}
- MOD_INC_USE_COUNT;
switch(cmd) {
case NFSCTL_SVC:
err = nfsctl_svc(&arg->ca_svc);
@@ -193,7 +197,6 @@ asmlinkage handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp)
default:
err = -EINVAL;
}
- MOD_DEC_USE_COUNT;
if (!err && resp)
copy_to_user(resp, res, sizeof(*resp));
@@ -205,6 +208,7 @@ done:
kfree(res);
unlock_kernel ();
+ MOD_DEC_USE_COUNT;
return err;
}
@@ -224,7 +228,6 @@ int
init_module(void)
{
printk("Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
- nfsd_init();
do_nfsservctl = handle_sys_nfsservctl;
return 0;
}
@@ -242,6 +245,7 @@ cleanup_module(void)
do_nfsservctl = NULL;
nfsd_export_shutdown();
nfsd_cache_shutdown();
+ nfsd_fh_free();
#ifdef CONFIG_PROC_FS
nfsd_stat_shutdown();
#endif
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index abb2f7fd3..ff341f012 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -7,18 +7,994 @@
*/
#include <linux/sched.h>
+#include <linux/malloc.h>
#include <linux/fs.h>
#include <linux/unistd.h>
#include <linux/string.h>
#include <linux/stat.h>
+#include <linux/dcache.h>
#include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h>
#define NFSDDBG_FACILITY NFSDDBG_FH
+#define NFSD_PARANOIA 1
+/* #define NFSD_DEBUG_VERBOSE 1 */
+
+extern unsigned long num_physpages;
+
+#define NFSD_FILE_CACHE 0
+#define NFSD_DIR_CACHE 1
+struct fh_entry {
+ struct dentry * dentry;
+ unsigned long reftime;
+ ino_t ino;
+ dev_t dev;
+};
+
+#define NFSD_MAXFH PAGE_SIZE/sizeof(struct fh_entry)
+static struct fh_entry filetable[NFSD_MAXFH];
+static struct fh_entry dirstable[NFSD_MAXFH];
+
+static int nfsd_nr_verified = 0;
+static int nfsd_nr_put = 0;
+static unsigned long nfsd_next_expire = 0;
+
+static int add_to_fhcache(struct dentry *, int);
+static int nfsd_d_validate(struct dentry *);
+struct dentry * lookup_inode(dev_t, ino_t, ino_t);
+
+static LIST_HEAD(fixup_head);
+static LIST_HEAD(path_inuse);
+static int nfsd_nr_fixups = 0;
+static int nfsd_nr_paths = 0;
+#define NFSD_MAX_PATHS 500
+#define NFSD_MAX_FIXUPAGE 60*HZ
+
+struct nfsd_fixup {
+ struct list_head lru;
+ ino_t dir;
+ ino_t ino;
+ dev_t dev;
+ struct dentry *dentry;
+ unsigned long reftime;
+};
+
+struct nfsd_path {
+ struct list_head lru;
+ unsigned long reftime;
+ int users;
+ ino_t ino;
+ dev_t dev;
+ char name[1];
+};
+
+static struct nfsd_fixup * find_cached_lookup(dev_t dev, ino_t dir, ino_t ino)
+{
+ struct list_head *tmp = fixup_head.next;
+
+ for (; tmp != &fixup_head; tmp = tmp->next) {
+ struct nfsd_fixup *fp;
+
+ fp = list_entry(tmp, struct nfsd_fixup, lru);
+ if (fp->ino != ino)
+ continue;
+ if (fp->dir != dir)
+ continue;
+ if (fp->dev != dev)
+ continue;
+ list_del(tmp);
+ list_add(tmp, &fixup_head);
+ fp->reftime = jiffies;
+ return fp;
+ }
+ return NULL;
+}
+
+/*
+ * Save the dentry pointer from a successful lookup.
+ */
+static void add_to_lookup_cache(struct dentry *dentry, struct knfs_fh *fh)
+{
+ struct nfsd_fixup *fp;
+
+ fp = find_cached_lookup(fh->fh_dev, fh->fh_dirino, fh->fh_ino);
+ if (fp) {
+ fp->dentry = dentry;
+ return;
+ }
+
+ /*
+ * Add a new entry. The small race here is unimportant:
+ * if another task adds the same lookup, both entries
+ * will be consistent.
+ */
+ fp = kmalloc(sizeof(struct nfsd_fixup), GFP_KERNEL);
+ if (fp) {
+ fp->dir = fh->fh_dirino;
+ fp->ino = fh->fh_ino;
+ fp->dev = fh->fh_dev;
+ fp->dentry = dentry;
+ fp->reftime = jiffies;
+ list_add(&fp->lru, &fixup_head);
+ nfsd_nr_fixups++;
+ }
+}
+
+static void free_fixup_entry(struct nfsd_fixup *fp)
+{
+ list_del(&fp->lru);
+ kfree(fp);
+ nfsd_nr_fixups--;
+}
+
+/*
+ * Copy a dentry's path into the specified buffer.
+ */
+static int copy_path(char *buffer, struct dentry *dentry, int namelen)
+{
+ char *p, *b = buffer;
+ int result = 0, totlen = 0, len;
+
+ while (1) {
+ struct dentry *parent;
+ dentry = dentry->d_covers;
+ parent = dentry->d_parent;
+ len = dentry->d_name.len;
+ p = (char *) dentry->d_name.name + len;
+ totlen += len;
+ if (totlen > namelen)
+ goto out;
+ while (len--)
+ *b++ = *(--p);
+ if (dentry == parent)
+ break;
+ dentry = parent;
+ totlen++;
+ if (totlen > namelen)
+ goto out;
+ *b++ = '/';
+ }
+ *b = 0;
+
+ /*
+ * Now reverse in place ...
+ */
+ p = buffer;
+ while (p < b) {
+ char c = *(--b);
+ *b = *p;
+ *p++ = c;
+ }
+ result = 1;
+out:
+ return result;
+}
+
+/*
+ * Add a dentry's path to the path cache.
+ */
+static int add_to_path_cache(struct dentry *dentry)
+{
+ struct inode *inode = dentry->d_inode;
+ struct dentry *this;
+ struct nfsd_path *new;
+ int len, result = 0;
+
+#ifdef NFSD_DEBUG_VERBOSE
+printk("add_to_path_cache: cacheing %s/%s\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
+ /*
+ * Get the length of the full pathname.
+ */
+restart:
+ len = 0;
+ this = dentry;
+ while (1) {
+ struct dentry *parent;
+ this = this->d_covers;
+ parent = this->d_parent;
+ len += this->d_name.len;
+ if (this == parent)
+ break;
+ this = parent;
+ len++;
+ }
+ /*
+ * Allocate a structure to hold the path.
+ */
+ new = kmalloc(sizeof(struct nfsd_path) + len, GFP_KERNEL);
+ if (new) {
+ new->users = 0;
+ new->reftime = jiffies;
+ new->ino = inode->i_ino;
+ new->dev = inode->i_dev;
+ result = copy_path(new->name, dentry, len);
+ if (!result)
+ goto retry;
+ list_add(&new->lru, &path_inuse);
+ nfsd_nr_paths++;
+#ifdef NFSD_DEBUG_VERBOSE
+printk("add_to_path_cache: added %s, paths=%d\n", new->name, nfsd_nr_paths);
+#endif
+ }
+ return result;
+
+ /*
+ * If the dentry's path length changed, just try again ...
+ */
+retry:
+ kfree(new);
+ printk("add_to_path_cache: path length changed, retrying\n");
+ goto restart;
+}
+
+/*
+ * Search for a path entry for the specified (dev, inode).
+ */
+struct nfsd_path *get_path_entry(dev_t dev, ino_t ino)
+{
+ struct nfsd_path *pe;
+ struct list_head *tmp;
+
+ for (tmp = path_inuse.next; tmp != &path_inuse; tmp = tmp->next) {
+ pe = list_entry(tmp, struct nfsd_path, lru);
+ if (pe->ino != ino)
+ continue;
+ if (pe->dev != dev)
+ continue;
+ list_del(tmp);
+ list_add(tmp, &path_inuse);
+ pe->users++;
+ pe->reftime = jiffies;
+#ifdef NFSD_PARANOIA
+printk("get_path_entry: found %s for %s/%ld\n", pe->name, kdevname(dev), ino);
+#endif
+ return pe;
+ }
+ return NULL;
+}
+
+static void put_path(struct nfsd_path *pe)
+{
+ pe->users--;
+}
+
+static void free_path_entry(struct nfsd_path *pe)
+{
+ if (pe->users)
+ printk("free_path_entry: %s in use, users=%d\n",
+ pe->name, pe->users);
+ list_del(&pe->lru);
+ kfree(pe);
+ nfsd_nr_paths--;
+}
+
+struct nfsd_getdents_callback {
+ struct nfsd_dirent *dirent;
+ ino_t dirino; /* parent inode number */
+ int found; /* dirent inode matched? */
+ int sequence; /* sequence counter */
+};
+
+struct nfsd_dirent {
+ ino_t ino; /* preset to desired entry */
+ int len;
+ char name[256];
+};
+
+/*
+ * A rather strange filldir function to capture the inode number
+ * for the second entry (the parent inode) and the name matching
+ * the specified inode number.
+ */
+static int filldir_one(void * __buf, const char * name, int len,
+ off_t pos, ino_t ino)
+{
+ struct nfsd_getdents_callback *buf = __buf;
+ struct nfsd_dirent *dirent = buf->dirent;
+ int result = 0;
+
+ buf->sequence++;
+#ifdef NFSD_DEBUG_VERBOSE
+printk("filldir_one: seq=%d, ino=%ld, name=%s\n", buf->sequence, ino, name);
+#endif
+ if (buf->sequence == 2) {
+ buf->dirino = ino;
+ goto out;
+ }
+ if (dirent->ino == ino) {
+ dirent->len = len;
+ memcpy(dirent->name, name, len);
+ dirent->name[len] = 0;
+ buf->found = 1;
+ result = -1;
+ }
+out:
+ return result;
+}
+
+/*
+ * Read a directory and return the parent inode number and the name
+ * of the specified entry. The dirent must be initialized with the
+ * inode number of the desired entry.
+ */
+static int get_parent_ino(struct dentry *dentry, struct nfsd_dirent *dirent)
+{
+ struct inode *dir = dentry->d_inode;
+ int error;
+ struct file file;
+ struct nfsd_getdents_callback buffer;
+
+ error = -ENOTDIR;
+ if (!dir || !S_ISDIR(dir->i_mode))
+ goto out;
+ error = -EINVAL;
+ if (!dir->i_op || !dir->i_op->default_file_ops)
+ goto out;
+ /*
+ * Open the directory ...
+ */
+ error = init_private_file(&file, dentry, FMODE_READ);
+ if (error)
+ goto out;
+ error = -EINVAL;
+ if (!file.f_op->readdir)
+ goto out_close;
+
+ buffer.dirent = dirent;
+ buffer.dirino = 0;
+ buffer.found = 0;
+ buffer.sequence = 0;
+ while (1) {
+ int old_seq = buffer.sequence;
+ down(&dir->i_sem);
+ error = file.f_op->readdir(&file, &buffer, filldir_one);
+ up(&dir->i_sem);
+ if (error < 0)
+ break;
+
+ error = 0;
+ if (buffer.found)
+ break;
+ error = -ENOENT;
+ if (old_seq == buffer.sequence)
+ break;
+ }
+ dirent->ino = buffer.dirino;
+
+out_close:
+ if (file.f_op->release)
+ file.f_op->release(dir, &file);
+out:
+ return error;
+}
+
+/*
+ * Look up a dentry given inode and parent inode numbers.
+ *
+ * This relies on the ability of a unix-like filesystem to return
+ * the parent inode of a directory as the ".." (second) entry.
+ *
+ * This could be further optimized if we had an efficient way of
+ * searching for a dentry given the inode: as we walk up the tree,
+ * it's likely that a dentry exists before we reach the root.
+ */
+struct dentry * lookup_inode(dev_t dev, ino_t dirino, ino_t ino)
+{
+ struct super_block *sb;
+ struct dentry *root, *dentry, *result;
+ struct inode *dir;
+ char *name;
+ unsigned long page;
+ ino_t root_ino;
+ int error;
+ struct nfsd_dirent dirent;
+
+ result = ERR_PTR(-ENOMEM);
+ page = __get_free_page(GFP_KERNEL);
+ if (!page)
+ goto out;
+
+ /*
+ * Get the root dentry for the device.
+ */
+ result = ERR_PTR(-ENOENT);
+ sb = get_super(dev);
+ if (!sb)
+ goto out_page;
+ root = dget(sb->s_root);
+ root_ino = root->d_inode->i_ino; /* usually 2 */
+
+ name = (char *) page + PAGE_SIZE;
+ *(--name) = 0;
+
+ /*
+ * Walk up the tree to construct the name string.
+ * When we reach the root inode, look up the name
+ * relative to the root dentry.
+ */
+ while (1) {
+ if (ino == root_ino) {
+ if (*name == '/')
+ name++;
+ /*
+ * Note: this dput()s the root dentry.
+ */
+ result = lookup_dentry(name, root, 0);
+ break;
+ }
+
+ result = ERR_PTR(-ENOENT);
+ dir = iget(sb, dirino);
+ if (!dir)
+ goto out_root;
+ dentry = d_alloc_root(dir, NULL);
+ if (!dentry)
+ goto out_iput;
+
+ /*
+ * Get the name for this inode and the next parent inode.
+ */
+ dirent.ino = ino;
+ error = get_parent_ino(dentry, &dirent);
+ result = ERR_PTR(error);
+ dput(dentry);
+ if (error)
+ goto out_root;
+ /*
+ * Prepend the name to the buffer.
+ */
+ result = ERR_PTR(-ENAMETOOLONG);
+ name -= (dirent.len + 1);
+ if ((unsigned long) name <= page)
+ goto out_root;
+ memcpy(name + 1, dirent.name, dirent.len);
+ *name = '/';
+
+ /*
+ * Make sure we can't get caught in a loop ...
+ */
+ if (dirino == dirent.ino && dirino != root_ino) {
+ printk("lookup_inode: looping?? (ino=%ld, path=%s)\n",
+ dirino, name);
+ goto out_root;
+ }
+ ino = dirino;
+ dirino = dirent.ino;
+ }
+
+out_page:
+ free_page(page);
+out:
+ return result;
+
+ /*
+ * Error exits ...
+ */
+out_iput:
+ result = ERR_PTR(-ENOMEM);
+ iput(dir);
+out_root:
+ dput(root);
+ goto out;
+}
+
+/*
+ * Find an entry in the cache matching the given dentry pointer.
+ */
+static struct fh_entry *find_fhe(struct dentry *dentry, int cache,
+ struct fh_entry **empty)
+{
+ struct fh_entry *fhe;
+ int i, found = (empty == NULL) ? 1 : 0;
+
+ fhe = (cache == NFSD_FILE_CACHE) ? &filetable[0] : &dirstable[0];
+ for (i = 0; i < NFSD_MAXFH; i++, fhe++) {
+ if (fhe->dentry == dentry) {
+ fhe->reftime = jiffies;
+ return fhe;
+ }
+ if (!found && !fhe->dentry) {
+ found = 1;
+ *empty = fhe;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Expire a cache entry.
+ */
+static void expire_fhe(struct fh_entry *empty, int cache)
+{
+ struct dentry *dentry = empty->dentry;
+
+#ifdef NFSD_DEBUG_VERBOSE
+printk("expire_fhe: expiring %s/%s, d_count=%d, ino=%ld\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count,empty->ino);
+#endif
+ empty->dentry = NULL; /* no dentry */
+ /*
+ * Add the parent to the dir cache before releasing the dentry,
+ * and check whether to save a copy of the dentry's path.
+ */
+ if (dentry != dentry->d_parent) {
+ struct dentry *parent = dget(dentry->d_parent);
+ if (add_to_fhcache(parent, NFSD_DIR_CACHE))
+ nfsd_nr_verified++;
+ else
+ dput(parent);
+ /*
+ * If we're expiring a directory, copy its path.
+ */
+ if (cache == NFSD_DIR_CACHE) {
+ add_to_path_cache(dentry);
+ }
+ }
+ dput(dentry);
+ nfsd_nr_put++;
+}
+
+/*
+ * Look for an empty slot, or select one to expire.
+ */
+static void expire_slot(int cache)
+{
+ struct fh_entry *fhe, *empty = NULL;
+ unsigned long oldest = -1;
+ int i;
+
+ fhe = (cache == NFSD_FILE_CACHE) ? &filetable[0] : &dirstable[0];
+ for (i = 0; i < NFSD_MAXFH; i++, fhe++) {
+ if (!fhe->dentry)
+ goto out;
+ if (fhe->reftime < oldest) {
+ oldest = fhe->reftime;
+ empty = fhe;
+ }
+ }
+ if (empty)
+ expire_fhe(empty, cache);
+
+out:
+ return;
+}
+
+/*
+ * Expire any cache entries older than a certain age.
+ */
+static void expire_old(int cache, int age)
+{
+ struct list_head *tmp;
+ struct fh_entry *fhe;
+ int i;
+
+#ifdef NFSD_DEBUG_VERBOSE
+printk("expire_old: expiring %s older than %d\n",
+(cache == NFSD_FILE_CACHE) ? "file" : "dir", age);
+#endif
+ fhe = (cache == NFSD_FILE_CACHE) ? &filetable[0] : &dirstable[0];
+ for (i = 0; i < NFSD_MAXFH; i++, fhe++) {
+ if (!fhe->dentry)
+ continue;
+ if ((jiffies - fhe->reftime) > age)
+ expire_fhe(fhe, cache);
+ }
+
+ /*
+ * Remove old entries from the patch-up cache.
+ */
+ while ((tmp = fixup_head.prev) != &fixup_head) {
+ struct nfsd_fixup *fp;
+ fp = list_entry(tmp, struct nfsd_fixup, lru);
+ if ((jiffies - fp->reftime) < NFSD_MAX_FIXUPAGE)
+ break;
+ free_fixup_entry(fp);
+ }
+
+ /*
+ * Trim the path cache ...
+ */
+ while (nfsd_nr_paths > NFSD_MAX_PATHS) {
+ struct nfsd_path *pe;
+ pe = list_entry(path_inuse.prev, struct nfsd_path, lru);
+ if (pe->users)
+ break;
+ free_path_entry(pe);
+ }
+}
+
+/*
+ * Add a dentry to the file or dir cache.
+ *
+ * Note: As NFS filehandles must have an inode, we don't accept
+ * negative dentries.
+ */
+static int add_to_fhcache(struct dentry *dentry, int cache)
+{
+ struct fh_entry *fhe, *empty = NULL;
+ struct inode *inode = dentry->d_inode;
+
+ if (!inode) {
+#ifdef NFSD_PARANOIA
+printk("add_to_fhcache: %s/%s rejected, no inode!\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
+ return 0;
+ }
+
+repeat:
+ fhe = find_fhe(dentry, cache, &empty);
+ if (fhe) {
+ return 0;
+ }
+
+ /*
+ * Not found ... make a new entry.
+ */
+ if (empty) {
+ empty->dentry = dentry;
+ empty->reftime = jiffies;
+ empty->ino = inode->i_ino;
+ empty->dev = inode->i_dev;
+ return 1;
+ }
+
+ expire_slot(cache);
+ goto repeat;
+}
+
+/*
+ * Find an entry in the dir cache for the specified inode number.
+ */
+static struct fh_entry *find_fhe_by_ino(dev_t dev, ino_t ino)
+{
+ struct fh_entry * fhe = &dirstable[0];
+ int i;
+
+ for (i = 0; i < NFSD_MAXFH; i++, fhe++) {
+ if (fhe->ino == ino && fhe->dev == dev) {
+ fhe->reftime = jiffies;
+ return fhe;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Find the (directory) dentry with the specified (dev, inode) number.
+ * Note: this leaves the dentry in the cache.
+ */
+static struct dentry *find_dentry_by_ino(dev_t dev, ino_t ino)
+{
+ struct fh_entry *fhe;
+ struct nfsd_path *pe;
+ struct dentry * dentry;
+
+#ifdef NFSD_DEBUG_VERBOSE
+printk("find_dentry_by_ino: looking for inode %ld\n", ino);
+#endif
+ /*
+ * Special case: inode number 2 is the root inode,
+ * so we can use the root dentry for the device.
+ */
+ if (ino == 2) {
+ struct super_block *sb = get_super(dev);
+ if (sb) {
+#ifdef NFSD_PARANOIA
+printk("find_dentry_by_ino: getting root dentry for %s\n", kdevname(dev));
+#endif
+ if (sb->s_root) {
+ dentry = dget(sb->s_root);
+ goto out;
+ } else {
+#ifdef NFSD_PARANOIA
+ printk("find_dentry_by_ino: %s has no root??\n",
+ kdevname(dev));
+#endif
+ }
+ }
+ }
+
+ /*
+ * Search the dentry cache ...
+ */
+ fhe = find_fhe_by_ino(dev, ino);
+ if (fhe) {
+ dentry = dget(fhe->dentry);
+ goto out;
+ }
+
+ /*
+ * Search the path cache ...
+ */
+ dentry = NULL;
+ pe = get_path_entry(dev, ino);
+ if (pe) {
+ struct dentry *res;
+ res = lookup_dentry(pe->name, NULL, 0);
+ if (!IS_ERR(res)) {
+ struct inode *inode = res->d_inode;
+ if (inode && inode->i_ino == ino &&
+ inode->i_dev == dev) {
+ dentry = res;
+#ifdef NFSD_PARANOIA
+printk("find_dentry_by_ino: found %s/%s, ino=%ld\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, ino);
+#endif
+ if (add_to_fhcache(dentry, NFSD_DIR_CACHE)) {
+ dget(dentry);
+ nfsd_nr_verified++;
+ }
+ } else {
+ dput(res);
+ }
+ } else {
+#ifdef NFSD_PARANOIA
+printk("find_dentry_by_ino: %s lookup failed\n", pe->name);
+#endif
+ }
+ put_path(pe);
+ }
+out:
+ return dentry;
+}
+
+/*
+ * Look for an entry in the file cache matching the dentry pointer,
+ * and verify that the (dev, inode) numbers are correct. If found,
+ * the entry is removed from the cache.
+ */
+static struct dentry *find_dentry_in_fhcache(struct knfs_fh *fh)
+{
+ struct fh_entry * fhe;
+
+ fhe = find_fhe(fh->fh_dcookie, NFSD_FILE_CACHE, NULL);
+ if (fhe) {
+ struct dentry *parent, *dentry = fhe->dentry;
+ struct inode *inode = dentry->d_inode;
+ if (!inode) {
+#ifdef NFSD_PARANOIA
+printk("find_dentry_in_fhcache: %s/%s has no inode!\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
+ goto out;
+ }
+ if (inode->i_ino != fh->fh_ino || inode->i_dev != fh->fh_dev)
+ goto out;
+
+ fhe->dentry = NULL;
+ fhe->ino = 0;
+ fhe->dev = 0;
+ nfsd_nr_put++;
+ /*
+ * Make sure the parent is in the dir cache ...
+ */
+ parent = dget(dentry->d_parent);
+ if (add_to_fhcache(parent, NFSD_DIR_CACHE))
+ nfsd_nr_verified++;
+ else
+ dput(parent);
+ return dentry;
+ }
+out:
+ return NULL;
+}
+
+/*
+ * Look for an entry in the parent directory with the specified
+ * inode number.
+ */
+static struct dentry *lookup_by_inode(struct dentry *parent, ino_t ino)
+{
+ struct dentry *dentry;
+ int error;
+ struct nfsd_dirent dirent;
+
+ /*
+ * Search the directory for the inode number.
+ */
+ dirent.ino = ino;
+ error = get_parent_ino(parent, &dirent);
+ if (error) {
+#ifdef NFSD_PARANOIA
+printk("lookup_by_inode: ino %ld not found in %s\n", ino, parent->d_name.name);
+#endif
+ goto no_entry;
+ }
+#ifdef NFSD_PARANOIA
+printk("lookup_by_inode: found %s\n", dirent.name);
+#endif
+
+ dentry = lookup_dentry(dirent.name, dget(parent), 0);
+ if (!IS_ERR(dentry)) {
+ if (dentry->d_inode && dentry->d_inode->i_ino == ino)
+ goto out;
+#ifdef NFSD_PARANOIA
+printk("lookup_by_inode: %s/%s inode mismatch??\n",
+parent->d_name.name, dentry->d_name.name);
+#endif
+ dput(dentry);
+ } else {
+#ifdef NFSD_PARANOIA
+printk("lookup_by_inode: %s lookup failed, error=%ld\n",
+dirent.name, PTR_ERR(dentry));
+#endif
+ }
+
+no_entry:
+ dentry = NULL;
+out:
+ return dentry;
+
+}
+
+/*
+ * Search the fix-up list for a dentry from a prior lookup.
+ */
+static struct dentry *nfsd_cached_lookup(struct knfs_fh *fh)
+{
+ struct nfsd_fixup *fp;
+
+ fp = find_cached_lookup(fh->fh_dev, fh->fh_dirino, fh->fh_ino);
+ if (fp)
+ return fp->dentry;
+ return NULL;
+}
+
+/*
+ * The is the basic lookup mechanism for turning an NFS filehandle
+ * into a dentry. There are several levels to the search:
+ * (1) Look for the dentry pointer the short-term fhcache,
+ * and verify that it has the correct inode number.
+ *
+ * (2) Try to validate the dentry pointer in the filehandle,
+ * and verify that it has the correct inode number. If this
+ * fails, check for a cached lookup in the fix-up list and
+ * repeat step (2) using the new dentry pointer.
+ *
+ * (3) Look up the dentry by using the inode and parent inode numbers
+ * to build the name string. This should succeed for any unix-like
+ * filesystem.
+ *
+ * (4) Search for the parent dentry in the dir cache, and then
+ * look for the name matching the inode number.
+ *
+ * (5) The most general case ... search the whole volume for the inode.
+ *
+ * If successful, we return a dentry with the use count incremented.
+ *
+ * Note: steps (4) and (5) above are probably unnecessary now that (3)
+ * is working. Remove the code once this is verified ...
+ */
+static struct dentry *
+find_fh_dentry(struct knfs_fh *fh)
+{
+ struct dentry *dentry, *parent;
+ int looked_up = 0, retry = 0;
+
+ /*
+ * Stage 1: Look for the dentry in the short-term fhcache.
+ */
+ dentry = find_dentry_in_fhcache(fh);
+ if (dentry) {
+ nfsdstats.fh_cached++;
+ goto out;
+ }
+
+ /*
+ * Stage 2: Attempt to validate the dentry in the filehandle.
+ */
+ dentry = fh->fh_dcookie;
+recheck:
+ if (nfsd_d_validate(dentry)) {
+ struct inode * dir = dentry->d_parent->d_inode;
+
+ if (dir->i_ino == fh->fh_dirino && dir->i_dev == fh->fh_dev) {
+ struct inode * inode = dentry->d_inode;
+ /*
+ * NFS filehandles must always have an inode,
+ * so we won't accept a negative dentry.
+ */
+ if (inode && inode->i_ino == fh->fh_ino) {
+ dget(dentry);
+#ifdef NFSD_DEBUG_VERBOSE
+printk("find_fh_dentry: validated %s/%s, ino=%ld\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino);
+#endif
+ if (!retry)
+ nfsdstats.fh_valid++;
+ else {
+ nfsdstats.fh_fixup++;
+#ifdef NFSD_DEBUG_VERBOSE
+printk("find_fh_dentry: retried validation successful\n");
+#endif
+ }
+ goto out;
+ }
+ }
+ }
+
+ /*
+ * Before proceeding to a lookup, check whether we cached a
+ * prior lookup. If so, try to validate that dentry ...
+ */
+ if (!retry && (dentry = nfsd_cached_lookup(fh)) != NULL) {
+ retry = 1;
+ goto recheck;
+ }
+
+ /*
+ * Stage 3: Look up the dentry based on the inode and parent inode
+ * numbers. This should work for all unix-like filesystems ...
+ */
+ looked_up = 1;
+ dentry = lookup_inode(fh->fh_dev, fh->fh_dirino, fh->fh_ino);
+ if (!IS_ERR(dentry)) {
+ struct inode * inode = dentry->d_inode;
+#ifdef NFSD_DEBUG_VERBOSE
+printk("find_fh_dentry: looked up %s/%s\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
+ if (inode && inode->i_ino == fh->fh_ino) {
+ nfsdstats.fh_lookup++;
+ goto out;
+ }
+#ifdef NFSD_PARANOIA
+printk("find_fh_dentry: %s/%s lookup mismatch!\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
+ dput(dentry);
+ }
+
+ /*
+ * Stage 4: Look for the parent dentry in the fhcache ...
+ */
+ parent = find_dentry_by_ino(fh->fh_dev, fh->fh_dirino);
+ if (parent) {
+ /*
+ * ... then search for the inode in the parent directory.
+ */
+ dentry = lookup_by_inode(parent, fh->fh_ino);
+ dput(parent);
+ if (dentry)
+ goto out;
+ }
+
+ /*
+ * Stage 5: Search the whole volume.
+ */
+#ifdef NFSD_PARANOIA
+printk("find_fh_dentry: %s, %ld/%ld not found -- need full search!\n",
+kdevname(fh->fh_dev), fh->fh_dirino, fh->fh_ino);
+#endif
+ dentry = NULL;
+ nfsdstats.fh_stale++;
+
+out:
+ if (looked_up && dentry) {
+ add_to_lookup_cache(dentry, fh);
+ }
+
+ /*
+ * Perform any needed housekeeping ...
+ * N.B. move this into one of the daemons ...
+ */
+ if (jiffies >= nfsd_next_expire) {
+ expire_old(NFSD_FILE_CACHE, 5*HZ);
+ expire_old(NFSD_DIR_CACHE , 60*HZ);
+ nfsd_next_expire = jiffies + 5*HZ;
+ }
+ return dentry;
+}
/*
* Perform sanity checks on the dentry in a client's file handle.
+ *
+ * Note that the filehandle dentry may need to be freed even after
+ * an error return.
*/
u32
fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
@@ -27,50 +1003,53 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
struct dentry *dentry;
struct inode *inode;
struct knfs_fh *fh = &fhp->fh_handle;
+ u32 error = 0;
if(fhp->fh_dverified)
- return 0;
+ goto out;
dprintk("nfsd: fh_lookup(exp %x/%ld fh %p)\n",
- fh->fh_xdev, fh->fh_xino, fh->fh_dentry);
+ fh->fh_xdev, fh->fh_xino, fh->fh_dcookie);
- /* Look up the export entry. */
+ /*
+ * Look up the export entry.
+ * N.B. We need to lock this while in use ...
+ */
+ error = nfserr_stale;
exp = exp_get(rqstp->rq_client, fh->fh_xdev, fh->fh_xino);
- if (!exp) {
- /* nfsdstats.fhstale++; */
- return nfserr_stale; /* export entry revoked */
- }
+ if (!exp) /* export entry revoked */
+ goto out;
/* Check if the request originated from a secure port. */
+ error = nfserr_perm;
if (!rqstp->rq_secure && EX_SECURE(exp)) {
printk(KERN_WARNING
"nfsd: request from insecure port (%08lx:%d)!\n",
ntohl(rqstp->rq_addr.sin_addr.s_addr),
ntohs(rqstp->rq_addr.sin_port));
- return nfserr_perm;
+ goto out;
}
/* Set user creds if we haven't done so already. */
nfsd_setuser(rqstp, exp);
- dentry = fh->fh_dentry;
-
- if(!d_validate(dentry, fh->fh_dparent, fh->fh_dhash, fh->fh_dlen) ||
- !(inode = dentry->d_inode) ||
- !inode->i_nlink) {
- /* Currently we cannot tell the difference between
- * a bogus pointer and a true unlink between fh
- * uses. But who cares about accurate error reporting
- * to buggy/malicious clients... -DaveM
- */
-
- /* nfsdstats.fhstale++; */
- return nfserr_stale;
- }
-
- dget(dentry);
- fhp->fh_dverified = 1;
+ /*
+ * Look up the dentry using the NFS fh.
+ */
+ error = nfserr_stale;
+ dentry = find_fh_dentry(fh);
+ if (!dentry)
+ goto out;
+ /*
+ * Note: it's possible that the returned dentry won't be the
+ * one in the filehandle. We can correct the FH for our use,
+ * but unfortunately the client will keep sending the broken
+ * one. Hopefully the lookup will keep patching things up..
+ */
+ fhp->fh_dentry = dentry;
fhp->fh_export = exp;
+ fhp->fh_dverified = 1;
+ nfsd_nr_verified++;
/* Type check. The correct error return for type mismatches
* does not seem to be generally agreed upon. SunOS seems to
@@ -78,33 +1057,226 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
* spec says this is incorrect (implementation notes for the
* write call).
*/
- if (type > 0 && (inode->i_mode & S_IFMT) != type)
- return (type == S_IFDIR)? nfserr_notdir : nfserr_isdir;
- if (type < 0 && (inode->i_mode & S_IFMT) == -type)
- return (type == -S_IFDIR)? nfserr_notdir : nfserr_isdir;
+ inode = dentry->d_inode;
+ if (type > 0 && (inode->i_mode & S_IFMT) != type) {
+ error = (type == S_IFDIR)? nfserr_notdir : nfserr_isdir;
+ goto out;
+ }
+ if (type < 0 && (inode->i_mode & S_IFMT) == -type) {
+ error = (type == -S_IFDIR)? nfserr_notdir : nfserr_isdir;
+ goto out;
+ }
/* Finally, check access permissions. */
- return nfsd_permission(fhp->fh_export, dentry, access);
+ error = nfsd_permission(fhp->fh_export, dentry, access);
+if (error)
+printk("fh_verify: %s/%s permission failure, acc=%x, error=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, access, error);
+
+out:
+ return error;
}
/*
- * Compose file handle for NFS reply.
+ * Compose a filehandle for an NFS reply.
+ *
+ * Note that when first composed, the dentry may not yet have
+ * an inode. In this case a call to fh_update should be made
+ * before the fh goes out on the wire ...
*/
void
fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry)
{
+ struct inode * inode = dentry->d_inode;
+
dprintk("nfsd: fh_compose(exp %x/%ld dentry %p)\n",
exp->ex_dev, exp->ex_ino, dentry);
- fh_init(fhp); /* initialize empty fh */
- fhp->fh_handle.fh_dentry = dentry;
- fhp->fh_handle.fh_dparent = dentry->d_parent;
- fhp->fh_handle.fh_dhash = dentry->d_name.hash;
- fhp->fh_handle.fh_dlen = dentry->d_name.len;
+ /*
+ * N.B. We shouldn't need to init the fh -- the call to fh_compose
+ * may not be done on error paths, but the cleanup must call fh_put.
+ * Fix this soon!
+ */
+ fh_init(fhp);
+ fhp->fh_handle.fh_dcookie = dentry;
+ if (inode) {
+ fhp->fh_handle.fh_ino = inode->i_ino;
+ }
+ fhp->fh_handle.fh_dirino = dentry->d_parent->d_inode->i_ino;
+ fhp->fh_handle.fh_dev = dentry->d_parent->d_inode->i_dev;
fhp->fh_handle.fh_xdev = exp->ex_dev;
fhp->fh_handle.fh_xino = exp->ex_ino;
+
+ fhp->fh_dentry = dentry; /* our internal copy */
fhp->fh_export = exp;
/* We stuck it there, we know it's good. */
fhp->fh_dverified = 1;
+ nfsd_nr_verified++;
+}
+
+/*
+ * Update filehandle information after changing a dentry.
+ */
+void
+fh_update(struct svc_fh *fhp)
+{
+ struct dentry *dentry;
+ struct inode *inode;
+
+ if (!fhp->fh_dverified) {
+ printk("fh_update: fh not verified!\n");
+ goto out;
+ }
+
+ dentry = fhp->fh_dentry;
+ inode = dentry->d_inode;
+ if (!inode) {
+ printk("fh_update: %s/%s still negative!\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
+ goto out;
+ }
+ fhp->fh_handle.fh_ino = inode->i_ino;
+out:
+ return;
+}
+
+/*
+ * Release a filehandle. If the filehandle carries a dentry count,
+ * we add the dentry to the short-term cache rather than release it.
+ */
+void
+fh_put(struct svc_fh *fhp)
+{
+ if (fhp->fh_dverified) {
+ struct dentry * dentry = fhp->fh_dentry;
+ fh_unlock(fhp);
+ fhp->fh_dverified = 0;
+ if (!dentry->d_count) {
+ printk("fh_put: %s/%s has d_count 0!\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
+ return;
+ }
+ if (!dentry->d_inode || !add_to_fhcache(dentry, 0)) {
+ dput(dentry);
+ nfsd_nr_put++;
+ }
+ }
+}
+
+/*
+ * Verify that the FH dentry is still a valid dentry pointer.
+ * After making some preliminary checks, we ask VFS to verify
+ * that it is indeed a dentry.
+ */
+static int nfsd_d_validate(struct dentry *dentry)
+{
+ unsigned long dent_addr = (unsigned long) dentry;
+ unsigned long min_addr = PAGE_OFFSET;
+ unsigned long max_addr = min_addr + (num_physpages << PAGE_SHIFT);
+ unsigned long align_mask = 0x0F;
+ unsigned int len;
+ int valid = 0;
+
+ if (dent_addr < min_addr)
+ goto bad_addr;
+ if (dent_addr > max_addr - sizeof(struct dentry))
+ goto bad_addr;
+ if ((dent_addr & ~align_mask) != dent_addr)
+ goto bad_align;
+ /*
+ * Looks safe enough to dereference ...
+ */
+ len = dentry->d_name.len;
+ if (len > NFS_MAXNAMLEN)
+ goto out;
+ /*
+ * Note: d_validate doesn't dereference the parent pointer ...
+ * just combines it with the name hash to find the hash chain.
+ */
+ valid = d_validate(dentry, dentry->d_parent, dentry->d_name.hash, len);
+
+out:
+ return valid;
+
+bad_addr:
+ printk("nfsd_d_validate: invalid address %lx\n", dent_addr);
+ goto out;
+bad_align:
+ printk("nfsd_d_validate: unaligned address %lx\n", dent_addr);
+ goto out;
+}
+
+/*
+ * Flush any cached dentries for the specified device
+ * or for all devices.
+ *
+ * This is called when revoking the last export for a
+ * device, so that it can be unmounted cleanly.
+ */
+void nfsd_fh_flush(dev_t dev)
+{
+ struct fh_entry *fhe;
+ int i, pass = 2;
+
+ fhe = &filetable[0];
+ while (pass--) {
+ for (i = 0; i < NFSD_MAXFH; i++, fhe++) {
+ struct dentry *dentry = fhe->dentry;
+ if (!dentry)
+ continue;
+ if (dev && dentry->d_inode->i_dev != dev)
+ continue;
+ fhe->dentry = NULL;
+ dput(dentry);
+ nfsd_nr_put++;
+ }
+ fhe = &dirstable[0];
+ }
+}
+
+/*
+ * Free the dentry and path caches.
+ */
+void nfsd_fh_free(void)
+{
+ struct list_head *tmp;
+ int i;
+
+ /* Flush dentries for all devices */
+ nfsd_fh_flush(0);
+
+ /*
+ * N.B. write a destructor for these lists ...
+ */
+ i = 0;
+ while ((tmp = fixup_head.next) != &fixup_head) {
+ struct nfsd_fixup *fp;
+ fp = list_entry(tmp, struct nfsd_fixup, lru);
+ free_fixup_entry(fp);
+ i++;
+ }
+ printk("nfsd_fh_free: %d fixups freed\n", i);
+
+ i = 0;
+ while ((tmp = path_inuse.next) != &path_inuse) {
+ struct nfsd_path *pe;
+ pe = list_entry(tmp, struct nfsd_path, lru);
+ free_path_entry(pe);
+ i++;
+ }
+ printk("nfsd_fh_free: %d paths freed\n", i);
+
+ printk("nfsd_fh_free: verified %d, put %d\n",
+ nfsd_nr_verified, nfsd_nr_put);
+}
+
+void nfsd_fh_init(void)
+{
+ memset(filetable, 0, NFSD_MAXFH*sizeof(struct fh_entry));
+ memset(dirstable, 0, NFSD_MAXFH*sizeof(struct fh_entry));
+ INIT_LIST_HEAD(&path_inuse);
+ INIT_LIST_HEAD(&fixup_head);
+
+ printk("nfsd_init: initialized fhcache, entries=%lu\n", NFSD_MAXFH);
}
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 1e9cf788f..6cb65b5ef 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -78,6 +78,8 @@ nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp,
/*
* Look up a path name component
+ * Note: the dentry in the resp->fh may be negative if the file
+ * doesn't exist yet.
* N.B. After this call resp->fh needs an fh_put
*/
static int
@@ -88,10 +90,8 @@ nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
dprintk("nfsd: LOOKUP %p %s\n", SVCFH_DENTRY(&argp->fh), argp->name);
- nfserr = nfsd_lookup(rqstp, &argp->fh,
- argp->name,
- argp->len,
- &resp->fh);
+ nfserr = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len,
+ &resp->fh);
fh_put(&argp->fh);
RETURN(nfserr);
@@ -209,11 +209,10 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, MAY_EXEC);
if (nfserr)
goto done; /* must fh_put dirfhp even on error */
- dirp = dirfhp->fh_handle.fh_dentry->d_inode;
+ dirp = dirfhp->fh_dentry->d_inode;
/* Check for MAY_WRITE separately. */
- nfserr = nfsd_permission(dirfhp->fh_export,
- dirfhp->fh_handle.fh_dentry,
+ nfserr = nfsd_permission(dirfhp->fh_export, dirfhp->fh_dentry,
MAY_WRITE);
if (nfserr == nfserr_rofs) {
rdonly = 1; /* Non-fatal error for echo > /dev/null */
@@ -224,7 +223,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
exists = !nfsd_lookup(rqstp, dirfhp, argp->name, argp->len, newfhp);
if (newfhp->fh_dverified)
- inode = newfhp->fh_handle.fh_dentry->d_inode;
+ inode = newfhp->fh_dentry->d_inode;
/* Get rid of this soon... */
if (exists && !inode) {
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index cec3ba7f3..1d9a9dd5a 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -18,7 +18,7 @@
#define NFSDDBG_FACILITY NFSDDBG_XDR
u32 nfs_ok, nfserr_perm, nfserr_noent, nfserr_io, nfserr_nxio,
- nfserr_acces, nfserr_exist, nfserr_nodev, nfserr_notdir,
+ nfserr_inval, nfserr_acces, nfserr_exist, nfserr_nodev, nfserr_notdir,
nfserr_isdir, nfserr_fbig, nfserr_nospc, nfserr_rofs,
nfserr_nametoolong, nfserr_dquot, nfserr_stale;
@@ -47,10 +47,11 @@ nfsd_xdr_init(void)
if (inited)
return;
- nfs_ok = htonl(NFS_OK);
- nfserr_perm = htonl(NFSERR_PERM);
- nfserr_noent = htonl(NFSERR_NOENT);
- nfserr_io = htonl(NFSERR_IO);
+ nfs_ok = htonl(NFS_OK);
+ nfserr_perm = htonl(NFSERR_PERM);
+ nfserr_noent = htonl(NFSERR_NOENT);
+ nfserr_io = htonl(NFSERR_IO);
+ nfserr_inval = htonl(NFSERR_INVAL);
nfserr_nxio = htonl(NFSERR_NXIO);
nfserr_acces = htonl(NFSERR_ACCES);
nfserr_exist = htonl(NFSERR_EXIST);
@@ -363,7 +364,7 @@ int
nfssvc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
struct nfsd_attrstat *resp)
{
- if (!(p = encode_fattr(rqstp, p, resp->fh.fh_handle.fh_dentry->d_inode)))
+ if (!(p = encode_fattr(rqstp, p, resp->fh.fh_dentry->d_inode)))
return 0;
return xdr_ressize_check(rqstp, p);
}
@@ -373,7 +374,7 @@ nfssvc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
struct nfsd_diropres *resp)
{
if (!(p = encode_fh(p, &resp->fh))
- || !(p = encode_fattr(rqstp, p, resp->fh.fh_handle.fh_dentry->d_inode)))
+ || !(p = encode_fattr(rqstp, p, resp->fh.fh_dentry->d_inode)))
return 0;
return xdr_ressize_check(rqstp, p);
}
@@ -391,7 +392,7 @@ int
nfssvc_encode_readres(struct svc_rqst *rqstp, u32 *p,
struct nfsd_readres *resp)
{
- if (!(p = encode_fattr(rqstp, p, resp->fh.fh_handle.fh_dentry->d_inode)))
+ if (!(p = encode_fattr(rqstp, p, resp->fh.fh_dentry->d_inode)))
return 0;
*p++ = htonl(resp->count);
p += XDR_QUADLEN(resp->count);
diff --git a/fs/nfsd/stats.c b/fs/nfsd/stats.c
index ee76fcf6d..51a0fbc71 100644
--- a/fs/nfsd/stats.c
+++ b/fs/nfsd/stats.c
@@ -32,11 +32,15 @@ nfsd_proc_read(char *buffer, char **start, off_t offset, int count,
{
int len;
- len = sprintf(buffer,
- "rc %d %d %d\n",
+ len = sprintf(buffer, "rc %d %d %d %d %d %d %d %d\n",
nfsdstats.rchits,
nfsdstats.rcmisses,
- nfsdstats.rcnocache);
+ nfsdstats.rcnocache,
+ nfsdstats.fh_cached,
+ nfsdstats.fh_valid,
+ nfsdstats.fh_fixup,
+ nfsdstats.fh_lookup,
+ nfsdstats.fh_stale);
/* Assume we haven't hit EOF yet. Will be set by svc_proc_read. */
*eof = 0;
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index df6eb0e2c..4579cddec 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -36,6 +36,8 @@
#include <asm/uaccess.h>
#endif
+extern void fh_update(struct svc_fh*);
+
#define NFSDDBG_FACILITY NFSDDBG_FILEOP
/* Open mode for nfsd_open */
@@ -108,10 +110,11 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
dprintk("nfsd: nfsd_lookup(fh %p, %s)\n", SVCFH_DENTRY(fhp), name);
/* Obtain dentry and export. */
- if ((err = fh_verify(rqstp, fhp, S_IFDIR, MAY_NOP)) != 0)
- return err;
+ err = fh_verify(rqstp, fhp, S_IFDIR, MAY_NOP);
+ if (err)
+ goto out;
- dparent = fhp->fh_handle.fh_dentry;
+ dparent = fhp->fh_dentry;
exp = fhp->fh_export;
/* Fast path... */
@@ -121,11 +124,16 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
!nfsd_iscovered(dparent, exp)) {
struct dentry *dchild;
- dchild = lookup_dentry(name, dget(dparent), 1);
+ /* Lookup the name, but don't follow links */
+ dchild = lookup_dentry(name, dget(dparent), 0);
err = PTR_ERR(dchild);
if (IS_ERR(dchild))
return nfserrno(-err);
+ /*
+ * Note: we compose the filehandle now, but as the
+ * dentry may be negative, it may need to be updated.
+ */
fh_compose(resfh, exp, dchild);
return (dchild->d_inode ? 0 : nfserr_noent);
}
@@ -135,6 +143,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
return nfserr_noent;
if (nfsd_iscovered(dparent, exp))
return nfserr_acces;
+out:
return err;
}
@@ -158,10 +167,11 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap)
ftype = S_IFREG;
/* Get inode */
- if ((err = fh_verify(rqstp, fhp, ftype, accmode)) != 0)
- return err;
+ err = fh_verify(rqstp, fhp, ftype, accmode);
+ if (err)
+ goto out;
- dentry = fhp->fh_handle.fh_dentry;
+ dentry = fhp->fh_dentry;
inode = dentry->d_inode;
/* The size case is special... */
@@ -169,7 +179,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap)
if (iap->ia_size < inode->i_size) {
err = nfsd_permission(fhp->fh_export, dentry, MAY_TRUNC);
if (err != 0)
- return err;
+ goto out;
}
if ((err = get_write_access(inode)) != 0)
return nfserrno(-err);
@@ -211,8 +221,9 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap)
if (EX_ISSYNC(fhp->fh_export))
write_inode_now(inode);
}
-
- return 0;
+ err = 0;
+out:
+ return err;
}
/*
@@ -230,20 +241,23 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
access = wflag? MAY_WRITE : MAY_READ;
if ((err = fh_verify(rqstp, fhp, type, access)) != 0)
- return err;
+ goto out;
- dentry = fhp->fh_handle.fh_dentry;
+ dentry = fhp->fh_dentry;
inode = dentry->d_inode;
/* Disallow access to files with the append-only bit set or
* with mandatory locking enabled */
+ err = nfserr_perm;
if (IS_APPEND(inode) || IS_ISMNDLK(inode))
- return nfserr_perm;
+ goto out;
if (!inode->i_op || !inode->i_op->default_file_ops)
- return nfserr_perm;
+ goto out;
- if (wflag && (err = get_write_access(inode)) != 0)
- return nfserrno(-err);
+ if (wflag && (err = get_write_access(inode)) != 0) {
+ err = nfserrno(-err);
+ goto out;
+ }
memset(filp, 0, sizeof(*filp));
filp->f_op = inode->i_op->default_file_ops;
@@ -252,6 +266,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
filp->f_mode = wflag? FMODE_WRITE : FMODE_READ;
filp->f_dentry = dentry;
+ err = 0;
if (filp->f_op->open) {
err = filp->f_op->open(inode, filp);
if (err) {
@@ -262,11 +277,11 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
* is really on callers stack frame. -DaveM
*/
filp->f_count--;
- return nfserrno(-err);
+ err = nfserrno(-err);
}
}
-
- return 0;
+out:
+ return err;
}
/*
@@ -281,7 +296,8 @@ nfsd_close(struct file *filp)
if (!inode->i_count)
printk(KERN_WARNING "nfsd: inode count == 0!\n");
if (!dentry->d_count)
- printk(KERN_WARNING "nfsd: wheee, dentry count == 0!\n");
+ printk(KERN_WARNING "nfsd: wheee, %s/%s d_count == 0!\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
if (filp->f_op && filp->f_op->release)
filp->f_op->release(inode, filp);
if (filp->f_mode & FMODE_WRITE)
@@ -299,6 +315,9 @@ nfsd_sync(struct inode *inode, struct file *filp)
/*
* Obtain the readahead parameters for the given file
+ *
+ * N.B. is raparm cache for a file cleared when the file closes??
+ * (dentry might be reused later.)
*/
static inline struct raparms *
nfsd_get_raparms(struct dentry *dentry)
@@ -364,7 +383,7 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, char *buf,
file.f_pos = offset;
oldfs = get_fs(); set_fs(KERNEL_DS);
- err = file.f_op->read(inode, &file, buf, *count);
+ err = file.f_op->read(&file, buf, *count, &file.f_pos);
set_fs(oldfs);
/* Write back readahead params */
@@ -432,7 +451,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
/* Write the data. */
oldfs = get_fs(); set_fs(KERNEL_DS);
- err = file.f_op->write(inode, &file, buf, cnt);
+ err = file.f_op->write(&file, buf, cnt, &file.f_pos);
set_fs(oldfs);
/* clear setuid/setgid flag after write */
@@ -506,39 +525,53 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct inode *dirp;
int err;
+ err = nfserr_perm;
if (!flen)
- return nfserr_perm;
+ goto out;
if (!(iap->ia_valid & ATTR_MODE))
iap->ia_mode = 0;
- if ((err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE)) != 0)
- return err;
+ err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE);
+ if (err)
+ goto out;
- dentry = fhp->fh_handle.fh_dentry;
+ dentry = fhp->fh_dentry;
dirp = dentry->d_inode;
/* Get all the sanity checks out of the way before we lock the parent. */
- if(!dirp->i_op || !dirp->i_op->lookup) {
- return nfserrno(-ENOTDIR);
- } else if(type == S_IFREG) {
+ err = nfserr_notdir;
+ if(!dirp->i_op || !dirp->i_op->lookup)
+ goto out;
+ err = nfserr_perm;
+ if (type == S_IFREG) {
if(!dirp->i_op->create)
- return nfserr_perm;
+ goto out;
} else if(type == S_IFDIR) {
if(!dirp->i_op->mkdir)
- return nfserr_perm;
+ goto out;
} else if((type == S_IFCHR) || (type == S_IFBLK) || (type == S_IFIFO)) {
if(!dirp->i_op->mknod)
- return nfserr_perm;
+ goto out;
} else {
- return nfserr_perm;
+ goto out;
}
- if(!resfhp->fh_dverified) {
+ /*
+ * The response filehandle may have been setup already ...
+ */
+ if (!resfhp->fh_dverified) {
dchild = lookup_dentry(fname, dget(dentry), 0);
err = PTR_ERR(dchild);
if(IS_ERR(dchild))
return nfserrno(-err);
} else
- dchild = resfhp->fh_handle.fh_dentry;
+ dchild = resfhp->fh_dentry;
+ /*
+ * Make sure the child dentry is still negative ...
+ */
+ if (dchild->d_inode) {
+ printk("nfsd_create: dentry %s/%s not negative!\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
+ }
/* Looks good, lock the directory. */
fh_lock(fhp);
@@ -562,9 +595,15 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
if (EX_ISSYNC(fhp->fh_export))
write_inode_now(dirp);
- /* If needed, assemble the file handle for the newly created file. */
- if(!resfhp->fh_dverified)
+ /*
+ * Assemble the file handle for the newly created file,
+ * or update the filehandle to get the new inode info.
+ */
+ if (!resfhp->fh_dverified) {
fh_compose(resfhp, fhp->fh_export, dchild);
+ } else {
+ fh_update(resfhp);
+ }
/* Set file attributes. Mode has already been set and
* setting uid/gid works only for root. Irix appears to
@@ -574,7 +613,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
err = 0;
if ((iap->ia_valid &= (ATTR_UID|ATTR_GID|ATTR_MODE)) != 0)
err = nfsd_setattr(rqstp, resfhp, iap);
-
+out:
return err;
}
@@ -597,7 +636,7 @@ nfsd_truncate(struct svc_rqst *rqstp, struct svc_fh *fhp, unsigned long size)
if ((err = fh_verify(rqstp, fhp, S_IFREG, MAY_WRITE|MAY_TRUNC)) != 0)
return err;
- dentry = fhp->fh_handle.fh_dentry;
+ dentry = fhp->fh_dentry;
inode = dentry->d_inode;
if ((err = get_write_access(inode)) != 0)
@@ -633,13 +672,14 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
int err;
if ((err = fh_verify(rqstp, fhp, S_IFLNK, MAY_READ)) != 0)
- return err;
+ goto out;
- dentry = fhp->fh_handle.fh_dentry;
+ dentry = fhp->fh_dentry;
inode = dentry->d_inode;
+ err = nfserr_inval;
if (!inode->i_op || !inode->i_op->readlink)
- return nfserr_io;
+ goto out;
UPDATE_ATIME(inode);
oldfs = get_fs(); set_fs(KERNEL_DS);
@@ -647,10 +687,14 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
set_fs(oldfs);
if (err < 0)
- return nfserrno(-err);
- *lenp = err;
+ err = nfserrno(-err);
+ else {
+ *lenp = err;
+ err = 0;
+ }
- return 0;
+out:
+ return err;
}
/*
@@ -667,41 +711,43 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct inode *dirp;
int err;
+ err = nfserr_noent;
if (!flen || !plen)
- return nfserr_noent;
+ goto out;
if ((err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE)) != 0)
- return err;
+ goto out;
+ dentry = fhp->fh_dentry;
- dentry = fhp->fh_handle.fh_dentry;
+ err = nfserr_perm;
+ if (nfsd_iscovered(dentry, fhp->fh_export))
+ goto out;
dirp = dentry->d_inode;
-
- if (nfsd_iscovered(dentry, fhp->fh_export) ||
- !dirp->i_op ||
- !dirp->i_op->symlink)
- return nfserr_perm;
+ if (!dirp->i_op || !dirp->i_op->symlink)
+ goto out;
dnew = lookup_dentry(fname, dget(dentry), 0);
err = PTR_ERR(dnew);
if (IS_ERR(dnew))
- goto out;
+ goto out_nfserr;
err = -EEXIST;
- if(dnew->d_inode)
- goto compose_and_out;
-
- fh_lock(fhp);
- err = dirp->i_op->symlink(dirp, dnew, path);
- fh_unlock(fhp);
-
- if (!err) {
- if (EX_ISSYNC(fhp->fh_export))
- write_inode_now(dirp);
+ if (!dnew->d_inode) {
+ fh_lock(fhp);
+ err = dirp->i_op->symlink(dirp, dnew, path);
+ fh_unlock(fhp);
+ if (!err) {
+ if (EX_ISSYNC(fhp->fh_export))
+ write_inode_now(dirp);
+ }
}
-compose_and_out:
fh_compose(resfhp, fhp->fh_export, dnew);
+
+out_nfserr:
+ if (err)
+ err = nfserrno(-err);
out:
- return (err ? nfserrno(-err) : 0);
+ return err;
}
/*
@@ -720,7 +766,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
(err = fh_verify(rqstp, tfhp, S_IFREG, MAY_NOP)) != 0)
return err;
- ddir = ffhp->fh_handle.fh_dentry;
+ ddir = ffhp->fh_dentry;
dirp = ddir->d_inode;
dnew = lookup_dentry(fname, dget(ddir), 1);
@@ -731,7 +777,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
err = -EEXIST;
if (dnew->d_inode)
goto dput_and_out;
- dest = tfhp->fh_handle.fh_dentry->d_inode;
+ dest = tfhp->fh_dentry->d_inode;
err = -EPERM;
if (!len)
@@ -794,10 +840,10 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
|| (err = fh_verify(rqstp, tfhp, S_IFDIR, MAY_CREATE)) != 0)
return err;
- fdentry = ffhp->fh_handle.fh_dentry;
+ fdentry = ffhp->fh_dentry;
fdir = fdentry->d_inode;
- tdentry = tfhp->fh_handle.fh_dentry;
+ tdentry = tfhp->fh_dentry;
tdir = tdentry->d_inode;
if (!flen || (fname[0] == '.' &&
@@ -816,6 +862,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
if (IS_ERR(ndentry))
goto out_dput_old;
+ /* N.B. check this ... problems in locking?? */
nfsd_double_down(&tdir->i_sem, &fdir->i_sem);
err = -EXDEV;
if (fdir->i_dev != tdir->i_dev)
@@ -856,7 +903,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
if ((err = fh_verify(rqstp, fhp, S_IFDIR, MAY_REMOVE)) != 0)
return err;
- dentry = fhp->fh_handle.fh_dentry;
+ dentry = fhp->fh_dentry;
dirp = dentry->d_inode;
rdentry = lookup_dentry(fname, dget(dentry), 0);
@@ -975,20 +1022,24 @@ nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct statfs *stat)
unsigned long oldfs;
int err;
- if ((err = fh_verify(rqstp, fhp, 0, MAY_NOP)) != 0)
- return err;
- dentry = fhp->fh_handle.fh_dentry;
+ err = fh_verify(rqstp, fhp, 0, MAY_NOP);
+ if (err)
+ goto out;
+ dentry = fhp->fh_dentry;
inode = dentry->d_inode;
+ err = nfserr_io;
if (!(sb = inode->i_sb) || !sb->s_op->statfs)
- return nfserr_io;
+ goto out;
oldfs = get_fs();
set_fs (KERNEL_DS);
sb->s_op->statfs(sb, stat, sizeof(*stat));
set_fs (oldfs);
+ err = 0;
- return 0;
+out:
+ return err;
}
/*
diff --git a/fs/nls/.cvsignore b/fs/nls/.cvsignore
new file mode 100644
index 000000000..4671378ae
--- /dev/null
+++ b/fs/nls/.cvsignore
@@ -0,0 +1 @@
+.depend
diff --git a/fs/nls/Config.in b/fs/nls/Config.in
new file mode 100644
index 000000000..90cc3a161
--- /dev/null
+++ b/fs/nls/Config.in
@@ -0,0 +1,44 @@
+#
+# Native language support configuration
+#
+
+mainmenu_option next_comment
+comment 'Native Language Support'
+
+# msdos and Joliet want NLS
+if [ "$CONFIG_JOLIET" = "y" -o "$CONFIG_FAT_FS" != "n" ]; then
+ define_bool CONFIG_NLS y
+else
+ define_bool CONFIG_NLS n
+fi
+
+if [ "$CONFIG_NLS" = "y" ]; then
+ tristate 'Codepage 437' CONFIG_NLS_CODEPAGE_437
+ tristate 'Codepage 737' CONFIG_NLS_CODEPAGE_737
+ tristate 'Codepage 775' CONFIG_NLS_CODEPAGE_775
+ tristate 'Codepage 850' CONFIG_NLS_CODEPAGE_850
+ tristate 'Codepage 852' CONFIG_NLS_CODEPAGE_852
+ tristate 'Codepage 855' CONFIG_NLS_CODEPAGE_855
+ tristate 'Codepage 857' CONFIG_NLS_CODEPAGE_857
+ tristate 'Codepage 860' CONFIG_NLS_CODEPAGE_860
+ tristate 'Codepage 861' CONFIG_NLS_CODEPAGE_861
+ tristate 'Codepage 862' CONFIG_NLS_CODEPAGE_862
+ tristate 'Codepage 863' CONFIG_NLS_CODEPAGE_863
+ tristate 'Codepage 864' CONFIG_NLS_CODEPAGE_864
+ tristate 'Codepage 865' CONFIG_NLS_CODEPAGE_865
+ tristate 'Codepage 866' CONFIG_NLS_CODEPAGE_866
+ tristate 'Codepage 869' CONFIG_NLS_CODEPAGE_869
+ tristate 'Codepage 874' CONFIG_NLS_CODEPAGE_874
+ tristate 'NLS ISO 8859-1' CONFIG_NLS_ISO8859_1
+ tristate 'NLS ISO 8859-2' CONFIG_NLS_ISO8859_2
+ tristate 'NLS ISO 8859-3' CONFIG_NLS_ISO8859_3
+ tristate 'NLS ISO 8859-4' CONFIG_NLS_ISO8859_4
+ tristate 'NLS ISO 8859-5' CONFIG_NLS_ISO8859_5
+ tristate 'NLS ISO 8859-6' CONFIG_NLS_ISO8859_6
+ tristate 'NLS ISO 8859-7' CONFIG_NLS_ISO8859_7
+ tristate 'NLS ISO 8859-8' CONFIG_NLS_ISO8859_8
+ tristate 'NLS ISO 8859-9' CONFIG_NLS_ISO8859_9
+ tristate 'NLS KOI8-R' CONFIG_NLS_KOI8_R
+fi
+
+endmenu
diff --git a/fs/nls/Makefile b/fs/nls/Makefile
new file mode 100644
index 000000000..4f51a5f9d
--- /dev/null
+++ b/fs/nls/Makefile
@@ -0,0 +1,300 @@
+#
+# Makefile for native language support
+#
+
+MOD_LIST_NAME := NLS_MODULES
+
+NLS = nls_base.o
+
+ifeq ($(CONFIG_NLS_CODEPAGE_437),y)
+NLS += nls_cp437.o
+else
+ ifeq ($(CONFIG_NLS_CODEPAGE_437),m)
+ M_OBJS += nls_cp437.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_737),y)
+NLS += nls_cp737.o
+else
+ ifeq ($(CONFIG_NLS_CODEPAGE_737),m)
+ M_OBJS += nls_cp737.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_775),y)
+NLS += nls_cp775.o
+else
+ ifeq ($(CONFIG_NLS_CODEPAGE_775),m)
+ M_OBJS += nls_cp775.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_850),y)
+NLS += nls_cp850.o
+else
+ ifeq ($(CONFIG_NLS_CODEPAGE_850),m)
+ M_OBJS += nls_cp850.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_852),y)
+NLS += nls_cp852.o
+else
+ ifeq ($(CONFIG_NLS_CODEPAGE_852),m)
+ M_OBJS += nls_cp852.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_855),y)
+NLS += nls_cp855.o
+else
+ ifeq ($(CONFIG_NLS_CODEPAGE_855),m)
+ M_OBJS += nls_cp855.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_857),y)
+NLS += nls_cp857.o
+else
+ ifeq ($(CONFIG_NLS_CODEPAGE_857),m)
+ M_OBJS += nls_cp857.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_860),y)
+NLS += nls_cp860.o
+else
+ ifeq ($(CONFIG_NLS_CODEPAGE_860),m)
+ M_OBJS += nls_cp860.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_861),y)
+NLS += nls_cp861.o
+else
+ ifeq ($(CONFIG_NLS_CODEPAGE_861),m)
+ M_OBJS += nls_cp861.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_862),y)
+NLS += nls_cp862.o
+else
+ ifeq ($(CONFIG_NLS_CODEPAGE_862),m)
+ M_OBJS += nls_cp862.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_863),y)
+NLS += nls_cp863.o
+else
+ ifeq ($(CONFIG_NLS_CODEPAGE_863),m)
+ M_OBJS += nls_cp863.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_864),y)
+NLS += nls_cp864.o
+else
+ ifeq ($(CONFIG_NLS_CODEPAGE_864),m)
+ M_OBJS += nls_cp864.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_865),y)
+NLS += nls_cp865.o
+else
+ ifeq ($(CONFIG_NLS_CODEPAGE_865),m)
+ M_OBJS += nls_cp865.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_866),y)
+NLS += nls_cp866.o
+else
+ ifeq ($(CONFIG_NLS_CODEPAGE_866),m)
+ M_OBJS += nls_cp866.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_869),y)
+NLS += nls_cp869.o
+else
+ ifeq ($(CONFIG_NLS_CODEPAGE_869),m)
+ M_OBJS += nls_cp869.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_874),y)
+NLS += nls_cp874.o
+else
+ ifeq ($(CONFIG_NLS_CODEPAGE_874),m)
+ M_OBJS += nls_cp874.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_1250),y)
+NLS += nls_cp1250.o
+else
+ ifeq ($(CONFIG_NLS_CODEPAGE_1250),m)
+ M_OBJS += nls_cp1250.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_1251),y)
+NLS += nls_cp1251.o
+else
+ ifeq ($(CONFIG_NLS_CODEPAGE_1251),m)
+ M_OBJS += nls_cp1251.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_1252),y)
+NLS += nls_cp1252.o
+else
+ ifeq ($(CONFIG_NLS_CODEPAGE_1252),m)
+ M_OBJS += nls_cp1252.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_1253),y)
+NLS += nls_cp1253.o
+else
+ ifeq ($(CONFIG_NLS_CODEPAGE_1253),m)
+ M_OBJS += nls_cp1253.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_1254),y)
+NLS += nls_cp1254.o
+else
+ ifeq ($(CONFIG_NLS_CODEPAGE_1254),m)
+ M_OBJS += nls_cp1254.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_1255),y)
+NLS += nls_cp1255.o
+else
+ ifeq ($(CONFIG_NLS_CODEPAGE_1255),m)
+ M_OBJS += nls_cp1255.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_1256),y)
+NLS += nls_cp1256.o
+else
+ ifeq ($(CONFIG_NLS_CODEPAGE_1256),m)
+ M_OBJS += nls_cp1256.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_1257),y)
+NLS += nls_cp1257.o
+else
+ ifeq ($(CONFIG_NLS_CODEPAGE_1257),m)
+ M_OBJS += nls_cp1257.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_CODEPAGE_1258),y)
+NLS += nls_cp1258.o
+else
+ ifeq ($(CONFIG_NLS_CODEPAGE_1258),m)
+ M_OBJS += nls_cp1258.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_ISO8859_1),y)
+NLS += nls_iso8859-1.o
+else
+ ifeq ($(CONFIG_NLS_ISO8859_1),m)
+ M_OBJS += nls_iso8859-1.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_ISO8859_2),y)
+NLS += nls_iso8859-2.o
+else
+ ifeq ($(CONFIG_NLS_ISO8859_2),m)
+ M_OBJS += nls_iso8859-2.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_ISO8859_3),y)
+NLS += nls_iso8859-3.o
+else
+ ifeq ($(CONFIG_NLS_ISO8859_3),m)
+ M_OBJS += nls_iso8859-3.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_ISO8859_4),y)
+NLS += nls_iso8859-4.o
+else
+ ifeq ($(CONFIG_NLS_ISO8859_4),m)
+ M_OBJS += nls_iso8859-4.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_ISO8859_5),y)
+NLS += nls_iso8859-5.o
+else
+ ifeq ($(CONFIG_NLS_ISO8859_5),m)
+ M_OBJS += nls_iso8859-5.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_ISO8859_6),y)
+NLS += nls_iso8859-6.o
+else
+ ifeq ($(CONFIG_NLS_ISO8859_6),m)
+ M_OBJS += nls_iso8859-6.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_ISO8859_7),y)
+NLS += nls_iso8859-7.o
+else
+ ifeq ($(CONFIG_NLS_ISO8859_7),m)
+ M_OBJS += nls_iso8859-7.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_ISO8859_8),y)
+NLS += nls_iso8859-8.o
+else
+ ifeq ($(CONFIG_NLS_ISO8859_8),m)
+ M_OBJS += nls_iso8859-8.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_ISO8859_9),y)
+NLS += nls_iso8859-9.o
+else
+ ifeq ($(CONFIG_NLS_ISO8859_9),m)
+ M_OBJS += nls_iso8859-9.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_ISO8859_10),y)
+NLS += nls_iso8859-10.o
+else
+ ifeq ($(CONFIG_NLS_ISO8859_10),m)
+ M_OBJS += nls_iso8859-10.o
+ endif
+endif
+
+ifeq ($(CONFIG_NLS_KOI8_R),y)
+NLS += nls_koi8-r.o
+else
+ ifeq ($(CONFIG_NLS_KOI8_R),m)
+ M_OBJS += nls_koi8-r.o
+ endif
+endif
+
+O_TARGET = nls.o
+OX_OBJS = $(NLS)
+
+include $(TOPDIR)/Rules.make
diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c
new file mode 100644
index 000000000..ba0a134e4
--- /dev/null
+++ b/fs/nls/nls_base.c
@@ -0,0 +1,497 @@
+/*
+ * linux/fs/nls.c
+ *
+ * Native language support--charsets and unicode translations.
+ * By Gordon Chaffee 1996, 1997
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/config.h>
+#include <linux/nls.h>
+#include <linux/malloc.h>
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
+#include <asm/byteorder.h>
+
+static struct nls_table *tables = (struct nls_table *) NULL;
+
+/*
+ * Sample implementation from Unicode home page.
+ * http://www.stonehand.com/unicode/standard/fss-utf.html
+ */
+struct utf8_table {
+ int cmask;
+ int cval;
+ int shift;
+ long lmask;
+ long lval;
+};
+
+static struct utf8_table utf8_table[] =
+{
+ {0x80, 0x00, 0*6, 0x7F, 0, /* 1 byte sequence */},
+ {0xE0, 0xC0, 1*6, 0x7FF, 0x80, /* 2 byte sequence */},
+ {0xF0, 0xE0, 2*6, 0xFFFF, 0x800, /* 3 byte sequence */},
+ {0xF8, 0xF0, 3*6, 0x1FFFFF, 0x10000, /* 4 byte sequence */},
+ {0xFC, 0xF8, 4*6, 0x3FFFFFF, 0x200000, /* 5 byte sequence */},
+ {0xFE, 0xFC, 5*6, 0x7FFFFFFF, 0x4000000, /* 6 byte sequence */},
+ {0, /* end of table */}
+};
+
+int
+utf8_mbtowc(__u16 *p, const __u8 *s, int n)
+{
+ long l;
+ int c0, c, nc;
+ struct utf8_table *t;
+
+ printk("utf8_mbtowc\n");
+ nc = 0;
+ c0 = *s;
+ l = c0;
+ for (t = utf8_table; t->cmask; t++) {
+ nc++;
+ if ((c0 & t->cmask) == t->cval) {
+ l &= t->lmask;
+ if (l < t->lval)
+ return -1;
+ *p = l;
+ return nc;
+ }
+ if (n <= nc)
+ return -1;
+ s++;
+ c = (*s ^ 0x80) & 0xFF;
+ if (c & 0xC0)
+ return -1;
+ l = (l << 6) | c;
+ }
+ return -1;
+}
+
+int
+utf8_mbstowcs(__u16 *pwcs, const __u8 *s, int n)
+{
+ __u16 *op;
+ const __u8 *ip;
+ int size;
+
+ printk("\nutf8_mbstowcs: n=%d\n", n);
+ op = pwcs;
+ ip = s;
+ while (*ip && n > 0) {
+ printk(" %02x", *ip);
+ if (*ip & 0x80) {
+ size = utf8_mbtowc(op, ip, n);
+ if (size == -1) {
+ /* Ignore character and move on */
+ ip++;
+ n--;
+ } else {
+ op += size;
+ ip += size;
+ n -= size;
+ }
+ } else {
+ *op++ = *ip++;
+ }
+ }
+ return (op - pwcs);
+}
+
+int
+utf8_wctomb(__u8 *s, __u16 wc, int maxlen)
+{
+ long l;
+ int c, nc;
+ struct utf8_table *t;
+
+ if (s == 0)
+ return 0;
+
+ l = wc;
+ nc = 0;
+ for (t = utf8_table; t->cmask && maxlen; t++, maxlen--) {
+ nc++;
+ if (l <= t->lmask) {
+ c = t->shift;
+ *s = t->cval | (l >> c);
+ while (c > 0) {
+ c -= 6;
+ s++;
+ *s = 0x80 | ((l >> c) & 0x3F);
+ }
+ return nc;
+ }
+ }
+ return -1;
+}
+
+int
+utf8_wcstombs(__u8 *s, const __u16 *pwcs, int maxlen)
+{
+ const __u16 *ip;
+ __u8 *op;
+ int size;
+
+ op = s;
+ ip = pwcs;
+ while (*ip && maxlen > 0) {
+ if (*ip > 0x7f) {
+ size = utf8_wctomb(op, *ip, maxlen);
+ if (size == -1) {
+ /* Ignore character and move on */
+ maxlen--;
+ } else {
+ op += size;
+ maxlen -= size;
+ }
+ } else {
+ *op++ = (__u8) *ip;
+ }
+ ip++;
+ }
+ return (op - s);
+}
+
+int register_nls(struct nls_table * nls)
+{
+ struct nls_table ** tmp = &tables;
+
+ if (!nls)
+ return -EINVAL;
+ if (nls->next)
+ return -EBUSY;
+ while (*tmp) {
+ if (nls == *tmp) {
+ return -EBUSY;
+ }
+ tmp = &(*tmp)->next;
+ }
+ nls->next = tables;
+ tables = nls;
+ return 0;
+}
+
+int unregister_nls(struct nls_table * nls)
+{
+ struct nls_table ** tmp = &tables;
+
+ while (*tmp) {
+ if (nls == *tmp) {
+ *tmp = nls->next;
+ return 0;
+ }
+ tmp = &(*tmp)->next;
+ }
+ return -EINVAL;
+}
+
+struct nls_table *find_nls(char *charset)
+{
+ struct nls_table *nls = tables;
+ while (nls) {
+ if (! strcmp(nls->charset, charset))
+ return nls;
+ nls = nls->next;
+ }
+ return NULL;
+}
+
+struct nls_table *load_nls(char *charset)
+{
+ struct nls_table *nls;
+ char buf[40];
+ int ret;
+
+ nls = find_nls(charset);
+ if (nls) {
+ nls->inc_use_count();
+ return nls;
+ }
+
+#ifndef CONFIG_KERNELD
+ return NULL;
+#else
+ if (strlen(charset) > sizeof(buf) - sizeof("nls_")) {
+ printk("Unable to load NLS charset %s: name too long\n", charset);
+ return NULL;
+ }
+
+ sprintf(buf, "nls_%s", charset);
+ ret = request_module(buf);
+ if (ret != 0) {
+ printk("Unable to load NLS charset %s\n", charset);
+ return NULL;
+ }
+ nls = find_nls(charset);
+ if (nls) {
+ nls->inc_use_count();
+ }
+ return nls;
+#endif
+}
+
+void unload_nls(struct nls_table *nls)
+{
+ nls->dec_use_count();
+}
+
+struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0x80, 0x00}, {0x81, 0x00}, {0x82, 0x00}, {0x83, 0x00},
+ {0x84, 0x00}, {0x85, 0x00}, {0x86, 0x00}, {0x87, 0x00},
+ {0x88, 0x00}, {0x89, 0x00}, {0x8a, 0x00}, {0x8b, 0x00},
+ {0x8c, 0x00}, {0x8d, 0x00}, {0x8e, 0x00}, {0x8f, 0x00},
+ /* 0x90*/
+ {0x90, 0x00}, {0x91, 0x00}, {0x92, 0x00}, {0x93, 0x00},
+ {0x94, 0x00}, {0x95, 0x00}, {0x96, 0x00}, {0x97, 0x00},
+ {0x98, 0x00}, {0x99, 0x00}, {0x9a, 0x00}, {0x9b, 0x00},
+ {0x9c, 0x00}, {0x9d, 0x00}, {0x9e, 0x00}, {0x9f, 0x00},
+ /* 0xa0*/
+ {0xa0, 0x00}, {0xa1, 0x00}, {0xa2, 0x00}, {0xa3, 0x00},
+ {0xa4, 0x00}, {0xa5, 0x00}, {0xa6, 0x00}, {0xa7, 0x00},
+ {0xa8, 0x00}, {0xa9, 0x00}, {0xaa, 0x00}, {0xab, 0x00},
+ {0xac, 0x00}, {0xad, 0x00}, {0xae, 0x00}, {0xaf, 0x00},
+ /* 0xb0*/
+ {0xb0, 0x00}, {0xb1, 0x00}, {0xb2, 0x00}, {0xb3, 0x00},
+ {0xb4, 0x00}, {0xb5, 0x00}, {0xb6, 0x00}, {0xb7, 0x00},
+ {0xb8, 0x00}, {0xb9, 0x00}, {0xba, 0x00}, {0xbb, 0x00},
+ {0xbc, 0x00}, {0xbd, 0x00}, {0xbe, 0x00}, {0xbf, 0x00},
+ /* 0xc0*/
+ {0xc0, 0x00}, {0xc1, 0x00}, {0xc2, 0x00}, {0xc3, 0x00},
+ {0xc4, 0x00}, {0xc5, 0x00}, {0xc6, 0x00}, {0xc7, 0x00},
+ {0xc8, 0x00}, {0xc9, 0x00}, {0xca, 0x00}, {0xcb, 0x00},
+ {0xcc, 0x00}, {0xcd, 0x00}, {0xce, 0x00}, {0xcf, 0x00},
+ /* 0xd0*/
+ {0xd0, 0x00}, {0xd1, 0x00}, {0xd2, 0x00}, {0xd3, 0x00},
+ {0xd4, 0x00}, {0xd5, 0x00}, {0xd6, 0x00}, {0xd7, 0x00},
+ {0xd8, 0x00}, {0xd9, 0x00}, {0xda, 0x00}, {0xdb, 0x00},
+ {0xdc, 0x00}, {0xdd, 0x00}, {0xde, 0x00}, {0xdf, 0x00},
+ /* 0xe0*/
+ {0xe0, 0x00}, {0xe1, 0x00}, {0xe2, 0x00}, {0xe3, 0x00},
+ {0xe4, 0x00}, {0xe5, 0x00}, {0xe6, 0x00}, {0xe7, 0x00},
+ {0xe8, 0x00}, {0xe9, 0x00}, {0xea, 0x00}, {0xeb, 0x00},
+ {0xec, 0x00}, {0xed, 0x00}, {0xee, 0x00}, {0xef, 0x00},
+ /* 0xf0*/
+ {0xf0, 0x00}, {0xf1, 0x00}, {0xf2, 0x00}, {0xf3, 0x00},
+ {0xf4, 0x00}, {0xf5, 0x00}, {0xf6, 0x00}, {0xf7, 0x00},
+ {0xf8, 0x00}, {0xf9, 0x00}, {0xfa, 0x00}, {0xfb, 0x00},
+ {0xfc, 0x00}, {0xfd, 0x00}, {0xfe, 0x00}, {0xff, 0x00},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00
+};
+
+
+void inc_use_count(void)
+{
+}
+
+void dec_use_count(void)
+{
+}
+
+static struct nls_table default_table = {
+ "default",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+
+
+/* Returns a simple default translation table */
+struct nls_table *load_nls_default(void)
+{
+ return &default_table;
+}
+
+EXPORT_SYMBOL(register_nls);
+EXPORT_SYMBOL(unregister_nls);
+EXPORT_SYMBOL(unload_nls);
+EXPORT_SYMBOL(find_nls);
+EXPORT_SYMBOL(load_nls);
+EXPORT_SYMBOL(load_nls_default);
+EXPORT_SYMBOL(utf8_mbtowc);
+EXPORT_SYMBOL(utf8_mbstowcs);
+EXPORT_SYMBOL(utf8_wctomb);
+EXPORT_SYMBOL(utf8_wcstombs);
+
+int init_nls(void)
+{
+#ifdef CONFIG_NLS_ISO8859_1
+ init_nls_iso8859_1();
+#endif
+#ifdef CONFIG_NLS_ISO8859_2
+ init_nls_iso8859_2();
+#endif
+#ifdef CONFIG_NLS_ISO8859_3
+ init_nls_iso8859_3();
+#endif
+#ifdef CONFIG_NLS_ISO8859_4
+ init_nls_iso8859_4();
+#endif
+#ifdef CONFIG_NLS_ISO8859_5
+ init_nls_iso8859_5();
+#endif
+#ifdef CONFIG_NLS_ISO8859_6
+ init_nls_iso8859_6();
+#endif
+#ifdef CONFIG_NLS_ISO8859_7
+ init_nls_iso8859_7();
+#endif
+#ifdef CONFIG_NLS_ISO8859_8
+ init_nls_iso8859_8();
+#endif
+#ifdef CONFIG_NLS_ISO8859_9
+ init_nls_iso8859_9();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_437
+ init_nls_cp437();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_737
+ init_nls_cp737();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_775
+ init_nls_cp775();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_850
+ init_nls_cp850();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_852
+ init_nls_cp852();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_855
+ init_nls_cp855();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_857
+ init_nls_cp857();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_860
+ init_nls_cp860();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_861
+ init_nls_cp861();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_862
+ init_nls_cp862();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_863
+ init_nls_cp863();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_864
+ init_nls_cp864();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_865
+ init_nls_cp865();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_866
+ init_nls_cp866();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_869
+ init_nls_cp869();
+#endif
+#ifdef CONFIG_NLS_CODEPAGE_874
+ init_nls_cp874();
+#endif
+#ifdef CONFIG_NLS_KOI8_R
+ init_nls_koi8_r();
+#endif
+ return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls();
+}
+
+
+void cleanup_module(void)
+{
+}
+#endif /* ifdef MODULE */
diff --git a/fs/nls/nls_cp437.c b/fs/nls/nls_cp437.c
new file mode 100644
index 000000000..70495cd71
--- /dev/null
+++ b/fs/nls/nls_cp437.c
@@ -0,0 +1,447 @@
+/*
+ * linux/fs/nls_cp437.c
+ *
+ * Charset cp437 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0xc7, 0x00}, {0xfc, 0x00}, {0xe9, 0x00}, {0xe2, 0x00},
+ {0xe4, 0x00}, {0xe0, 0x00}, {0xe5, 0x00}, {0xe7, 0x00},
+ {0xea, 0x00}, {0xeb, 0x00}, {0xe8, 0x00}, {0xef, 0x00},
+ {0xee, 0x00}, {0xec, 0x00}, {0xc4, 0x00}, {0xc5, 0x00},
+ /* 0x90*/
+ {0xc9, 0x00}, {0xe6, 0x00}, {0xc6, 0x00}, {0xf4, 0x00},
+ {0xf6, 0x00}, {0xf2, 0x00}, {0xfb, 0x00}, {0xf9, 0x00},
+ {0xff, 0x00}, {0xd6, 0x00}, {0xdc, 0x00}, {0xa2, 0x00},
+ {0xa3, 0x00}, {0xa5, 0x00}, {0xa7, 0x20}, {0x92, 0x01},
+ /* 0xa0*/
+ {0xe1, 0x00}, {0xed, 0x00}, {0xf3, 0x00}, {0xfa, 0x00},
+ {0xf1, 0x00}, {0xd1, 0x00}, {0xaa, 0x00}, {0xba, 0x00},
+ {0xbf, 0x00}, {0x10, 0x23}, {0xac, 0x00}, {0xbd, 0x00},
+ {0xbc, 0x00}, {0xa1, 0x00}, {0xab, 0x00}, {0xbb, 0x00},
+ /* 0xb0*/
+ {0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+ {0x24, 0x25}, {0x61, 0x25}, {0x62, 0x25}, {0x56, 0x25},
+ {0x55, 0x25}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+ {0x5d, 0x25}, {0x5c, 0x25}, {0x5b, 0x25}, {0x10, 0x25},
+ /* 0xc0*/
+ {0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+ {0x00, 0x25}, {0x3c, 0x25}, {0x5e, 0x25}, {0x5f, 0x25},
+ {0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+ {0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0x67, 0x25},
+ /* 0xd0*/
+ {0x68, 0x25}, {0x64, 0x25}, {0x65, 0x25}, {0x59, 0x25},
+ {0x58, 0x25}, {0x52, 0x25}, {0x53, 0x25}, {0x6b, 0x25},
+ {0x6a, 0x25}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+ {0x84, 0x25}, {0x8c, 0x25}, {0x90, 0x25}, {0x80, 0x25},
+ /* 0xe0*/
+ {0xb1, 0x03}, {0xdf, 0x00}, {0x93, 0x03}, {0xc0, 0x03},
+ {0xa3, 0x03}, {0xc3, 0x03}, {0xb5, 0x00}, {0xc4, 0x03},
+ {0xa6, 0x03}, {0x98, 0x03}, {0xa9, 0x03}, {0xb4, 0x03},
+ {0x1e, 0x22}, {0xc6, 0x03}, {0xb5, 0x03}, {0x29, 0x22},
+ /* 0xf0*/
+ {0x61, 0x22}, {0xb1, 0x00}, {0x65, 0x22}, {0x64, 0x22},
+ {0x20, 0x23}, {0x21, 0x23}, {0xf7, 0x00}, {0x48, 0x22},
+ {0xb0, 0x00}, {0x19, 0x22}, {0xb7, 0x00}, {0x1a, 0x22},
+ {0x7f, 0x20}, {0xb2, 0x00}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xff, 0xad, 0x9b, 0x9c, 0x00, 0x9d, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0xa6, 0xae, 0xaa, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0xf8, 0xf1, 0xfd, 0x00, 0x00, 0xe6, 0x00, 0xfa, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0xa7, 0xaf, 0xac, 0xab, 0x00, 0xa8, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, 0x92, 0x80, /* 0xc0-0xc7 */
+ 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0xe1, /* 0xd8-0xdf */
+ 0x85, 0xa0, 0x83, 0x00, 0x84, 0x86, 0x91, 0x87, /* 0xe0-0xe7 */
+ 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b, /* 0xe8-0xef */
+ 0x00, 0xa4, 0x95, 0xa2, 0x93, 0x00, 0x94, 0xf6, /* 0xf0-0xf7 */
+ 0x00, 0x97, 0xa3, 0x96, 0x81, 0x00, 0x00, 0x98, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page03[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0xe8, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0xe0, 0x00, 0x00, 0xeb, 0xee, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page22[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0xec, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page23[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+ 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */
+ 0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */
+ 0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */
+ 0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, page01, NULL, page03, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ page20, NULL, page22, page23, NULL, page25, NULL, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+ 0x00, 0x00, 0xe2, 0x00, 0xe4, 0x00, 0xe6, 0x00, /* 0xe0-0xe7 */
+ 0xe8, 0xe9, 0xea, 0x00, 0xec, 0x00, 0x00, 0xef, /* 0xe8-0xef */
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0x00, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "cp437",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_cp437(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_cp437();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/nls/nls_cp737.c b/fs/nls/nls_cp737.c
new file mode 100644
index 000000000..fdcd2be3e
--- /dev/null
+++ b/fs/nls/nls_cp737.c
@@ -0,0 +1,375 @@
+/*
+ * linux/fs/nls_cp737.c
+ *
+ * Charset cp737 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0x91, 0x03}, {0x92, 0x03}, {0x93, 0x03}, {0x94, 0x03},
+ {0x95, 0x03}, {0x96, 0x03}, {0x97, 0x03}, {0x98, 0x03},
+ {0x99, 0x03}, {0x9a, 0x03}, {0x9b, 0x03}, {0x9c, 0x03},
+ {0x9d, 0x03}, {0x9e, 0x03}, {0x9f, 0x03}, {0xa0, 0x03},
+ /* 0x90*/
+ {0xa1, 0x03}, {0xa3, 0x03}, {0xa4, 0x03}, {0xa5, 0x03},
+ {0xa6, 0x03}, {0xa7, 0x03}, {0xa8, 0x03}, {0xa9, 0x03},
+ {0xb1, 0x03}, {0xb2, 0x03}, {0xb3, 0x03}, {0xb4, 0x03},
+ {0xb5, 0x03}, {0xb6, 0x03}, {0xb7, 0x03}, {0xb8, 0x03},
+ /* 0xa0*/
+ {0xb9, 0x03}, {0xba, 0x03}, {0xbb, 0x03}, {0xbc, 0x03},
+ {0xbd, 0x03}, {0xbe, 0x03}, {0xbf, 0x03}, {0xc0, 0x03},
+ {0xc1, 0x03}, {0xc3, 0x03}, {0xc2, 0x03}, {0xc4, 0x03},
+ {0xc5, 0x03}, {0xc6, 0x03}, {0xc7, 0x03}, {0xc8, 0x03},
+ /* 0xb0*/
+ {0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+ {0x24, 0x25}, {0x61, 0x25}, {0x62, 0x25}, {0x56, 0x25},
+ {0x55, 0x25}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+ {0x5d, 0x25}, {0x5c, 0x25}, {0x5b, 0x25}, {0x10, 0x25},
+ /* 0xc0*/
+ {0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+ {0x00, 0x25}, {0x3c, 0x25}, {0x5e, 0x25}, {0x5f, 0x25},
+ {0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+ {0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0x67, 0x25},
+ /* 0xd0*/
+ {0x68, 0x25}, {0x64, 0x25}, {0x65, 0x25}, {0x59, 0x25},
+ {0x58, 0x25}, {0x52, 0x25}, {0x53, 0x25}, {0x6b, 0x25},
+ {0x6a, 0x25}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+ {0x84, 0x25}, {0x8c, 0x25}, {0x90, 0x25}, {0x80, 0x25},
+ /* 0xe0*/
+ {0xc9, 0x03}, {0xac, 0x03}, {0xad, 0x03}, {0xae, 0x03},
+ {0xca, 0x03}, {0xaf, 0x03}, {0xcc, 0x03}, {0xcd, 0x03},
+ {0xcb, 0x03}, {0xce, 0x03}, {0x86, 0x03}, {0x88, 0x03},
+ {0x89, 0x03}, {0x8a, 0x03}, {0x8c, 0x03}, {0x8e, 0x03},
+ /* 0xf0*/
+ {0x8f, 0x03}, {0xb1, 0x00}, {0x65, 0x22}, {0x64, 0x22},
+ {0xaa, 0x03}, {0xab, 0x03}, {0xf7, 0x00}, {0x48, 0x22},
+ {0xb0, 0x00}, {0x19, 0x22}, {0xb7, 0x00}, {0x1a, 0x22},
+ {0x7f, 0x20}, {0xb2, 0x00}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0xf8, 0xf1, 0xfd, 0x00, 0x00, 0x00, 0x00, 0xfa, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page03[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x00, /* 0x80-0x87 */
+ 0xeb, 0xec, 0xed, 0x00, 0xee, 0x00, 0xef, 0xf0, /* 0x88-0x8f */
+ 0x00, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, /* 0x90-0x97 */
+ 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, /* 0x98-0x9f */
+ 0x8f, 0x90, 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, /* 0xa0-0xa7 */
+ 0x96, 0x97, 0xf4, 0xf5, 0xe1, 0xe2, 0xe3, 0xe5, /* 0xa8-0xaf */
+ 0x00, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, /* 0xb0-0xb7 */
+ 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, /* 0xb8-0xbf */
+ 0xa7, 0xa8, 0xaa, 0xa9, 0xab, 0xac, 0xad, 0xae, /* 0xc0-0xc7 */
+ 0xaf, 0xe0, 0xe4, 0xe8, 0xe6, 0xe7, 0xe9, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page22[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+ 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */
+ 0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */
+ 0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */
+ 0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, NULL, NULL, page03, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ page20, NULL, page22, NULL, NULL, page25, NULL, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0x00, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "cp737",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_cp737(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_cp737();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/nls/nls_cp775.c b/fs/nls/nls_cp775.c
new file mode 100644
index 000000000..f7b49476a
--- /dev/null
+++ b/fs/nls/nls_cp775.c
@@ -0,0 +1,375 @@
+/*
+ * linux/fs/nls_cp775.c
+ *
+ * Charset cp775 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0x06, 0x01}, {0xfc, 0x00}, {0xe9, 0x00}, {0x01, 0x01},
+ {0xe4, 0x00}, {0x23, 0x01}, {0xe5, 0x00}, {0x07, 0x01},
+ {0x42, 0x01}, {0x13, 0x01}, {0x56, 0x01}, {0x57, 0x01},
+ {0x2b, 0x01}, {0x79, 0x01}, {0xc4, 0x00}, {0xc5, 0x00},
+ /* 0x90*/
+ {0xc9, 0x00}, {0xe6, 0x00}, {0xc6, 0x00}, {0x4d, 0x01},
+ {0xf6, 0x00}, {0x22, 0x01}, {0xa2, 0x00}, {0x5a, 0x01},
+ {0x5b, 0x01}, {0xd6, 0x00}, {0xdc, 0x00}, {0xf8, 0x00},
+ {0xa3, 0x00}, {0xd8, 0x00}, {0xd7, 0x00}, {0xa4, 0x00},
+ /* 0xa0*/
+ {0x00, 0x01}, {0x2a, 0x01}, {0xf3, 0x00}, {0x7b, 0x01},
+ {0x7c, 0x01}, {0x7a, 0x01}, {0x1d, 0x20}, {0xa6, 0x00},
+ {0xa9, 0x00}, {0xae, 0x00}, {0xac, 0x00}, {0xbd, 0x00},
+ {0xbc, 0x00}, {0x41, 0x01}, {0xab, 0x00}, {0xbb, 0x00},
+ /* 0xb0*/
+ {0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+ {0x24, 0x25}, {0x04, 0x01}, {0x0c, 0x01}, {0x18, 0x01},
+ {0x16, 0x01}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+ {0x5d, 0x25}, {0x2e, 0x01}, {0x60, 0x01}, {0x10, 0x25},
+ /* 0xc0*/
+ {0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+ {0x00, 0x25}, {0x3c, 0x25}, {0x72, 0x01}, {0x6a, 0x01},
+ {0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+ {0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0x7d, 0x01},
+ /* 0xd0*/
+ {0x05, 0x01}, {0x0d, 0x01}, {0x19, 0x01}, {0x17, 0x01},
+ {0x2f, 0x01}, {0x61, 0x01}, {0x73, 0x01}, {0x6b, 0x01},
+ {0x7e, 0x01}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+ {0x84, 0x25}, {0x8c, 0x25}, {0x90, 0x25}, {0x80, 0x25},
+ /* 0xe0*/
+ {0xd3, 0x00}, {0xdf, 0x00}, {0x4c, 0x01}, {0x43, 0x01},
+ {0xf5, 0x00}, {0xd5, 0x00}, {0xb5, 0x00}, {0x44, 0x01},
+ {0x36, 0x01}, {0x37, 0x01}, {0x3b, 0x01}, {0x3c, 0x01},
+ {0x46, 0x01}, {0x12, 0x01}, {0x45, 0x01}, {0x19, 0x20},
+ /* 0xf0*/
+ {0xad, 0x00}, {0xb1, 0x00}, {0x1c, 0x20}, {0xbe, 0x00},
+ {0xb6, 0x00}, {0xa7, 0x00}, {0xf7, 0x00}, {0x1e, 0x20},
+ {0xb0, 0x00}, {0x19, 0x22}, {0xb7, 0x00}, {0xb9, 0x00},
+ {0xb3, 0x00}, {0xb2, 0x00}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xff, 0x00, 0x96, 0x9c, 0x9f, 0x00, 0xa7, 0xf5, /* 0xa0-0xa7 */
+ 0x00, 0xa8, 0x00, 0xae, 0xaa, 0xf0, 0xa9, 0x00, /* 0xa8-0xaf */
+ 0xf8, 0xf1, 0xfd, 0xfc, 0x00, 0xe6, 0xf4, 0xfa, /* 0xb0-0xb7 */
+ 0x00, 0xfb, 0x00, 0xaf, 0xac, 0xab, 0xf3, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, 0x92, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0xe0, 0x00, 0xe5, 0x99, 0x9e, /* 0xd0-0xd7 */
+ 0x9d, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0xe1, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x84, 0x86, 0x91, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0xa2, 0x00, 0xe4, 0x94, 0xf6, /* 0xf0-0xf7 */
+ 0x9b, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+ 0xa0, 0x83, 0x00, 0x00, 0xb5, 0xd0, 0x80, 0x87, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0xb6, 0xd1, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0xed, 0x89, 0x00, 0x00, 0xb8, 0xd3, /* 0x10-0x17 */
+ 0xb7, 0xd2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x95, 0x85, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0xa1, 0x8c, 0x00, 0x00, 0xbd, 0xd4, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xe9, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0xea, 0xeb, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0xad, 0x88, 0xe3, 0xe7, 0xee, 0xec, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0xe2, 0x93, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x8b, /* 0x50-0x57 */
+ 0x00, 0x00, 0x97, 0x98, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0xbe, 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0xc7, 0xd7, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0xc6, 0xd6, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x8d, 0xa5, 0xa3, 0xa4, 0xcf, 0xd8, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0xef, 0x00, 0x00, 0xf2, 0xa6, 0xf7, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page22[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+ 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0xcd, 0xba, 0x00, 0x00, 0xc9, 0x00, 0x00, 0xbb, /* 0x50-0x57 */
+ 0x00, 0x00, 0xc8, 0x00, 0x00, 0xbc, 0x00, 0x00, /* 0x58-0x5f */
+ 0xcc, 0x00, 0x00, 0xb9, 0x00, 0x00, 0xcb, 0x00, /* 0x60-0x67 */
+ 0x00, 0xca, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, page01, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ page20, NULL, page22, NULL, NULL, page25, NULL, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x8a, 0x00, 0x00, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x00, 0x00, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+ 0x00, 0x99, 0x9a, 0x00, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+ 0xa0, 0xa1, 0x00, 0xa3, 0x00, 0x00, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+ 0xe0, 0x00, 0xe2, 0xe3, 0x00, 0xe5, 0xe6, 0x00, /* 0xe0-0xe7 */
+ 0xe8, 0x00, 0xea, 0x00, 0x00, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "cp775",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_cp775(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_cp775();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/nls/nls_cp850.c b/fs/nls/nls_cp850.c
new file mode 100644
index 000000000..cb6e0e77a
--- /dev/null
+++ b/fs/nls/nls_cp850.c
@@ -0,0 +1,339 @@
+/*
+ * linux/fs/nls_cp850.c
+ *
+ * Charset cp850 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0xc7, 0x00}, {0xfc, 0x00}, {0xe9, 0x00}, {0xe2, 0x00},
+ {0xe4, 0x00}, {0xe0, 0x00}, {0xe5, 0x00}, {0xe7, 0x00},
+ {0xea, 0x00}, {0xeb, 0x00}, {0xe8, 0x00}, {0xef, 0x00},
+ {0xee, 0x00}, {0xec, 0x00}, {0xc4, 0x00}, {0xc5, 0x00},
+ /* 0x90*/
+ {0xc9, 0x00}, {0xe6, 0x00}, {0xc6, 0x00}, {0xf4, 0x00},
+ {0xf6, 0x00}, {0xf2, 0x00}, {0xfb, 0x00}, {0xf9, 0x00},
+ {0xff, 0x00}, {0xd6, 0x00}, {0xdc, 0x00}, {0xf8, 0x00},
+ {0xa3, 0x00}, {0xd8, 0x00}, {0xd7, 0x00}, {0x92, 0x01},
+ /* 0xa0*/
+ {0xe1, 0x00}, {0xed, 0x00}, {0xf3, 0x00}, {0xfa, 0x00},
+ {0xf1, 0x00}, {0xd1, 0x00}, {0xaa, 0x00}, {0xba, 0x00},
+ {0xbf, 0x00}, {0xae, 0x00}, {0xac, 0x00}, {0xbd, 0x00},
+ {0xbc, 0x00}, {0xa1, 0x00}, {0xab, 0x00}, {0xbb, 0x00},
+ /* 0xb0*/
+ {0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+ {0x24, 0x25}, {0xc1, 0x00}, {0xc2, 0x00}, {0xc0, 0x00},
+ {0xa9, 0x00}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+ {0x5d, 0x25}, {0xa2, 0x00}, {0xa5, 0x00}, {0x10, 0x25},
+ /* 0xc0*/
+ {0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+ {0x00, 0x25}, {0x3c, 0x25}, {0xe3, 0x00}, {0xc3, 0x00},
+ {0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+ {0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0xa4, 0x00},
+ /* 0xd0*/
+ {0xf0, 0x00}, {0xd0, 0x00}, {0xca, 0x00}, {0xcb, 0x00},
+ {0xc8, 0x00}, {0x31, 0x01}, {0xcd, 0x00}, {0xce, 0x00},
+ {0xcf, 0x00}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+ {0x84, 0x25}, {0xa6, 0x00}, {0xcc, 0x00}, {0x80, 0x25},
+ /* 0xe0*/
+ {0xd3, 0x00}, {0xdf, 0x00}, {0xd4, 0x00}, {0xd2, 0x00},
+ {0xf5, 0x00}, {0xd5, 0x00}, {0xb5, 0x00}, {0xfe, 0x00},
+ {0xde, 0x00}, {0xda, 0x00}, {0xdb, 0x00}, {0xd9, 0x00},
+ {0xfd, 0x00}, {0xdd, 0x00}, {0xaf, 0x00}, {0xb4, 0x00},
+ /* 0xf0*/
+ {0xad, 0x00}, {0xb1, 0x00}, {0x17, 0x20}, {0xbe, 0x00},
+ {0xb6, 0x00}, {0xa7, 0x00}, {0xf7, 0x00}, {0xb8, 0x00},
+ {0xb0, 0x00}, {0xa8, 0x00}, {0xb7, 0x00}, {0xb9, 0x00},
+ {0xb3, 0x00}, {0xb2, 0x00}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xff, 0xad, 0xbd, 0x9c, 0xcf, 0xbe, 0xdd, 0xf5, /* 0xa0-0xa7 */
+ 0xf9, 0xb8, 0xa6, 0xae, 0xaa, 0xf0, 0xa9, 0xee, /* 0xa8-0xaf */
+ 0xf8, 0xf1, 0xfd, 0xfc, 0xef, 0xe6, 0xf4, 0xfa, /* 0xb0-0xb7 */
+ 0xf7, 0xfb, 0xa7, 0xaf, 0xac, 0xab, 0xf3, 0xa8, /* 0xb8-0xbf */
+ 0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* 0xc0-0xc7 */
+ 0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* 0xc8-0xcf */
+ 0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0x9e, /* 0xd0-0xd7 */
+ 0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0xe1, /* 0xd8-0xdf */
+ 0x85, 0xa0, 0x83, 0xc6, 0x84, 0x86, 0x91, 0x87, /* 0xe0-0xe7 */
+ 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b, /* 0xe8-0xef */
+ 0xd0, 0xa4, 0x95, 0xa2, 0x93, 0xe4, 0x94, 0xf6, /* 0xf0-0xf7 */
+ 0x9b, 0x97, 0xa3, 0x96, 0x81, 0xec, 0xe7, 0x98, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+ 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0xcd, 0xba, 0x00, 0x00, 0xc9, 0x00, 0x00, 0xbb, /* 0x50-0x57 */
+ 0x00, 0x00, 0xc8, 0x00, 0x00, 0xbc, 0x00, 0x00, /* 0x58-0x5f */
+ 0xcc, 0x00, 0x00, 0xb9, 0x00, 0x00, 0xcb, 0x00, /* 0x60-0x67 */
+ 0x00, 0xca, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, page01, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ page20, NULL, NULL, NULL, NULL, page25, NULL, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x99, 0x9a, 0x00, 0x9c, 0x9d, 0x9e, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0x00, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0x00, 0xd1, 0xd2, 0xd3, 0xd4, 0x00, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+ 0xe0, 0x00, 0xe2, 0xe3, 0x00, 0xe5, 0xe6, 0x00, /* 0xe0-0xe7 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0x00, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "cp850",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_cp850(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_cp850();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/nls/nls_cp852.c b/fs/nls/nls_cp852.c
new file mode 100644
index 000000000..d454de854
--- /dev/null
+++ b/fs/nls/nls_cp852.c
@@ -0,0 +1,339 @@
+/*
+ * linux/fs/nls_cp852.c
+ *
+ * Charset cp852 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0xc7, 0x00}, {0xfc, 0x00}, {0xe9, 0x00}, {0xe2, 0x00},
+ {0xe4, 0x00}, {0x6f, 0x01}, {0x07, 0x01}, {0xe7, 0x00},
+ {0x42, 0x01}, {0xeb, 0x00}, {0x50, 0x01}, {0x51, 0x01},
+ {0xee, 0x00}, {0x79, 0x01}, {0xc4, 0x00}, {0x06, 0x01},
+ /* 0x90*/
+ {0xc9, 0x00}, {0x39, 0x01}, {0x3a, 0x01}, {0xf4, 0x00},
+ {0xf6, 0x00}, {0x3d, 0x01}, {0x3e, 0x01}, {0x5a, 0x01},
+ {0x5b, 0x01}, {0xd6, 0x00}, {0xdc, 0x00}, {0x64, 0x01},
+ {0x65, 0x01}, {0x41, 0x01}, {0xd7, 0x00}, {0x0d, 0x01},
+ /* 0xa0*/
+ {0xe1, 0x00}, {0xed, 0x00}, {0xf3, 0x00}, {0xfa, 0x00},
+ {0x04, 0x01}, {0x05, 0x01}, {0x7d, 0x01}, {0x7e, 0x01},
+ {0x18, 0x01}, {0x19, 0x01}, {0xac, 0x00}, {0x7a, 0x01},
+ {0x0c, 0x01}, {0x5f, 0x01}, {0xab, 0x00}, {0xbb, 0x00},
+ /* 0xb0*/
+ {0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+ {0x24, 0x25}, {0xc1, 0x00}, {0xc2, 0x00}, {0x1a, 0x01},
+ {0x5e, 0x01}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+ {0x5d, 0x25}, {0x7b, 0x01}, {0x7c, 0x01}, {0x10, 0x25},
+ /* 0xc0*/
+ {0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+ {0x00, 0x25}, {0x3c, 0x25}, {0x02, 0x01}, {0x03, 0x01},
+ {0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+ {0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0xa4, 0x00},
+ /* 0xd0*/
+ {0x11, 0x01}, {0x10, 0x01}, {0x0e, 0x01}, {0xcb, 0x00},
+ {0x0f, 0x01}, {0x47, 0x01}, {0xcd, 0x00}, {0xce, 0x00},
+ {0x1b, 0x01}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+ {0x84, 0x25}, {0x62, 0x01}, {0x6e, 0x01}, {0x80, 0x25},
+ /* 0xe0*/
+ {0xd3, 0x00}, {0xdf, 0x00}, {0xd4, 0x00}, {0x43, 0x01},
+ {0x44, 0x01}, {0x48, 0x01}, {0x60, 0x01}, {0x61, 0x01},
+ {0x54, 0x01}, {0xda, 0x00}, {0x55, 0x01}, {0x70, 0x01},
+ {0xfd, 0x00}, {0xdd, 0x00}, {0x63, 0x01}, {0xb4, 0x00},
+ /* 0xf0*/
+ {0xad, 0x00}, {0xdd, 0x02}, {0xdb, 0x02}, {0xc7, 0x02},
+ {0xd8, 0x02}, {0xa7, 0x00}, {0xf7, 0x00}, {0xb8, 0x00},
+ {0xb0, 0x00}, {0xa8, 0x00}, {0xd9, 0x02}, {0x71, 0x01},
+ {0x58, 0x01}, {0x59, 0x01}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xff, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0xf5, /* 0xa0-0xa7 */
+ 0xf9, 0x00, 0x00, 0xae, 0xaa, 0xf0, 0x00, 0x00, /* 0xa8-0xaf */
+ 0xf8, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0xf7, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0xb5, 0xb6, 0x00, 0x8e, 0x00, 0x00, 0x80, /* 0xc0-0xc7 */
+ 0x00, 0x90, 0x00, 0xd3, 0x00, 0xd6, 0xd7, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0xe0, 0xe2, 0x00, 0x99, 0x9e, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0xe9, 0x00, 0x9a, 0xed, 0x00, 0xe1, /* 0xd8-0xdf */
+ 0x00, 0xa0, 0x83, 0x00, 0x84, 0x00, 0x00, 0x87, /* 0xe0-0xe7 */
+ 0x00, 0x82, 0x00, 0x89, 0x00, 0xa1, 0x8c, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0xa2, 0x93, 0x00, 0x94, 0xf6, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0xa3, 0x00, 0x81, 0xec, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+ 0x00, 0x00, 0xc6, 0xc7, 0xa4, 0xa5, 0x8f, 0x86, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0xac, 0x9f, 0xd2, 0xd4, /* 0x08-0x0f */
+ 0xd1, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0xa8, 0xa9, 0xb7, 0xd8, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x91, 0x92, 0x00, 0x00, 0x95, 0x96, 0x00, /* 0x38-0x3f */
+ 0x00, 0x9d, 0x88, 0xe3, 0xe4, 0x00, 0x00, 0xd5, /* 0x40-0x47 */
+ 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x8a, 0x8b, 0x00, 0x00, 0xe8, 0xea, 0x00, 0x00, /* 0x50-0x57 */
+ 0xfc, 0xfd, 0x97, 0x98, 0x00, 0x00, 0xb8, 0xad, /* 0x58-0x5f */
+ 0xe6, 0xe7, 0xdd, 0xee, 0x9b, 0x9c, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x85, /* 0x68-0x6f */
+ 0xeb, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x8d, 0xab, 0xbd, 0xbe, 0xa6, 0xa7, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page02[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf3, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0xf4, 0xfa, 0x00, 0xf2, 0x00, 0xf1, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+ 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0xcd, 0xba, 0x00, 0x00, 0xc9, 0x00, 0x00, 0xbb, /* 0x50-0x57 */
+ 0x00, 0x00, 0xc8, 0x00, 0x00, 0xbc, 0x00, 0x00, /* 0x58-0x5f */
+ 0xcc, 0x00, 0x00, 0xb9, 0x00, 0x00, 0xcb, 0x00, /* 0x60-0x67 */
+ 0x00, 0xca, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, page01, page02, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, page25, NULL, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x8a, 0x00, 0x00, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x00, 0x00, 0x00, 0x95, 0x00, 0x97, /* 0x90-0x97 */
+ 0x00, 0x99, 0x9a, 0x9b, 0x00, 0x9d, 0x9e, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0xa4, 0x00, 0xa6, 0x00, /* 0xa0-0xa7 */
+ 0xa8, 0x00, 0xaa, 0x00, 0xac, 0x00, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0x00, 0xbf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0x00, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0x00, 0xd1, 0xd2, 0xd3, 0x00, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0x00, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+ 0xe0, 0x00, 0xe2, 0xe3, 0x00, 0x00, 0xe6, 0x00, /* 0xe0-0xe7 */
+ 0xe8, 0xe9, 0x00, 0xeb, 0x00, 0xed, 0x00, 0xef, /* 0xe8-0xef */
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0xf8, 0xf9, 0xfa, 0x00, 0xfc, 0x00, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "cp852",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_cp852(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_cp852();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/nls/nls_cp855.c b/fs/nls/nls_cp855.c
new file mode 100644
index 000000000..240de8071
--- /dev/null
+++ b/fs/nls/nls_cp855.c
@@ -0,0 +1,339 @@
+/*
+ * linux/fs/nls_cp855.c
+ *
+ * Charset cp855 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0x52, 0x04}, {0x02, 0x04}, {0x53, 0x04}, {0x03, 0x04},
+ {0x51, 0x04}, {0x01, 0x04}, {0x54, 0x04}, {0x04, 0x04},
+ {0x55, 0x04}, {0x05, 0x04}, {0x56, 0x04}, {0x06, 0x04},
+ {0x57, 0x04}, {0x07, 0x04}, {0x58, 0x04}, {0x08, 0x04},
+ /* 0x90*/
+ {0x59, 0x04}, {0x09, 0x04}, {0x5a, 0x04}, {0x0a, 0x04},
+ {0x5b, 0x04}, {0x0b, 0x04}, {0x5c, 0x04}, {0x0c, 0x04},
+ {0x5e, 0x04}, {0x0e, 0x04}, {0x5f, 0x04}, {0x0f, 0x04},
+ {0x4e, 0x04}, {0x2e, 0x04}, {0x4a, 0x04}, {0x2a, 0x04},
+ /* 0xa0*/
+ {0x30, 0x04}, {0x10, 0x04}, {0x31, 0x04}, {0x11, 0x04},
+ {0x46, 0x04}, {0x26, 0x04}, {0x34, 0x04}, {0x14, 0x04},
+ {0x35, 0x04}, {0x15, 0x04}, {0x44, 0x04}, {0x24, 0x04},
+ {0x33, 0x04}, {0x13, 0x04}, {0xab, 0x00}, {0xbb, 0x00},
+ /* 0xb0*/
+ {0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+ {0x24, 0x25}, {0x45, 0x04}, {0x25, 0x04}, {0x38, 0x04},
+ {0x18, 0x04}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+ {0x5d, 0x25}, {0x39, 0x04}, {0x19, 0x04}, {0x10, 0x25},
+ /* 0xc0*/
+ {0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+ {0x00, 0x25}, {0x3c, 0x25}, {0x3a, 0x04}, {0x1a, 0x04},
+ {0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+ {0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0xa4, 0x00},
+ /* 0xd0*/
+ {0x3b, 0x04}, {0x1b, 0x04}, {0x3c, 0x04}, {0x1c, 0x04},
+ {0x3d, 0x04}, {0x1d, 0x04}, {0x3e, 0x04}, {0x1e, 0x04},
+ {0x3f, 0x04}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+ {0x84, 0x25}, {0x1f, 0x04}, {0x4f, 0x04}, {0x80, 0x25},
+ /* 0xe0*/
+ {0x2f, 0x04}, {0x40, 0x04}, {0x20, 0x04}, {0x41, 0x04},
+ {0x21, 0x04}, {0x42, 0x04}, {0x22, 0x04}, {0x43, 0x04},
+ {0x23, 0x04}, {0x36, 0x04}, {0x16, 0x04}, {0x32, 0x04},
+ {0x12, 0x04}, {0x4c, 0x04}, {0x2c, 0x04}, {0x16, 0x21},
+ /* 0xf0*/
+ {0xad, 0x00}, {0x4b, 0x04}, {0x2b, 0x04}, {0x37, 0x04},
+ {0x17, 0x04}, {0x48, 0x04}, {0x28, 0x04}, {0x4d, 0x04},
+ {0x2d, 0x04}, {0x49, 0x04}, {0x29, 0x04}, {0x47, 0x04},
+ {0x27, 0x04}, {0xa7, 0x00}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xff, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0xfd, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0xae, 0x00, 0xf0, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page04[256] = {
+ 0x00, 0x85, 0x81, 0x83, 0x87, 0x89, 0x8b, 0x8d, /* 0x00-0x07 */
+ 0x8f, 0x91, 0x93, 0x95, 0x97, 0x00, 0x99, 0x9b, /* 0x08-0x0f */
+ 0xa1, 0xa3, 0xec, 0xad, 0xa7, 0xa9, 0xea, 0xf4, /* 0x10-0x17 */
+ 0xb8, 0xbe, 0xc7, 0xd1, 0xd3, 0xd5, 0xd7, 0xdd, /* 0x18-0x1f */
+ 0xe2, 0xe4, 0xe6, 0xe8, 0xab, 0xb6, 0xa5, 0xfc, /* 0x20-0x27 */
+ 0xf6, 0xfa, 0x9f, 0xf2, 0xee, 0xf8, 0x9d, 0xe0, /* 0x28-0x2f */
+ 0xa0, 0xa2, 0xeb, 0xac, 0xa6, 0xa8, 0xe9, 0xf3, /* 0x30-0x37 */
+ 0xb7, 0xbd, 0xc6, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, /* 0x38-0x3f */
+ 0xe1, 0xe3, 0xe5, 0xe7, 0xaa, 0xb5, 0xa4, 0xfb, /* 0x40-0x47 */
+ 0xf5, 0xf9, 0x9e, 0xf1, 0xed, 0xf7, 0x9c, 0xde, /* 0x48-0x4f */
+ 0x00, 0x84, 0x80, 0x82, 0x86, 0x88, 0x8a, 0x8c, /* 0x50-0x57 */
+ 0x8e, 0x90, 0x92, 0x94, 0x96, 0x00, 0x98, 0x9a, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page21[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+ 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0xcd, 0xba, 0x00, 0x00, 0xc9, 0x00, 0x00, 0xbb, /* 0x50-0x57 */
+ 0x00, 0x00, 0xc8, 0x00, 0x00, 0xbc, 0x00, 0x00, /* 0x58-0x5f */
+ 0xcc, 0x00, 0x00, 0xb9, 0x00, 0x00, 0xcb, 0x00, /* 0x60-0x67 */
+ 0x00, 0xca, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, NULL, NULL, NULL, page04, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, page21, NULL, NULL, NULL, page25, NULL, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x00, 0x81, 0x00, 0x83, 0x00, 0x85, 0x00, 0x87, /* 0x80-0x87 */
+ 0x00, 0x89, 0x00, 0x8b, 0x00, 0x8d, 0x00, 0x8f, /* 0x88-0x8f */
+ 0x00, 0x91, 0x00, 0x93, 0x00, 0x95, 0x00, 0x97, /* 0x90-0x97 */
+ 0x00, 0x99, 0x00, 0x9b, 0x00, 0x9d, 0x00, 0x9f, /* 0x98-0x9f */
+ 0x00, 0xa1, 0x00, 0xa3, 0x00, 0xa5, 0x00, 0xa7, /* 0xa0-0xa7 */
+ 0x00, 0xa9, 0x00, 0xab, 0x00, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0x00, 0xb6, 0x00, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0x00, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0x00, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0x00, 0xd1, 0x00, 0xd3, 0x00, 0xd5, 0x00, 0xd7, /* 0xd0-0xd7 */
+ 0x00, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0x00, 0xdf, /* 0xd8-0xdf */
+ 0xe0, 0x00, 0xe2, 0x00, 0xe4, 0x00, 0xe6, 0x00, /* 0xe0-0xe7 */
+ 0xe8, 0x00, 0xea, 0x00, 0xec, 0x00, 0xee, 0xef, /* 0xe8-0xef */
+ 0xf0, 0x00, 0xf2, 0x00, 0xf4, 0x00, 0xf6, 0x00, /* 0xf0-0xf7 */
+ 0xf8, 0x00, 0xfa, 0x00, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "cp855",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_cp855(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_cp855();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/nls/nls_cp857.c b/fs/nls/nls_cp857.c
new file mode 100644
index 000000000..c5f0f9367
--- /dev/null
+++ b/fs/nls/nls_cp857.c
@@ -0,0 +1,303 @@
+/*
+ * linux/fs/nls_cp857.c
+ *
+ * Charset cp857 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0xc7, 0x00}, {0xfc, 0x00}, {0xe9, 0x00}, {0xe2, 0x00},
+ {0xe4, 0x00}, {0xe0, 0x00}, {0xe5, 0x00}, {0xe7, 0x00},
+ {0xea, 0x00}, {0xeb, 0x00}, {0xe8, 0x00}, {0xef, 0x00},
+ {0xee, 0x00}, {0x31, 0x01}, {0xc4, 0x00}, {0xc5, 0x00},
+ /* 0x90*/
+ {0xc9, 0x00}, {0xe6, 0x00}, {0xc6, 0x00}, {0xf4, 0x00},
+ {0xf6, 0x00}, {0xf2, 0x00}, {0xfb, 0x00}, {0xf9, 0x00},
+ {0x30, 0x01}, {0xd6, 0x00}, {0xdc, 0x00}, {0xf8, 0x00},
+ {0xa3, 0x00}, {0xd8, 0x00}, {0x5e, 0x01}, {0x5f, 0x01},
+ /* 0xa0*/
+ {0xe1, 0x00}, {0xed, 0x00}, {0xf3, 0x00}, {0xfa, 0x00},
+ {0xf1, 0x00}, {0xd1, 0x00}, {0x1e, 0x01}, {0x1f, 0x01},
+ {0xbf, 0x00}, {0xae, 0x00}, {0xac, 0x00}, {0xbd, 0x00},
+ {0xbc, 0x00}, {0xa1, 0x00}, {0xab, 0x00}, {0xbb, 0x00},
+ /* 0xb0*/
+ {0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+ {0x24, 0x25}, {0xc1, 0x00}, {0xc2, 0x00}, {0xc0, 0x00},
+ {0xa9, 0x00}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+ {0x5d, 0x25}, {0xa2, 0x00}, {0xa5, 0x00}, {0x10, 0x25},
+ /* 0xc0*/
+ {0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+ {0x00, 0x25}, {0x3c, 0x25}, {0xe3, 0x00}, {0xc3, 0x00},
+ {0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+ {0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0xa4, 0x00},
+ /* 0xd0*/
+ {0xba, 0x00}, {0xaa, 0x00}, {0xca, 0x00}, {0xcb, 0x00},
+ {0xc8, 0x00}, {0x00, 0x00}, {0xcd, 0x00}, {0xce, 0x00},
+ {0xcf, 0x00}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+ {0x84, 0x25}, {0xa6, 0x00}, {0xcc, 0x00}, {0x80, 0x25},
+ /* 0xe0*/
+ {0xd3, 0x00}, {0xdf, 0x00}, {0xd4, 0x00}, {0xd2, 0x00},
+ {0xf5, 0x00}, {0xd5, 0x00}, {0xb5, 0x00}, {0x00, 0x00},
+ {0xd7, 0x00}, {0xda, 0x00}, {0xdb, 0x00}, {0xd9, 0x00},
+ {0xec, 0x00}, {0xff, 0x00}, {0xaf, 0x00}, {0xb4, 0x00},
+ /* 0xf0*/
+ {0xad, 0x00}, {0xb1, 0x00}, {0x00, 0x00}, {0xbe, 0x00},
+ {0xb6, 0x00}, {0xa7, 0x00}, {0xf7, 0x00}, {0xb8, 0x00},
+ {0xb0, 0x00}, {0xa8, 0x00}, {0xb7, 0x00}, {0xb9, 0x00},
+ {0xb3, 0x00}, {0xb2, 0x00}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xff, 0xad, 0xbd, 0x9c, 0xcf, 0xbe, 0xdd, 0xf5, /* 0xa0-0xa7 */
+ 0xf9, 0xb8, 0xd1, 0xae, 0xaa, 0xf0, 0xa9, 0xee, /* 0xa8-0xaf */
+ 0xf8, 0xf1, 0xfd, 0xfc, 0xef, 0xe6, 0xf4, 0xfa, /* 0xb0-0xb7 */
+ 0xf7, 0xfb, 0xd0, 0xaf, 0xac, 0xab, 0xf3, 0xa8, /* 0xb8-0xbf */
+ 0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* 0xc0-0xc7 */
+ 0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* 0xc8-0xcf */
+ 0x00, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0xe8, /* 0xd0-0xd7 */
+ 0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0x00, 0x00, 0xe1, /* 0xd8-0xdf */
+ 0x85, 0xa0, 0x83, 0xc6, 0x84, 0x86, 0x91, 0x87, /* 0xe0-0xe7 */
+ 0x8a, 0x82, 0x88, 0x89, 0xec, 0xa1, 0x8c, 0x8b, /* 0xe8-0xef */
+ 0x00, 0xa4, 0x95, 0xa2, 0x93, 0xe4, 0x94, 0xf6, /* 0xf0-0xf7 */
+ 0x9b, 0x97, 0xa3, 0x96, 0x81, 0x00, 0x00, 0xed, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6, 0xa7, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x98, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x9f, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+ 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0xcd, 0xba, 0x00, 0x00, 0xc9, 0x00, 0x00, 0xbb, /* 0x50-0x57 */
+ 0x00, 0x00, 0xc8, 0x00, 0x00, 0xbc, 0x00, 0x00, /* 0x58-0x5f */
+ 0xcc, 0x00, 0x00, 0xb9, 0x00, 0x00, 0xcb, 0x00, /* 0x60-0x67 */
+ 0x00, 0xca, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, page01, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, page25, NULL, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x98, 0x99, 0x9a, 0x00, 0x9c, 0x9d, 0x9e, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0xa6, 0x00, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0x00, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+ 0xe0, 0x00, 0xe2, 0xe3, 0x00, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0x00, 0x00, 0xee, 0xef, /* 0xe8-0xef */
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "cp857",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_cp857(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_cp857();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/nls/nls_cp860.c b/fs/nls/nls_cp860.c
new file mode 100644
index 000000000..97bc9f9e7
--- /dev/null
+++ b/fs/nls/nls_cp860.c
@@ -0,0 +1,411 @@
+/*
+ * linux/fs/nls_cp860.c
+ *
+ * Charset cp860 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0xc7, 0x00}, {0xfc, 0x00}, {0xe9, 0x00}, {0xe2, 0x00},
+ {0xe3, 0x00}, {0xe0, 0x00}, {0xc1, 0x00}, {0xe7, 0x00},
+ {0xea, 0x00}, {0xca, 0x00}, {0xe8, 0x00}, {0xcd, 0x00},
+ {0xd4, 0x00}, {0xec, 0x00}, {0xc3, 0x00}, {0xc2, 0x00},
+ /* 0x90*/
+ {0xc9, 0x00}, {0xc0, 0x00}, {0xc8, 0x00}, {0xf4, 0x00},
+ {0xf5, 0x00}, {0xf2, 0x00}, {0xda, 0x00}, {0xf9, 0x00},
+ {0xcc, 0x00}, {0xd5, 0x00}, {0xdc, 0x00}, {0xa2, 0x00},
+ {0xa3, 0x00}, {0xd9, 0x00}, {0xa7, 0x20}, {0xd3, 0x00},
+ /* 0xa0*/
+ {0xe1, 0x00}, {0xed, 0x00}, {0xf3, 0x00}, {0xfa, 0x00},
+ {0xf1, 0x00}, {0xd1, 0x00}, {0xaa, 0x00}, {0xba, 0x00},
+ {0xbf, 0x00}, {0xd2, 0x00}, {0xac, 0x00}, {0xbd, 0x00},
+ {0xbc, 0x00}, {0xa1, 0x00}, {0xab, 0x00}, {0xbb, 0x00},
+ /* 0xb0*/
+ {0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+ {0x24, 0x25}, {0x61, 0x25}, {0x62, 0x25}, {0x56, 0x25},
+ {0x55, 0x25}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+ {0x5d, 0x25}, {0x5c, 0x25}, {0x5b, 0x25}, {0x10, 0x25},
+ /* 0xc0*/
+ {0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+ {0x00, 0x25}, {0x3c, 0x25}, {0x5e, 0x25}, {0x5f, 0x25},
+ {0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+ {0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0x67, 0x25},
+ /* 0xd0*/
+ {0x68, 0x25}, {0x64, 0x25}, {0x65, 0x25}, {0x59, 0x25},
+ {0x58, 0x25}, {0x52, 0x25}, {0x53, 0x25}, {0x6b, 0x25},
+ {0x6a, 0x25}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+ {0x84, 0x25}, {0x8c, 0x25}, {0x90, 0x25}, {0x80, 0x25},
+ /* 0xe0*/
+ {0xb1, 0x03}, {0xdf, 0x00}, {0x93, 0x03}, {0xc0, 0x03},
+ {0xa3, 0x03}, {0xc3, 0x03}, {0xb5, 0x00}, {0xc4, 0x03},
+ {0xa6, 0x03}, {0x98, 0x03}, {0xa9, 0x03}, {0xb4, 0x03},
+ {0x1e, 0x22}, {0xc6, 0x03}, {0xb5, 0x03}, {0x29, 0x22},
+ /* 0xf0*/
+ {0x61, 0x22}, {0xb1, 0x00}, {0x65, 0x22}, {0x64, 0x22},
+ {0x20, 0x23}, {0x21, 0x23}, {0xf7, 0x00}, {0x48, 0x22},
+ {0xb0, 0x00}, {0x19, 0x22}, {0xb7, 0x00}, {0x1a, 0x22},
+ {0x7f, 0x20}, {0xb2, 0x00}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xff, 0xad, 0x9b, 0x9c, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0xa6, 0xae, 0xaa, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0xf8, 0xf1, 0xfd, 0x00, 0x00, 0xe6, 0x00, 0xfa, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0xa7, 0xaf, 0xac, 0xab, 0x00, 0xa8, /* 0xb8-0xbf */
+ 0x91, 0x86, 0x8f, 0x8e, 0x00, 0x00, 0x00, 0x80, /* 0xc0-0xc7 */
+ 0x92, 0x90, 0x89, 0x00, 0x98, 0x8b, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0xa5, 0xa9, 0x9f, 0x8c, 0x99, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x9d, 0x96, 0x00, 0x9a, 0x00, 0x00, 0xe1, /* 0xd8-0xdf */
+ 0x85, 0xa0, 0x83, 0x84, 0x00, 0x00, 0x00, 0x87, /* 0xe0-0xe7 */
+ 0x8a, 0x82, 0x88, 0x00, 0x8d, 0xa1, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0xa4, 0x95, 0xa2, 0x93, 0x94, 0x00, 0xf6, /* 0xf0-0xf7 */
+ 0x00, 0x97, 0xa3, 0x00, 0x81, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page03[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0xe8, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0xe0, 0x00, 0x00, 0xeb, 0xee, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page22[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0xec, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page23[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+ 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */
+ 0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */
+ 0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */
+ 0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, NULL, NULL, page03, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ page20, NULL, page22, page23, NULL, page25, NULL, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x00, /* 0x80-0x87 */
+ 0x00, 0x89, 0x00, 0x8b, 0x8c, 0x00, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x00, 0x00, 0x00, 0x96, 0x00, /* 0x90-0x97 */
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+ 0x00, 0x00, 0xe2, 0x00, 0xe4, 0x00, 0xe6, 0x00, /* 0xe0-0xe7 */
+ 0xe8, 0xe9, 0xea, 0x00, 0xec, 0x00, 0x00, 0xef, /* 0xe8-0xef */
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0x00, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "cp860",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_cp860(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_cp860();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/nls/nls_cp861.c b/fs/nls/nls_cp861.c
new file mode 100644
index 000000000..1ebbeed33
--- /dev/null
+++ b/fs/nls/nls_cp861.c
@@ -0,0 +1,447 @@
+/*
+ * linux/fs/nls_cp861.c
+ *
+ * Charset cp861 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0xc7, 0x00}, {0xfc, 0x00}, {0xe9, 0x00}, {0xe2, 0x00},
+ {0xe4, 0x00}, {0xe0, 0x00}, {0xe5, 0x00}, {0xe7, 0x00},
+ {0xea, 0x00}, {0xeb, 0x00}, {0xe8, 0x00}, {0xd0, 0x00},
+ {0xf0, 0x00}, {0xde, 0x00}, {0xc4, 0x00}, {0xc5, 0x00},
+ /* 0x90*/
+ {0xc9, 0x00}, {0xe6, 0x00}, {0xc6, 0x00}, {0xf4, 0x00},
+ {0xf6, 0x00}, {0xfe, 0x00}, {0xfb, 0x00}, {0xdd, 0x00},
+ {0xfd, 0x00}, {0xd6, 0x00}, {0xdc, 0x00}, {0xf8, 0x00},
+ {0xa3, 0x00}, {0xd8, 0x00}, {0xa7, 0x20}, {0x92, 0x01},
+ /* 0xa0*/
+ {0xe1, 0x00}, {0xed, 0x00}, {0xf3, 0x00}, {0xfa, 0x00},
+ {0xc1, 0x00}, {0xcd, 0x00}, {0xd3, 0x00}, {0xda, 0x00},
+ {0xbf, 0x00}, {0x10, 0x23}, {0xac, 0x00}, {0xbd, 0x00},
+ {0xbc, 0x00}, {0xa1, 0x00}, {0xab, 0x00}, {0xbb, 0x00},
+ /* 0xb0*/
+ {0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+ {0x24, 0x25}, {0x61, 0x25}, {0x62, 0x25}, {0x56, 0x25},
+ {0x55, 0x25}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+ {0x5d, 0x25}, {0x5c, 0x25}, {0x5b, 0x25}, {0x10, 0x25},
+ /* 0xc0*/
+ {0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+ {0x00, 0x25}, {0x3c, 0x25}, {0x5e, 0x25}, {0x5f, 0x25},
+ {0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+ {0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0x67, 0x25},
+ /* 0xd0*/
+ {0x68, 0x25}, {0x64, 0x25}, {0x65, 0x25}, {0x59, 0x25},
+ {0x58, 0x25}, {0x52, 0x25}, {0x53, 0x25}, {0x6b, 0x25},
+ {0x6a, 0x25}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+ {0x84, 0x25}, {0x8c, 0x25}, {0x90, 0x25}, {0x80, 0x25},
+ /* 0xe0*/
+ {0xb1, 0x03}, {0xdf, 0x00}, {0x93, 0x03}, {0xc0, 0x03},
+ {0xa3, 0x03}, {0xc3, 0x03}, {0xb5, 0x00}, {0xc4, 0x03},
+ {0xa6, 0x03}, {0x98, 0x03}, {0xa9, 0x03}, {0xb4, 0x03},
+ {0x1e, 0x22}, {0xc6, 0x03}, {0xb5, 0x03}, {0x29, 0x22},
+ /* 0xf0*/
+ {0x61, 0x22}, {0xb1, 0x00}, {0x65, 0x22}, {0x64, 0x22},
+ {0x20, 0x23}, {0x21, 0x23}, {0xf7, 0x00}, {0x48, 0x22},
+ {0xb0, 0x00}, {0x19, 0x22}, {0xb7, 0x00}, {0x1a, 0x22},
+ {0x7f, 0x20}, {0xb2, 0x00}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xff, 0xad, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0xae, 0xaa, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0xf8, 0xf1, 0xfd, 0x00, 0x00, 0xe6, 0x00, 0xfa, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0xaf, 0xac, 0xab, 0x00, 0xa8, /* 0xb8-0xbf */
+ 0x00, 0xa4, 0x00, 0x00, 0x8e, 0x8f, 0x92, 0x80, /* 0xc0-0xc7 */
+ 0x00, 0x90, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x8b, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x99, 0x00, /* 0xd0-0xd7 */
+ 0x9d, 0x00, 0xa7, 0x00, 0x9a, 0x97, 0x8d, 0xe1, /* 0xd8-0xdf */
+ 0x85, 0xa0, 0x83, 0x00, 0x84, 0x86, 0x91, 0x87, /* 0xe0-0xe7 */
+ 0x8a, 0x82, 0x88, 0x89, 0x00, 0xa1, 0x00, 0x00, /* 0xe8-0xef */
+ 0x8c, 0x00, 0x00, 0xa2, 0x93, 0x00, 0x94, 0xf6, /* 0xf0-0xf7 */
+ 0x9b, 0x00, 0xa3, 0x96, 0x81, 0x98, 0x95, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page03[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0xe8, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0xe0, 0x00, 0x00, 0xeb, 0xee, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page22[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0xec, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page23[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+ 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */
+ 0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */
+ 0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */
+ 0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, page01, NULL, page03, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ page20, NULL, page22, page23, NULL, page25, NULL, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x8b, 0x00, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x00, 0x00, 0x00, 0x00, 0x97, /* 0x90-0x97 */
+ 0x00, 0x99, 0x9a, 0x00, 0x9c, 0x9d, 0x9e, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+ 0x00, 0x00, 0xe2, 0x00, 0xe4, 0x00, 0xe6, 0x00, /* 0xe0-0xe7 */
+ 0xe8, 0xe9, 0xea, 0x00, 0xec, 0x00, 0x00, 0xef, /* 0xe8-0xef */
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0x00, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "cp861",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_cp861(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_cp861();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/nls/nls_cp862.c b/fs/nls/nls_cp862.c
new file mode 100644
index 000000000..1f50a26dc
--- /dev/null
+++ b/fs/nls/nls_cp862.c
@@ -0,0 +1,483 @@
+/*
+ * linux/fs/nls_cp862.c
+ *
+ * Charset cp862 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0xd0, 0x05}, {0xd1, 0x05}, {0xd2, 0x05}, {0xd3, 0x05},
+ {0xd4, 0x05}, {0xd5, 0x05}, {0xd6, 0x05}, {0xd7, 0x05},
+ {0xd8, 0x05}, {0xd9, 0x05}, {0xda, 0x05}, {0xdb, 0x05},
+ {0xdc, 0x05}, {0xdd, 0x05}, {0xde, 0x05}, {0xdf, 0x05},
+ /* 0x90*/
+ {0xe0, 0x05}, {0xe1, 0x05}, {0xe2, 0x05}, {0xe3, 0x05},
+ {0xe4, 0x05}, {0xe5, 0x05}, {0xe6, 0x05}, {0xe7, 0x05},
+ {0xe8, 0x05}, {0xe9, 0x05}, {0xea, 0x05}, {0xa2, 0x00},
+ {0xa3, 0x00}, {0xa5, 0x00}, {0xa7, 0x20}, {0x92, 0x01},
+ /* 0xa0*/
+ {0xe1, 0x00}, {0xed, 0x00}, {0xf3, 0x00}, {0xfa, 0x00},
+ {0xf1, 0x00}, {0xd1, 0x00}, {0xaa, 0x00}, {0xba, 0x00},
+ {0xbf, 0x00}, {0x10, 0x23}, {0xac, 0x00}, {0xbd, 0x00},
+ {0xbc, 0x00}, {0xa1, 0x00}, {0xab, 0x00}, {0xbb, 0x00},
+ /* 0xb0*/
+ {0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+ {0x24, 0x25}, {0x61, 0x25}, {0x62, 0x25}, {0x56, 0x25},
+ {0x55, 0x25}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+ {0x5d, 0x25}, {0x5c, 0x25}, {0x5b, 0x25}, {0x10, 0x25},
+ /* 0xc0*/
+ {0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+ {0x00, 0x25}, {0x3c, 0x25}, {0x5e, 0x25}, {0x5f, 0x25},
+ {0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+ {0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0x67, 0x25},
+ /* 0xd0*/
+ {0x68, 0x25}, {0x64, 0x25}, {0x65, 0x25}, {0x59, 0x25},
+ {0x58, 0x25}, {0x52, 0x25}, {0x53, 0x25}, {0x6b, 0x25},
+ {0x6a, 0x25}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+ {0x84, 0x25}, {0x8c, 0x25}, {0x90, 0x25}, {0x80, 0x25},
+ /* 0xe0*/
+ {0xb1, 0x03}, {0xdf, 0x00}, {0x93, 0x03}, {0xc0, 0x03},
+ {0xa3, 0x03}, {0xc3, 0x03}, {0xb5, 0x00}, {0xc4, 0x03},
+ {0xa6, 0x03}, {0x98, 0x03}, {0xa9, 0x03}, {0xb4, 0x03},
+ {0x1e, 0x22}, {0xc6, 0x03}, {0xb5, 0x03}, {0x29, 0x22},
+ /* 0xf0*/
+ {0x61, 0x22}, {0xb1, 0x00}, {0x65, 0x22}, {0x64, 0x22},
+ {0x20, 0x23}, {0x21, 0x23}, {0xf7, 0x00}, {0x48, 0x22},
+ {0xb0, 0x00}, {0x19, 0x22}, {0xb7, 0x00}, {0x1a, 0x22},
+ {0x7f, 0x20}, {0xb2, 0x00}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xff, 0xad, 0x9b, 0x9c, 0x00, 0x9d, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0xa6, 0xae, 0xaa, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0xf8, 0xf1, 0xfd, 0x00, 0x00, 0xe6, 0x00, 0xfa, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0xa7, 0xaf, 0xac, 0xab, 0x00, 0xa8, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, /* 0xd8-0xdf */
+ 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0xa4, 0x00, 0xa2, 0x00, 0x00, 0x00, 0xf6, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page03[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0xe8, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0xe0, 0x00, 0x00, 0xeb, 0xee, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page05[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0xd0-0xd7 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0xd8-0xdf */
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0xe0-0xe7 */
+ 0x98, 0x99, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page22[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0xec, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page23[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+ 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */
+ 0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */
+ 0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */
+ 0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, page01, NULL, page03, NULL, page05, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ page20, NULL, page22, page23, NULL, page25, NULL, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+ 0x00, 0x00, 0xe2, 0x00, 0xe4, 0x00, 0xe6, 0x00, /* 0xe0-0xe7 */
+ 0xe8, 0xe9, 0xea, 0x00, 0xec, 0x00, 0x00, 0xef, /* 0xe8-0xef */
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0x00, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "cp862",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_cp862(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_cp862();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/nls/nls_cp863.c b/fs/nls/nls_cp863.c
new file mode 100644
index 000000000..6b6c7a99e
--- /dev/null
+++ b/fs/nls/nls_cp863.c
@@ -0,0 +1,447 @@
+/*
+ * linux/fs/nls_cp863.c
+ *
+ * Charset cp863 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0xc7, 0x00}, {0xfc, 0x00}, {0xe9, 0x00}, {0xe2, 0x00},
+ {0xc2, 0x00}, {0xe0, 0x00}, {0xb6, 0x00}, {0xe7, 0x00},
+ {0xea, 0x00}, {0xeb, 0x00}, {0xe8, 0x00}, {0xef, 0x00},
+ {0xee, 0x00}, {0x17, 0x20}, {0xc0, 0x00}, {0xa7, 0x00},
+ /* 0x90*/
+ {0xc9, 0x00}, {0xc8, 0x00}, {0xca, 0x00}, {0xf4, 0x00},
+ {0xcb, 0x00}, {0xcf, 0x00}, {0xfb, 0x00}, {0xf9, 0x00},
+ {0xa4, 0x00}, {0xd4, 0x00}, {0xdc, 0x00}, {0xa2, 0x00},
+ {0xa3, 0x00}, {0xd9, 0x00}, {0xdb, 0x00}, {0x92, 0x01},
+ /* 0xa0*/
+ {0xa6, 0x00}, {0xb4, 0x00}, {0xf3, 0x00}, {0xfa, 0x00},
+ {0xa8, 0x00}, {0xb8, 0x00}, {0xb3, 0x00}, {0xaf, 0x00},
+ {0xce, 0x00}, {0x10, 0x23}, {0xac, 0x00}, {0xbd, 0x00},
+ {0xbc, 0x00}, {0xbe, 0x00}, {0xab, 0x00}, {0xbb, 0x00},
+ /* 0xb0*/
+ {0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+ {0x24, 0x25}, {0x61, 0x25}, {0x62, 0x25}, {0x56, 0x25},
+ {0x55, 0x25}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+ {0x5d, 0x25}, {0x5c, 0x25}, {0x5b, 0x25}, {0x10, 0x25},
+ /* 0xc0*/
+ {0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+ {0x00, 0x25}, {0x3c, 0x25}, {0x5e, 0x25}, {0x5f, 0x25},
+ {0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+ {0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0x67, 0x25},
+ /* 0xd0*/
+ {0x68, 0x25}, {0x64, 0x25}, {0x65, 0x25}, {0x59, 0x25},
+ {0x58, 0x25}, {0x52, 0x25}, {0x53, 0x25}, {0x6b, 0x25},
+ {0x6a, 0x25}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+ {0x84, 0x25}, {0x8c, 0x25}, {0x90, 0x25}, {0x80, 0x25},
+ /* 0xe0*/
+ {0xb1, 0x03}, {0xdf, 0x00}, {0x93, 0x03}, {0xc0, 0x03},
+ {0xa3, 0x03}, {0xc3, 0x03}, {0xb5, 0x00}, {0xc4, 0x03},
+ {0xa6, 0x03}, {0x98, 0x03}, {0xa9, 0x03}, {0xb4, 0x03},
+ {0x1e, 0x22}, {0xc6, 0x03}, {0xb5, 0x03}, {0x29, 0x22},
+ /* 0xf0*/
+ {0x61, 0x22}, {0xb1, 0x00}, {0x65, 0x22}, {0x64, 0x22},
+ {0x20, 0x23}, {0x21, 0x23}, {0xf7, 0x00}, {0x48, 0x22},
+ {0xb0, 0x00}, {0x19, 0x22}, {0xb7, 0x00}, {0x1a, 0x22},
+ {0x7f, 0x20}, {0xb2, 0x00}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xff, 0x00, 0x9b, 0x9c, 0x98, 0x00, 0xa0, 0x8f, /* 0xa0-0xa7 */
+ 0xa4, 0x00, 0x00, 0xae, 0xaa, 0x00, 0x00, 0xa7, /* 0xa8-0xaf */
+ 0xf8, 0xf1, 0xfd, 0xa6, 0xa1, 0xe6, 0x86, 0xfa, /* 0xb0-0xb7 */
+ 0xa5, 0x00, 0x00, 0xaf, 0xac, 0xab, 0xad, 0x00, /* 0xb8-0xbf */
+ 0x8e, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x80, /* 0xc0-0xc7 */
+ 0x91, 0x90, 0x92, 0x94, 0x00, 0x00, 0xa8, 0x95, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x9d, 0x00, 0x9e, 0x9a, 0x00, 0x00, 0xe1, /* 0xd8-0xdf */
+ 0x85, 0x00, 0x83, 0x00, 0x00, 0x00, 0x00, 0x87, /* 0xe0-0xe7 */
+ 0x8a, 0x82, 0x88, 0x89, 0x00, 0x00, 0x8c, 0x8b, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0xa2, 0x93, 0x00, 0x00, 0xf6, /* 0xf0-0xf7 */
+ 0x00, 0x97, 0xa3, 0x96, 0x81, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page03[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0xe8, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0xe0, 0x00, 0x00, 0xeb, 0xee, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8d, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page22[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0xec, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page23[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+ 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */
+ 0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */
+ 0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */
+ 0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, page01, NULL, page03, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ page20, NULL, page22, page23, NULL, page25, NULL, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x00, 0x00, 0x00, 0x84, 0x00, 0x86, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x00, 0x94, 0x95, 0x00, 0x00, /* 0x90-0x97 */
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x00, /* 0x98-0x9f */
+ 0xa0, 0xa1, 0x00, 0x00, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+ 0x00, 0x00, 0xe2, 0x00, 0xe4, 0x00, 0xe6, 0x00, /* 0xe0-0xe7 */
+ 0xe8, 0xe9, 0xea, 0x00, 0xec, 0x00, 0x00, 0xef, /* 0xe8-0xef */
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0x00, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "cp863",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_cp863(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_cp863();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/nls/nls_cp864.c b/fs/nls/nls_cp864.c
new file mode 100644
index 000000000..e425d5d48
--- /dev/null
+++ b/fs/nls/nls_cp864.c
@@ -0,0 +1,438 @@
+/*
+ * linux/fs/nls_cp864.c
+ *
+ * Charset cp864 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x6a, 0x06}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0xb0, 0x00}, {0xb7, 0x00}, {0x19, 0x22}, {0x1a, 0x22},
+ {0x92, 0x25}, {0x00, 0x25}, {0x02, 0x25}, {0x3c, 0x25},
+ {0x24, 0x25}, {0x2c, 0x25}, {0x1c, 0x25}, {0x34, 0x25},
+ {0x10, 0x25}, {0x0c, 0x25}, {0x14, 0x25}, {0x18, 0x25},
+ /* 0x90*/
+ {0xb2, 0x03}, {0x1e, 0x22}, {0xc6, 0x03}, {0xb1, 0x00},
+ {0xbd, 0x00}, {0xbc, 0x00}, {0x48, 0x22}, {0xab, 0x00},
+ {0xbb, 0x00}, {0xf7, 0xfe}, {0xf8, 0xfe}, {0x00, 0x00},
+ {0x00, 0x00}, {0xfb, 0xfe}, {0xfc, 0xfe}, {0x00, 0x00},
+ /* 0xa0*/
+ {0xa0, 0x00}, {0xad, 0x00}, {0x82, 0xfe}, {0xa3, 0x00},
+ {0xa4, 0x00}, {0x84, 0xfe}, {0x00, 0x00}, {0x00, 0x00},
+ {0x8e, 0xfe}, {0x8f, 0xfe}, {0x95, 0xfe}, {0x99, 0xfe},
+ {0x0c, 0x06}, {0x9d, 0xfe}, {0xa1, 0xfe}, {0xa5, 0xfe},
+ /* 0xb0*/
+ {0x60, 0x06}, {0x61, 0x06}, {0x62, 0x06}, {0x63, 0x06},
+ {0x64, 0x06}, {0x65, 0x06}, {0x66, 0x06}, {0x67, 0x06},
+ {0x68, 0x06}, {0x69, 0x06}, {0xd1, 0xfe}, {0x1b, 0x06},
+ {0xb1, 0xfe}, {0xb5, 0xfe}, {0xb9, 0xfe}, {0x1f, 0x06},
+ /* 0xc0*/
+ {0xa2, 0x00}, {0x80, 0xfe}, {0x81, 0xfe}, {0x83, 0xfe},
+ {0x85, 0xfe}, {0xca, 0xfe}, {0x8b, 0xfe}, {0x8d, 0xfe},
+ {0x91, 0xfe}, {0x93, 0xfe}, {0x97, 0xfe}, {0x9b, 0xfe},
+ {0x9f, 0xfe}, {0xa3, 0xfe}, {0xa7, 0xfe}, {0xa9, 0xfe},
+ /* 0xd0*/
+ {0xab, 0xfe}, {0xad, 0xfe}, {0xaf, 0xfe}, {0xb3, 0xfe},
+ {0xb7, 0xfe}, {0xbb, 0xfe}, {0xbf, 0xfe}, {0xc1, 0xfe},
+ {0xc5, 0xfe}, {0xcb, 0xfe}, {0xcf, 0xfe}, {0xa6, 0x00},
+ {0xac, 0x00}, {0xf7, 0x00}, {0xd7, 0x00}, {0xc9, 0xfe},
+ /* 0xe0*/
+ {0x40, 0x06}, {0xd3, 0xfe}, {0xd7, 0xfe}, {0xdb, 0xfe},
+ {0xdf, 0xfe}, {0xe3, 0xfe}, {0xe7, 0xfe}, {0xeb, 0xfe},
+ {0xed, 0xfe}, {0xef, 0xfe}, {0xf3, 0xfe}, {0xbd, 0xfe},
+ {0xcc, 0xfe}, {0xce, 0xfe}, {0xcd, 0xfe}, {0xe1, 0xfe},
+ /* 0xf0*/
+ {0x7d, 0xfe}, {0x51, 0x06}, {0xe5, 0xfe}, {0xe9, 0xfe},
+ {0xec, 0xfe}, {0xf0, 0xfe}, {0xf2, 0xfe}, {0xd0, 0xfe},
+ {0xd5, 0xfe}, {0xf5, 0xfe}, {0xf6, 0xfe}, {0xdd, 0xfe},
+ {0xd9, 0xfe}, {0xf1, 0xfe}, {0xa0, 0x25}, {0x00, 0x00},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x00, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xa0, 0x00, 0xc0, 0xa3, 0xa4, 0x00, 0xdb, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x97, 0xdc, 0xa1, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x80, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x98, 0x95, 0x94, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page03[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page06[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0xbf, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0xf1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0x60-0x67 */
+ 0xb8, 0xb9, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page22[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x82, 0x83, 0x00, 0x00, 0x00, 0x91, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+ 0x85, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x8c, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x8f, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char pagefe[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0xc1, 0xc2, 0xa2, 0xc3, 0xa5, 0xc4, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc7, 0xa8, 0xa9, /* 0x88-0x8f */
+ 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xaa, 0x00, 0xca, /* 0x90-0x97 */
+ 0x00, 0xab, 0x00, 0xcb, 0x00, 0xad, 0x00, 0xcc, /* 0x98-0x9f */
+ 0x00, 0xae, 0x00, 0xcd, 0x00, 0xaf, 0x00, 0xce, /* 0xa0-0xa7 */
+ 0x00, 0xcf, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xd2, /* 0xa8-0xaf */
+ 0x00, 0xbc, 0x00, 0xd3, 0x00, 0xbd, 0x00, 0xd4, /* 0xb0-0xb7 */
+ 0x00, 0xbe, 0x00, 0xd5, 0x00, 0xeb, 0x00, 0xd6, /* 0xb8-0xbf */
+ 0x00, 0xd7, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0xdf, 0xc5, 0xd9, 0xec, 0xee, 0xed, 0xda, /* 0xc8-0xcf */
+ 0xf7, 0xba, 0x00, 0xe1, 0x00, 0xf8, 0x00, 0xe2, /* 0xd0-0xd7 */
+ 0x00, 0xfc, 0x00, 0xe3, 0x00, 0xfb, 0x00, 0xe4, /* 0xd8-0xdf */
+ 0x00, 0xef, 0x00, 0xe5, 0x00, 0xf2, 0x00, 0xe6, /* 0xe0-0xe7 */
+ 0x00, 0xf3, 0x00, 0xe7, 0xf4, 0xe8, 0x00, 0xe9, /* 0xe8-0xef */
+ 0xf5, 0xfd, 0xf6, 0xea, 0x00, 0xf9, 0xfa, 0x99, /* 0xf0-0xf7 */
+ 0x9a, 0x00, 0x00, 0x9d, 0x9e, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, NULL, NULL, page03, NULL, NULL, page06, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, page22, NULL, NULL, page25, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, pagefe, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "cp864",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_cp864(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_cp864();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/nls/nls_cp865.c b/fs/nls/nls_cp865.c
new file mode 100644
index 000000000..7763b9ddd
--- /dev/null
+++ b/fs/nls/nls_cp865.c
@@ -0,0 +1,447 @@
+/*
+ * linux/fs/nls_cp865.c
+ *
+ * Charset cp865 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0xc7, 0x00}, {0xfc, 0x00}, {0xe9, 0x00}, {0xe2, 0x00},
+ {0xe4, 0x00}, {0xe0, 0x00}, {0xe5, 0x00}, {0xe7, 0x00},
+ {0xea, 0x00}, {0xeb, 0x00}, {0xe8, 0x00}, {0xef, 0x00},
+ {0xee, 0x00}, {0xec, 0x00}, {0xc4, 0x00}, {0xc5, 0x00},
+ /* 0x90*/
+ {0xc9, 0x00}, {0xe6, 0x00}, {0xc6, 0x00}, {0xf4, 0x00},
+ {0xf6, 0x00}, {0xf2, 0x00}, {0xfb, 0x00}, {0xf9, 0x00},
+ {0xff, 0x00}, {0xd6, 0x00}, {0xdc, 0x00}, {0xf8, 0x00},
+ {0xa3, 0x00}, {0xd8, 0x00}, {0xa7, 0x20}, {0x92, 0x01},
+ /* 0xa0*/
+ {0xe1, 0x00}, {0xed, 0x00}, {0xf3, 0x00}, {0xfa, 0x00},
+ {0xf1, 0x00}, {0xd1, 0x00}, {0xaa, 0x00}, {0xba, 0x00},
+ {0xbf, 0x00}, {0x10, 0x23}, {0xac, 0x00}, {0xbd, 0x00},
+ {0xbc, 0x00}, {0xa1, 0x00}, {0xab, 0x00}, {0xa4, 0x00},
+ /* 0xb0*/
+ {0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+ {0x24, 0x25}, {0x61, 0x25}, {0x62, 0x25}, {0x56, 0x25},
+ {0x55, 0x25}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+ {0x5d, 0x25}, {0x5c, 0x25}, {0x5b, 0x25}, {0x10, 0x25},
+ /* 0xc0*/
+ {0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+ {0x00, 0x25}, {0x3c, 0x25}, {0x5e, 0x25}, {0x5f, 0x25},
+ {0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+ {0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0x67, 0x25},
+ /* 0xd0*/
+ {0x68, 0x25}, {0x64, 0x25}, {0x65, 0x25}, {0x59, 0x25},
+ {0x58, 0x25}, {0x52, 0x25}, {0x53, 0x25}, {0x6b, 0x25},
+ {0x6a, 0x25}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+ {0x84, 0x25}, {0x8c, 0x25}, {0x90, 0x25}, {0x80, 0x25},
+ /* 0xe0*/
+ {0xb1, 0x03}, {0xdf, 0x00}, {0x93, 0x03}, {0xc0, 0x03},
+ {0xa3, 0x03}, {0xc3, 0x03}, {0xb5, 0x00}, {0xc4, 0x03},
+ {0xa6, 0x03}, {0x98, 0x03}, {0xa9, 0x03}, {0xb4, 0x03},
+ {0x1e, 0x22}, {0xc6, 0x03}, {0xb5, 0x03}, {0x29, 0x22},
+ /* 0xf0*/
+ {0x61, 0x22}, {0xb1, 0x00}, {0x65, 0x22}, {0x64, 0x22},
+ {0x20, 0x23}, {0x21, 0x23}, {0xf7, 0x00}, {0x48, 0x22},
+ {0xb0, 0x00}, {0x19, 0x22}, {0xb7, 0x00}, {0x1a, 0x22},
+ {0x7f, 0x20}, {0xb2, 0x00}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xff, 0xad, 0x00, 0x9c, 0xaf, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0xa6, 0xae, 0xaa, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0xf8, 0xf1, 0xfd, 0x00, 0x00, 0xe6, 0x00, 0xfa, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0xa7, 0x00, 0xac, 0xab, 0x00, 0xa8, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, 0x92, 0x80, /* 0xc0-0xc7 */
+ 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, /* 0xd0-0xd7 */
+ 0x9d, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0xe1, /* 0xd8-0xdf */
+ 0x85, 0xa0, 0x83, 0x00, 0x84, 0x86, 0x91, 0x87, /* 0xe0-0xe7 */
+ 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b, /* 0xe8-0xef */
+ 0x00, 0xa4, 0x95, 0xa2, 0x93, 0x00, 0x94, 0xf6, /* 0xf0-0xf7 */
+ 0x9b, 0x97, 0xa3, 0x96, 0x81, 0x00, 0x00, 0x98, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page03[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0xe8, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0xe0, 0x00, 0x00, 0xeb, 0xee, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page22[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0xec, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page23[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+ 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */
+ 0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */
+ 0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */
+ 0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, page01, NULL, page03, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ page20, NULL, page22, page23, NULL, page25, NULL, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x99, 0x9a, 0x00, 0x9c, 0x9d, 0x9e, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+ 0x00, 0x00, 0xe2, 0x00, 0xe4, 0x00, 0xe6, 0x00, /* 0xe0-0xe7 */
+ 0xe8, 0xe9, 0xea, 0x00, 0xec, 0x00, 0x00, 0xef, /* 0xe8-0xef */
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0x00, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "cp865",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_cp865(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_cp865();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/nls/nls_cp866.c b/fs/nls/nls_cp866.c
new file mode 100644
index 000000000..985b2dfbb
--- /dev/null
+++ b/fs/nls/nls_cp866.c
@@ -0,0 +1,375 @@
+/*
+ * linux/fs/nls_cp866.c
+ *
+ * Charset cp866 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0x10, 0x04}, {0x11, 0x04}, {0x12, 0x04}, {0x13, 0x04},
+ {0x14, 0x04}, {0x15, 0x04}, {0x16, 0x04}, {0x17, 0x04},
+ {0x18, 0x04}, {0x19, 0x04}, {0x1a, 0x04}, {0x1b, 0x04},
+ {0x1c, 0x04}, {0x1d, 0x04}, {0x1e, 0x04}, {0x1f, 0x04},
+ /* 0x90*/
+ {0x20, 0x04}, {0x21, 0x04}, {0x22, 0x04}, {0x23, 0x04},
+ {0x24, 0x04}, {0x25, 0x04}, {0x26, 0x04}, {0x27, 0x04},
+ {0x28, 0x04}, {0x29, 0x04}, {0x2a, 0x04}, {0x2b, 0x04},
+ {0x2c, 0x04}, {0x2d, 0x04}, {0x2e, 0x04}, {0x2f, 0x04},
+ /* 0xa0*/
+ {0x30, 0x04}, {0x31, 0x04}, {0x32, 0x04}, {0x33, 0x04},
+ {0x34, 0x04}, {0x35, 0x04}, {0x36, 0x04}, {0x37, 0x04},
+ {0x38, 0x04}, {0x39, 0x04}, {0x3a, 0x04}, {0x3b, 0x04},
+ {0x3c, 0x04}, {0x3d, 0x04}, {0x3e, 0x04}, {0x3f, 0x04},
+ /* 0xb0*/
+ {0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+ {0x24, 0x25}, {0x61, 0x25}, {0x62, 0x25}, {0x56, 0x25},
+ {0x55, 0x25}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+ {0x5d, 0x25}, {0x5c, 0x25}, {0x5b, 0x25}, {0x10, 0x25},
+ /* 0xc0*/
+ {0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+ {0x00, 0x25}, {0x3c, 0x25}, {0x5e, 0x25}, {0x5f, 0x25},
+ {0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+ {0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0x67, 0x25},
+ /* 0xd0*/
+ {0x68, 0x25}, {0x64, 0x25}, {0x65, 0x25}, {0x59, 0x25},
+ {0x58, 0x25}, {0x52, 0x25}, {0x53, 0x25}, {0x6b, 0x25},
+ {0x6a, 0x25}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+ {0x84, 0x25}, {0x8c, 0x25}, {0x90, 0x25}, {0x80, 0x25},
+ /* 0xe0*/
+ {0x40, 0x04}, {0x41, 0x04}, {0x42, 0x04}, {0x43, 0x04},
+ {0x44, 0x04}, {0x45, 0x04}, {0x46, 0x04}, {0x47, 0x04},
+ {0x48, 0x04}, {0x49, 0x04}, {0x4a, 0x04}, {0x4b, 0x04},
+ {0x4c, 0x04}, {0x4d, 0x04}, {0x4e, 0x04}, {0x4f, 0x04},
+ /* 0xf0*/
+ {0x01, 0x04}, {0x51, 0x04}, {0x04, 0x04}, {0x54, 0x04},
+ {0x07, 0x04}, {0x57, 0x04}, {0x0e, 0x04}, {0x5e, 0x04},
+ {0xb0, 0x00}, {0x19, 0x22}, {0xb7, 0x00}, {0x1a, 0x22},
+ {0x16, 0x21}, {0xa4, 0x00}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xff, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page04[256] = {
+ 0x00, 0xf0, 0x00, 0x00, 0xf2, 0x00, 0x00, 0xf4, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x00, /* 0x08-0x0f */
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x10-0x17 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x18-0x1f */
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x20-0x27 */
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x28-0x2f */
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0x30-0x37 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0x38-0x3f */
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0x40-0x47 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0x48-0x4f */
+ 0x00, 0xf1, 0x00, 0x00, 0xf3, 0x00, 0x00, 0xf5, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page21[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page22[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+ 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */
+ 0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */
+ 0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */
+ 0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, NULL, NULL, NULL, page04, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, page21, page22, NULL, NULL, page25, NULL, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0xf0, 0x00, 0xf2, 0x00, 0xf4, 0x00, 0xf6, 0x00, /* 0xf0-0xf7 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "cp866",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_cp866(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_cp866();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/nls/nls_cp869.c b/fs/nls/nls_cp869.c
new file mode 100644
index 000000000..1edac6b63
--- /dev/null
+++ b/fs/nls/nls_cp869.c
@@ -0,0 +1,339 @@
+/*
+ * linux/fs/nls_cp869.c
+ *
+ * Charset cp869 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x86, 0x03}, {0x00, 0x00},
+ {0xb7, 0x00}, {0xac, 0x00}, {0xa6, 0x00}, {0x18, 0x20},
+ {0x19, 0x20}, {0x88, 0x03}, {0x15, 0x20}, {0x89, 0x03},
+ /* 0x90*/
+ {0x8a, 0x03}, {0xaa, 0x03}, {0x8c, 0x03}, {0x00, 0x00},
+ {0x00, 0x00}, {0x8e, 0x03}, {0xab, 0x03}, {0xa9, 0x00},
+ {0x8f, 0x03}, {0xb2, 0x00}, {0xb3, 0x00}, {0xac, 0x03},
+ {0xa3, 0x00}, {0xad, 0x03}, {0xae, 0x03}, {0xaf, 0x03},
+ /* 0xa0*/
+ {0xca, 0x03}, {0x90, 0x03}, {0xcc, 0x03}, {0xcd, 0x03},
+ {0x91, 0x03}, {0x92, 0x03}, {0x93, 0x03}, {0x94, 0x03},
+ {0x95, 0x03}, {0x96, 0x03}, {0x97, 0x03}, {0xbd, 0x00},
+ {0x98, 0x03}, {0x99, 0x03}, {0xab, 0x00}, {0xbb, 0x00},
+ /* 0xb0*/
+ {0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x02, 0x25},
+ {0x24, 0x25}, {0x9a, 0x03}, {0x9b, 0x03}, {0x9c, 0x03},
+ {0x9d, 0x03}, {0x63, 0x25}, {0x51, 0x25}, {0x57, 0x25},
+ {0x5d, 0x25}, {0x9e, 0x03}, {0x9f, 0x03}, {0x10, 0x25},
+ /* 0xc0*/
+ {0x14, 0x25}, {0x34, 0x25}, {0x2c, 0x25}, {0x1c, 0x25},
+ {0x00, 0x25}, {0x3c, 0x25}, {0xa0, 0x03}, {0xa1, 0x03},
+ {0x5a, 0x25}, {0x54, 0x25}, {0x69, 0x25}, {0x66, 0x25},
+ {0x60, 0x25}, {0x50, 0x25}, {0x6c, 0x25}, {0xa3, 0x03},
+ /* 0xd0*/
+ {0xa4, 0x03}, {0xa5, 0x03}, {0xa6, 0x03}, {0xa7, 0x03},
+ {0xa8, 0x03}, {0xa9, 0x03}, {0xb1, 0x03}, {0xb2, 0x03},
+ {0xb3, 0x03}, {0x18, 0x25}, {0x0c, 0x25}, {0x88, 0x25},
+ {0x84, 0x25}, {0xb4, 0x03}, {0xb5, 0x03}, {0x80, 0x25},
+ /* 0xe0*/
+ {0xb6, 0x03}, {0xb7, 0x03}, {0xb8, 0x03}, {0xb9, 0x03},
+ {0xba, 0x03}, {0xbb, 0x03}, {0xbc, 0x03}, {0xbd, 0x03},
+ {0xbe, 0x03}, {0xbf, 0x03}, {0xc0, 0x03}, {0xc1, 0x03},
+ {0xc3, 0x03}, {0xc2, 0x03}, {0xc4, 0x03}, {0x84, 0x03},
+ /* 0xf0*/
+ {0xad, 0x00}, {0xb1, 0x00}, {0xc5, 0x03}, {0xc6, 0x03},
+ {0xc7, 0x03}, {0xa7, 0x00}, {0xc8, 0x03}, {0x85, 0x03},
+ {0xb0, 0x00}, {0xa8, 0x00}, {0xc9, 0x03}, {0xcb, 0x03},
+ {0xb0, 0x03}, {0xce, 0x03}, {0xa0, 0x25}, {0xa0, 0x00},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xff, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x8a, 0xf5, /* 0xa0-0xa7 */
+ 0xf9, 0x97, 0x00, 0xae, 0x89, 0xf0, 0x00, 0x00, /* 0xa8-0xaf */
+ 0xf8, 0xf1, 0x99, 0x9a, 0x00, 0x00, 0x00, 0x88, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0xaf, 0x00, 0xab, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page03[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0xef, 0xf7, 0x86, 0x00, /* 0x80-0x87 */
+ 0x8d, 0x8f, 0x90, 0x00, 0x92, 0x00, 0x95, 0x98, /* 0x88-0x8f */
+ 0xa1, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, /* 0x90-0x97 */
+ 0xac, 0xad, 0xb5, 0xb6, 0xb7, 0xb8, 0xbd, 0xbe, /* 0x98-0x9f */
+ 0xc6, 0xc7, 0x00, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, /* 0xa0-0xa7 */
+ 0xd4, 0xd5, 0x91, 0x96, 0x9b, 0x9d, 0x9e, 0x9f, /* 0xa8-0xaf */
+ 0xfc, 0xd6, 0xd7, 0xd8, 0xdd, 0xde, 0xe0, 0xe1, /* 0xb0-0xb7 */
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, /* 0xb8-0xbf */
+ 0xea, 0xeb, 0xed, 0xec, 0xee, 0xf2, 0xf3, 0xf4, /* 0xc0-0xc7 */
+ 0xf6, 0xfa, 0xa0, 0xfb, 0xa2, 0xa3, 0xfd, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, /* 0x10-0x17 */
+ 0x8b, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+ 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0xcd, 0xba, 0x00, 0x00, 0xc9, 0x00, 0x00, 0xbb, /* 0x50-0x57 */
+ 0x00, 0x00, 0xc8, 0x00, 0x00, 0xbc, 0x00, 0x00, /* 0x58-0x5f */
+ 0xcc, 0x00, 0x00, 0xb9, 0x00, 0x00, 0xcb, 0x00, /* 0x60-0x67 */
+ 0x00, 0xca, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, NULL, NULL, page03, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ page20, NULL, NULL, NULL, NULL, page25, NULL, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+ 0x98, 0x99, 0x9a, 0x00, 0x9c, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0xd9, 0xda, 0xdb, 0xdc, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, /* 0xe8-0xef */
+ 0xf0, 0xf1, 0x00, 0x00, 0x00, 0xf5, 0x00, 0xf7, /* 0xf0-0xf7 */
+ 0xf8, 0xf9, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "cp869",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_cp869(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_cp869();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/nls/nls_cp874.c b/fs/nls/nls_cp874.c
new file mode 100644
index 000000000..26350555f
--- /dev/null
+++ b/fs/nls/nls_cp874.c
@@ -0,0 +1,303 @@
+/*
+ * linux/fs/nls_cp874.c
+ *
+ * Charset cp874 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x26, 0x20}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0x90*/
+ {0x00, 0x00}, {0x18, 0x20}, {0x19, 0x20}, {0x1c, 0x20},
+ {0x1d, 0x20}, {0x22, 0x20}, {0x13, 0x20}, {0x14, 0x20},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0xa0*/
+ {0xa0, 0x00}, {0x01, 0x0e}, {0x02, 0x0e}, {0x03, 0x0e},
+ {0x04, 0x0e}, {0x05, 0x0e}, {0x06, 0x0e}, {0x07, 0x0e},
+ {0x08, 0x0e}, {0x09, 0x0e}, {0x0a, 0x0e}, {0x0b, 0x0e},
+ {0x0c, 0x0e}, {0x0d, 0x0e}, {0x0e, 0x0e}, {0x0f, 0x0e},
+ /* 0xb0*/
+ {0x10, 0x0e}, {0x11, 0x0e}, {0x12, 0x0e}, {0x13, 0x0e},
+ {0x14, 0x0e}, {0x15, 0x0e}, {0x16, 0x0e}, {0x17, 0x0e},
+ {0x18, 0x0e}, {0x19, 0x0e}, {0x1a, 0x0e}, {0x1b, 0x0e},
+ {0x1c, 0x0e}, {0x1d, 0x0e}, {0x1e, 0x0e}, {0x1f, 0x0e},
+ /* 0xc0*/
+ {0x20, 0x0e}, {0x21, 0x0e}, {0x22, 0x0e}, {0x23, 0x0e},
+ {0x24, 0x0e}, {0x25, 0x0e}, {0x26, 0x0e}, {0x27, 0x0e},
+ {0x28, 0x0e}, {0x29, 0x0e}, {0x2a, 0x0e}, {0x2b, 0x0e},
+ {0x2c, 0x0e}, {0x2d, 0x0e}, {0x2e, 0x0e}, {0x2f, 0x0e},
+ /* 0xd0*/
+ {0x30, 0x0e}, {0x31, 0x0e}, {0x32, 0x0e}, {0x33, 0x0e},
+ {0x34, 0x0e}, {0x35, 0x0e}, {0x36, 0x0e}, {0x37, 0x0e},
+ {0x38, 0x0e}, {0x39, 0x0e}, {0x3a, 0x0e}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x3f, 0x0e},
+ /* 0xe0*/
+ {0x40, 0x0e}, {0x41, 0x0e}, {0x42, 0x0e}, {0x43, 0x0e},
+ {0x44, 0x0e}, {0x45, 0x0e}, {0x46, 0x0e}, {0x47, 0x0e},
+ {0x48, 0x0e}, {0x49, 0x0e}, {0x4a, 0x0e}, {0x4b, 0x0e},
+ {0x4c, 0x0e}, {0x4d, 0x0e}, {0x4e, 0x0e}, {0x4f, 0x0e},
+ /* 0xf0*/
+ {0x50, 0x0e}, {0x51, 0x0e}, {0x52, 0x0e}, {0x53, 0x0e},
+ {0x54, 0x0e}, {0x55, 0x0e}, {0x56, 0x0e}, {0x57, 0x0e},
+ {0x58, 0x0e}, {0x59, 0x0e}, {0x5a, 0x0e}, {0x5b, 0x0e},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page0e[256] = {
+ 0x00, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0x00-0x07 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0x08-0x0f */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0x10-0x17 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0x18-0x1f */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0x20-0x27 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0x28-0x2f */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0x30-0x37 */
+ 0xd8, 0xd9, 0xda, 0x00, 0x00, 0x00, 0x00, 0xdf, /* 0x38-0x3f */
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0x40-0x47 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0x48-0x4f */
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0x50-0x57 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x96, 0x97, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x91, 0x92, 0x00, 0x00, 0x93, 0x94, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x85, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, page0e, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ page20, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "cp874",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_cp874(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_cp874();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/nls/nls_iso8859-1.c b/fs/nls/nls_iso8859-1.c
new file mode 100644
index 000000000..3b32a706e
--- /dev/null
+++ b/fs/nls/nls_iso8859-1.c
@@ -0,0 +1,227 @@
+/*
+ * linux/fs/nls_iso8859-1.c
+ *
+ * Charset iso8859-1 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0x90*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0xa0*/
+ {0xa0, 0x00}, {0xa1, 0x00}, {0xa2, 0x00}, {0xa3, 0x00},
+ {0xa4, 0x00}, {0xa5, 0x00}, {0xa6, 0x00}, {0xa7, 0x00},
+ {0xa8, 0x00}, {0xa9, 0x00}, {0xaa, 0x00}, {0xab, 0x00},
+ {0xac, 0x00}, {0xad, 0x00}, {0xae, 0x00}, {0xaf, 0x00},
+ /* 0xb0*/
+ {0xb0, 0x00}, {0xb1, 0x00}, {0xb2, 0x00}, {0xb3, 0x00},
+ {0xb4, 0x00}, {0xb5, 0x00}, {0xb6, 0x00}, {0xb7, 0x00},
+ {0xb8, 0x00}, {0xb9, 0x00}, {0xba, 0x00}, {0xbb, 0x00},
+ {0xbc, 0x00}, {0xbd, 0x00}, {0xbe, 0x00}, {0xbf, 0x00},
+ /* 0xc0*/
+ {0xc0, 0x00}, {0xc1, 0x00}, {0xc2, 0x00}, {0xc3, 0x00},
+ {0xc4, 0x00}, {0xc5, 0x00}, {0xc6, 0x00}, {0xc7, 0x00},
+ {0xc8, 0x00}, {0xc9, 0x00}, {0xca, 0x00}, {0xcb, 0x00},
+ {0xcc, 0x00}, {0xcd, 0x00}, {0xce, 0x00}, {0xcf, 0x00},
+ /* 0xd0*/
+ {0xd0, 0x00}, {0xd1, 0x00}, {0xd2, 0x00}, {0xd3, 0x00},
+ {0xd4, 0x00}, {0xd5, 0x00}, {0xd6, 0x00}, {0xd7, 0x00},
+ {0xd8, 0x00}, {0xd9, 0x00}, {0xda, 0x00}, {0xdb, 0x00},
+ {0xdc, 0x00}, {0xdd, 0x00}, {0xde, 0x00}, {0xdf, 0x00},
+ /* 0xe0*/
+ {0xe0, 0x00}, {0xe1, 0x00}, {0xe2, 0x00}, {0xe3, 0x00},
+ {0xe4, 0x00}, {0xe5, 0x00}, {0xe6, 0x00}, {0xe7, 0x00},
+ {0xe8, 0x00}, {0xe9, 0x00}, {0xea, 0x00}, {0xeb, 0x00},
+ {0xec, 0x00}, {0xed, 0x00}, {0xee, 0x00}, {0xef, 0x00},
+ /* 0xf0*/
+ {0xf0, 0x00}, {0xf1, 0x00}, {0xf2, 0x00}, {0xf3, 0x00},
+ {0xf4, 0x00}, {0xf5, 0x00}, {0xf6, 0x00}, {0xf7, 0x00},
+ {0xf8, 0x00}, {0xf9, 0x00}, {0xfa, 0x00}, {0xfb, 0x00},
+ {0xfc, 0x00}, {0xfd, 0x00}, {0xfe, 0x00}, {0xff, 0x00},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "iso8859-1",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_iso8859_1(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_iso8859_1();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/nls/nls_iso8859-2.c b/fs/nls/nls_iso8859-2.c
new file mode 100644
index 000000000..b21961b69
--- /dev/null
+++ b/fs/nls/nls_iso8859-2.c
@@ -0,0 +1,299 @@
+/*
+ * linux/fs/nls_iso8859-2.c
+ *
+ * Charset iso8859-2 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0x90*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0xa0*/
+ {0xa0, 0x00}, {0x04, 0x01}, {0xd8, 0x02}, {0x41, 0x01},
+ {0xa4, 0x00}, {0x3d, 0x01}, {0x5a, 0x01}, {0xa7, 0x00},
+ {0xa8, 0x00}, {0x60, 0x01}, {0x5e, 0x01}, {0x64, 0x01},
+ {0x79, 0x01}, {0xad, 0x00}, {0x7d, 0x01}, {0x7b, 0x01},
+ /* 0xb0*/
+ {0xb0, 0x00}, {0x05, 0x01}, {0xdb, 0x02}, {0x42, 0x01},
+ {0xb4, 0x00}, {0x3e, 0x01}, {0x5b, 0x01}, {0xc7, 0x02},
+ {0xb8, 0x00}, {0x61, 0x01}, {0x5f, 0x01}, {0x65, 0x01},
+ {0x7a, 0x01}, {0xdd, 0x02}, {0x7e, 0x01}, {0x7c, 0x01},
+ /* 0xc0*/
+ {0x54, 0x01}, {0xc1, 0x00}, {0xc2, 0x00}, {0x02, 0x01},
+ {0xc4, 0x00}, {0x39, 0x01}, {0x06, 0x01}, {0xc7, 0x00},
+ {0x0c, 0x01}, {0xc9, 0x00}, {0x18, 0x01}, {0xcb, 0x00},
+ {0x1a, 0x01}, {0xcd, 0x00}, {0xce, 0x00}, {0x0e, 0x01},
+ /* 0xd0*/
+ {0x10, 0x01}, {0x43, 0x01}, {0x47, 0x01}, {0xd3, 0x00},
+ {0xd4, 0x00}, {0x50, 0x01}, {0xd6, 0x00}, {0xd7, 0x00},
+ {0x58, 0x01}, {0x6e, 0x01}, {0xda, 0x00}, {0x70, 0x01},
+ {0xdc, 0x00}, {0xdd, 0x00}, {0x62, 0x01}, {0xdf, 0x00},
+ /* 0xe0*/
+ {0x55, 0x01}, {0xe1, 0x00}, {0xe2, 0x00}, {0x03, 0x01},
+ {0xe4, 0x00}, {0x3a, 0x01}, {0x07, 0x01}, {0xe7, 0x00},
+ {0x0d, 0x01}, {0xe9, 0x00}, {0x19, 0x01}, {0xeb, 0x00},
+ {0x1b, 0x01}, {0xed, 0x00}, {0xee, 0x00}, {0x0f, 0x01},
+ /* 0xf0*/
+ {0x11, 0x01}, {0x44, 0x01}, {0x48, 0x01}, {0xf3, 0x00},
+ {0xf4, 0x00}, {0x51, 0x01}, {0xf6, 0x00}, {0xf7, 0x00},
+ {0x59, 0x01}, {0x6f, 0x01}, {0xfa, 0x00}, {0x71, 0x01},
+ {0xfc, 0x00}, {0xfd, 0x00}, {0x63, 0x01}, {0xd9, 0x02},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, /* 0xa8-0xaf */
+ 0xb0, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0xc1, 0xc2, 0x00, 0xc4, 0x00, 0x00, 0xc7, /* 0xc0-0xc7 */
+ 0x00, 0xc9, 0x00, 0xcb, 0x00, 0xcd, 0xce, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0xd3, 0xd4, 0x00, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0xda, 0x00, 0xdc, 0xdd, 0x00, 0xdf, /* 0xd8-0xdf */
+ 0x00, 0xe1, 0xe2, 0x00, 0xe4, 0x00, 0x00, 0xe7, /* 0xe0-0xe7 */
+ 0x00, 0xe9, 0x00, 0xeb, 0x00, 0xed, 0xee, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0xf3, 0xf4, 0x00, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0xfa, 0x00, 0xfc, 0xfd, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+ 0x00, 0x00, 0xc3, 0xe3, 0xa1, 0xb1, 0xc6, 0xe6, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0xc8, 0xe8, 0xcf, 0xef, /* 0x08-0x0f */
+ 0xd0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0xca, 0xea, 0xcc, 0xec, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0xc5, 0xe5, 0x00, 0x00, 0xa5, 0xb5, 0x00, /* 0x38-0x3f */
+ 0x00, 0xa3, 0xb3, 0xd1, 0xf1, 0x00, 0x00, 0xd2, /* 0x40-0x47 */
+ 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0xd5, 0xf5, 0x00, 0x00, 0xc0, 0xe0, 0x00, 0x00, /* 0x50-0x57 */
+ 0xd8, 0xf8, 0xa6, 0xb6, 0x00, 0x00, 0xaa, 0xba, /* 0x58-0x5f */
+ 0xa9, 0xb9, 0xde, 0xfe, 0xab, 0xbb, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0xf9, /* 0x68-0x6f */
+ 0xdb, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0xac, 0xbc, 0xaf, 0xbf, 0xae, 0xbe, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page02[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0xa2, 0xff, 0x00, 0xb2, 0x00, 0xbd, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, page01, page02, NULL, NULL, NULL, NULL, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0x00, 0xb2, 0x00, 0xb4, 0x00, 0x00, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "iso8859-2",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_iso8859_2(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_iso8859_2();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/nls/nls_iso8859-3.c b/fs/nls/nls_iso8859-3.c
new file mode 100644
index 000000000..d5d7f7f27
--- /dev/null
+++ b/fs/nls/nls_iso8859-3.c
@@ -0,0 +1,299 @@
+/*
+ * linux/fs/nls_iso8859-3.c
+ *
+ * Charset iso8859-3 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0x90*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0xa0*/
+ {0xa0, 0x00}, {0x26, 0x01}, {0xd8, 0x02}, {0xa3, 0x00},
+ {0xa4, 0x00}, {0x00, 0x00}, {0x24, 0x01}, {0xa7, 0x00},
+ {0xa8, 0x00}, {0x30, 0x01}, {0x5e, 0x01}, {0x1e, 0x01},
+ {0x34, 0x01}, {0xad, 0x00}, {0x00, 0x00}, {0x7b, 0x01},
+ /* 0xb0*/
+ {0xb0, 0x00}, {0x27, 0x01}, {0xb2, 0x00}, {0xb3, 0x00},
+ {0xb4, 0x00}, {0xb5, 0x00}, {0x25, 0x01}, {0xb7, 0x00},
+ {0xb8, 0x00}, {0x31, 0x01}, {0x5f, 0x01}, {0x1f, 0x01},
+ {0x35, 0x01}, {0xbd, 0x00}, {0x00, 0x00}, {0x7c, 0x01},
+ /* 0xc0*/
+ {0xc0, 0x00}, {0xc1, 0x00}, {0xc2, 0x00}, {0x00, 0x00},
+ {0xc4, 0x00}, {0x0a, 0x01}, {0x08, 0x01}, {0xc7, 0x00},
+ {0xc8, 0x00}, {0xc9, 0x00}, {0xca, 0x00}, {0xcb, 0x00},
+ {0xcc, 0x00}, {0xcd, 0x00}, {0xce, 0x00}, {0xcf, 0x00},
+ /* 0xd0*/
+ {0x00, 0x00}, {0xd1, 0x00}, {0xd2, 0x00}, {0xd3, 0x00},
+ {0xd4, 0x00}, {0x20, 0x01}, {0xd6, 0x00}, {0xd7, 0x00},
+ {0x1c, 0x01}, {0xd9, 0x00}, {0xda, 0x00}, {0xdb, 0x00},
+ {0xdc, 0x00}, {0x6c, 0x01}, {0x5c, 0x01}, {0xdf, 0x00},
+ /* 0xe0*/
+ {0xe0, 0x00}, {0xe1, 0x00}, {0xe2, 0x00}, {0x00, 0x00},
+ {0xe4, 0x00}, {0x0b, 0x01}, {0x09, 0x01}, {0xe7, 0x00},
+ {0xe8, 0x00}, {0xe9, 0x00}, {0xea, 0x00}, {0xeb, 0x00},
+ {0xec, 0x00}, {0xed, 0x00}, {0xee, 0x00}, {0xef, 0x00},
+ /* 0xf0*/
+ {0x00, 0x00}, {0xf1, 0x00}, {0xf2, 0x00}, {0xf3, 0x00},
+ {0xf4, 0x00}, {0x21, 0x01}, {0xf6, 0x00}, {0xf7, 0x00},
+ {0x1d, 0x01}, {0xf9, 0x00}, {0xfa, 0x00}, {0xfb, 0x00},
+ {0xfc, 0x00}, {0x6d, 0x01}, {0x5d, 0x01}, {0xd9, 0x02},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xa0, 0x00, 0x00, 0xa3, 0xa4, 0x00, 0x00, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, /* 0xa8-0xaf */
+ 0xb0, 0x00, 0xb2, 0xb3, 0xb4, 0xb5, 0x00, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0x00, 0xc4, 0x00, 0x00, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0x00, 0xd1, 0xd2, 0xd3, 0xd4, 0x00, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0x00, 0xd9, 0xda, 0xdb, 0xdc, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */
+ 0xe0, 0xe1, 0xe2, 0x00, 0xe4, 0x00, 0x00, 0xe7, /* 0xe0-0xe7 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+ 0x00, 0xf1, 0xf2, 0xf3, 0xf4, 0x00, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0x00, 0xf9, 0xfa, 0xfb, 0xfc, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0xc6, 0xe6, 0xc5, 0xe5, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0xd8, 0xf8, 0xab, 0xbb, /* 0x18-0x1f */
+ 0xd5, 0xf5, 0x00, 0x00, 0xa6, 0xb6, 0xa1, 0xb1, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0xa9, 0xb9, 0x00, 0x00, 0xac, 0xbc, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0xde, 0xfe, 0xaa, 0xba, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0xdd, 0xfd, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0xaf, 0xbf, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page02[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0xa2, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, page01, page02, NULL, NULL, NULL, NULL, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0x00, 0xb2, 0xb3, 0xb4, 0xb5, 0x00, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0x00, 0x00, 0x00, 0x00, 0xbd, 0xbe, 0x00, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0xe3, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "iso8859-3",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_iso8859_3(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_iso8859_3();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/nls/nls_iso8859-4.c b/fs/nls/nls_iso8859-4.c
new file mode 100644
index 000000000..f03aaaa2c
--- /dev/null
+++ b/fs/nls/nls_iso8859-4.c
@@ -0,0 +1,299 @@
+/*
+ * linux/fs/nls_iso8859-4.c
+ *
+ * Charset iso8859-4 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0x90*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0xa0*/
+ {0xa0, 0x00}, {0x04, 0x01}, {0x38, 0x01}, {0x56, 0x01},
+ {0xa4, 0x00}, {0x28, 0x01}, {0x3b, 0x01}, {0xa7, 0x00},
+ {0xa8, 0x00}, {0x60, 0x01}, {0x12, 0x01}, {0x22, 0x01},
+ {0x66, 0x01}, {0xad, 0x00}, {0x7d, 0x01}, {0xaf, 0x00},
+ /* 0xb0*/
+ {0xb0, 0x00}, {0x05, 0x01}, {0xdb, 0x02}, {0x57, 0x01},
+ {0xb4, 0x00}, {0x29, 0x01}, {0x3c, 0x01}, {0xc7, 0x02},
+ {0xb8, 0x00}, {0x61, 0x01}, {0x13, 0x01}, {0x23, 0x01},
+ {0x67, 0x01}, {0x4a, 0x01}, {0x7e, 0x01}, {0x4b, 0x01},
+ /* 0xc0*/
+ {0x00, 0x01}, {0xc1, 0x00}, {0xc2, 0x00}, {0xc3, 0x00},
+ {0xc4, 0x00}, {0xc5, 0x00}, {0xc6, 0x00}, {0x2e, 0x01},
+ {0x0c, 0x01}, {0xc9, 0x00}, {0x18, 0x01}, {0xcb, 0x00},
+ {0x16, 0x01}, {0xcd, 0x00}, {0xce, 0x00}, {0x2a, 0x01},
+ /* 0xd0*/
+ {0x10, 0x01}, {0x45, 0x01}, {0x4c, 0x01}, {0x36, 0x01},
+ {0xd4, 0x00}, {0xd5, 0x00}, {0xd6, 0x00}, {0xd7, 0x00},
+ {0xd8, 0x00}, {0x72, 0x01}, {0xda, 0x00}, {0xdb, 0x00},
+ {0xdc, 0x00}, {0x68, 0x01}, {0x6a, 0x01}, {0xdf, 0x00},
+ /* 0xe0*/
+ {0x01, 0x01}, {0xe1, 0x00}, {0xe2, 0x00}, {0xe3, 0x00},
+ {0xe4, 0x00}, {0xe5, 0x00}, {0xe6, 0x00}, {0x2f, 0x01},
+ {0x0d, 0x01}, {0xe9, 0x00}, {0x19, 0x01}, {0xeb, 0x00},
+ {0x17, 0x01}, {0xed, 0x00}, {0xee, 0x00}, {0x2b, 0x01},
+ /* 0xf0*/
+ {0x11, 0x01}, {0x46, 0x01}, {0x4d, 0x01}, {0x37, 0x01},
+ {0xf4, 0x00}, {0xf5, 0x00}, {0xf6, 0x00}, {0xf7, 0x00},
+ {0xf8, 0x00}, {0x73, 0x01}, {0xfa, 0x00}, {0xfb, 0x00},
+ {0xfc, 0x00}, {0x69, 0x01}, {0x6b, 0x01}, {0xd9, 0x02},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0xc9, 0x00, 0xcb, 0x00, 0xcd, 0xce, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0x00, 0xda, 0xdb, 0xdc, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */
+ 0x00, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0xe9, 0x00, 0xeb, 0x00, 0xed, 0xee, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0xf8, 0x00, 0xfa, 0xfb, 0xfc, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+ 0xc0, 0xe0, 0x00, 0x00, 0xa1, 0xb1, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0xc8, 0xe8, 0x00, 0x00, /* 0x08-0x0f */
+ 0xd0, 0xf0, 0xaa, 0xba, 0x00, 0x00, 0xcc, 0xec, /* 0x10-0x17 */
+ 0xca, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0xab, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0xa5, 0xb5, 0xcf, 0xef, 0x00, 0x00, 0xc7, 0xe7, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd3, 0xf3, /* 0x30-0x37 */
+ 0xa2, 0x00, 0x00, 0xa6, 0xb6, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xf1, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0xbd, 0xbf, 0xd2, 0xf2, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, 0xb3, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0xa9, 0xb9, 0x00, 0x00, 0x00, 0x00, 0xac, 0xbc, /* 0x60-0x67 */
+ 0xdd, 0xfd, 0xde, 0xfe, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0xd9, 0xf9, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0xbe, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page02[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0xff, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, page01, page02, NULL, NULL, NULL, NULL, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+ 0xa0, 0xa1, 0x00, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0x00, 0xb2, 0x00, 0xb4, 0x00, 0x00, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "iso8859-4",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_iso8859_4(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_iso8859_4();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/nls/nls_iso8859-5.c b/fs/nls/nls_iso8859-5.c
new file mode 100644
index 000000000..94bece0bb
--- /dev/null
+++ b/fs/nls/nls_iso8859-5.c
@@ -0,0 +1,303 @@
+/*
+ * linux/fs/nls_iso8859-5.c
+ *
+ * Charset iso8859-5 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0x90*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0xa0*/
+ {0xa0, 0x00}, {0x01, 0x04}, {0x02, 0x04}, {0x03, 0x04},
+ {0x04, 0x04}, {0x05, 0x04}, {0x06, 0x04}, {0x07, 0x04},
+ {0x08, 0x04}, {0x09, 0x04}, {0x0a, 0x04}, {0x0b, 0x04},
+ {0x0c, 0x04}, {0xad, 0x00}, {0x0e, 0x04}, {0x0f, 0x04},
+ /* 0xb0*/
+ {0x10, 0x04}, {0x11, 0x04}, {0x12, 0x04}, {0x13, 0x04},
+ {0x14, 0x04}, {0x15, 0x04}, {0x16, 0x04}, {0x17, 0x04},
+ {0x18, 0x04}, {0x19, 0x04}, {0x1a, 0x04}, {0x1b, 0x04},
+ {0x1c, 0x04}, {0x1d, 0x04}, {0x1e, 0x04}, {0x1f, 0x04},
+ /* 0xc0*/
+ {0x20, 0x04}, {0x21, 0x04}, {0x22, 0x04}, {0x23, 0x04},
+ {0x24, 0x04}, {0x25, 0x04}, {0x26, 0x04}, {0x27, 0x04},
+ {0x28, 0x04}, {0x29, 0x04}, {0x2a, 0x04}, {0x2b, 0x04},
+ {0x2c, 0x04}, {0x2d, 0x04}, {0x2e, 0x04}, {0x2f, 0x04},
+ /* 0xd0*/
+ {0x30, 0x04}, {0x31, 0x04}, {0x32, 0x04}, {0x33, 0x04},
+ {0x34, 0x04}, {0x35, 0x04}, {0x36, 0x04}, {0x37, 0x04},
+ {0x38, 0x04}, {0x39, 0x04}, {0x3a, 0x04}, {0x3b, 0x04},
+ {0x3c, 0x04}, {0x3d, 0x04}, {0x3e, 0x04}, {0x3f, 0x04},
+ /* 0xe0*/
+ {0x40, 0x04}, {0x41, 0x04}, {0x42, 0x04}, {0x43, 0x04},
+ {0x44, 0x04}, {0x45, 0x04}, {0x46, 0x04}, {0x47, 0x04},
+ {0x48, 0x04}, {0x49, 0x04}, {0x4a, 0x04}, {0x4b, 0x04},
+ {0x4c, 0x04}, {0x4d, 0x04}, {0x4e, 0x04}, {0x4f, 0x04},
+ /* 0xf0*/
+ {0x16, 0x21}, {0x51, 0x04}, {0x52, 0x04}, {0x53, 0x04},
+ {0x54, 0x04}, {0x55, 0x04}, {0x56, 0x04}, {0x57, 0x04},
+ {0x58, 0x04}, {0x59, 0x04}, {0x5a, 0x04}, {0x5b, 0x04},
+ {0x5c, 0x04}, {0xa7, 0x00}, {0x5e, 0x04}, {0x5f, 0x04},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page04[256] = {
+ 0x00, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0x00-0x07 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0x00, 0xae, 0xaf, /* 0x08-0x0f */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0x10-0x17 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0x18-0x1f */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0x20-0x27 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0x28-0x2f */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0x30-0x37 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0x38-0x3f */
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0x40-0x47 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0x48-0x4f */
+ 0x00, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0x50-0x57 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0x00, 0xfe, 0xff, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page21[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, NULL, NULL, NULL, page04, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, page21, NULL, NULL, NULL, NULL, NULL, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "iso8859-5",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_iso8859_5(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_iso8859_5();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/nls/nls_iso8859-6.c b/fs/nls/nls_iso8859-6.c
new file mode 100644
index 000000000..050aee92d
--- /dev/null
+++ b/fs/nls/nls_iso8859-6.c
@@ -0,0 +1,263 @@
+/*
+ * linux/fs/nls_iso8859-6.c
+ *
+ * Charset iso8859-6 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x60, 0x06}, {0x61, 0x06}, {0x62, 0x06}, {0x63, 0x06},
+ {0x64, 0x06}, {0x65, 0x06}, {0x66, 0x06}, {0x67, 0x06},
+ {0x68, 0x06}, {0x69, 0x06}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0x90*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0xa0*/
+ {0xa0, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0xa4, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x0c, 0x06}, {0xad, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0xb0*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x1b, 0x06},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x1f, 0x06},
+ /* 0xc0*/
+ {0x00, 0x00}, {0x21, 0x06}, {0x22, 0x06}, {0x23, 0x06},
+ {0x24, 0x06}, {0x25, 0x06}, {0x26, 0x06}, {0x27, 0x06},
+ {0x28, 0x06}, {0x29, 0x06}, {0x2a, 0x06}, {0x2b, 0x06},
+ {0x2c, 0x06}, {0x2d, 0x06}, {0x2e, 0x06}, {0x2f, 0x06},
+ /* 0xd0*/
+ {0x30, 0x06}, {0x31, 0x06}, {0x32, 0x06}, {0x33, 0x06},
+ {0x34, 0x06}, {0x35, 0x06}, {0x36, 0x06}, {0x37, 0x06},
+ {0x38, 0x06}, {0x39, 0x06}, {0x3a, 0x06}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0xe0*/
+ {0x40, 0x06}, {0x41, 0x06}, {0x42, 0x06}, {0x43, 0x06},
+ {0x44, 0x06}, {0x45, 0x06}, {0x46, 0x06}, {0x47, 0x06},
+ {0x48, 0x06}, {0x49, 0x06}, {0x4a, 0x06}, {0x4b, 0x06},
+ {0x4c, 0x06}, {0x4d, 0x06}, {0x4e, 0x06}, {0x4f, 0x06},
+ /* 0xf0*/
+ {0x50, 0x06}, {0x51, 0x06}, {0x52, 0x06}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page06[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0xbf, /* 0x18-0x1f */
+ 0x00, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0x20-0x27 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0x28-0x2f */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0x30-0x37 */
+ 0xd8, 0xd9, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0x40-0x47 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0x48-0x4f */
+ 0xf0, 0xf1, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x60-0x67 */
+ 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, NULL, NULL, NULL, NULL, NULL, page06, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "iso8859-6",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_iso8859_6(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_iso8859_6();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/nls/nls_iso8859-7.c b/fs/nls/nls_iso8859-7.c
new file mode 100644
index 000000000..3790378ac
--- /dev/null
+++ b/fs/nls/nls_iso8859-7.c
@@ -0,0 +1,339 @@
+/*
+ * linux/fs/nls_iso8859-7.c
+ *
+ * Charset iso8859-7 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0x90*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0xa0*/
+ {0xa0, 0x00}, {0xbd, 0x02}, {0xbc, 0x02}, {0xa3, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0xa6, 0x00}, {0xa7, 0x00},
+ {0xa8, 0x00}, {0xa9, 0x00}, {0x00, 0x00}, {0xab, 0x00},
+ {0xac, 0x00}, {0xad, 0x00}, {0x00, 0x00}, {0x15, 0x20},
+ /* 0xb0*/
+ {0xb0, 0x00}, {0xb1, 0x00}, {0xb2, 0x00}, {0xb3, 0x00},
+ {0x84, 0x03}, {0x85, 0x03}, {0x86, 0x03}, {0xb7, 0x00},
+ {0x88, 0x03}, {0x89, 0x03}, {0x8a, 0x03}, {0xbb, 0x00},
+ {0x8c, 0x03}, {0xbd, 0x00}, {0x8e, 0x03}, {0x8f, 0x03},
+ /* 0xc0*/
+ {0x90, 0x03}, {0x91, 0x03}, {0x92, 0x03}, {0x93, 0x03},
+ {0x94, 0x03}, {0x95, 0x03}, {0x96, 0x03}, {0x97, 0x03},
+ {0x98, 0x03}, {0x99, 0x03}, {0x9a, 0x03}, {0x9b, 0x03},
+ {0x9c, 0x03}, {0x9d, 0x03}, {0x9e, 0x03}, {0x9f, 0x03},
+ /* 0xd0*/
+ {0xa0, 0x03}, {0xa1, 0x03}, {0x00, 0x00}, {0xa3, 0x03},
+ {0xa4, 0x03}, {0xa5, 0x03}, {0xa6, 0x03}, {0xa7, 0x03},
+ {0xa8, 0x03}, {0xa9, 0x03}, {0xaa, 0x03}, {0xab, 0x03},
+ {0xac, 0x03}, {0xad, 0x03}, {0xae, 0x03}, {0xaf, 0x03},
+ /* 0xe0*/
+ {0xb0, 0x03}, {0xb1, 0x03}, {0xb2, 0x03}, {0xb3, 0x03},
+ {0xb4, 0x03}, {0xb5, 0x03}, {0xb6, 0x03}, {0xb7, 0x03},
+ {0xb8, 0x03}, {0xb9, 0x03}, {0xba, 0x03}, {0xbb, 0x03},
+ {0xbc, 0x03}, {0xbd, 0x03}, {0xbe, 0x03}, {0xbf, 0x03},
+ /* 0xf0*/
+ {0xc0, 0x03}, {0xc1, 0x03}, {0xc2, 0x03}, {0xc3, 0x03},
+ {0xc4, 0x03}, {0xc5, 0x03}, {0xc6, 0x03}, {0xc7, 0x03},
+ {0xc8, 0x03}, {0xc9, 0x03}, {0xca, 0x03}, {0xcb, 0x03},
+ {0xcc, 0x03}, {0xcd, 0x03}, {0xce, 0x03}, {0x00, 0x00},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xa0, 0x00, 0x00, 0xa3, 0x00, 0x00, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0x00, 0xab, 0xac, 0xad, 0x00, 0x00, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0x00, 0x00, 0x00, 0xb7, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0xbb, 0x00, 0xbd, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page02[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0xa2, 0xa1, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page03[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0xb4, 0xb5, 0xb6, 0x00, /* 0x80-0x87 */
+ 0xb8, 0xb9, 0xba, 0x00, 0xbc, 0x00, 0xbe, 0xbf, /* 0x88-0x8f */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0x90-0x97 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0x98-0x9f */
+ 0xd0, 0xd1, 0x00, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xa0-0xa7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xa8-0xaf */
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xb0-0xb7 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xb8-0xbf */
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xc0-0xc7 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, NULL, page02, page03, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ page20, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0x00, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "iso8859-7",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_iso8859_7(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_iso8859_7();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/nls/nls_iso8859-8.c b/fs/nls/nls_iso8859-8.c
new file mode 100644
index 000000000..b639b7392
--- /dev/null
+++ b/fs/nls/nls_iso8859-8.c
@@ -0,0 +1,303 @@
+/*
+ * linux/fs/nls_iso8859-8.c
+ *
+ * Charset iso8859-8 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0x90*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0xa0*/
+ {0xa0, 0x00}, {0x00, 0x00}, {0xa2, 0x00}, {0xa3, 0x00},
+ {0xa4, 0x00}, {0xa5, 0x00}, {0xa6, 0x00}, {0xa7, 0x00},
+ {0xa8, 0x00}, {0xa9, 0x00}, {0xd7, 0x00}, {0xab, 0x00},
+ {0xac, 0x00}, {0xad, 0x00}, {0xae, 0x00}, {0x3e, 0x20},
+ /* 0xb0*/
+ {0xb0, 0x00}, {0xb1, 0x00}, {0xb2, 0x00}, {0xb3, 0x00},
+ {0xb4, 0x00}, {0xb5, 0x00}, {0xb6, 0x00}, {0xb7, 0x00},
+ {0xb8, 0x00}, {0xb9, 0x00}, {0xf7, 0x00}, {0xbb, 0x00},
+ {0xbc, 0x00}, {0xbd, 0x00}, {0xbe, 0x00}, {0x00, 0x00},
+ /* 0xc0*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0xd0*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x17, 0x20},
+ /* 0xe0*/
+ {0xd0, 0x05}, {0xd1, 0x05}, {0xd2, 0x05}, {0xd3, 0x05},
+ {0xd4, 0x05}, {0xd5, 0x05}, {0xd6, 0x05}, {0xd7, 0x05},
+ {0xd8, 0x05}, {0xd9, 0x05}, {0xda, 0x05}, {0xdb, 0x05},
+ {0xdc, 0x05}, {0xdd, 0x05}, {0xde, 0x05}, {0xdf, 0x05},
+ /* 0xf0*/
+ {0xe0, 0x05}, {0xe1, 0x05}, {0xe2, 0x05}, {0xe3, 0x05},
+ {0xe4, 0x05}, {0xe5, 0x05}, {0xe6, 0x05}, {0xe7, 0x05},
+ {0xe8, 0x05}, {0xe9, 0x05}, {0xea, 0x05}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xa0, 0x00, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0x00, 0xab, 0xac, 0xad, 0xae, 0x00, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0x00, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page05[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xd0-0xd7 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xd8-0xdf */
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xe0-0xe7 */
+ 0xf8, 0xf9, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page20[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, NULL, NULL, NULL, NULL, page05, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ page20, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "iso8859-8",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_iso8859_8(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_iso8859_8();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/nls/nls_iso8859-9.c b/fs/nls/nls_iso8859-9.c
new file mode 100644
index 000000000..aef5b410e
--- /dev/null
+++ b/fs/nls/nls_iso8859-9.c
@@ -0,0 +1,263 @@
+/*
+ * linux/fs/nls_iso8859-9.c
+ *
+ * Charset iso8859-9 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0x90*/
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},
+ /* 0xa0*/
+ {0xa0, 0x00}, {0xa1, 0x00}, {0xa2, 0x00}, {0xa3, 0x00},
+ {0xa4, 0x00}, {0xa5, 0x00}, {0xa6, 0x00}, {0xa7, 0x00},
+ {0xa8, 0x00}, {0xa9, 0x00}, {0xaa, 0x00}, {0xab, 0x00},
+ {0xac, 0x00}, {0xad, 0x00}, {0xae, 0x00}, {0xaf, 0x00},
+ /* 0xb0*/
+ {0xb0, 0x00}, {0xb1, 0x00}, {0xb2, 0x00}, {0xb3, 0x00},
+ {0xb4, 0x00}, {0xb5, 0x00}, {0xb6, 0x00}, {0xb7, 0x00},
+ {0xb8, 0x00}, {0xb9, 0x00}, {0xba, 0x00}, {0xbb, 0x00},
+ {0xbc, 0x00}, {0xbd, 0x00}, {0xbe, 0x00}, {0xbf, 0x00},
+ /* 0xc0*/
+ {0xc0, 0x00}, {0xc1, 0x00}, {0xc2, 0x00}, {0xc3, 0x00},
+ {0xc4, 0x00}, {0xc5, 0x00}, {0xc6, 0x00}, {0xc7, 0x00},
+ {0xc8, 0x00}, {0xc9, 0x00}, {0xca, 0x00}, {0xcb, 0x00},
+ {0xcc, 0x00}, {0xcd, 0x00}, {0xce, 0x00}, {0xcf, 0x00},
+ /* 0xd0*/
+ {0x1e, 0x01}, {0xd1, 0x00}, {0xd2, 0x00}, {0xd3, 0x00},
+ {0xd4, 0x00}, {0xd5, 0x00}, {0xd6, 0x00}, {0xd7, 0x00},
+ {0xd8, 0x00}, {0xd9, 0x00}, {0xda, 0x00}, {0xdb, 0x00},
+ {0xdc, 0x00}, {0x30, 0x01}, {0x5e, 0x01}, {0xdf, 0x00},
+ /* 0xe0*/
+ {0xe0, 0x00}, {0xe1, 0x00}, {0xe2, 0x00}, {0xe3, 0x00},
+ {0xe4, 0x00}, {0xe5, 0x00}, {0xe6, 0x00}, {0xe7, 0x00},
+ {0xe8, 0x00}, {0xe9, 0x00}, {0xea, 0x00}, {0xeb, 0x00},
+ {0xec, 0x00}, {0xed, 0x00}, {0xee, 0x00}, {0xef, 0x00},
+ /* 0xf0*/
+ {0x1f, 0x01}, {0xf1, 0x00}, {0xf2, 0x00}, {0xf3, 0x00},
+ {0xf4, 0x00}, {0xf5, 0x00}, {0xf6, 0x00}, {0xf7, 0x00},
+ {0xf8, 0x00}, {0xf9, 0x00}, {0xfa, 0x00}, {0xfb, 0x00},
+ {0xfc, 0x00}, {0x31, 0x01}, {0x5f, 0x01}, {0xff, 0x00},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0x00, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+ 0x00, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0x00, 0x00, 0xff, /* 0xf8-0xff */
+};
+
+static unsigned char page01[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0xf0, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0xdd, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xfe, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, page01, NULL, NULL, NULL, NULL, NULL, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "iso8859-9",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_iso8859_9(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_iso8859_9();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/nls/nls_koi8-r.c b/fs/nls/nls_koi8-r.c
new file mode 100644
index 000000000..8d08ba3ef
--- /dev/null
+++ b/fs/nls/nls_koi8-r.c
@@ -0,0 +1,375 @@
+/*
+ * linux/fs/nls_koi8-r.c
+ *
+ * Charset koi8-r translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+
+static struct nls_unicode charset2uni[256] = {
+ /* 0x00*/
+ {0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+ {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+ {0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+ {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+ /* 0x10*/
+ {0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+ {0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+ {0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+ /* 0x20*/
+ {0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+ {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+ {0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+ {0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+ /* 0x30*/
+ {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+ {0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+ {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+ {0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+ /* 0x40*/
+ {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+ {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+ {0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+ {0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+ /* 0x50*/
+ {0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+ {0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+ {0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+ /* 0x60*/
+ {0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+ {0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+ {0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+ {0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+ /* 0x70*/
+ {0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+ {0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+ {0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+ {0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+ /* 0x80*/
+ {0x00, 0x25}, {0x02, 0x25}, {0x0c, 0x25}, {0x10, 0x25},
+ {0x14, 0x25}, {0x18, 0x25}, {0x1c, 0x25}, {0x24, 0x25},
+ {0x2c, 0x25}, {0x34, 0x25}, {0x3c, 0x25}, {0x80, 0x25},
+ {0x84, 0x25}, {0x88, 0x25}, {0x8c, 0x25}, {0x90, 0x25},
+ /* 0x90*/
+ {0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x20, 0x23},
+ {0xa0, 0x25}, {0x19, 0x22}, {0x1a, 0x22}, {0x48, 0x22},
+ {0x64, 0x22}, {0x65, 0x22}, {0xa0, 0x00}, {0x21, 0x23},
+ {0xb0, 0x00}, {0xb2, 0x00}, {0xb7, 0x00}, {0xf7, 0x00},
+ /* 0xa0*/
+ {0x50, 0x25}, {0x51, 0x25}, {0x52, 0x25}, {0x51, 0x04},
+ {0x53, 0x25}, {0x54, 0x25}, {0x55, 0x25}, {0x56, 0x25},
+ {0x57, 0x25}, {0x58, 0x25}, {0x59, 0x25}, {0x5a, 0x25},
+ {0x5b, 0x25}, {0x5c, 0x25}, {0x5d, 0x25}, {0x5e, 0x25},
+ /* 0xb0*/
+ {0x5f, 0x25}, {0x60, 0x25}, {0x61, 0x25}, {0x01, 0x04},
+ {0x62, 0x25}, {0x63, 0x25}, {0x64, 0x25}, {0x65, 0x25},
+ {0x66, 0x25}, {0x67, 0x25}, {0x68, 0x25}, {0x69, 0x25},
+ {0x6a, 0x25}, {0x6b, 0x25}, {0x6c, 0x25}, {0xa9, 0x00},
+ /* 0xc0*/
+ {0x4e, 0x04}, {0x30, 0x04}, {0x31, 0x04}, {0x46, 0x04},
+ {0x34, 0x04}, {0x35, 0x04}, {0x44, 0x04}, {0x33, 0x04},
+ {0x45, 0x04}, {0x38, 0x04}, {0x39, 0x04}, {0x3a, 0x04},
+ {0x3b, 0x04}, {0x3c, 0x04}, {0x3d, 0x04}, {0x3e, 0x04},
+ /* 0xd0*/
+ {0x3f, 0x04}, {0x4f, 0x04}, {0x40, 0x04}, {0x41, 0x04},
+ {0x42, 0x04}, {0x43, 0x04}, {0x36, 0x04}, {0x32, 0x04},
+ {0x4c, 0x04}, {0x4b, 0x04}, {0x37, 0x04}, {0x48, 0x04},
+ {0x4d, 0x04}, {0x49, 0x04}, {0x47, 0x04}, {0x4a, 0x04},
+ /* 0xe0*/
+ {0x2e, 0x04}, {0x10, 0x04}, {0x11, 0x04}, {0x26, 0x04},
+ {0x14, 0x04}, {0x15, 0x04}, {0x24, 0x04}, {0x13, 0x04},
+ {0x25, 0x04}, {0x18, 0x04}, {0x19, 0x04}, {0x1a, 0x04},
+ {0x1b, 0x04}, {0x1c, 0x04}, {0x1d, 0x04}, {0x1e, 0x04},
+ /* 0xf0*/
+ {0x1f, 0x04}, {0x2f, 0x04}, {0x20, 0x04}, {0x21, 0x04},
+ {0x22, 0x04}, {0x23, 0x04}, {0x16, 0x04}, {0x12, 0x04},
+ {0x2c, 0x04}, {0x2b, 0x04}, {0x17, 0x04}, {0x28, 0x04},
+ {0x2d, 0x04}, {0x29, 0x04}, {0x27, 0x04}, {0x2a, 0x04},
+};
+
+static unsigned char page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x9c, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page04[256] = {
+ 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0xe1, 0xe2, 0xf7, 0xe7, 0xe4, 0xe5, 0xf6, 0xfa, /* 0x10-0x17 */
+ 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, /* 0x18-0x1f */
+ 0xf2, 0xf3, 0xf4, 0xf5, 0xe6, 0xe8, 0xe3, 0xfe, /* 0x20-0x27 */
+ 0xfb, 0xfd, 0xff, 0xf9, 0xf8, 0xfc, 0xe0, 0xf1, /* 0x28-0x2f */
+ 0xc1, 0xc2, 0xd7, 0xc7, 0xc4, 0xc5, 0xd6, 0xda, /* 0x30-0x37 */
+ 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, /* 0x38-0x3f */
+ 0xd2, 0xd3, 0xd4, 0xd5, 0xc6, 0xc8, 0xc3, 0xde, /* 0x40-0x47 */
+ 0xdb, 0xdd, 0xdf, 0xd9, 0xd8, 0xdc, 0xc0, 0xd1, /* 0x48-0x4f */
+ 0x00, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page22[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x95, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x98, 0x99, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page23[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x93, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+ 0x80, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x83, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x85, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0xa0, 0xa1, 0xa2, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, /* 0x50-0x57 */
+ 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, /* 0x58-0x5f */
+ 0xb1, 0xb2, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, /* 0x60-0x67 */
+ 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x8b, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x8d, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x8f, 0x90, 0x91, 0x92, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+ page00, NULL, NULL, NULL, page04, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, page22, page23, NULL, page25, NULL, NULL,
+};
+
+static unsigned char charset2upper[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+ 0xa0, 0xa1, 0xa2, 0x00, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+
+
+static void inc_use_count(void)
+{
+ MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+ MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+ "koi8-r",
+ page_uni2charset,
+ charset2uni,
+ inc_use_count,
+ dec_use_count,
+ NULL
+};
+
+int init_nls_koi8_r(void)
+{
+ return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return init_nls_koi8_r();
+}
+
+
+void cleanup_module(void)
+{
+ unregister_nls(&table);
+ return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff --git a/fs/pipe.c b/fs/pipe.c
index f5688541d..8c476c34a 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -33,12 +33,16 @@
/* in case of paging and multiple read/write on the same pipe. (FGC) */
-static long pipe_read(struct inode * inode, struct file * filp,
- char * buf, unsigned long count)
+static ssize_t pipe_read(struct file * filp, char * buf,
+ size_t count, loff_t *ppos)
{
- int chars = 0, size = 0, read = 0;
+ struct inode * inode = filp->f_dentry->d_inode;
+ ssize_t chars = 0, size = 0, read = 0;
char *pipebuf;
+ if (ppos != &filp->f_pos)
+ return -ESPIPE;
+
if (filp->f_flags & O_NONBLOCK) {
if (PIPE_LOCK(*inode))
return -EAGAIN;
@@ -52,7 +56,7 @@ static long pipe_read(struct inode * inode, struct file * filp,
if (!PIPE_WRITERS(*inode))
return 0;
}
- if (current->signal & ~current->blocked)
+ if (signal_pending(current))
return -ERESTARTSYS;
interruptible_sleep_on(&PIPE_WAIT(*inode));
}
@@ -83,17 +87,21 @@ static long pipe_read(struct inode * inode, struct file * filp,
return 0;
}
-static long pipe_write(struct inode * inode, struct file * filp,
- const char * buf, unsigned long count)
+static ssize_t pipe_write(struct file * filp, const char * buf,
+ size_t count, loff_t *ppos)
{
- int chars = 0, free = 0, written = 0;
+ struct inode * inode = filp->f_dentry->d_inode;
+ ssize_t chars = 0, free = 0, written = 0;
char *pipebuf;
+ if (ppos != &filp->f_pos)
+ return -ESPIPE;
+
if (!PIPE_READERS(*inode)) { /* no readers */
send_sig(SIGPIPE,current,0);
return -EPIPE;
}
-/* if count <= PIPE_BUF, we have to make it atomic */
+ /* if count <= PIPE_BUF, we have to make it atomic */
if (count <= PIPE_BUF)
free = count;
else
@@ -104,7 +112,7 @@ static long pipe_write(struct inode * inode, struct file * filp,
send_sig(SIGPIPE,current,0);
return written? :-EPIPE;
}
- if (current->signal & ~current->blocked)
+ if (signal_pending(current))
return written? :-ERESTARTSYS;
if (filp->f_flags & O_NONBLOCK)
return written? :-EAGAIN;
@@ -138,20 +146,20 @@ static long long pipe_lseek(struct file * file, long long offset, int orig)
return -ESPIPE;
}
-static long bad_pipe_r(struct inode * inode, struct file * filp,
- char * buf, unsigned long count)
+static ssize_t bad_pipe_r(struct file * filp, char * buf,
+ size_t count, loff_t *ppos)
{
return -EBADF;
}
-static long bad_pipe_w(struct inode * inode, struct file * filp,
- const char * buf, unsigned long count)
+static ssize_t bad_pipe_w(struct file * filp, const char * buf,
+ size_t count, loff_t *ppos)
{
return -EBADF;
}
static int pipe_ioctl(struct inode *pino, struct file * filp,
- unsigned int cmd, unsigned long arg)
+ unsigned int cmd, unsigned long arg)
{
switch (cmd) {
case FIONREAD:
@@ -206,13 +214,14 @@ static unsigned int fifo_poll(struct file * filp, poll_table * wait)
* the open() code hasn't guaranteed a connection (O_NONBLOCK),
* and we need to act differently until we do get a writer..
*/
-static long connect_read(struct inode * inode, struct file * filp,
- char * buf, unsigned long count)
+static ssize_t connect_read(struct file * filp, char * buf,
+ size_t count, loff_t *ppos)
{
+ struct inode * inode = filp->f_dentry->d_inode;
if (PIPE_EMPTY(*inode) && !PIPE_WRITERS(*inode))
return 0;
filp->f_op = &read_fifo_fops;
- return pipe_read(inode,filp,buf,count);
+ return pipe_read(filp,buf,count,ppos);
}
static unsigned int connect_poll(struct file * filp, poll_table * wait)
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 4415a7c54..4e22dfa16 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -61,12 +61,12 @@ int get_malloc(char * buffer);
#endif
-static long read_core(struct inode * inode, struct file * file,
- char * buf, unsigned long count)
+static ssize_t read_core(struct file * file, char * buf,
+ size_t count, loff_t *ppos)
{
- unsigned long p = file->f_pos, memsize;
- int read;
- int count1;
+ unsigned long p = *ppos, memsize;
+ ssize_t read;
+ ssize_t count1;
char * pnt;
struct user dump;
#if defined (__i386__) || defined (__mc68000__)
@@ -101,16 +101,21 @@ static long read_core(struct inode * inode, struct file * file,
read += count1;
}
- while (count > 0 && p < PAGE_SIZE + FIRST_MAPPED) {
- put_user(0,buf);
- buf++;
- p++;
- count--;
- read++;
+ if (count > 0 && p < PAGE_SIZE + FIRST_MAPPED) {
+ count1 = PAGE_SIZE + FIRST_MAPPED - p;
+ if (count1 > count)
+ count1 = count;
+ clear_user(buf, count1);
+ buf += count1;
+ p += count1;
+ count -= count1;
+ read += count1;
}
- copy_to_user(buf, (void *) (PAGE_OFFSET + p - PAGE_SIZE), count);
- read += count;
- file->f_pos += read;
+ if (count > 0) {
+ copy_to_user(buf, (void *) (PAGE_OFFSET+p-PAGE_SIZE), count);
+ read += count;
+ }
+ *ppos += read;
return read;
}
@@ -129,11 +134,11 @@ struct inode_operations proc_kcore_inode_operations = {
* buffer. Use of the program readprofile is recommended in order to
* get meaningful info out of these data.
*/
-static long read_profile(struct inode *inode, struct file *file,
- char *buf, unsigned long count)
+static ssize_t read_profile(struct file *file, char *buf,
+ size_t count, loff_t *ppos)
{
- unsigned long p = file->f_pos;
- int read;
+ unsigned long p = *ppos;
+ ssize_t read;
char * pnt;
unsigned int sample_step = 1 << prof_shift;
@@ -143,14 +148,14 @@ static long read_profile(struct inode *inode, struct file *file,
count = (prof_len+1)*sizeof(unsigned int) - p;
read = 0;
- while (p < sizeof(unsigned long) && count > 0) {
+ while (p < sizeof(unsigned int) && count > 0) {
put_user(*((char *)(&sample_step)+p),buf);
buf++; p++; count--; read++;
}
pnt = (char *)prof_buffer + p - sizeof(unsigned int);
copy_to_user(buf,(void *)pnt,count);
read += count;
- file->f_pos += read;
+ *ppos += read;
return read;
}
@@ -160,10 +165,9 @@ static long read_profile(struct inode *inode, struct file *file,
* Writing a 'profiling multiplier' value into it also re-sets the profiling
* interrupt frequency, on architectures that support this.
*/
-static long write_profile(struct inode * inode, struct file * file,
- const char * buf, unsigned long count)
+static ssize_t write_profile(struct file * file, const char * buf,
+ size_t count, loff_t *ppos)
{
- int i=prof_len;
#ifdef __SMP__
extern int setup_profiling_timer (unsigned int multiplier);
@@ -178,8 +182,7 @@ static long write_profile(struct inode * inode, struct file * file,
}
#endif
- while (i--)
- prof_buffer[i]=0UL;
+ memset(prof_buffer, 0, prof_len * sizeof(*prof_buffer));
return count;
}
@@ -348,6 +351,12 @@ static unsigned long get_phys_addr(struct task_struct * p, unsigned long ptr)
if (!p || !p->mm || ptr >= TASK_SIZE)
return 0;
+ /* Check for NULL pgd .. shouldn't happen! */
+ if (!p->mm->pgd) {
+ printk("get_phys_addr: pid %d has NULL pgd!\n", p->pid);
+ return 0;
+ }
+
page_dir = pgd_offset(p->mm,ptr);
if (pgd_none(*page_dir))
return 0;
@@ -921,58 +930,76 @@ static int get_statm(int pid, char * buffer)
* For the /proc/<pid>/maps file, we use fixed length records, each containing
* a single line.
*/
-#define MAPS_LINE_LENGTH 1024
-#define MAPS_LINE_SHIFT 10
+#define MAPS_LINE_LENGTH 4096
+#define MAPS_LINE_SHIFT 12
/*
* f_pos = (number of the vma in the task->mm->mmap list) * MAPS_LINE_LENGTH
* + (index into the line)
*/
/* for systems with sizeof(void*) == 4: */
-#define MAPS_LINE_FORMAT4 "%08lx-%08lx %s %08lx %s %lu\n"
+#define MAPS_LINE_FORMAT4 "%08lx-%08lx %s %08lx %s %lu"
#define MAPS_LINE_MAX4 49 /* sum of 8 1 8 1 4 1 8 1 5 1 10 1 */
/* for systems with sizeof(void*) == 8: */
-#define MAPS_LINE_FORMAT8 "%016lx-%016lx %s %016lx %s %lu\n"
+#define MAPS_LINE_FORMAT8 "%016lx-%016lx %s %016lx %s %lu"
#define MAPS_LINE_MAX8 73 /* sum of 16 1 16 1 4 1 16 1 5 1 10 1 */
#define MAPS_LINE_MAX MAPS_LINE_MAX8
-static long read_maps (int pid, struct file * file,
- char * buf, unsigned long count)
+static ssize_t read_maps (int pid, struct file * file, char * buf,
+ size_t count, loff_t *ppos)
{
- struct task_struct *p = find_task_by_pid(pid);
- char * destptr;
+ struct task_struct *p;
+ struct vm_area_struct * map, * next;
+ char * destptr = buf, * buffer;
loff_t lineno;
- int column;
- struct vm_area_struct * map;
- int i;
+ ssize_t column, i;
+ int volatile_task;
+ long retval;
+
+ /*
+ * We might sleep getting the page, so get it first.
+ */
+ retval = -ENOMEM;
+ buffer = (char*)__get_free_page(GFP_KERNEL);
+ if (!buffer)
+ goto out;
+ retval = -EINVAL;
+ p = find_task_by_pid(pid);
if (!p)
- return -EINVAL;
+ goto freepage_out;
if (!p->mm || p->mm == &init_mm || count == 0)
- return 0;
+ goto getlen_out;
+
+ /* Check whether the mmaps could change if we sleep */
+ volatile_task = (p != current || p->mm->count > 1);
/* decode f_pos */
- lineno = file->f_pos >> MAPS_LINE_SHIFT;
- column = file->f_pos & (MAPS_LINE_LENGTH-1);
+ lineno = *ppos >> MAPS_LINE_SHIFT;
+ column = *ppos & (MAPS_LINE_LENGTH-1);
/* quickly go to line lineno */
for (map = p->mm->mmap, i = 0; map && (i < lineno); map = map->vm_next, i++)
continue;
- destptr = buf;
-
- for ( ; map ; ) {
+ for ( ; map ; map = next ) {
/* produce the next line */
- char line[MAPS_LINE_MAX+1];
+ char *line;
char str[5], *cp = str;
int flags;
kdev_t dev;
unsigned long ino;
+ int maxlen = (sizeof(void*) == 4) ?
+ MAPS_LINE_MAX4 : MAPS_LINE_MAX8;
int len;
+ /*
+ * Get the next vma now (but it won't be used if we sleep).
+ */
+ next = map->vm_next;
flags = map->vm_flags;
*cp++ = flags & VM_READ ? 'r' : '-';
@@ -986,30 +1013,41 @@ static long read_maps (int pid, struct file * file,
if (map->vm_dentry != NULL) {
dev = map->vm_dentry->d_inode->i_dev;
ino = map->vm_dentry->d_inode->i_ino;
- }
+ line = d_path(map->vm_dentry, buffer, PAGE_SIZE);
+ buffer[PAGE_SIZE-1] = '\n';
+ line -= maxlen;
+ if(line < buffer)
+ line = buffer;
+ } else
+ line = buffer;
len = sprintf(line,
sizeof(void*) == 4 ? MAPS_LINE_FORMAT4 : MAPS_LINE_FORMAT8,
map->vm_start, map->vm_end, str, map->vm_offset,
kdevname(dev), ino);
+ if(map->vm_dentry) {
+ for(i = len; i < maxlen; i++)
+ line[i] = ' ';
+ len = buffer + PAGE_SIZE - line;
+ } else
+ line[len++] = '\n';
if (column >= len) {
column = 0; /* continue with next line at column 0 */
lineno++;
- map = map->vm_next;
- continue;
+ continue; /* we haven't slept */
}
i = len-column;
if (i > count)
i = count;
- copy_to_user(destptr, line+column, i);
- destptr += i; count -= i;
- column += i;
+ copy_to_user(destptr, line+column, i); /* may have slept */
+ destptr += i;
+ count -= i;
+ column += i;
if (column >= len) {
column = 0; /* next time: next line at column 0 */
lineno++;
- map = map->vm_next;
}
/* done? */
@@ -1019,14 +1057,20 @@ static long read_maps (int pid, struct file * file,
/* By writing to user space, we might have slept.
* Stop the loop, to avoid a race condition.
*/
- if (p != current)
+ if (volatile_task)
break;
}
/* encode f_pos */
- file->f_pos = (lineno << MAPS_LINE_SHIFT) + column;
+ *ppos = (lineno << MAPS_LINE_SHIFT) + column;
+
+getlen_out:
+ retval = destptr - buf;
- return destptr-buf;
+freepage_out:
+ free_page((unsigned long)buffer);
+out:
+ return retval;
}
#ifdef CONFIG_MODULES
@@ -1172,13 +1216,14 @@ static inline int fill_array(char * page, int pid, int type, char **start, off_t
#define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */
-static long array_read(struct inode * inode, struct file * file,
- char * buf, unsigned long count)
+static ssize_t array_read(struct file * file, char * buf,
+ size_t count, loff_t *ppos)
{
+ struct inode * inode = file->f_dentry->d_inode;
unsigned long page;
char *start;
- int length;
- int end;
+ ssize_t length;
+ ssize_t end;
unsigned int type, pid;
struct proc_dir_entry *dp;
@@ -1192,11 +1237,11 @@ static long array_read(struct inode * inode, struct file * file,
start = NULL;
dp = (struct proc_dir_entry *) inode->u.generic_ip;
if (dp->get_info)
- length = dp->get_info((char *)page, &start, file->f_pos,
+ length = dp->get_info((char *)page, &start, *ppos,
count, 0);
else
length = fill_array((char *) page, pid, type,
- &start, file->f_pos, count);
+ &start, *ppos, count);
if (length < 0) {
free_page(page);
return length;
@@ -1204,19 +1249,19 @@ static long array_read(struct inode * inode, struct file * file,
if (start != NULL) {
/* We have had block-adjusting processing! */
copy_to_user(buf, start, length);
- file->f_pos += length;
+ *ppos += length;
count = length;
} else {
/* Static 4kB (or whatever) block capacity */
- if (file->f_pos >= length) {
+ if (*ppos >= length) {
free_page(page);
return 0;
}
- if (count + file->f_pos > length)
- count = length - file->f_pos;
- end = count + file->f_pos;
- copy_to_user(buf, (char *) page + file->f_pos, count);
- file->f_pos = end;
+ if (count + *ppos > length)
+ count = length - *ppos;
+ end = count + *ppos;
+ copy_to_user(buf, (char *) page + *ppos, count);
+ *ppos = end;
}
free_page(page);
return count;
@@ -1255,15 +1300,16 @@ struct inode_operations proc_array_inode_operations = {
NULL /* permission */
};
-static long arraylong_read(struct inode * inode, struct file * file,
- char * buf, unsigned long count)
+static ssize_t arraylong_read(struct file * file, char * buf,
+ size_t count, loff_t *ppos)
{
+ struct inode * inode = file->f_dentry->d_inode;
unsigned int pid = inode->i_ino >> 16;
unsigned int type = inode->i_ino & 0x0000ffff;
switch (type) {
case PROC_PID_MAPS:
- return read_maps(pid, file, buf, count);
+ return read_maps(pid, file, buf, count, ppos);
}
return -EINVAL;
}
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 7e9a65e08..ac6704e4b 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -50,13 +50,17 @@ static struct inode_operations proc_base_inode_operations = {
NULL /* permission */
};
-static void proc_pid_fill_inode(struct inode * inode)
+/*
+ * The fill argument is non-zero when the inode is being filled ...
+ * we don't need to do anything when it's being deleted.
+ */
+static void proc_pid_fill_inode(struct inode * inode, int fill)
{
struct task_struct *p;
int pid = inode->i_ino >> 16;
int ino = inode->i_ino & 0xffff;
- if ((p = find_task_by_pid(pid)) != NULL) {
+ if (fill && (p = find_task_by_pid(pid)) != NULL) {
if (p->dumpable || ino == PROC_PID_INO) {
inode->i_uid = p->euid;
inode->i_gid = p->gid;
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 83139f492..89da7544b 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -16,11 +16,13 @@
#include <linux/stat.h>
#include <asm/bitops.h>
-static long proc_file_read(struct inode * inode, struct file * file,
- char * buf, unsigned long nbytes);
-static long proc_file_write(struct inode * inode, struct file * file,
- const char * buffer, unsigned long count);
-static long long proc_file_lseek(struct file * file, long long offset, int orig);
+extern struct inode_operations proc_dyna_dir_inode_operations;
+
+static ssize_t proc_file_read(struct file * file, char * buf,
+ size_t nbytes, loff_t *ppos);
+static ssize_t proc_file_write(struct file * file, const char * buffer,
+ size_t count, loff_t *ppos);
+static long long proc_file_lseek(struct file *, long long, int);
int proc_match(int len, const char *name,struct proc_dir_entry * de)
{
@@ -44,17 +46,14 @@ static struct file_operations proc_file_operations = {
NULL /* can't fsync */
};
-/*
- * proc files can do almost nothing..
- */
struct inode_operations proc_file_inode_operations = {
- &proc_file_operations, /* default proc file-ops */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
+ &proc_file_operations, /* default proc file-ops */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
@@ -98,18 +97,17 @@ struct inode_operations proc_net_inode_operations = {
/* 4K page size but our output routines use some slack for overruns */
#define PROC_BLOCK_SIZE (3*1024)
-static long proc_file_read(struct inode * inode, struct file * file,
- char * buf, unsigned long nbytes)
+static ssize_t
+proc_file_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
{
+ struct inode * inode = file->f_dentry->d_inode;
char *page;
- int retval=0;
+ ssize_t retval=0;
int eof=0;
- int n, count;
+ ssize_t n, count;
char *start;
struct proc_dir_entry * dp;
- if (nbytes < 0)
- return -EINVAL;
dp = (struct proc_dir_entry *) inode->u.generic_ip;
if (!(page = (char*) __get_free_page(GFP_KERNEL)))
return -ENOMEM;
@@ -127,12 +125,12 @@ static long proc_file_read(struct inode * inode, struct file * file,
* XXX What gives with the file->f_flags & O_ACCMODE
* test? Seems stupid to me....
*/
- n = dp->get_info(page, &start, file->f_pos, count,
+ n = dp->get_info(page, &start, *ppos, count,
(file->f_flags & O_ACCMODE) == O_RDWR);
if (n < count)
eof = 1;
} else if (dp->read_proc) {
- n = dp->read_proc(page, &start, file->f_pos,
+ n = dp->read_proc(page, &start, *ppos,
count, &eof, dp->data);
} else
break;
@@ -141,8 +139,8 @@ static long proc_file_read(struct inode * inode, struct file * file,
/*
* For proc files that are less than 4k
*/
- start = page + file->f_pos;
- n -= file->f_pos;
+ start = page + *ppos;
+ n -= *ppos;
if (n <= 0)
break;
if (n > count)
@@ -163,7 +161,7 @@ static long proc_file_read(struct inode * inode, struct file * file,
break;
}
- file->f_pos += n; /* Move down the file */
+ *ppos += n; /* Move down the file */
nbytes -= n;
buf += n;
retval += n;
@@ -172,24 +170,25 @@ static long proc_file_read(struct inode * inode, struct file * file,
return retval;
}
-static long
-proc_file_write(struct inode * inode, struct file * file,
- const char * buffer, unsigned long count)
+static ssize_t
+proc_file_write(struct file * file, const char * buffer,
+ size_t count, loff_t *ppos)
{
+ struct inode *inode = file->f_dentry->d_inode;
struct proc_dir_entry * dp;
- if (count < 0)
- return -EINVAL;
dp = (struct proc_dir_entry *) inode->u.generic_ip;
if (!dp->write_proc)
return -EIO;
+ /* FIXME: does this routine need ppos? probably... */
return dp->write_proc(file, buffer, count, dp->data);
}
-static long long proc_file_lseek(struct file * file, long long offset, int orig)
+static long long
+proc_file_lseek(struct file * file, long long offset, int orig)
{
switch (orig) {
case 0:
@@ -240,57 +239,77 @@ static int xlate_proc_name(const char *name,
struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
struct proc_dir_entry *parent)
{
- struct proc_dir_entry *ent;
- const char *fn;
-
- if (parent)
- fn = name;
- else {
- if (xlate_proc_name(name, &parent, &fn))
- return NULL;
- }
+ struct proc_dir_entry *ent = NULL;
+ const char *fn = name;
+ int len;
+
+ if (!parent && xlate_proc_name(name, &parent, &fn) != 0)
+ goto out;
+ len = strlen(fn);
- ent = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
+ ent = kmalloc(sizeof(struct proc_dir_entry) + len + 1, GFP_KERNEL);
if (!ent)
- return NULL;
+ goto out;
memset(ent, 0, sizeof(struct proc_dir_entry));
+ memcpy(((char *) ent) + sizeof(*ent), fn, len + 1);
+ ent->name = ((char *) ent) + sizeof(*ent);
+ ent->namelen = len;
- if (mode == S_IFDIR)
+ if (mode == S_IFDIR) {
mode |= S_IRUGO | S_IXUGO;
- else if (mode == 0)
- mode = S_IFREG | S_IRUGO;
-
- ent->name = fn;
- ent->namelen = strlen(fn);
- ent->mode = mode;
- if (S_ISDIR(mode))
+ ent->ops = &proc_dyna_dir_inode_operations;
ent->nlink = 2;
- else
+ }
+ else if (mode == 0) {
+ mode = S_IFREG | S_IRUGO;
ent->nlink = 1;
+ }
+ ent->mode = mode;
proc_register(parent, ent);
+out:
return ent;
}
+extern void free_proc_entry(struct proc_dir_entry *);
+void free_proc_entry(struct proc_dir_entry *de)
+{
+ kfree(de);
+}
+
+/*
+ * Remove a /proc entry and free it if it's not currently in use.
+ * If it is in use, we set the 'deleted' flag.
+ */
void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
{
struct proc_dir_entry *de;
- const char *fn;
+ const char *fn = name;
int len;
- if (parent)
- fn = name;
- else
- if (xlate_proc_name(name, &parent, &fn))
- return;
+ if (!parent && xlate_proc_name(name, &parent, &fn) != 0)
+ goto out;
len = strlen(fn);
for (de = parent->subdir; de ; de = de->next) {
if (proc_match(len, fn, de))
break;
}
- if (de)
+
+ if (de) {
+printk("remove_proc_entry: parent nlink=%d, file nlink=%d\n",
+parent->nlink, de->nlink);
proc_unregister(parent, de->low_ino);
- kfree(de);
+ de->nlink = 0;
+ de->deleted = 1;
+ if (!de->count)
+ free_proc_entry(de);
+ else {
+ printk("remove_proc_entry: %s/%s busy, count=%d\n",
+ parent->name, de->name, de->count);
+ }
+ }
+out:
+ return;
}
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 4bc4a4f17..c33616604 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -17,23 +17,66 @@
#include <asm/system.h>
#include <asm/uaccess.h>
+extern void free_proc_entry(struct proc_dir_entry *);
+
+struct proc_dir_entry * de_get(struct proc_dir_entry *de)
+{
+ if (de)
+ de->count++;
+ return de;
+}
+
+/*
+ * Decrements the use count and checks for deferred deletion.
+ */
+void de_put(struct proc_dir_entry *de)
+{
+ if (de) {
+ if (!de->count) {
+ printk("de_put: entry %s already free!\n", de->name);
+ return;
+ }
+
+ if (!--de->count) {
+ if (de->deleted) {
+ printk("de_put: deferred delete of %s\n",
+ de->name);
+ free_proc_entry(de);
+ }
+ }
+ }
+}
+
static void proc_put_inode(struct inode *inode)
{
#ifdef CONFIG_SUN_OPENPROMFS_MODULE
- if ((inode->i_ino >= PROC_OPENPROM_FIRST)
- && (inode->i_ino < PROC_OPENPROM_FIRST + PROC_NOPENPROM)
- && proc_openprom_use)
+ if ((inode->i_ino >= PROC_OPENPROM_FIRST) &&
+ (inode->i_ino < PROC_OPENPROM_FIRST + PROC_NOPENPROM) &&
+ proc_openprom_use)
(*proc_openprom_use)(inode, 0);
#endif
+ /*
+ * Kill off unused inodes ... VFS will unhash and
+ * delete the inode if we set i_nlink to zero.
+ */
+ if (inode->i_count == 1)
+ inode->i_nlink = 0;
}
/*
- * Does this ever happen?
+ * Decrement the use count of the proc_dir_entry.
*/
static void proc_delete_inode(struct inode *inode)
{
- printk("proc_delete_inode()?\n");
- inode->i_size = 0;
+ struct proc_dir_entry *de = inode->u.generic_ip;
+ if (de) {
+ /*
+ * Call the fill_inode hook to release module counts.
+ */
+ if (de->fill_inode)
+ de->fill_inode(inode, 0);
+ de_put(de);
+ }
}
static void proc_put_super(struct super_block *sb)
@@ -47,7 +90,7 @@ static struct super_operations proc_sops = {
proc_read_inode,
proc_write_inode,
proc_put_inode,
- proc_delete_inode,
+ proc_delete_inode, /* delete_inode(struct inode *) */
NULL,
proc_put_super,
NULL,
@@ -85,9 +128,24 @@ static int parse_options(char *options,uid_t *uid,gid_t *gid)
return 1;
}
-struct inode * proc_get_inode(struct super_block * s, int ino, struct proc_dir_entry * de)
+struct inode * proc_get_inode(struct super_block * sb, int ino,
+ struct proc_dir_entry * de)
{
- struct inode * inode = iget(s, ino);
+ struct inode * inode;
+
+ /*
+ * Increment the use count so the dir entry can't disappear.
+ */
+ de_get(de);
+#if 1
+/* shouldn't ever happen */
+if (de && de->deleted)
+printk("proc_iget: using deleted entry %s, count=%d\n", de->name, de->count);
+#endif
+
+ inode = iget(sb, ino);
+ if (!inode)
+ goto out_fail;
#ifdef CONFIG_SUN_OPENPROMFS_MODULE
if ((inode->i_ino >= PROC_OPENPROM_FIRST)
@@ -95,23 +153,29 @@ struct inode * proc_get_inode(struct super_block * s, int ino, struct proc_dir_e
&& proc_openprom_use)
(*proc_openprom_use)(inode, 1);
#endif
- if (inode && inode->i_sb == s) {
- inode->u.generic_ip = (void *) de;
- if (de) {
- if (de->mode) {
- inode->i_mode = de->mode;
- inode->i_uid = de->uid;
- inode->i_gid = de->gid;
- }
- if (de->size)
- inode->i_size = de->size;
- if (de->ops)
- inode->i_op = de->ops;
- if (de->nlink)
- inode->i_nlink = de->nlink;
- if (de->fill_inode)
- de->fill_inode(inode);
+ /* N.B. How can this test ever fail?? */
+ if (inode->i_sb != sb)
+ printk("proc_get_inode: inode fubar\n");
+
+ inode->u.generic_ip = (void *) de;
+ if (de) {
+ if (de->mode) {
+ inode->i_mode = de->mode;
+ inode->i_uid = de->uid;
+ inode->i_gid = de->gid;
}
+ if (de->size)
+ inode->i_size = de->size;
+ if (de->ops)
+ inode->i_op = de->ops;
+ if (de->nlink)
+ inode->i_nlink = de->nlink;
+ /*
+ * The fill_inode routine should use this call
+ * to increment module counts, if necessary.
+ */
+ if (de->fill_inode)
+ de->fill_inode(inode, 1);
}
/*
* Fixup the root inode's nlink value
@@ -126,26 +190,40 @@ struct inode * proc_get_inode(struct super_block * s, int ino, struct proc_dir_e
}
read_unlock(&tasklist_lock);
}
+out:
return inode;
+
+out_fail:
+ de_put(de);
+ goto out;
}
struct super_block *proc_read_super(struct super_block *s,void *data,
int silent)
{
+ struct inode * root_inode;
+
lock_super(s);
s->s_blocksize = 1024;
s->s_blocksize_bits = 10;
s->s_magic = PROC_SUPER_MAGIC;
s->s_op = &proc_sops;
+ root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root);
+ if (!root_inode)
+ goto out_no_root;
+ s->s_root = d_alloc_root(root_inode, NULL);
+ if (!s->s_root)
+ goto out_no_root;
+ parse_options(data, &root_inode->i_uid, &root_inode->i_gid);
unlock_super(s);
- s->s_root = d_alloc_root(proc_get_inode(s, PROC_ROOT_INO, &proc_root), NULL);
- if (!s->s_root) {
- s->s_dev = 0;
- printk("get root inode failed\n");
- return NULL;
- }
- parse_options(data, &s->s_root->d_inode->i_uid, &s->s_root->d_inode->i_gid);
return s;
+
+out_no_root:
+ printk("proc_read_super: get root inode failed\n");
+ iput(root_inode);
+ s->s_dev = 0;
+ unlock_super(s);
+ return NULL;
}
int proc_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
diff --git a/fs/proc/kmsg.c b/fs/proc/kmsg.c
index 1cc6a9c83..42346a895 100644
--- a/fs/proc/kmsg.c
+++ b/fs/proc/kmsg.c
@@ -30,8 +30,8 @@ static int kmsg_release(struct inode * inode, struct file * file)
return 0;
}
-static long kmsg_read(struct inode * inode, struct file * file,
- char * buf, unsigned long count)
+static ssize_t kmsg_read(struct file * file, char * buf,
+ size_t count, loff_t *ppos)
{
return sys_syslog(2,buf,count);
}
diff --git a/fs/proc/mem.c b/fs/proc/mem.c
index 126683ea4..c49f187c0 100644
--- a/fs/proc/mem.c
+++ b/fs/proc/mem.c
@@ -70,9 +70,10 @@ static struct task_struct * get_task(int pid)
return tsk;
}
-static long mem_read(struct inode * inode, struct file * file,
- char * buf, unsigned long count)
+static ssize_t mem_read(struct file * file, char * buf,
+ size_t count, loff_t *ppos)
{
+ struct inode * inode = file->f_dentry->d_inode;
pgd_t *page_dir;
pmd_t *page_middle;
pte_t pte;
@@ -80,18 +81,18 @@ static long mem_read(struct inode * inode, struct file * file,
struct task_struct * tsk;
unsigned long addr;
char *tmp;
- int i;
+ ssize_t scount, i;
tsk = get_task(inode->i_ino >> 16);
if (!tsk)
return -ESRCH;
- addr = file->f_pos;
- count = check_range(tsk->mm, addr, count);
- if (count < 0)
- return count;
+ addr = *ppos;
+ scount = check_range(tsk->mm, addr, count);
+ if (scount < 0)
+ return scount;
tmp = buf;
- while (count > 0) {
- if (current->signal & ~current->blocked)
+ while (scount > 0) {
+ if (signal_pending(current))
break;
page_dir = pgd_offset(tsk->mm,addr);
if (pgd_none(*page_dir))
@@ -114,22 +115,23 @@ static long mem_read(struct inode * inode, struct file * file,
break;
page = (char *) pte_page(pte) + (addr & ~PAGE_MASK);
i = PAGE_SIZE-(addr & ~PAGE_MASK);
- if (i > count)
- i = count;
+ if (i > scount)
+ i = scount;
copy_to_user(tmp, page, i);
addr += i;
tmp += i;
- count -= i;
+ scount -= i;
}
- file->f_pos = addr;
+ *ppos = addr;
return tmp-buf;
}
#ifndef mem_write
-static long mem_write(struct inode * inode, struct file * file,
- char * buf, unsigned long count)
+static ssize_t mem_write(struct file * file, char * buf,
+ size_t count, loff_t *ppos)
{
+ struct inode * inode = file->f_dentry->d_inode;
pgd_t *page_dir;
pmd_t *page_middle;
pte_t pte;
@@ -137,15 +139,15 @@ static long mem_write(struct inode * inode, struct file * file,
struct task_struct * tsk;
unsigned long addr;
char *tmp;
- int i;
+ long i;
- addr = file->f_pos;
+ addr = *ppos;
tsk = get_task(inode->i_ino >> 16);
if (!tsk)
return -ESRCH;
tmp = buf;
while (count > 0) {
- if (current->signal & ~current->blocked)
+ if (signal_pending(current))
break;
page_dir = pgd_offset(tsk,addr);
if (pgd_none(*page_dir))
@@ -177,10 +179,10 @@ static long mem_write(struct inode * inode, struct file * file,
tmp += i;
count -= i;
}
- file->f_pos = addr;
+ *ppos = addr;
if (tmp != buf)
return tmp-buf;
- if (current->signal & ~current->blocked)
+ if (signal_pending(current))
return -ERESTARTSYS;
return 0;
}
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 3f7d0cfee..c72c06483 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -25,6 +25,7 @@
static int proc_root_readdir(struct file *, void *, filldir_t);
static int proc_root_lookup(struct inode *,struct dentry *);
+static int proc_unlink(struct inode *, struct dentry *);
static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8] = {0};
@@ -73,6 +74,29 @@ struct inode_operations proc_dir_inode_operations = {
};
/*
+ * /proc dynamic directories now support unlinking
+ */
+struct inode_operations proc_dyna_dir_inode_operations = {
+ &proc_dir_operations, /* default proc dir ops */
+ NULL, /* create */
+ proc_lookup, /* lookup */
+ NULL, /* link */
+ proc_unlink, /* unlink(struct inode *, struct dentry *) */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL /* permission */
+};
+
+/*
* The root /proc directory is special, as it has the
* <pid> directories. Thus we don't use the generic
* directory handling functions for that..
@@ -173,7 +197,8 @@ proc_openprom_register(int (*readdir)(struct inode *, struct file *, void *, fil
int proc_openprom_regdev(struct openpromfs_dev *d)
{
- if (proc_openpromdev_ino == PROC_OPENPROMD_FIRST + PROC_NOPENPROMD) return -1;
+ if (proc_openpromdev_ino == PROC_OPENPROMD_FIRST + PROC_NOPENPROMD)
+ return -1;
d->next = proc_openprom_devices;
d->inode = proc_openpromdev_ino++;
proc_openprom_devices = d;
@@ -218,6 +243,7 @@ proc_openprom_defreaddir(struct inode * inode, struct file * filp,
(inode, filp, dirent, filldir);
return -EINVAL;
}
+#define OPENPROM_DEFREADDIR proc_openprom_defreaddir
static int
proc_openprom_deflookup(struct inode * dir, struct dentry *dentry)
@@ -229,17 +255,17 @@ proc_openprom_deflookup(struct inode * dir, struct dentry *dentry)
(dir, dentry);
return -ENOENT;
}
+#define OPENPROM_DEFLOOKUP proc_openprom_deflookup
+#else
+#define OPENPROM_DEFREADDIR NULL
+#define OPENPROM_DEFLOOKUP NULL
#endif
static struct file_operations proc_openprom_operations = {
NULL, /* lseek - default */
NULL, /* read - bad */
NULL, /* write - bad */
-#if defined(CONFIG_SUN_OPENPROMFS_MODULE) && defined(CONFIG_KERNELD)
- proc_openprom_defreaddir,/* readdir */
-#else
- NULL, /* readdir */
-#endif
+ OPENPROM_DEFREADDIR, /* readdir */
NULL, /* poll - default */
NULL, /* ioctl - default */
NULL, /* mmap */
@@ -251,11 +277,7 @@ static struct file_operations proc_openprom_operations = {
struct inode_operations proc_openprom_inode_operations = {
&proc_openprom_operations,/* default net directory file-ops */
NULL, /* create */
-#if defined(CONFIG_SUN_OPENPROMFS_MODULE) && defined(CONFIG_KERNELD)
- proc_openprom_deflookup,/* lookup */
-#else
- NULL, /* lookup */
-#endif
+ OPENPROM_DEFLOOKUP, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
@@ -639,6 +661,26 @@ void proc_root_init(void)
}
/*
+ * As some entries in /proc are volatile, we want to
+ * get rid of unused dentries. This could be made
+ * smarter: we could keep a "volatile" flag in the
+ * inode to indicate which ones to keep.
+ */
+static void
+proc_delete_dentry(struct dentry * dentry)
+{
+ d_drop(dentry);
+}
+
+static struct dentry_operations proc_dentry_operations =
+{
+ NULL, /* revalidate */
+ NULL, /* d_hash */
+ NULL, /* d_compare */
+ proc_delete_dentry /* d_delete(struct dentry *) */
+};
+
+/*
* Don't create negative dentries here, return -ENOENT by hand
* instead.
*/
@@ -646,12 +688,15 @@ int proc_lookup(struct inode * dir, struct dentry *dentry)
{
struct inode *inode;
struct proc_dir_entry * de;
+ int error;
+ error = -ENOTDIR;
if (!dir || !S_ISDIR(dir->i_mode))
- return -ENOTDIR;
+ goto out;
- de = (struct proc_dir_entry *) dir->u.generic_ip;
+ error = -ENOENT;
inode = NULL;
+ de = (struct proc_dir_entry *) dir->u.generic_ip;
if (de) {
for (de = de->subdir; de ; de = de->next) {
if (!de || !de->low_ino)
@@ -660,18 +705,20 @@ int proc_lookup(struct inode * dir, struct dentry *dentry)
continue;
if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
int ino = de->low_ino | (dir->i_ino & ~(0xffff));
+ error = -EINVAL;
inode = proc_get_inode(dir->i_sb, ino, de);
- if (!inode)
- return -EINVAL;
break;
}
}
}
- if (!inode)
- return -ENOENT;
- d_add(dentry, inode);
- return 0;
+ if (inode) {
+ dentry->d_op = &proc_dentry_operations;
+ d_add(dentry, inode);
+ error = 0;
+ }
+out:
+ return error;
}
static int proc_root_lookup(struct inode * dir, struct dentry * dentry)
@@ -721,6 +768,8 @@ static int proc_root_lookup(struct inode * dir, struct dentry * dentry)
if (!inode)
return -EINVAL;
}
+
+ dentry->d_op = &proc_dentry_operations;
d_add(dentry, inode);
return 0;
}
@@ -827,3 +876,15 @@ static int proc_root_readdir(struct file * filp,
read_unlock(&tasklist_lock);
return 0;
}
+
+static int proc_unlink(struct inode *dir, struct dentry *dentry)
+{
+ struct proc_dir_entry * dp = dir->u.generic_ip;
+
+printk("proc_file_unlink: deleting %s/%s\n", dp->name, dentry->d_name.name);
+
+ remove_proc_entry(dentry->d_name.name, dp);
+ dentry->d_inode->i_nlink = 0;
+ d_delete(dentry);
+ return 0;
+}
diff --git a/fs/proc/scsi.c b/fs/proc/scsi.c
index 831a2623d..3bc4b1d59 100644
--- a/fs/proc/scsi.c
+++ b/fs/proc/scsi.c
@@ -29,10 +29,10 @@
#include <asm/uaccess.h>
/* forward references */
-static long proc_readscsi(struct inode * inode, struct file * file,
- char * buf, unsigned long count);
-static long proc_writescsi(struct inode * inode, struct file * file,
- const char * buf, unsigned long count);
+static ssize_t proc_readscsi(struct file * file, char * buf,
+ size_t count, loff_t *ppos);
+static ssize_t proc_writescsi(struct file * file, const char * buf,
+ size_t count, loff_t *ppos);
static long long proc_scsilseek(struct file *, long long, int);
extern void build_proc_dir_hba_entries(uint);
@@ -101,13 +101,14 @@ int get_not_present_info(char *buffer, char **start, off_t offset, int length)
* use some slack for overruns
*/
-static long proc_readscsi(struct inode * inode, struct file * file,
- char * buf, unsigned long count)
+static ssize_t proc_readscsi(struct file * file, char * buf,
+ size_t count, loff_t *ppos)
{
- int length;
- int bytes = count;
- int copied = 0;
- int thistime;
+ struct inode * inode = file->f_dentry->d_inode;
+ ssize_t length;
+ ssize_t bytes = count;
+ ssize_t copied = 0;
+ ssize_t thistime;
char * page;
char * start;
@@ -121,9 +122,9 @@ static long proc_readscsi(struct inode * inode, struct file * file,
if(dispatch_scsi_info_ptr)
length = dispatch_scsi_info_ptr(inode->i_ino, page, &start,
- file->f_pos, thistime, 0);
+ *ppos, thistime, 0);
else
- length = get_not_present_info(page, &start, file->f_pos, thistime);
+ length = get_not_present_info(page, &start, *ppos, thistime);
if(length < 0) {
free_page((ulong) page);
return(length);
@@ -140,7 +141,7 @@ static long proc_readscsi(struct inode * inode, struct file * file,
* Copy the bytes
*/
copy_to_user(buf + copied, start, length);
- file->f_pos += length; /* Move down the file */
+ *ppos += length; /* Move down the file */
bytes -= length;
copied += length;
@@ -154,10 +155,11 @@ static long proc_readscsi(struct inode * inode, struct file * file,
}
-static long proc_writescsi(struct inode * inode, struct file * file,
- const char * buf, unsigned long count)
+static ssize_t proc_writescsi(struct file * file, const char * buf,
+ size_t count, loff_t *ppos)
{
- int ret = 0;
+ struct inode * inode = file->f_dentry->d_inode;
+ ssize_t ret = 0;
char * page;
if(count > PROC_BLOCK_SIZE) {
diff --git a/fs/read_write.c b/fs/read_write.c
index df3d34d3e..616dbd760 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -16,10 +16,11 @@
#include <linux/malloc.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/limits.h>
#include <asm/uaccess.h>
-static long long default_llseek(struct file *file, long long offset, int origin)
+static loff_t default_llseek(struct file *file, loff_t offset, int origin)
{
long long retval;
@@ -42,9 +43,9 @@ static long long default_llseek(struct file *file, long long offset, int origin)
return retval;
}
-static inline long long llseek(struct file *file, long long offset, unsigned int origin)
+static inline loff_t llseek(struct file *file, loff_t offset, int origin)
{
- long long (*fn)(struct file *, long long, int);
+ loff_t (*fn)(struct file *, loff_t, int);
fn = default_llseek;
if (file->f_op && file->f_op->llseek)
@@ -52,9 +53,9 @@ static inline long long llseek(struct file *file, long long offset, unsigned int
return fn(file, offset, origin);
}
-asmlinkage long sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
+asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
{
- long retval;
+ off_t retval;
struct file * file;
struct dentry * dentry;
struct inode * inode;
@@ -67,23 +68,23 @@ asmlinkage long sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
!(inode = dentry->d_inode))
goto bad;
retval = -EINVAL;
- if (origin > 2)
- goto bad;
- retval = llseek(file, offset, origin);
+ if (origin <= 2)
+ retval = llseek(file, offset, origin);
bad:
unlock_kernel();
return retval;
}
+#if !defined(__alpha__) && !defined(__sparc_v9__)
asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high,
unsigned long offset_low, loff_t * result,
unsigned int origin)
{
- long retval;
+ int retval;
struct file * file;
struct dentry * dentry;
struct inode * inode;
- long long offset;
+ loff_t offset;
lock_kernel();
retval = -EBADF;
@@ -96,10 +97,10 @@ asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high,
if (origin > 2)
goto bad;
- offset = llseek(file, (((unsigned long long) offset_high << 32) | offset_low),
- origin);
+ offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
+ origin);
- retval = offset;
+ retval = (int)offset & INT_MAX;
if (offset >= 0) {
retval = copy_to_user(result, &offset, sizeof(offset));
if (retval)
@@ -109,120 +110,114 @@ bad:
unlock_kernel();
return retval;
}
+#endif
-asmlinkage long sys_read(unsigned int fd, char * buf, unsigned long count)
+asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
{
- int error;
+ ssize_t ret;
struct file * file;
- struct dentry * dentry;
- struct inode * inode;
- long (*read)(struct inode *, struct file *, char *, unsigned long);
+ ssize_t (*read)(struct file *, char *, size_t, loff_t *);
lock_kernel();
- error = -EBADF;
+
+ ret = -EBADF;
file = fget(fd);
if (!file)
goto bad_file;
- dentry = file->f_dentry;
- if (!dentry)
+ ret = -EBADF;
+ if (!(file->f_mode & FMODE_READ))
goto out;
- inode = dentry->d_inode;
- if (!inode)
+ ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
+ file, file->f_pos, count);
+ if (ret)
goto out;
- error = -EBADF;
- if (!(file->f_mode & 1))
- goto out;
- error = locks_verify_area(FLOCK_VERIFY_READ,inode,file,file->f_pos,count);
- if (error)
- goto out;
- error = -EINVAL;
+ ret = -EINVAL;
if (!file->f_op || !(read = file->f_op->read))
goto out;
- error = read(inode,file,buf,count);
+ ret = read(file, buf, count, &file->f_pos);
out:
fput(file);
bad_file:
unlock_kernel();
- return error;
+ return ret;
}
-asmlinkage long sys_write(unsigned int fd, const char * buf, unsigned long count)
+asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
{
- int error;
+ ssize_t ret;
struct file * file;
- struct dentry * dentry;
struct inode * inode;
- long (*write)(struct inode *, struct file *, const char *, unsigned long);
+ ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
lock_kernel();
- error = -EBADF;
+
+ ret = -EBADF;
file = fget(fd);
if (!file)
goto bad_file;
- dentry = file->f_dentry;
- if (!dentry)
- goto out;
- inode = dentry->d_inode;
- if (!inode)
+ if (!(file->f_mode & FMODE_WRITE))
goto out;
- if (!(file->f_mode & 2))
+ inode = file->f_dentry->d_inode;
+ ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
+ file->f_pos, count);
+ if (ret)
goto out;
- error = locks_verify_area(FLOCK_VERIFY_WRITE,inode,file,file->f_pos,count);
- if (error)
- goto out;
- error = -EINVAL;
+ ret = -EINVAL;
if (!file->f_op || !(write = file->f_op->write))
goto out;
+
down(&inode->i_sem);
- error = write(inode,file,buf,count);
+ ret = write(file, buf, count, &file->f_pos);
up(&inode->i_sem);
out:
fput(file);
bad_file:
unlock_kernel();
- return error;
+ return ret;
}
-typedef long (*IO_fn_t)(struct inode *, struct file *, char *, unsigned long);
-static long do_readv_writev(int type, struct inode * inode, struct file * file,
- const struct iovec * vector, unsigned long count)
+static ssize_t do_readv_writev(int type, struct file *file,
+ const struct iovec * vector,
+ unsigned long count)
{
- unsigned long tot_len;
+ typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
+
+ size_t tot_len;
struct iovec iovstack[UIO_FASTIOV];
struct iovec *iov=iovstack;
- long retval, i;
- IO_fn_t fn;
+ ssize_t ret, i;
+ io_fn_t fn;
+ struct inode *inode;
/*
* First get the "struct iovec" from user memory and
* verify all the pointers
*/
+ ret = 0;
if (!count)
- return 0;
+ goto out_nofree;
+ ret = -EINVAL;
if (count > UIO_MAXIOV)
- return -EINVAL;
+ goto out_nofree;
if (count > UIO_FASTIOV) {
iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
- if (!iov)
- return -ENOMEM;
- }
- if (copy_from_user(iov, vector, count*sizeof(*vector))) {
- if (iov != iovstack)
- kfree(iov);
- return -EFAULT;
+ ret = -ENOMEM;
+ if (!iov) goto out_nofree;
}
+ ret = -EFAULT;
+ if (copy_from_user(iov, vector, count*sizeof(*vector)))
+ goto out;
+
tot_len = 0;
for (i = 0 ; i < count ; i++)
tot_len += iov[i].iov_len;
- retval = locks_verify_area(type == VERIFY_READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
- inode, file, file->f_pos, tot_len);
- if (retval) {
- if (iov != iovstack)
- kfree(iov);
- return retval;
- }
+ inode = file->f_dentry->d_inode;
+ ret = locks_verify_area((type == VERIFY_READ
+ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
+ inode, file, file->f_pos, tot_len);
+ if (ret) goto out;
/*
* Then do the actual IO. Note that sockets need to be handled
@@ -230,116 +225,165 @@ static long do_readv_writev(int type, struct inode * inode, struct file * file,
* iovec's natively
*/
if (inode->i_sock) {
- int err;
- err = sock_readv_writev(type, inode, file, iov, count, tot_len);
- if (iov != iovstack)
- kfree(iov);
- return err;
+ ret = sock_readv_writev(type,inode,file,iov,count,tot_len);
+ goto out;
}
- if (!file->f_op) {
- if (iov != iovstack)
- kfree(iov);
- return -EINVAL;
- }
+ ret = -EINVAL;
+ if (!file->f_op)
+ goto out;
+
/* VERIFY_WRITE actually means a read, as we write to user space */
fn = file->f_op->read;
if (type == VERIFY_READ)
- fn = (IO_fn_t) file->f_op->write;
+ fn = (io_fn_t) file->f_op->write;
+
+ ret = 0;
vector = iov;
while (count > 0) {
void * base;
- int len, nr;
+ size_t len;
+ ssize_t nr;
base = vector->iov_base;
len = vector->iov_len;
vector++;
count--;
- /* Any particular reason why we do not grab the inode semaphore
- * when doing writes here? -DaveM
- */
- nr = fn(inode, file, base, len);
+ nr = fn(file, base, len, &file->f_pos);
+
if (nr < 0) {
- if (retval)
- break;
- retval = nr;
+ if (!ret) ret = nr;
break;
}
- retval += nr;
+ ret += nr;
if (nr != len)
break;
}
+
+out:
if (iov != iovstack)
kfree(iov);
- return retval;
+out_nofree:
+ return ret;
}
-asmlinkage long sys_readv(unsigned long fd, const struct iovec * vector, unsigned long count)
+asmlinkage ssize_t sys_readv(unsigned long fd, const struct iovec * vector,
+ unsigned long count)
{
struct file * file;
- struct dentry * dentry;
- struct inode * inode;
- long err;
+ ssize_t ret;
lock_kernel();
- err = -EBADF;
- if (fd >= NR_OPEN)
- goto out;
- file = current->files->fd[fd];
+ ret = -EBADF;
+ file = fget(fd);
if (!file)
+ goto bad_file;
+ if (!(file->f_mode & FMODE_READ))
goto out;
+ ret = do_readv_writev(VERIFY_WRITE, file, vector, count);
+out:
+ fput(file);
+bad_file:
+ unlock_kernel();
+ return ret;
+}
- if (!(file->f_mode & 1))
- goto out;
+asmlinkage ssize_t sys_writev(unsigned long fd, const struct iovec * vector,
+ unsigned long count)
+{
+ struct file * file;
+ ssize_t ret;
- dentry = file->f_dentry;
- if (!dentry)
- goto out;
+ lock_kernel();
- inode = dentry->d_inode;
- if (!inode)
+ ret = -EBADF;
+ file = fget(fd);
+ if (!file)
+ goto bad_file;
+ if (!(file->f_mode & FMODE_WRITE))
goto out;
- err = do_readv_writev(VERIFY_WRITE, inode, file, vector, count);
+ down(&file->f_dentry->d_inode->i_sem);
+ ret = do_readv_writev(VERIFY_READ, file, vector, count);
+ up(&file->f_dentry->d_inode->i_sem);
+
out:
+ fput(file);
+bad_file:
unlock_kernel();
- return err;
+ return ret;
}
-asmlinkage long sys_writev(unsigned long fd, const struct iovec * vector, unsigned long count)
+/* From the Single Unix Spec: pread & pwrite act like lseek to pos + op +
+ lseek back to original location. They fail just like lseek does on
+ non-seekable files. */
+
+asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
+ size_t count, loff_t pos)
{
- long error;
+ ssize_t ret;
struct file * file;
- struct dentry * dentry;
- struct inode * inode;
+ ssize_t (*read)(struct file *, char *, size_t, loff_t *);
lock_kernel();
- error = -EBADF;
- if (fd >= NR_OPEN)
+ ret = -EBADF;
+ file = fget(fd);
+ if (!file)
+ goto bad_file;
+ if (!(file->f_mode & FMODE_READ))
+ goto out;
+ ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
+ file, pos, count);
+ if (ret)
goto out;
+ ret = -EINVAL;
+ if (!file->f_op || !(read = file->f_op->read))
+ goto out;
+ if (pos < 0)
+ goto out;
+ ret = read(file, buf, count, &pos);
+out:
+ fput(file);
+bad_file:
+ unlock_kernel();
+ return ret;
+}
+
+asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
+ size_t count, loff_t pos)
+{
+ ssize_t ret;
+ struct file * file;
+ ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
+
+ lock_kernel();
- file = current->files->fd[fd];
+ ret = -EBADF;
+ file = fget(fd);
if (!file)
+ goto bad_file;
+ if (!(file->f_mode & FMODE_WRITE))
goto out;
-
- if (!(file->f_mode & 2))
+ ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode,
+ file, pos, count);
+ if (ret)
goto out;
-
- dentry = file->f_dentry;
- if (!dentry)
+ ret = -EINVAL;
+ if (!file->f_op || !(write = file->f_op->write))
goto out;
-
- inode = dentry->d_inode;
- if (!inode)
+ if (pos < 0)
goto out;
- down(&inode->i_sem);
- error = do_readv_writev(VERIFY_READ, inode, file, vector, count);
- up(&inode->i_sem);
+ down(&file->f_dentry->d_inode->i_sem);
+ ret = write(file, buf, count, &pos);
+ up(&file->f_dentry->d_inode->i_sem);
+
out:
+ fput(file);
+bad_file:
unlock_kernel();
- return error;
+ return ret;
}
diff --git a/fs/readdir.c b/fs/readdir.c
index c11682f34..fab0b3e76 100644
--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -87,7 +87,13 @@ asmlinkage int old_readdir(unsigned int fd, void * dirent, unsigned int count)
if (!file->f_op || !file->f_op->readdir)
goto out;
+ /*
+ * Get the inode's semaphore to prevent changes
+ * to the directory while we read it.
+ */
+ down(&inode->i_sem);
error = file->f_op->readdir(file, &buf, fillonedir);
+ up(&inode->i_sem);
if (error < 0)
goto out;
error = buf.count;
@@ -173,7 +179,13 @@ asmlinkage int sys_getdents(unsigned int fd, void * dirent, unsigned int count)
if (!file->f_op || !file->f_op->readdir)
goto out;
+ /*
+ * Get the inode's semaphore to prevent changes
+ * to the directory while we read it.
+ */
+ down(&inode->i_sem);
error = file->f_op->readdir(file, &buf, filldir);
+ up(&inode->i_sem);
if (error < 0)
goto out;
lastdirent = buf.previous;
diff --git a/fs/select.c b/fs/select.c
index 5cb06164b..d804d58b3 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -184,7 +184,7 @@ static int do_select(int n, fd_set_buffer *fds, poll_table *wait)
}
}
wait = NULL;
- if (retval || !current->timeout || (current->signal & ~current->blocked))
+ if (retval || !current->timeout || signal_pending(current))
break;
schedule();
}
@@ -328,12 +328,23 @@ asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct
zero_fd_set(n, &fds->res_out);
zero_fd_set(n, &fds->res_ex);
error = do_select(n, fds, wait);
+ if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
+ unsigned long timeout = current->timeout - jiffies - 1;
+ unsigned long sec = 0, usec = 0;
+ if ((long) timeout > 0) {
+ sec = timeout / HZ;
+ usec = timeout % HZ;
+ usec *= (1000000/HZ);
+ }
+ put_user(sec, &tvp->tv_sec);
+ put_user(usec, &tvp->tv_usec);
+ }
current->timeout = 0;
if (error < 0)
goto out;
if (!error) {
error = -ERESTARTNOHAND;
- if (current->signal & ~current->blocked)
+ if (signal_pending(current))
goto out;
error = 0;
}
@@ -384,7 +395,7 @@ static int do_poll(unsigned int nfds, struct pollfd *fds, poll_table *wait)
}
wait = NULL;
- if (count || !current->timeout || (current->signal & ~current->blocked))
+ if (count || !current->timeout || signal_pending(current))
break;
schedule();
}
@@ -439,7 +450,7 @@ asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, int timeout)
__put_user(fds->revents, &ufds->revents);
}
kfree(fds1);
- if (!fdcount && (current->signal & ~current->blocked))
+ if (!fdcount && signal_pending(current))
err = -EINTR;
else
err = fdcount;
diff --git a/fs/smbfs/Makefile b/fs/smbfs/Makefile
index 3d9588e6d..202cc5932 100644
--- a/fs/smbfs/Makefile
+++ b/fs/smbfs/Makefile
@@ -8,7 +8,7 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
O_TARGET := smbfs.o
-O_OBJS := proc.o dir.o sock.o inode.o file.o ioctl.o
+O_OBJS := proc.o dir.o cache.o sock.o inode.o file.o ioctl.o
M_OBJS := $(O_TARGET)
# If you want debugging output, please uncomment the following line
diff --git a/fs/smbfs/cache.c b/fs/smbfs/cache.c
new file mode 100644
index 000000000..292493dac
--- /dev/null
+++ b/fs/smbfs/cache.c
@@ -0,0 +1,316 @@
+/*
+ * cache.c
+ *
+ * Copyright (C) 1997 by Bill Hawes
+ *
+ * Routines to support directory cacheing using the page cache.
+ * Right now this only works for smbfs, but will be generalized
+ * for use with other filesystems.
+ */
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/dirent.h>
+#include <linux/smb_fs.h>
+
+#include <asm/page.h>
+
+#define SMBFS_PARANOIA 1
+/* #define SMBFS_DEBUG_VERBOSE 1 */
+
+static inline struct inode *
+get_cache_inode(struct cache_head *cachep)
+{
+ return (mem_map + MAP_NR((unsigned long) cachep))->inode;
+}
+
+/*
+ * Get a pointer to the cache_head structure,
+ * mapped as the page at offset 0. The page is
+ * kept locked while we're using the cache.
+ */
+struct cache_head *
+smb_get_dircache(struct dentry * dentry)
+{
+ struct inode * inode = dentry->d_inode;
+ struct cache_head * cachep;
+
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_get_dircache: finding cache for %s/%s\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
+ cachep = (struct cache_head *) get_cached_page(inode, 0, 1);
+ if (!cachep)
+ goto out;
+ if (cachep->valid)
+ {
+ struct cache_index * index = cachep->index;
+ struct cache_block * block;
+ unsigned long offset;
+ int i;
+
+ cachep->valid = 0;
+ /*
+ * Here we only want to find existing cache blocks,
+ * not add new ones.
+ */
+ for (i = 0; i < cachep->pages; i++, index++) {
+#ifdef SMBFS_PARANOIA
+if (index->block)
+printk("smb_get_dircache: cache %s/%s has existing block!\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
+ offset = PAGE_SIZE + (i << PAGE_SHIFT);
+ block = (struct cache_block *) get_cached_page(inode,
+ offset, 0);
+ if (!block)
+ goto out;
+ index->block = block;
+ }
+ cachep->valid = 1;
+ }
+out:
+ return cachep;
+}
+
+/*
+ * Unlock and release the data blocks.
+ */
+static void
+smb_free_cache_blocks(struct cache_head * cachep)
+{
+ struct cache_index * index = cachep->index;
+ int i;
+
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_free_cache_blocks: freeing %d blocks\n", cachep->pages);
+#endif
+ for (i = 0; i < cachep->pages; i++, index++)
+ {
+ if (index->block)
+ {
+ put_cached_page((unsigned long) index->block);
+ index->block = NULL;
+ }
+ }
+}
+
+/*
+ * Unlocks and releases the dircache.
+ */
+void
+smb_free_dircache(struct cache_head * cachep)
+{
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_free_dircache: freeing cache\n");
+#endif
+ smb_free_cache_blocks(cachep);
+ put_cached_page((unsigned long) cachep);
+}
+
+/*
+ * Initializes the dircache. We release any existing data blocks,
+ * and then clear the cache_head structure.
+ */
+void
+smb_init_dircache(struct cache_head * cachep)
+{
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_init_dircache: initializing cache, %d blocks\n", cachep->pages);
+#endif
+ smb_free_cache_blocks(cachep);
+ memset(cachep, 0, sizeof(struct cache_head));
+}
+
+/*
+ * Add a new entry to the cache. This assumes that the
+ * entries are coming in order and are added to the end.
+ */
+void
+smb_add_to_cache(struct cache_head * cachep, struct cache_dirent *entry,
+ off_t fpos)
+{
+ struct inode * inode = get_cache_inode(cachep);
+ struct cache_index * index;
+ struct cache_block * block;
+ unsigned long page_off;
+ unsigned int nent, offset, len = entry->len;
+ unsigned int needed = len + sizeof(struct cache_entry);
+
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_add_to_cache: cache inode %p, status %d, adding %s at %ld\n",
+inode, cachep->status, entry->d_name, fpos);
+#endif
+ /*
+ * Don't do anything if we've had an error ...
+ */
+ if (cachep->status)
+ goto out;
+
+ index = &cachep->index[cachep->idx];
+ if (!index->block)
+ goto get_block;
+
+ /* space available? */
+ if (needed < index->space)
+ {
+ add_entry:
+ nent = index->num_entries;
+ index->num_entries++;
+ index->space -= needed;
+ offset = index->space +
+ index->num_entries * sizeof(struct cache_entry);
+ block = index->block;
+ memcpy(&block->cb_data.names[offset], entry->name, len);
+ block->cb_data.table[nent].namelen = len;
+ block->cb_data.table[nent].offset = offset;
+ block->cb_data.table[nent].ino = entry->ino;
+ cachep->entries++;
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_add_to_cache: added entry %s, len=%d, pos=%ld, entries=%d\n",
+entry->d_name, len, fpos, cachep->entries);
+#endif
+ return;
+ }
+ /*
+ * This block is full ... advance the index.
+ */
+ cachep->idx++;
+ if (cachep->idx > NINDEX) /* not likely */
+ goto out_full;
+ index++;
+#ifdef SMBFS_PARANOIA
+if (index->block)
+printk("smb_add_to_cache: new index already has block!\n");
+#endif
+
+ /*
+ * Get the next cache block
+ */
+get_block:
+ cachep->pages++;
+ page_off = PAGE_SIZE + (cachep->idx << PAGE_SHIFT);
+ block = (struct cache_block *) get_cached_page(inode, page_off, 1);
+ if (block)
+ {
+ index->block = block;
+ index->space = PAGE_SIZE;
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_add_to_cache: inode=%p, pages=%d, block at %ld\n",
+inode, cachep->pages, page_off);
+#endif
+ goto add_entry;
+ }
+ /*
+ * On failure, just set the return status ...
+ */
+out_full:
+ cachep->status = -ENOMEM;
+out:
+ return;
+}
+
+int
+smb_find_in_cache(struct cache_head * cachep, off_t pos,
+ struct cache_dirent *entry)
+{
+ struct cache_index * index = cachep->index;
+ struct cache_block * block;
+ unsigned int i, nent, offset = 0;
+ off_t next_pos = 2;
+
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_find_in_cache: cache %p, looking for pos=%ld\n", cachep, pos);
+#endif
+ for (i = 0; i < cachep->pages; i++, index++)
+ {
+ if (pos < next_pos)
+ break;
+ nent = pos - next_pos;
+ next_pos += index->num_entries;
+ if (pos >= next_pos)
+ continue;
+ /*
+ * The entry is in this block. Note: we return
+ * then name as a reference with _no_ null byte.
+ */
+ block = index->block;
+ entry->ino = block->cb_data.table[nent].ino;
+ entry->len = block->cb_data.table[nent].namelen;
+ offset = block->cb_data.table[nent].offset;
+ entry->name = &block->cb_data.names[offset];
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_find_in_cache: found %s, len=%d, pos=%ld\n",
+entry->name, entry->len, pos);
+#endif
+ break;
+ }
+ return offset;
+}
+
+int
+smb_refill_dircache(struct cache_head * cachep, struct dentry *dentry)
+{
+ struct inode * inode = dentry->d_inode;
+ int result;
+
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_refill_dircache: cache %s/%s, blocks=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, cachep->pages);
+#endif
+ /*
+ * Fill the cache, starting at position 2.
+ */
+retry:
+ inode->u.smbfs_i.cache_valid |= SMB_F_CACHEVALID;
+ result = smb_proc_readdir(dentry, 2, cachep);
+ if (result < 0)
+ {
+#ifdef SMBFS_PARANOIA
+printk("smb_refill_dircache: readdir failed, result=%d\n", result);
+#endif
+ goto out;
+ }
+
+ /*
+ * Check whether the cache was invalidated while
+ * we were doing the scan ...
+ */
+ if (!(inode->u.smbfs_i.cache_valid & SMB_F_CACHEVALID))
+ {
+#ifdef SMBFS_PARANOIA
+printk("smb_refill_dircache: cache invalidated, retrying\n");
+#endif
+ goto retry;
+ }
+
+ result = cachep->status;
+ if (!result)
+ {
+ cachep->valid = 1;
+ }
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_refill_cache: cache %s/%s status=%d, entries=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name,
+cachep->status, cachep->entries);
+#endif
+
+out:
+ return result;
+}
+
+void
+smb_invalid_dir_cache(struct inode * dir)
+{
+ /*
+ * Get rid of any unlocked pages, and clear the
+ * 'valid' flag in case a scan is in progress.
+ */
+ invalidate_inode_pages(dir);
+ dir->u.smbfs_i.cache_valid &= ~SMB_F_CACHEVALID;
+ dir->u.smbfs_i.oldmtime = 0;
+}
+
diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c
index 3196e9009..921aa86e1 100644
--- a/fs/smbfs/dir.c
+++ b/fs/smbfs/dir.c
@@ -8,36 +8,27 @@
#include <linux/sched.h>
#include <linux/errno.h>
-#include <linux/stat.h>
#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include <linux/mm.h>
+
#include <linux/smb_fs.h>
#include <linux/smbno.h>
-#include <linux/errno.h>
-
-#include <asm/uaccess.h>
-#include <asm/semaphore.h>
#define SMBFS_PARANOIA 1
/* #define SMBFS_DEBUG_VERBOSE 1 */
/* #define pr_debug printk */
+#define SMBFS_MAX_AGE 5*HZ
-#define this_dir_cached(dir) ((dir->i_sb == c_sb) && (dir->i_ino == c_ino))
-
-static long
-smb_dir_read(struct inode *inode, struct file *filp,
- char *buf, unsigned long count);
-
-static int
-smb_readdir(struct file *filp, void *dirent, filldir_t filldir);
+static ssize_t smb_dir_read(struct file *, char *, size_t, loff_t *);
+static int smb_readdir(struct file *, void *, filldir_t);
+static int smb_dir_open(struct inode *, struct file *);
static int smb_lookup(struct inode *, struct dentry *);
static int smb_create(struct inode *, struct dentry *, int);
static int smb_mkdir(struct inode *, struct dentry *, int);
static int smb_rmdir(struct inode *, struct dentry *);
static int smb_unlink(struct inode *, struct dentry *);
-static int smb_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
+static int smb_rename(struct inode *, struct dentry *,
+ struct inode *, struct dentry *);
static struct file_operations smb_dir_operations =
{
@@ -48,7 +39,7 @@ static struct file_operations smb_dir_operations =
NULL, /* poll - default */
smb_ioctl, /* ioctl */
NULL, /* mmap */
- NULL, /* no special open code */
+ smb_dir_open, /* open(struct inode *, struct file *) */
NULL, /* no special release code */
NULL /* fsync */
};
@@ -72,140 +63,37 @@ struct inode_operations smb_dir_inode_operations =
NULL, /* bmap */
NULL, /* truncate */
NULL, /* permission */
- NULL /* smap */
+ NULL, /* smap */
+ NULL, /* updatepage */
+ smb_revalidate_inode, /* revalidate */
};
-static void smb_put_dentry(struct dentry *);
-static struct dentry_operations smbfs_dentry_operations =
-{
- NULL, /* revalidate */
- NULL, /* d_hash */
- NULL, /* d_compare */
- smb_put_dentry /* d_delete */
-};
-
-static long
-smb_dir_read(struct inode *inode, struct file *filp, char *buf,
- unsigned long count)
+static ssize_t
+smb_dir_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
{
return -EISDIR;
}
/*
- * This is the callback from dput(). We close the file so that
- * cached dentries don't keep the file open.
+ * Check whether a dentry already exists for the given name,
+ * and return the inode number if it has an inode. This is
+ * needed to keep getcwd() working.
*/
-void
-smb_put_dentry(struct dentry *dentry)
+static ino_t
+find_inode_number(struct dentry *dir, struct qstr *name)
{
- struct inode *ino = dentry->d_inode;
- if (ino)
- smb_close(ino);
-}
-
-/* Static variables for the dir cache */
-static struct smb_dirent *c_entry = NULL;
-static struct super_block * c_sb = NULL;
-static unsigned long c_ino = 0;
-static int c_seen_eof;
-static int c_size;
-static int c_last_returned_index;
-
-static struct smb_dirent *
-smb_search_in_cache(struct inode *dir, unsigned long f_pos)
-{
- int i;
-
- if (this_dir_cached(dir))
- for (i = 0; i < c_size; i++)
- {
- if (c_entry[i].f_pos < f_pos)
- continue;
- if (c_entry[i].f_pos == f_pos)
- {
- c_last_returned_index = i;
- return &(c_entry[i]);
- }
- break;
- }
- return NULL;
-}
+ struct dentry * dentry;
+ ino_t ino = 0;
-/*
- * Compute the hash for a qstr ... move to include/linux/dcache.h?
- */
-static unsigned int hash_it(const char * name, unsigned int len)
-{
- unsigned long hash;
- hash = init_name_hash();
- while (len--)
- hash = partial_name_hash(*name++, hash);
- return end_name_hash(hash);
-}
-
-static struct semaphore refill_cache_sem = MUTEX;
-/*
- * Called with the refill semaphore held.
- */
-static int
-smb_refill_dir_cache(struct dentry *dentry, unsigned long f_pos)
-{
- struct inode *dir = dentry->d_inode;
- ino_t ino_start;
- int i, result;
-
- result = smb_proc_readdir(dentry, f_pos,
- SMB_READDIR_CACHE_SIZE, c_entry);
-#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_refill_dir_cache: dir=%s/%s, pos=%lu, result=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, f_pos, result);
-#endif
-
- if (result <= 0)
- {
- /*
- * If an error occurred, the cache may have been partially
- * filled prior to failing, so we must invalidate.
- * N.B. Might not need to for 0 return ... save cache?
- */
- c_sb = NULL;
- c_ino = 0;
- c_seen_eof = 0;
- goto out;
- }
-
- /* Suppose there are a multiple of cache entries? */
- c_seen_eof = (result < SMB_READDIR_CACHE_SIZE);
- c_sb = dir->i_sb;
- c_ino = dir->i_ino;
- c_size = result;
- c_last_returned_index = 0; /* is this used? */
-
- ino_start = smb_invent_inos(c_size);
- /*
- * If a dentry already exists, we have to give the cache entry
- * the correct inode number. This is needed for getcwd().
- */
- for (i = 0; i < c_size; i++)
+ name->hash = full_name_hash(name->name, name->len);
+ dentry = d_lookup(dir, name);
+ if (dentry)
{
- struct dentry * new_dentry;
- struct qstr qname;
-
- c_entry[i].attr.f_ino = ino_start++;
- qname.name = c_entry[i].name;
- qname.len = c_entry[i].len;
- qname.hash = hash_it(qname.name, qname.len);
- new_dentry = d_lookup(dentry, &qname);
- if (new_dentry)
- {
- struct inode * inode = new_dentry->d_inode;
- if (inode)
- c_entry[i].attr.f_ino = inode->i_ino;
- dput(new_dentry);
- }
+ if (dentry->d_inode)
+ ino = dentry->d_inode->i_ino;
+ dput(dentry);
}
-out:
- return result;
+ return ino;
}
static int
@@ -213,38 +101,34 @@ smb_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
struct dentry *dentry = filp->f_dentry;
struct inode *dir = dentry->d_inode;
- struct smb_dirent *entry;
+ struct cache_head *cachep;
int result;
- pr_debug("smb_readdir: filp->f_pos = %d\n", (int) filp->f_pos);
- pr_debug("smb_readdir: dir->i_ino = %ld, c_ino = %ld\n",
- dir->i_ino, c_ino);
-
- result = -EBADF;
- if ((dir == NULL) || !S_ISDIR(dir->i_mode))
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_readdir: reading %s/%s, f_pos=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, (int) filp->f_pos);
+#endif
+ /*
+ * Make sure our inode is up-to-date.
+ */
+ result = smb_revalidate_inode(dir);
+ if (result)
goto out;
-
/*
- * Check whether the directory cache exists yet
+ * Get the cache pointer ...
*/
- if (c_entry == NULL)
+ result = -EIO;
+ cachep = smb_get_dircache(dentry);
+ if (!cachep)
+ goto out;
+ /*
+ * Make sure the cache is up-to-date.
+ */
+ if (!cachep->valid)
{
- int size = sizeof(struct smb_dirent) * SMB_READDIR_CACHE_SIZE;
- result = -ENOMEM;
- entry = (struct smb_dirent *) smb_vmalloc(size);
- /*
- * Somebody else may have allocated the cache,
- * so we check again to avoid a memory leak.
- */
- if (!c_entry)
- {
- if (!entry)
- goto out;
- c_entry = entry;
- } else if (entry) {
- printk("smb_readdir: cache already alloced!\n");
- smb_vfree(entry);
- }
+ result = smb_refill_dircache(cachep, dentry);
+ if (result)
+ goto out_free;
}
result = 0;
@@ -252,111 +136,180 @@ smb_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
case 0:
if (filldir(dirent, ".", 1, 0, dir->i_ino) < 0)
- goto out;
+ goto out_free;
filp->f_pos = 1;
case 1:
if (filldir(dirent, "..", 2, 1,
dentry->d_parent->d_inode->i_ino) < 0)
- goto out;
+ goto out_free;
filp->f_pos = 2;
}
- /*
- * Since filldir() could block if dirent is paged out,
- * we hold the refill semaphore while using the cache.
- * N.B. It's possible that the directory could change
- * between calls to readdir ... what to do??
- */
- down(&refill_cache_sem);
- entry = smb_search_in_cache(dir, filp->f_pos);
- if (entry == NULL)
+ while (1)
{
- /* Past the end of _this_ directory? */
- if (this_dir_cached(dir) && c_seen_eof &&
- filp->f_pos == c_entry[c_size-1].f_pos + 1)
- {
-#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_readdir: eof reached for %s/%s, c_size=%d, pos=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, c_size, (int) filp->f_pos);
-#endif
- goto up_and_out;
- }
- result = smb_refill_dir_cache(dentry, filp->f_pos);
- if (result <= 0)
- goto up_and_out;
- entry = c_entry;
- }
+ struct cache_dirent this_dirent, *entry = &this_dirent;
- while (entry < &(c_entry[c_size]))
- {
- pr_debug("smb_readdir: entry->name = %s\n", entry->name);
+ if (!smb_find_in_cache(cachep, filp->f_pos, entry))
+ break;
+ /*
+ * Check whether to look up the inode number.
+ */
+ if (!entry->ino) {
+ struct qstr qname;
+ /* N.B. Make cache_dirent name a qstr! */
+ qname.name = entry->name;
+ qname.len = entry->len;
+ entry->ino = find_inode_number(dentry, &qname);
+ if (!entry->ino)
+ entry->ino = smb_invent_inos(1);
+ }
if (filldir(dirent, entry->name, entry->len,
- entry->f_pos, entry->attr.f_ino) < 0)
+ filp->f_pos, entry->ino) < 0)
break;
-#if SMBFS_PARANOIA
-/* should never happen */
-if (!this_dir_cached(dir) || (entry->f_pos != filp->f_pos))
-printk("smb_readdir: cache changed!\n");
-#endif
filp->f_pos += 1;
- entry += 1;
}
- result = 0;
-up_and_out:
- up(&refill_cache_sem);
+ /*
+ * Release the dircache.
+ */
+out_free:
+ smb_free_dircache(cachep);
out:
return result;
}
-void
-smb_init_dir_cache(void)
+static int
+smb_dir_open(struct inode *dir, struct file *file)
{
- c_entry = NULL;
- c_sb = NULL;
- c_ino = 0;
- c_seen_eof = 0;
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_dir_open: (%s/%s)\n", file->f_dentry->d_parent->d_name.name,
+file->f_dentry->d_name.name);
+#endif
+ return smb_revalidate_inode(dir);
}
-void
-smb_invalid_dir_cache(struct inode * dir)
+/*
+ * Dentry operations routines
+ */
+static int smb_lookup_validate(struct dentry *);
+static void smb_delete_dentry(struct dentry *);
+
+static struct dentry_operations smbfs_dentry_operations =
+{
+ smb_lookup_validate, /* d_validate(struct dentry *) */
+ NULL, /* d_hash */
+ NULL, /* d_compare */
+ smb_delete_dentry /* d_delete(struct dentry *) */
+};
+
+/*
+ * This is the callback when the dcache has a lookup hit.
+ */
+static int
+smb_lookup_validate(struct dentry * dentry)
{
- if (this_dir_cached(dir))
+ struct inode * inode = dentry->d_inode;
+ unsigned long age = jiffies - dentry->d_time;
+ int valid;
+
+ /*
+ * The default validation is based on dentry age:
+ * we believe in dentries for 5 seconds. (But each
+ * successful server lookup renews the timestamp.)
+ */
+ valid = (age <= SMBFS_MAX_AGE) || IS_ROOT(dentry);
+#ifdef SMBFS_DEBUG_VERBOSE
+if (!valid)
+printk("smb_lookup_validate: %s/%s not valid, age=%lu\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, age);
+#endif
+
+ if (inode)
+ {
+ if (is_bad_inode(inode))
+ {
+#ifdef SMBFS_PARANOIA
+printk("smb_lookup_validate: %s/%s has dud inode\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
+ valid = 0;
+ }
+ } else
+ {
+ /*
+ * What should we do for negative dentries?
+ */
+ }
+ return valid;
+}
+
+/*
+ * This is the callback from dput() when d_count is going to 0.
+ * We use this to unhash dentries with bad inodes and close files.
+ */
+static void
+smb_delete_dentry(struct dentry * dentry)
+{
+ if ((jiffies - dentry->d_time) > SMBFS_MAX_AGE)
+ {
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_delete_dentry: %s/%s expired, d_time=%lu, now=%lu\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_time, jiffies);
+#endif
+ d_drop(dentry);
+ }
+
+ if (dentry->d_inode)
+ {
+ if (is_bad_inode(dentry->d_inode))
+ {
+#ifdef SMBFS_PARANOIA
+printk("smb_delete_dentry: bad inode, unhashing %s/%s\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
+ d_drop(dentry);
+ }
+ smb_close_dentry(dentry);
+ } else
{
- c_sb = NULL;
- c_ino = 0;
- c_seen_eof = 0;
+ /* N.B. Unhash negative dentries? */
}
}
+/*
+ * Whenever a lookup succeeds, we know the parent directories
+ * are all valid, so we want to update the dentry timestamps.
+ * N.B. Move this to dcache?
+ */
void
-smb_free_dir_cache(void)
+smb_renew_times(struct dentry * dentry)
{
- if (c_entry != NULL)
+ for (;;)
{
- /* N.B. can this block?? */
- smb_vfree(c_entry);
+ dentry->d_time = jiffies;
+ if (dentry == dentry->d_parent)
+ break;
+ dentry = dentry->d_parent;
}
- c_entry = NULL;
}
static int
-smb_lookup(struct inode *dir, struct dentry *d_entry)
+smb_lookup(struct inode *dir, struct dentry *dentry)
{
struct smb_fattr finfo;
struct inode *inode;
int error;
error = -ENAMETOOLONG;
- if (d_entry->d_name.len > SMB_MAXNAMELEN)
+ if (dentry->d_name.len > SMB_MAXNAMELEN)
goto out;
- error = smb_proc_getattr(d_entry->d_parent, &(d_entry->d_name), &finfo);
-#if SMBFS_PARANOIA
+ error = smb_proc_getattr(dentry->d_parent, &(dentry->d_name), &finfo);
+#ifdef SMBFS_PARANOIA
if (error && error != -ENOENT)
printk("smb_lookup: find %s/%s failed, error=%d\n",
-d_entry->d_parent->d_name.name, d_entry->d_name.name, error);
+dentry->d_parent->d_name.name, dentry->d_name.name, error);
#endif
inode = NULL;
@@ -364,16 +317,17 @@ d_entry->d_parent->d_name.name, d_entry->d_name.name, error);
goto add_entry;
if (!error)
{
+ error = -EACCES;
finfo.f_ino = smb_invent_inos(1);
inode = smb_iget(dir->i_sb, &finfo);
- error = -EACCES;
if (inode)
{
/* cache the dentry pointer */
- inode->u.smbfs_i.dentry = d_entry;
+ inode->u.smbfs_i.dentry = dentry;
add_entry:
- d_entry->d_op = &smbfs_dentry_operations;
- d_add(d_entry, inode);
+ dentry->d_op = &smbfs_dentry_operations;
+ d_add(dentry, inode);
+ smb_renew_times(dentry);
error = 0;
}
}
@@ -385,56 +339,85 @@ out:
* This code is common to all routines creating a new inode.
*/
static int
-smb_instantiate(struct inode *dir, struct dentry *dentry)
+smb_instantiate(struct dentry *dentry, __u16 fileid, int have_id)
{
+ struct smb_sb_info *server = server_from_dentry(dentry);
+ struct inode *inode;
struct smb_fattr fattr;
int error;
- smb_invalid_dir_cache(dir);
-
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_instantiate: file %s/%s, fileid=%u\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, fileid);
+#endif
error = smb_proc_getattr(dentry->d_parent, &(dentry->d_name), &fattr);
- if (!error)
+ if (error)
+ goto out_close;
+
+ smb_renew_times(dentry);
+ fattr.f_ino = smb_invent_inos(1);
+ inode = smb_iget(dentry->d_sb, &fattr);
+ if (!inode)
+ goto out_no_inode;
+
+ if (have_id)
{
- struct inode *inode;
- error = -EACCES;
- fattr.f_ino = smb_invent_inos(1);
- inode = smb_iget(dir->i_sb, &fattr);
- if (inode)
- {
- /* cache the dentry pointer */
- inode->u.smbfs_i.dentry = dentry;
- d_instantiate(dentry, inode);
- error = 0;
- }
+ inode->u.smbfs_i.fileid = fileid;
+ inode->u.smbfs_i.access = SMB_O_RDWR;
+ inode->u.smbfs_i.open = server->generation;
}
+ /* cache the dentry pointer */
+ inode->u.smbfs_i.dentry = dentry;
+ d_instantiate(dentry, inode);
+out:
return error;
+
+out_no_inode:
+ error = -EACCES;
+out_close:
+ if (have_id)
+ {
+#ifdef SMBFS_PARANOIA
+printk("smb_instantiate: %s/%s failed, error=%d, closing %u\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, error, fileid);
+#endif
+ smb_close_fileid(dentry, fileid);
+ }
+ goto out;
}
-/* N.B. Should the mode argument be put into the fattr? */
+/* N.B. How should the mode argument be used? */
static int
smb_create(struct inode *dir, struct dentry *dentry, int mode)
{
+ __u16 fileid;
int error;
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_create: creating %s/%s, mode=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, mode);
+#endif
error = -ENAMETOOLONG;
if (dentry->d_name.len > SMB_MAXNAMELEN)
goto out;
- /* FIXME: In the CIFS create call we get the file in open
- * state. Currently we close it directly again, although this
- * is not necessary anymore. */
-
+ smb_invalid_dir_cache(dir);
error = smb_proc_create(dentry->d_parent, &(dentry->d_name),
- 0, CURRENT_TIME);
- if (!error)
+ 0, CURRENT_TIME, &fileid);
+ if (!error) {
+ error = smb_instantiate(dentry, fileid, 1);
+ } else
{
- error = smb_instantiate(dir, dentry);
+#ifdef SMBFS_PARANOIA
+printk("smb_create: %s/%s failed, error=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, error);
+#endif
}
out:
return error;
}
-/* N.B. Should the mode argument be put into the fattr? */
+/* N.B. How should the mode argument be used? */
static int
smb_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
@@ -444,10 +427,11 @@ smb_mkdir(struct inode *dir, struct dentry *dentry, int mode)
if (dentry->d_name.len > SMB_MAXNAMELEN)
goto out;
+ smb_invalid_dir_cache(dir);
error = smb_proc_mkdir(dentry->d_parent, &(dentry->d_name));
if (!error)
{
- error = smb_instantiate(dir, dentry);
+ error = smb_instantiate(dentry, 0, 0);
}
out:
return error;
@@ -459,20 +443,30 @@ smb_rmdir(struct inode *dir, struct dentry *dentry)
int error;
error = -ENAMETOOLONG;
- if (dentry->d_name.len > NFS_MAXNAMLEN)
+ if (dentry->d_name.len > SMB_MAXNAMELEN)
goto out;
/*
* Since the dentry is holding an inode, the file
* is in use, so we have to close it first.
*/
- if (dentry->d_inode)
- smb_close(dentry->d_inode);
- smb_invalid_dir_cache(dir);
+ smb_close(dentry->d_inode);
+
+ /*
+ * Prune any child dentries so this dentry can become negative.
+ */
+ if (dentry->d_count > 1) {
+ shrink_dcache_parent(dentry);
+ error = -EBUSY;
+ if (dentry->d_count > 1)
+ goto out;
+ }
+ smb_invalid_dir_cache(dir);
error = smb_proc_rmdir(dentry->d_parent, &(dentry->d_name));
if (!error)
{
+ smb_renew_times(dentry);
d_delete(dentry);
}
out:
@@ -492,13 +486,13 @@ smb_unlink(struct inode *dir, struct dentry *dentry)
* Since the dentry is holding an inode, the file
* is in use, so we have to close it first.
*/
- if (dentry->d_inode)
- smb_close(dentry->d_inode);
- smb_invalid_dir_cache(dir);
+ smb_close(dentry->d_inode);
+ smb_invalid_dir_cache(dir);
error = smb_proc_unlink(dentry->d_parent, &(dentry->d_name));
if (!error)
{
+ smb_renew_times(dentry);
d_delete(dentry);
}
out:
@@ -511,19 +505,6 @@ smb_rename(struct inode *old_dir, struct dentry *old_dentry,
{
int error;
- error = -ENOTDIR;
- if (!old_dir || !S_ISDIR(old_dir->i_mode))
- {
- printk("smb_rename: old inode is NULL or not a directory\n");
- goto out;
- }
-
- if (!new_dir || !S_ISDIR(new_dir->i_mode))
- {
- printk("smb_rename: new inode is NULL or not a directory\n");
- goto out;
- }
-
error = -ENAMETOOLONG;
if (old_dentry->d_name.len > SMB_MAXNAMELEN ||
new_dentry->d_name.len > SMB_MAXNAMELEN)
@@ -538,10 +519,8 @@ smb_rename(struct inode *old_dir, struct dentry *old_dentry,
if (new_dentry->d_inode)
smb_close(new_dentry->d_inode);
- /* Assume success and invalidate now */
smb_invalid_dir_cache(old_dir);
smb_invalid_dir_cache(new_dir);
-
error = smb_proc_mv(old_dentry->d_parent, &(old_dentry->d_name),
new_dentry->d_parent, &(new_dentry->d_name));
/*
@@ -549,22 +528,24 @@ smb_rename(struct inode *old_dir, struct dentry *old_dentry,
*/
if (error == -EEXIST)
{
-#ifdef SMBFS_PARANOIA
+#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_rename: existing file %s/%s, d_count=%d\n",
new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
new_dentry->d_count);
#endif
error = smb_proc_unlink(new_dentry->d_parent,
&(new_dentry->d_name));
-#ifdef SMBFS_PARANOIA
+#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_rename: after unlink error=%d\n", error);
#endif
- if (error)
- goto out;
- d_delete(new_dentry);
-
- error = smb_proc_mv(old_dentry->d_parent, &(old_dentry->d_name),
- new_dentry->d_parent, &(new_dentry->d_name));
+ if (!error)
+ {
+ d_delete(new_dentry);
+ error = smb_proc_mv(old_dentry->d_parent,
+ &(old_dentry->d_name),
+ new_dentry->d_parent,
+ &(new_dentry->d_name));
+ }
}
/*
@@ -572,6 +553,8 @@ printk("smb_rename: after unlink error=%d\n", error);
*/
if (!error)
{
+ smb_renew_times(old_dentry);
+ smb_renew_times(new_dentry->d_parent);
d_move(old_dentry, new_dentry);
}
out:
diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c
index 9653a7be6..2454fdf8e 100644
--- a/fs/smbfs/file.c
+++ b/fs/smbfs/file.c
@@ -12,13 +12,15 @@
#include <linux/fcntl.h>
#include <linux/stat.h>
#include <linux/mm.h>
-#include <linux/smb_fs.h>
#include <linux/malloc.h>
#include <linux/pagemap.h>
#include <asm/uaccess.h>
#include <asm/system.h>
+#include <linux/smbno.h>
+#include <linux/smb_fs.h>
+
#define SMBFS_PARANOIA 1
/* #define SMBFS_DEBUG_VERBOSE 1 */
/* #define pr_debug printk */
@@ -29,11 +31,20 @@ min(int a, int b)
return a < b ? a : b;
}
+static inline void
+smb_unlock_page(struct page *page)
+{
+ clear_bit(PG_locked, &page->flags);
+ wake_up(&page->wait);
+}
+
static int
smb_fsync(struct file *file, struct dentry * dentry)
{
- printk("smb_fsync: sync file %s/%s\n",
- dentry->d_parent->d_name.name, dentry->d_name.name);
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_fsync: sync file %s/%s\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
return 0;
}
@@ -43,14 +54,13 @@ smb_fsync(struct file *file, struct dentry * dentry)
static int
smb_readpage_sync(struct inode *inode, struct page *page)
{
- unsigned long offset = page->offset;
char *buffer = (char *) page_address(page);
+ unsigned long offset = page->offset;
struct dentry * dentry = inode->u.smbfs_i.dentry;
- int rsize = SMB_SERVER(inode)->opt.max_xmit - (SMB_HEADER_LEN+15);
- int result, refresh = 0;
+ int rsize = smb_get_rsize(SMB_SERVER(inode));
int count = PAGE_SIZE;
+ int result;
- pr_debug("SMB: smb_readpage_sync(%p)\n", page);
clear_bit(PG_error, &page->flags);
result = -EIO;
@@ -60,27 +70,32 @@ smb_readpage_sync(struct inode *inode, struct page *page)
goto io_error;
}
- result = smb_open(dentry, O_RDONLY);
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_readpage_sync: file %s/%s, count=%d@%ld, rsize=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, count, offset, rsize);
+#endif
+ result = smb_open(dentry, SMB_O_RDONLY);
if (result < 0)
+ {
+#ifdef SMBFS_PARANOIA
+printk("smb_readpage_sync: %s/%s open failed, error=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, result);
+#endif
goto io_error;
- /* Should revalidate inode ... */
+ }
do {
if (count < rsize)
rsize = count;
-#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_readpage: reading %s/%s, offset=%ld, buffer=%p, size=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, offset, buffer, rsize);
-#endif
result = smb_proc_read(inode, offset, rsize, buffer);
if (result < 0)
goto io_error;
- refresh = 1;
count -= result;
offset += result;
buffer += result;
+ inode->i_atime = CURRENT_TIME;
if (result < rsize)
break;
} while (count);
@@ -90,10 +105,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, offset, buffer, rsize);
result = 0;
io_error:
- if (refresh)
- smb_refresh_inode(inode);
- clear_bit(PG_locked, &page->flags);
- wake_up(&page->wait);
+ smb_unlock_page(page);
return result;
}
@@ -110,7 +122,7 @@ smb_readpage(struct inode *inode, struct page *page)
set_bit(PG_locked, &page->flags);
atomic_inc(&page->count);
error = smb_readpage_sync(inode, page);
- __free_page(page);
+ free_page(page_address(page));
return error;
}
@@ -122,47 +134,50 @@ static int
smb_writepage_sync(struct inode *inode, struct page *page,
unsigned long offset, unsigned int count)
{
- int wsize = SMB_SERVER(inode)->opt.max_xmit - (SMB_HEADER_LEN+15);
- int result, refresh = 0, written = 0;
- u8 *buffer;
-
- pr_debug("SMB: smb_writepage_sync(%x/%ld %d@%ld)\n",
- inode->i_dev, inode->i_ino,
- count, page->offset + offset);
+ u8 *buffer = (u8 *) page_address(page) + offset;
+ int wsize = smb_get_wsize(SMB_SERVER(inode));
+ int result, written = 0;
- buffer = (u8 *) page_address(page) + offset;
offset += page->offset;
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_writepage_sync: file %s/%s, count=%d@%ld, wsize=%d\n",
+((struct dentry *) inode->u.smbfs_i.dentry)->d_parent->d_name.name,
+((struct dentry *) inode->u.smbfs_i.dentry)->d_name.name, count, offset, wsize);
+#endif
do {
if (count < wsize)
wsize = count;
result = smb_proc_write(inode, offset, wsize, buffer);
-
- if (result < 0) {
- /* Must mark the page invalid after I/O error */
- clear_bit(PG_uptodate, &page->flags);
+ if (result < 0)
goto io_error;
- }
/* N.B. what if result < wsize?? */
#ifdef SMBFS_PARANOIA
if (result < wsize)
printk("smb_writepage_sync: short write, wsize=%d, result=%d\n", wsize, result);
#endif
- refresh = 1;
buffer += wsize;
offset += wsize;
written += wsize;
count -= wsize;
+ /*
+ * Update the inode now rather than waiting for a refresh.
+ */
+ inode->i_mtime = inode->i_atime = CURRENT_TIME;
+ if (offset > inode->i_size)
+ inode->i_size = offset;
+ inode->u.smbfs_i.cache_valid |= SMB_F_LOCALWRITE;
} while (count);
-io_error:
- if (refresh)
- smb_refresh_inode(inode);
-
- clear_bit(PG_locked, &page->flags);
- wake_up(&page->wait);
+out:
+ smb_unlock_page(page);
return written ? written : result;
+
+io_error:
+ /* Must mark the page invalid after I/O error */
+ clear_bit(PG_uptodate, &page->flags);
+ goto out;
}
/*
@@ -181,7 +196,7 @@ smb_writepage(struct inode *inode, struct page *page)
set_bit(PG_locked, &page->flags);
atomic_inc(&page->count);
result = smb_writepage_sync(inode, page, 0, PAGE_SIZE);
- __free_page(page);
+ free_page(page_address(page));
return result;
}
@@ -189,8 +204,8 @@ static int
smb_updatepage(struct inode *inode, struct page *page, const char *buffer,
unsigned long offset, unsigned int count, int sync)
{
- u8 *page_addr;
- int result;
+ unsigned long page_addr = page_address(page);
+ int result;
pr_debug("SMB: smb_updatepage(%x/%ld %d@%ld, sync=%d)\n",
inode->i_dev, inode->i_ino,
@@ -203,39 +218,53 @@ smb_updatepage(struct inode *inode, struct page *page, const char *buffer,
set_bit(PG_locked, &page->flags);
atomic_inc(&page->count);
- page_addr = (u8 *) page_address(page);
-
- if (copy_from_user(page_addr + offset, buffer, count))
+ if (copy_from_user((char *) page_addr + offset, buffer, count))
goto bad_fault;
result = smb_writepage_sync(inode, page, offset, count);
out:
- __free_page(page);
+ free_page(page_addr);
return result;
bad_fault:
- printk("smb_updatepage: fault at page=%p buffer=%p\n", page, buffer);
+#ifdef SMBFS_PARANOIA
+printk("smb_updatepage: fault at addr=%lu, offset=%lu, buffer=%p\n",
+page_addr, offset, buffer);
+#endif
result = -EFAULT;
clear_bit(PG_uptodate, &page->flags);
- clear_bit(PG_locked, &page->flags);
- wake_up(&page->wait);
+ smb_unlock_page(page);
goto out;
}
-static long
-smb_file_read(struct inode * inode, struct file * file,
- char * buf, unsigned long count)
+static ssize_t
+smb_file_read(struct file * file, char * buf, size_t count, loff_t *ppos)
{
- int status;
+ struct dentry * dentry = file->f_dentry;
+ struct inode * inode = dentry->d_inode;
+ ssize_t status;
- pr_debug("SMB: read(%x/%ld (%d), %lu@%lu)\n",
- inode->i_dev, inode->i_ino, inode->i_count,
- count, (unsigned long) file->f_pos);
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_file_read: file %s/%s, count=%lu@%lu\n",
+dentry->d_parent->d_name.name, dentry->d_name.name,
+(unsigned long) count, (unsigned long) *ppos);
+#endif
status = smb_revalidate_inode(inode);
- if (status >= 0)
+ if (status)
{
- status = generic_file_read(inode, file, buf, count);
+#ifdef SMBFS_PARANOIA
+printk("smb_file_read: %s/%s validation failed, error=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, status);
+#endif
+ goto out;
}
+
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_file_read: before read, size=%ld, pages=%ld, flags=%x, atime=%ld\n",
+inode->i_size, inode->i_nrpages, inode->i_flags, inode->i_atime);
+#endif
+ status = generic_file_read(file, buf, count, ppos);
+out:
return status;
}
@@ -246,57 +275,117 @@ smb_file_mmap(struct file * file, struct vm_area_struct * vma)
struct inode * inode = dentry->d_inode;
int status;
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_file_mmap: file %s/%s, address %lu - %lu\n",
+dentry->d_parent->d_name.name, dentry->d_name.name,
+vma->vm_start, vma->vm_end);
+#endif
+
status = smb_revalidate_inode(inode);
- if (status >= 0)
+ if (status)
{
- status = generic_file_mmap(file, vma);
+#ifdef SMBFS_PARANOIA
+printk("smb_file_mmap: %s/%s validation failed, error=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, status);
+#endif
+ goto out;
}
+ status = generic_file_mmap(file, vma);
+out:
return status;
}
/*
* Write to a file (through the page cache).
*/
-static long
-smb_file_write(struct inode *inode, struct file *file,
- const char *buf, unsigned long count)
+static ssize_t
+smb_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
- int result;
-
- pr_debug("SMB: write(%x/%ld (%d), %lu@%lu)\n",
- inode->i_dev, inode->i_ino, inode->i_count,
- count, (unsigned long) file->f_pos);
+ struct dentry * dentry = file->f_dentry;
+ struct inode * inode = dentry->d_inode;
+ ssize_t result;
- result = -EINVAL;
- if (!inode) {
- printk("smb_file_write: inode = NULL\n");
- goto out;
- }
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_file_write: file %s/%s, count=%lu@%lu\n",
+dentry->d_parent->d_name.name, dentry->d_name.name,
+(unsigned long) count, (unsigned long) *ppos);
+#endif
result = smb_revalidate_inode(inode);
- if (result < 0)
- goto out;
-
- result = smb_open(file->f_dentry, O_WRONLY);
- if (result < 0)
- goto out;
+ if (result)
+ {
+#ifdef SMBFS_PARANOIA
+printk("smb_file_write: %s/%s validation failed, error=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, result);
+#endif
+ goto out;
+ }
- result = -EINVAL;
- if (!S_ISREG(inode->i_mode)) {
- printk("smb_file_write: write to non-file, mode %07o\n",
- inode->i_mode);
+ result = smb_open(dentry, SMB_O_WRONLY);
+ if (result)
goto out;
- }
- result = 0;
if (count > 0)
{
- result = generic_file_write(inode, file, buf, count);
+ result = generic_file_write(file, buf, count, ppos);
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_file_write: pos=%ld, size=%ld, mtime=%ld, atime=%ld\n",
+(long) file->f_pos, inode->i_size, inode->i_mtime, inode->i_atime);
+#endif
}
out:
return result;
}
+static int
+smb_file_open(struct inode *inode, struct file * file)
+{
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_file_open: opening %s/%s, d_count=%d\n",
+file->f_dentry->d_parent->d_name.name, file->f_dentry->d_name.name,
+file->f_dentry->d_count);
+#endif
+ return 0;
+}
+
+static int
+smb_file_release(struct inode *inode, struct file * file)
+{
+ struct dentry * dentry = file->f_dentry;
+
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_file_release: closing %s/%s, d_count=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
+#endif
+
+ if (dentry->d_count == 1)
+ {
+ smb_close(inode);
+ }
+ return 0;
+}
+
+/*
+ * Check whether the required access is compatible with
+ * an inode's permission. SMB doesn't recognize superuser
+ * privileges, so we need our own check for this.
+ */
+static int
+smb_file_permission(struct inode *inode, int mask)
+{
+ int mode = inode->i_mode;
+ int error = 0;
+
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_file_permission: mode=%x, mask=%x\n", mode, mask);
+#endif
+ /* Look at user permissions */
+ mode >>= 6;
+ if ((mode & 7 & mask) != mask)
+ error = -EACCES;
+ return error;
+}
+
static struct file_operations smb_file_operations =
{
NULL, /* lseek - default */
@@ -305,10 +394,14 @@ static struct file_operations smb_file_operations =
NULL, /* readdir - bad */
NULL, /* poll - default */
smb_ioctl, /* ioctl */
- smb_file_mmap, /* mmap */
- NULL, /* open */
- NULL, /* release */
- smb_fsync, /* fsync */
+ smb_file_mmap, /* mmap(struct file*, struct vm_area_struct*) */
+ smb_file_open, /* open(struct inode*, struct file*) */
+ smb_file_release, /* release(struct inode*, struct file*) */
+ smb_fsync, /* fsync(struct file*, struct dentry*) */
+ NULL, /* fasync(struct file*, int) */
+ NULL, /* check_media_change(kdev_t dev) */
+ NULL, /* revalidate(kdev_t dev) */
+ NULL /* lock(struct file*, int, struct file_lock*) */
};
struct inode_operations smb_file_inode_operations =
@@ -329,7 +422,7 @@ struct inode_operations smb_file_inode_operations =
smb_writepage, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
- NULL, /* permission */
+ smb_file_permission, /* permission */
NULL, /* smap */
smb_updatepage, /* updatepage */
smb_revalidate_inode, /* revalidate */
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 9203650e2..b21892863 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -10,32 +10,31 @@
#include <linux/module.h>
#include <linux/sched.h>
-#include <linux/smb_fs.h>
-#include <linux/smbno.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/locks.h>
-#include <linux/file.h>
-#include <linux/fcntl.h>
#include <linux/malloc.h>
#include <linux/init.h>
+#include <linux/dcache.h>
+
+#include <linux/smb_fs.h>
+#include <linux/smbno.h>
+#include <linux/smb_mount.h>
#include <asm/system.h>
#include <asm/uaccess.h>
-#define SB_of(server) ((struct super_block *) ((char *)(server) - \
- (unsigned long)(&((struct super_block *)0)->u.smbfs_sb)))
-
-extern int close_fp(struct file *filp);
+#define SMBFS_PARANOIA 1
+/* #define SMBFS_DEBUG_VERBOSE 1 */
+static void smb_read_inode(struct inode *);
static void smb_put_inode(struct inode *);
static void smb_delete_inode(struct inode *);
-static void smb_read_inode(struct inode *);
static void smb_put_super(struct super_block *);
-static int smb_statfs(struct super_block *, struct statfs *, int);
+static int smb_statfs(struct super_block *, struct statfs *, int);
static struct super_operations smb_sops =
{
@@ -67,7 +66,7 @@ smb_invent_inos(unsigned long n)
return ino;
}
-static struct smb_fattr *read_fattr;
+static struct smb_fattr *read_fattr = NULL;
static struct semaphore read_semaphore = MUTEX;
struct inode *
@@ -80,14 +79,34 @@ smb_iget(struct super_block *sb, struct smb_fattr *fattr)
down(&read_semaphore);
read_fattr = fattr;
result = iget(sb, fattr->f_ino);
+ read_fattr = NULL;
up(&read_semaphore);
return result;
}
+/*
+ * Copy the inode data to a smb_fattr structure.
+ */
+void
+smb_get_inode_attr(struct inode *inode, struct smb_fattr *fattr)
+{
+ memset(fattr, 0, sizeof(struct smb_fattr));
+ fattr->f_mode = inode->i_mode;
+ fattr->f_nlink = inode->i_nlink;
+ fattr->f_uid = inode->i_uid;
+ fattr->f_gid = inode->i_gid;
+ fattr->f_rdev = inode->i_rdev;
+ fattr->f_size = inode->i_size;
+ fattr->f_mtime = inode->i_mtime;
+ fattr->f_ctime = inode->i_ctime;
+ fattr->f_atime = inode->i_atime;
+ fattr->f_blksize= inode->i_blksize;
+ fattr->f_blocks = inode->i_blocks;
+}
+
static void
smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr)
{
- inode->i_dev = inode->i_sb->s_dev;
inode->i_mode = fattr->f_mode;
inode->i_nlink = fattr->f_nlink;
inode->i_uid = fattr->f_uid;
@@ -99,6 +118,10 @@ smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr)
inode->i_atime = fattr->f_atime;
inode->i_blksize= fattr->f_blksize;
inode->i_blocks = fattr->f_blocks;
+ /*
+ * Update the "last time refreshed" field for revalidation.
+ */
+ inode->u.smbfs_i.oldmtime = jiffies;
}
static void
@@ -106,15 +129,15 @@ smb_read_inode(struct inode *inode)
{
pr_debug("smb_iget: %p\n", read_fattr);
- if ((atomic_read(&read_semaphore.count) == 1) ||
- (inode->i_ino != read_fattr->f_ino))
+ if (!read_fattr || inode->i_ino != read_fattr->f_ino)
{
printk("smb_read_inode called from invalid point\n");
return;
}
- smb_set_inode_attr(inode, read_fattr);
+ inode->i_dev = inode->i_sb->s_dev;
memset(&(inode->u.smbfs_i), 0, sizeof(inode->u.smbfs_i));
+ smb_set_inode_attr(inode, read_fattr);
if (S_ISREG(inode->i_mode))
inode->i_op = &smb_file_inode_operations;
@@ -131,59 +154,143 @@ smb_read_inode(struct inode *inode)
void
smb_invalidate_inodes(struct smb_sb_info *server)
{
- printk("smb_invalidate_inodes\n");
- shrink_dcache(); /* should shrink only this sb */
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_invalidate_inodes\n");
+#endif
+ shrink_dcache_sb(SB_of(server));
invalidate_inodes(SB_of(server));
}
+/*
+ * This is called when we want to check whether the inode
+ * has changed on the server. If it has changed, we must
+ * invalidate our local caches.
+ */
int
-smb_revalidate_inode(struct inode *ino)
+smb_revalidate_inode(struct inode *inode)
{
- struct dentry * dentry = ino->u.smbfs_i.dentry;
+ time_t last_time;
int error = 0;
pr_debug("smb_revalidate_inode\n");
- if (!ino)
- goto bad_no_inode;
- dentry = ino->u.smbfs_i.dentry;
-#if 0
- if (dentry)
+ /*
+ * If this is a file opened with write permissions,
+ * the inode will be up-to-date.
+ */
+ if (S_ISREG(inode->i_mode) && smb_is_open(inode)) {
+ if (inode->u.smbfs_i.access == SMB_O_RDWR ||
+ inode->u.smbfs_i.access == SMB_O_WRONLY)
+ goto out;
+ }
+
+ /*
+ * Check whether we've recently refreshed the inode.
+ */
+ if (jiffies < inode->u.smbfs_i.oldmtime + HZ/10)
{
- printk("smb_revalidate: checking %s/%s\n",
- dentry->d_parent->d_name.name, dentry->d_name.name);
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_revalidate_inode: up-to-date, jiffies=%lu, oldtime=%lu\n",
+jiffies, inode->u.smbfs_i.oldmtime);
+#endif
+ goto out;
}
+
+ /*
+ * Save the last modified time, then refresh the inode.
+ * (Note: a size change should have a different mtime.)
+ */
+ last_time = inode->i_mtime;
+ error = smb_refresh_inode(inode);
+ if (error || inode->i_mtime != last_time)
+ {
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_revalidate: %s/%s changed, old=%ld, new=%ld\n",
+((struct dentry *)inode->u.smbfs_i.dentry)->d_parent->d_name.name,
+((struct dentry *)inode->u.smbfs_i.dentry)->d_name.name,
+(long) last_time, (long) inode->i_mtime);
#endif
+ if (!S_ISDIR(inode->i_mode))
+ invalidate_inode_pages(inode);
+ else
+ smb_invalid_dir_cache(inode);
+ }
out:
return error;
-
-bad_no_inode:
- printk("smb_revalidate: no inode!\n");
- error = -EINVAL;
- goto out;
}
+/*
+ * This is called to update the inode attributes after
+ * we've made changes to a file or directory.
+ */
int
-smb_refresh_inode(struct inode *ino)
+smb_refresh_inode(struct inode *inode)
{
- struct dentry * dentry = ino->u.smbfs_i.dentry;
+ struct dentry * dentry = inode->u.smbfs_i.dentry;
struct smb_fattr fattr;
int error;
pr_debug("smb_refresh_inode\n");
- error = -EIO;
- if (!dentry) {
+ if (!dentry)
+ {
printk("smb_refresh_inode: no dentry, can't refresh\n");
+ error = -EIO;
goto out;
}
- /* N.B. Should check for changes of important fields! cf. NFS */
+ /*
+ * Kludge alert ... for some reason we can't get attributes
+ * for the root directory, so just return success.
+ */
+ error = 0;
+ if (IS_ROOT(dentry))
+ goto out;
+
error = smb_proc_getattr(dentry->d_parent, &(dentry->d_name), &fattr);
if (!error)
{
- smb_set_inode_attr(ino, &fattr);
+ smb_renew_times(dentry);
+ /*
+ * Check whether the type part of the mode changed,
+ * and don't update the attributes if it did.
+ */
+ if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT))
+ smb_set_inode_attr(inode, &fattr);
+ else
+ {
+ /*
+ * Big trouble! The inode has become a new object,
+ * so any operations attempted on it are invalid.
+ *
+ * Take a couple of steps to limit damage:
+ * (1) Mark the inode as bad so that subsequent
+ * lookup validations will fail.
+ * (2) Clear i_nlink so the inode will be released
+ * at iput() time. (Unhash it as well?)
+ * We also invalidate the caches for good measure.
+ */
+#ifdef SMBFS_PARANOIA
+printk("smb_refresh_inode: %s/%s changed mode, %07o to %07o\n",
+dentry->d_parent->d_name.name, dentry->d_name.name,
+inode->i_mode, fattr.f_mode);
+#endif
+ fattr.f_mode = inode->i_mode; /* save mode */
+ make_bad_inode(inode);
+ inode->i_mode = fattr.f_mode; /* restore mode */
+ /*
+ * No need to worry about unhashing the dentry: the
+ * lookup validation will see that the inode is bad.
+ * But we do want to invalidate the caches ...
+ */
+ if (!S_ISDIR(inode->i_mode))
+ invalidate_inode_pages(inode);
+ else
+ smb_invalid_dir_cache(inode);
+ error = -EIO;
+ }
}
out:
return error;
+
}
/*
@@ -192,19 +299,20 @@ out:
static void
smb_put_inode(struct inode *ino)
{
- struct dentry * dentry;
pr_debug("smb_put_inode: count = %d\n", ino->i_count);
if (ino->i_count > 1) {
+ struct dentry * dentry;
/*
* Check whether the dentry still holds this inode.
- * This looks scary, but should work ... d_inode is
- * cleared before iput() in the dcache.
+ * This looks scary, but should work ... if this is
+ * the last use, d_inode == NULL or d_count == 0.
*/
dentry = (struct dentry *) ino->u.smbfs_i.dentry;
- if (dentry && dentry->d_inode != ino) {
+ if (dentry && (dentry->d_inode != ino || dentry->d_count == 0))
+ {
ino->u.smbfs_i.dentry = NULL;
-#if 1
+#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_put_inode: cleared dentry for %s/%s (%ld), count=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name, ino->i_ino, ino->i_count);
#endif
@@ -248,6 +356,7 @@ smb_put_super(struct super_block *sb)
if (server->conn_pid)
kill_proc(server->conn_pid, SIGTERM, 0);
+ kfree(server->mnt);
if (server->packet)
smb_vfree(server->packet);
sb->s_dev = 0;
@@ -260,10 +369,9 @@ smb_put_super(struct super_block *sb)
struct super_block *
smb_read_super(struct super_block *sb, void *raw_data, int silent)
{
- struct smb_mount_data *data = (struct smb_mount_data *)raw_data;
+ struct smb_mount_data *mnt, *data = (struct smb_mount_data *) raw_data;
struct smb_fattr root;
kdev_t dev = sb->s_dev;
- unsigned char *packet;
struct inode *root_inode;
struct dentry *dentry;
@@ -275,62 +383,83 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent)
if (data->version != SMB_MOUNT_VERSION)
goto out_wrong_data;
- packet = smb_vmalloc(SMB_INITIAL_PACKET_SIZE);
- if (!packet)
- goto out_no_mem;
-
lock_super(sb);
sb->s_blocksize = 1024; /* Eh... Is this correct? */
sb->s_blocksize_bits = 10;
sb->s_magic = SMB_SUPER_MAGIC;
- sb->s_dev = dev;
+ sb->s_flags = 0;
+ sb->s_dev = dev; /* shouldn't need this ... */
sb->s_op = &smb_sops;
sb->u.smbfs_sb.sock_file = NULL;
sb->u.smbfs_sb.sem = MUTEX;
+ sb->u.smbfs_sb.wait = NULL;
sb->u.smbfs_sb.conn_pid = 0;
- sb->u.smbfs_sb.packet = packet;
- sb->u.smbfs_sb.packet_size = SMB_INITIAL_PACKET_SIZE;
+ sb->u.smbfs_sb.state = CONN_INVALID; /* no connection yet */
sb->u.smbfs_sb.generation = 0;
+ sb->u.smbfs_sb.packet_size = smb_round_length(SMB_INITIAL_PACKET_SIZE);
+ sb->u.smbfs_sb.packet = smb_vmalloc(sb->u.smbfs_sb.packet_size);
+ if (!sb->u.smbfs_sb.packet)
+ goto out_no_mem;
- sb->u.smbfs_sb.m = *data;
- sb->u.smbfs_sb.m.file_mode = (sb->u.smbfs_sb.m.file_mode &
- (S_IRWXU | S_IRWXG | S_IRWXO)) | S_IFREG;
- sb->u.smbfs_sb.m.dir_mode = (sb->u.smbfs_sb.m.dir_mode &
- (S_IRWXU | S_IRWXG | S_IRWXO)) | S_IFDIR;
+ mnt = kmalloc(sizeof(struct smb_mount_data), GFP_KERNEL);
+ if (!mnt)
+ goto out_no_mount;
+ *mnt = *data;
+ /* ** temp ** pass config flags in file mode */
+ mnt->version = (mnt->file_mode >> 9);
+#ifdef CONFIG_SMB_WIN95
+ mnt->version |= SMB_FIX_WIN95;
+#endif
+ mnt->file_mode &= (S_IRWXU | S_IRWXG | S_IRWXO);
+ mnt->file_mode |= S_IFREG;
+ mnt->dir_mode &= (S_IRWXU | S_IRWXG | S_IRWXO);
+ mnt->dir_mode |= S_IFDIR;
+ sb->u.smbfs_sb.mnt = mnt;
+ /*
+ * Display the enabled options
+ */
+ if (mnt->version & SMB_FIX_WIN95)
+ printk("SMBFS: Win 95 bug fixes enabled\n");
+ if (mnt->version & SMB_FIX_OLDATTR)
+ printk("SMBFS: Using core getattr (Win 95 speedup)\n");
+ /*
+ * Keep the super block locked while we get the root inode.
+ */
smb_init_root_dirent(&(sb->u.smbfs_sb), &root);
-
- sb->s_root = NULL;
- unlock_super(sb);
-
root_inode = smb_iget(sb, &root);
if (!root_inode)
goto out_no_root;
+
dentry = d_alloc_root(root_inode, NULL);
if (!dentry)
goto out_no_root;
root_inode->u.smbfs_i.dentry = dentry;
sb->s_root = dentry;
+
+ unlock_super(sb);
return sb;
-out_no_data:
- printk("smb_read_super: missing data argument\n");
- goto out;
-out_wrong_data:
- printk(KERN_ERR "smb_read_super: wrong data argument."
- " Recompile smbmount.\n");
- goto out;
-out_no_mem:
- pr_debug("smb_read_super: could not alloc packet\n");
- goto out;
out_no_root:
- sb->s_dev = 0; /* iput() might block */
printk(KERN_ERR "smb_read_super: get root inode failed\n");
iput(root_inode);
- smb_vfree(packet);
-out:
+ kfree(sb->u.smbfs_sb.mnt);
+out_no_mount:
+ smb_vfree(sb->u.smbfs_sb.packet);
+ goto out_unlock;
+out_no_mem:
+ printk("smb_read_super: could not alloc packet\n");
+out_unlock:
+ unlock_super(sb);
+ goto out_fail;
+out_wrong_data:
+ printk("smb_read_super: need mount version %d\n", SMB_MOUNT_VERSION);
+ goto out_fail;
+out_no_data:
+ printk("smb_read_super: missing data argument\n");
+out_fail:
sb->s_dev = 0;
MOD_DEC_USE_COUNT;
return NULL;
@@ -355,8 +484,10 @@ smb_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
int
smb_notify_change(struct inode *inode, struct iattr *attr)
{
+ struct smb_sb_info *server = SMB_SERVER(inode);
struct dentry *dentry = inode->u.smbfs_i.dentry;
- int error;
+ unsigned int mask = (S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO);
+ int error, refresh = 0;
error = -EIO;
if (!dentry)
@@ -365,49 +496,53 @@ smb_notify_change(struct inode *inode, struct iattr *attr)
goto out;
}
+ error = smb_revalidate_inode(inode);
+ if (error)
+ goto out;
+
if ((error = inode_change_ok(inode, attr)) < 0)
goto out;
error = -EPERM;
- if (((attr->ia_valid & ATTR_UID) &&
- (attr->ia_uid != SMB_SERVER(inode)->m.uid)))
+ if ((attr->ia_valid & ATTR_UID) && (attr->ia_uid != server->mnt->uid))
goto out;
- if (((attr->ia_valid & ATTR_GID) &&
- (attr->ia_uid != SMB_SERVER(inode)->m.gid)))
+ if ((attr->ia_valid & ATTR_GID) && (attr->ia_uid != server->mnt->gid))
goto out;
- if (((attr->ia_valid & ATTR_MODE) &&
- (attr->ia_mode & ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO))))
+ if ((attr->ia_valid & ATTR_MODE) && (attr->ia_mode & ~mask))
goto out;
- /*
- * Assume success and invalidate the parent's dir cache
- */
- smb_invalid_dir_cache(dentry->d_parent->d_inode);
-
if ((attr->ia_valid & ATTR_SIZE) != 0)
{
- if ((error = smb_open(dentry, O_WRONLY)) < 0)
+ error = smb_open(dentry, O_WRONLY);
+ if (error)
goto out;
-
- if ((error = smb_proc_trunc(SMB_SERVER(inode),
- inode->u.smbfs_i.fileid,
- attr->ia_size)) < 0)
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_notify_change: changing %s/%s, old size=%ld, new size=%ld\n",
+dentry->d_parent->d_name.name, dentry->d_name.name,
+(long) inode->i_size, (long) attr->ia_size);
+#endif
+ error = smb_proc_trunc(server, inode->u.smbfs_i.fileid,
+ attr->ia_size);
+ if (error)
goto out;
+ /*
+ * We don't implement an i_op->truncate operation,
+ * so we have to update the page cache here.
+ */
+ if (attr->ia_size < inode->i_size) {
+ truncate_inode_pages(inode, attr->ia_size);
+ inode->i_size = attr->ia_size;
+ }
+ refresh = 1;
}
+
if ((attr->ia_valid & (ATTR_CTIME | ATTR_MTIME | ATTR_ATIME)) != 0)
{
-
struct smb_fattr fattr;
- fattr.attr = 0;
- fattr.f_size = inode->i_size;
- fattr.f_blksize = inode->i_blksize;
- fattr.f_ctime = inode->i_ctime;
- fattr.f_mtime = inode->i_mtime;
- fattr.f_atime = inode->i_atime;
-
+ smb_get_inode_attr(inode, &fattr);
if ((attr->ia_valid & ATTR_CTIME) != 0)
fattr.f_ctime = attr->ia_ctime;
@@ -417,15 +552,16 @@ smb_notify_change(struct inode *inode, struct iattr *attr)
if ((attr->ia_valid & ATTR_ATIME) != 0)
fattr.f_atime = attr->ia_atime;
- error = smb_proc_setattr(SMB_SERVER(inode), dentry, &fattr);
- if (error >= 0)
- {
- inode->i_ctime = fattr.f_ctime;
- inode->i_mtime = fattr.f_mtime;
- inode->i_atime = fattr.f_atime;
- }
+ error = smb_proc_setattr(server, dentry, &fattr);
+ if (error)
+ goto out;
+ refresh = 1;
}
+ error = 0;
+
out:
+ if (refresh)
+ smb_refresh_inode(inode);
return error;
}
@@ -461,7 +597,6 @@ init_module(void)
smb_current_vmalloced = 0;
#endif
- smb_init_dir_cache();
read_semaphore = MUTEX;
return init_smb_fs();
@@ -471,7 +606,6 @@ void
cleanup_module(void)
{
pr_debug("smbfs: cleanup_module called\n");
- smb_free_dir_cache();
unregister_filesystem(&smb_fs_type);
#ifdef DEBUG_SMB_MALLOC
printk(KERN_DEBUG "smb_malloced: %d\n", smb_malloced);
diff --git a/fs/smbfs/ioctl.c b/fs/smbfs/ioctl.c
index 45bebd2fe..5eb3dc88f 100644
--- a/fs/smbfs/ioctl.c
+++ b/fs/smbfs/ioctl.c
@@ -8,10 +8,11 @@
#include <linux/errno.h>
#include <linux/fs.h>
-#include <linux/smb_fs.h>
#include <linux/ioctl.h>
#include <linux/sched.h>
#include <linux/mm.h>
+#include <linux/smb_fs.h>
+#include <linux/smb_mount.h>
#include <asm/uaccess.h>
@@ -19,33 +20,33 @@ int
smb_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
+ int result = -EINVAL;
+
switch (cmd)
{
case SMB_IOC_GETMOUNTUID:
- return put_user(SMB_SERVER(inode)->m.mounted_uid,
+ result = put_user(SMB_SERVER(inode)->mnt->mounted_uid,
(uid_t *) arg);
+ break;
case SMB_IOC_NEWCONN:
{
struct smb_conn_opt opt;
- int result;
if (arg == 0)
{
/* The process offers a new connection upon SIGUSR1 */
- return smb_offerconn(SMB_SERVER(inode));
+ result = smb_offerconn(SMB_SERVER(inode));
}
-
- if ((result = verify_area(VERIFY_READ, (uid_t *) arg,
- sizeof(opt))) != 0)
+ else
{
- return result;
+ result = -EFAULT;
+ if (!copy_from_user(&opt, (void *)arg, sizeof(opt)))
+ result = smb_newconn(SMB_SERVER(inode), &opt);
}
- copy_from_user(&opt, (void *)arg, sizeof(opt));
-
- return smb_newconn(SMB_SERVER(inode), &opt);
+ break;
}
default:
- return -EINVAL;
}
+ return result;
}
diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c
index 57b4be6fb..966ee1e27 100644
--- a/fs/smbfs/proc.c
+++ b/fs/smbfs/proc.c
@@ -5,21 +5,30 @@
* Copyright (C) 1997 by Volker Lendecke
*
* 28/06/96 - Fixed long file name support (smb_proc_readdir_long) by Yuri Per
+ * 28/09/97 - Fixed smb_d_path [now smb_build_path()] to be non-recursive
+ * by Riccardo Facchetti
*/
-#include <linux/config.h>
#include <linux/fs.h>
-#include <linux/smbno.h>
-#include <linux/smb_fs.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/malloc.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
+#include <linux/dcache.h>
+#include <linux/dirent.h>
+
+#include <linux/smb_fs.h>
+#include <linux/smbno.h>
+#include <linux/smb_mount.h>
-#include <asm/uaccess.h>
#include <asm/string.h>
+#define SMBFS_PARANOIA 1
+/* #define SMBFS_DEBUG_TIMESTAMP 1 */
+/* #define SMBFS_DEBUG_VERBOSE 1 */
+/* #define pr_debug printk */
+
#define SMB_VWV(packet) ((packet) + SMB_HEADER_LEN)
#define SMB_CMD(packet) (*(packet+8))
#define SMB_WCT(packet) (*(packet+SMB_HEADER_LEN - 1))
@@ -29,12 +38,8 @@
#define SMB_DIRINFO_SIZE 43
#define SMB_STATUS_SIZE 21
-#define SMBFS_PARANOIA 1
-/* #define SMBFS_DEBUG_VERBOSE 1 */
-/* #define pr_debug printk */
-
-static int smb_request_ok(struct smb_sb_info *s, int command, int wct, int bcc);
-void smb_close_socket(struct smb_sb_info *);
+static int smb_proc_setfile_trans2(struct smb_sb_info *, struct inode *,
+ struct smb_fattr *);
static inline int
min(int a, int b)
@@ -43,9 +48,9 @@ min(int a, int b)
}
static void
-str_upper(char *name)
+str_upper(char *name, int len)
{
- while (*name)
+ while (len--)
{
if (*name >= 'a' && *name <= 'z')
*name -= ('a' - 'A');
@@ -54,9 +59,9 @@ str_upper(char *name)
}
static void
-str_lower(char *name)
+str_lower(char *name, int len)
{
- while (*name)
+ while (len--)
{
if (*name >= 'A' && *name <= 'Z')
*name += ('a' - 'A');
@@ -64,6 +69,17 @@ str_lower(char *name)
}
}
+static void reverse_string(char *buf, int len) {
+ char c;
+ char *end = buf+len-1;
+
+ while(buf < end) {
+ c = *buf;
+ *(buf++) = *end;
+ *(end--) = c;
+ }
+}
+
/*****************************************************************************/
/* */
/* Encoding/Decoding section */
@@ -85,30 +101,55 @@ smb_encode_smb_length(__u8 * p, __u32 len)
}
/*
- * Return the server for the specified dentry
- * N.B. Make this a #define in the smb header
+ * smb_build_path: build the path to entry and name storing it in buf.
+ * The path returned will have the trailing '\0'.
*/
-static struct smb_sb_info * server_from_dentry(struct dentry * dentry)
+static int smb_build_path(struct dentry * entry, struct qstr * name, char * buf)
{
- return &dentry->d_sb->u.smbfs_sb;
-}
+ char *path = buf;
-static int smb_d_path(struct dentry * entry, char * buf)
-{
+ if (entry == NULL)
+ goto test_name_and_out;
+
+ /*
+ * If IS_ROOT, we have to do no walking at all.
+ */
if (IS_ROOT(entry)) {
- *buf = '\\';
- return 1;
- } else {
- int len = smb_d_path(entry->d_parent, buf);
-
- buf += len;
- if (len > 1) {
- *buf++ = '\\';
- len++;
- }
- memcpy(buf, entry->d_name.name, entry->d_name.len);
- return len + entry->d_name.len;
+ *(path++) = '\\';
+ if (name != NULL)
+ goto name_and_out;
+ goto out;
}
+
+ /*
+ * Build the path string walking the tree backward from end to ROOT
+ * and store it in reversed order [see reverse_string()]
+ */
+ for (;;) {
+ memcpy(path, entry->d_name.name, entry->d_name.len);
+ reverse_string(path, entry->d_name.len);
+ path += entry->d_name.len;
+
+ *(path++) = '\\';
+
+ entry = entry->d_parent;
+
+ if (IS_ROOT(entry))
+ break;
+ }
+
+ reverse_string(buf, path-buf);
+
+test_name_and_out:
+ if (name != NULL) {
+ *(path++) = '\\';
+name_and_out:
+ memcpy(path, name->name, name->len);
+ path += name->len;
+ }
+out:
+ *(path++) = '\0';
+ return (path-buf);
}
static char *smb_encode_path(struct smb_sb_info *server, char *buf,
@@ -116,18 +157,10 @@ static char *smb_encode_path(struct smb_sb_info *server, char *buf,
{
char *start = buf;
- if (dir != NULL)
- buf += smb_d_path(dir, buf);
-
- if (name != NULL) {
- *buf++ = '\\';
- memcpy(buf, name->name, name->len);
- buf += name->len;
- *buf++ = 0;
- }
+ buf += smb_build_path(dir, name, buf);
if (server->opt.protocol <= SMB_PROTOCOL_COREPLUS)
- str_upper(start);
+ str_upper(start, buf - start);
return buf;
}
@@ -143,24 +176,25 @@ static int day_n[] =
extern struct timezone sys_tz;
-static int
-utc2local(int time)
+static time_t
+utc2local(time_t time)
{
return time - sys_tz.tz_minuteswest * 60;
}
-static int
-local2utc(int time)
+static time_t
+local2utc(time_t time)
{
return time + sys_tz.tz_minuteswest * 60;
}
/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
-static int
-date_dos2unix(unsigned short time, unsigned short date)
+static time_t
+date_dos2unix(__u16 date, __u16 time)
{
- int month, year, secs;
+ int month, year;
+ time_t secs;
month = ((date >> 5) & 15) - 1;
year = date >> 9;
@@ -175,14 +209,15 @@ date_dos2unix(unsigned short time, unsigned short date)
/* Convert linear UNIX date to a MS-DOS time/date pair. */
static void
-date_unix2dos(int unix_date, __u8 * date, __u8 * time)
+date_unix2dos(int unix_date, __u16 *date, __u16 *time)
{
int day, year, nl_day, month;
unix_date = utc2local(unix_date);
- WSET(time, 0,
- (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) +
- (((unix_date / 3600) % 24) << 11));
+ *time = (unix_date % 60) / 2 +
+ (((unix_date / 60) % 60) << 5) +
+ (((unix_date / 3600) % 24) << 11);
+
day = unix_date / 86400 - 3652;
year = day / 365;
if ((year + 3) / 4 + 365 * year > day)
@@ -199,12 +234,10 @@ date_unix2dos(int unix_date, __u8 * date, __u8 * time)
if (day_n[month] > nl_day)
break;
}
- WSET(date, 0,
- nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9));
+ *date = nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9);
}
-
/*****************************************************************************/
/* */
/* Support section. */
@@ -244,21 +277,91 @@ smb_valid_packet(__u8 * packet)
static int
smb_verify(__u8 * packet, int command, int wct, int bcc)
{
- return (SMB_CMD(packet) == command &&
- SMB_WCT(packet) >= wct &&
- (bcc == -1 || SMB_BCC(packet) >= bcc)) ? 0 : -EIO;
+ if (SMB_CMD(packet) != command)
+ goto bad_command;
+ if (SMB_WCT(packet) < wct)
+ goto bad_wct;
+ if (bcc != -1 && SMB_BCC(packet) < bcc)
+ goto bad_bcc;
+ return 0;
+
+bad_command:
+ printk("smb_verify: command=%x, SMB_CMD=%x??\n",
+ command, SMB_CMD(packet));
+ goto fail;
+bad_wct:
+ printk("smb_verify: command=%x, wct=%d, SMB_WCT=%d??\n",
+ command, wct, SMB_WCT(packet));
+ goto fail;
+bad_bcc:
+ printk("smb_verify: command=%x, bcc=%d, SMB_BCC=%d??\n",
+ command, bcc, SMB_BCC(packet));
+fail:
+ return -EIO;
}
+/*
+ * Returns the maximum read or write size for the current packet size
+ * and max_xmit value.
+ * N.B. Since this value is usually computed before locking the server,
+ * the server's packet size must never be decreased!
+ */
static int
-smb_errno(int errcls, int error)
+smb_get_xmitsize(struct smb_sb_info *server, int overhead)
+{
+ int size = server->packet_size;
+
+ /*
+ * Start with the smaller of packet size and max_xmit ...
+ */
+ if (size > server->opt.max_xmit)
+ size = server->opt.max_xmit;
+ return size - overhead;
+}
+
+/*
+ * Calculate the maximum read size
+ */
+int
+smb_get_rsize(struct smb_sb_info *server)
{
+ int overhead = SMB_HEADER_LEN + 5 * sizeof(__u16) + 2 + 1 + 2;
+ int size = smb_get_xmitsize(server, overhead);
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_get_rsize: packet=%d, xmit=%d, size=%d\n",
+server->packet_size, server->opt.max_xmit, size);
+#endif
+ return size;
+}
+
+/*
+ * Calculate the maximum write size
+ */
+int
+smb_get_wsize(struct smb_sb_info *server)
+{
+ int overhead = SMB_HEADER_LEN + 5 * sizeof(__u16) + 2 + 1 + 2;
+ int size = smb_get_xmitsize(server, overhead);
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_get_wsize: packet=%d, xmit=%d, size=%d\n",
+server->packet_size, server->opt.max_xmit, size);
+#endif
+ return size;
+}
+
+static int
+smb_errno(struct smb_sb_info *server)
+{
+ int errcls = server->rcls;
+ int error = server->err;
+ char *class = "Unknown";
+
if (errcls == ERRDOS)
switch (error)
{
case ERRbadfunc:
return EINVAL;
case ERRbadfile:
- return ENOENT;
case ERRbadpath:
return ENOENT;
case ERRnofids:
@@ -274,7 +377,6 @@ smb_errno(int errcls, int error)
case ERRbadmem:
return EFAULT;
case ERRbadenv:
- return EREMOTEIO;
case ERRbadformat:
return EREMOTEIO;
case ERRbadaccess:
@@ -287,7 +389,7 @@ smb_errno(int errcls, int error)
return EREMOTEIO;
case ERRdiffdevice:
return EXDEV;
- case ERRnofiles:
+ case ERRnofiles: /* Why is this mapped to 0?? */
return 0;
case ERRbadshare:
return ETXTBSY;
@@ -295,18 +397,19 @@ smb_errno(int errcls, int error)
return EDEADLK;
case ERRfilexists:
return EEXIST;
- case 87:
+ case 87: /* should this map to 0?? */
return 0; /* Unknown error!! */
case 123: /* Invalid name?? e.g. .tmp* */
return ENOENT;
+ case 145: /* Win NT 4.0: non-empty directory? */
+ return EBUSY;
/* This next error seems to occur on an mv when
* the destination exists */
case 183:
return EEXIST;
default:
- printk("smb_errno: ERRDOS code %d, returning EIO\n",
- error);
- return EIO;
+ class = "ERRDOS";
+ goto err_unknown;
} else if (errcls == ERRSRV)
switch (error)
{
@@ -319,9 +422,8 @@ smb_errno(int errcls, int error)
case ERRaccess:
return EACCES;
default:
- printk("smb_errno: ERRSRV code %d, returning EIO\n",
- error);
- return EIO;
+ class = "ERRSRV";
+ goto err_unknown;
} else if (errcls == ERRHRD)
switch (error)
{
@@ -332,7 +434,6 @@ smb_errno(int errcls, int error)
case ERRnotready:
return EUCLEAN;
case ERRbadcmd:
- return EIO;
case ERRdata:
return EIO;
case ERRbadreq:
@@ -342,15 +443,15 @@ smb_errno(int errcls, int error)
case ERRlock:
return EDEADLK;
default:
- printk("smb_errno: ERRHRD code %d, returning EIO\n",
- error);
- return EIO;
+ class = "ERRHRD";
+ goto err_unknown;
} else if (errcls == ERRCMD)
- {
- printk("smb_errno: ERRCMD code %d, returning EIO\n", error);
- return EIO;
- }
- return 0;
+ class = "ERRCMD";
+
+err_unknown:
+ printk("smb_errno: class %s, code %d from command %x\n",
+ class, error, SMB_CMD(server->packet));
+ return EIO;
}
static inline void
@@ -365,38 +466,6 @@ smb_unlock_server(struct smb_sb_info *server)
up(&(server->sem));
}
-/* smb_request_ok: We expect the server to be locked. Then we do the
- request and check the answer completely. When smb_request_ok
- returns 0, you can be quite sure that everything went well. When
- the answer is <=0, the returned number is a valid unix errno. */
-
-static int
-smb_request_ok(struct smb_sb_info *s, int command, int wct, int bcc)
-{
- int result = 0;
-
- s->rcls = 0;
- s->err = 0;
-
- if (smb_request(s) < 0)
- {
- pr_debug("smb_request failed\n");
- result = -EIO;
- } else if (smb_valid_packet(s->packet) != 0)
- {
- pr_debug("not a valid packet!\n");
- result = -EIO;
- } else if (s->rcls != 0)
- {
- result = -smb_errno(s->rcls, s->err);
- } else if (smb_verify(s->packet, command, wct, bcc) != 0)
- {
- pr_debug("smb_verify failed\n");
- result = -EIO;
- }
- return result;
-}
-
/*
* smb_retry: This function should be called when smb_request_ok has
indicated an error. If the error was indicated because the
@@ -409,6 +478,8 @@ smb_request_ok(struct smb_sb_info *s, int command, int wct, int bcc)
static int
smb_retry(struct smb_sb_info *server)
{
+ struct wait_queue wait = { current, NULL };
+ unsigned long timeout;
int result = 0;
if (server->state != CONN_INVALID)
@@ -423,23 +494,106 @@ smb_retry(struct smb_sb_info *server)
goto out;
}
- printk("smb_retry: signalling process %d\n", server->conn_pid);
kill_proc(server->conn_pid, SIGUSR1, 0);
+#if 0
server->conn_pid = 0;
+#endif
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_retry: signalled pid %d, waiting for new connection\n",
+server->conn_pid);
+#endif
/*
- * Block here until we get a new connection.
- * N.B. This needs to be fixed ... we should wait in an
- * interruptible sleep for CONN_VALID.
+ * Wait here for a new connection.
*/
- printk("smb_retry: blocking for new connection\n");
- smb_lock_server(server);
+ timeout = jiffies + 10*HZ;
+ add_wait_queue(&server->wait, &wait);
+ while (1)
+ {
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + HZ;
+ if (server->state != CONN_INVALID)
+ break;
+ if (jiffies > timeout)
+ {
+ printk("smb_retry: timed out, try again later\n");
+ break;
+ }
+ if (signal_pending(current))
+ {
+ printk("smb_retry: caught signal\n");
+ break;
+ }
+ schedule();
+ }
+ remove_wait_queue(&server->wait, &wait);
+ current->timeout = 0;
+ current->state = TASK_RUNNING;
if (server->state == CONN_VALID)
{
- printk("smb_retry: new connection pid=%d\n", server->conn_pid);
+#ifdef SMBFS_PARANOIA
+printk("smb_retry: new connection pid=%d\n", server->conn_pid);
+#endif
result = 1;
}
+
+out:
+ return result;
+}
+
+/* smb_request_ok: We expect the server to be locked. Then we do the
+ request and check the answer completely. When smb_request_ok
+ returns 0, you can be quite sure that everything went well. When
+ the answer is <=0, the returned number is a valid unix errno. */
+
+static int
+smb_request_ok(struct smb_sb_info *s, int command, int wct, int bcc)
+{
+ int result = -EIO;
+
+ s->rcls = 0;
+ s->err = 0;
+
+ /* Make sure we have a connection */
+ if (s->state != CONN_VALID)
+ {
+ if (!smb_retry(s))
+ goto out;
+ }
+
+ if (smb_request(s) < 0)
+ {
+ pr_debug("smb_request failed\n");
+ goto out;
+ }
+ if (smb_valid_packet(s->packet) != 0)
+ {
+#ifdef SMBFS_PARANOIA
+printk("smb_request_ok: invalid packet!\n");
+#endif
+ goto out;
+ }
+
+ /*
+ * Check for server errors. The current smb_errno() routine
+ * is squashing some error codes, but I don't think this is
+ * correct: after a server error the packet won't be valid.
+ */
+ if (s->rcls != 0)
+ {
+ result = -smb_errno(s);
+ if (!result)
+ printk("smb_request_ok: rcls=%d, err=%d mapped to 0\n",
+ s->rcls, s->err);
+ /*
+ * Exit now even if the error was squashed ...
+ * packet verify will fail anyway.
+ */
+ goto out;
+ }
+ result = smb_verify(s->packet, command, wct, bcc);
+
out:
return result;
}
@@ -447,7 +601,7 @@ out:
/*
* This is called with the server locked after a successful smb_newconn().
* It installs the new connection pid, sets server->state to CONN_VALID,
- * and unlocks the server.
+ * and wakes up the process waiting for the new connection.
* N.B. The first call is made without locking the server -- need to fix!
*/
int
@@ -456,23 +610,26 @@ smb_offerconn(struct smb_sb_info *server)
int error;
error = -EACCES;
- if (!suser() && (current->uid != server->m.mounted_uid))
+ if ((current->uid != server->mnt->mounted_uid) && !suser())
goto out;
+ if (atomic_read(&server->sem.count) == 1)
+ {
+ printk("smb_offerconn: server not locked, count=%d\n",
+ atomic_read(&server->sem.count));
+#if 0
+ goto out;
+#endif
+ }
server->conn_pid = current->pid;
server->state = CONN_VALID;
- printk("smb_offerconn: state valid, pid=%d\n", server->conn_pid);
+ wake_up_interruptible(&server->wait);
+#ifdef SMBFS_PARANOIA
+printk("smb_offerconn: state valid, pid=%d\n", server->conn_pid);
+#endif
error = 0;
- /*
- * The initial call may be made without the server locked?
- */
out:
- if (atomic_read(&server->sem.count) != 1)
- smb_unlock_server(server);
- else
- printk("smb_offerconn: server not locked, count=%d\n",
- atomic_read(&server->sem.count));
return error;
}
@@ -488,15 +645,21 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt)
error = -EBADF;
if (opt->fd >= NR_OPEN || !(filp = current->files->fd[opt->fd]))
- goto out_unlock;
- if (!S_ISSOCK(filp->f_dentry->d_inode->i_mode))
- goto out_unlock;
- if (!S_ISSOCK(filp->f_dentry->d_inode->i_mode))
- goto out_unlock;
+ goto out;
+ if (!smb_valid_socket(filp->f_dentry->d_inode))
+ goto out;
error = -EACCES;
- if (!suser() && (current->uid != server->m.mounted_uid))
- goto out_unlock;
+ if ((current->uid != server->mnt->mounted_uid) && !suser())
+ goto out;
+ if (atomic_read(&server->sem.count) == 1)
+ {
+ printk("smb_newconn: server not locked, count=%d\n",
+ atomic_read(&server->sem.count));
+#if 0
+ goto out;
+#endif
+ }
/*
* Make sure the old socket is closed
@@ -507,23 +670,15 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt)
server->sock_file = filp;
smb_catch_keepalive(server);
server->opt = *opt;
- pr_debug("smb_newconn: protocol = %d\n", server->opt.protocol);
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_newconn: protocol=%d, max_xmit=%d\n",
+server->opt.protocol, server->opt.max_xmit);
+#endif
server->generation += 1;
error = 0;
out:
return error;
-
- /*
- * Unlock now if an error occurred.
- */
-out_unlock:
- if (atomic_read(&server->sem.count) != 1)
- smb_unlock_server(server);
- else
- printk("smb_newconn: server not locked, count=%d\n",
- atomic_read(&server->sem.count));
- goto out;
}
/* smb_setup_header: We completely set up the packet. You only have to
@@ -536,6 +691,10 @@ smb_setup_header(struct smb_sb_info * server, __u8 command, __u16 wct, __u16 bcc
__u8 *p = server->packet;
__u8 *buf = server->packet;
+if (xmit_len > server->packet_size)
+printk("smb_setup_header: Aieee, xmit len > packet! len=%d, size=%d\n",
+xmit_len, server->packet_size);
+
p = smb_encode_smb_length(p, xmit_len - 4);
*p++ = 0xff;
@@ -577,117 +736,202 @@ smb_setup_bcc(struct smb_sb_info *server, __u8 * p)
}
/*
- * We're called with the server locked, and we leave it that way. We
- * try maximum permissions.
+ * We're called with the server locked, and we leave it that way.
*/
-
static int
-smb_proc_open(struct smb_sb_info *server, struct dentry *dir)
+smb_proc_open(struct smb_sb_info *server, struct dentry *dentry, int wish)
{
- struct inode *ino = dir->d_inode;
+ struct inode *ino = dentry->d_inode;
+ int mode, read_write = 0x42, read_only = 0x40;
int error;
char *p;
+ /*
+ * Attempt to open r/w, unless there are no write privileges.
+ */
+ mode = read_write;
+ if (!(ino->i_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
+ mode = read_only;
+#if 0
+ if (!(wish & (O_WRONLY | O_RDWR)))
+ mode = read_only;
+#endif
+
retry:
p = smb_setup_header(server, SMBopen, 2, 0);
- WSET(server->packet, smb_vwv0, 0x42); /* read/write */
+ WSET(server->packet, smb_vwv0, mode);
WSET(server->packet, smb_vwv1, aSYSTEM | aHIDDEN | aDIR);
*p++ = 4;
- p = smb_encode_path(server, p, dir, NULL);
+ p = smb_encode_path(server, p, dentry, NULL);
smb_setup_bcc(server, p);
- if ((error = smb_request_ok(server, SMBopen, 7, 0)) != 0)
+ error = smb_request_ok(server, SMBopen, 7, 0);
+ if (error != 0)
{
if (smb_retry(server))
goto retry;
- if ((error != -EACCES) && (error != -ETXTBSY)
- && (error != -EROFS))
- goto out;
-
- p = smb_setup_header(server, SMBopen, 2, 0);
- WSET(server->packet, smb_vwv0, 0x40); /* read only */
- WSET(server->packet, smb_vwv1, aSYSTEM | aHIDDEN | aDIR);
- *p++ = 4;
- p = smb_encode_path(server, p, dir, NULL);
- smb_setup_bcc(server, p);
-
- if ((error = smb_request_ok(server, SMBopen, 7, 0)) != 0)
+ if (mode == read_write &&
+ (error == -EACCES || error == -ETXTBSY || error == -EROFS))
{
- if (smb_retry(server))
- goto retry;
- goto out;
+#ifdef SMBFS_PARANOIA
+printk("smb_proc_open: %s/%s R/W failed, error=%d, retrying R/O\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, error);
+#endif
+ mode = read_only;
+ goto retry;
}
}
/* We should now have data in vwv[0..6]. */
ino->u.smbfs_i.fileid = WVAL(server->packet, smb_vwv0);
ino->u.smbfs_i.attr = WVAL(server->packet, smb_vwv1);
+ /* smb_vwv2 has mtime */
+ /* smb_vwv4 has size */
ino->u.smbfs_i.access = WVAL(server->packet, smb_vwv6);
- ino->u.smbfs_i.access &= 3;
+ ino->u.smbfs_i.access &= SMB_ACCMASK;
+ /* N.B. Suppose the open failed?? */
ino->u.smbfs_i.open = server->generation;
- pr_debug("smb_proc_open: entry->access = %d\n", ino->u.smbfs_i.access);
-out:
+#ifdef SMBFS_PARANOIA
+if (error)
+printk("smb_proc_open: %s/%s failed, error=%d, access=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name,error,ino->u.smbfs_i.access);
+#endif
return error;
}
+/*
+ * Make sure the file is open, and check that the access
+ * is compatible with the desired access.
+ */
int
-smb_open(struct dentry *dir, int wish)
+smb_open(struct dentry *dentry, int wish)
{
- struct inode *i = dir->d_inode;
+ struct inode *inode = dentry->d_inode;
int result;
- result = -EIO;
- if (!i)
+ result = -ENOENT;
+ if (!inode)
{
printk("smb_open: no inode for dentry %s/%s\n",
- dir->d_parent->d_name.name, dir->d_name.name);
+ dentry->d_parent->d_name.name, dentry->d_name.name);
goto out;
}
/*
- * If the inode is already open, we don't need to lock the server.
+ * Note: If the caller holds an active dentry and the file is
+ * currently open, we can be sure that the file isn't about
+ * to be closed. (See smb_close_dentry() below.)
*/
- if (!smb_is_open(i))
+ if (!smb_is_open(inode))
{
- struct smb_sb_info *server = SMB_SERVER(i);
+ struct smb_sb_info *server = SMB_SERVER(inode);
smb_lock_server(server);
- result = smb_proc_open(server, dir);
+ result = 0;
+ if (!smb_is_open(inode))
+ result = smb_proc_open(server, dentry, wish);
smb_unlock_server(server);
if (result)
{
- printk("smb_open: %s/%s open failed, result=%d\n",
- dir->d_parent->d_name.name, dir->d_name.name,
- result);
+#ifdef SMBFS_PARANOIA
+printk("smb_open: %s/%s open failed, result=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, result);
+#endif
goto out;
}
+ /*
+ * A successful open means the path is still valid ...
+ */
+ smb_renew_times(dentry);
}
- result = -EACCES;
- if (((wish == O_RDONLY) && ((i->u.smbfs_i.access == O_RDONLY)
- || (i->u.smbfs_i.access == O_RDWR)))
- || ((wish == O_WRONLY) && ((i->u.smbfs_i.access == O_WRONLY)
- || (i->u.smbfs_i.access == O_RDWR)))
- || ((wish == O_RDWR) && (i->u.smbfs_i.access == O_RDWR)))
- result = 0;
-
+ /*
+ * Check whether the access is compatible with the desired mode.
+ */
+ result = 0;
+ if (inode->u.smbfs_i.access != wish &&
+ inode->u.smbfs_i.access != SMB_O_RDWR)
+ {
+#ifdef SMBFS_PARANOIA
+printk("smb_open: %s/%s access denied, access=%x, wish=%x\n",
+dentry->d_parent->d_name.name, dentry->d_name.name,
+inode->u.smbfs_i.access, wish);
+#endif
+ result = -EACCES;
+ }
out:
return result;
}
/* We're called with the server locked */
-static int smb_proc_close(struct smb_sb_info *server,
- __u16 fileid, __u32 mtime)
+static int
+smb_proc_close(struct smb_sb_info *server, __u16 fileid, __u32 mtime)
{
smb_setup_header(server, SMBclose, 3, 0);
WSET(server->packet, smb_vwv0, fileid);
- DSET(server->packet, smb_vwv1, mtime);
+ DSET(server->packet, smb_vwv1, utc2local(mtime));
return smb_request_ok(server, SMBclose, 0, 0);
}
+/*
+ * Called with the server locked.
+ *
+ * Win NT 4.0 has an apparent bug in that it fails to update the
+ * modify time when writing to a file. As a workaround, we update
+ * the attributes if the file has been modified locally (we want to
+ * keep modify and access times in sync ...)
+ */
+static int
+smb_proc_close_inode(struct smb_sb_info *server, struct inode * ino)
+{
+ int result = 0;
+ if (smb_is_open(ino))
+ {
+ /*
+ * Check whether to update locally-modified attributes at
+ * closing time. This is necessary to keep the modify and
+ * access times in sync.
+ *
+ * Kludge alert: If we're using trans2 getattr messages,
+ * the timestamps are accurate only to two seconds ...
+ * we must round the time to avoid cache invalidations!
+ */
+ if (ino->u.smbfs_i.access == SMB_O_RDWR ||
+ ino->u.smbfs_i.access == SMB_O_WRONLY) {
+ struct smb_fattr fattr;
+
+ if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2) {
+ if (ino->i_mtime & 1)
+ ino->i_mtime--;
+ if (ino->i_atime & 1)
+ ino->i_atime--;
+ }
+ smb_get_inode_attr(ino, &fattr);
+ smb_proc_setfile_trans2(server, ino, &fattr);
+ }
+
+ /*
+ * We clear the open flag in advance, in case another
+ * process observes the value while we block below.
+ */
+ ino->u.smbfs_i.open = 0;
+ result = smb_proc_close(server, ino->u.smbfs_i.fileid,
+ ino->i_mtime);
+ ino->u.smbfs_i.cache_valid &= ~SMB_F_LOCALWRITE;
+ /*
+ * Force a revalidation after closing ... some servers
+ * don't post the size until the file has been closed.
+ */
+ if (server->opt.protocol < SMB_PROTOCOL_NT1)
+ ino->u.smbfs_i.oldmtime = 0;
+ ino->u.smbfs_i.closed = jiffies;
+ }
+ return result;
+}
+
int
smb_close(struct inode *ino)
{
@@ -697,39 +941,81 @@ smb_close(struct inode *ino)
{
struct smb_sb_info *server = SMB_SERVER(ino);
smb_lock_server(server);
- result = smb_proc_close(server, ino->u.smbfs_i.fileid,
- ino->i_mtime);
+ result = smb_proc_close_inode(server, ino);
smb_unlock_server(server);
- ino->u.smbfs_i.open = 0;
}
return result;
}
+/*
+ * This routine is called from dput() when d_count is going to 0.
+ * We use this to close the file so that cached dentries don't
+ * keep too many files open.
+ *
+ * There are some tricky race conditions here: the dentry may go
+ * back into use while we're closing the file, and we don't want
+ * the new user to be confused as to the open status.
+ */
+void
+smb_close_dentry(struct dentry * dentry)
+{
+ struct inode *ino = dentry->d_inode;
+
+ if (ino)
+ {
+ if (smb_is_open(ino))
+ {
+ struct smb_sb_info *server = SMB_SERVER(ino);
+ smb_lock_server(server);
+ /*
+ * Check whether the dentry is back in use.
+ */
+ if (dentry->d_count <= 1)
+ {
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_close_dentry: closing %s/%s, count=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
+#endif
+ smb_proc_close_inode(server, ino);
+ }
+ smb_unlock_server(server);
+ }
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_close_dentry: closed %s/%s, count=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
+#endif
+ }
+}
+
+/*
+ * This is used to close a file following a failed instantiate.
+ * Since we don't have an inode, we can't use any of the above.
+ */
+int
+smb_close_fileid(struct dentry *dentry, __u16 fileid)
+{
+ struct smb_sb_info *server = server_from_dentry(dentry);
+ int result = 0;
+
+ smb_lock_server(server);
+ result = smb_proc_close(server, fileid, CURRENT_TIME);
+ smb_unlock_server(server);
+ return result;
+}
+
/* In smb_proc_read and smb_proc_write we do not retry, because the
file-id would not be valid after a reconnection. */
-/* smb_proc_read: fs indicates if it should be copied with
- copy_to_user. */
-
int
-smb_proc_read(struct inode *ino, off_t offset, long count, char *data)
+smb_proc_read(struct inode *ino, off_t offset, int count, char *data)
{
struct smb_sb_info *server = SMB_SERVER(ino);
__u16 returned_count, data_len;
char *buf;
int result;
- struct dentry * dentry;
-
- if (!ino || !(dentry = ino->u.smbfs_i.dentry))
- {
- printk("smb_proc_read: no inode!\n");
- return -EIO;
- }
smb_lock_server(server);
smb_setup_header(server, SMBread, 5, 0);
-
- /* Achtung! Do not refer to the cached packet after the request! */
buf = server->packet;
WSET(buf, smb_vwv0, ino->u.smbfs_i.fileid);
WSET(buf, smb_vwv1, count);
@@ -739,10 +1025,6 @@ smb_proc_read(struct inode *ino, off_t offset, long count, char *data)
result = smb_request_ok(server, SMBread, 5, -1);
if (result < 0)
goto out;
-#if 0
-printk("smb_proc_read: file %s/%s, result=%d, packet=%p\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, result, server->packet);
-#endif
returned_count = WVAL(server->packet, smb_vwv0);
buf = SMB_BUF(server->packet);
@@ -758,6 +1040,11 @@ dentry->d_parent->d_name.name, dentry->d_name.name, result, server->packet);
result = data_len;
out:
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_proc_read: file %s/%s, count=%d, result=%d\n",
+((struct dentry *) ino->u.smbfs_i.dentry)->d_parent->d_name.name,
+((struct dentry *) ino->u.smbfs_i.dentry)->d_name.name, count, result);
+#endif
smb_unlock_server(server);
return result;
}
@@ -766,10 +1053,16 @@ int
smb_proc_write(struct inode *ino, off_t offset, int count, const char *data)
{
struct smb_sb_info *server = SMB_SERVER(ino);
- int res = 0;
+ int result;
__u8 *p;
smb_lock_server(server);
+#if SMBFS_DEBUG_VERBOSE
+printk("smb_proc_write: file %s/%s, count=%d@%ld, packet_size=%d\n",
+((struct dentry *)ino->u.smbfs_i.dentry)->d_parent->d_name.name,
+((struct dentry *)ino->u.smbfs_i.dentry)->d_name.name,
+count, offset, server->packet_size);
+#endif
p = smb_setup_header(server, SMBwrite, 5, count + 3);
WSET(server->packet, smb_vwv0, ino->u.smbfs_i.fileid);
WSET(server->packet, smb_vwv1, count);
@@ -780,21 +1073,21 @@ smb_proc_write(struct inode *ino, off_t offset, int count, const char *data)
WSET(p, 0, count);
memcpy(p+2, data, count);
- if ((res = smb_request_ok(server, SMBwrite, 1, 0)) >= 0)
- res = WVAL(server->packet, smb_vwv0);
+ result = smb_request_ok(server, SMBwrite, 1, 0);
+ if (result >= 0)
+ result = WVAL(server->packet, smb_vwv0);
smb_unlock_server(server);
-
- return res;
+ return result;
}
int
smb_proc_create(struct dentry *dir, struct qstr *name,
- __u16 attr, time_t ctime)
+ __u16 attr, time_t ctime, __u16 *fileid)
{
struct smb_sb_info *server;
- int error;
char *p;
+ int error;
server = server_from_dentry(dir);
smb_lock_server(server);
@@ -807,15 +1100,14 @@ smb_proc_create(struct dentry *dir, struct qstr *name,
p = smb_encode_path(server, p, dir, name);
smb_setup_bcc(server, p);
- if ((error = smb_request_ok(server, SMBcreate, 1, 0)) < 0)
+ error = smb_request_ok(server, SMBcreate, 1, 0);
+ if (error < 0)
{
if (smb_retry(server))
- {
goto retry;
- }
goto out;
}
- smb_proc_close(server, WVAL(server->packet, smb_vwv0), CURRENT_TIME);
+ *fileid = WVAL(server->packet, smb_vwv0);
error = 0;
out:
@@ -846,10 +1138,11 @@ smb_proc_mv(struct dentry *odir, struct qstr *oname,
if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0)
{
if (smb_retry(server))
- {
goto retry;
- }
+ goto out;
}
+ result = 0;
+out:
smb_unlock_server(server);
return result;
}
@@ -873,10 +1166,11 @@ smb_proc_mkdir(struct dentry *dir, struct qstr *name)
if ((result = smb_request_ok(server, SMBmkdir, 0, 0)) < 0)
{
if (smb_retry(server))
- {
goto retry;
- }
+ goto out;
}
+ result = 0;
+out:
smb_unlock_server(server);
return result;
}
@@ -900,10 +1194,11 @@ smb_proc_rmdir(struct dentry *dir, struct qstr *name)
if ((result = smb_request_ok(server, SMBrmdir, 0, 0)) < 0)
{
if (smb_retry(server))
- {
goto retry;
- }
+ goto out;
}
+ result = 0;
+out:
smb_unlock_server(server);
return result;
}
@@ -928,10 +1223,11 @@ smb_proc_unlink(struct dentry *dir, struct qstr *name)
if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0)
{
if (smb_retry(server))
- {
goto retry;
- }
+ goto out;
}
+ result = 0;
+out:
smb_unlock_server(server);
return result;
}
@@ -940,18 +1236,16 @@ int
smb_proc_trunc(struct smb_sb_info *server, __u16 fid, __u32 length)
{
char *p;
- char *buf;
int result;
smb_lock_server(server);
retry:
- buf = server->packet;
p = smb_setup_header(server, SMBwrite, 5, 0);
- WSET(buf, smb_vwv0, fid);
- WSET(buf, smb_vwv1, 0);
- DSET(buf, smb_vwv2, length);
- WSET(buf, smb_vwv4, 0);
+ WSET(server->packet, smb_vwv0, fid);
+ WSET(server->packet, smb_vwv1, 0);
+ DSET(server->packet, smb_vwv2, length);
+ WSET(server->packet, smb_vwv4, 0);
*p++ = 4;
*p++ = 0;
smb_setup_bcc(server, p);
@@ -959,10 +1253,11 @@ smb_proc_trunc(struct smb_sb_info *server, __u16 fid, __u32 length)
if ((result = smb_request_ok(server, SMBwrite, 1, 0)) < 0)
{
if (smb_retry(server))
- {
goto retry;
- }
+ goto out;
}
+ result = 0;
+out:
smb_unlock_server(server);
return result;
}
@@ -973,22 +1268,27 @@ smb_init_dirent(struct smb_sb_info *server, struct smb_fattr *fattr)
memset(fattr, 0, sizeof(*fattr));
fattr->f_nlink = 1;
- fattr->f_uid = server->m.uid;
- fattr->f_gid = server->m.gid;
+ fattr->f_uid = server->mnt->uid;
+ fattr->f_gid = server->mnt->gid;
fattr->f_blksize = 512;
}
static void
smb_finish_dirent(struct smb_sb_info *server, struct smb_fattr *fattr)
{
- fattr->f_mode = server->m.file_mode;
if (fattr->attr & aDIR)
{
- fattr->f_mode = server->m.dir_mode;
+ /* N.B. check for read-only directories */
+ fattr->f_mode = server->mnt->dir_mode;
fattr->f_size = 512;
+ } else
+ {
+ fattr->f_mode = server->mnt->file_mode;
+ if (fattr->attr & aRONLY)
+ fattr->f_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
}
- fattr->f_blocks = 0; /* already set to zero? */
+ fattr->f_blocks = 0;
if ((fattr->f_blksize != 0) && (fattr->f_size != 0))
{
fattr->f_blocks =
@@ -1003,50 +1303,51 @@ smb_init_root_dirent(struct smb_sb_info *server, struct smb_fattr *fattr)
smb_init_dirent(server, fattr);
fattr->attr = aDIR;
fattr->f_ino = 1;
+ fattr->f_mtime = CURRENT_TIME;
smb_finish_dirent(server, fattr);
}
-
+/*
+ * Note that we are now returning the name as a reference to avoid
+ * an extra copy, and that the upper/lower casing is done in place.
+ */
static __u8 *
-smb_decode_dirent(struct smb_sb_info *server, __u8 *p,
- struct smb_dirent *entry)
+smb_decode_dirent(struct smb_sb_info *server, __u8 *p,
+ struct cache_dirent *entry)
{
- smb_init_dirent(server, &(entry->attr));
+ int len;
+
+ /*
+ * SMB doesn't have a concept of inode numbers ...
+ */
+ entry->ino = 0;
p += SMB_STATUS_SIZE; /* reserved (search_status) */
- entry->attr.attr = *p;
- entry->attr.f_mtime = entry->attr.f_atime = entry->attr.f_ctime =
- date_dos2unix(WVAL(p, 1), WVAL(p, 3));
- entry->attr.f_size = DVAL(p, 5);
- entry->len = strlen(p + 9);
- if (entry->len > 12)
- {
- entry->len = 12;
- }
- memcpy(entry->name, p + 9, entry->len);
- entry->name[entry->len] = '\0';
- while (entry->len > 2)
+ entry->name = p + 9;
+ len = strlen(entry->name);
+ if (len > 12)
{
- /* Pathworks fills names with spaces */
- entry->len -= 1;
- if (entry->name[entry->len] == ' ')
- {
- entry->name[entry->len] = '\0';
- }
+ len = 12;
}
+ /*
+ * Trim trailing blanks for Pathworks servers
+ */
+ while (len > 2 && entry->name[len-1] == ' ')
+ len--;
+ entry->len = len;
+
switch (server->opt.case_handling)
{
case SMB_CASE_UPPER:
- str_upper(entry->name);
+ str_upper(entry->name, len);
break;
case SMB_CASE_LOWER:
- str_lower(entry->name);
+ str_lower(entry->name, len);
break;
default:
break;
}
- pr_debug("smb_decode_dirent: name = %s\n", entry->name);
- smb_finish_dirent(server, &(entry->attr));
+ pr_debug("smb_decode_dirent: len=%d, name=%s\n", len, entry->name);
return p + 22;
}
@@ -1056,50 +1357,46 @@ smb_decode_dirent(struct smb_sb_info *server, __u8 *p,
static int
smb_proc_readdir_short(struct smb_sb_info *server, struct dentry *dir, int fpos,
- int cache_size, struct smb_dirent *entry)
+ void *cachep)
{
char *p;
- char *buf;
- int error;
int result;
- int i;
- int first, total_count;
- struct smb_dirent *current_entry;
+ int i, first, entries_seen, entries;
+ int entries_asked = (server->opt.max_xmit - 100) / SMB_DIRINFO_SIZE;
__u16 bcc;
__u16 count;
char status[SMB_STATUS_SIZE];
- int entries_asked = (server->opt.max_xmit - 100) / SMB_DIRINFO_SIZE;
-
static struct qstr mask = { "*.*", 3, 0 };
- pr_debug("SMB call readdir %d @ %d\n", cache_size, fpos);
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_proc_readdir_short: %s/%s, pos=%d\n",
+dir->d_parent->d_name.name, dir->d_name.name, fpos);
+#endif
smb_lock_server(server);
+ /* N.B. We need to reinitialize the cache to restart */
retry:
+ smb_init_dircache(cachep);
first = 1;
- total_count = 0;
- current_entry = entry;
+ entries = 0;
+ entries_seen = 2; /* implicit . and .. */
while (1)
{
- buf = server->packet;
+ p = smb_setup_header(server, SMBsearch, 2, 0);
+ WSET(server->packet, smb_vwv0, entries_asked);
+ WSET(server->packet, smb_vwv1, aDIR);
+ *p++ = 4;
if (first == 1)
{
- p = smb_setup_header(server, SMBsearch, 2, 0);
- WSET(buf, smb_vwv0, entries_asked);
- WSET(buf, smb_vwv1, aDIR);
- *p++ = 4;
p = smb_encode_path(server, p, dir, &mask);
*p++ = 5;
WSET(p, 0, 0);
p += 2;
+ first = 0;
} else
{
- p = smb_setup_header(server, SMBsearch, 2, 0);
- WSET(buf, smb_vwv0, entries_asked);
- WSET(buf, smb_vwv1, aDIR);
- *p++ = 4;
*p++ = 0;
*p++ = 5;
WSET(p, 0, SMB_STATUS_SIZE);
@@ -1110,39 +1407,25 @@ smb_proc_readdir_short(struct smb_sb_info *server, struct dentry *dir, int fpos,
smb_setup_bcc(server, p);
- if ((error = smb_request_ok(server, SMBsearch, 1, -1)) < 0)
+ result = smb_request_ok(server, SMBsearch, 1, -1);
+ if (result < 0)
{
- if ((server->rcls == ERRDOS)
- && (server->err == ERRnofiles))
- {
- result = total_count - fpos;
- goto unlock_return;
- } else
- {
- if (smb_retry(server))
- {
- goto retry;
- }
- result = error;
- goto unlock_return;
- }
+ if ((server->rcls == ERRDOS) &&
+ (server->err == ERRnofiles))
+ break;
+ if (smb_retry(server))
+ goto retry;
+ goto unlock_return;
}
p = SMB_VWV(server->packet);
count = WVAL(p, 0);
- bcc = WVAL(p, 2);
-
- first = 0;
-
if (count <= 0)
- {
- result = total_count - fpos;
- goto unlock_return;
- }
+ break;
+
+ result = -EIO;
+ bcc = WVAL(p, 2);
if (bcc != count * SMB_DIRINFO_SIZE + 3)
- {
- result = -EIO;
goto unlock_return;
- }
p += 7;
/* Read the last entry into the status field. */
@@ -1155,102 +1438,120 @@ smb_proc_readdir_short(struct smb_sb_info *server, struct dentry *dir, int fpos,
for (i = 0; i < count; i++)
{
- if (total_count < fpos)
+ struct cache_dirent this_ent, *entry = &this_ent;
+
+ p = smb_decode_dirent(server, p, entry);
+ if (entries_seen == 2 && entry->name[0] == '.')
{
- p += SMB_DIRINFO_SIZE;
- pr_debug("smb_proc_readdir: skipped entry.\n");
- pr_debug(" total_count = %d\n"
- " i = %d, fpos = %d\n",
- total_count, i, fpos);
- } else if (total_count >= fpos + cache_size)
+ if (entry->len == 1)
+ continue;
+ if (entry->name[1] == '.' && entry->len == 2)
+ continue;
+ }
+ if (entries_seen >= fpos)
{
- result = total_count - fpos;
- goto unlock_return;
+ pr_debug("smb_proc_readdir: fpos=%u\n",
+ entries_seen);
+ smb_add_to_cache(cachep, entry, entries_seen);
+ entries++;
} else
{
- p = smb_decode_dirent(server, p,
- current_entry);
- current_entry->f_pos = total_count;
- pr_debug("smb_proc_readdir: entry->f_pos = "
- "%u\n", entry->f_pos);
- current_entry += 1;
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_proc_readdir: skipped, seen=%d, i=%d, fpos=%d\n",
+entries_seen, i, fpos);
+#endif
}
- total_count += 1;
+ entries_seen++;
}
}
- unlock_return:
+ result = entries;
+
+ unlock_return:
smb_unlock_server(server);
return result;
}
-/* interpret a long filename structure - this is mostly guesses at the
- moment. The length of the structure is returned. The structure of
- a long filename depends on the info level. 260 is used by NT and 2
- is used by OS/2. */
-
+/*
+ * Interpret a long filename structure using the specified info level:
+ * level 1 -- Win NT, Win 95, OS/2
+ * level 259 -- File name and length only, Win NT, Win 95
+ * There seem to be numerous inconsistencies and bugs in implementation.
+ *
+ * We return a reference to the name string to avoid copying, and perform
+ * any needed upper/lower casing in place. Note!! Level 259 entries may
+ * not have any space beyond the name, so don't try to write a null byte!
+ */
static char *
smb_decode_long_dirent(struct smb_sb_info *server, char *p,
- struct smb_dirent *entry, int level)
+ struct cache_dirent *entry, int level)
{
char *result;
- unsigned int len;
+ unsigned int len = 0;
- smb_init_dirent(server, &(entry->attr));
+ /*
+ * SMB doesn't have a concept of inode numbers ...
+ */
+ entry->ino = 0;
switch (level)
{
- /* We might add more levels later... */
case 1:
- entry->attr.f_ctime = date_dos2unix(WVAL(p, 6), WVAL(p, 4));
- entry->attr.f_atime = date_dos2unix(WVAL(p, 10), WVAL(p, 8));
- entry->attr.f_mtime = date_dos2unix(WVAL(p, 14), WVAL(p, 12));
- entry->attr.f_size = DVAL(p, 16);
- entry->attr.attr = *(p+24);
- /*
- * Achtung, lengths can go up to 255
- */
len = *((unsigned char *) p + 26);
entry->len = len;
- strncpy(entry->name, p + 27, len);
- entry->name[len] = '\0';
-
+ entry->name = p + 27;
result = p + 28 + len;
break;
+ case 259: /* SMB_FIND_FILE_NAMES_INFO = 0x103 */
+ result = p + DVAL(p, 0);
+ /* DVAL(p, 4) should be resume key? Seems to be 0 .. */
+ len = DVAL(p, 8);
+ if (len > 255)
+ len = 255;
+ entry->name = p + 12;
+ /*
+ * Kludge alert: Win NT 4.0 adds a trailing null byte and
+ * counts it in the name length, but Win 95 doesn't. Hence
+ * we test for a trailing null and decrement the length ...
+ */
+ if (len && entry->name[len-1] == '\0')
+ len--;
+ entry->len = len;
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_decode_long_dirent: info 259 at %p, len=%d, name=%s\n",
+p, len, entry->name);
+#endif
+ break;
+
default:
- printk("smb_decode: Unknown long filename format %d\n", level);
+ printk("smb_decode_long_dirent: Unknown level %d\n", level);
result = p + WVAL(p, 0);
}
switch (server->opt.case_handling)
{
case SMB_CASE_UPPER:
- str_upper(entry->name);
+ str_upper(entry->name, len);
break;
case SMB_CASE_LOWER:
- str_lower(entry->name);
+ str_lower(entry->name, len);
break;
default:
break;
}
- smb_finish_dirent(server, &(entry->attr));
-
return result;
}
static int
smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos,
- int cache_size, struct smb_dirent *cache)
+ void *cachep)
{
- /* NT uses 260, OS/2 uses 2. Both accept 1. */
- const int info_level = 1;
+ /* Both NT and OS/2 accept info level 1 (but see note below). */
+ int info_level = 1;
const int max_matches = 512;
- char *p;
- char *lastname;
- unsigned lastname_len;
- int i;
+ char *p, *mask, *lastname;
int first, entries, entries_seen;
unsigned char *resp_data = NULL;
@@ -1260,36 +1561,45 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos,
__u16 command;
- int result;
-
- int ff_resume_key = 0;
+ int ff_resume_key = 0; /* this isn't being used */
int ff_searchcount = 0;
int ff_eos = 0;
int ff_lastname = 0;
int ff_dir_handle = 0;
int loop_count = 0;
+ int mask_len, i, result;
- char param[SMB_MAXPATHLEN + 2 + 12]; /* too long for the stack! */
- int mask_len;
- char *mask = &(param[12]);
-
+ char param[12 + SMB_MAXPATHLEN + 2]; /* too long for the stack! */
static struct qstr star = { "*", 1, 0 };
- mask_len = smb_encode_path(server, mask, dir, &star) - mask;
-
- mask[mask_len] = 0;
- mask[mask_len + 1] = 0;
-
- pr_debug("smb_readdir_long cache=%d, fpos=%d, mask=%s\n",
- cache_size, fpos, mask);
+ /*
+ * Check whether to change the info level. There appears to be
+ * a bug in Win NT 4.0's handling of info level 1, whereby it
+ * truncates the directory scan for certain patterns of files.
+ * Hence we use level 259 for NT. (And Win 95 as well ...)
+ */
+ if (server->opt.protocol >= SMB_PROTOCOL_NT1)
+ info_level = 259;
smb_lock_server(server);
retry:
-
+ /*
+ * Encode the initial path
+ */
+ mask = &(param[12]);
+ mask_len = smb_encode_path(server, mask, dir, &star) - mask;
first = 1;
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_proc_readdir_long: starting fpos=%d, mask=%s\n", fpos, mask);
+#endif
+ /*
+ * We must reinitialize the dircache when retrying.
+ */
+ smb_init_dircache(cachep);
entries = 0;
entries_seen = 2;
+ ff_eos = 0;
while (ff_eos == 0)
{
@@ -1301,6 +1611,7 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos,
entries = -EIO;
break;
}
+
if (first != 0)
{
command = TRANSACT2_FINDFIRST;
@@ -1314,28 +1625,31 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos,
} else
{
command = TRANSACT2_FINDNEXT;
- pr_debug("hand=0x%X resume=%d ff_lastnm=%d mask=%s\n",
- ff_dir_handle, ff_resume_key, ff_lastname,
- mask);
- WSET(param, 0, ff_dir_handle);
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_proc_readdir_long: handle=0x%X, resume=%d, lastname=%d, mask=%s\n",
+ff_dir_handle, ff_resume_key, ff_lastname, mask);
+#endif
+ WSET(param, 0, ff_dir_handle); /* search handle */
WSET(param, 2, max_matches); /* max count */
WSET(param, 4, info_level);
DSET(param, 6, ff_resume_key); /* ff_resume_key */
WSET(param, 10, 8 + 4 + 2); /* resume required +
close on end +
continue */
-#ifdef CONFIG_SMB_WIN95
- /* Windows 95 is not able to deliver answers
- to FIND_NEXT fast enough, so sleep 0.2 seconds */
- current->timeout = jiffies + HZ / 5;
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- current->timeout = 0;
-#endif
+ if (server->mnt->version & SMB_FIX_WIN95)
+ {
+ /* Windows 95 is not able to deliver answers
+ * to FIND_NEXT fast enough, so sleep 0.2 sec
+ */
+ current->timeout = jiffies + HZ / 5;
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ current->timeout = 0;
+ }
}
result = smb_trans2_request(server, command,
- 0, NULL, 12 + mask_len + 2, param,
+ 0, NULL, 12 + mask_len + 1, param,
&resp_data_len, &resp_data,
&resp_param_len, &resp_param);
@@ -1343,10 +1657,13 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos,
{
if (smb_retry(server))
{
+#ifdef SMBFS_PARANOIA
+printk("smb_proc_readdir_long: error=%d, retrying\n", result);
+#endif
goto retry;
}
#ifdef SMBFS_PARANOIA
-printk("smb_proc_readdir_long: trans2_request error=%d\n", result);
+printk("smb_proc_readdir_long: error=%d, breaking\n", result);
#endif
entries = result;
break;
@@ -1354,13 +1671,17 @@ printk("smb_proc_readdir_long: trans2_request error=%d\n", result);
if (server->rcls != 0)
{
#ifdef SMBFS_PARANOIA
-printk("smb_proc_readdir_long: error, rcls=%d, err=%d\n",
+printk("smb_proc_readdir_long: rcls=%d, err=%d, breaking\n",
server->rcls, server->err);
#endif
- /* Why isn't this considered an error? */
- /* entries = -EIO; */
+ entries = -smb_errno(server);
break;
}
+#ifdef SMBFS_PARANOIA
+if (resp_data + resp_data_len > server->packet + server->packet_size)
+printk("s_p_r_l: data past packet end! data=%p, len=%d, packet=%p\n",
+resp_data + resp_data_len, resp_data_len, server->packet + server->packet_size);
+#endif
/* parse out some important return info */
if (first != 0)
@@ -1380,97 +1701,101 @@ server->rcls, server->err);
{
break;
}
- /* point to the data bytes */
- p = resp_data;
/* we might need the lastname for continuations */
- lastname = "";
- lastname_len = 0;
+ mask_len = 0;
if (ff_lastname > 0)
{
- ff_resume_key = 0;
- lastname = p + ff_lastname;
+ lastname = resp_data + ff_lastname;
switch (info_level)
{
- case 260:
- lastname_len = resp_data_len - ff_lastname;
+ case 259:
+ if (ff_lastname < resp_data_len)
+ mask_len = resp_data_len - ff_lastname;
break;
case 1:
- lastname_len = *((unsigned char *) lastname++);
+ /* Win NT 4.0 doesn't set the length byte */
+ lastname++;
+ if (ff_lastname + 2 < resp_data_len)
+ mask_len = strlen(lastname);
break;
}
+ /*
+ * Update the mask string for the next message.
+ */
+ if (mask_len > 255)
+ mask_len = 255;
+ if (mask_len)
+ strncpy(mask, lastname, mask_len);
+ ff_resume_key = 0;
}
- lastname_len = min(lastname_len, 256);
- strncpy(mask, lastname, lastname_len);
- mask[lastname_len] = '\0';
-
+ mask[mask_len] = 0;
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_proc_readdir_long: new mask, len=%d@%d, mask=%s\n",
+mask_len, ff_lastname, mask);
+#endif
/* Now we are ready to parse smb directory entries. */
+ /* point to the data bytes */
+ p = resp_data;
for (i = 0; i < ff_searchcount; i++)
{
- struct smb_dirent *entry = &(cache[entries]);
+ struct cache_dirent this_ent, *entry = &this_ent;
- p = smb_decode_long_dirent(server, p,
- entry, info_level);
+ p = smb_decode_long_dirent(server, p, entry,
+ info_level);
pr_debug("smb_readdir_long: got %s\n", entry->name);
- if ((entry->name[0] == '.')
- && ((entry->name[1] == '\0')
- || ((entry->name[1] == '.')
- && (entry->name[2] == '\0'))))
+ /* ignore . and .. from the server */
+ if (entries_seen == 2 && entry->name[0] == '.')
{
- /* ignore . and .. from the server */
- continue;
+ if (entry->len == 1)
+ continue;
+ if (entry->name[1] == '.' && entry->len == 2)
+ continue;
}
if (entries_seen >= fpos)
{
- entry->f_pos = entries_seen;
+ smb_add_to_cache(cachep, entry, entries_seen);
entries += 1;
}
- entries_seen += 1;
- if (entries < cache_size)
- continue;
-
- /* cache is full */
- goto finished;
+ entries_seen++;
}
- pr_debug("received %d entries (eos=%d resume=%d)\n",
- ff_searchcount, ff_eos, ff_resume_key);
-
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_proc_readdir_long: received %d entries, eos=%d, resume=%d\n",
+ff_searchcount, ff_eos, ff_resume_key);
+#endif
first = 0;
}
- finished:
smb_unlock_server(server);
return entries;
}
int
-smb_proc_readdir(struct dentry *dir, int fpos,
- int cache_size, struct smb_dirent *entry)
+smb_proc_readdir(struct dentry *dir, int fpos, void *cachep)
{
struct smb_sb_info *server;
server = server_from_dentry(dir);
if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
- return smb_proc_readdir_long(server, dir, fpos, cache_size,
- entry);
+ return smb_proc_readdir_long(server, dir, fpos, cachep);
else
- return smb_proc_readdir_short(server, dir, fpos, cache_size,
- entry);
+ return smb_proc_readdir_short(server, dir, fpos, cachep);
}
+/*
+ * Note: called with the server locked.
+ */
static int
smb_proc_getattr_core(struct smb_sb_info *server, struct dentry *dir,
- struct qstr *name, struct smb_fattr *attr)
+ struct qstr *name, struct smb_fattr *fattr)
{
int result;
char *p;
- smb_lock_server(server);
-
retry:
p = smb_setup_header(server, SMBgetatr, 0, 0);
*p++ = 4;
@@ -1483,68 +1808,100 @@ smb_proc_getattr_core(struct smb_sb_info *server, struct dentry *dir,
goto retry;
goto out;
}
- attr->attr = WVAL(server->packet, smb_vwv0);
- attr->f_ctime = attr->f_atime = attr->f_mtime =
- local2utc(DVAL(server->packet, smb_vwv1));
- attr->f_size = DVAL(server->packet, smb_vwv3);
+ fattr->attr = WVAL(server->packet, smb_vwv0);
+ fattr->f_mtime = local2utc(DVAL(server->packet, smb_vwv1));
+ fattr->f_size = DVAL(server->packet, smb_vwv3);
+ fattr->f_ctime = fattr->f_mtime;
+ fattr->f_atime = fattr->f_mtime;
+#ifdef SMBFS_DEBUG_TIMESTAMP
+printk("getattr_core: %s/%s, mtime=%ld\n",
+dir->d_name.name, name->name, fattr->f_mtime);
+#endif
result = 0;
out:
- smb_unlock_server(server);
return result;
}
+/*
+ * Note: called with the server locked.
+ */
static int
smb_proc_getattr_trans2(struct smb_sb_info *server, struct dentry *dir,
struct qstr *name, struct smb_fattr *attr)
{
- char param[SMB_MAXPATHLEN + 20];
char *p;
int result;
-
+ __u16 date, time;
+ int off_date = 0, off_time = 2;
unsigned char *resp_data = NULL;
unsigned char *resp_param = NULL;
int resp_data_len = 0;
int resp_param_len = 0;
+ char param[SMB_MAXPATHLEN + 20]; /* too big for the stack! */
+ retry:
WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */
DSET(param, 2, 0);
p = smb_encode_path(server, param + 6, dir, name);
- smb_lock_server(server);
- retry:
result = smb_trans2_request(server, TRANSACT2_QPATHINFO,
0, NULL, p - param, param,
&resp_data_len, &resp_data,
&resp_param_len, &resp_param);
-
- if (server->rcls != 0)
- {
- result = -smb_errno(server->rcls, server->err);
- goto out;
- }
if (result < 0)
{
if (smb_retry(server))
goto retry;
goto out;
}
+ if (server->rcls != 0)
+ {
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_proc_getattr_trans2: for %s: result=%d, rcls=%d, err=%d\n",
+&param[6], result, server->rcls, server->err);
+#endif
+ result = -smb_errno(server);
+ goto out;
+ }
result = -ENOENT;
if (resp_data_len < 22)
+ {
+#ifdef SMBFS_PARANOIA
+printk("smb_proc_getattr_trans2: not enough data for %s, len=%d\n",
+&param[6], resp_data_len);
+#endif
goto out;
+ }
- attr->f_ctime = date_dos2unix(WVAL(resp_data, 2),
- WVAL(resp_data, 0));
- attr->f_atime = date_dos2unix(WVAL(resp_data, 6),
- WVAL(resp_data, 4));
- attr->f_mtime = date_dos2unix(WVAL(resp_data, 10),
- WVAL(resp_data, 8));
+ /*
+ * Kludge alert: Win 95 swaps the date and time field,
+ * contrary to the CIFS docs and Win NT practice.
+ */
+ if (server->mnt->version & SMB_FIX_WIN95) {
+ off_date = 2;
+ off_time = 0;
+ }
+ date = WVAL(resp_data, off_date);
+ time = WVAL(resp_data, off_time);
+ attr->f_ctime = date_dos2unix(date, time);
+
+ date = WVAL(resp_data, 4 + off_date);
+ time = WVAL(resp_data, 4 + off_time);
+ attr->f_atime = date_dos2unix(date, time);
+
+ date = WVAL(resp_data, 8 + off_date);
+ time = WVAL(resp_data, 8 + off_time);
+ attr->f_mtime = date_dos2unix(date, time);
+#ifdef SMBFS_DEBUG_TIMESTAMP
+printk("getattr_trans2: %s/%s, date=%x, time=%x, mtime=%ld\n",
+dir->d_name.name, name->name, date, time, attr->f_mtime);
+#endif
attr->f_size = DVAL(resp_data, 12);
attr->attr = WVAL(resp_data, 20);
result = 0;
out:
- smb_unlock_server(server);
return result;
}
@@ -1552,26 +1909,33 @@ int
smb_proc_getattr(struct dentry *dir, struct qstr *name,
struct smb_fattr *fattr)
{
- struct smb_sb_info *server;
- int result = -1;
+ struct smb_sb_info *server = server_from_dentry(dir);
+ int result;
- server = server_from_dentry(dir);
+ smb_lock_server(server);
smb_init_dirent(server, fattr);
- if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
+ /*
+ * Win 95 is painfully slow at returning trans2 getattr info,
+ * so we provide the SMB_FIX_OLDATTR option switch.
+ */
+ if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2 &&
+ !(server->mnt->version & SMB_FIX_OLDATTR))
result = smb_proc_getattr_trans2(server, dir, name, fattr);
-
- if (result < 0)
+ else
result = smb_proc_getattr_core(server, dir, name, fattr);
smb_finish_dirent(server, fattr);
+ smb_unlock_server(server);
return result;
}
-
-/* In core protocol, there is only 1 time to be set, we use
- entry->f_mtime, to make touch work. */
+/*
+ * In the core protocol there is only one time to be set,
+ * so we use fattr->f_mtime to make `touch' work.
+ * Note: called with the server locked.
+ */
static int
smb_proc_setattr_core(struct smb_sb_info *server,
struct dentry *dir, struct smb_fattr *fattr)
@@ -1580,33 +1944,45 @@ smb_proc_setattr_core(struct smb_sb_info *server,
char *buf;
int result;
- smb_lock_server(server);
+#ifdef SMBFS_DEBUG_TIMESTAMP
+printk("setattr_core: %s/%s, mtime=%ld\n",
+dir->d_parent->d_name.name, dir->d_name.name, fattr->f_mtime);
+#endif
retry:
buf = server->packet;
p = smb_setup_header(server, SMBsetatr, 8, 0);
WSET(buf, smb_vwv0, fattr->attr);
DSET(buf, smb_vwv1, utc2local(fattr->f_mtime));
+ WSET(buf, smb_vwv3, 0); /* reserved values */
+ WSET(buf, smb_vwv4, 0);
+ WSET(buf, smb_vwv5, 0);
+ WSET(buf, smb_vwv6, 0);
+ WSET(buf, smb_vwv7, 0);
*p++ = 4;
p = smb_encode_path(server, p, dir, NULL);
- *p++ = 4;
- *p++ = 0;
-
smb_setup_bcc(server, p);
- if ((result = smb_request_ok(server, SMBsetatr, 0, 0)) < 0)
+
+ result = smb_request_ok(server, SMBsetatr, 0, 0);
+ if (result < 0)
+ {
if (smb_retry(server))
goto retry;
-
- smb_unlock_server(server);
+ goto out;
+ }
+ result = 0;
+out:
return result;
}
+/*
+ * Note: called with the server locked.
+ */
static int
smb_proc_setattr_trans2(struct smb_sb_info *server,
struct dentry *dir, struct smb_fattr *fattr)
{
- char param[SMB_MAXPATHLEN + 20];
- char data[26];
+ __u16 date, time;
char *p;
int result;
@@ -1614,51 +1990,127 @@ smb_proc_setattr_trans2(struct smb_sb_info *server,
unsigned char *resp_param = NULL;
int resp_data_len = 0;
int resp_param_len = 0;
+ char param[SMB_MAXPATHLEN + 20]; /* too long for the stack! */
+ char data[26];
+ retry:
WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */
DSET(param, 2, 0);
p = smb_encode_path(server, param + 6, dir, NULL);
- date_unix2dos(fattr->f_ctime, &(data[0]), &(data[2]));
- date_unix2dos(fattr->f_atime, &(data[4]), &(data[6]));
- date_unix2dos(fattr->f_mtime, &(data[8]), &(data[10]));
+ date_unix2dos(fattr->f_ctime, &date, &time);
+ WSET(data, 0, date);
+ WSET(data, 2, time);
+ date_unix2dos(fattr->f_atime, &date, &time);
+ WSET(data, 4, date);
+ WSET(data, 6, time);
+ date_unix2dos(fattr->f_mtime, &date, &time);
+ WSET(data, 8, date);
+ WSET(data, 10, time);
+#ifdef SMBFS_DEBUG_TIMESTAMP
+printk("setattr_trans2: %s/%s, date=%x, time=%x, mtime=%ld\n",
+dir->d_parent->d_name.name, dir->d_name.name, date, time, fattr->f_mtime);
+#endif
DSET(data, 12, fattr->f_size);
DSET(data, 16, fattr->f_blksize);
WSET(data, 20, fattr->attr);
- WSET(data, 22, 0);
+ DSET(data, 22, 0); /* ULONG EA size */
- smb_lock_server(server);
- retry:
result = smb_trans2_request(server, TRANSACT2_SETPATHINFO,
26, data, p - param, param,
&resp_data_len, &resp_data,
&resp_param_len, &resp_param);
-
- if (server->rcls != 0)
+ if (result < 0)
{
- smb_unlock_server(server);
- return -smb_errno(server->rcls, server->err);
+ if (smb_retry(server))
+ goto retry;
+ goto out;
}
+ result = 0;
+ if (server->rcls != 0)
+ result = -smb_errno(server);
+
+out:
+ return result;
+}
+
+/*
+ * Set the attributes for an open file.
+ */
+static int
+smb_proc_setfile_trans2(struct smb_sb_info *server,
+ struct inode * inode, struct smb_fattr *fattr)
+{
+ __u16 date, time;
+ unsigned char *resp_data = NULL;
+ unsigned char *resp_parm = NULL;
+ int resp_data_len = 0;
+ int resp_parm_len = 0;
+ int result;
+ char parm[6], data[26];
+
+ retry:
+ WSET(parm, 0, inode->u.smbfs_i.fileid);
+ WSET(parm, 2, 1); /* Info level SMB_INFO_STANDARD */
+
+ date_unix2dos(fattr->f_ctime, &date, &time);
+ WSET(data, 0, date);
+ WSET(data, 2, time);
+ date_unix2dos(fattr->f_atime, &date, &time);
+ WSET(data, 4, date);
+ WSET(data, 6, time);
+#ifdef SMBFS_DEBUG_TIMESTAMP
+printk("smb_proc_setfile_trans2: date=%x, time=%x, atime=%ld\n",
+date, time, fattr->f_atime);
+#endif
+ date_unix2dos(fattr->f_mtime, &date, &time);
+ WSET(data, 8, date);
+ WSET(data, 10, time);
+ DSET(data, 12, fattr->f_size);
+ DSET(data, 16, fattr->f_blksize);
+ WSET(data, 20, fattr->attr);
+ DSET(data, 22, 0); /* ULONG EA size */
+
+ result = smb_trans2_request(server, TRANSACT2_SETFILEINFO,
+ 26, data, 6, parm,
+ &resp_data_len, &resp_data,
+ &resp_parm_len, &resp_parm);
if (result < 0)
+ {
if (smb_retry(server))
goto retry;
+ goto out;
+ }
+ result = 0;
+ if (server->rcls != 0)
+ result = -smb_errno(server);
- smb_unlock_server(server);
- return 0;
+out:
+ return result;
}
int
smb_proc_setattr(struct smb_sb_info *server, struct dentry *dir,
struct smb_fattr *fattr)
{
- int result = -1;
+ int result;
- if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
- result = smb_proc_setattr_trans2(server, dir, fattr);
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_proc_setattr: setting %s/%s, open=%d\n",
+dir->d_parent->d_name.name, dir->d_name.name, smb_is_open(dir->d_inode));
+#endif
+ smb_lock_server(server);
+ if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2) {
+ struct inode *inode = dir->d_inode;
- if (result < 0)
+ if (smb_is_open(inode))
+ result = smb_proc_setfile_trans2(server, inode, fattr);
+ else
+ result = smb_proc_setattr_trans2(server, dir, fattr);
+ } else
result = smb_proc_setattr_core(server, dir, fattr);
+ smb_unlock_server(server);
return result;
}
diff --git a/fs/smbfs/sock.c b/fs/smbfs/sock.c
index aceca122b..f14836199 100644
--- a/fs/smbfs/sock.c
+++ b/fs/smbfs/sock.c
@@ -7,11 +7,9 @@
*/
#include <linux/sched.h>
-#include <linux/smb_fs.h>
#include <linux/errno.h>
#include <linux/socket.h>
#include <linux/fcntl.h>
-#include <linux/stat.h>
#include <linux/in.h>
#include <linux/net.h>
#include <linux/mm.h>
@@ -19,6 +17,7 @@
#include <net/scm.h>
#include <net/ip.h>
+#include <linux/smb_fs.h>
#include <linux/smb.h>
#include <linux/smbno.h>
@@ -97,11 +96,15 @@ smb_data_callback(struct sock *sk, int len)
while (1)
{
+ result = -EIO;
if (sk->dead)
{
+#ifdef SMBFS_PARANOIA
printk("smb_data_callback: sock dead!\n");
- return;
+#endif
+ break;
}
+
result = _recvfrom(socket, (void *) peek_buf, 1,
MSG_PEEK | MSG_DONTWAIT);
if (result == -EAGAIN)
@@ -126,18 +129,26 @@ smb_data_callback(struct sock *sk, int len)
}
}
+int
+smb_valid_socket(struct inode * inode)
+{
+ return (inode && S_ISSOCK(inode->i_mode) &&
+ inode->u.socket_i.type == SOCK_STREAM);
+}
+
static struct socket *
server_sock(struct smb_sb_info *server)
{
struct file *file;
- struct inode *inode;
-
- if (server &&
- (file = server->sock_file) &&
- (inode = file->f_dentry->d_inode) &&
- S_ISSOCK(inode->i_mode) &&
- inode->u.socket_i.type == SOCK_STREAM)
- return &(inode->u.socket_i);
+
+ if (server && (file = server->sock_file))
+ {
+#ifdef SMBFS_PARANOIA
+ if (!smb_valid_socket(file->f_dentry->d_inode))
+ printk("smb_server_sock: bad socket!\n");
+#endif
+ return &file->f_dentry->d_inode->u.socket_i;
+ }
return NULL;
}
@@ -242,15 +253,13 @@ smb_close_socket(struct smb_sb_info *server)
if (file)
{
- struct socket * socket = server_sock(server);
-
- printk("smb_close_socket: closing socket %p\n", socket);
- /*
- * We need a way to check for tasks running the callback!
- */
- if (socket->sk->data_ready == smb_data_callback)
- printk("smb_close_socket: still catching keepalives!\n");
-
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_close_socket: closing socket %p\n", server_sock(server));
+#endif
+#ifdef SMBFS_PARANOIA
+if (server_sock(server)->sk->data_ready == smb_data_callback)
+printk("smb_close_socket: still catching keepalives!\n");
+#endif
server->sock_file = NULL;
close_fp(file);
}
@@ -325,7 +334,9 @@ smb_get_length(struct socket *socket, unsigned char *header)
if (result < 0)
{
- pr_debug("smb_get_length: recv error = %d\n", -result);
+#ifdef SMBFS_PARANOIA
+printk("smb_get_length: recv error = %d\n", -result);
+#endif
return result;
}
switch (peek_buf[0])
@@ -339,7 +350,9 @@ smb_get_length(struct socket *socket, unsigned char *header)
goto re_recv;
default:
- pr_debug("smb_get_length: Invalid NBT packet\n");
+#ifdef SMBFS_PARANOIA
+printk("smb_get_length: Invalid NBT packet, code=%x\n", peek_buf[0]);
+#endif
return -EIO;
}
@@ -352,6 +365,16 @@ smb_get_length(struct socket *socket, unsigned char *header)
}
/*
+ * Since we allocate memory in increments of PAGE_SIZE,
+ * round up the packet length to the next multiple.
+ */
+int
+smb_round_length(int len)
+{
+ return (len + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+}
+
+/*
* smb_receive
* fs points to the correct segment
*/
@@ -359,170 +382,215 @@ static int
smb_receive(struct smb_sb_info *server)
{
struct socket *socket = server_sock(server);
- int len;
- int result;
+ unsigned char * packet = server->packet;
+ int len, result;
unsigned char peek_buf[4];
- len = smb_get_length(socket, peek_buf);
-
- if (len < 0)
- {
- return len;
- }
+ result = smb_get_length(socket, peek_buf);
+ if (result < 0)
+ goto out;
+ len = result;
+ /*
+ * Some servers do not respect our max_xmit and send
+ * larger packets. Try to allocate a new packet,
+ * but don't free the old one unless we succeed.
+ */
if (len + 4 > server->packet_size)
{
- /* Some servers do not care about our max_xmit. They
- send larger packets */
- pr_debug("smb_receive: Increase packet size from %d to %d\n",
- server->packet_size, len + 4);
+ int new_len = smb_round_length(len + 4);
+
+#ifdef SMBFS_PARANOIA
+printk("smb_receive: Increase packet size from %d to %d\n",
+server->packet_size, new_len);
+#endif
+ result = -ENOMEM;
+ packet = smb_vmalloc(new_len);
+ if (packet == NULL)
+ goto out;
smb_vfree(server->packet);
- server->packet = 0;
- server->packet_size = 0;
- server->packet = smb_vmalloc(len + 4);
- if (server->packet == NULL)
- {
- return -ENOMEM;
- }
- server->packet_size = len + 4;
+ server->packet = packet;
+ server->packet_size = new_len;
}
- memcpy(server->packet, peek_buf, 4);
- result = smb_receive_raw(socket, server->packet + 4, len);
-
+ memcpy(packet, peek_buf, 4);
+ result = smb_receive_raw(socket, packet + 4, len);
if (result < 0)
{
- pr_debug("smb_receive: receive error: %d\n", result);
- return result;
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_receive: receive error: %d\n", result);
+#endif
+ goto out;
}
- server->rcls = *(server->packet+9);
- server->err = WVAL(server->packet, 11);
+ server->rcls = *(packet + smb_rcls);
+ server->err = WVAL(packet, smb_err);
#ifdef SMBFS_DEBUG_VERBOSE
if (server->rcls != 0)
printk("smb_receive: rcls=%d, err=%d\n", server->rcls, server->err);
#endif
+out:
return result;
}
+/*
+ * This routine checks first for "fast track" processing, as most
+ * packets won't need to be copied. Otherwise, it allocates a new
+ * packet to hold the incoming data.
+ *
+ * Note that the final server packet must be the larger of the two;
+ * server packets aren't allowed to shrink.
+ */
static int
smb_receive_trans2(struct smb_sb_info *server,
int *ldata, unsigned char **data,
- int *lparam, unsigned char **param)
+ int *lparm, unsigned char **parm)
{
- int total_data = 0;
- int total_param = 0;
+ unsigned char *inbuf, *base, *rcv_buf = NULL;
+ unsigned int parm_disp, parm_offset, parm_count, parm_tot, parm_len = 0;
+ unsigned int data_disp, data_offset, data_count, data_tot, data_len = 0;
+ unsigned int total_p = 0, total_d = 0, buf_len = 0;
int result;
- unsigned char *rcv_buf;
- int buf_len;
- int data_len = 0;
- int param_len = 0;
-
- if ((result = smb_receive(server)) < 0)
- {
- return result;
- }
- if (server->rcls != 0)
- {
- *param = *data = server->packet;
- *ldata = *lparam = 0;
- return 0;
- }
- total_data = WVAL(server->packet, smb_tdrcnt);
- total_param = WVAL(server->packet, smb_tprcnt);
-
- pr_debug("smb_receive_trans2: td=%d,tp=%d\n", total_data, total_param);
-
- if ((total_data > TRANS2_MAX_TRANSFER)
- || (total_param > TRANS2_MAX_TRANSFER))
- {
- pr_debug("smb_receive_trans2: data/param too long\n");
- return -EIO;
- }
- buf_len = total_data + total_param;
- if (server->packet_size > buf_len)
- {
- buf_len = server->packet_size;
- }
- if ((rcv_buf = smb_vmalloc(buf_len)) == NULL)
- {
- pr_debug("smb_receive_trans2: could not alloc data area\n");
- return -ENOMEM;
- }
- *param = rcv_buf;
- *data = rcv_buf + total_param;
while (1)
{
- unsigned char *inbuf = server->packet;
-
- if (WVAL(inbuf, smb_prdisp) + WVAL(inbuf, smb_prcnt)
- > total_param)
- {
- pr_debug("smb_receive_trans2: invalid parameters\n");
- result = -EIO;
- goto fail;
- }
- memcpy(*param + WVAL(inbuf, smb_prdisp),
- smb_base(inbuf) + WVAL(inbuf, smb_proff),
- WVAL(inbuf, smb_prcnt));
- param_len += WVAL(inbuf, smb_prcnt);
-
- if (WVAL(inbuf, smb_drdisp) + WVAL(inbuf, smb_drcnt)
- > total_data)
+ result = smb_receive(server);
+ if (result < 0)
+ goto out;
+ inbuf = server->packet;
+ if (server->rcls != 0)
{
- pr_debug("smb_receive_trans2: invalid data block\n");
- result = -EIO;
- goto fail;
+ *parm = *data = inbuf;
+ *ldata = *lparm = 0;
+ goto out;
}
- pr_debug("disp: %d, off: %d, cnt: %d\n",
- WVAL(inbuf, smb_drdisp), WVAL(inbuf, smb_droff),
- WVAL(inbuf, smb_drcnt));
+ /*
+ * Extract the control data from the packet.
+ */
+ data_tot = WVAL(inbuf, smb_tdrcnt);
+ parm_tot = WVAL(inbuf, smb_tprcnt);
+ parm_disp = WVAL(inbuf, smb_prdisp);
+ parm_offset = WVAL(inbuf, smb_proff);
+ parm_count = WVAL(inbuf, smb_prcnt);
+ data_disp = WVAL(inbuf, smb_drdisp);
+ data_offset = WVAL(inbuf, smb_droff);
+ data_count = WVAL(inbuf, smb_drcnt);
+ base = smb_base(inbuf);
- memcpy(*data + WVAL(inbuf, smb_drdisp),
- smb_base(inbuf) + WVAL(inbuf, smb_droff),
- WVAL(inbuf, smb_drcnt));
- data_len += WVAL(inbuf, smb_drcnt);
+ /*
+ * Assume success and increment lengths.
+ */
+ parm_len += parm_count;
+ data_len += data_count;
- if ((WVAL(inbuf, smb_tdrcnt) > total_data)
- || (WVAL(inbuf, smb_tprcnt) > total_param))
+ if (!rcv_buf)
{
- pr_debug("smb_receive_trans2: data/params grew!\n");
- result = -EIO;
- goto fail;
+ /*
+ * Check for fast track processing ... just this packet.
+ */
+ if (parm_count == parm_tot && data_count == data_tot)
+ {
+#ifdef SMBFS_DEBUG_VERBOSE
+printk("smb_receive_trans2: fast track, parm=%u %u %u, data=%u %u %u\n",
+parm_disp, parm_offset, parm_count, data_disp, data_offset, data_count);
+#endif
+ *parm = base + parm_offset;
+ *data = base + data_offset;
+ goto success;
+ }
+
+ if (parm_tot > TRANS2_MAX_TRANSFER ||
+ data_tot > TRANS2_MAX_TRANSFER)
+ goto out_too_long;
+
+ /*
+ * Save the total parameter and data length.
+ */
+ total_d = data_tot;
+ total_p = parm_tot;
+
+ buf_len = total_d + total_p;
+ if (server->packet_size > buf_len)
+ buf_len = server->packet_size;
+ buf_len = smb_round_length(buf_len);
+
+ rcv_buf = smb_vmalloc(buf_len);
+ if (!rcv_buf)
+ goto out_no_mem;
+ *parm = rcv_buf;
+ *data = rcv_buf + total_p;
}
- /* the total lengths might shrink! */
- total_data = WVAL(inbuf, smb_tdrcnt);
- total_param = WVAL(inbuf, smb_tprcnt);
+ else if (data_tot > total_d || parm_tot > total_p)
+ goto out_data_grew;
+
+ if (parm_disp + parm_count > total_p)
+ goto out_bad_parm;
+ if (data_disp + data_count > total_d)
+ goto out_bad_data;
+ memcpy(*parm + parm_disp, base + parm_offset, parm_count);
+ memcpy(*data + data_disp, base + data_offset, data_count);
#ifdef SMBFS_PARANOIA
-if ((data_len >= total_data || param_len >= total_param) &&
- !(data_len >= total_data && param_len >= total_param))
-printk("smb_receive_trans2: dlen=%d, tdata=%d, plen=%d, tlen=%d\n",
-data_len, total_data, param_len, total_param);
+printk("smb_receive_trans2: copied, parm=%u of %u, data=%u of %u\n",
+parm_len, parm_tot, data_len, data_tot);
#endif
- /* shouldn't this be an OR test? don't want to overrun */
- if ((data_len >= total_data) && (param_len >= total_param))
- {
+ /*
+ * Check whether we've received all of the data. Note that
+ * we use the packet totals -- total lengths might shrink!
+ */
+ if (data_len >= data_tot && parm_len >= parm_tot)
break;
- }
- if ((result = smb_receive(server)) < 0)
- {
- goto fail;
- }
- result = -EIO;
- if (server->rcls != 0)
- goto fail;
}
- *ldata = data_len;
- *lparam = param_len;
- smb_vfree(server->packet);
- server->packet = rcv_buf;
- server->packet_size = buf_len;
- return 0;
+ /*
+ * Install the new packet. Note that it's possible, though
+ * unlikely, that the new packet could be smaller than the
+ * old one, in which case we just copy the data.
+ */
+ inbuf = server->packet;
+ if (buf_len >= server->packet_size)
+ {
+ server->packet_size = buf_len;
+ server->packet = rcv_buf;
+ rcv_buf = inbuf;
+ } else
+ {
+#ifdef SMBFS_PARANOIA
+printk("smb_receive_trans2: copying data, old size=%d, new size=%u\n",
+server->packet_size, buf_len);
+#endif
+ memcpy(inbuf, rcv_buf, parm_len + data_len);
+ }
- fail:
- smb_vfree(rcv_buf);
+success:
+ *ldata = data_len;
+ *lparm = parm_len;
+out:
+ if (rcv_buf)
+ smb_vfree(rcv_buf);
return result;
+
+out_no_mem:
+#ifdef SMBFS_PARANOIA
+ printk("smb_receive_trans2: couldn't allocate data area\n");
+#endif
+ result = -ENOMEM;
+ goto out;
+out_too_long:
+ printk("smb_receive_trans2: data/param too long, data=%d, parm=%d\n",
+ data_tot, parm_tot);
+ goto out_error;
+out_data_grew:
+ printk("smb_receive_trans2: data/params grew!\n");
+ goto out_error;
+out_bad_parm:
+ printk("smb_receive_trans2: invalid parms, disp=%d, cnt=%d, tot=%d\n",
+ parm_disp, parm_count, parm_tot);
+ goto out_error;
+out_bad_data:
+ printk("smb_receive_trans2: invalid data, disp=%d, cnt=%d, tot=%d\n",
+ data_disp, data_count, data_tot);
+out_error:
+ result = -EIO;
+ goto out;
}
/*
@@ -537,9 +605,6 @@ smb_request(struct smb_sb_info *server)
unsigned char *buffer;
result = -EBADF;
- if (!server) /* this can't happen */
- goto bad_no_server;
-
buffer = server->packet;
if (!buffer)
goto bad_no_packet;
@@ -586,13 +651,12 @@ out:
return result;
bad_conn:
- printk("smb_request: result %d, setting invalid\n", result);
+#ifdef SMBFS_PARANOIA
+printk("smb_request: result %d, setting invalid\n", result);
+#endif
server->state = CONN_INVALID;
smb_invalidate_inodes(server);
goto out;
-bad_no_server:
- printk("smb_request: no server!\n");
- goto out;
bad_no_packet:
printk("smb_request: no packet!\n");
goto out;
@@ -631,6 +695,7 @@ smb_send_trans2(struct smb_sb_info *server, __u16 trans2_command,
struct iovec iov[4];
struct msghdr msg;
+ /* N.B. This test isn't valid! packet_size may be < max_xmit */
if ((bcc + oparam) > server->opt.max_xmit)
{
return -ENOMEM;
@@ -639,6 +704,7 @@ smb_send_trans2(struct smb_sb_info *server, __u16 trans2_command,
WSET(server->packet, smb_tpscnt, lparam);
WSET(server->packet, smb_tdscnt, ldata);
+ /* N.B. these values should reflect out current packet size */
WSET(server->packet, smb_mprcnt, TRANS2_MAX_TRANSFER);
WSET(server->packet, smb_mdrcnt, TRANS2_MAX_TRANSFER);
WSET(server->packet, smb_msrcnt, 0);
@@ -739,13 +805,14 @@ smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command,
}
if (result < 0)
goto bad_conn;
- pr_debug("smb_trans2_request: result = %d\n", result);
out:
return result;
bad_conn:
- printk("smb_trans2_request: connection bad, setting invalid\n");
+#ifdef SMBFS_PARANOIA
+printk("smb_trans2_request: result=%d, setting invalid\n", result);
+#endif
server->state = CONN_INVALID;
smb_invalidate_inodes(server);
goto out;
diff --git a/fs/super.c b/fs/super.c
index 39513df4b..b9e40e385 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -17,8 +17,6 @@
* Added change_root: Werner Almesberger & Hans Lermen, Feb '96
*/
-#include <stdarg.h>
-
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -47,6 +45,14 @@
#include <linux/nfs_fs_sb.h>
#include <linux/nfs_mount.h>
+/*
+ * We use a semaphore to synchronize all mount/umount
+ * activity - imagine the mess if we have a race between
+ * unmounting a filesystem and re-mounting it (or something
+ * else).
+ */
+static struct semaphore mount_sem = MUTEX;
+
extern void wait_for_keypress(void);
extern struct file_operations * get_blkfops(unsigned int major);
@@ -244,29 +250,24 @@ static int fs_maxindex(void)
/*
* Whee.. Weird sysv syscall.
*/
-asmlinkage int sys_sysfs(int option, ...)
+asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2)
{
- va_list args;
int retval = -EINVAL;
- unsigned int index;
lock_kernel();
- va_start(args, option);
switch (option) {
case 1:
- retval = fs_index(va_arg(args, const char *));
+ retval = fs_index((const char *) arg1);
break;
case 2:
- index = va_arg(args, unsigned int);
- retval = fs_name(index, va_arg(args, char *));
+ retval = fs_name(arg1, (char *) arg2);
break;
case 3:
retval = fs_maxindex();
break;
}
- va_end(args);
unlock_kernel();
return retval;
}
@@ -593,31 +594,11 @@ static int do_umount(kdev_t dev,int unmount_root)
if (!sb->s_root)
return -ENOENT;
-
- if (dev==ROOT_DEV && !unmount_root) {
- /*
- * Special case for "unmounting" root. We just try to remount
- * it readonly, and sync() the device.
- */
- if (!(sb->s_flags & MS_RDONLY)) {
- /*
- * Make sure all quotas are turned off on this device we need to mount
- * it readonly so no more writes by the quotasystem.
- * If later on the remount fails too bad there are no quotas running
- * anymore. Turn them on again by hand.
- */
- quota_off(dev, -1);
- fsync_dev(dev);
- retval = do_remount_sb(sb, MS_RDONLY, 0);
- return retval;
- }
- return 0;
- }
-
/*
- * Before checking if the filesystem is still busy make sure the kernel
- * doesn't hold any quotafiles open on that device. If the umount fails
- * too bad there are no quotas running anymore. Turn them on again by hand.
+ * Before checking whether the filesystem is still busy,
+ * make sure the kernel doesn't hold any quotafiles open
+ * on the device. If the umount fails, too bad -- there
+ * are no quotas running anymore. Just turn them on again.
*/
quota_off(dev, -1);
@@ -627,12 +608,23 @@ static int do_umount(kdev_t dev,int unmount_root)
* root entry should be in use and (b) that root entry is
* clean.
*/
- shrink_dcache();
+ shrink_dcache_sb(sb);
fsync_dev(dev);
+ if (dev==ROOT_DEV && !unmount_root) {
+ /*
+ * Special case for "unmounting" root ...
+ * we just try to remount it readonly.
+ */
+ retval = 0;
+ if (!(sb->s_flags & MS_RDONLY))
+ retval = do_remount_sb(sb, MS_RDONLY, 0);
+ return retval;
+ }
+
retval = d_umount(sb);
if (retval)
- return retval;
+ goto out;
/* Forget any inodes */
if (invalidate_inodes(sb)) {
@@ -647,7 +639,9 @@ static int do_umount(kdev_t dev,int unmount_root)
sb->s_op->put_super(sb);
}
remove_vfsmnt(dev);
- return 0;
+ retval = 0;
+out:
+ return retval;
}
static int umount_dev(kdev_t dev)
@@ -665,6 +659,9 @@ static int umount_dev(kdev_t dev)
goto out_iput;
fsync_dev(dev);
+
+ down(&mount_sem);
+
retval = do_umount(dev,0);
if (!retval) {
fsync_dev(dev);
@@ -673,6 +670,8 @@ static int umount_dev(kdev_t dev)
put_unnamed_dev(dev);
}
}
+
+ up(&mount_sem);
out_iput:
iput(inode);
out:
@@ -767,6 +766,7 @@ int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const cha
struct vfsmount *vfsmnt;
int error;
+ down(&mount_sem);
error = -EACCES;
if (!(flags & MS_RDONLY) && dev && is_read_only(dev))
goto out;
@@ -810,12 +810,14 @@ int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const cha
vfsmnt->mnt_sb = sb;
vfsmnt->mnt_flags = flags;
d_mount(dir_d, sb->s_root);
- return 0; /* we don't dput(dir) - see umount */
+ error = 0;
+ goto out; /* we don't dput(dir) - see umount */
}
dput_and_out:
dput(dir_d);
out:
+ up(&mount_sem);
return error;
}
@@ -831,6 +833,13 @@ static int do_remount_sb(struct super_block *sb, int flags, char *data)
int retval;
struct vfsmount *vfsmnt;
+ /*
+ * Invalidate the inodes, as some mount options may be changed.
+ * N.B. If we are changing media, we should check the return
+ * from invalidate_inodes ... can't allow _any_ open files.
+ */
+ invalidate_inodes(sb);
+
if (!(flags & MS_RDONLY) && sb->s_dev && is_read_only(sb->s_dev))
return -EACCES;
/*flags |= MS_RDONLY;*/
@@ -861,8 +870,14 @@ static int do_remount(const char *dir,int flags,char *data)
struct super_block * sb = dentry->d_inode->i_sb;
retval = -EINVAL;
- if (dentry == sb->s_root)
+ if (dentry == sb->s_root) {
+ /*
+ * Shrink the dcache and sync the device.
+ */
+ shrink_dcache_sb(sb);
+ fsync_dev(sb->s_dev);
retval = do_remount_sb(sb, flags, data);
+ }
dput(dentry);
}
return retval;
@@ -917,12 +932,11 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
struct file_system_type * fstype;
struct dentry * dentry = NULL;
struct inode * inode = NULL;
- struct file_operations * fops;
kdev_t dev;
int retval = -EPERM;
- const char * t;
unsigned long flags = 0;
unsigned long page = 0;
+ struct file dummy; /* allows read-write or read-only flag */
lock_kernel();
if (!suser())
@@ -938,6 +952,7 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
free_page(page);
goto out;
}
+
retval = copy_mount_options (type, &page);
if (retval < 0)
goto out;
@@ -946,8 +961,8 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
retval = -ENODEV;
if (!fstype)
goto out;
- t = fstype->name;
- fops = NULL;
+
+ memset(&dummy, 0, sizeof(dummy));
if (fstype->fs_flags & FS_REQUIRES_DEV) {
dentry = namei(dev_name);
retval = PTR_ERR(dentry);
@@ -968,17 +983,15 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
if (MAJOR(dev) >= MAX_BLKDEV)
goto dput_and_out;
- fops = get_blkfops(MAJOR(dev));
retval = -ENOTBLK;
- if (!fops)
+ dummy.f_op = get_blkfops(MAJOR(dev));
+ if (!dummy.f_op)
goto dput_and_out;
- if (fops->open) {
- struct file dummy; /* allows read-write or read-only flag */
- memset(&dummy, 0, sizeof(dummy));
+ if (dummy.f_op->open) {
dummy.f_dentry = dentry;
dummy.f_mode = (new_flags & MS_RDONLY) ? 1 : 3;
- retval = fops->open(inode, &dummy);
+ retval = dummy.f_op->open(inode, &dummy);
if (retval)
goto dput_and_out;
}
@@ -993,22 +1006,28 @@ asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) {
flags = new_flags & ~MS_MGC_MSK;
retval = copy_mount_options(data, &page);
- if (retval < 0) {
- put_unnamed_dev(dev);
- goto dput_and_out;
- }
+ if (retval < 0)
+ goto clean_up;
}
- retval = do_mount(dev,dev_name,dir_name,t,flags,(void *) page);
+ retval = do_mount(dev, dev_name, dir_name, fstype->name, flags,
+ (void *) page);
free_page(page);
- if (retval && fops && fops->release) {
- fops->release(inode, NULL);
- put_unnamed_dev(dev);
- }
+ if (retval)
+ goto clean_up;
+
dput_and_out:
dput(dentry);
out:
unlock_kernel();
return retval;
+
+clean_up:
+ if (dummy.f_op) {
+ if (dummy.f_op->release)
+ dummy.f_op->release(inode, NULL);
+ } else
+ put_unnamed_dev(dev);
+ goto dput_and_out;
}
__initfunc(static void do_mount_root(void))
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c
index ac0bd2923..e93f8bb11 100644
--- a/fs/sysv/dir.c
+++ b/fs/sysv/dir.c
@@ -21,8 +21,8 @@
#include <asm/uaccess.h>
-static long sysv_dir_read(struct inode * inode, struct file * filp,
- char * buf, unsigned long count)
+static ssize_t sysv_dir_read(struct file * filp, char * buf,
+ size_t count, loff_t *ppos)
{
return -EISDIR;
}
diff --git a/fs/sysv/file.c b/fs/sysv/file.c
index 1a28e4c2a..2bb442220 100644
--- a/fs/sysv/file.c
+++ b/fs/sysv/file.c
@@ -33,7 +33,7 @@
#include <linux/fs.h>
#include <linux/sysv_fs.h>
-static long sysv_file_write(struct inode *, struct file *, const char *, unsigned long);
+static ssize_t sysv_file_write(struct file *, const char *, size_t, loff_t *);
/*
* We have mostly NULL's here: the current defaults are ok for
@@ -72,18 +72,19 @@ struct inode_operations sysv_file_inode_operations = {
NULL /* permission */
};
-long sysv_file_read(struct inode * inode, struct file * filp,
- char * buf, unsigned long count)
+ssize_t sysv_file_read(struct file * filp, char * buf,
+ size_t count, loff_t *ppos)
{
+ struct inode * inode = filp->f_dentry->d_inode;
struct super_block * sb = inode->i_sb;
- int read,left,chars;
- unsigned int block;
- int blocks, offset;
+ ssize_t read,left,chars;
+ size_t block;
+ ssize_t blocks, offset;
int bhrequest, uptodate;
struct buffer_head ** bhb, ** bhe;
struct buffer_head * bhreq[NBUF];
struct buffer_head * buflist[NBUF];
- unsigned int size;
+ size_t size;
if (!inode) {
printk("sysv_file_read: inode = NULL\n");
@@ -93,7 +94,7 @@ long sysv_file_read(struct inode * inode, struct file * filp,
printk("sysv_file_read: mode = %07o\n",inode->i_mode);
return -EINVAL;
}
- offset = filp->f_pos;
+ offset = *ppos;
size = inode->i_size;
if (offset > size)
left = 0;
@@ -167,7 +168,7 @@ long sysv_file_read(struct inode * inode, struct file * filp,
chars = left;
else
chars = sb->sv_block_size - offset;
- filp->f_pos += chars;
+ *ppos += chars;
left -= chars;
read += chars;
if (*bhe) {
@@ -200,12 +201,13 @@ long sysv_file_read(struct inode * inode, struct file * filp,
return read;
}
-static long sysv_file_write(struct inode * inode, struct file * filp,
- const char * buf, unsigned long count)
+static ssize_t sysv_file_write(struct file * filp, const char * buf,
+ size_t count, loff_t *ppos)
{
+ struct inode * inode = filp->f_dentry->d_inode;
struct super_block * sb = inode->i_sb;
off_t pos;
- int written,c;
+ ssize_t written, c;
struct buffer_head * bh;
char * p;
@@ -227,7 +229,7 @@ static long sysv_file_write(struct inode * inode, struct file * filp,
if (filp->f_flags & O_APPEND)
pos = inode->i_size;
else
- pos = filp->f_pos;
+ pos = *ppos;
written = 0;
while (written<count) {
bh = sysv_getblk (inode, pos >> sb->sv_block_size_bits, 1);
@@ -265,7 +267,7 @@ static long sysv_file_write(struct inode * inode, struct file * filp,
brelse(bh);
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- filp->f_pos = pos;
+ *ppos = pos;
mark_inode_dirty(inode);
return written;
}
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index b2d7edfbc..d84a9524f 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -46,13 +46,14 @@ void sysv_put_inode(struct inode *inode)
static struct super_operations sysv_sops = {
sysv_read_inode,
- sysv_notify_change,
sysv_write_inode,
sysv_put_inode,
+ NULL, /* delete_inode */
+ sysv_notify_change,
sysv_put_super,
sysv_write_super,
sysv_statfs,
- NULL
+ NULL /* remount_fs */
};
/* The following functions try to recognize specific filesystems.
diff --git a/fs/vfat/Makefile b/fs/vfat/Makefile
index 354757b9a..df903636f 100644
--- a/fs/vfat/Makefile
+++ b/fs/vfat/Makefile
@@ -8,8 +8,8 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
O_TARGET := vfat.o
-O_OBJS :=
-OX_OBJS := namei.o
+O_OBJS := namei.o
+OX_OBJS := vfatfs_syms.o
M_OBJS := $(O_TARGET)
include $(TOPDIR)/Rules.make
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index 587291669..c1ff4176c 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -11,21 +11,20 @@
*/
#include <linux/config.h>
+#define __NO_VERSION__
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/msdos_fs.h>
+#include <linux/nls.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/mm.h>
-#include <linux/init.h>
-
-#include <asm/uaccess.h>
+#include <linux/malloc.h>
#include "../fat/msbuffer.h"
-#include "../fat/tables.h"
#if 0
# define PRINTK(x) printk x
@@ -79,13 +78,30 @@ static struct super_operations vfat_sops = {
NULL /* remount */
};
+static int simple_getbool(char *s, int *setval)
+{
+ if (s) {
+ if (!strcmp(s,"1") || !strcmp(s,"yes") || !strcmp(s,"true")) {
+ *setval = 1;
+ } else if (!strcmp(s,"0") || !strcmp(s,"no") || !strcmp(s,"false")) {
+ *setval = 0;
+ } else {
+ return 0;
+ }
+ } else {
+ *setval = 1;
+ }
+ return 1;
+}
+
static int parse_options(char *options, struct fat_mount_options *opts)
{
char *this_char,*value,save,*savep;
- int ret;
+ int ret, val;
opts->unicode_xlate = opts->posixfs = 0;
opts->numtail = 1;
+ opts->utf8 = 0;
if (!options) return 1;
save = 0;
@@ -97,25 +113,19 @@ static int parse_options(char *options, struct fat_mount_options *opts)
savep = value;
*value++ = 0;
}
- if (!strcmp(this_char,"uni_xlate")) {
- if (value) {
- ret = 0;
- } else {
- opts->unicode_xlate = 1;
- }
- }
- else if (!strcmp(this_char,"posix")) {
- if (value) {
- ret = 0;
- } else {
- opts->posixfs = 1;
- }
- }
- else if (!strcmp(this_char,"nonumtail")) {
- if (value) {
- ret = 0;
- } else {
- opts->numtail = 0;
+ if (!strcmp(this_char,"utf8")) {
+ ret = simple_getbool(value, &val);
+ if (ret) opts->utf8 = val;
+ } else if (!strcmp(this_char,"uni_xlate")) {
+ ret = simple_getbool(value, &val);
+ if (ret) opts->unicode_xlate = val;
+ } else if (!strcmp(this_char,"posix")) {
+ ret = simple_getbool(value, &val);
+ if (ret) opts->posixfs = val;
+ } else if (!strcmp(this_char,"nonumtail")) {
+ ret = simple_getbool(value, &val);
+ if (ret) {
+ opts->numtail = !val;
}
}
if (this_char != options)
@@ -127,6 +137,9 @@ static int parse_options(char *options, struct fat_mount_options *opts)
return 0;
}
}
+ if (opts->unicode_xlate) {
+ opts->utf8 = 0;
+ }
return 1;
}
@@ -137,6 +150,8 @@ struct super_block *vfat_read_super(struct super_block *sb,void *data,
MOD_INC_USE_COUNT;
+ MSDOS_SB(sb)->options.isvfat = 1;
+
sb->s_op = &vfat_sops;
res = fat_read_super(sb, data, silent);
if (res == NULL) {
@@ -148,7 +163,6 @@ struct super_block *vfat_read_super(struct super_block *sb,void *data,
if (!parse_options((char *) data, &(MSDOS_SB(sb)->options))) {
MOD_DEC_USE_COUNT;
} else {
- MSDOS_SB(sb)->options.isvfat = 1;
MSDOS_SB(sb)->options.dotsOK = 0;
}
@@ -225,7 +239,6 @@ static const char *reserved_names[] = {
/* Characters that are undesirable in an MS-DOS file name */
static char bad_chars[] = "*?<>|\":/\\";
-static char bad_if_strict[] = "+=,; []";
static char replace_chars[] = "[];,+=";
static int vfat_find(struct inode *dir,struct qstr* name,
@@ -265,8 +278,8 @@ static int vfat_valid_longname(const char *name, int len, int dot_dirs,
return 0;
}
-static int vfat_valid_shortname(char conv,const char *name,int len,
- int dot_dirs)
+static int vfat_valid_shortname(const char *name,int len,
+ int dot_dirs, int utf8)
{
const char *walk, **reserved;
unsigned char c;
@@ -283,17 +296,17 @@ static int vfat_valid_shortname(char conv,const char *name,int len,
for (walk = name; len && walk-name < 8;) {
c = *walk++;
len--;
- if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
- if (conv == 'x' && strchr(replace_chars,c)) return -EINVAL;
- if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
- if (c >= 'A' && c <= 'Z' && (conv == 's' || conv == 'x')) return -EINVAL;
+ if (utf8 && (c & 0x80)) return -EINVAL;
+ if (strchr(bad_chars,c)) return -EINVAL;
+ if (strchr(replace_chars,c)) return -EINVAL;
+ if (c >= 'A' && c <= 'Z') return -EINVAL;
if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
if ((walk == name) && (c == 0xE5)) c = 0x05;
if (c == '.') break;
space = c == ' ';
}
if (space) return -EINVAL;
- if ((conv == 's' || conv == 'x') && len && c != '.') {
+ if (len && c != '.') {
c = *walk++;
len--;
if (c != '.') return -EINVAL;
@@ -304,18 +317,17 @@ static int vfat_valid_shortname(char conv,const char *name,int len,
while (len > 0 && walk-name < (MSDOS_NAME+1)) {
c = *walk++;
len--;
- if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
- if (conv == 's' && strchr(bad_if_strict,c))
- return -EINVAL;
- if (conv == 'x' && strchr(replace_chars,c))
+ if (utf8 && (c & 0x80)) return -EINVAL;
+ if (strchr(bad_chars,c)) return -EINVAL;
+ if (strchr(replace_chars,c))
return -EINVAL;
if (c < ' ' || c == ':' || c == '\\' || c == '.')
return -EINVAL;
- if (c >= 'A' && c <= 'Z' && (conv == 's' || conv == 'x')) return -EINVAL;
+ if (c >= 'A' && c <= 'Z') return -EINVAL;
space = c == ' ';
}
if (space) return -EINVAL;
- if ((conv == 's' || conv == 'x') && len) return -EINVAL;
+ if (len) return -EINVAL;
}
for (reserved = reserved_names; *reserved; reserved++)
if (!strncmp(name,*reserved,8)) return -EINVAL;
@@ -328,8 +340,8 @@ static int vfat_valid_shortname(char conv,const char *name,int len,
* returned. The formatted short filename is returned in 'res'.
*/
-static int vfat_format_name(char conv,const char *name,int len,char *res,
- int dot_dirs)
+static int vfat_format_name(const char *name,int len,char *res,
+ int dot_dirs,int utf8)
{
char *walk;
const char **reserved;
@@ -349,17 +361,17 @@ static int vfat_format_name(char conv,const char *name,int len,char *res,
for (walk = res; len && walk-res < 8; walk++) {
c = *name++;
len--;
- if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
- if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
- if (conv == 'x' && strchr(replace_chars,c)) return -EINVAL;
- if (c >= 'A' && c <= 'Z' && (conv == 's' || conv == 'x')) return -EINVAL;
+ if (utf8 && (c & 0x80)) return -EINVAL;
+ if (strchr(bad_chars,c)) return -EINVAL;
+ if (strchr(replace_chars,c)) return -EINVAL;
+ if (c >= 'A' && c <= 'Z') return -EINVAL;
if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
if (c == '.') break;
space = c == ' ';
*walk = c >= 'a' && c <= 'z' ? c-32 : c;
}
if (space) return -EINVAL;
- if ((conv == 's' || conv == 'x') && len && c != '.') {
+ if (len && c != '.') {
c = *name++;
len--;
if (c != '.') return -EINVAL;
@@ -370,19 +382,18 @@ static int vfat_format_name(char conv,const char *name,int len,char *res,
while (len > 0 && walk-res < MSDOS_NAME) {
c = *name++;
len--;
- if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
- if (conv == 's' && strchr(bad_if_strict,c))
- return -EINVAL;
- if (conv == 'x' && strchr(replace_chars,c))
+ if (utf8 && (c & 0x80)) return -EINVAL;
+ if (strchr(bad_chars,c)) return -EINVAL;
+ if (strchr(replace_chars,c))
return -EINVAL;
if (c < ' ' || c == ':' || c == '\\' || c == '.')
return -EINVAL;
- if (c >= 'A' && c <= 'Z' && (conv == 's' || conv == 'x')) return -EINVAL;
+ if (c >= 'A' && c <= 'Z') return -EINVAL;
space = c == ' ';
*walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
}
if (space) return -EINVAL;
- if ((conv == 's' || conv == 'x') && len) return -EINVAL;
+ if (len) return -EINVAL;
}
while (walk-res < MSDOS_NAME) *walk++ = ' ';
for (reserved = reserved_names; *reserved; reserved++)
@@ -397,7 +408,7 @@ static char skip_chars[] = ".:\"?<>| ";
* shortname does not exist
*/
static int vfat_create_shortname(struct inode *dir, const char *name,
- int len, char *name_res)
+ int len, char *name_res, int utf8)
{
const char *ip, *ext_start, *end;
char *p;
@@ -417,16 +428,25 @@ static int vfat_create_shortname(struct inode *dir, const char *name,
if (len && name[len-1]==' ') return -EINVAL;
if (len <= 12) {
/* Do a case insensitive search if the name would be a valid
- * shortname if is were all capitalized */
+ * shortname if is were all capitalized. However, do not
+ * allow spaces in short names because Win95 scandisk does
+ * not like that */
+ res = 0;
for (i = 0, p = msdos_name, ip = name; i < len; i++, p++, ip++)
{
+ if (*ip == ' ') {
+ res = -1;
+ break;
+ }
if (*ip >= 'A' && *ip <= 'Z') {
*p = *ip + 32;
} else {
*p = *ip;
}
}
- res = vfat_format_name('x', msdos_name, len, name_res, 1);
+ if (res == 0) {
+ res = vfat_format_name(msdos_name, len, name_res, 1, utf8);
+ }
if (res > -1) {
PRINTK(("vfat_create_shortname 1\n"));
qname.name=msdos_name;
@@ -476,7 +496,10 @@ static int vfat_create_shortname(struct inode *dir, const char *name,
for (baselen = i = 0, p = base, ip = name; i < sz && baselen < 8; i++)
{
- if (!strchr(skip_chars, *ip)) {
+ if (utf8 && (*ip & 0x80)) {
+ *p++ = '_';
+ baselen++;
+ } else if (!strchr(skip_chars, *ip)) {
if (*ip >= 'A' && *ip <= 'Z') {
*p = *ip + 32;
} else {
@@ -496,7 +519,10 @@ static int vfat_create_shortname(struct inode *dir, const char *name,
if (ext_start) {
extlen = 0;
for (p = ext, ip = ext_start; extlen < 3 && ip < end; ip++) {
- if (!strchr(skip_chars, *ip)) {
+ if (utf8 && (*ip & 0x80)) {
+ *p++ = '_';
+ extlen++;
+ } else if (!strchr(skip_chars, *ip)) {
if (*ip >= 'A' && *ip <= 'Z') {
*p = *ip + 32;
} else {
@@ -547,7 +573,7 @@ static int vfat_create_shortname(struct inode *dir, const char *name,
qname.len=totlen;
res = vfat_find(dir, &qname, 0, 0, 0, &sinfo);
}
- res = vfat_format_name('x', msdos_name, totlen, name_res, 1);
+ res = vfat_format_name(msdos_name, totlen, name_res, 1, utf8);
return res;
}
@@ -596,7 +622,9 @@ static loff_t vfat_find_free_slots(struct inode *dir,int slots)
ino = fat_get_entry(dir,&curr,&bh,&de);
}
- if (dir->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
+ if ((dir->i_ino == MSDOS_ROOT_INO) &&
+ (MSDOS_SB(sb)->fat_bits != 32))
+ return -ENOSPC;
if ((res = fat_add_cluster(dir)) < 0) return res;
ino = fat_get_entry(dir,&curr,&bh,&de);
}
@@ -605,7 +633,8 @@ static loff_t vfat_find_free_slots(struct inode *dir,int slots)
/* Translate a string, including coded sequences into Unicode */
static int
-xlate_to_uni(const char *name, int len, char *outname, int *outlen, int escape)
+xlate_to_uni(const char *name, int len, char *outname, int *outlen,
+ int escape, int utf8, struct nls_table *nls)
{
int i;
const unsigned char *ip;
@@ -613,22 +642,43 @@ xlate_to_uni(const char *name, int len, char *outname, int *outlen, int escape)
int fill;
unsigned char c1, c2, c3;
- op = outname;
- for (i = 0, ip = name, op = outname, *outlen = 0;
- i < len && *outlen <= 260; i++, *outlen += 1)
- {
- if (escape && (i < len - 4) &&
- (*ip == ':') &&
- ((c1 = fat_code2uni[ip[1]]) != 255) &&
- ((c2 = fat_code2uni[ip[2]]) != 255) &&
- ((c3 = fat_code2uni[ip[3]]) != 255)) {
- *op++ = (c1 << 4) + (c2 >> 2);
- *op++ = ((c2 & 0x3) << 6) + c3;
- ip += 4;
+ if (utf8) {
+ *outlen = utf8_mbstowcs((__u16 *) outname, name, PAGE_SIZE);
+ if (name[len-1] == '.')
+ *outlen-=2;
+ op = &outname[*outlen * sizeof(__u16)];
+ } else {
+ if (name[len-1] == '.')
+ len--;
+ op = outname;
+ if (nls) {
+ /* XXX: i is incorrectly computed. */
+ for (i = 0, ip = name, op = outname, *outlen = 0;
+ i < len && *outlen <= 260; i++, *outlen += 1)
+ {
+ if (escape && (*ip == ':')) {
+ if (i > len - 4) return -EINVAL;
+ c1 = fat_esc2uni[ip[1]];
+ c2 = fat_esc2uni[ip[2]];
+ c3 = fat_esc2uni[ip[3]];
+ if (c1 == 255 || c2 == 255 || c3 == 255)
+ return -EINVAL;
+ *op++ = (c1 << 4) + (c2 >> 2);
+ *op++ = ((c2 & 0x3) << 6) + c3;
+ ip += 4;
+ } else {
+ *op++ = nls->charset2uni[*ip].uni1;
+ *op++ = nls->charset2uni[*ip].uni2;
+ ip++;
+ }
+ }
} else {
- *op++ = fat_a2uni[*ip].uni1;
- *op++ = fat_a2uni[*ip].uni2;
- ip++;
+ for (i = 0, ip = name, op = outname, *outlen = 0;
+ i < len && *outlen <= 260; i++, *outlen += 1)
+ {
+ *op++ = *ip++;
+ *op++ = 0;
+ }
}
}
if (*outlen > 260)
@@ -653,7 +703,8 @@ xlate_to_uni(const char *name, int len, char *outname, int *outlen, int escape)
static int
vfat_fill_long_slots(struct msdos_dir_slot *ds, const char *name, int len,
- char *msdos_name, int *slots, int uni_xlate)
+ char *msdos_name, int *slots,
+ int uni_xlate, int utf8, struct nls_table *nls)
{
struct msdos_dir_slot *ps;
struct msdos_dir_entry *de;
@@ -667,10 +718,11 @@ vfat_fill_long_slots(struct msdos_dir_slot *ds, const char *name, int len,
int i;
loff_t offset;
+ if (name[len-1] == '.') len--;
if(!(page = __get_free_page(GFP_KERNEL)))
return -ENOMEM;
uniname = (char *) page;
- res = xlate_to_uni(name, len, uniname, &unilen, uni_xlate);
+ res = xlate_to_uni(name, len, uniname, &unilen, uni_xlate, utf8, nls);
if (res < 0) {
free_page(page);
return res;
@@ -690,8 +742,7 @@ vfat_fill_long_slots(struct msdos_dir_slot *ds, const char *name, int len,
ps->attr = ATTR_EXT;
ps->reserved = 0;
ps->alias_checksum = cksum;
- ps->start[0] = 0;
- ps->start[1] = 0;
+ ps->start = 0;
PRINTK(("vfat_fill_long_slots 5: uniname=%s\n",uniname));
offset = (slot - 1) * 26;
ip = &uniname[offset];
@@ -728,11 +779,14 @@ static int vfat_build_slots(struct inode *dir,const char *name,int len,
{
struct msdos_dir_entry *de;
char msdos_name[MSDOS_NAME];
- int res, xlate;
+ int res, xlate, utf8;
+ struct nls_table *nls;
PRINTK(("Entering vfat_build_slots: name=%s, len=%d\n", name, len));
de = (struct msdos_dir_entry *) ds;
xlate = MSDOS_SB(dir->i_sb)->options.unicode_xlate;
+ utf8 = MSDOS_SB(dir->i_sb)->options.utf8;
+ nls = MSDOS_SB(dir->i_sb)->nls_io;
*slots = 1;
*is_long = 0;
@@ -742,13 +796,13 @@ static int vfat_build_slots(struct inode *dir,const char *name,int len,
strncpy(de->name, MSDOS_DOT, MSDOS_NAME);
} else {
PRINTK(("vfat_build_slots 4\n"));
- res = vfat_valid_shortname('x', name, len, 1);
+ res = vfat_valid_shortname(name, len, 1, utf8);
if (res > -1) {
PRINTK(("vfat_build_slots 5a\n"));
- res = vfat_format_name('x', name, len, de->name, 1);
+ res = vfat_format_name(name, len, de->name, 1, utf8);
PRINTK(("vfat_build_slots 5b\n"));
} else {
- res = vfat_create_shortname(dir, name, len, msdos_name);
+ res = vfat_create_shortname(dir, name, len, msdos_name, utf8);
if (res < 0) {
return res;
}
@@ -761,7 +815,7 @@ static int vfat_build_slots(struct inode *dir,const char *name,int len,
*is_long = 1;
return vfat_fill_long_slots(ds, name, len, msdos_name,
- slots, xlate);
+ slots, xlate, utf8, nls);
}
}
return 0;
@@ -787,8 +841,11 @@ static int vfat_readdir_cb(
vf->name, vf->len, name, name_len);
#endif
+ /* Filenames cannot end in '.' or we treat like it has none */
if (vf->len != name_len) {
- return 0;
+ if ((vf->len != name_len + 1) || (vf->name[name_len] != '.')) {
+ return 0;
+ }
}
s1 = name; s2 = vf->name;
@@ -821,12 +878,17 @@ static int vfat_find(struct inode *dir,struct qstr* qname,
struct msdos_dir_entry *de;
struct msdos_dir_slot *ps;
loff_t offset;
- struct msdos_dir_slot ds[MSDOS_SLOTS];
+ struct msdos_dir_slot *ds;
int is_long;
int slots, slot;
int res;
PRINTK(("Entering vfat_find\n"));
+
+ ds = (struct msdos_dir_slot *)
+ kmalloc(sizeof(struct msdos_dir_slot)*MSDOS_SLOTS, GFP_KERNEL);
+ if (ds == NULL) return -ENOMEM;
+
fil.f_pos = 0;
vf.name = qname->name;
vf.len = qname->len;
@@ -835,10 +897,11 @@ static int vfat_find(struct inode *dir,struct qstr* qname,
vf.posix = MSDOS_SB(sb)->options.posixfs;
res = fat_readdirx(dir,&fil,(void *)&vf,vfat_readdir_cb,NULL,1,find_long,0);
PRINTK(("vfat_find: Debug 1\n"));
- if (res < 0) return res;
+ if (res < 0) goto cleanup;
if (vf.found) {
if (new_filename) {
- return -EEXIST;
+ res = -EEXIST;
+ goto cleanup;
}
sinfo_out->longname_offset = vf.offset;
sinfo_out->shortname_offset = vf.short_offset;
@@ -848,16 +911,19 @@ static int vfat_find(struct inode *dir,struct qstr* qname,
sinfo_out->ino = vf.ino;
PRINTK(("vfat_find: Debug 2\n"));
- return 0;
+ res = 0;
+ goto cleanup;
}
PRINTK(("vfat_find: Debug 3\n"));
- if (!vf.found && !new_filename)
- return -ENOENT;
+ if (!vf.found && !new_filename) {
+ res = -ENOENT;
+ goto cleanup;
+ }
res = vfat_build_slots(dir, qname->name, qname->len, ds,
&slots, &is_long);
- if (res < 0) return res;
+ if (res < 0) goto cleanup;
de = (struct msdos_dir_entry *) ds;
@@ -867,7 +933,8 @@ static int vfat_find(struct inode *dir,struct qstr* qname,
if (is_long) slots++;
offset = vfat_find_free_slots(dir, slots);
if (offset < 0) {
- return offset;
+ res = offset;
+ goto cleanup;
}
PRINTK(("vfat_find: create file 2\n"));
@@ -878,7 +945,8 @@ static int vfat_find(struct inode *dir,struct qstr* qname,
sinfo_out->ino = fat_get_entry(dir,&offset,&bh,&de);
if (sinfo_out->ino < 0) {
PRINTK(("vfat_find: problem\n"));
- return sinfo_out->ino;
+ res = sinfo_out->ino;
+ goto cleanup;
}
memcpy(de, ps, sizeof(struct msdos_dir_slot));
fat_mark_buffer_dirty(sb, bh, 1);
@@ -890,12 +958,12 @@ static int vfat_find(struct inode *dir,struct qstr* qname,
PRINTK(("vfat_find: create file 5\n"));
- memset(de->unused, 0, sizeof(de->unused));
fat_date_unix2dos(dir->i_mtime,&de->time,&de->date);
de->ctime_ms = 0;
de->ctime = de->time;
de->adate = de->cdate = de->date;
de->start = 0;
+ de->starthi = 0;
de->size = 0;
de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
de->lcase = CASE_LOWER_BASE | CASE_LOWER_EXT;
@@ -913,10 +981,15 @@ static int vfat_find(struct inode *dir,struct qstr* qname,
sinfo_out->total_slots = slots;
sinfo_out->shortname_offset = offset - sizeof(struct msdos_dir_slot);
sinfo_out->longname_offset = offset - sizeof(struct msdos_dir_slot) * slots;
+ res = 0;
return 0;
+ } else {
+ res = -ENOENT;
}
- return -ENOENT;
+cleanup:
+ kfree(ds);
+ return res;
}
int vfat_lookup(struct inode *dir,struct dentry *dentry)
@@ -1040,10 +1113,10 @@ static int vfat_create_a_dotdir(struct inode *dir,struct inode *parent,
dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
mark_inode_dirty(dir);
memcpy(de->name,name,MSDOS_NAME);
- memset(de->unused, 0, sizeof(de->unused));
de->lcase = 0;
de->attr = ATTR_DIR;
de->start = 0;
+ de->starthi = 0;
fat_date_unix2dos(dir->i_mtime,&de->time,&de->date);
de->ctime_ms = 0;
de->ctime = de->time;
@@ -1058,10 +1131,12 @@ static int vfat_create_a_dotdir(struct inode *dir,struct inode *parent,
if (isdot) {
dot->i_size = dir->i_size;
MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start;
+ MSDOS_I(dot)->i_logstart = MSDOS_I(dir)->i_logstart;
dot->i_nlink = dir->i_nlink;
} else {
dot->i_size = parent->i_size;
MSDOS_I(dot)->i_start = MSDOS_I(parent)->i_start;
+ MSDOS_I(dot)->i_logstart = MSDOS_I(parent)->i_logstart;
dot->i_nlink = parent->i_nlink;
}
@@ -1244,10 +1319,8 @@ static int vfat_rmdirx(struct inode *dir,struct dentry* dentry)
if (res > 0) {
res = 0;
}
- } else {
- printk("Problem in vfat_rmdirx\n");
+ dir->i_version = ++event;
}
- dir->i_version = ++event;
rmdir_done:
fat_brelse(sb, bh);
@@ -1275,19 +1348,15 @@ static int vfat_unlinkx(
struct slot_info sinfo;
bh = NULL;
- if ((res = vfat_find(dir,&dentry->d_name,1,0,0,&sinfo)) < 0)
- goto unlink_done;
+ res = vfat_find(dir,&dentry->d_name,1,0,0,&sinfo);
if (res >= 0 && sinfo.total_slots > 0) {
res = vfat_remove_entry(dir,&sinfo,&bh,dentry,0,nospc);
if (res > 0) {
res = 0;
}
- } else {
- printk("Problem in vfat_unlinkx: res=%d, total_slots=%d\n",res, sinfo.total_slots);
}
-unlink_done:
fat_brelse(sb, bh);
return res;
}
@@ -1329,7 +1398,16 @@ int vfat_unlink(struct inode *dir,struct dentry* dentry)
return res;
}
+/***** Unlink, as called for uvfatfs */
+int vfat_unlink_uvfat(struct inode *dir,struct dentry *dentry)
+{
+ int res;
+ res = vfat_unlinkx (dir,dentry,0);
+ iput(dir);
+ return res;
+}
+
int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
struct inode *new_dir,struct dentry *new_dentry)
{
@@ -1337,8 +1415,9 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
struct buffer_head *old_bh,*new_bh,*dotdot_bh;
struct msdos_dir_entry *old_de,*new_de,*dotdot_de;
loff_t old_offset,new_offset,old_longname_offset;
- int old_slots,old_ino,new_ino,dotdot_ino,ino;
- struct inode *old_inode, *new_inode, *dotdot_inode, *walk;
+ int old_slots,old_ino,new_ino,dotdot_ino;
+ struct inode *old_inode, *new_inode, *dotdot_inode;
+ struct dentry *walk;
int res, is_dir, i;
int locked = 0;
struct slot_info sinfo;
@@ -1373,25 +1452,13 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
res = -EINVAL;
goto rename_done;
}
- if (!(walk = iget(new_dir->i_sb,new_dir->i_ino))) return -EIO;
+ walk = new_dentry;
/* prevent moving directory below itself */
- while (walk->i_ino != MSDOS_ROOT_INO) {
- ino = fat_parent_ino(walk,1);
- iput(walk);
- if (ino < 0) {
- res = ino;
- goto rename_done;
- }
- if (ino == old_ino) {
- res = -EINVAL;
- goto rename_done;
- }
- if (!(walk = iget(new_dir->i_sb,ino))) {
- res = -EIO;
- goto rename_done;
- }
+ for (;;) {
+ if (walk == old_dentry) return -EINVAL;
+ if (walk == walk->d_parent) break;
+ walk = walk->d_parent;
}
- iput(walk);
}
res = vfat_find(new_dir,&new_dentry->d_name,1,0,is_dir,&sinfo);
@@ -1417,10 +1484,13 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
PRINTK(("vfat_rename 8\n"));
if (res < 0) goto rename_done;
} else {
- PRINTK(("vfat_rename 9\n"));
- res = vfat_unlinkx(new_dir,new_dentry,1);
- PRINTK(("vfat_rename 10\n"));
- if (res < 0) goto rename_done;
+ /* Is this the same file, different case? */
+ if (new_inode != old_inode) {
+ PRINTK(("vfat_rename 9\n"));
+ res = vfat_unlinkx(new_dir,new_dentry,1);
+ PRINTK(("vfat_rename 10\n"));
+ if (res < 0) goto rename_done;
+ }
}
}
@@ -1444,6 +1514,7 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
new_de->cdate = old_de->cdate;
new_de->adate = old_de->adate;
new_de->start = old_de->start;
+ new_de->starthi = old_de->starthi;
new_de->size = old_de->size;
if (!(new_inode = iget(new_dir->i_sb,new_ino))) goto rename_done;
@@ -1492,8 +1563,10 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
res = -EIO;
goto rename_done;
}
- dotdot_de->start = MSDOS_I(dotdot_inode)->i_start =
- MSDOS_I(new_dir)->i_start;
+ MSDOS_I(dotdot_inode)->i_start = MSDOS_I(new_dir)->i_start;
+ MSDOS_I(dotdot_inode)->i_logstart = MSDOS_I(new_dir)->i_logstart;
+ dotdot_de->start = CT_LE_W(MSDOS_I(new_dir)->i_logstart);
+ dotdot_de->starthi = CT_LE_W((MSDOS_I(new_dir)->i_logstart) >> 16);
mark_inode_dirty(dotdot_inode);
fat_mark_buffer_dirty(sb, dotdot_bh, 1);
old_dir->i_nlink--;
@@ -1505,8 +1578,9 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
}
if (res > 0) res = 0;
- d_instantiate(new_dentry,new_inode);
- d_delete(old_dentry);
+ if (res == 0) {
+ d_move(old_dentry, new_dentry);
+ }
rename_done:
if (locked)
@@ -1547,28 +1621,6 @@ void vfat_read_inode(struct inode *inode)
fat_read_inode(inode, &vfat_dir_inode_operations);
}
-static struct file_system_type vfat_fs_type = {
- "vfat",
- FS_REQUIRES_DEV,
- vfat_read_super,
- NULL
-};
-
-EXPORT_SYMBOL(vfat_create);
-EXPORT_SYMBOL(vfat_unlink);
-EXPORT_SYMBOL(vfat_mkdir);
-EXPORT_SYMBOL(vfat_rmdir);
-EXPORT_SYMBOL(vfat_rename);
-EXPORT_SYMBOL(vfat_put_super);
-EXPORT_SYMBOL(vfat_read_super);
-EXPORT_SYMBOL(vfat_read_inode);
-EXPORT_SYMBOL(vfat_lookup);
-
-__initfunc(int init_vfat_fs(void))
-{
- return register_filesystem(&vfat_fs_type);
-}
-
#ifdef MODULE
int init_module(void)
{
diff --git a/fs/vfat/vfatfs_syms.c b/fs/vfat/vfatfs_syms.c
new file mode 100644
index 000000000..739d8eae7
--- /dev/null
+++ b/fs/vfat/vfatfs_syms.c
@@ -0,0 +1,37 @@
+/*
+ * linux/fs/msdos/vfatfs_syms.c
+ *
+ * Exported kernel symbols for the VFAT filesystem.
+ * These symbols are used by dmsdos.
+ */
+
+#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S))
+#include <linux/version.h>
+#include <linux/module.h>
+
+#include <linux/mm.h>
+#include <linux/msdos_fs.h>
+
+struct file_system_type vfat_fs_type = {
+ "vfat",
+ FS_REQUIRES_DEV,
+ vfat_read_super,
+ NULL
+};
+
+EXPORT_SYMBOL(vfat_create);
+EXPORT_SYMBOL(vfat_unlink);
+EXPORT_SYMBOL(vfat_unlink_uvfat);
+EXPORT_SYMBOL(vfat_mkdir);
+EXPORT_SYMBOL(vfat_rmdir);
+EXPORT_SYMBOL(vfat_rename);
+EXPORT_SYMBOL(vfat_put_super);
+EXPORT_SYMBOL(vfat_read_super);
+EXPORT_SYMBOL(vfat_read_inode);
+EXPORT_SYMBOL(vfat_lookup);
+
+int init_vfat_fs(void)
+{
+ return register_filesystem(&vfat_fs_type);
+}
+