关于mount/samba/字符集的两篇好文

来源:互联网 发布:好视通视频会议软件 编辑:程序博客网 时间:2024/05/20 15:11

第一篇:字符集和编码II: fat/msdos/vfat(链接至原作者博客)

具体到文件名乱码的问题,需要明确两点

  1. 第一,文件名作为一个字符串,需要被编码后存入文件系统;
  2. 第二,Linux内核无非是个特殊的应用程序,它读取文件名,再把文件名以编码后的形式传递出去。

但Linux内核只能逐字节处理编码流(而Windows NT内核是UCS-2的,逐2字节处理编码流),因此必须采用某种单字节编码(这包括所有的不定长编码)进行输出——这就是Linux内核所谓的NLS。

在对文件名的处理上,fat和vfat的区别在于:fat/msdos只支持短文件名(8.3命名法),而vfat加入了对长文件名和UNICODE的支持。

为了保持与fat的兼容性,在vfat中,每个文件同时拥有“长”文件名和短文件名,其中短文件名不区分大小写(实际上是不允许小写字母出现在文件名中)。可以这么理解,对于vfat,“长文件名”是文件真正的名字,“短文件名”则是提供兼容性的名字。举例来说,文件“真名”为abc.txt,它的短文件名是ABC.TXT;文件“真名”为alongname.txt,它的短文件名则是ALONGN~1.TXT。

无论是fat还是vfat,短文件名按codepage编码存储,长文件名按UNICODE编码存储。因此,如果文件的真名(也就是长文件名)是\(s\),短文件名是\(s’\),则它们在文件系统中分别被存储为\[s,\,\varphi_{enc} \left( s' \right).\]

为了访问fat/vfat文件系统,我们需要用内核的msdos或vfat模块。它们有三个跟字符集有关的内核参数:codepage,iocharset,utf8。我们来确定它们对应着什么样的编码或解码函数。

  • codepage=enc:用来转换短文件名中字节码为128~255的代码页。这一选项指定的是短文件名的解码函数\( \varphi_{enc}^{-1} \)(因为短文件名被codepage编码了),解码的结果是短文件名被用unicode表示;
  • iocharset=enc:用来转换长文件名和解码后的短文件名。也就是说,这一选项指定编码函数\(\varphi_{enc}\),使得内核最终的输出是经过\(\varphi_{enc}\)编码的;
  • utf8:几乎等于iocharset=utf8

这样,参数有如下的具体选择:

  • codepage:这一选项只跟短文件名有关。短文件名可以通过mount -t msdos看到,也可以用windows命令行看到。不在乎短文件名的同学,这个选项完全无所谓;在乎短文件名并且使用简体中文的同学,请写
    codepage=936
  • iocharset:分情况讨论。
    • 若locale(不知道什么是locale的同志请自行补课)不是utf8,则选择相应的locale,比如GB系就应该选
      iocharset=cp936
    • 若locale是utf8的,可以选择
      iocharset=utf8

      但这样做的缺点是会导致vfat模块将允许短文件名使用小写字母,这与windows是不兼容的(使用iocharset=utf8时,内核会出一条警告信息的);

  • utf8:一个解决办法是使用utf8参数,只要iocharset!=utf8,vfat就会处理大小写的问题;而utf8参数则会最终处理字符集的转换。utf8参数只能显式地通过mount调用(不能在编译内核时预先指定,当然也可以写在/etc/fstab里),我的意思是这个选项不能偷懒不写。

最后是结论:

  1. codepage=936,这一选项可以在内核默认设置;
  2. 本地locale是gb系的,参数应为
    mount -t vfat -o iocharset=cp936
  3. 本地locale是utf8的,如果能忍受内核每次都要警告,并且不跟windows交互,可以
    mount -t vfat -o iocharset=utf8
  4. 要是不能忍3或者交互时出现奇怪的问题,那就
    mount -t vfat -o iocharset=cp936,utf8

    实际上只要内核默认的iocharset不是utf8,直接写

    mount -o utf8

    就可以,这里iocharset=xxx的作用仅仅是处理大小写,所以怎么填都没关系。

我们来看一下这些选项究竟做了些什么事情,假设一个FAT文件系统在简体中文的windows上用过,而Linux程序的locale设置为UTF-8,文件名为\(s\),其短文件名为\(s’\)

  1. 在文件系统上(也就是在硬盘里),文件名被存为\(s\),短文件名被存为\(\varphi_{cp936} \left( s’ \right)\);
  2. 内核通过codepage=936选项,将映射\(\varphi_{cp936}^{-1}\)作用于\(\varphi_{cp936} \left( s’ \right)\),得到\[\varphi_{cp936}^{-1} \circ \varphi_{cp936} \left( s' \right) = s';\]
  3. 内核通过utf8或iocharset=utf8选项,将映射\(\varphi_{utf8}\)作用于\(s, s’\),最终向应用程序输出\[\varphi_{utf8} \left( s' \right), \varphi_{utf8} \left( s \right);\]
  4. 应用程序(如ls、nautilus)通过locale的设置,将\(\varphi_{utf8}^{-1}\)作用于内核输出,得到我们所看见的字符串\(s,s’\).

第二篇:smbfs/cifs(链接至原作者博客)

SMB/CIFS是M$用于网络文件和打印共享的协议,linux下有不少该协议的实现(详情请咨询wikipedia)。server端基本是samba一统天下,client端常用的则有samba和linux的内核vfs模块smbfs/cifs。其中smbfs是依赖于samba的(更具体的,smbfs需要调用samba提供的smbmount等模块),而cifs则是一个独立的实现(尽管samba也提供了一个helper小程序mount.cifs,但这仅仅是一个转发函数而已,真正的mount过程完全由内核实现;也就是说,不需要安装samba就可以直接使用mount -t cifs,mount.cifs可以看成mount -t cifs的shortcut)。

服务器端我们不做讨论,smbconf的文章满天飞。

先说samba,这基本是SMB/CIFS的一个完整实现。大多数应用程序(如mc/nautilus/dolphin/mplayer/cups等)对windows网络共享的访问都依赖于samba所提供的smbclient,并且通常使用smb://server/share/file这种形式的URL。对于简单和偶尔的文件共享,一般来说这足够用了;另外,要用cups进行打印只能用samba。

然而,smb://server/share/file这种形式毕竟用起来不方便,特别是大部分工具并不支持samba。这时候使用内核模块就很方便,因为对所有的应用程序来说都是透明的,而且只要不用windows打印机就完全不需要依赖samba。

前面提到过内核提供了两个vfs模块:smbfs和cifs(注意区分作为协议的CIFS和作为内核vfs模块的cifs)。简单来说,用cifs

一、字符集/编码问题

足够新的服务端(windows>98,samba>=3)默认采用Unicode作内部编码以及网络传输,一般不会带来太多字符集/编码上的问题。

smbfs和cifs牵涉到字符集/编码的选项有两个:codepage和iocharset,其含义和MS系的其他文件系统(dosfs, vfat, ntfs, etc.)是一致的,前者指服务器传入字节流的编码,后者指本地所用的编码(具体解释请参见该文)。由于cifs总假定服务器用Unicode传输(这个假定基本上不会有问题,有问题的时候就只好用smbfs了),因此它没有codepage选项。

下面简单说明一下使用内核cifs模块进行mount网络共享的设置。

  • 首先,保证服务端的网络传输字符集是Unicode。对于win2k之后的windows操作系统、以及正常配置的samba server,这一点一般不需要操心。(如果有特殊情况或需要而使得samba server的传输字符集不是Unicode,请参考该文)。
  • 其次,确定客户端(也就是本机)所用的字符集。支持中文的字符集有UTF-8,GB2312、GBK、GB18030等等。如果是UTF-8,取NLS=utf8;如果是GB2312、GBK、GB18030,取NLS=cp936。(对于足够新的发行版,基本上utf8一统天下。)
  • 最后的mount命令如下:
    mount -t cifs -o iocharset=${NLS},user=me,pass=you,file_mode=0644,dir_mode=0755,uid=subi,gid=subi //server/share /smbshare

    另外,mount.cifs是samba自带的一个小程序,就是一个简单的wrapper。我印象中mount.cifs主要的好处是它可以interactively地从标准输入接受用户名和密码,而mount -t cifs只能显式在命令行里指定。通常,mount.cifs在samba软件包里(有的发行版也给mount.cifs单独打包),而mount在util-linux软件包里。

二、Samba的符号链接

问题:对于Samba共享目录中的符号链接(这些link指向共享目录外),Windows客户端能当成普通目录透明访问的。但在smbfs或cifs客户端里,这些符号链接能被认出来,但是链接所指的的目录在本地机器上当然是不存在的(即使存在也是本地机器的内容),因此服务器的相应资源无法访问。而用samba所附的smbclient可以正确访问。

这个问题同时与samba服务器和smbfs、cifs有关。symlink是samba所实现的unix extension的一部分(其他还包括symlink、hardlink、uid、gid等)。samba、smbfs/cifs在某些版本都实现了对unix extension的支持,其中包括symlink。

对于symlink的解释,有两种方式完成:由samba服务器follow symlink,这时候客户端是看不到symlink的存在的(比如Win客户端总是这样);由客户端follow symlink,这时候客户端知道它们是符号链接。

因此,对于windows客户端,symlink总是由服务器处理;而对于linux客户端,特别的,对于smbfs和cifs,symlink的处理依赖于服务器端和客户端的配置。samba服务器的配置文件smb.conf文件里,三个有关选项的默认设置如下:

unix extensions = yesfollow symlinks = yeswide links=yes

第一个选项如果选no,则总是由服务器端来处理symlink,这时候linux的客户端和win的客户端表现是相同的——symlink被当作普通目录;而默认设置yes则是启用unix extensioin,在客户端(smbfs/cifs)也开启unix extension支持的情况下,将会看到symlink并由客户端来handle them。

第二、三个选项设置samba服务器处理symlink的方式:是否跟随链接、是否跟随指向共享目录外的链接。

而在客户端,windows就不说了。smbfs总是启用unix extension,而cifs可以通过/proc/fs/cifs/LinuxExtensionsEnabled来控制。

两种处理symlink的方式都有需求。在需要访问共享目录外内容时,由server follow link是唯一的选择;而把共享目录当作一般的网络文件系统,直接支持unix extension更符合linux的需要。如果想用smbfs又想看到共享目录外内容,请阅读Q:[30nov04] smbfs and smbclient behave differently with symlinks (soft links)进行相应的改动(修改服务器端的smb.conf或hack客户端的smbfs kernel code)。否则,最好的选择是cifs:希望由server follow link,只需将/proc/fs/cifs/LinuxExtensionsEnabled设为0后remount,该值默认为1,所以若由client follow link,啥也不用干。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 中通快递把我发的货弄坏了了怎么办 在淘宝获取不了丰巢柜提货码怎么办 京东快递提货码数手机号错了怎么办 腾讯手游助手不能玩刺激战场怎么办 刚收的京东快递质量有问题怎么办 拼多多买家接受信息没有声音怎么办 苹果6s外放声音有杂音怎么办 华为手机不小心把视频删了怎么办 电脑做完系统不显示声卡了怎么办 苹果手机自带浏览器看视频卡怎么办 pr剪辑的时候视频太卡怎么办 小米手机忘记登录账号密码了怎么办 石膏线条软模硅胶模具气泡多怎么办 京东白条开通失败怎么办金牌用户 买家说我运费险没赔要投诉我怎么办 包邮有运费险的东西想退货怎么办 高锰酸钾沾到龟头上形成黑点怎么办 淘宝发货包邮买家退款运费怎么办 京东实名认证的手机号不用了怎么办 淘宝退货在自提柜 卖家不取怎么办 如果买家退货那卖家送的东西怎么办 陆金所注册手机号被占用要怎么办 重新登录而忘记密码和验证码怎么办 手机清理垃圾清掉的照片怎么办 收件人名字写错了拿不到快递怎么办 档案回原籍收件人写错了怎么办 寄申通快递收件人电话写错了怎么办 第三方支付倒闭了用户的钱怎么办啊 京东配送日期内货没送到家怎么办 拼多多拼单不成功优惠券退吗怎么办 退货退错了不发回来怎么办 商家总是不发退货地址过来怎么办 美团外卖下单后电话没改怎么办 从日本邮寄东西到中国被扣怎么办 淘宝拒收卖家收到货不退款怎么办 拒收的快递丢了卖家拒绝退款怎么办 京东买了东西超过七天想退货怎么办 微信买东西支付宝付款被骗怎么办 京东购物己付款卖家没发货怎么办 天猫先行退款卖家拒收怎么办 京东金条提前还款借不了怎么办