UNIX环境高级编程--4

函数stat fstat fstatat 和 lstat

  stat函数使用最多的地方可能就是ls -l 命令,用其可以获得有关一个文件的所有信息。

文件类型:

  (1)普通文件

  (2)目录文件

  (3)块特殊文件。这种类型的文件提供对设备带缓冲的访问,每次访问以固定长度为单位进行。

  (4)字符特殊文件:这种类型的文件提供对设备不带缓冲的访问,每次访问的长度可变。

  (5)FIFO:这种类型的文件用于进程间通信,也叫做命名管道

  (6)套接字:用于进程间的网络通讯,也可以用在一台宿主机上进程间的非网络通信。

  (7)符号链接:这种类型的文件指向另一个文件。

      链接有两种,一种被称为硬链接(Hard Link),另一种被称为符号链接(Symbolic Link,也叫做软链接)。默认情况下,ln命令产生硬链接。

      首先,符号链接属于软连接。直观感觉上,软连接类似于"浅拷贝"。只是复制了一份具有时效性的文件信息。不像硬链接一样,和原始文件息息相关的感觉。详情如下:      

##########################################

(一)硬链接

1.产生硬链接的语法

# ln 源文件 目标文件  (注意:不能为目录创建硬链接)

2.关于inode

inode 译成中文就是索引节点。每个存储设备或存储设备的分区(存储设备是硬盘、软盘、U盘 ... ... )被格式化为文件系统后,应该有两部份,一部份是inode,另一部份是Block,Block是用来存储数据用的。而inode呢,就是用来存储这些数 据的信息,这些信息包括文件大小、属主、归属的用户组、读写权限等。inode为每个文件进行信息索引,所以就有了inode的数值。操作系统根据指令, 能通过inode值最快的找到相对应的文件。

硬连接指通过索引节点来进行的连接。在Linux的文件系统中,保存在磁盘分区中的文件不管是什么类型都给它分配一个编号,称为索引节点号 (Inode Index)。在Linux中,多个文件名指向同一索引节点是存在的。一般这种连接就是硬连接。硬连接的作用是允许一个文件拥有多个有效路径名,这样用户 就可以建立硬连接到重要文件,以防止“误删”的功能。其原因如上所述,因为对应该目录的索引节点有一个以上的连接。只删除一个连接并不影响索引节点本身和 其它的连接,只有当最后一个连接被删除后,文件的数据块及目录的连接才会被释放。也就是说,文件才会被真正删除。

3.inode相同的文件是硬链接文件

 在Linux 文件系统中,inode值相同的文件是硬链接文件,也就是说,不同的文件名,inode可能是相同的,一个inode值可以对应多个文件。

 inode值相同的文件,他们的关系是互为硬链接的关系。当我们修改其中一个文件的内容时,互为硬链接的文件的内容也会跟着变化。如果我们删除互为硬链接关系的某个文件时,其它的文件并不受影响。

(二)软链接(符号链接

与硬连接相对应,Lnux系统中还存在另一种连接,称为符号连接(Symbilc Link),也叫软连接。软链接文件有点类似于Windows的快捷方式。它实际上是特殊文件的一种。在符号连接中,文件实际上是一个文本文件,其中包含的有另一文件的位置信息。

1.产生软链接的语法

     # ln -s 源文件或目录 目标文件或目录

   2.关于软链接

    软链接也叫符号链接,它和硬链接有所不同,软链接文件只是其源文件的一个标记。当我们删除了源文件后,链接文件不能独立存在,虽然仍保留文件名,但我们却不能查看软链接文件的内容了。

    值得我们注意的是:当我们修改链接文件的内容时,就意味着我们在修改源文件的内容。当然源文件的属性也会发生改变,链接文件的属性并不会发生变化。当我们 把源文件删除后,链接文件只存在一个文件名,因为失去了源文件,所以软链接文件也就不存在了。这一点和硬链接是不同的;

(三)示例

touch f1(创建一个f1的文件)

ln f1 f2 创佳一个f2的硬连接

ln -s f1 f3 创建一个f3的软连接

此时如果删除f3,对f1,f2无影响;如果删除f2,对f1,f3也无影响,如果删除f1,那么因为f2也应用f1,所以并不影响f2节 点的,touch 创建的文件仍然存在;但是此时f3因为是软连接,导致f3失效。如果删除f1,f2 ,那么touch 创佳的文件会被删除

##########################################

用户ID和组ID:
    实际用户ID、实际组ID    ---   我们实际上是谁
    有效用户ID、有效组ID、附属组ID --- 用于文件访问权限检查
    保存的设置用户ID、保存的设置组ID --- 由exec函数保存
    还有关于kernel关于这3个用户的维护过程:
    1.实际用户ID,这个ID可以认为是用户也不会改变的,除了root用户下的setuid这个函数可以改变,因为通常我们在login以后我们的用户就已经决定下来啦,那么也就是说实际用户ID是不变的。
    2.有效用户ID,这个ID通常情况下是不改变的,但是当执行文件被设置了设置用户ID位,那么exec会将这个进程的有效用户ID修改成这个可执行文件的本来的用户,就像我们前面所说的那样的。
    3.保存设置用户ID,这个准确的说可以认为是有效用户ID的备份,不管什么时候,只要运行了exec以后都会对有效用户ID进行拷贝的。


文件访问权限:
    每个文件有9个访问权限,可以分为3类:用户(读、写、执行),组(读、写、执行),其他(读、写、执行)。用户指文件所有者。
    chomd命令用于修改这9个权限。chmod用o表示其他,g表示组,u表示用户。
    如果对某个路径下面的某个文件进行操作,那么不光要对该文件有相应权限而且对于路径上的目录也要有执行权限(这样才能搜索到这个执行文件)
新文件和目录的所有权:
    新文件的用户ID设置为进程的有效用户ID。组ID:
    (1)设置成进程的有效组ID
    (2)所在目录的组ID
    其实在UNIX的实现中,文件权限用12个二进制位表示,如果该位置上的值是 1,表示有相应的权限:
    11 10 9 8 7 6 5 4 3 2 1 0
    S   G  T r w x r w x r w x
    第11位为SUID位,第10位为SGID位,第9位为sticky位(粘滞位),第8-0位对应于上面的三组rwx位。
    粘滞位:如果用户对目录有写权限,则可以删除其中的文件和子目录,即使该用户不是这些文件的所有者,而且也没有读或写许可。粘着位出现执行许可的位置上,用t表示,设置了该位后,其它用户就不可以删除不属于他的文件和目录。
    上面的-rwsr-xr-x的值为: 1 0 0 1 1 1 1 0 1 1 0 1
          -rw-r-Sr--的值为: 0 1 0 1 1 0 1 0 0 1 0 0


函数access和faccessat:
    函数按照实际用户ID和实际组ID进行访问权限测试。

函数umask:
    umask函数为进程设置文件模式创建屏蔽字,并返回之前的值。
    实现4-9发现生成的.out文件不具有可执行权限:ls -l .out 显示为:-rw-rw-r--    x代表执行权限,发现这里没有用户|组|其他的执行权限。然后给赋读和执行权限。
    原因:gcc -c 4-9.c 只做编译不进行后续链接成可执行文件的操作。所以不是可执行文件。不加-c将会编译链接得到可执行文件。
    umask(0):不做任何屏蔽
    $u mask显示当前文件模式下的屏蔽字 : 0002 代表其他写。027代表阻止同组写以及其他用户读
    umask可以控制所创建的文件的默认权限。

函数chmod、fchmod和fchmodat:
    这三个函数可以更改现有文件的访问权限。
    ls命令列出的时间和日期并没有改变。chmod函数更新的只是i节点最近一次被更改的时间。ls显示的是最后一次修改文件内容的时间。

粘着位:
    如果一个可执行文件的这一位被设置了,那么当该程序第一次被执行,在其终止时,程序正文部分的一个副本仍会被保存在交换区(指的是机器指令)。这使得下一次执行该程序时能较快的将其装载入内存。。
    通常UNIX文件系统中的数据块都是随机存放的,交换区是被作为一个连续文件来处理的。开机启动时,自动文件的正文部分总是在交换空间中。.
函数chown、fchown、fchownat和lchown:
    下面几个chown函数可用于改变文件的用户ID和组ID。如果两个参数owner或group中任意一个是-1,则对应的ID不变。
    lchown和fchownat更改符号链接本身的所有者,而不是符号链接(软连接 ln那种)所指向的文件的所有者。
    fchown函数改变fd参数指向的打开文件的所有者。
        
文件长度:
    stat结构成员st_size表示以字节为单位的文件的长度。此字段只对普通文件、目录文件和符号链接有意义。
    文件长度通常是16或者512的整数倍。

stat:
    通过文件名获取文件信息,并保存在buf所指的结构体stat中。
    
文件系统:
    UNIX文件系统有多种实现。
    传统的基于BSD(伯克利软件套件)的UNIX文件系统(UFS)
    读写DOS格式软盘的文件系统(PCFS)
    读CD的文件系统(HSFS)
    一个磁盘分成一个或者多个分区。每个分区可以包含一个文件系统。i节点是固定长度的记录项,它包含有关文件的大部分信息。
    (1)硬链接:每个i节点中都有一个链接计数,其值是指向该i节点的目录项数。只有当链接计数减少至0时,才能删除该文件。
    (2)软连接:符号链接。符号链接的内容(在数据块中)包含了该符号链接所指向的文件的名字。
    建立软连接,软连接文件指向源文件的节点,不创建新的文件节点。链接数不变。对目录建立的软连接类似快捷方式;
    建立硬链接,硬链接文件与源文件同样,创建一个新的文件节点。各自连接数+1。
    (3)i节点包含了文件有关的所有信息:文件类型、文件访问权限、文件长度和指向文件数据块的指针。只有2项:文件名和i节点编号存在目录块中。
    (4)硬链接不能跨越不同文件系统的原因:目录项中的i节点编号指向同一文件系统的相应i节点编号。
    (5)在不更换文件系统的情况下为一个文件出重命名时,该文件的实际内容并未移动,只需要构造一个指向现有i节点的新目录项,并删除老的目录项,链接计数不变。
函数link linkat unlink unlinkat 和remove:
    unlink的这种特性经常被程序用来确保即使是在程序崩溃时,他所创建的临时文件也不会遗留下来。进程用open或creat创建一个文件,然后立即调用unlink,因为该文件仍旧是打开的,所以不会将其内容删除。只有当进程关闭该文件或者终止时,该文件的内容才会被删除。
    
符号链接(软连接):
    符号链接是对一个文件的间接指针,与硬链接不同,硬链接指向文件的i节点。
    硬链接通常要求链接和文件位于同一个文件系统中。
    只有超级用户才能创建指向目录的硬链接
    软链接也容易出现路径循环问题。可以使用unlink来消除。但是如果创建了一个这种循环的硬链接,那么就很难消除它。所以link函数不允许普通用户权限构造指向目录的硬链接。
    
创建和读取符号链接:
    可以用symlink或symlinkat函数创建一个符号链接。创建符号链接时,并不要求acutualpath已经存在。
    
文件时间:
    修改时间:文件内容最后一次被修改的时间。
    状态更改时间:该文件的i节点最后一次被修改的时间。(如更改文件的访问权限、更改用户ID、更改链接数,这些并没有更改文件的实际内容)。因为i节点中的信息与文件的实际内容是分开存放的。
    
函数mkdir mkdirat和rmdir
    用mkdir 和 mkdirat创建目录,用rmdir函数删除目录。
    创建一个新目录后,会自动创建. 和 ..两个目录项。
    rmdir函数可以空!空!目录。如果调用次函数使目录的链接计数=0,并且也没有其他进程打开次目录,则释放由此目录占用的空间。如果在链接计数达到0时,有一个或者多个进程打开次目录,则在此函数返回前删除最后一个链接以及.he ..项。

读目录:
    一个目录的写权限位和执行权限位决定了在该目录中新建文件以及删除文件。
    这里解释一下4-22.c程序,完成的功能是统计给定目录下面一层文件或者目录的信息。
    三种数据结构:
        stat: 文件的详细信息。
        三个使用stat结构的函数:
            int fstat(int filedes, struct stat *buf);
            int stat(const char *path, struct stat *buf);
            int lstat(const char *path, struct stat *buf);
            后两个使用文件路径,而第一个fstat使用文件描述符。文件描述符需要我们用open系统调用后才能得到的!
            lstat与stat的区别:当文件是一个符号链接时,lstat返回的是该符号链接本身的信息;而stat返回的是该链接指向的真实文件的信息。
        
        struct stat {  
            mode_t     st_mode;       //文件访问权限   S_IRWXU = S_IRUSR|S_IWUSR|S_IXUSR  SIRWXG = S_IRGRP|S_IWGRP|S_IXGRP  SIRWXO = S_IROTH|S_IRWOTH|S_IRXOTH
            ino_t      st_ino;       //索引节点号  
            dev_t      st_dev;        //文件使用的设备号  
            dev_t      st_rdev;       //设备文件的设备号  
            nlink_t    st_nlink;      //文件的硬连接数  
            uid_t      st_uid;        //所有者用户识别号  
            gid_t      st_gid;        //组识别号  
            off_t      st_size;       //以字节为单位的文件容量  
            time_t     st_atime;      //最后一次访问该文件的时间  
            time_t     st_mtime;      //最后一次修改该文件的时间  
            time_t     st_ctime;      //最后一次改变该文件状态的时间  
            blksize_t st_blksize;    //包含该文件的磁盘块的大小  
            blkcnt_t   st_blocks;     //该文件所占的磁盘块  
          };  
        dirent:其他文件的名字以及指向这些文件有关的信息的指针;
        struct dirent   
        {   
              long d_ino; /* inode number 索引节点号 */  
             
            off_t d_off; /* offset to this dirent 在目录文件中的偏移 */  
             
            unsigned short d_reclen; /* length of this d_name 文件名长 */  
             
            unsigned char d_type; /* the type of d_name 文件类型 */  
             
            char d_name [NAME_MAX+1]; /* file name (null-terminated) 文件名,最长255字符 */  
        }  
        DIR:目录的有关信息;
        struct __dirstream   
        {   
            void *__fd;    
            char *__data;    
            int __entry_data;    
            char *__ptr;    
            int __entry_ptr;    
            size_t __allocation;    
            size_t __size;    
            __libc_lock_define (, __lock)    
        };   
        typedef struct __dirstream DIR;  
        
    总体流程:
        获取/a/b.txt (获取a目录下的b文件)如下,
        首先,使用opendir函数打开目录a,返回指向目录a的DIR结构体dp;
        接着,调用readdir(dp)读取a目录下的所有文件(包括目录),返回a目录下所有文件信息的dirent结构体 dirp;
        然后,遍历dirp,调用stat(lstat区别在于对链接文件的处理) (dirp->name, stat *e)来获取每一个文件的详细信息,存储在stat结构体e中。

函数chdir fchdir 和 getcwd:
    每个进程都有一个当前工作目录,次目录是搜索所有相对路径名的起点。当用户登陆到UNIX系统时,其当前工作目录通常是口令文件(/etc/passwd)中该用户登录项第6个字段---用户的起始目录(home directory)。当前工作目录是进程的一个属性,起始目录则是登录名的一个属性。
    chdir:更改当前的工作路径
    getcwd:获取当前的工作目录

设备特殊文件:
    设备分类:
        字符型设备:每次与系统传说1个字符的设备,这些设备通常为比如键盘、打印机、传真等设备提供流通信服务。一般都只能是顺序发送。
        块设备:    与操作系统用块的方式移动数据的设备。这些设备节点通常代表可以寻址设备,比如硬盘、CD-ROM和内存域。
        伪设备:在类UNIX操作系统中,设备节电并不一定要对应物理设备。没有这种对应关系的是伪设备。
    特殊设备:
        这里说到特殊设备除了硬盘主板等,只是它在linux shell命令里面,有特殊的作用,因此把它们单独拿出来。这些设备分别是:
        /dev/stdin:标准输入。
        /dev/stdout:标准输出。
        /dev/stderr:标准错误。
        /dev/null:黑洞设备,丢弃一切写入其中的数据,空设备用于丢弃不需要的输出流。
        /dev/zero:提供无限空字符(NULL,ASCII NUL, 0x00)。用来覆盖信息,产生一个特定大小的空白文件。
        /dev/full:常满设备。总是在向其写入时返回设备无剩余空间,读取时返回无限个空字符。用次设备测试程序在遇到磁盘无剩余空间错误时的行为
        /dev/random,urandom:随机数发生器。
        /dev/fd:记录用户打开的文件描述符。
        /dev/tcp|upd:读取该类形式设备,将会创建一个连接host主机port端口的tcp[udp]连接。打开一个socket通讯端口。
        /dev/loop:可以把loop文件,作为块设备挂载使用。
    使用宏定义:
        major(stat_buf.st_dev) minor(stat_buf.st_dev)来访问主、次设备号。

每天学很多linux命令:
wc -c file :计算file中的字节数。
du 命令:显示用于文件的块的数量 -s 只显示该目录和其中包含的文件的磁盘使用情况的总和。
fdisk -l :显示分区以及适用情况
ln f1 f2 :建立f1到f2的硬链接     ln -s f1 f2:建立f1到f2的软连接
mv A B : 重命名 A -> B   (mv命令可以移动或者重命名文件)
cat file :显示一个文件     cat > file : 创建一个file文件     cat file1 file2 file3 > file : 合并几个文件
find / -name filename* : 在/根目录下查找所有以filename开头的文件
stat filename : 查看filename文件的文件信息。 最近访问时间、 最近更改(内容)时间、 最近改动(状态)时间; 盘块号;访问权限等
rmdir函数可以 folder : 删除空!空!文件夹
pwd :显示当前路径
dd if=/dev/zero of=testzero count=1024 bs=1024  :创建一个大小为1M文件,该文件一个块是1024字节,一共是1024块(刚好1M),用/dev/zero文件内容填充它。输出创建到:testzero文件



软文一篇:
linux下普通文件与目录文件的区别
http://my.oschina.net/michaelyuanyuan/blog/109147

原文地址:https://www.cnblogs.com/luntai/p/6123785.html