UNIX文件属性

关于UNIX文件的介绍我认为主要可以从文件的存储方式和文件的属性来介绍。文件的存储方式在之前的文章里已经提过,这里不再详细说明。

要研究UNIX文件的属性及文件的相关操作,必须从结构体struct stat说起,以下是stst结构的定义,其所在的位置是”/usr/include/sys/stat.h”,我们在编程使用到该结时也需要添加头文件#inclucde <stdio.h>

struct stat {

        dev_t           st_dev;         /* [XSI] ID of device containing file */

        ino_t           st_ino;         /* [XSI] File serial number */

        mode_t          st_mode;        /* [XSI] Mode of file (see below) */

        nlink_t         st_nlink;       /* [XSI] Number of hard links */

        uid_t           st_uid;         /* [XSI] User ID of the file */

        gid_t           st_gid;         /* [XSI] Group ID of the file */

        dev_t           st_rdev;        /* [XSI] Device ID */

#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)

        struct  timespec st_atimespec;  /* time of last access */

        struct  timespec st_mtimespec;  /* time of last data modification */

        struct  timespec st_ctimespec;  /* time of last status change */

#else

        time_t          st_atime;       /* [XSI] Time of last access */

        long            st_atimensec;   /* nsec of last access */

        time_t          st_mtime;       /* [XSI] Last data modification time */

        long            st_mtimensec;   /* last data modification nsec */

        time_t          st_ctime;       /* [XSI] Time of last status change */

        long            st_ctimensec;   /* nsec of last status change */

#endif

        off_t           st_size;        /* [XSI] file size, in bytes */

        blkcnt_t        st_blocks;      /* [XSI] blocks allocated for file */

        blksize_t       st_blksize;     /* [XSI] optimal blocksize for I/O */

        __uint32_t      st_flags;       /* user defined flags for file */

        __uint32_t      st_gen;         /* file generation number */

        __int32_t       st_lspare;      /* RESERVED: DO NOT USE! */

        __int64_t       st_qspare[2];   /* RESERVED: DO NOT USE! */

};

关于struct stat结构在我们实现ls的时候需要大量用到,ls实际上封装的就是对于struct stat结构信息的读取来实现提取文件属性的功能。

我们可以先在函数中定义struct stat变量,然后通过系统调用stat函数,并将上面指向struct stat类型变量的指针作为参数传递给stat函数,并将得到的值赋予变量。这里stat系统调用的工作不过是将存储在某文件存储在磁盘inode结点中的文件信息重新填入了我们定义的内存变量中,这样我们才得以能够直接访问它们。

在这个结构体中,最值得我们讨论的是st_mode变量,它用来确定文件类型及文件的使用权限。我们根据st_mode变量的不同比特位来确定文件的类型。在sys/stat.h头文件中同样定义了这些常量,当我们将其与st_mode变量相与时,如果得到的结果不为0则可以判定该文件的类型。用于判定文件类型的常量如下。

#define S_IFIFO         0010000         /* [XSI] named pipe (fifo) */

#define S_IFCHR         0020000         /* [XSI] character special */

#define S_IFDIR         0040000         /* [XSI] directory */

#define S_IFBLK         0060000         /* [XSI] block special */

#define S_IFREG         0100000         /* [XSI] regular */

#define S_IFLNK         0120000         /* [XSI] symbolic link */

#define S_IFSOCK        0140000         /* [XSI] socket */

当然,我们也可以直接通过封装好的判定函数来确定文件的类型,实际上这些函数所做的工作正是与上述常量进行与操作。

除了文件类型之外,文件的权限也是文件的重中之重。我们将UNIX系统中文件的所有者分为3种,分别是本人、所属组和其他用户。某种用户对文件的操作权限包括读、写和执行。也就是说在st_mode中需要至少九个比特位来确认用户对文件的操作权限。

我们按照本人、本人所属组、其他用户来分配,比如111-110-001表示本人对文件具有读写执行的权限,本人所属组对文件具有读写权限但不具有执行权限,其他用户对该文件只具有执行权限。判定用户权限时候,我们依旧可以通过定义好的常量与st_mode相与得到用户是否具有相应的权限,这些常量如下。

#define S_IRUSR         0000400         /* [XSI] R for owner */

#define S_IWUSR         0000200         /* [XSI] W for owner */

#define S_IXUSR         0000100         /* [XSI] X for owner */

#define S_IRGRP         0000040         /* [XSI] R for group */

#define S_IWGRP         0000020         /* [XSI] W for group */

#define S_IXGRP         0000010         /* [XSI] X for group */

#define S_IROTH         0000004         /* [XSI] R for other */

#define S_IWOTH         0000002         /* [XSI] W for other */

#define S_IXOTH         0000001         /* [XSI] X for other */

通常我们在shell中创建新文件时都通过shellumask来作为新建文件的默认权限掩码。这里umask专门用来屏蔽某一用户的某种特定操作的权限,比如umask值等于777,相当于把所有用户对该文件的操作权限全部屏蔽了。如果是775,则相当于把其他用户的写权限屏蔽掉了。当然,如果是我们在程序中创建新文件,则新建文件可以摆脱shell默认umask的影响,这时我们可以通过在程序内重新定义umask值来完成对文件权限的改变,屏蔽掉多余的权限。

之前我们也提到过,目录文件也是一种文件,只不过目录文件相对比较特殊一些。对于目录而言,文件的权限相对来说比较难理解一些。目录的具有可读权限表示可以获得该目录中所有文件名的列表,我们可以将读等同于“获得”。如果目录是我们需要访问的某个文件的一部分组成时,只有具有执行权限才能通过该目录,我们可以将执行等同于“通过”,当某个目录不具备执行权限时,实际上在此目录下定义的所有文件都无法被搜索到。如果我们需要在某个目录下增删文件的话,首先目录必须要有写和执行的权限,执行权限是为了能够使目录能够出现在文件的路径上,而写权限是为了能够增删目录文件条目。

除了st_mode变量之外,我们还需要关注st_nlink变量,当我们创建硬链接时,两个目录项指向同一个inode结点,均可以对实际的文件进行操作。但是当其中一处删除文件时并不能直接删掉文件,而是只能对引用计数减1,当引用计数减为0时,文件才可以被完全删除。当然了,这里的链接计数只是对于硬链接而言的,符号链接并不采用这种方式。

除此以外不得不提的是st_uidst_gid,这两个变量标记了文件创建之后文件所有者ID和所属组ID,当某个进程访问某文件时,首先需要将文件的所有者IDst_uid)和进程的有效用户ID进行匹配,如果相同,则设置文件st_mode中所指定的文件所有者权限。如果文件所有者ID和进程有效用户ID不匹配,则就进程的所属组IDst_gid匹配,如果相同则设置st_mode中指定的组成员权限。若均不能匹配则设置其他用户权限。

上述流程中,如果进程有效用户IDst_uid相匹配的话,那么接下来的工作就不会再做了。

其他的关于文件大小,修改时间等属性就不再一一罗列了。

Advertisements