1. 简介
存储在文件系统中的每一个文件,它们都有自己的文件类型,所有者,访问权限,链接数、大小等属性。本章函数可以对文件或目录的属性进行访问和修改,对于更多的细节,可以查看相关函数的man手册。
2. 函数原型
1. int stat(const char *pathname, struct stat *statbuf); 4. int fstatat(int dirfd, const char *pathname, struct stat *statbuf, int flags); | 返回文件(目录)的属性: (1)lstat返回符号链接本身的信息,而不是符号链接引用的文件信息。 (2)fstatatf以打开目录的文件描述符dirfd为起始目录,返回相对路径pathname的文件信息,如果pathname是绝对路径,则忽略dirfd。flags指定是否跟随符号链接。 4个函数返回值:若成功,返回0;若出错,返回-1 |
1. int access(const char *pathname, int mode) 2. int faccessat(int fd, const char *pathname, int mode, int flag) | 测试文件的访问权限,mode参数: F_OK:测试文件是否存在 R_OK:测试读权限 W_OK:测试写权限 X_OK:测试执行权限 若flag=AT_EACCESS,则访问检测用的是有效用户ID和有效组ID,而不是实际用户ID和实际组ID 2个函数返回值:若成功,返回0;若出错,返回-1 |
mode_t umask(mode_t cmask) | 设置文件模式创建屏蔽字 返回值:返回之前的文件模式创建屏蔽字 |
1. int chmod(const char *pathname, mode_t mode) 2. int fchmod(int fd, mode_t mode) 3. int fchmodat(int fd, const char *pathname, mode_t mode, int flag) | 3个函数改变现有文件的访问权限: 若flag=AT_SYMLINK_NOFOLLOW,fchmodat不跟随符号链接 3个函数返回值:若成功,返回0;若出错,返回-1 |
1. int chown(const char *pathanme, uid_t owner, gid_t group) 2. int fchown(int fd, uid_t owner, gid_t group) 3. int fchownat(int fd, const char *pathanme, uid_t owner, gid_t group, int flag) 4. int lchown(const char *pathanme, uid_t owner, gid_t group) | 4个函数更改文件的用户ID和组ID,若owner或group中任一个是-1,则对应ID不变。当pathname为相对路径时,若fchownat函数flag=AT_SYMLINK_NOFOLLOW,则与lchown作用一样,只修改符号链接本身,而不是符号链接引用的文件。 4个函数返回值:若成功,返回0;若出错,返回-1 |
1. int truncate(const char *pathname, off_t lenth) 2. int ftruncate(const char *pathname, off_t lenth) | 截断文件长度 2个函数返回值:若成功,返回0;若出错,返回-1 |
1. int link(const char *existingpath, const char *newpath) 2. int linkat(int efd, const char *existingpath, int nfd, const char *newpath, int flag) | 建立文件硬链接,不允许对目录建立硬链接 2个函数返回值:若成功,返回0;若出错,返回-1 |
1. int ulink(const char *pathname) 2. int ulinkat(int fd, const char *pathname, int flag) | 解除文件链接,当链接计数为0时,文件内容被删除,另一个条件是当进程打开了一个文件,即使该文件链接计数为0,也不能删除其内容。当flag=AT_REMOVEDIR时,可删除目录。 2个函数返回值:若成功,返回0;若出错,返回-1 |
int remove(const char *pathname) | 解除对文件或目录的链接 返回值:若成功,返回0;若出错,返回-1 |
1. int rename(const char *oldname, const char *newname) 2. int renameat(int oldfd, const char *oldname, int newfd, const char *newname) | 重命名文件或目录 2个函数返回值:若成功,返回0;若出错,返回-1 |
1. int symlink(const char *actualpath, const char *sympath) 2. int symlinkat(const char *actualpath, int fd, const char *sympath) | 创建一个符号链接 2个函数返回值:若成功,返回0;若出错,返回-1 |
1. ssize_t readlink(const char *restrict pathname, char *restrict buf, size_t bufsize) 2. ssize_t readlink(int fd, const char *restrict pathname, char *restrict buf, size_t bufsize) | 读取符号链接文件本身的内容 2个函数返回值:若成功,返回读取的字节数;若出错,返回-1 |
1. int futimens(int fd, const struct timespec times[2]) 2. int utimensat(int fd, const char *path, const struct timespec times[2], int flag) 3. int utimes( const struct timeval times[2]) | 更改文件的访问和修改时间 3个函数返回值:若成功,返回读取的字节数;若出错,返回-1 |
1. int mkdir(const char *pathname, mode_t mod) 2. int mkdirat(int fd, const char *pathname, mode_t mod) | 创建一个目录 2个函数返回值:若成功,返回0;若出错,返回-1 |
int rmdir(const char *pathname) | 删除一个空目录 返回值:若成功,返回0;若出错,返回-1 |
DIR *opendir(const char *pathname) DIR *fdopendir(int fd) | 打开目录 2个函数返回值:若成功,返回指针;若出错,返回NULL |
struct dirent *readdir(DIR *dp) | 读取一个目录项 返回值:若成功,返回指针;若出错,返回NULL |
void rewinddir(DIR *dp) | 将目录项的位置重置为开始 |
int closedir(DIR *dp) | 关闭目录 返回值:若成功,返回指针;若出错,返回-1 |
long telldir(DIR *dp) | 返回值:若成功,返回与dp关联的目录中的当前位置;若出错,返回-1 |
void seekdir(DIR *dp, long loc) | 设置目录流的位置 |
1. int chdir(const char *name) 2. int fchdir(int fd) | 更改当前工作目录 2个函数返回值:若成功,返回0;若出错,返回-1 |
char *getcwd(char *buf, size_t size) | 返回调用进程当前工作目录 返回值:若成功,返回buf;若出错,返回NULL |
3.实例
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#define TESET_ACCESS(mode, bit) do { \
if ((mode)&bit) { \
printf( #bit " is ok\n"); \
} else { \
printf( #bit " is not\n"); \
} \
} while (0)
void printf_stat(const char *file, const struct stat *buf)
{
printf("file %s stat: \n", file);
/* // man 7 inode
S_ISREG(m) is it a regular file?
S_ISDIR(m) directory?
S_ISCHR(m) character device?
S_ISBLK(m) block device?
S_ISFIFO(m) FIFO (named pipe)?
S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.)
S_ISSOCK(m) socket? (Not in POSIX.1-1996.)
S_ISUID 04000 set-user-ID bit (see execve(2))
S_ISGID 02000 set-group-ID bit (see below)
S_ISVTX 01000 sticky bit (see below)
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
*/
switch (buf->st_mode & S_IFMT) {
case S_IFBLK:
printf("block device\n");
break;
case S_IFCHR:
printf("character device\n");
break;
case S_IFDIR:
printf("directory\n");
break;
case S_IFIFO:
printf("FIFO/pipe\n");
break;
case S_IFLNK:
printf("symlink\n");
break;
case S_IFREG:
printf("regular file\n");
break;
case S_IFSOCK:
printf("socket\n");
break;
default:
printf("unknown?\n");
break;
}
TESET_ACCESS(buf->st_mode, S_IRUSR);
TESET_ACCESS(buf->st_mode, S_IWUSR);
TESET_ACCESS(buf->st_mode, S_IXUSR);
TESET_ACCESS(buf->st_mode, S_IRGRP);
TESET_ACCESS(buf->st_mode, S_IWGRP);
TESET_ACCESS(buf->st_mode, S_IXGRP);
TESET_ACCESS(buf->st_mode, S_IROTH);
TESET_ACCESS(buf->st_mode, S_IWOTH);
TESET_ACCESS(buf->st_mode, S_IXOTH);
printf("uid: %d, gid: %d\n", buf->st_uid, buf->st_gid);
printf("size: %ld\n", buf->st_size);
printf("links: %ld\n", buf->st_nlink);
}
int main()
{
int fd = open("t.txt", O_RDWR|O_CREAT|O_APPEND|O_SYNC/*|O_EXCL*/, (S_IRUSR|S_IWUSR)|(S_IRGRP|S_IWGRP)|(S_IROTH));
if (fd < 0) {
perror("open error");
}
struct stat buf = {0};
if (stat("t.txt", &buf) < 0) {
perror("stat error");
}
printf_stat("stat", &buf);
memset(&buf, 0, sizeof(buf));
if (fstat(fd, &buf) < 0) {
perror("fstat error");
}
printf_stat("fstat", &buf);
int fddir = open("..", O_RDONLY|O_DIRECTORY); // Need to create capter4 directory
if (fddir > 0) {
memset(&buf, 0, sizeof(buf));
// if (fstatat(fd, "capter4/t.txt", &buf, AT_SYMLINK_NOFOLLOW) < 0) {
if (fstatat(fddir, "capter4/t.txt", &buf, AT_SYMLINK_NOFOLLOW) < 0) {
perror("fstatat error");
}
printf_stat("fstatat", &buf);
}
//if (access("t.txt", R_OK|W_OK|X_OK) < 0) {
if (access("t.txt", R_OK|W_OK) < 0) {
printf("Access test fail.\n");
}
mode_t mode = umask(S_IXUSR|S_IXGRP|S_IXOTH);
printf("mode = %04x\n", mode);
int fd2 = open("t2.txt", O_RDWR|O_CREAT|O_APPEND, (S_IRWXU)|(S_IRWXG)|(S_IRWXO)); // t2.txt: 0666
close(fd2);
if (link("../capter4", "t2.txt.link") < 0) {
//if (link("t2.txt", "t2.txt.link") < 0) {
perror("link error");
}
return 0;
}
4. 小结
1. 理解文件访问权限和访问模式,了解文件和目录的所有属性
2. 理解用户ID和组ID,包括实际、有效和设置用户ID和组ID
3. 理解文件系统的结构,硬链接和符号链接的区别
3. 掌握文件和目录的创建和删除相关函数,包括相似函数的参数用法及区别(比如函数xx,相似函数fxx、fdxx、xxat、fxxat)