struct stat
{
mode_t st_mode; //file type & mode
ino_t st_ino; //inode number
nlink_t st_nlink: //number of hard links
uid_t st_uid; //user ID of owner
gid_t st_gid; //group ID of owner
time_t st_atime; //time of last access
time_t st_mtime; //time of last modification
time_t st_ctime; //time of last file status change
blkcnt_t st_blocks; //number of disk blocks allocated
dev_t st_dev; //device number(file system)
dev_t st_rdev: //device number for special files
};
st_mode中file type表示文件的属性,例如是否是目录,是否是普通文件的等等。
而mode包含文件的权限,如所有者权限,所属群组权限,其他人的权限。
注意:
一定要记住,一个文件最重要的几条
1)三个函数
#include <sys/stat.h>
int stat(const char *restrict pathname,
struct stat *restrict buf);
int fstat(int filedes, struct stat *buf);
int lstat(const char *restrict pathname,
struct stat *restrict buf);
注意lstat与stat的区别在于lstat可以读到链接文件的信息,而stat会读取链接文件链接到的文件的信息。
1)文件类型及他们相关的测试宏,用法S_ISREG(mode),mode是st_mode类型。
1.普通文件:S_ISREG()
2.目录文件:S_ISDIR()
3.块特殊文件:S_ISCHR()
4.字符特殊文件:S_ISBLK()
5.FIFO:S_ISFIFO()
6.套接字:S_ISSOCK()
7.符号链接:S_ISLNK()
2)测试宏原理
例如:S_ISDIR()
#define S_ISDIR(mode) (((mode & S_IFMT) == S_IFDIR)
例如对于 /usr/include/stdio.h的打开,首先我们要有/、/usr、/usr/include的执行权限,然后还要有对stdio.h文件的适当权限才可以打开。
新文件的用户ID是进程的有效用户ID
新文件的组ID可以是进程的有效组ID,也可以是所在目录的组ID
当在一个进程中创建一个文件时,文件的user ID即所有者是这个进程的euid。而该文件的group ID,则有两种情况:
1.为这个进程的egid
2.这个文件必定创建在一个目录下,那么可以设置该文件的gID为这个目录的gID。这种作法必须设置目录的第六个权限为s,即该目录必须设置set gid。注意的是:这里指的是目录的群组gID,而不是目录的所有者。
用于判断当前进程的ruid是否有权限接触文件
int access(const char *pathname, int mode);
mode取值:
R_OK:read permission
W_OK:write permission
X_OK:execute permission
注意点:
需要注意的是如果二进制文件设置了set uid时,一个进程对于这个文件的access permission就有一点不同了。因为一个二进制文件设置了set uid,那么我们执行了这个文件之后,我们自己的euid就是这个文件的所有者的ID了。切记,切记。
说明:
unlink从目录中删除该项,并把文件的inode count减一
int unlink(const char *pathname);
/* 成功返回0,失败返回-1 */
注意点:
如果一个文件的inode的计数为0,这个文件就会被删除。
需要注意的是:如果在一个进程中打开了这个文件,这个文件就不会被删除。所以当一个文件被关闭了,内核会先去检查是否还有进程打开了这个文件,如果没有再去检查这个link count,此时如果为0,则文件被删除。
unlink的用法:一般用于临时文件
如果一个进程创建了一个文件,然后crash了,那么它创建的文件还会留着。但是如果用了unlink,即在创建一个文件之后马上unlink,这时虽然逻辑上删除了这个文件,但是这个文件依然是被这个进程打开的,除非这个进程调用close或者死亡了。这样这个进程依然可以处理这个文件。然后进程退出时,内核自动删除这个文件。
一般用于进程临时创建的文件,避免进程crash之后留下了许多临时文件。
int rename(const char *oldname, const char *newname);
注意点:
对于oldname如果是一个普通文件,那么newname如果不存在就没事,如果存在那么就可以是目录,如果存在且不是目录,就会去删除newname
如果oldname是一个目录,那么newname不存在且不是oldname的后缀就没事,如果newname存在那么newname必须是一个空目录,执行rename时会删除这个目录。
如果oldname或newname是一个link文件,那么就会代表他们link的对象。
如果oldname == newname就没什么事发生,只是返回0
sszie_t readlink(const char *restrict pathname,
char *restrict buf,
size_t bufsize);
pathname指向一个符号链接文件,把这个符号链接中的内容读到buf中。成功返回读到的个数,失败返回-1。
一个文件一般有3种时间:
access time
modify time:the time when the contents of the file were last modified
change status time:the time when the inode of the file were last modified
#include <sys/stat.h> mode_t umask(mode_t cmask);
九个访问权限:
cmask是这9个权限的位操作的结果。umask返回的是以前的屏蔽字。
注意点:
umask会设置当前的默认权限,并且返回以前的权限,对应文件中的9个权限。
需要注意的是,在没有umask时,即umask为0时:
普通文件的权限是666
目录文件的权限是777
有umask时,会再进行对应的减法操作,如umask=022,
那么创建一个普通文件:他的权限是666-022=644
创建一个目录文件:他的权限是777-022=755
#include <dirent.h>
DIR *opendir(const char *pathname);
struct dirent *readdir(DIR *dp);
void rewinddir(DIR *dp);
int closedir(DIR *dp);
说明:
1. DIR 类似于FILE。
2. readdir用于读取目录文件中的类容,执行过程类似于getline函数,readdir返回的是一个dirent类型。
3. rewinddir:把dp的偏移重新设置到目录文件的开始处。
struct dirent一般结构
struct dirent
{
ino_t d_ino; //inode number
char d_name[NAME_MAX + 1]; //null terminated filename
};
注意点:
d_name里面存的base name,即文件名,而不是绝对路径。
获取当前绝对路径
char *getcwd(char *buf, size_t size);
成功返回buf,失败返回-1
注意buf必须足够大,还有字符\0也要存。