<<UNIX环境高级编程>>之第四章理解

来源:互联网 发布:xp添加网络打印机 url 编辑:程序博客网 时间:2024/06/05 19:22

一.引言:本章观察文件系统的特征和性质.
二.stat,fstat,latat函数:给定一个pathname,stat函数返回一个与此明明文件有关的信息结构,fstat函数获得已在描述符filedes上打开的文件的有关信息.lstat函数类似stat,但是当命名文件是一个”符号连接”时,lstat返回该”符号连接”的有关信息,而不是由该符号连接引用的文件的信息.
(符号连接解释在下方)

#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);

此博客讲的很详细:http://blog.csdn.net/blitzskies/article/details/42400321

    mode_t st_mode; /* file type & mode (permissions) */    ino_t st_ino; /* i-node number (serial number) */    dev_t st_dev; /* device number (file system) */    dev_t st_rdev; /* device number for special files */    nlink_t st_nlink; /* number of links */    uid_t st_uid; /* user ID of owner */    gid_t st_gid; /* group ID of owner */    off_t st_size; /* size in bytes, for regular files */    struct timespec st_atim; /* time of last access */    struct timespec st_mtim; /* time of last modification */    struct timespec st_ctim; /* time of last file status change */    blksize_t st_blksize; /* best I/O block size */    blkcnt_t st_blocks; /* number of disk blocks allocated */};

这个structure是重点,包含了一个文件所需要的信息.
三.文件类型:
1.普通文件(regular file):包含某种形式数据,对于普通文件的内容的解释由处理该文件的应用程序进行.
2.目录文件(directory file):包含其他文件的名字以及指向与这些文件有关信息的指针.只有内核才可以写目录文件.
3.字符特殊文件(character special file):这种文件用于系统的某些类型的设备.
4.块特殊文件(block special file):典型用于磁盘设备,系统中所有设备必是字符特殊文件或块特殊文件中一种.
5.FIFO:用于进程间的通信,有时将其称为命名管道.
6.套接口(socket):用于进程间的网络通信,套接口也可用于在一台宿主机上的进程之间的非网络通信.
7.符号连接(symbolic link):这种文件指向另一个文件.
tips:文件类型信息包含在stat结构的st_mode成员中.

四.设置用户ID和设置组ID:
1.实际用户ID和实际组ID:标识我们究竟是谁,这两个字段在登录时取自口令文件中的登录项,通常在一个登录回话期间这些值不会改变,但是超级用户进程有办法改变它们.
2.有效用户ID,有效组ID以及添加组ID决定我们的文件访问权.
3.保存的set-user-ID和set-group-ID在执行一个程序时包含了有效用户ID和有效组ID的副本.
4.每个文件有一个所有者和组所有者,所有者由stat结构中的st_uid表示,组所有者则有st_gid表示.
5.一般情况下,有效用户ID等于实际用户ID,有效组ID等于实际组ID,但是我们可以在文件方式字(st_mode)中设置一个特殊标志,其定义是”当执行此文件时,将进程的有效用户ID设置问文件的所有者(st_uid)”.同理,我们可以在另一位设置使得执行此文件的进程的有效组ID设置为文件的组所有者ID(st_gid).这两位分别被称为(set-user-ID)位和(set-group-ID);
tips:这就是为什么我们的real ID不是root调用passwd文件确可以修改密码做出root权限才能干的事(可以输入passwd命令尝试一下).
五.文件存取许可权:st_mode值包含了对文件的存取许可权位.所有文件类型(目录,字符特别文件等)都有存取许可权.
tips:everything is a file.
每个文件有9个存取位,分为3类,u表示用户,g表示组,o表示其他,每类分为读,写,执行.
规则:
1.使用路径打开任一类型的文件时,对该路径中包含的每一个目录,包括它肯能隐含的当前工作目录都应具有执行许可权.例:打开/usr/dict/words,需要对目录/,/usr,/usr/dict的执行许可权,然后需要对文件本身有适当的许可权,这取决于以何种方式打开它(只读,读-写等).
2.对于一个文件的读许可权决定我们是否能够打开该文件进行读操作.
3.写许可权同理.
4.在一个目录中创建一个新文件:必须对该目录具有写许可权和执行许可权
注意:
5.删除一个文件:必须对包含该文件的目录具有写许可权和执行许可权.对该文件本身则不需要有读,写许可权
进程每次打开,创建删除一个文件时,内核就进行文件存取许可权测试:
1.若进程的有效用户ID是0,则允许读写.
2.若进程的有效用户ID等于文件的所有者ID(也就是该进程拥有此文件):
a)若适当的所有者存取许可权位被设置,则允许存取
b)否则拒绝
tips:适当的存取许可权指的是,若进程为读而打开该文件,则用户读位应为1;若进程为写而打开文件,则用户写位应为1,若进程将执行该文件,则用户执行位应为1.
3.若进程的有效组ID或进程的添加组ID之一等于文件的组ID:
a:若适当的组存取许可位被设置,则允许存取.
b:否则拒绝
4:若适当的其他用户存取许可权位被设置,则允许,否则拒绝.
六.新文件和目录的所有权:
1.新文件的用户ID设置为进程的有效用户ID.
2.新文件的组ID可以是进程的有效组ID.
3.新文件的组ID可以是它所在目录的组ID.
七.access函数:以上所说当用OPEN函数打开文件,内核以进程的有效用户ID和组ID为基础执行存取许可权测试.但是,如果希望按其实际用户ID和组ID来测试其存取能力就可以调用access函数.
例:如上,如果调用set-user-ID或者set-group-ID把进程权限设置为根,这是effective id就是根权限了,但是如果仍想验证实际用户能否存取一个给定的文件,就可以再调用access进行实际用户ID测试,通过才可获得该文件的权限.

#include <unistd.h>int access(const char * pathname,int mode);mode常数有4个,R_OK,W_OK,X_OK,F_OK分别测试读,写,执行许可权和文件是否存在.八.umask函数:umask函数为进程设置文件方式创建屏蔽字,并返回以前的值.tips:这是少数几个没有出错返回的函数中的一个.#include <sys/types.h>#include <sys/stat.h>mode_t umask(mode_t cmask);参数cmask由上述9个常数逐位或构成.例:#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include "apue.h"int main(void){    umask(0);    if(creat("foo",S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) < 0)            err_sys("create error for foo");    umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);    if(creat("bar",S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) < 0)            err_sys("creat error for bar");    exit(0);}ls -l foo-rw-rw-rw- 1 yichen yichen 0 115 17:20 fools -l bar-rw------- 1 yichen yichen 0 115 17:20 bar

是不是一目了然:文件屏蔽位就是这个意思了.
九.chmod 和 fchmod函数:更改现存文件的存取许可权.

#include <sys/types.h>#include <sys/stat.h>int chmod(const char * pathname,mode_t mode);int fchmod(int filedes,mode_t mode);chmod函数:在制定的文件上进行操作.fchmod函数:对一打开的文件进行操作.tips:我们看它们的参数就可知晓了,一个需要路径,一个是需要文件描述符.为了改变你一个文件的许可权位,进程的有效用户ID必须等于文件的所有者,或者该进程必须具有超级用户许可权.chmod 函数的mode常数有15个,其中有9个取自文件许可位,另外6个分别为:S_ISUID 执行时set_user_IDS_ISGID 执行时set_group_IDS_ISVTX 保存正文S_IRWXU,S_IRWXG,S_IRWXO,对应9个文件许可位的综合用户,组,其他读写执行.

十.粘住位:已经被淘汰了.
十一.chown,fchowm和lchown函数:
chown函数用于更改文件的用户ID和组ID.

#include <sys/types.h>#include <unistd.h>int chown(const char * pathname,uid_t owner,gid_t group);int fchown(int filedes,uid_t owner,gid_t group);int lchown(const char *pathname,uid_t owner,gid_t group);

这三个函数的区别点在所引用的文件是否是符号连接(文件本身指向另一个文件).在符号连接情况下,lchown更改符号链接本身的所有者,而不是该符号链接所指向的文件.
十二.文件长度:
stat结构的成员st_dize包含了以字节为单位的该文件的长度.此字段只对普通文件,目录文件和符号连接有意义.
普通文件:文件长度可以是0,在读这种文件时,将得到文件结束只是.
目录:文件长度通常是一个数,例如16或512的整倍数.(在二十一说明)
符号连接:文件长度是在文件名中的实际字节数.
例如:lrwxrwxrwx l root 7 sep 25 07:14 lib -> usr/lib
7就是路径名usr/lib的长度.
文件中的空洞(hole):空洞是超过文件结尾端的位移量设置,并写了某些数据造成的.
ls -l core
-rw-r–r– l stevens 8483248 Nov 18 12:18 core
du -s core
文件core的长度超过8M字节,而du命令则报告该文件所使用的磁盘空间总量是272个512字节块(139264字节)则此文件有很多空洞.
read函数对于没有写过的字节位置读到的数据字节是0,如果实行:
wc -c core
8483248 core
由此可见,正常的I/O操作读至整个文件长度(-c 计算文件字符)
如果使用公用程序,例如cat复制这种文件,那么所有这些空洞都被携程实际数据字节0.

十三.文件截短:
truncate函数和ftruncate函数:

#include <sys/types.h>#include <unistd.h>int truncate(const char *pathname,off_t length);int ftruncate(int filedes,off_t length);

这两个函数将由路径名pathname或打开文件描述符filedes制定一个现存文件的长度截短为length.如果文件长度大于length则截短,如果小于后果与系统有关.
十四.文件系统:
这块内容重要,但不好总结性文字描述:需要复习时对比原书4.15(72页).
十五:link,unlink,remove和rename函数:
link:
任何一个文件可有多个目录项指向i节点:

#include <unistd.h>int link(const char *existingpath,const char *newpath);

此函数创建一个新目录项newpath,它引用现存文件existingpath,如果newpath已经存在,则返回出错.
创建新目录项以及增加连接计数应当是个原子操作.
tips:只有超级用户进程可以创建指向一个目录的新连接,其理由是这样做可能在文件系统中形成循环,大多数处理文件系统的公用程序都不能处理这种情况.
unlink:删除一个现存的目录项:

#include <unistd.h>int unlink(const char*pathname);

此函数删除目录项,并将由pathname所引用的文件的连接计数减1.如果该文件还有其他连接,则仍可通过其他连接存取该文件的数据.如果出错,则不对该文件作任何更改.
tips:为了解除对文件的连接,必须对包含该目录项的目录具有wx权利.只有当连接计数达到0时,该文件的内容才可被删除.只要有进程打开了该文件,其内容也不能删除,关闭一个文件时,内核首先检查使该文件打开的进程计数.如果该计数达到0,然后内核检查其连接计数,如果这也是0,那么就删除该文件的内容.
如果pathname是符号连接,那么unlink涉及的是符号连接而不是该连接所引用的文件.
超级用户可以调用带参数pathname的unlink制定一个目录,但是通常不适用这种方式,而使用函数rmdir.
remove函数:
对于文件,remove等同于unlink,对于目录,remove等同与rmdir

#include <stdio.h>int remove(const char*pathname);rename函数:文件或目录用rename函数更名.#include <stdio.h>int rename(const char * oldname,const char * newname);

十六.符号连接:
符号连接是对一个文件的间接指针,它与硬连接(文件系统)有所不同,硬连接直接指向文件的i节点.
作用:1.硬连接通常要求连接和文件位于同一文件系统中.2.只有超级用户才能创建到目录的硬连接(原因见文件系统)
对符号连接以及它指向什么没有文件系统限制,任何用户都可创建指向目录的符号连接.符号连接一般用于将一个文件或整个目录结构移到系统中其他某个位置.
各个函数与符号连接的关系:
跟随符号连接:access,chdir,chmod,creat,exec,link,mkdir,mkfifo,mknod,open,opendir,pathconf,stat,unlink
不跟随符号连接:lchown,lstat,readlink,remove,rename,unlink
chown跟不跟随取决与系统.
十七:symlink和readlink函数:

symlink函数创建一个符号连接:#include <unistd.h>int symlink(const char * actualpath,const char * sympath);

该函数创建了一个指向actualpath的新目录项sympath,在创建此符号连接时,并不要求actualpath已经存在.并且,actualpath和sympath并不需要位于同一文件系统中.
readlink:
因为open函数跟随符号连接,所以需要有一种方法打开该连接本身,并读该连接中的名字.readlink函数提供了这种功能.

#include <unistd.h>int readlink(const char*pathname,char *buf,int bufsize);

此函数组合open,read,close的所有操作.
十八.文件的时间:分为三种,文件数据的最后存取时间,文件数据的最后修改时间,i节点状态的最后更改时间.
十九.用与更改文件时间:具体用具体查.
二十.mkdir和rmdir:创建目录和删除目录.
mkdir创建目录自动创建.和..目录,并且后可指定文件存取许可权.
rmdir:仅能删除空目录.
二十一.读目录:具有存取许可权的人以用户都可读目录,但只有内核才能写目录.
tips:一个目录的写许可权位和执行许可权位决定了在该目录中能否创建新文件以及删除文件,它们并不表示能否写目录本身.
二十二:chdir,fchdir,getcwd函数:
每个进程都有一个当前工作目录,此目录是所有所有相对路径名的七点.
chdir和fchdir函数用于更改当前工作目录

#include <unistd.h>int chdir(const char*pathname);int fchdir(int filedes);

分别用路径名和文件描述符来制定新的当前工作目录.
内核为每个进程只保存当前工作目录i节点编号以及设备标识,并不保存该目录的完整路径名.
getcwd:取得当前工作目录的绝对路径名.

#include <unistd.h>char * getcwd(char *buf,size_t size);

二十三:特殊设备文件:感觉没什么用.
二十四:系统调用函数:svnc和fsync:用到查

这章函数太多:虽然一般都是用到查,我还是过一遍对每个函数有点具体印象即可.

0 0
原创粉丝点击