第四章 文件和目录
#include <sys/stat.h>
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);
stat函数返回pathname文件有关的信息结构,lstat返回符号链接有关信息,而不是符号链接应用的文件
Unix中一切皆为对象,文件信息结构如下:
struct stat
{
mode_t st_mode;//文件类型,模式字
ino_t st_ino;//i节点号
dev_t st_dev;//设备号(文件系统)
dev_t st_rdev;//特殊文件设备号,SUS XSI扩展
nlink_t st_nlink;//i节点连接计数,硬链接
uid_t st_uid;//文件所有者ID
gid_t st_gid;//文件组所有者ID
off_t st_size;//文件大小(字节)
time_t st_atime;//最后访问时间
time_t st_mtime;//最后修改时间
time_t st_ctime;//文件状态最后访问时间
time_t st_blksize;//SUS XSI扩展
time_t st_blocks;//SUS XSI扩展
}
文件类型:ls命令 测试宏;POSIX.1允许将IPC对象(如消息队列,信号量)表示为文件,但是Linux,FreeBSD,Solaris,MacOS都不将这些对象表示为文件。
1)普通文件 - S_ISREG(stat.st_mode)
2)目录文件 d S_ISDIR()
3)块文件 b S_ISCHR() 这种文件提供对设备(如磁盘)带缓冲的访问,每次访问以固定长度为单位进行。
4)字符文件 c S_ISBLK() 提供对设备不带缓冲的访问,访问长度可变。
5)FIFO f S_ISFIFO() 命名管道(named pipe),用于IPC
6)套接字 s S_ISSOCK()
7)符号链接 l S_ISLNK()
重要问题(用户和组)
弄清楚的概念,
与进程相关联的ID
1) 实际用户ID 登录时取自口令文件/etc/passwd
2)实际组ID 登录时取自口令文件/etc/passwd
3)有效用户ID
4)有效组ID
5)附加组ID
6)保存的设置用户ID 在执行程序是包含了有效用户ID和有效组ID的副本,setuid函数
7)保存的设置组ID
通常有效用户ID等于实际用户ID,有效组ID等于实际组ID。但是当执行一个文件程序(可执行文件)时,文件模式自的两位:设置用户ID位, 设置组ID位。当他们设置时,其含义是,当执行此文件时,将进程的有效用户ID(有效组ID)设置为文件所有者的用户ID(组ID)。 运行设置用户ID程序的进程通常得到额外的权限。
文件访问权限(九位)
文件所有者owner/user 文件所有者所在的组成员group 其他成员other
owner:S_IRUSR S_IWUSR S_IXUSR
group:S_IRGRP S_IWGRP S_IXGRP
other:S_IROTH S_IWOTH S_IXOTH
目录的执行权限位常被称为搜索位:要打开文件a,则包含a的目录用户都必须具有可执行权限。
目录的读权限和执行权限.
注意:
打开文件权限位(O_RDONLY,O_WRONLY,O_RDWR)
对文件指定O_TRUNC标志,文件必须具有写权限
在目录中创建文件,该目录必须具有写权限和执行权限
使用open或creat创建新文件时,新文件的用户ID为进程的有效用户ID;新文件的组ID可以是进程的有效组ID,可以使他所在目录的组ID。
当open打开文件时,内核以进程的有效用户ID和有效组ID为基础执行其访问权限测试。
#include <unistd.h>
int access(const char *pathname, int mode);//按照实际用户ID和实际组ID进行访问权限测试。
mode的值:
R_OK:测试读权限
W_OK:测试写权限
X_OK:测试执行权限
F_OK:测试文件是否存在
#include <sys/stat.h>
mode_t umask(mode_t cmask);--设置文件模式创建屏蔽字,返回以前的值,无出错返回
文件模式创建屏蔽字,与每个进程相关联。cmask是9个常量的按位或。
文件模式创建屏蔽字为1的位,文件的mode相应位关闭。
#include <sys/stat.h>
int chmod(const char *pathname, mode_t mode);//更改现有文件的访问权限
int fchmod(int fd, mode_t mode);
mode_t的位(除了文件访问权限位9位,以外还有六位)
S_IRWXU 用户读写执行
S_IRWXG 组读写执行
S_IRRWXO 其它读写执行
S_ISUID 执行时设置用户ID
S_ISGID 执行时设置组ID
S_ISVTX 保存正文(站住位)
/* 改变文件的用户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 lchown(const char *pathname, uid_t owner, gid_t group);
/* 文件截短,将文件截断为length */
#include <unistd.h>
int truncate(const char *pathname, off_t length);
int truncate(int fd, off_t length);
文件空洞,由所设置的偏移量超过文件尾端,并写了某些数据后造成的。du命令,查看文件占用的磁盘块数。
下面是个重要问题!——文件系统
Unix文件系统(Unix file system),BSD快速文件系统
磁盘0号扇区称为主引导记录(Master Boot Record,MBR),MBR的结尾是分区表(给出每个分区的起始地址和结束地址)。 表中的一个分区被标记为活动分区。计算机被引导时,BIOS读入并执行MBR,MBR确定活动分区,读入其第一个块,称为引 导块并执行。引导块中的程序将装载该分区的操作系统,保留引导块,可以保证以后可以安装操作系统。
超级块,保存文件系统重要参数。
文件系统空闲块,位图形式或指针列表
分区(引导块,超级块,文件系统空闲块,其它)
一个磁盘分成几个分区,每个分区包含一个文件系统。文件系统格式:
自举块(引导块) 超级块 柱面组0 柱面组1 ... 柱面组n
i节点,包含了大多数与文件有关的信息:文件类型,文件访问权限位,文件长度,指向该文件所占用的数据块的指针。 目录项,存放文件名和i节点编号。
每个文件系统对它们的i节点进行编号,目录项中的i节点指向同一文件系统中相应的i节点,不能使一个目录项指向另一个文件系统的i节点。
ln命令不能跨越文件系统。
普通文件链接计数和目录文件的链接计数
mkdir test
当前目录 . 链接计数2 任何一个页目录(不含任何子目录和文件的目录)的链接计数总是2 test/. ; test/..
上级目录 .. 链接计数3 不解释 ../. ; ../.. ; ../test
创建指向现有文件的链接(硬链接)
#include <unistd.h>
int link(const char *path, const char *newpath);
int unlink(const char *pathname);//删除一个现有的目录项
int remove(const char *pathname);//对文件unlink,对于目录与rmdir
POSIX.1 允许实现支持跨文件系统的链接,但是多实现要求六个路径名在同一文件系统中。
如果实现支持创建指向一个目录的硬链接,也仅限于root用户。理由是可能在文件系统中形成循环,而大多数处理文件系统的
程序都不能处理这种情况,很多文件系统实现不允许目录硬链接。
为了避开硬链接的限制,引入符号链接。(文件系统限制,目录限制)
每个文件保持有时间
st_atime:文件数据的最后访问时间
st_mtime:文件数据的最后修改时间
st_ctime:i节点状态的最后更改状态
i节点状态(文件的访问权限,用户ID,链接数)
#include <utime.h>
int utime(const char *pathname, const struct utimbuf *times);//改变一个文件的访问和修改时间
struct utimbuf
{
time_t actime;//访问时间
time_t modtime;//修改时间
}