目录
1、文件类型
Linux 系统中的 7 种文件类型。
1)普通文件
2)目录
3)字符设备文件
4)块设备文件
5)符号链接文件
6)管道文件
7)套接字文件
1.1、查看文件类型
1)ls -l 文件
2)stat 文件
1.2、struct stat 结构体
struct stat
{
dev_t st_dev; /* 文件所在设备的 ID */
ino_t st_ino; /* 文件对应 inode 节点编号 */
mode_t st_mode; /* 文件对应的模式 */
nlink_t st_nlink; /* 文件的链接数 */
uid_t st_uid; /* 文件所有者的用户 ID */
gid_t st_gid; /* 文件所有者的组 ID */
dev_t st_rdev; /* 设备号(指针对设备文件) */
off_t st_size; /* 文件大小(以字节为单位) */
blksize_t st_blksize; /* 文件内容存储的块大小 */
blkcnt_t st_blocks; /* 文件内容所占块数 */
struct timespec st_atim; /* 文件数据的最后访问时间 */
struct timespec st_mtim; /* 文件数据的最后修改时间 */
struct timespec st_ctim; /* i节点状态最后更改时间 */
};
每个文件时间属性所保存的实际精度依赖于文件系统的实现。对于把时间戳记录在秒级的文件系统来说,纳秒这个字段就会被填充为0.对于时间戳的记录精度高于秒级的文件来说,不足的值被转换成纳秒并记录在纳秒这个字段中。
注:系统并不维护对一个i节点的最后一次访问时间,所以access和stat函数并不更改着3个时间中的任一个。
系统管理员常常使用访问时间来删除在一定时间范围内没有被访问过的文件。典型的例子是删除在过去一周内没有被访问过的名为a.out或core的文件。find命令常被用来进行这种类型的操作。
修改时间和状态更改时间可被用来归档那些内容已经修改或i节点已经被更改的文件。
目录是包含目录项(文件名和相关的i节点编号)的文件,增加、删除或修改目录项会影响到它所在目录相关的3个时间。例如,创建一个新文件影响到包含此新文件的目录,也影响该新文件的i节点。但是读或写一个文件,只影响该文件的i节点,而对目录无影响。
ls命令按着3个时间值中的一个排序进行显示。系统默认(用-l或-t选项调用时)是按文件的修改时间的先后排序显示。-u选项使ls命令按访问时间排序,-c选项则使其按状态更改时间排序。
1.2.1、st_mode 变量
st_mode 是 struct stat 结构体中的一个成员变量, 是一个 32 位无符号整形数据,该变量记录了文件的类型、文件的权限这些信息,其表示方法如下所示:
相关的宏定义如下所示:
宏 | 值 | 说明 |
拥有者权限 | ||
S_IRWXU | 00700 | owner has read, write, and execute permission |
S_IRUSR | 00400 | owner has read permission |
S_IWUSR | 00200 | owner has write permission |
S_IXUSR | 00100 | owner has execute permission |
组成员权限 | ||
S_IRWXG | 00070 | group has read, write, and execute permission |
S_IRGRP | 00040 | group has read permission |
S_IWGRP | 00020 | group has write permission |
S_IXGRP | 00010 | group has execute permission |
其他人权限 | ||
S_IRWXO | 00007 | others (not in group) have read, write, and execute permission |
S_IROTH | 00004 | others have read permission |
S_IWOTH | 00002 | others have write permission |
S_IXOTH | 00001 | others have execute permission |
特殊权限 | ||
S_ISUID | 04000 | set-user-ID 位权限 |
S_ISGID | 02000 | set-group-ID 位权限 |
S_ISVTX | 01000 | Sticky 位权限 |
文件类型 | ||
S_IFSOCK | 0140000 | socket(套接字文件) |
S_IFLNK | 0120000 | symbolic link(链接文件) |
S_IFREG | 0100000 | regular file(普通文件) |
S_IFBLK | 0060000 | block device(块设备文件) |
S_IFDIR | 0040000 | directory(目录) |
S_IFCHR | 0020000 | character device(字符设备文件) |
S_IFIFO | 0010000 | FIFO(管道文件) |
文件类型字段位掩码 | ||
S_IFMT | 0170000 | 文件类型字段位掩码 |
Linux 系统封装用于判断文件类型的宏,如下所示(m 为 st_mode 变量)
S_ISREG(m) | 判断是不是普通文件,如果是返回 true,否则返回 false |
S_ISDIR(m) | 判断是不是目录,如果是返回 true,否则返回 false |
S_ISCHR(m) | 判断是不是字符设备文件,如果是返回 true,否则返回 false |
S_ISBLK(m) | 判断是不是块设备文件,如果是返回 true,否则返回 false |
S_ISFIFO(m) | 判断是不是管道文件,如果是返回 true,否则返回 false |
S_ISLNK(m) | 判断是不是链接文件,如果是返回 true,否则返回 false |
S_ISSOCK(m) | 判断是不是套接字文件,如果是返回 true,否则返回 false |
POSIX.1允许实现将进程间通信(IPC)对象(如消息队列和信号量等)说明为文件。下面的宏可用来从stat结构中确定IPC对象的类型。这些宏的参数并非st_mode,而是指向stat结构的指针。
S_TYPEISMQ() | 消息队列 |
S_TYPEISSEM() | 信号量 |
S_TYPEISSHM() | 共享存储对象 |
1.2.2、文件的时间属性
1)文件最后被访问的时间: 访问指的是读取文件内容,文件内容最后一次被读取的时间,譬如使用read()函数读取文件内容便会改变该时间属性;
2)文件内容最后被修改的时间: 文件内容发生改变,譬如使用 write()函数写入数据到文件中便会改变该时间属性;
3)文件状态最后被改变的时间: 状态更改指的是该文件的 inode 节点最后一次被修改的时间,如更改文件的访问权限、更改文件的用户 ID、用户组 ID、更改链接数等,但它们并没有更改文件的实际内容,也没有访问(读取)文件内容。
1.3、stat()函数
stat 函数是 Linux 中的系统调用,用于获取文件相关的信息。
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *buf);
参数 pathname: 用于指定一个需要查看属性的文件路径。
参数 buf:保存获取到的文件属性信息。
返回值: 成功返回 0;失败返回-1,并设置 error。
1.4、fstat() 函数
fstat 与 stat 区别在于, stat 是从文件名出发得到文件属性信息,不需要先打开文件;而 fstat 函数则是从文件描述符出发得到文件属性信息,所以使用 fstat 函数之前需要先打开文件得到文件描述符。具体该用 stat还是 fstat,看具体的情况;譬如,并不想通过打开文件来得到文件属性信息,那么就使用 stat,如果文件已经打开了,那么就使用 fstat。
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int fstat(int fd, struct stat *buf);
参数 fd: 表示文件描述符
参数 buf: struct stat 类型指针,用于指向一个 struct stat 结构体变量。
返回值: 成功返回 0;失败返回-1,并设置 error。
1.5、lstat()函数
lstat与 stat、 fstat 的区别在于,对于符号链接文件, stat、 fstat 查阅的是符号链接文件所指向的文件对应的文件属性信息,而 lstat 查阅的是符号链接文件本身的属性信息。
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int lstat(const char *pathname, struct stat *buf);
参数 pathname: 用于指定一个需要查看属性的文件路径。
参数 buf: struct stat 类型指针,用于指向一个 struct stat 结构体变量。
返回值: 成功返回 0;失败返回-1,并设置 error。
2、文件权限
2.1、进程相关联的用户 ID 和组 ID
ID 类型 | 作用 |
实际用户 ID | 实际的用户ID和组ID |
实际组 ID | |
有效用户 ID | 用于文件访问权限检查 |
有效组 ID |
对于有效用户 ID 和有效组 ID 来说,这是进程所持有的概念,对于文件来说,并无此属性! 有效
用户 ID 和有效组 ID 是站在操作系统的角度,用于给操作系统判断当前执行该进程的用户在当前环境下对某个文件是否拥有相应的权限。
注:绝大部分情况下,进程的有效用户等于实际用户(有效用户 ID 等于实际用户 ID) ,有效组等于实际组(有效组 ID 等于实际组 ID)。
2.2、普通权限和特殊权限
当进程每次对文件进行读、写、执行等操作时,内核就会对文件进行访问权限检查,以确定该进程对文件是否拥有相应的权限。而文件的权限检查就涉及到了文件的所有者(st_uid)、文件所属组(st_gid)以及其它用户,当然这里指的是从文件的角度来看;而对于进程来说,参与文件权限检查的是进程的有效用户、有效用户组以及进程的附属组用户。
2.2.1、普通权限
每个文件都有 9 个普通的访问权限位。
注:
文件权限为:r,w,x时,显示rwx
文件权限为:r,w,x,s时,显示rws
文件权限为:r,w,s时,显示rwS
2.2.2、特殊权限
1) 当进程对文件进行操作的时候、将进行权限检查,如果文件的 set-user-ID 位权限被设置,内核会将进程的有效 ID 设置为该文件的用户 ID(文件所有者 ID) ,意味着该进程直接获取了文件所有者的权限、以文件所有者的身份操作该文件。使用passwd命令修改密码时,原理是通过修改etc/shadow文件从而实现用户账号密码的修改。而shadow文件只有root用户可以修改的。那普通用户为什么可以通过passwd修改字节的账号密码呢。其原理其实就是,passwd程序st_mode被设置了S_ISUID。此时,虽然passwd文件的所有者是root用户,但由于设置了S_ISUID,在程序运行时,程序的有效用户ID会被设置为root。所以,程序拥有root用户的权限,可以修改shadow文件。
2)当进程对文件进行操作的时候、将进行权限检查,如果文件的 set-group-ID 位权限被设置,内核会将进程的有效用户组 ID 设置为该文件的用户组 ID(文件所属组 ID) ,意味着该进程直接获取了文件所属组成员的权限、以文件所属组成员的身份操作该文件。对于文件夹的S_ISGID,如果文件夹A设置了S_ISGID,如果在A文件夹内创建B文件夹,则B文件夹的组ID默认为A文件夹的组ID。如果,没设置,则为创建文件夹的进程的有效ID。
注:
给文件所有者加S_ISUID :chmod u+s 文件名 (去除该位,则通过chmod u-s 文件名即可)
给文件所有者组加S_ISGID:chmod g+s 文件名 (去除该位,则通过chmod g-s 文件名即可)
2.3、chown() 函数
改变文件的所有者和所属组。
#include <unistd.h>
int chown(const char *pathname, uid_t owner, gid_t group);
参数 pathname:用于指定一个需要修改所有者和所属组的文件路径。
参数 owner:将文件的所有者修改为该参数指定的用户
参数 group:将文件的所属组修改为该参数指定的用户组
返回值: 成功返回 0;失败将返回-1,兵并且会设置 errno。
限制条件:
a、 只有超级用户进程能更改文件的用户 ID;
b、 普通用户进程可以将文件的组 ID 修改为其所从属的任意附属组 ID,前提条件是该进程的有效用户 ID 等于文件的用户 ID;而超级用户进程可以将文件的组 ID 修改为任意值。
2.4、fchown()函数
与stat和fstat的区别类似。
#include <unistd.h>
int fchown(int fd, uid_t owner, gid_t group);
2.5、 lchown()函数
与stat和 lstat的区别类似。
#include <unistd.h>
int lchown(const char *pathname, uid_t owner, gid_t group);
2.6、getuid()函数
#include <unistd.h>
#include <sys/types.h>
uid_t getuid(void);
返回值 :用户ID
2.7、 getgid()函数
#include <unistd.h>
#include <sys/types.h>
gid_t getgid(void);
返回值 :组ID
2.8、access()函数
检查执行进程的用户是否对该文件拥有的相应权限。
#include <unistd.h>
int access(const char *pathname, int mode);
pathname: 需要进行权限检查的文件路径。
mode: 该参数可以取以下值:
F_OK | 检查文件是否存在 |
R_OK | 检查是否拥有读权限 |
W_OK | 检查是否拥有写权限 |
X_OK | 检查是否拥有执行权限 |
返回值: 检查项通过则返回 0,表示拥有相应的权限并且文件存在;否则返回-1,如果多个检查项组合在一起,只要其中任何一项不通过都会返回-1。
2.9、chmod()函数
修改文件权限。
#include <sys/stat.h>
int chmod(const char *pathname, mode_t mode);
参数 pathname: 需要进行权限修改的文件路径,若该参数所指为符号链接,实际改变权限的文件是符号链接所指向的文件,而不是符号链接文件本身。
参数 mode: 该参数用于描述文件权限。
返回值: 成功返回 0;失败返回-1,并设置 errno。
注:文件权限对于文件来说是非常重要的属性,是不能随随便便被任何用户所修改的, 要想更改文件权限,要么是超级用户(root) 进程、要么进程有效用户 ID 与文件的用户 ID(文件所有者)相匹配。
2.10、fchmod ()函数
fchmod()与 chmod()的区别在于使用了文件描述符来代替文件路径,就像是 fstat 与 stat 的区别。
#include <sys/stat.h>
int fchmod(int fd, mode_t mode);
2.11、fchmodat()函数
fchmodat()函数与chmod函数在下面两种情况下是相同的:一种是pathname参数为绝对路径,另一种是fd参数取值为AT_FDCWD而pathname参数为相对路径。否则fchmodat计算相对于打开目录(fd参数指定的pathname)。flag参数可以用于改变fchmodat的行为,当设置了AT_SYMLINK_NOFOLLOW标志时,fchmodat并不会跟随符号链接。
参数mode:
mode | 说明 |
S_ISUID | 执行时设置用户ID |
S_ISGID | 执行时设置组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 | 其他执行 |
2.11、umask ()函数
umask函数为u进程设置文件模式创建屏蔽字,并返回之前的值。
通常在登录时,由shell的启动文件设置一次,然后,再不改变。当编写创建新文件的程序时,如果我们想确保指定的访问权限位已经激活,那么必须再进程运行时修改umask值。例如,如果想确保任何用户都能读文件,则应将umask设置为0.否则,当进程运行时,有效的umask值可能关闭该权限位。
权限掩码主要用于对新建文件的权限进行屏蔽。
注:权限掩码的表示方式与文件权限的表示方式相同, 但是需要去除特殊权限位, umask 不能对特殊权限位进行屏蔽。
#include <sys/types.h>
#include <sys/stat.h>
mode_t umask(mode_t mask);
参数 mask: 需要设置的权限掩码值。
返回值: 返回设置之前的 umask 值。
注:更改进程的文件模式创建屏蔽字并不影响其父进程(常常是shell)的屏蔽字.umask 是进程自身的一种属性、 A 进程的 umask 与 B 进程的 umask 无关(父子进程关系除外)。在 shell 终端下可以使用 umask 命令设置 shell 终端的 umask 值,但是该 shell 终端关闭之后、再次打开一个终端,新打开的终端将与之前关闭的终端并无任何瓜葛!
umask
umask -S
3、文件时间
futimens和utimensat函数可以指定纳秒级精度的时间戳。
例子,使用带O_TRUNC选项的open函数将文件长短截断为0,但并不更改其访问时间及修改时间。
3.1、utime()函数
显式的修改文件的时间属性。
#include <sys/types.h>
#include <utime.h>
int utime(const char *filename, const struct utimbuf *times);
参数 filename: 需要修改时间属性的文件路径。
参数 times: 将时间属性修改为该参数所指定的时间值。
struct utimbuf {
time_t actime; /* 访问时间 */
time_t modtime; /* 内容修改时间 */
};
返回值: 成功返回值 0;失败将返回-1,并会设置 errno。
注:除以下三种情况之外的用户进程将无法对文件时间戳进行修改。
1)超级用户进程(以 root 身份运行的进程) 。
2)有效用户 ID 与该文件用户 ID(文件所有者)相匹配的进程。
3)在参数 times 等于 NULL 的情况下,对文件拥有写权限的进程。
3.2、utimes()函数
utimes()与 utime()最大的区别在于可以以微秒级精度来指定时间值。
#include <sys/time.h>
int utimes(const char *filename, const struct timeval times[2]);
参数 filename: 需要修改时间属性的文件路径。
参数 times: 将时间属性修改为该参数所指定的时间值, times 是一个 struct timeval 结构体类型的数组, 数组共有两个元素, 第一个元素用于指定访问时间,第二个元素用于指定内容修改时间。
返回值: 成功返回 0;失败返回-1,并且会设置 errno。
注:不能对状态更改时间st_ctime指定一个值,因为调用此函数时,此字段会自动更新。
3.3、futimens()函数
显式修改文件时间戳
#include <fcntl.h>
#include <sys/stat.h>
int futimens(int fd, const struct timespec times[2]);
参数 fd: 文件描述符。
参数 times: 将时间属性修改为该参数所指定的时间值, times 指向拥有 2 个 struct timespec 结构体类型变量的数组,数组共有两个元素, 第一个元素用于指定访问时间,第二个元素用于指定内容修改时间。
1)如果参数是一个空指针,则修改访问时间和修改时间都设置为当前时间。
2)如果参数指向2个timespec结构的数组,任一数组元素的tv_nsec字段的值为UTIME_NOW,相应的时间戳就设置为当前时间,忽略相应的tv_sec字段。
???3)如果参数指向2个timespec结构的数组,任一数组元素的tv_nsec字段的值为UTIME_OMIT,相应的时间戳保持不变,忽略相应的tv_sec字段。
4)如果参数指向2个timespec结构的数组,且tv_nsec字段的值即不是UTIME_OMIT也不是UTIME_NOW。相应的时间戳设置为相应的tv_sec和tv_nsec字段的值。
执行这些函数所要求的优先级取决于times参数的值。
1)如果参数是空指针,或者任一tv_nsec字段设置为UTIME_NOW,则进程的有效用户ID必须等于该文件的所有者ID;进程对该文件必须具有写权限,或者进程是一个超级用户进程。
2)如果参数是非空指针,或者任一tv_nsec字段即不是UTIME_OMIT也不是UTIME_NOW,则进程的有效用户ID必须等于该文件的所有者ID;或者进程是一个超级用户进程。对文件只具有写权限是不够的。
3)如果参数是非空指针,并且两个tv_nsec字段的值都为UTIME_OMIT,就不执行任何权限检查。
返回值: 成功返回 0;失败将返回-1,并设置 errno。
3.4、utimensat()函数
futimens函数需要打开文件来更改它的时间,utimensat函数提供了一种使用文件名更改文件时间的方法。
#include <fcntl.h>
#include <sys/stat.h>
int utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags);
参数 dirfd: 该参数可以是一个目录的文件描述符,也可以是特殊值 AT_FDCWD;如果 pathname 参数指定的是文件的绝对路径,则此参数会被忽略。
pathname: 指定文件路径。如果 pathname 参数指定的是一个相对路径、并且 dirfd 参数不等于特殊值AT_FDCWD,则实际操作的文件路径是相对于文件描述符 dirfd 指向的目录进行解析。如果 pathname 参数指定的是一个相对路径、并且 dirfd 参数等于特殊值 AT_FDCWD, 则实际操作的文件路径是相对于调用进程的当前工作目录进行解析。
参数 times:将时间属性修改为该参数所指定的时间值。
参数 flags : 此 参 数 可 以 为 0 , 也 可 以 设 置 为 AT_SYMLINK_NOFOLLOW , 如 果 设 置 为AT_SYMLINK_NOFOLLOW,当 pathname 参数指定的文件是符号链接, 则修改的是该符号链接的时间戳,而不是它所指向的文件。
返回值: 成功返回 0;失败返回-1、并会设置时间戳。
4、软链接和硬链接
4.1、硬链接
硬链接文件与源文件都拥有相同的 inode 号,指向了物理硬盘的同一个区块,仅仅只是文件名字不同而已,创建出来的硬链接文件与源文件对文件系统来说是完全平等的关系。当为文件每创建一个硬链接, inode 节点上的链接数就会加一,每删除一个硬链接, inode 节点上的链接数就会减一,直到为 0, inode 节点和对应的数据块才会被文件系统所回收,也就意味着文件已经从文件系
统中被删除了。
4.2、软链接
软链接文件与源文件有着不同的 inode 号, 它们之间有着不同的数据块。但是软链接文件的数据块中存储的是源文件的路径名,链接文件可以通过这个路径找到被链接的源文件,它们之间类似于一种“主从”关系,当源文件被删除之后,软链接文件依然存在,但此时它指向的是一个无效的文件路径, 这种链接文件被称为悬空链接。
4.3、软链接优点
1)可以对目录创建软链接;
2)可以跨越不同文件系统;
3)可以对不存在的文件创建软链接;
4.4、link()函数
创建硬链接文件。
#include <unistd.h>
int link(const char *oldpath, const char *newpath);
参数 oldpath: 用于指定被链接的源文件路径,应避免 oldpath 参数指定为软链接文件,为软链接文件创建硬链接没有意义,虽然并不会报错。
参数 newpath: 用于指定硬链接文件路径,如果 newpath 指定的文件路径已存在,则会产生错误。
返回值: 成功返回 0;失败将返回-1,并且会设置 errno。
4、创建和读取符号链接
在创建符号链接时,并不要求文件已存在。并且文件和软链接不需要位于同一文件系统中。
4.5、symlink()函数
创建软链接文件。
#include <unistd.h>
int symlink(const char *target, const char *linkpath);
参数 target: 用于指定被链接的源文件路径, target 参数指定的也可以是一个软链接文件。
参数 linkpath: 用于指定软链接文件路径。
返回值: 成功返回 0;失败将返回-1,并会设置 errno。
注:创建软链接时,并不要求 target 参数指定的文件路径已经存在,如果文件不存在,那么创建的软链接将成为“悬空链接”。
4.5、symlinkat()函数
如果linkpath参数指定的是绝对路径或者fd参数设置了AT_FDCWD值,那么symlinkat就等于symlink函数。
4.6、readlink()函数
读取出软链接文件中存储的路径信息。
#include <unistd.h>
ssize_t readlink(const char *pathname, char *buf, size_t bufsiz);
参数 pathname: 需要读取的软链接文件路径。 只能是软链接文件路径,不能是其它类型文件,否则调用函数将报错。
参数 buf: 用于存放路径信息的缓冲区。在buf中返回的符号链接的内容不以null字节终止。
参数 bufsiz: 读取大小,一般读取的大小需要大于链接文件数据块中存储的文件路径信息字节大小。
返回值: 失败将返回-1,并会设置 errno;成功将返回读取到的字节数。
4.6、readlinkat()函数
如果pathname参数指定的是绝对路径或者fd参数设置了AT_FDCWD值,那么readlinkat就等于readlink函数。但是fd如果是一个打开目录的有效文件描述符并且pathname参数是相对路径名,则readlinkat计算相对于fd代表的打开目录的路径名。
5、文件与目录
5.1、mkdir()函数
创建目录。
#include <sys/stat.h>
#include <sys/types.h>
int mkdir(const char *pathname, mode_t mode);
参数 pathname:指定的新建目录的路径,该路径名可以是相对路径,也可以是绝对路径,若指定的路径名已经存在,则调用 mkdir()将会失败。
参数 mode: 新建目录的权限设置,设置方式与 open 函数的 mode 参数一样,最终权限为(mode & ~umask)。mode 参数指定了新目录的权限,目录拥有与普通文件相同的权限位,但是其表示的含义与普通文件却有不同。
返回值: 成功返回 0;失败将返回-1,并会设置 errno。
常见的错误是指定与文件相同的mode(只指定读、写权限)。但是,对于目录通常至少要设置一个执行权限位,以允许访问该目录中的文件名。
5.1、mkdirat()函数
mkdirat函数与mkdir函数类似。当fd参数为AT_FDCWD或pathname参数指定了绝对路径名时。mkdirat和mkdir完全一样,否则fd参数是一个打开目录,相对路径名根据此打开目录进行计算。
5.2、rmdir()函数
删除一个目录。如果调用此函数使目录链接计数为0,并且没有其他进程打开此目录,则释放由此目录占用的空间。如果链接计数达到0时,有进程打开此目录,则在此函数返回前删除最后一个链接及.和。。项。另外,在此目录中不能再创建新文件。但是再最后一个进程关闭它之前并不释放此目录。(即使另一些进程打开该目录,它们在此目录下也不能执行其他操作。这样处理的原因是,为了使rmdir函数成功执行,该目录必须是空的)
#include <unistd.h>
int rmdir(const char *pathname);
参数 pathname: 需要删除的目录对应的路径名,并且该目录必须是一个空目录,也就是该目录下只有.和..这两个目录项; pathname 指定的路径名不能是软链接文件,即使该链接文件指向了一个空目录。
返回值: 成功返回 0;失败将返回-1,并会设置 errno。
对某个目录具有访问权限的任一用户都可以读该目录,但是,为了防止文件系统产生混乱,只有内核才能写目录。一个目录的写权限位和执行权限位决定了在该目录中能否创建新文件以及删除文件,它们并不表示能否写目录本身。
opendir执行初始化操作,使第一个readdir返回目录中的第一个目录项。DIR结构由fdopendir创建时,readdir返回的第一项取决于传给fdopendir函数文件描述符相关联的文件偏移量。
注:目录中各目录项的顺序与实现有关。它们通常并不按字母顺序排列。
5.3、opendir()函数
打开一个目录,并返回指向该目录的句柄,供后续操作使用。
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
参数 name: 指定需要打开的目录路径名,可以是绝对路径,也可以是相对路径。
返回值: 成功将返回指向该目录的句柄,后续对该目录的操作需要使用该DIR指针变量;若调用失败,则返回NULL。
5.3、fdopendir()函数
提供了一种方法,可以把打开文件描述符转换成目录处理函数需要的DIR结构。
5.4、readdir()函数
读取目录,获取目录下所有文件的名称以及对应 inode 号。
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
参数 dirp: 目录句柄 DIR 指针。
返回值: 返回一个指向 struct dirent 结构体的指针, 该结构体表示 dirp 指向的目录流中的下一个目录条目。在到达目录流的末尾或发生错误时,它返回 NULL。
struct dirent {
ino_t d_ino; /* inode 编号 */
off_t d_off; /* not an offset; see NOTES */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file; not supported by all filesystem types */
char d_name[256]; /* 文件名 */
};
5.5、rewinddir()函数
可将目录流重置为目录起点, 以便对 readdir()的下一次调用将从目录列表中的第一个文件开始。
#include <sys/types.h>
#include <dirent.h>
void rewinddir(DIR *dirp);
参数 dirp: 目录句柄。
返回值: 无返回值。
5.6、closedir()函数
closedir()函数用于关闭处于打开状态的目录,同时释放它所使用的资源。
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
参数 dirp: 目录句柄。
返回值: 成功返回 0;失败将返回-1,并设置 errno。
5.7、getcwd()函数
读取进程的当前工作目录。
#include <unistd.h>
char *getcwd(char *buf, size_t size);
参数 buf: getcwd()将内含当前工作目录绝对路径的字符串存放在 buf 缓冲区中。
参数 size: 缓冲区的大小,分配的缓冲区大小必须要大于字符串长度,否则调用将会失败。
返回值: 如果调用成功将返回指向 buf 的指针,失败将返回 NULL,并设置 errno。
注:若传入的 buf 为 NULL,且 size 为 0,则 getcwd()内部会按需分配一个缓冲区,并将指向该缓冲区的指针作为函数的返回值,为了避免内存泄漏,调用者使用完之后必须调用 free()来释放这一缓冲区所占内存空间。这不是POSIX.1或Single UNIX Specification的所属部分,应当避免使用。
5.8、chdir()函数
每个进程都有一个当前工作目录,此目录是搜索所有相对路径名的起点。当前工作目录是进程的一个属性,起始目录是登录名的一个属性。
在更换工作目录前,可以调用getcwd函数先将其保存起来。在完成了处理后,就可以将所保存的原工作目录路径名作为调用参数传递给chdir,这样就返回到了文件系统中的出发点。
fchdir函数提供了一种完成此任务的便捷方法。在更换到文件系统中的不同位置前,无需调用getcwd函数,而是使用open打开当前工作目录,然后保存其返回的文件描述符。当希望回到原工作目录时,只要简单地将文件描述符传送给fchdir。
改变当前工作目录。
#include <unistd.h>
int chdir(const char *path);
参数 path: 将进程的当前工作目录更改为 path 参数指定的目录,可以是绝对路径、也可以是相对路径,指定的目录必须要存在,否则会报错。
参数 fd: 将进程的当前工作目录更改为 fd 文件描述符所指定的目录(譬如使用 open 函数打开一个目录)。
返回值: 成功均返回 0;失败均返回-1,并设置 errno。
5.9、fchdir()函数
fchdir()与chdir()区别在于,指定目录的方式不同。 chdir()是以路径的方式进行指定,而 fchdir()则是通过文件描述符,文件描述符可调用 open()打开相应的目录时获得。
#include <unistd.h>
int fchdir(int fd);
参数 fd: 将进程的当前工作目录更改为 fd 文件描述符所指定的目录。
返回值: 成功均返回 0;失败均返回-1,并设置 errno。
5.10、unlink()函数
unlink()用于删除一个文件(不包括目录)
#include <unistd.h>
int unlink(const char *pathname);
参数 pathname: 需要删除的文件路径,可使用相对路径、也可使用绝对路径,如果 pathname 参数指定的文件不存在,则调用 unlink()失败。
返回值: 成功返回 0;失败将返回-1,并设置 errno。
注:unlink()系统调用并不会对软链接进行解引用操作,若 pathname 指定的文件为软链接文件,则删除软链接文件本身,而非软链接所指定的文件。
5.11、remove()函数
用于移除一个文件或空目录。
#include <stdio.h>
int remove(const char *pathname);
参数 pathname: 需要删除的文件或目录路径,可以是相对路径、也可是绝对路径。
注:pathname 参数指定的是一个非目录文件,那么 remove()去调用 unlink(),如果 pathname 参数指定的是一个目录,那么 remove()去调用 rmdir()。
返回值: 成功返回 0;失败将返回-1,并设置 errno。
注:与 unlink()、 rmdir()一样, remove()不对软链接进行解引用操作,若 pathname 参数指定的是一个软链接文件,则 remove()会删除链接文件本身、而非所指向的文件。
5.12、rename()函数
可以对文件进行重命名,也可以将文件移至同一文件系统中的另一个目录下
#include <stdio.h>
int rename(const char *oldpath, const char *newpath);
参数 oldpath: 原文件路径。
参数 newpath: 新文件路径。
返回值: 成功返回 0;失败将返回-1,并设置 errno。
注:rename()系统调用对其两个参数中的软链接均不进行解引用。