linux文件和目录


内容概览

1. 引言

4.1 4个stat函数 #include <sys/stat.h> int stat(const char *pathname, struct stat *buf); int fstat(int fd, struct stat *buf); int lstat(const char *pathname, struct stat *buf); int fstatat(int fd, const char *pathname,struct stat *buf, int flag); 返回值:成功返回0,错处返回-1 (1) stat函数将于此路径名的文件有关信息保存在buf指向的缓冲区中。 (2) fstat函数获取已打开描述符fd上相关信息。 (3) lstat函数返回该符号链接的有关信息,而不是由该符号链接引用的文件的信息。 (4) fstatat函数为一个相对于当前打开目录的路径名返回的文件信息。flag参数控制着是否跟随这一个符号链接。当标志设置为AT_SYMLINK_NOFOLLOW时,则不会跟随符号链接。 4.2 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 file system I/O */ blkcnt_t st_blocks; /* number of 512B blocks allocated */ time_t st_atime; /* time of last access */ time_t st_mtime; /* time of last modification */ time_t st_ctime; /* time of last status change */ }; 4.3 文件类型 Unix/Linux系统中,文件有7种类型: (1) 普通文件(regular file)。至于普通文件是文本文件还是二进制数据,对于内核而言没有区别,关键在于解释这个文件的应用程序。 (2) 目录文件(directory file)。这种文件包含了其他文件的名字以及指向与这些文件有关信息的指针。 (3) 块特殊文件(block special file)。这种类型的文件提供对设备带缓冲的访问,每次访问以固定长度为单位进行。 (4) 字符特殊文件(character special file)。这种类型的文件提供对设备不带缓冲的访问,每次访问长度可变。 (5) FIFO。用于进程间通信,也叫管道(pipe)。 (6) 套接字(socket)。这种类型的文件用于进程间的网络通信。 (7) 符号链接(symbolic link)。这种类型的文件指向另一个文件。 文件类型信息保存在stat结构的st_mode成员中,可以使用下面的宏来确定文件类型。 宏 文件类型 S_ISREG() 普通文件 S_ISDIR() 目录文件 S_ISCHR() 字符特殊文件 S_ISBLK() 块特殊文件 S_ISFIFO() FIFO或管道 S_ISLNK() 符号链接 S_ISSOCK() 套接字 早期的Unix版本并不提供S_ISxxx宏,需要将sd_mode与屏蔽字S_IFMT位与运算,然后与名为S_IFxx的常量进行比较。 #define S_ISDIR (mode) ( ( (mode) & S_IFMT) )==S_IFDIR) 4.4 文件访问权限 4.4.1 文件的9个访问权限位 stat结构中的成员st_mode值也包含对了文件的访问权限为。每个文件有9个访问权限位: st_mode屏蔽 含义 S_IRUSR S_IWUSR S_IXUSR 用户读 用户写 用户执行 S_IRGRP S_IWGRP S_IXGRP 组读 组写 组执行 S_IROTH S_IWOTH S_IXOTH 其他读 其他写 其他执行 (1) 目录的读权限和执行权限与普通文件的意义是不同的。对于目录,读权限允许我们获取该目录中所有文件名的列表。当一个目录是我们要访问文件的路径名的一个组成部分时,对该目录的执行权限使我们可通过该目录(也就是搜索该目录,寻找一个特定的文件名)。 (2) 对目录具有写权限和执行权限,才能在目录中创建一个文件。 (3) 如果要删除一个现有文件,必须对包含该文件的目录具有写权限和执行权限,但对该文件本身则不需要读、写权限。 4.4.2 内核文件访问权限测试 进程每次打开、创建或删除一个文件时,内核就进行文件访问权限测试: (1) 若进程的有效用户ID是0(超级用户),则允许访问。 (2) 若进程的有效用户ID等于文件的所有者ID(也就是进程拥有此文件),那么如果所有者适当的访问权限为被设置,则允许访问,否则拒绝访问。 (3) 若进程的有效组ID或进程的附属组ID之一等于文件的组ID,那么如果适当的访问权限位被设置,则允许访问,否则拒绝访问。 (4) 若其他用户适当的访问权限为被设置,则允许访问,否则拒绝访问。 4.5 access和faccessat函数 当一个进程使用设置用户ID或设置组ID功能作为另一个用户(或组)运行时,希望按其实际用户ID和实际组ID来测试其访问权限,就需要使用access或faccessat函数。 #include <unistd.h> int access(const char *pathname, int mode); int faccessat(int fd, const char *pathname, int mode, int flag); 返回值:成功返回0,错误返回-1 mode参数: mode 说明 F_OK 测试文件是否存在(access函数) R_OK 测试读权限 W_OK 测试写权限 X_OK 测试执行权限 flag参数可以用于改变faccessat函数的行为,如果flag设置为AT_EACCESS,访问检查用的是调用进程的有效用户ID和有效组ID,而不是实际用户ID和实际组ID。 4.6 umask函数 #include <sys/stat/h> mode_t umask(mode_t cmask); 返回值:之前的文件模式创建屏蔽字 umask函数为进程设置文件模式创建屏蔽字,并返回之前的值。 cmask是4.4.1中列出的9个常量中的若干个按位或组成的。 4.7 更改文件访问权限:chmod、fchmod和fchmodat #include <sys/stat.h> int chmod(const char *pathname, mode_t mode); int fchmod(int fd, mode_t mode); int fchmodat(int fd,const char *pathname, mode_t mode,int flag); 返回值:成功返回0,出错返回-1 flag参数可以用于改变fchmodat的行为,当设置了AT_SYMLINK_NOFOLLOW标志时,不会跟随符号链接。为了改变一个文件的权限位,进程的有效用户ID必须等于文件的所有者ID,或者该进程必须具有超级用户权限。 参数mode所示常量的按位或: mode 说明 S_ISUID S_ISGID S_ISVTX 执行时设置用户ID 执行时设置组ID 保存正文(粘着位) S_IRWXU S_IRUSR S_IWUSR S_IXUSR 用户读写执行 用户读 用户写 用户执行 S_IRWXG S_IRGRP S_IWGRP S_IXGRP 组读写执行 组读 组写 组执行 S_IRWXO S_IROTH S_IWOTH S_IXOTH 其他读写执行 其他读 其他写 其他执行 如果我们只想修改其中的某些权限位,先调用stat获得当前权限,然后修改他。

4.8 更改文件实际用户ID和实际组ID #include <unistd.h> int chown(const char *pathname, uid_t owner, gid_t group); int fchown(int fd, uid_t owner, gid_t group); int fchownat(int fd, const char *pathname, uid_t owner, gid_t group, int flag); int lchown(const *pathname, uid_t owner, gid_t group); 返回值:成功返回0,出错返回-1 (1) owner或group中的任意一个是-1,则对应的ID不变。 (2) 在富豪链接情况下,lchown和fchownat(设置了AT_SYMLINK_NOFOLLOW标志)更改符号链接本身的所有者,而不是该符号链接所指向的文件的所有者。 (3) 基于BSD的系统一直规定只有超级用户才能更改一个文件的所有者。System V则允许仁义用户更改他们所拥有的文件的所有者。 4.9 文件截断 #include <unistd.h> int truncate(const char *pathname, off_t length); int ftruncate(int fd, off_t length); 这两个函数将一个现有文件长度截断为length。如果该文件以前的长度大于length,则超过length意外的数据不能再访问。如果以前的长度小于length,文件长度增加,在以前的文件尾端和新的文件尾端之间的数据读作0。 4.10 创建一个现有文件的链接 任何一个文件可以有多个目录项指向其i节点。创建一个指向现有文件的链接的方法是使用link函数或linkat函数。 #include <unistd.h> int link(const char *existingpath,const char *newpath; int linkat(int efd,const char *existingpath, int nfd, const char *newpath, int flag); 返回值:成功返回0,出错返回-1 如果newpath已经存在,则返回出错。只创建newpath的最后一个分量,路径中的其他部分应当已经存在。 当现有文件是符号链接时,有flag参数来控制linkat函数是创建指向现有符号链接的链接还是创建指向现有符号链接所指向的文件的链接。flag参数设置了AT_SYMLINK_NOFOLLOW标志,就创建指向符号链接目标的链接。 4.11 删除现有的目录项 #include <unistd.h> int unlink(const char *pathname); int unlinkat(int fd, const char *pathname, int flag); 返回值:成功返回0,出错返回-1 删除目录项,并将由pathname所引用文件的链接计数减1. flag参数给出了一种方法,使调用进程可以改变unlinkat函数的额默认行为,当AT_REMOVEDIR标志被设置时,unlinkat函数可以类似于rmdir一样删除目录。 4.12 创建和读取符号链接 符号链接是对一个文件的简介指针,而硬链接直接指向文件的i节点,引入符号链接是为了避开硬链接的一些限制。硬链接通常要求链接和文件位于同一文件系统中;只有超级用户才能创建指向目录的硬链接。 #include <unistd.h> int symlink(const char *actualpath, const char *sympathy); int symlinkat(const char *actualpath, const char *sympathy); 返回值:成功返回0,错误返回-1 函数创建了一个指向actualpath的新目录项sympath。在创建此符号链接是,并不要求actualpath已经存在。 因为open函数跟随符号链接,所以需要有一种方法打开该链接本身,并读该连接中的名字。 #include <unistd.h> ssize_t readlink(const char *pathname, char *buf, size_t bufsize); ssize_t readlinkat(int fd, const char *pathname, char *buf, size_t bufsize); 返回值:成功返回读取的字节数,出错返回-1 4.13 读目录函数 #include <dirent.h> DIR *opendir(const char *pathname); DIR *fdopendir(int fd); 返回值:成功回到顶部指针,出错返回NULL struct dirent *readdir(DIR *dp); 返回值:成功返回dirent结构指针,若在目录尾或出错,返回NULL void rewinddir(DIR *dp); int closedir(DIR *dp); 返回值:成功返回0,出错返回-1 long telldir(DIR *dp); 返回值:与dp关联的目录中的当前位置 void seekdir(DIR *dp,long loc); DIR结构是一个内部结构,上述函数用这个内部结构保存当前正在被读的目录的有关信息。 有opendir和fdopendir返回的指向DIR。opendir执行初始化操作,使第一个readdir回到顶部中的第一个目录项。DIR结构有fdopendir创建时,readdir返回的第一项取决于传给fdopendir函数的文件描述符相关的文件偏移量。 4.14 mkdir、mkdirat、rmdir函数 4.14.1 创建空目录 #include <sys/stat.h> int mkdir(const char *pathname, mode_t mode); int mkdirat(int fd, const char *pathname, mode_t mode); 返回值:成功返回0,出错返回-1 创建一个新的空目录,其中. 和 .. 目录项是自动创建的。所指定的文件访问权限mode还会经过进程的文件模式创建屏蔽字修改(umask)。 对于目录通常至少要设置一个执行权限位,以允许访问该目录中的文件名。 4.14.2 删除空目录 #include <unistd.h> int rmdir(const char *pathname); 返回值:成功返回0,失败返回-1 如果调用此函数使得目录的链接计数为0,并且也没有其他进程打开此目录,则释放此目录。 如果链接计数达到0时,有一个 或多个进程打开此目录,则在此函数返回前删除最后一个链接. 和 ..项。而且在此目录中不能再创建新文件,但是在最后一个进程关闭它之前并不释放此目录。 4.15 文件权限位总结 mode常量 说明 对普通文件的影响 对目录文件的影响 S_ISUID 设置用户ID 执行时设置有效用户ID S_ISGID 设置组ID 若组执行位设置,则执行时设置有效组ID;否则使强制性起作用 将目录中创建的新文件的组ID设置为目录的组ID S_ISVTX 粘着位 在交换区缓冲程序正文 限制在目录中删除和重命名文件 S_IRWXU 用户读写执行 许可用户读写执行文件 许可用户读目录项,删除和创建目录,搜索给定路径名 S_IRUSR 用户读 许可用户读文件 许可用户读目录项 S_IWUSR 用户写 许可用户写文件 许可用户在目录中删除和创建文件 S_IXUSR 用户执行 许可用户执行文件 许可用户在目录中搜索给定路径名 S_IRWXG 组读写执行 许可组读写执行文件 许可组读目录项,删除和创建目录,搜索给定路径名 S_IRGRP 组读 许可组读文件 许可组读目录项 S_IWGRP 组写 许可组写文件 许可组在目录中删除和创建文件 S_IXGRP 组执行 许可组执行文件 许可组在目录中搜索给定路径名 S_IRWXO 其他读写执行 许可其读写执行文件 许可其他读目录项,删除和创建目录,搜索给定路径名 S_IROTH 其他读 许可其他读文件 许可其他读目录项 S_IWOTH 其他鞋 许可其他写文件 许可其他在目录了中删除和创建文件 S_IXOTH 其他执行 许可其他执行文件 许可其他在目录中搜索给定路径名

本章节摘自《Linux C编程一站式学习》
https://akaedu.github.io/book/
版权 © 2008, 2009 宋劲杉, 北京亚嵌教育研究中心
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with the Invariant Sections being 前言, with no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in GNU Free Documentation License Version 1.3, 3 November 2008.

100次点赞 100次阅读