diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-12-06 23:51:34 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1997-12-06 23:51:34 +0000 |
commit | 230e5ab6a084ed50470f101934782dbf54b0d06b (patch) | |
tree | 5dd821c8d33f450470588e7a543f74bf74306e9e /fs | |
parent | c9b1c8a64c6444d189856f1e26bdcb8b4cd0113a (diff) |
Merge with Linux 2.1.67.
Diffstat (limited to 'fs')
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(¤t->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 && @@ -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(¤t->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); @@ -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: + */ @@ -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", +¶m[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", +¶m[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); +} + |