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命令如下:
    ? View Code BASH
    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自带的一个小程序,本质就是一个简单的转发函数;mount.cifs跟mount -t cifs唯一的区别就是mount.cifs在samba软件包里,而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文件里,三个有关选项的默认设置如下:

? View Code BASH
unix extensions = yes follow symlinks = yes wide 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,啥也不用干。


3 responses to “五一的破事:smbfs/cifs”


  1. mount smbfs的问题困扰我了很久,你这篇文章让我知道了cifs,并大致解决了问题,先谢过 :)
    不过有个问题,我试了,也看了man mount.cifs,发现cifs似乎是使用unicode传送路径的,所以iocharset选项用来进行linux端路径的编码与unicode间 的转换,所以应该指定linux的编码。如我的linux是utf8的locale,iocharset=utf8,而不是cp936.

  2. 呵呵,这篇文章写了很久了,有些地方当时没认识清楚现在也一直没空改:(

    mount.cifs的iocharset的确是指本地编码,我本地是utf8的,当时设置成iocharset=cp936是因为一些比较复杂的原因…现在改回来成iocharset=utf8了,呵呵~~

    多谢指正:)我得抽时间改了,以免贻笑方家。

你可能感兴趣的:(smbfs/cifs)