stat,fstat,fstatat,lstat
#include
int stat(const char *restrict pathname,struct stat *restrict buf);//文件有关信息
int fstat(int fd,struct stat *buf);//获取文件有关信息
int lstat(const char *restrict pathname,struct stat *restrict buf);//link有关信息,比stat多检测link文件
int fstatat(int fd,const char *restrict pathname,struct stat *restrict buf,int flag);//
struct stat{
mode_t st_mode;i节点 中文件访问权限
ino_t st_ino;目录项中 i节点编号
dev_t st_dev;
dev_t st_rdev;
nlink_t st_nlink;有链接计数
uid_t st_uid;
gid_t st_gid;
off_t st_size;
struct timespec st_atime;
struct timespec st_mtime;
struct timespec st_ctime;
blksize_t st_blksize;
blkcnt_t st_blocks;
}
struct timespec{
time_t tv_sec;
long tv_nsec;
...
}
//附一份macos 10.13.4
truct stat {
dev_t st_dev; /* [XSI] ID of device containing file */
ino_t st_ino; /* [XSI] File serial number */
mode_t st_mode; /* [XSI] Mode of file (see below) */
nlink_t st_nlink; /* [XSI] Number of hard links */
uid_t st_uid; /* [XSI] User ID of the file */
gid_t st_gid; /* [XSI] Group ID of the file */
dev_t st_rdev; /* [XSI] Device ID */
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
struct timespec st_atimespec; /* time of last access */
struct timespec st_mtimespec; /* time of last data modification */
struct timespec st_ctimespec; /* time of last status change */
#else
time_t st_atime; /* [XSI] Time of last access */
long st_atimensec; /* nsec of last access */
time_t st_mtime; /* [XSI] Last data modification time */
long st_mtimensec; /* last data modification nsec */
time_t st_ctime; /* [XSI] Time of last status change */
long st_ctimensec; /* nsec of last status change */
#endif
off_t st_size; /* [XSI] file size, in bytes */
blkcnt_t st_blocks; /* [XSI] blocks allocated for file */
blksize_t st_blksize; /* [XSI] optimal blocksize for I/O */
__uint32_t st_flags; /* user defined flags for file */
__uint32_t st_gen; /* file generation number */
__int32_t st_lspare; /* RESERVED: DO NOT USE! */
__int64_t st_qspare[2]; /* RESERVED: DO NOT USE! */
};
文件类型
- 普通文件
- 目录文件
- 块特殊文件 FreeBSD不再支持
- 字符特殊文件
- FIFO 命令管道,用于进程间通信,第十五章会说明
- 套接字 socket,用于进程间的网络通信
- 符号链接
文件类型信息包含在stat结构的st_mode成员中,上面有定义
//文件类型宏 st_mode 对应上面七种文件
S_ISREG()
S_ISDIR()
S_ISBLK()
S_ISCHR()
S_ISFIFO()
S_ISSOCK()
S_ISLNK()
//POSIX.1 允许实现将IPC对象说明为文件,但是有四种unix系统不将这些对象表示为文件,蛋疼,标准不遵守
S_TYPEISMQ() 消息队列
S_TYPEISSEM() 信号量
S_TYPEISSHM() 共享存储对象
设置用户ID和设置组ID
一个进程关联的ID有6种
实际用户id,组id就是有效用户id,组id
执行一个程序文件的时候,如果该文件设置了下面的S_ISUID权限,那么进程执行这个文件的时候就会将进程有效用户id设置成文件所有者用户id,类似S_ISGID,下面有chmod的条件二的特例
s权限位
典型场景,普通用户可以修改密码,而密码记录文件/etc/passwd和/etc/shadow普通用户都是无法修改的,没有权限,但是passwd命令的权限是-rwsr-xr-x,这就以为着,普通用户使用这个命令时,在执行的进程中,实际就以属主root身份执行,当然前提是要有相应的执行权限x
安全问题,第八章讨论
文件访问权限
st_mode 值包含了这些权限。
用户(拥有者)读写执行,同组读写执行,其他组读写执行
0400 0200 0100 0040 0020 0010 0004 0002 0001
S_IRUSR S_IWUSR S_IXUSR S_IRGRP S_IWGRP S_IXGRP S_IROTH S_IWOTH S_IXOTH
进程中操作文件,其实开这个进程的实际用户id,组id就是进程的有效用户id,组id
- 打开一个文件就拥有了上目录的执行权限,对目录执行权限位被称为搜索位。这就是为什么对于目录其执行权限位常被称为搜索位的原因。
- 读权限
- 写权限
- open中指定O_TRUNC,必须要有写权限
- 创建新文件,必须要有当前目录的写和执行权限
- 删除文件,必须要有当前目录的写和执行权限,对该文件本身不需要读、写权限,如果设置t权限那么要检测是否是文件或者目录拥有者或者root
- 7个exec函数任何执行某个文件,都需要具有该文件的执行权限,而且必须是普通文件
新文件和目录的所有权
新文件和新目录所有权规则相同
用户ID为进程有效用户ID;组ID实现两种:进程有效组ID,所在目录的组ID
#include
int access(const char *pathname,int mode);
int faccessat(int fd,const char *pathname,int mode,int flag);//成功0
mode 值
R_OK W_OK X_OK
umask
#include
mode_t umask(mode_t cmask);//返回值是之前文件模式创建屏蔽字,少数几个没有出错返回
作用就是无法设置权限
常用002(其他用户写),022(),027()
2018-4-10 23:31
chmod,fchmod,fchmodat
#include
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);
改文件权限必须是拥有者或者超管
mode:上面9中再加下面六种
组合权限:S_IRWXU S_IRWXG S_IRWXO
特殊权限三种:
s权限:S_ISUID(执行时设置用户ID) S_ISGID(执行时设置组ID)
t权限:粘着位,S_ISVTX(保存正文saved-text) ,现在只针对目录,删除文件的权限
chmod("file",(buf.st_mode & ~S_IXGRP) | S_ISGID)
s权限配合执行权限(用户和组必须设置x权限)可以以root身份权限执行
vtx权限也就是t权限:给目录和文件设置t权限是完全不同目的,目录拥有t权限,那么目录下的文件只有该目录拥有者或者文件拥有者和root才能删除和更名
chmod 会自动清除两个权限位的条件
- 一些unix系统,不允许除root用户以外的用户设置文件S_ISVTX,防止用户恶意设置,影响系统性能(linux系统没有这种限制)
- 新文件的组ID不等于进程有效组ID,而且没有root权限,那么设置组ID会被关闭
chown,fchown,fchownat,lchown
#include
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 char *pathname,uid_t owner,gid_t group);
AT_FDCWD 相对path = 绝对path 很多函数用到
基于BSD系统规定只有root用户可以更改一个文件的所有者
System V 则允许任一用户更改他们所拥有文件的所有者
文件长度
st_size
st_blksize
st_blocks
文件空洞
原因是偏移量超过文件尾端,并写入数据造成的
文件截断
第三章open函数第二个参数中有个O_TRUNC
#include
int truncate(const char *pathname,off_t length);
int ftruncate(int fd,off_t length);
文件系统
solaris支持多种不同类型的磁盘文件系统
基于传统bsd的ufs,读写dos的pcfs,cd的hsfs
macos大小写不敏感
2018-4-12 23:55
文件系统的构成,下面
- 磁盘:各个分区
- 文件系统:自举块,超级块,柱面0...
- 柱面:超级块的副本,配置信息,i节点图,块位图,i节点,数据块
- i节点:各个i节点...
目录和文件块:i节点数组,数据块,目录块
目录块(项)中有文件名,i节点编号(数据类型是ino_t),其中i节点指向数据块
每个i节点有个链接计数,就是指向该节点的目录项数,只有减少至0,才可以删除文件,就是解除对一个文件的链接并不是释放该文件占用的磁盘块,就是删除一个目录项是unlink而不是delete
这个链接计数在stat结构中是st_nlink的成员,其基本系统数据类型是nlink_t,这是硬链接,这个计数初始文件1,叶目录2(本身+./),创建一个硬链接就+1,无法给目录创建或者条件很苛刻
-
软链接S_IFLINK,符号链接symbolic link,它的实际类容:在数据块中包含了该符号链接指向的文件名字,比如
ls lib lib -> usr/lib 实际类容就是 usr/lib 这7个字节
i节点,stat大多信息来自i节点:文件类型、文件访问权限、文件长度、指向文件数据块的指针
目录项,一个目录项不能指向另一个文件系统
link,linkat,unlink,unlinkat,remove
#include
int link(const char *existingpath,const char *newpath);
int linkat(int efd,const char *existingpath,int nfd,const char *newpath,int flag);
创建新目录项和添加链接计数是一个原子操作
#include
int unlink(const char *existingpath,const char *newpath);
int unlinkat(int fd,const char *pathname,int flag);
#include
int remove(const char *pathname)
rename,renameat
#include
int rename(const char *oldname,const char *newname);
int renameat(int oldfd,const char *oldname,int newfd,const char *newname);
符号链接
符号链接是一个文件的间接指针,硬链接直接指向文件的i节点
引入符号链接是因为劈开硬链接的一些限制
- 不要求链接和文件位于同一个文件系统中
- root才能创建(底层文件系统支持的情况下,因为很多还是不支持,mac和linux)
必须考虑函数是否可以处理符号链接
Mkdir,mkinfo,mknod,rmdir
避免子目录指向父目录造成死循环,而且软链接可以unlink,但是硬链接很难消除,这就是为什么硬链接有限制
创建和读取符号链接
#include
int symlink(const char *actualpath,const char *sympath);
int symlinkat(const char *actualpath,int fd,const char *sympath);
//open函数跟随符号链接,所有下面方法可以打开链接本身
ssize_t readlink(const char* restrict pathname,char* restrict buf,size_t bufsize);
ssize_t readlinkat(int fd,cosnt char* restrict pathname,char* restrict buf,size_t bufsize);
两个函数组合了open、read、close的所有操作
文件的时间
每个文件会维护三个时间
ls命令选项 | |||
---|---|---|---|
st_atime | 最后访问时间-文件内容 | read | -u |
st_mtime | 最后修改时间-文件内容 | write | 默认 |
st_ctime | i节点最后更改时间 | chown,chmod | -c |
i节点所有信息都是与文件的实际内容分开存放的
st_ctime 系统不会维护,没有函数可以去自定义修改这个
access、stat函数并不更改这3个时间中的任何一个
ps 创建一个新文件影响到包含次新文件的目录,页影响该文件的i节点,但是读或写只影响该文件的i节点
futimens,utimensat,utimes
POSIX.1中
#include
int futimens(int fd,const struct timespec times[2]);
int utimensat(int fd,const char *path,const struct timespec times[2],int flag);
tv_nsec 字段:UTIME_NOW,UTIME_OMIT
times[2]:第一个包含访问时间st_atime,第二个包含修改时间st_mtime
Single UNIX Specification的XSI扩展中
#include
int utimes(const char *pathname,const struct timeval times[2]);
struct timeval{
time_t tv_sec;//s
long tv_usec;//ms
}
场景:touch命令使用这些函数的某一个,tar和cpio也会可选地调用这些函数
Ps: macos中有些问题
mkdir,mkdirat,rmdir
#include
int mkdir(const char *pathname,mode_t mode);
int mkdirat(int fd,const char *pathname,mode_t mode);
对应目录来说,通常至少要设置一个x权限位,允许访问该目录中的文件名
#include
int rmdir(const char *pathname);
读目录
一个目录的w和x权限决定能否在目录下new和del文件(当然前提是该目录的t权限位没有设置),但是这并不代表能否写目录本身
#include
DIR *opendir(const char *pathname);//success:返回指针 fail:返回NULL
DIR *fdopendir(int fd);//success:返回指针 fail:返回NULL
以上两个函数返回的指针由下面5个函数使用
struct dirent *readdir(DIR *dp);//success:返回指针 fail:返回NULL。返回下一个目录的指针
void rewinddir(DIR *dp);//将偏移量放在最开始
int closedir(DIR *dp);//关闭目录
long telldir(DIR *dp);//返回值与dp关联的目录中的当前位置。查询偏移量
void seekdir(DIR *dp,long loc);//设置偏移量
DIR是一个内部结构
fig4.22实现了遍历目录
chdir,fchdir,getcwd
chdir,fchdir可以更改当前工作目录
#include
int chdir(const char *pathname);
int fchdir(int fd);
#include
char *getcwd(char *buf,size_t size);//success:返回buf,fail:返回NULL
设备特殊文件
st_dev,st_rdev
小结
S_ISUID S_ISGID
设置用户ID 设置组 ID
执行时设置有效用户 ID
若组执行位设置,则执行时设置有效 组 ID;否则使强制性锁起作用(若支持)
(未使用)
将在目录中创建的新文件的组 ID 设置为目录的组 ID
S_ISVTX
粘着位
在交换区缓存程序正文(若支持)
限止在目录中删除和重命名文件
S_IRUSR S_IWUSR S_IXUSR
用户读 用户写 用户执行
许可用户读文件
许可用户写文件
许可用户执行文件
许可用户读目录项 许可用户在目录中删除和创建文件 许可用户在目录中搜索给定路径名
S_IRGRP S_IWGRP S_IXGRP
组读 组写 组执行
许可组读文件
许可组写文件
许可组执行文件
许可组读目录项
许可组在目录中删除和创建文件
许可组在目录中搜索给定路径名
S_IROTH S_IWOTH S_IXOTH
其他读 其他写 其他执行
许可其他读文件
许可其他写文件
许可其他执行文件
许可其他读目录项 许可其他在目录中删除和创建文件 许可其他在目录中搜索给定路径名