免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1854 | 回复: 0
打印 上一主题 下一主题

unix环境高级编程--第4章 文件和目录 (上) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2003-07-08 18:54 |只看该作者 |倒序浏览
4?1〓引言?
在上一章我们说明了执行I/O操作的基本函数。其讨论是围绕普通文件的I/O进行的
-打开-
文件,读或写一个文件。本章将观察文件系统的其它特征和文件的性质。我们从s
tat函数开
始,并逐个说明stat结构的每一个成员以了解文件的所有属性。在此过程中,我们
的说明修
改这些属性的各个函数(更改属主,更改许可数等)。我们也将更详细地察看Unix文
件系统的
结构以及符号连接。本章结束部分介绍对目录进行操作的各个函数,并且开发了一
个以降序
遍历目录层次结构的函数。?
4?2〓stat,fstat以及lstat函数?
本章的讨论的中心是三个stat函数以及它们所返回的信息。?
#include<sys/types?h>;?
#include<sys/stat?h>;?
int stat(const char *?pathname?,struct stat *?buf?);?
int fstat(int ?filedes,?struct stat *?buf?);?


int lstat(const char *?pathname,?struct stat *?buf?);?
三个函数的返回:若成功为0,出错为-1?
给予一个pathname,stat函数返回一个与此命名文件有关的信息结构,fstat函数获
得已在插
述符filedes上打开的文件的有关信息。lstat函数类似于stat,但是当命名的文件
是一个符
号连接时,lstat返回该符号连接的有关信息,而不是由该符号连接引用的文件的
信息。(在
4?2)节中当降序周游目录层次结构时,我们需要lstat。在4?16节中的较详细地
说明符号
连接。)?
lstat函数不属于POSIX 1003?1-1990标准,但很可能加到1003?1a中。SVR4和4?
3+BSD支
持lstat。?
第二个参数是个指针,它指向一个我们应提供的结构。这些函数填写由buf指向的
结构。该
结构的实际定义可能所实施而有所不同,但其基本形式是:?
struct stat{?
mode 迹茫模*常病絫 st 迹茫模*常病絤ode; /*文件类型和方式(许可数)*/?
ino 迹茫模*常病絫 st 迹茫模*常病絠no;/* i-节点号(序列号)*/?
dev 迹茫模*常病絫 st 迹茫模*常病絛ev;/*设备号(文件系统)*/?
dev 迹茫模*常病絫 st 迹茫模*常病絩dev;/*特殊文件的设备号*/?


nlink 迹茫模*常病絫 st 迹茫模*常病絥link;/*连接数*/?
uid 迹茫模*常病絫 st 迹茫模*常病絬id;/*属主的用户ID*/?
gid 迹茫模*常病絫 st 迹茫模*常病絞id;/*属主的组ID*/?
off 迹茫模*常病絫 st 迹茫模*常病絪ize;/*普通文件的字节长度*/?
time 迹茫模*常病絫 st 迹茫模*常病絘time;/*最后存取时间*/?
time 迹茫模*常病絫 st 迹茫模*常病絤time;/*最后修改存取时间*/?
time 迹茫模*常病絫 st 迹茫模*常病絚time;/*最后文件状态更改时间*/?
long st 迹茫模*常病絙lksize;/*最佳I/O块长*/?
long st 迹茫模*常病絙locks;/*分配的512字节块块数?
};?
POSIX?1未定义st 迹茫模*常病絩dev?st 迹茫模*常病絙lksige和st 迹茫模?
?2〗blo
cks字段。SVR4和4?3+BSD则定义了这些字段。?
注意,除最后两个以外,其它各成员都说明为基本系统数据类型(见2?7节)。我们
将说明此
结构的每个成员以了解文件属性。?
stat函数的最大用户很可能是ls-l命令,用其可以获得有关一个文件的所有信息。
?
4?3〓文件类型?
至今我们已介绍了两种不同的文件类型-普通文件和目录。Unix系统的大多数文件
是普通文
件或目录,但是也有另外一些文件类型:?


1?普通文件(Regular file)。这是最常见的文件类型,这种文件包含了某种形式
的数据。
至于这种数据是文本还是二进制数据对于系统核而言并无区别。对普通文件内容的
解释由处
理该文件的应用程序进行。?
2?目录文件(Directory file)。这种文件包含了其它文件的名字以及指向与这些
文件有关
信息的指针。对一个目录文件具有读许可数的任一进程都可以读该目录的内容,但
只有系统
核可以写目录文件。?
3?字符特殊文件(Charocter special file)。这种文件用于系统中的某些类型的
设备。?
4?块特殊文件(Block special file)。这种文件典型地用于磁盘设备。系统中的
所有设备
或者是字符特殊文件,或者是块特殊文件。?
5? FIFO。这种文件用于进程间的通信,有时也将其称为命名管道。在14?5对其
进行说明
。?
6?套接口(socket)。这种文件用于进程间的网络通信。套接口也可用于在一台宿
主机上的
进程之间的非网络通信。在第十五章,我们将用套接口进行进程间的通信。?
只有4?3+BSD才返回套接口文件类型,虽然SVR4支持用套接口进行进程间通信,但


现在是经
由套接口函数库实现的,而不是通过系统核内的套接口文件类型,将来的SVR4版本
可能会支
持套接口文件类型。?
7?符号连接(Symbolic link)。这种文件指向另一个文件。我们在4?16中将更多
地述及符
号连接。?
文件类型信息,包含在stat结构的st 迹茫模*常病絤ode成员中。我们可以用图4
?1中的宏
确室文件类型。这些宏的参数都是stat结构中的st 迹茫模*常病絤ode成员。??
?
图4?1〓在<sys/stat?h>;中的文件类型宏?
实例?
程序4?1取其命令行参数,然后针对每一个命令行参数打印其文件类型。???
程序4?1〓对每个命令行参数打印文件类型?
程序4?1的样本输出是:?
$ a?out/vmunix/etc/dev/ttya/dev/sd0a/var/spool/cron/FIFO\?
>;/bin/dev/printer?
/vmunix:普通?
/etc:目录?
/dev/ttya:字符特殊?
/dev/sd0a:块?


/var/spool/cron/FIFO:fifo?
/bin:symbolic符号连接?
/dev/printer:套接口?
(其中,在第一命令行末端我们键入了一个反斜线,通知shell我们要在下一行继续
键入命令
,然后shell在下一行上用其第二提示符,>;,提示我们特地使用了lstat函数而不是
stat函数
以便检测符号连接。如若使用了stat函数,则决不会观察到符号连接。?
较早的Unix版本并不提供S 迹茫模*常病絀SXXX宏,于是就需要将st 迹茫模*常?
〗mode与
屏蔽字S 迹茫模*常病絀FMT逻辑与,然后与
名为s 迹茫模*常病絀FXXX的常数相比较。SVR4和4?3+BSD在文件<sys/stat?h>;
中定义了
此屏蔽字和相关的常数。如若我们查看此文件,则可找到S 迹茫模*常病絀SDIR宏
定义为:
?
我们说过,普通文件是最主要的文件类型,但是观察一下在一个给定的系统中各种
文件的比
例是很有兴趣的。图4?2中显示了在一个中等规模的系统中的统计值。这一数据是
由4?21
节中的程序得到的。???
图4?2〓不同类型文件的计数值和比例?


4?4〓设置一用户 迹茫模*常病絀D和设置一组 迹茫模*常病絀D?
与一个进程相关联的ID有六个或更多。它们示于图4?3中。???
图4?3〓与每个进程相关联的用户ID和组ID?
·实际用户ID和实际组ID标识我们究竟是谁。这两个字段在登录时取自我们在口令
文件中的
记录项。通常,在一个登录会话期这些值并不改变,但是超级用户进程有方法,改
变它们,
在8?10节中将说明这些方法。?
·有效用户ID,有效组ID以及添加组ID决定了我们的文件存取数,下一节将对此进
行说明。
(我们已在1?8节中说明了添加组ID)。?
·保存的设置一用户 迹茫模*常病絀D和保存的设置一组 迹茫模*常病絀D在执行
一个程序
时包含了有效用户I
D和有效组ID的副本,在8?10节中说明setuid函数时,我们将说明这两个保存值的
作用。?
在POSIX?1中,这些保存ID是可选择的。一个应用程序在编译时可测试常数  CD
*常病?
POSIX 迹茫模*常病絊AVED 迹茫模*常病絀
DS,或在运行时以参数 迹茫模*常病絊C 迹茫模*常病絊AVED 迹茫模*常病絀D
S调用函数
sysconf,以判断此实现是否支持这种特征。SVR4支持此特征。?


FIPS 。 5|-1要求POSIX?1的这种可选择特征。?
通常,有效用户ID等于实际用户ID,以及有效组ID等于实际用户ID。?
每个文件有一个属主和组属主,属主是由stat结构中的st 迹茫模*常病絬id表示
的,组属
主则由st 迹茫模*常病絞id成员表示。?
当我们执行一个程序文件时,进程的有效用户ID通常就是实际用户ID,有效组ID通
常是实际
组ID。但是可以在文件方式字(st 迹茫模*常病絤ode)中设置一个特殊标志,其定
义是"当
执行此文件时
,将进程的有效用户ID设置为文件的属主(st 迹茫模*常病絬id)"。与此相类似,
在文件
方式字中可以设
置另一位,它使得执行此文件的进程的有效组ID设置为文件的组属主(st 迹茫模?
?2〗gid
)。在文件方式字中的这两位被称之为设置一用户 迹茫模*常病絀D位和设置一组
迹茫模?
?2〗ID位。?
例如,若文件属主是超级用户,而且设置了该文件的设置一用户 迹茫模*常病絀
D位,然后
当该程序由一
个进程运行时,则该进程具有超级用户优先数。不管执行此文件的进程的实际用户


ID是什么
,都作这种处理。作为一个例子,Unix程序passwd(1)允许任一用户改变其口令字
,该程序
是一个设置一用户 迹茫模*常病絀D程序。因为该程序应能将用户的新口令字写入
口令字文
件中(典型地
这是/etc/passwd或/etc/shadow),而只有超级用户才具有该文件的写许可数,所以
需要使用
设置一用户 迹茫模*常病絀D特征。因为运行设置一用户 迹茫模*常病絀D程序的
进程通常
得到额外的许
可数,所以要特别谨慎地编写这种程序。我们将在第八章更详细地讨论这种类型的
程序。?
再返回到stat函数,设置一用户 迹茫模*常病絀D位及设置一组 迹茫模*常病絀
D位都包含
在st 迹茫模*常病絤ode值中。这两位可用常数S 迹茫模*常病絀SUID和S  CD
*常病絀
SGID测试。?
4?5〓文件存取许可数?
st 迹茫模*常病絤ode值也包含了对文件的存取数位。当我们说及文件时,我们指
的是前面
所提到的任何


类型的文件。所有文件类型(目录,字符特别文件等)都有许可数。很多人认为只有
普通文件
有存取许可数,这是一种误解。?
每个文件有9个存取数位,可将它们分成三类。这些都示于图4?4中。???
图4?4〓9个存取数位(在<sys/stat?h>;中定义)?
在图4?4开头三行中,术语用户指的是文件属主。chmod(1)命令用于修改这9个许
可数位。
该命令允许我们用u表示用户(属主),用g表示组,用o表示其他。有些书把这三种
用户夫妇
别称之为属主,组和世界。这会造成混乱,因为chmod命令用o表示其他,而不是属
主(owner
)。我们将使用术语用户,组和其他,以便与chmod命令一致。?
图中的三类存取数-读、写及执行-以各种方式由不同的函数使用。我们将这些不同
的使用
方法摘要列在下面,当说明这些函数时,再进一步作讨论。?
第一个规则是,我们用名字要打开任一类型的文件时,对该名字中包含的每一个目
录,包括
它可能隐含的当前工作目录都应具有执行许可数。这就是为什么对于目录其执行许
可数位常
被称为搜索位的原因。?
例如,为了打开文件/usr/dict/words,我们需要具有对目录/,/usr,/usr/dict的
执行许可


数。然后,我们需要对该文件本身的适当许可数,这取决于我们要以何种方式打开
它(只读,读-写等)。
如果当前目录是/usr/dic,那么为了打开文件words,我们需要有对该目录的执行许
可数。这
就是隐含了当前目录的例子,我们在指定打开文件words时,没有显式地提及/usr
/dic?wor
ds与/words两种表示方法是一致的。?
注意,对于目录的读许可数和执行许可数的意义是不相同的。读许可数允许我们读
目录,获
得在该目录中所有文件名的列表。当一个目录是我们要存取文件的路径名的一个分
量时,对
该目录的执行许可数使我们可通过该目录。(也就是搜索该目录,寻找一个特定的
文件名。
)?
引用隐含目录的另一个例子是,如果PATH环境变量(在8?4节中说明)指定了一个我
们不具有
存取数的目录,那么shell决不会在该目录下打到可执行文件。?
·对于一个文件的读许可数决定了我们是否能够打开该文件进行读操作。这对应于
open函数
的O 迹茫模*常病絉DONLY和O 迹茫模*常病絉DWR标志。?
·对于一个文件的写许可数决定了我们是否可能够打开该文件进行写操作这对应于
open函数


的O 迹茫模*常病絎RONLY和O 迹茫模*常病絉DWR标志。?
·对于一个文件的写许可数决定了我们是否能够打开该文件进行写操作。这对应于
open函数
的O 迹茫模*常病絎RONLY和O 迹茫模*常病絉DWR标志。?
·为了在open函数中对一个文件指定O 迹茫模*常病絋RUNC标志,我们必须对该文
件具有写
操作许可数。?
·为了在一个目录中创建一个新文件,我们对该目录需要具有写许可数和执行许可
数。?
·为了删除一个文件,我们需要对包含该文件的目录具有写许可数和执行许可数。
对该文件
本身则不需要有读、写许可数。?
·如果我们用6个exec函数(8?9节)中的任何一个执行某个文件,则我们需要对该
文件具有
执行许可数。?
进程每次打开、创建或删除一个文件时,系统核就进行文件存取数测试,而这种测
试可能涉
及文件的属主(st 迹茫模*常病絬id和st 迹茫模*常病絞id)。进程的有效ID(有
效用户ID
和有效组ID)、以及进程的添加
组ID(若支持的话)。两个属主ID是文件的性质,而有效ID和添加组ID则是进程的性
质。系统


核进行的测试是:?
1?若进程的有效用户ID是O(超级用户),则允许存取。这给于了超级用户对文件系
统进行处
理的最充分的自由。?
2?若进程的有效用户ID等于文件的属主ID(也就是该进程拥有此文件):?
a?若适当的属主用户存取数位是设置的,则允许存许,?
b?否则拒绝存取。?
关于确当的存取数位,我们指的是,如若进程为读而打开该文件,是属主用户-读
位应为1
。若进程为写而打开该文件,则属主用户-写位必须为1。若进程将执行该文件,则
属主用
户-执行位必须为1。?
3?若进程的有效组ID或进程的添加组ID之一等于文件的组ID:?
a?若适当的组存取数位是设置的,则允许存取,?
b?否则拒绝存取。?
4?若适当的其他用户存取数位是设置的,则允许存取,否则拒绝存取。?
按序试执行这四步。注意,如若进程拥有此文件(第2步),则按用户存取数批准或
拒绝该进
程对文件的存取-不查看组存取数。相类似,若进程并不拥有该文件。但进程属于
某个适当
的组,则按组存取数批准拒绝该进程对文件的存取-不查看其它用户存取数。?
4?6〓新文件和目录的属主关系?


在第三章中,当说明用open或creat创建新文件时,我们没有说明赋与新文件的用
户ID和组I
D的值是什么。在4?20中,我们将说明如何创建一个新目录以及mkdir函数。关于
新目录的
属主关系的规则与本节将说明的新文件的属主关系的规则相同。?
新文件的用户ID设置为进程的有效用户ID。关于组ID,POSIX?1允许选择下列之一
作为新文
件的组ID。?
1?新文件的组ID可以是进程的有效组ID。?
2?新文件的组ID可以是它所在目录的组ID。?
在SVR4中,新文件的组ID决取于它所在的目录的设置一组 迹茫模*常病絀D位是否
设置。如
果该目录的这
一位已经设置,则新文件的组ID设置为目录的组ID;否则新文件 组ID设置为进程
的有效组I
D。?
4?3+BSD总是使用目录的组ID作为新文件的组ID。?
其它系统允许以一个文件系统作为单位在POSIX?1所允许的两种方法中选择一种,
为此在mo
unt(1)命令中使用了一个特殊标志。?
FIPS |5|-1要求一个新文件的组ID是它所在目录的组ID。?
使用POSIX?1所允许的第二种方法(继承目录的组ID)使得在某个目录下创建的文件


和目录都
有该目录的组ID。于是文件和目录的组属主关系从该点就向下传递。例如,在/va
r/spcol目
录中就使用这种方法。?
正如前面提到的,这种设置组属主关系的方法对4?3+BSD是系统默认的,对SVR4则
是可选择
的。在SVR4之下,我们必须设置设置一组 迹茫模*常病絀D位。更进一步,为供这
种方法能
够正常工作,
SVR4的mkdir函数要自动地传递一个目录的设置一组 迹茫模*常病絀D位。(在4?
20节中我
们将说明,mkdir就是这样做的)。?
4?7〓access函数?
正如前面所说明的,当用open函数打开一个文件时,系统核以进程的有效用户ID和
有效组ID
为基础执行其存取数限测试。有时,进程也希望按其实际用户ID和实际组ID来测试
其存取能
力。例如当一个进程使用设置一用户 迹茫模*常病絀D,或设置一组 迹茫模*常?
〗ID特征
作为另一个用户(或组)运行
时,这可能就是需要的。即使一个进程可能已经设置一用户 迹茫模*常病絀D为根
,它仍可


能想验证实际
用户能否存取一个给定的文件。access函数是按实际用户ID和实际组ID进行存取数
测试的。
(经过4?5节结束部分中所述的4个步骤,但将有效改为实际。)?
#include<unistd?h>;?
int access(const char *?pathname,?int ?mode?);?
返回:若成功为0,出错为-1?
其中,mode是图4?5中所列常数的按位或。???
图4?5?
实例?
程序4?2显示了access函数的使用。下面是该程序的一些运动结果:?
$ ls -1 a?out?
-rwxrwxr-x 1 stevens 105216 Jan 18 08:48 a?out?
$ a?out a?out?
read access OK?
open for reading OK?
$ ls -1/etc/uucp/Systems?
-rw-r----- 1 uucp 1441 Jul 18 15:05/etc/uucp/Systems?
$ a?out/etc/uucp/Systems?
access error for/etc/uucp/Systemsermission denied?
open error for /etc/uucp/Systemsermission denied?
$ su〓成为超级用户?


Password:输入超级用户口令?
# chown uucp a?out?
# chkmod u+s a?out将文件用户ID改为uucp,打开设置用户ID位???
程序4?2〓access函数的实例。?
在本例中,设置一用户 迹茫模*常病絀D程序可以确定实际用户不能读某个文件,
而open函
数却能打开该文件。?
在上面例子以及在第八章中,我们有时要成为超级用户,以便例示某些功能是如何
工作的。
如果你使用多用户系统,但无超级用户许可数,那么你就不能完整地重复这些实例
。?
4?8〓umask函数?
至此我们已说明了与每个文件相关联的9个存取数位,在此基础上我们可以说明与
每个进程
相关联的文件方式创建屏蔽字。?
umask函数为进程设置文件方式创建屏蔽字,并返回以前的值。9这是少数几个没有
出错返回
的函数中的一个。)?
#include<sys/types?h>;?
#include<sys/stat?h>;?
mode 迹茫模*常病絫 umask(mode 迹茫模*常病絫 ?cmask)?;?
返回:以前的文件方式创建 帘为?


其中,参数cmask是由图4?4中的9个常数(S 迹茫模*常病絀RUSR,S 迹茫模*常?
〗IWUSR等
)按位或构成的。?
在进程创建一个新文件或一个新目录时,就一定会使用文件方式创建屏蔽字。(回
忆3?3和3
?4节,在那里我们说明了open和creat函数。这两个函数都有一个参数mode,它指
定了新文
件的存取许可数位。)我们将在4?20节说明如何创建一个新目录,在文件方式创建
屏蔽字中
为1的位,在文件mode中的相应位则一定被转成0。?
实例?
程序4?3创建了两个文件,创建第一个时,umask值为0,创建第二个时,umask值
禁止所有
组和其它存取数。若运行此程序可得如下结果,从中可见存取数是如何设置的。?

$ umask〓第一次打印当前文件方式创建 帘为?
02?
$ a?out-
4 ls -1 foo bar?
-rw------- 1 stevens 0 Nov 16 16:23 bar?
-rw -rw-rw- 1 stevens 0 Nov 16 16:23 foo?
$ umask〓观察文件方式创建屏蔽是否更改?


02???
程序4?3〓umask函数的实例?
4?9〓chmod和fchmod函数?
这两个函数使我们可以更改现存文件的存取许可数。?
#include<sys/types?h>;?
#include<sys/stat?h>;?
int chmod(const char *?pathname,?mode 迹茫模*常病絫 ?mode);??
int fchmod(int ?filedes,?mode 迹茫模*常病絫 ?mode);??
二个函数返回:若成功为0,出错为-1?
chmod函数在指定的文件上进行操作,而fchmod函数则对已打开的文件进行操作。
?
fchmod函数并不是POSIX?1的组成部分。这是SVR4和4?3+BSD的扩充部分。?
为了改变一个文件的许可数位,进程的有效用户ID必须等于文件的属主,或者该进
程必须具
有超级用户许可数。?
参数mode是图4?6中所示常数的某种按位或。???
图4?6〓chmod函数的mode常数(取自<sys/stat?h>?
注意,在图4?6中,有9项是取自图4?4中的9个文件存取许可数位。我们另外加上
了二位设
置 迹茫模*常病絀D常数(S 迹茫模*常病絀S〔UG〕ID),保存 迹茫模*常病 正文
常数(S〖
茫模*常病絀SVTX),以及三个组合常数(S 迹茫模*常病絀RWX〔UGO〕)


。(在这里,我们使用了标准Unix字符类算符 病? ,表示方括号算符中的任何一
个字符。
例如,最后一个,S 迹茫模*常病絀RWX〔UGO〕表示了三个常数:S 迹茫模*常?
〗IRWXU、
S 迹茫模*常病絀RWXG和S 迹茫模*常病絀RWXO。这一字符
类算符是大多数Unix shell和很多标准Unix应用程序都提供的正规表达式的一种形
式。)?
保存 迹茫模*常病 正文位(S 迹茫模*常病絀SVTX)不是POSIX?1的一部分。我们
在下一节
说明其目的。?
实例?
先回忆一下为例示umask函数我们运行程序4?3时,文件foo和bar的最后状态:?

$ ls-1 foo bar?
-rw------- 1 stevens 0 Nov 16 16:23 bar?
-rw-rw-rw- 1 stenens 0 Nov 16 16:23 foo?
程序4?4修改了这两个文件的方式。在运行程序4?4后,我们见到的这两个文件的
最后状态
是:?
$ ls -1 foo bar?
-rw-r--r-- 1 stevens 0 Nov 16 16:23 bar?
-rw-rwlrw- 1 stenens 0 Nov 16 16:23 foo?


在此例子中,我们相对于foo的当前状态设置其许可数。为此,先调用stat获得其
当前许可
数,然后修改它。我们已显式地打开了设置一组 迹茫模*常病絀D位、关闭了组〖
茫模*?
2〗执行位。对普通文件这样
做的结果是对该文件可以加强制性记录锁,我们将在12?3节中讨论强制性锁。注
意,ls命
令将组 迹茫模*常病 执行许可数表示为l,它表示对该文件可以加强制性记录锁
。对文件b
ar,不管其当前许可数位如何,我们将其许可数设置为一绝对值。???
程序4?4〓chmod函数的实例?
最后也要注意到。在我们运行程序4?4后ls命令列出的时间和日期并不改变。在4
?18节中
,我们会了解到chmod函数更新的只是i-node最近一次被更改的时间。按系统默认
方式ls-l
列出的是最后修改文件内容的时间。?
chmod函数在下列条件下自动清除2个许可数位。?
·如果我们试图设置普通文件的粘住位(S 迹茫模*常病絀SVTX),而且又没有超级
用户优先
数,那么mode
中的粘住位自动被关闭。(我们将在下一节说明粘住位)。这意味着只有超级用户才
能设置普


通文件的粘住位。这样做的理由是可以防止不怀好意的用户设置粘诠位,并试图以
此方式填
满交换区(如果系统支持保存 迹茫模*常病 正文特征的话)。?
·新创建文件的组ID可能不是调用进程所属的组。回忆一下4?6节,新文件的组I
D可能是父
目录的组ID。特别地,如果新文件的组ID不等于进程的有效组ID或者进程添加组I
D中的一个
,以及进程没有超级用户优先数,那么设置一组 迹茫模*常病絀D位自动被关闭。
这就防止
了用户创建一个设置一组 迹茫模*常病絀D文件,而该文件是由并非该用户所属的
组拥有的
。?
4?3+BSD和其它贝克莱导出的系统增加了另外的安全性特征以试图防止保获位的错
误使用。
如果一个没有超级用户优先数的进程写一个文件,则设置一用户 迹茫模*常病絀
D位和设置
一组 迹茫模*常病絀D位自动
被清除。如果一个不怀好意的用户找到一个他可以写的设置一组 迹茫模*常病絀
D和设置一
用户 迹茫模*常病絀D文件,即使他可以修改此文件,但失去了对该文件的特别优
先数。?
4?10〓粘住位?


S 迹茫模*常病絀SVTX位有一段有趣的历史。在Unix的早期版本,这一位被称之为
粘住位。
如果一个可执
行程序文件的这一位被设置了,那么在该程序第一次执行并结束时,该程序正文的
一个文本
被保存在交换区。(程序的正文部分是机器指令部分。)这使得下次执行该程序时能
较快地将
其装入内存区。其原因是:在交换区,该文件是被连续存放的,而在一般的Unix文
件系统中
,文件的各数据块很可能是随机存放的。对于常用的应用程序,例如文本编辑程序
和编辑程
序的各部分常设置它们所在文件的粘住位。自然,对交换区中可以同时存放的设置
了粘住位
的文件数有一定限制,以免过多占用交换区空间,但无论如何这是一个有用的技术
。因为在
系统再次自草前,文件的正文部分总是在交换区中,所以使用了名字"粘住"。后来
的Unix
版本称之为保存 迹茫模*常病 正文位,因此也就有了常数S 迹茫模*常病絀SVT
X。现今较
新的Unix系统大多数都具有虚存系统,以及快速文件系统,所以可再需要使用这种
技术。?
目前粘住位的主要作用是针对目录文件的。如果对一个目录设置了粘住位,则只有


对该目录
文件具有写许可数的用户并且满足下列条件之一,才能删除或换名该目录下的文件
:?
·拥有此文件?
·拥有此目录,或者?
·是超级用户?
目录/tmp和/var/spool/uucppublic是设置粘住位的后选者-这两个目录是任何用户
都可在
其中创建文件的目录。这两个目录对任一用户(用户、组和其他)的许可数通常都是
读、写和
执行。但是用户不应能删除或换名属于其他人的文件,为此在这两个目录的文件方
式中都设
置了粘住位。?
POSIX?1没有定义粘住位。但SVR4和4?3+BSD则支持这种特征。?
4?11〓chown,fchown和lchown函数?
chown函数可用于更改文件的用户ID和组ID。?
#include<sys/types?h>;?
#include<unistd?h>;?
int chown(const char *?pathname,?uid 迹茫模*常病絫 ?owner?,gid〖C
模*常?
〗t? group);??
int fchown(int ?filedes,?uid 迹茫模*常病絫 ?owner,?gid 迹茫模*常?


〗t ?gro
up);??
int lchown(const char *?pathname,?uid 迹茫模*常病絫 ?owner,?gid〖C
模*常?
〗t ?group);??
三个函数的返回:若成功为0,出错为-1?
除了所引用的文件是个符号连接以外,这三个函数的操作相类似。在符号连接情况
下,lcho
wn更改符号连接本身的属主,而不是该符号连接所指向文件的属主。?
fchown函数并不在POSIX 1003?1-1990标准中,但很可能被加到1003?1a,SVR4和
4?3+BS
D则支持fchown。?
只有SVR4支持lchown函数。在非SVR4系统中(POSIX?1和4?3+BSD),若chown的参
数pathnam
e是符号连接,则改变该符号连接的属主关系,而不改变它所指向的文件的属主关
系。为了
更改该符号连接所指向的文件的属主关系,我们应指定该实际文件本身的pathnam
e,而不是
指向该文件的连接文件的pathname。?
SVR4,4?3+BSD和XPG3允许我们将参数owner或group指定为-1,以表示不改变相应
的ID。这
不是POSIX?1的一部分。?


基于贝克莱的系统一直规定只有超级用户才能更改一个文件的属主。这样做的原因
是防止用
户改变其文件的属主从而摆脱盘空间限额对他们的限制。但是,系统V则允许任一
用户更改
他们所拥有的文件的属主。?
按照 迹茫模*常病絇OSIX 迹茫模*常病紺HOWN 迹茫模*常病絉ESTRICTED的值,
POSIX?1
在这两种形式的操作中选用一种。FIPS | 担?迹茫模*常病?1要求 迹茫模*常?
〗POSIX
迹茫模*常病紺HOWN 迹茫模*常病絉ESTRICTED。?
对于SVR4,此功能是个配置可选择项,而4?3+BSD则总对chown施加了限制。?
回忆图2?5,该常数可选地定义在头文件<unistd?h>;中,而且总是可以用pathco
nf或fpath
conf函数查询。此可选项还与所引用的文件有关-可在每个文件系统基础上,使该
任选项起
作用或不起作用。在下文中,我们如提及"若 迹茫模*常病絇OSIX 迹茫模*常病?
CHOWN〖
茫模*常病絉ESTRICTED起作用",则表示
这适用于我们正在谈及的文件,而不管该实际常数是否在头文件中定义。(例如,
4?3+BSD
总有这种限制,而并不在头文件中定义此常数。)?
若 迹茫模*常病絇OSIX 迹茫模*常病紺HOWN 迹茫模*常病絉ESTRICTED对指定的


文件起作
用,则?
1?只有超级用户进程能更改该文件的用户ID。?
2?若满足下列条件,一个非超级用户进程可以更改该文件的组ID:?
a?进程拥有此文件(其有效用户ID等于该文件的用户ID),以及?
b?参数owner等于文件的用户 迹茫模*常病絀D,参数group等于进程的有效组ID
或进程的
添加组ID之一。?
这意味着,当 迹茫模*常病絇OSIX 迹茫模*常病紺HOWN 迹茫模*常病絉ESTRIC
TED有效时
,你不能更改其
他用户的文件的用户ID。你可以更入你所拥用的文件的组ID,但只能改到你所属于
的组。?
如果这些函数由非超级用户进程调用,则在成功返回时,该文件的设置一用户〖C
模*常?
〗ID位和设置一组 迹茫模*常病絀D位都被清除。?
4?12〓文件长度?
stat结构的成员st 迹茫模*常病絪ige包含了以字节为单位的该文件的长度。此字
段只对普
通文件、目录文件和符号连接才是有意义的。?
SVR4对管道也定义了文件长度,它表示可从该管道中读到的字节数,我们将在14?
2中讨论


管道。?
对于普通文件,其文件长度可以是0,在读这种文件时,将得到文件结束指示。?

对于目录,文件长度通常是一个数,例如16或512的整倍数,我们将在4?21节中说
明读目录
操作。?
对于符号连接,文件长度是在文件名中的实际字节数。例如,?
lrwxrwxrwx 1 root 7 Sep 25 07:14 lib->;usr/lib?
其中,文件长度7就是路径名usr/lib的长度。(注意,因为符号连接文件长度总是
由st〖C
模*常病絪ige指示,所以符号连接并不包含通常C语言用作名字结尾的null字符
。)?
SVR4和4?3+BSD也提供字段st 迹茫模*常病絙lksige和st 迹茫模*常病絙locks
。第一个
是对文件I/O较好的块长度,第
二个是所分配的实际512字节块块数。回忆一下3?9节,其中提到了当我们将st〖
茫模*?
2〗blksige用
于读操作时,读一个文件所需的最少时间量。为了效率的缘故,标准I/O库(我们将
在第五章
中说明)也试图一次读、写st 迹茫模*常病絙lksige字节。?
要知道,不同的Unix版本其st-blocks所用的单位可能不是512-字节块。使用此值


并不是可
移植的。?
文件中的空洞?
在3?6节中,我们提及普通文件可以包含"空洞"。在程序3?2中例示了这一点。空
洞是由
超过文件结尾端的位移量设置,并写了某些数据后造成的。作为一个例子,考虑下
列情况:
?
$ ls -1 core?
-rw-r--r-- 1 stevens 8483248 Nov 18 12:18 core?
$ du -s core?
272 core?
文件core的长度超过8兆字节,而du命令则报告该文件所使用的盘空间总量是272个
512字节
块(139,264字节)。(在很多贝克莱类的系统上,du命令报告1024字节块块数;SV
R4则报告5
12-字节块块数。)很明显,此文件有很多空洞。?
正如我们在3?6节中提及的,read函数对于没有写过的字节位置读到的数据字节是
0。如果
我们执行:?
$ wc -c core?
8483248 core?


中的字符(
字节)数。)?
如果我们使用公用程序,例如cat,复制这种文件,那么所有这些空洞都被写成实际
数据字节
0。?
$ cat core>;core?copy?
$ ls -1 core*?
-rw-r--r-- 1 stevens 8483248 Nov 18 12:18 core?
-rw-rw-r-- 1 stevens 8483248 Nov 18 12:27 core?copy?
$ du -s core*?
272 core?
16592 core?copy?
从中可见,新文件所用的字节数是8,495,104(512×16,592)。此长度与
ls命令报
告的长度之间的差别是由于文件系统使用了若干块以保持指向实际数据块的各指针
。?
有兴趣的读者应当参阅Bach〔19 福丁 的4?2节和Leffler〔1989〕的7?2节,
以更详细
地了解文件的物理安排。?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP