文件的存取权限—模式位疑难详解
发布时间:2006-10-14 8:57:39   收集提供:gaoqian
一、前言
   ========

   本文主要说明Linux下普通文件及目录的存取权限设置。本文是为稍具基础的初学者写的(我也是beginner),如
   果您能够理解如下几行'ls -l'命令的输出含义(注意下面标注^的位),那您就没有必要读本文了——别浪费时
   间看对你没用的东西,时间是最宝贵的!

-r-sr-xr-x   1 root     bin         26975 Jun 24  1999 01:32 /usr/bin/passwd-----------1.1
   ^ 
-rwxrwSr-x   1 zyd      zyd         12506 Oct 29 10:27 test_euid-----------------------1.2
      ^
drwxrwxrwt   5 root     root         1024 Nov  1 17:17 01;34 /tmp----------------------1.3
^^^^     ^   ^
-rwxr-xr-x   2 zyd      zyd         32506 Oct 19 10:20 hard_link-----------------------1.4
             ^
lrwxr-xr-x   1 zyd      zyd         1 Oct 23 10:40 sym_link->/tmp/sym_target-----------1.5
^                                                            ^^^^^^^^^^^^^^^



   二、'ls -l'命令输出格式简介
   ===========================

   'ls -l'命令以长格式显示文件列表,其各字段含义如下:

lrwxr-xr-x   1 zyd      users         15 Oct 23 10:40 sym_link->/tmp/sym_target
 _________     ___      _____            ____________ ________  _______________
|    |       |  |         |            |       |          |            |
|    |       |  |         |            |       |          |            +--符号连接(s_link)
|    |       |  |         |            |       |          |
|    |       |  |         |            |       |          +-----文件名(name)
|    |       |  |         |            |       |
|    |       |  |         |            |       +----文件最后更改时间(time)
|    |       |  |         |            |
|    |       |  |         |            +------------以字节计的文件长度(size)
|    |       |  |         |
|    |       |  |         +----------文件属组(group)
|    |       |  |
|    |       |  +--------------------文件属主(user)
|    |       |
|    |       +-------连接数位(count)
|    |
|    +-------文件模式位(mode),占9位
|
+------------文件类型位(type),占一位

   以上9个字段中除了s_link外,其他字段对不同文件和目录都应该有。其中user、group、time和name的含义自
   明,本文就不再介绍,其它字段将分专题小节在本文介绍。


   三、文件类型(type)

   Linux支持的文件类型主要包括一下7类,箭头右面的字符就是相应的文件类型位标志:
   1、普通文件========>-
   2、目录文件========>d
   3、符号连接========>l
   4、字符设备文件====>c
   5、块设备文件======>b
   6、命名管道FIFO
   7、套接口socket

   其中FIFO和socket超出了本文的范畴,不做介绍。其它文件简单解释如下:

   1、普通文件:就是普通文件(废话!),你用'vi myfile'建立的myfile就是普通文件,比如可执行二进制代码
   文件、script脚本文件、ASCII文本文件、数据文件、配置文件......就解释到这样行吗?

   2、目录文件:目录可以理解成放其它文件和/或其它目录的容器,是一种特殊文件,其内容由目录项组成,每个
   目录项主要包括两部分内容:文件名name和索引节点号inode,两者和起来称为连接,我们将在下小节对inode
   进行更详细的介绍。

   3、设备文件:不知道诸位是否有使用DOS的经验,如果我们的机器只有三个DOS系统文件IO.SYS, MSDOS.SYS,
   COMMAND.COM,而你需要编辑一份英文文档,日后再通过打印机输出,你能怎么办?

   COPY CON MYDOC.TXT

   ;在此输入文档内容

   ^+D ;结束存盘

   COPY MYDOC.TXT > PRN ;打印文档

   如果你熟悉这个过程,那你就已经理解设备文件了。以上的CON和PRN分别是DOS定义的两个设备文件,分别对应
   终端和并行打印口。这种设计使我们不必了解设备使用的具体硬件细节,按使用普通文件相同的方法来使用外部
   设备。


   Linux下的设备文件分为三大类:字符设备、块设备和网络设备,要想准确区别它们可能需要单独写一篇更臭更
   长的文章,大致情况是:字符设备是直接读取的,不使用缓冲区,象串行口、终端等;而块设备都是通过缓冲区
   进行读取的,并且每次只能读取一定数量的块,比如磁盘每次至少要读取一个扇区(如512字节),块设备可以实
   现随机读写;网络设备即前面提到的socket,因为我还不很熟悉,就不乱说了。设备文件一般都保存在/dev目
   录下,诸位可以用ls -l命令看看都有什么?反正本文的重点在于介绍普通文件和目录,设备文件不是重点,所
   以就只介绍到这里。


   四、索引节点、硬连接和连接计数
   ==============================

   1、索引节点inode:

   Linux为每个文件分配一个称为索引节点的号码inode,可以将inode简单理解成一个指针,它永远指向本文件的
   具体存储位置。系统是通过索引节点(而不是文件名)来定位每一个文件。例如:

   假设我们在硬盘当前目录下建立了一个名为mytext文本文件,其内容只有一行:
   This is my file.
   当然这行文字一定是存储在磁盘数据区某个具体位置里(物理上要通过磁头号、柱面号和扇区号来描述,在本例
   中假设分别是1、20、30)。
   假设其inode是262457,那么系统通过一段标准程序,就能将这个inode转换成存放此文件的具体物理地址(1磁
   头、20柱面、30扇区),最终读出文件的内容:“This is my file.”
   所以inode是指向一个文件数据区的指针号码,一个inode对应着系统中唯一的一片物理数据区,而位于两个不
   同物理数据区的文件必定分别对应着两个不同的inode号码。

   文件拷贝命令:
   # cp /home/zyd/mytext newfile
   在当前工作目录建立了一个新文件newfile,其实际操作主要包括如下三步:
   1、在当前目录中增加一个目录项,其文件名域填入newfile,并分配了一个新的inode,假设是262456。
   2、将原文件(在1磁头、20柱面、30扇区)的内容复制了一份到新的空闲物理块(假设是1磁头、20柱面、31扇
   区)。
   3、填写一些其他关键信息,使系统通过这些信息及inode号码可以完成物理地址的转换。

   所以文件复制要分配新的inode和新的数据区,虽然两个文件的内容是一样的。


   2、硬连接hardlink:
   我们实际使用文件时一般是通过文件名来引用的。通过上面的讨论,我们知道:1个inode号码肯定和一片完全
   属于一个文件的数据区一一对应。那么一个文件系统中两个或更多个不同的文件名能否对应同一个文件呢?答案
   是肯定的。我们知道inode号码是记录在文件名对应的目录项中的,我们可以使两个或多个文件的目录项具有相
   同的inode值,实际上就使它们对应着同一个文件。有几个目录项具有相同的inode号,我们就说这个文件有几
   个硬连接(hardlink),对于普通文件,ls -l命令的连接计数count域的数值就是本文件拥有的硬连接数。硬连
   接可以通过ln命令建立,例如:

   # ln /home/zyd/mytext hardlink_mytext
   就建立了一个新的文件hardlink_mytext,这个文件的inode同样是262457。建立硬连接实际上只是增加了一个
   目录项,但并复制文件数据区,原文件的数据区由两个文件共享。这一方面能够节约大量磁盘空间,同时可以保
   证两个文件能同步更新。

   'ls -il'可以显示文件的inode(在下面最左边):

   262456 -rw-rw-r-- 1 zyd zyd 17 Nov 3 14:52 newfile
   262457 -rw-rw-r-- 2 zyd zyd 17 Nov 3 14:50 hardlink_mytext
   262457 -rw-rw-r-- 2 zyd zyd 17 Nov 3 14:50 mytext


   3、连接计数count:

   前面我们介绍了,文件的连接计数域表明本系统中共有几个文件目录项的inode和本文件相同,也就是本文件共
   有几个硬连接。如上面的例子中hardlink_mytext和mytext文件的count值都是2。

   那么对于目录,其count域的含义是什么呢?目录的count同样表示共有多少个目录项指向此目录,不过要详细
   说明必须进一步解释VFS文件系统的结构,为简单起见,只要这样理解就行了:(count-2)等于本目录包含的直
   接子目录数(就是只包括儿子,不包括孙子啦!)。例如:如果一个目录/abc的count域为5,那么
   /abc目录一定包含3个子目录。

   至此我们已经介绍了普通文件、目录文件、设备文件、硬连接、连接计数、索引节点等非常重要的概念。

   4、进一步说明:

   硬连接文件实际上并不是一种新的文件类型,两个文件互为对方的硬连接。它们应该都是普通文件(谁能告诉
   我:其它类型的文件可以硬连接吗?)。两个文件除了名称或/和文件目录不同外,其它部分完全相同,更改了一
   个文件,另一个的文件长度、内容、更改时间等都将相应发生变化,更改了一个文件的权限位mode,另一个也会
   发生同样的变化。

   注意连接计数字段count,互为硬连接的两个文件的count值都是2,表明有两个inode指向同一文件的inode。
   当我们删除其中一个文件时,系统首先将(count-1)->count,如果结果是零,就将其目录项和数据区都删除,
   否则只将本目录项删除,数据区仍然保留,仍然可以通过另外的文件名访问。根据这个特性,可以通过为重要的
   文件建立硬连接的方法来防止其被误删除。

   一个文件系统允许的inode节点数是有限的,如果文件数量太多,即使每个文件都是0字节的空文件,系统最终
   也会因为节点空间耗尽而不能再创建文件。所以当发现不能建立文件时首先要考虑硬盘数据区是否还有空间(可
   通过du命令),其次还得检查节点空间。

   互为硬连接的多个文件必须位于同一个文件系统上。根设备及任何一个需要mount才能挂接进来的分区、软盘、
   NFS、光驱等都是一个独立的文件系统,每个文件系统有一个相应的设备号,不同文件系统中具有相同inode节
   点的文件间没有任何联系。系统则通过设备号和inode号的组合唯一确定一个文件。

   Linux之所以能支持多种文件系统,其实是由于Linux提供了一个虚拟文件系统VFS,VFS作为实际文件系统的上
   层软件,掩盖了实际文件系统底层的具体结构差异,为系统访问位于不同文件系统的文件提供了一个统一的接
   口。实际上许多文件系统并不具备inode结构,其目录结构也和以上的讨论不同,但通过VFS,系统均为其提供
   了虚拟一致的inode和目录项结构。所以,'ls -il'命令实际显示的inode应该是VFS inode,也就是说,
   inode是存在于内存中的数据结构,而不一定是实际的硬盘结构。但为Linux量身定做的ext2文件系统具备实际
   的inode和连接型目录项结构,所以,对于ext2文件系统,可以认为我们上面讨论的关于硬连接的概念是完全正
   确的。

   本节最后两段的说明如果您暂时理解不了也没关系,随着学习的深入,慢慢就能理解了。


   五、符号连接
   ============

   不同文件系统中的文件不能建立硬连接,但可以通过符号连接进行同步。符号连接是一种独立的文件类型,它有
   自己的数据区,但数据区的内容只是一个被它指向的文件的路径名。前言那节的例子1.5说明文件sym_link是一
   个指向/tmp/sym_target文件的符号连接,如果我们cat sym_link,系统自动将它指向的文件打开显示而不是
   显示sym_link文件本身,注意sym_link的文件长度是15,正是字符串/tmp/sym_target的长度。建立符号连接
   和建立硬连接一样使用ln命令,不过要加入'-s'选项:

   ln -s /home/zyd/file_system/mytext my_sym_link
   # ls -li my_sym_link
   262458 lrwxrwxrwx 1 zyd zyd 28 Nov 3 14:55 my_sym_link -> /home/zyd/file_system/mytext

   思考题:建立符号连接时一般都要输入目标文件的绝对路径,为什么? 
   (提示:假设我们想让用户在任意当前目录都能执行/usr/local/my_bin/myproc而运行如下命令:
   # cd /usr/local/bin
   # ln -s ../my_bin/myproc myproc)


   六、文件模式位mode
   ==================

   通过chmod命令可以改变用户对相应文件的存取权限。
   Linux系统用一个16位的字来存储每个文件的type和mode,其中高4位通过组合来决定文件的type,它是在文件
   创建时写入的,用户不能更改。下面介绍后面的12位模式位

 bit|11 10 9 |8  7  6 | 5  4  3 | 2  1  0 |
----|--------|--------|---------|---------|
    | X  X X |X  X  X | X  X  X | X  X  X |
----|--------|--------|---------|---------|
mode          r  w  x   r  w  x   r  w  x 



   将这12位分成4组,高位组(9,10,11位)每位都有特殊的含义,下面将具体说明。此高位组(6,7,8位)决定文件
   属主拥有的权限,再下一组决定文件属组成员对此文件拥有的权限,最低位组决定除了属主及属组以外的用户拥
   有的对此文件操作的权限。

   较低3组中每组从最低位到最高位分别是执行位、改写位和读取位,哪位置1表示有相关权限。例如第6位是1表示
   属主可以执行此文件,第4位是1同组其他用户可以改写此文件,第2位是1表示其它用户可以读此文件。每组的3
   位构成一位8进制数,可以将各权限位的组合通过3位8进制表示,例如:
   111 101 100表示成754,则命令:
   chmod 754 filename使文件的属主能读、写和执行filename文件,本组的其他用户可以读和执行此文件,但不
   能修改。其他用户则只能读该文件。

   第11位是SUID位,第10位是SGID位,第9位是粘附位。
   如果某个可执行文件设置了SUID位,则此文件运行时的进程将具备和此文件属主相同的权限。
   /usr/bin/passwd设置了SUID位且其属主是root,则任何用户运行它时,其进程就具备了root权限,这就是为
   什么普通用户也可以通过passwd命令更改自己的登陆口令的原因(实际就是改变/etc/shadow文件,只有root有
   权读写此文件).具备SUID位且属主可执行,则属主执行位显示s来代替没有SUID位的x,如果属主不能执行,则
   显示为大写的S。

   SGID和SUID含义相对应。设置SGID位且属组可执行,则属组执行位改成s显示,否则以S显示。

   粘附位根据其他用户是否可执行分别在ls -l时在其他用户执行位上显示成t或T。对于可执行文件,设置了粘附
   位可以使其第一次运行后在交换分区swap中保留正文的副本,由于交换分区的文件是连续存放的,所以下次运行
   时能较快调入内存。对于现代文件系统来说,这一功能已经没有什么实际意义了。

   如果对一个目录设置了粘附位,则只有对于该目录具有写许可权的用户且满足如下三个条件之一,才能删除或更
   名该目录下的文件:
   1、超级用户root。
   2、此目录的拥有者。
   3、拥有要被删除或更改名字的文件。
   这一特性被Linux使用到了/tmp目录上:任何人都可以使用该目录存储文件,但只有文件所有者和root可以删除
   或更名文件。

   最后要谈的是目录的读、写和执行位的准确含义
   初学者常常对目录的权限位理解得似是而非,原因主要在于对文件系统的确切结构不理解。
   r表示读目录,w表示写目录,而x表示搜索目录(注意不是执行目录)
   我们通过以上讨论已经知道目录实际是一种特殊文件,它由目录项构成,每个目录项包括该目录下一个文件的文
   件名和inode。所以读权限就是读目录项的权限,因此获得此目录所包含的文件名列表。同样写目录权限就是更
   改目录目录文件(增加、减少和更名目录项),实际就是能否在该目录建立、删除文件和为文件改名。搜索权限通
   俗点可以理解为进入目录对文件内容进行操作的权限,包括打开文件、获取文件的进一步详细信息等权力。更通
   俗点,我们可以将目录比喻为盛药的盒子,我们在一个大药盒(根目录)上贴上叫“药品”的标签(目录名),下面
   列着“青霉素”和“感冒药”(目录项),拥有x权限相当于有打开这个盒子的钥匙。如果我们拥有钥匙,就能打
   开这个盒子(拥有根目录的x权限,可以进入),打开后发现里面还有一个加锁的盒子贴有“感冒药”标签(子目
   录),下面列着“感冒通”、“感康”......,另外还有一个药瓶里面装有消炎药青霉素(文件)。
   如果我们需要服用“青霉素”(相当于打开根目录下的文件),则我们必须拥有开大箱子的钥匙(根目录x权限)和
   吃药的权力(相应文件权限),但如果我们需要服用“感康”,则必须还有下一把钥匙。目录读权限相当于我们是
   否识字,写权限相当于我们是否拥有一只笔。只要识字,我们没有任何钥匙也能大致了解大箱子内有什么,但无
   法了解小盒子里有些什么具体药品。如果需要了解就必须首先能打开大箱子。如果我们要向大箱子内放入一种新
   药或拿出一种药品(相当于在根目录内创建、删除文件),我们首先必须能进入大箱子(x),然后有笔(w)能相应
   更改大箱子的标签。
   有了以上的比喻,下面进行正式说明:
   1、当我们打开任何文件时(也就是我们的命令中包含最终文件名时),对该文件名的绝对路径中的每个目录均必
   须拥有x搜索权限。也只有拥有了x权限,才能用cd命令进入该目录。
   2、读权限允许我们通过ls命令获得该目录的文件名列表,但前提仍然是必须对该目录的所有上级目录拥有x权限
   (想想药盒的故事)。
   3、在满足目录权限的前提下,最终对文件的读、写、执行取决于文件权限。
   4、只要你拥有一个目录的写权限及其所有上层目录的搜索权限,你就能在该目录建立文件和删除文件,即使这
   个文件不归你所有!!!
   5、超级用户可以超越大多数文件权限的检查。

   思考题:
   1、为什么目录建立的默认权限是rwxr-xr-x?
   2、假设在你的当前目录下有一个子目录test,你拥有读和写权限,没有搜索权限,如下命令哪些能够成功执
   行?为什么?
   ls test
   ls -l test
   cd test
   cp /etc/passwd ./test/newpasswd
   del test/new_file
   ln test/new_file up_file


   七、更改文件模式mode
   ====================

   更改文件模式可以通过chmod命令进行,我们将mode的低12位每3位一组组成4位8进制数,被设置权限的位为1,
   否则为0,作为chmod的参数之一,后面跟需要更改权限的文件名列表,例如:

   # chmod 4752 this.file
   设置了this.file的SUID位(4),文件属主可以读、写和执行(7)、同组其他用户可以读和执行,不能更改(5)、
   其他用户只能改写、不能读和执行(2)——哪位真的这样设置了权限位,肯定脑筋有点问题:)

   (全文完)

   ======================================== 一点说明 ======================================

   我接触Linux还不满1年,UNIX则从未见过,又刚刚学习编程,文中错误和不当之处难免,欢迎各位指正。

   Julian Chang
   julian_ch@bigfoot.com
   2000年11月20日
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50