Linux系统文件和目录的学习总结

    今天学习了Linux系统的文件和目录知识。在这里总结记录一下个人觉得需要了解和掌握的相关知识。

    总的来说,文件和目录的相关知识,围绕着三个系统函数stat、fstat和lstat函数展开。所以在这里先列出着三个函数以及相关参数作用进行说明。这三函数调用成功返回0,否则 返回-1;stat函数通过给定的pathname获得指定路径的文件的结构信息;fstat函数则获取在文件描述符上打开的文件的结构信息;lstat函数则是获取给定的符号链接文件(软链接)的结构信息。从概念上看,stat函数与lstat类似,可以通过给定路径的文件的结构信息。那么这个就衍生了一个问题:如果我使用stat函数获取给定的符号链接文件的结构信息会跟lstat有什么不同?要解释这个问题需要先了解相关的知识,往后看就可以有答案了。

//@param pathname 目的文件路径

//@param fd 目的文件描述符

//@param buf stat结构体,记录了指定的目的的文件的相关信息,结构如下:

/*

struct stat {
               dev_t     st_dev;         /* ID of device containing file */
               ino_t     st_ino;         /* inode number */
               mode_t    st_mode;        /* protection */
               nlink_t   st_nlink;       /* number of hard links */
               uid_t     st_uid;         /* user ID of owner */
               gid_t     st_gid;         /* group ID of owner */
               dev_t     st_rdev;        /* device ID (if special file) */
               off_t     st_size;        /* total size, in bytes */
               blksize_t st_blksize;     /* blocksize for filesystem I/O */
               blkcnt_t  st_blocks;      /* number of 512B blocks allocated */

               /* Since Linux 2.6, the kernel supports nanosecond
                  precision for the following timestamp fields.
                  For the details before Linux 2.6, see NOTES. */

               struct timespec st_atim;  /* time of last access */
               struct timespec st_mtim;  /* time of last modification */
               struct timespec st_ctim;  /* time of last status change */

           #define st_atime st_atim.tv_sec      /* Backward compatibility */
           #define st_mtime st_mtim.tv_sec
           #define st_ctime st_ctim.tv_sec
           };

*/

int stat(const char *pathname, struct stat *buf);

int fstat(int fd, struct stat *buf);

int lstat(const char *pathname, struct stat *buf);

    这次,要对stat结构体的重要成员成员进行一个全面的总结理解。通过调用上述三个函数之后,可以获取到stat结构信息。其中,对于st_mode成员,包含了文件类型、设置-用户-ID和设置-组-ID、文件存取许可权限。

1、文件类型:

    在Linux系统之中,一切皆文件。文件被分为七种类型:下面列出这七种文件类型以及其在Linux系统中的表示符号。这些文件的类型,在获取stat结构信息之后可以使用一系列的宏定义进行判断文件的类型,分别是S_ISREG(m)、S_ISDIR(m)、S_ISLNK(m)、 S_ISBLK(m)、S_ISCHR(m)、S_ISFIFO(m)、S_ISSOCK(m)。

普通文件:-

目录:d

符号链接文件:l

块设备文件:b

字符设备文件:c

命名管道:p

套接字:s

2、设置-用户-ID和设置-组-ID

    说到这两个ID,就得说明跟进程相关6个ID。实际用户ID和实际组ID、有效用户ID和有效组ID和添加组ID、设置-用户-ID和设置-组-ID。对于一个进程来说,实际用户ID和实际组ID就是启动了启动了这个进程的用户ID和组ID,而这个进程的有效用户ID和有效组ID、添加组ID表明了在该进程运行过程中,该进程有权限访问资源(简单点说,可以说文件),进程能够访问有效用户ID和有效组ID拥有或者能够访问的资源。在一般情况下,实际用户ID和有效用户ID、实际组ID和有效组ID是相同的。而如果设置了设置-用户-ID位之后,有效用户ID就可能发生改变,有效用户ID变成了该进程对应的程序文件的所有者的用户ID。同理设置了设置-组-ID位,有效组ID也会发生一样的改变。

3、文件的存取许可权限

    文件权限可以分位三个范围的文件权限,分为用户(文件所有者)的权限,组的权限(用户所在组)以及其他人的权限。下图给出st_mode字段中文件存取许可权的屏蔽位以及对应的意义。这些权限可以在创建文件的时候设定,也可在文件创建之后修改文件的权限,使用chmod命令,该命令允许用u表示用户,g表示组,o表示其他人。同时使用r表示文件的读权限,w表示文件的写权限,x表示文件的执行权限。那么修改文件的用户写权限可以用命令chmod u+w 文件名。此外,还可使用数字表示文件的权限:chmod 777 文件名。其中三个数字从左到右分别表示用户、用户所在组以及其他的文件存取权限,数字为八进制,4表示可读,2表示可写,1表示可执行。

Linux系统文件和目录的学习总结

    说到读写和执行权限,这里说明一下文件与目录的读写和执行权限分别代表这能在文件或者目录中进行什么样的操作。

文件:读权限表示能够查看文件的内容;写权限表示能够修改文件的内容;执行权限表示能够执行文件。目录:写权限表示能够读取目录的内容;写权限表示能够向目录中增加、删除或者移除文件等操作;执行权限表示能够打开目录,进入到目录中。

    说到文件的存取权限,需要结合到进程对文件的访问的权限。这就要从文件从一开始创建说起。在一个进程中创建的文件,文件的用户ID会被设置为进程的有效用户ID,而组ID则一般会被设置为文件所在目录的组ID。这样,之后,在进程中使用open函数对文件进行访问的时候,就会做一个判断。将文件的用户ID与进程的有效用户ID进行比较,如果相同才可以对文件进行文件所允许的相关的权限的操作。但是,之前说过进程的实际用户ID和有效用户ID不一定相同,所以很多时候,我们都向通过以实际用户ID为标准测试实际用户ID对文件的存取权限。这个时候就要使用到一个系统函数access函数,调用该函数成功时候,表示有对应的权限,返回值为0;若失败,表示没有对应的存取权限,返回值为-1;下面给出access函数:

//@param pathname 文件路径

//@param mode 文件的读写或者执行权限,有R_OK是否可读、W_OK是否可写、X_OK是否可执行、F_OK文件是否存在。    

int access(const char *pathname, int mode);

    对于st_size成员字段,表示文件的大小,以字节为单位。st_uid字段表示文件的用户ID,st_gid表示文件的组ID。

    对于st_ino字段表示i节点编号,st_nlink字段表示文件的硬链接数。说到这两个字段,需要进一步理解Linux系统的V文件系统。如图所示:

Linux系统文件和目录的学习总结

    我们可以把一个磁盘分为多个分区,每个分区有一个文件系统,在文件系统中包括自举块(或者引导块),超级块,i节点表以及目录块和数据块。引导块主要存放着读入操作系统的引导程序。超级块则记录了整个文件系统的管理信息。i节点表保存文件系统中的i节点。一个i节点对应一个文件或者目录,根节点保存在i节点表的最开始位置。之后的目录快和数据块则是用于保存数据。在创建一个文件的时候,文件系统就会创建一个i节点,i节点记录了数据保存的相关信息,需要获取文件数据的时候可以通过i节点获取到文件的数据。之后的数据块和目录块实际都是用来保存数据的,只是目录保存的是目录项,目录项记录了该目录下的文件名和文件i节点。总结来说,一般文件创建的时候,文件系统文件创建一个文件节点,然后再文件对应的目录中对应的目录块中添加目录项。然而,创建目录,文件系统为目录创建一个目录节点没分配目录快,再目录块中添加.和..的目录项(系统默认为每个目录添加),然后再该目录的父目录中添加一个目录项。这个就是LinuxV文件系统的大致工作流程和原理。

    而所谓的硬链接,其实就是一个目录项。创建一个硬链接的时候,目录块中添加一个目录项,该目录项的i节点与创建硬链接时候指定的目的文件指向的i节点相同。说到硬链接,需要涉及到软链接。何为软链接,之前说过的文件类型中,符号链接就是一个软链接,软链接本质上就是一个文件,然而这个文件的内容则是指向另一个文件的链接信息。这就是软链接,可以说是快捷方式。硬链接和软链接之间的区别除此之外,还有就是硬链接不能跨分区创建,而软连接可以;不能为目录创建硬链接,一般只有超级管理员可以为目录创建硬链接,这样是为了防止出现目录硬链接的创建发导致文件系统循环的问题出现。下面介绍与硬链接和软链接有关的函数。

硬链接:link函数和unlink函数均是成功返回0,失败返回-1。link函数是为文件建立一个硬链接,对于给出的newpath如果已经存在,则创建硬链接失败。unlink函数是删除指定路径的目录项。

//@param oldpath 指定需要建立硬链接的文件路径。

//@param newpath 指定建立硬链接的新文件路径

int link(const char *oldpath, const char *newpath);

//@param pathname 需要删除目录项的文件路径名。

int unlink(const char *pathname);

软链接:使用symlink函数可以创建一个软链接。readlink函数可以读取符号链接文件的内容。这里为什么用不能用open函数读取呢,如果使用了open函数读取文件内容,你会发现,他最终读取的是该符号链接所指向的文件的内容而非符号链接文件本身的内容。这是为什么呢?这就关系到了函数是否具有跟随符号链接的特性了,有的系统函数具有跟随符号链接的特性,就如open函数就具有这个特性,所以使用open函数读取符号链接的内容最终成了读取符号链接所指向的文件的内容。到这里,文章一开头的一个疑问也就迎刃而解,关于使用函数stat和lstat函数对符号链接文件结构信息的获取的区别也是因为这个原因。

//@param target 需要链接到的目的文件路径

//@param linkpath 需要创建的符号链接的文件路径

int symlink(const char *target, const char *linkpath);//成功 返回0,否则返回-1

//@param pathname 指定的符号链接路径

//@param buf 将符号链接文件内容读取到此的目的buf换冲区

//@param bufsize 缓冲区的大小

int readlink(const char *pathname, char *buf, size_t bufsize);//成功返回读入buf的字节数,否则返回-1

    好了,就总结这些个人认为需要理解掌握的知识。