论坛: UNIX系统 标题: Linux2.4.x核心的NLS补丁(解决在linux下看windows分区文件名的问题) 复制本贴地址    
作者: magic [buaaytt]    论坛用户   登录
作者:zhangtao <zhangtao @ zhangtao . org> 
  版权:GNU GPL
 

内容简介:Linux 2.4.x 核心的NLS 补丁,这个补丁是修正 CP932、CP936、CP949、CP950的转换表的问题。

 

下载:

patch包: nls_932_936_949_950.patch.tgz (用法:在/usr/src/linux目录下,执行patch -p1 ...)

完整的源代码包:nls_932_936_949_950.tgz

生成源程序的包:build_cp932.tgz, build_cp936.tgz, build_cp949.tgz 和 build_cp950.tgz

 

描述:
简介:

Linux核心的NLS支持,对于东亚区语言的支持含有错误。在本文中您将了解其错误原因,并给出了解决办法。希望Linux核心开发团队能够注意此问题。
NLS是什么?

NLS 是Native Language Supportt的缩写,意即“本地语言支持”。其主要作用是在Unicode(这里指的是UTF-16格式)和本地语言字符之间进行相互转换。 Linux核心中的NLS支持放在 LINUX_KERNEL_SOURCE(一般是/usr/src/linux)目录下的fs/nls目录下,所有的文件都是以nls_开头的C程序;一般情况下,我们把他们编译成可加载的核心模块,而后放在lib/modules/KERNEL_VERSION/kernel/fs/nls目录下面(KERNEL_VERSION是核心的版本号,例如:2.4.20-19)。

某些文件系统使用了Unicode编码,即它的目录、文件名在磁盘/光盘上是以Unicode编码方式存储的。然而Linux控制台(Console)使用的是本地语言,许多程序对目录、文件名进行操作时也是如此。为此,就需要在Unicode和本地语言之间进行转换,以便能够在控制台上显示正常的目录、文件名。属于这类的常见文件系统,包括用于Windows 9x系列的fat和vfat,用于Windows NT的NTFS,ISO-9660 CDROM文件系统的Microsoft Joliet CDROM扩展。注意:NLS并不会影响文件中的内容,而只是影响文件、目录名。
NLS如何使用?

像其他可加载的核心模块,可以使用命令:"insmod nls_cpxxx.o"来使用此NLS模块。但是除非你mount设备时使用了特殊的参数,否则它根本不会被使用。举个例子:如果我想mount一个 vfat的文件系统,假定它位于/dev/hda8,其中包含了许多简体中文的目录、文件名,则mount命令是:"mount -t vfat -o iocharset=cp936, codepage=936 /dev/hda8 /wind"。只有这样才能能够正常的看到中文的目录、文件名,否则按照核心的一般设置,它使用的是nls_iso8859-1来进行转换,中文就会变成 “?”字符。在这个命令中,最值得注意的是 iocharset 项目。按照mount手册的解释,它表示:在8bit的字符和16bit的字符间进行转换的字符集设置;缺省是iso8859-1;长文件名在磁盘存储时是Unicode格式的。顺便提一下:codepage项目是fat、vfat特有的选项,表示:把文件名转换为短文件名时所使用的字符集,缺省是 437,即美国、加拿大所使用的字符集。

同样,如果我想使用含有中文文件名的CDROM光盘,我应当使用这样的命令:mount -t iso9660 -o iocharset=cp936 /dev/cdrom /mnt/cdrom。
东亚语言

对于东亚地区的Linux用户来说,他们经常遇到的字符集有以下几种:
CP932 日本语(Shift-JIS,EUC-JP)
CP936 简体中文(CP936(就是GBK),GB2312)
Cp949 朝鲜语(CP949,EUC-KR)
CP950 繁体中文(Big5)

在nls_cp9xx.c中提到,其转换表是从 http://www.microsoft.com/typography/unicode/unicodecp.htm 下载的,虽然此页面目前还存在,但是其转换表的链接已经失效。正确的链接是这里 http://www.microsoft.com/globaldev/reference/cphome.mspx。不过这里微软并没有直接提供转换表下载,而是进行了分页图片显示。
问题描述

我在Windows 2000简体中文版下新建一个文本文件:“路浪不茶.good.txt”;然后,在Linux下的这个位置,也新建一个文本文件:“路浪不茶.bad.txt”。初看起来,一切正常。但是回到Windows环境,在资源管理器中,可以看到



仔细观察,你会发现这4个汉字有着微小的不同。

使用支持Unicode的程序打开这两个文件,例如:记事本、IE浏览器等,可以正常的打开文件并显示其内容。然而使用Visual C++打开时,程序报错:。

在cmd终端窗口下,如果我使用“新宋体”作为字体,就会发现“路浪不茶.bad.txt”中的汉字显示为四个方框;

如果我使用通常的终端字体,则显示为四个空格。

很有趣的是,我可以新建一个文件:“路浪不茶.bad.txt”,而不会产生冲突。

如果在Windows9x下,打开文件“路浪不茶.bad.txt”时会显示“文件系统错误”,并且无法删除。

我们已经知道,vfat文件系统存储的是Unicode的文件名。所以,虽然看起来很相象,但实际上上面提到的两个文件名中的汉字是不同的;也因此才能新建一个“所谓”的“同名文件”而居然不产生冲突错误。那么,问题出在哪里呢?

查看nls_cp936.c,可以知道本地语言到Unicode变换调用的是uni2char函数,反向则调用char2uni函数。uni2char函数对应的转换表是多个c2u_XX[256]数组(XX是要转换的本地语言字符的第一个字节的16进制表示),每个元素是一个wchar_t(2个字节),即对应的Unicode编码;char2uni函数对应的则多个是u2c_XX[512]数组(XX是要转换的Unicode字符的第一个字节的 16进制表示),每个元素是一个unsigned char,相邻的两个组成一个本地字符。

“路”字的GB编码是0xC2B7,正常的对应Unicode编码是0x8DEF。检查nls_cp936.c,查找到 c2u_C2[256],再看其第0xB7个元素是 0xF937。反过来,查找u2c_F9[512],再看其第0x37*2和0x37*2+1个元素,它们组成了0xC2B7。再查找u2c_8D [512],再看其第0xEF*2和0xEF*2+1个元素,它们同样组成了0xC2B7。也就是说,有两个Unicode字符对应同一个汉字,而此汉字转换成Unicode时,却偏偏选取了一个错误的值。“浪不茶”这些字存在着同样的问题。

之所以出现这样的问题,原因好像是转换表的问题。不过,我在互联网上搜索了许久,仍然找不到问题的来源。Linux核心文档说NLS的作者是Gordon Chaffee(主页是:http://bmrc.berkeley.edu/people/chaffee/),但是我无法找到任何相关的资料。因此,我只能猜测是转换表的问题。
解决办法

首先,必须找到一个正确的转换表。当然,可以从微软网站下载,不过需要手动的拼接;所以我选择了使用GNU LIBICONV(http://www.gnu.org/software/libiconv/)提供的转换表。下载地址是:http://web.mit.edu/afs/dev/source/src-current/third/libiconv/tests/GBK.TXT。这个文本的格式是:每行是一个记录,它有两部分,第一部分是本地语言字符,第二部分是对应的Unicode字符,两者都是16进制表示的。

接着,我写了两个perl脚本来转换文本到C程序格式。它们分别是c2u.pl 和 u2c.pl。使用方法是:"perl c2u.pl(u2c.pl) < GBK.txt >out.txt"

最后,把原来的nls_cp936.c的头尾部分,与脚本生成的转换表共同组成新的nls_cp936.c。头部分在这里,尾部分在这里。

检查CP932、CP949、CP950,可以发现同样的问题。仿照CP936的解决方法,可以生成新的C程序。

它们的源转换表分别是:
语言代码 源转换表 下载地址
CP932 CP932.TXT http://web.mit.edu/afs/dev/source/src-current/third/libiconv/tests/CP932.TXT
CP936 GBK.TXT http://web.mit.edu/afs/dev/source/src-current/third/libiconv/tests/GBK.TXT
CP949 CP949.TXT http://web.mit.edu/afs/dev/source/src-current/third/libiconv/tests/CP949.TXT
CP950 CP950.TXT http://web.mit.edu/afs/dev/source/src-current/third/libiconv/tests/CP950.TXT
2.6核心测试版仍旧有问题

我检查了最新的2.6.0test4核心(2003.8.23),对东亚语言的支持与2.4核心的相同。很明显,结果是仍然有此问题。

地主 发表时间: 12/04 10:51

论坛: UNIX系统

20CN网络安全小组版权所有
Copyright © 2000-2010 20CN Security Group. All Rights Reserved.
论坛程序编写:NetDemon

粤ICP备05087286号