1.4: File system
xv6 文件系统
xv6 文件系统提供了两种类型的文件:数据文件和目录。
数据文件:包含未解释的字节数组。
目录:包含指向数据文件和其他目录的命名引用。
目录形成一棵树,起点是一个称为 根目录(/)的特殊目录。例如,路径 /a/b/c 表示在根目录/下的a目录中的 b 目录中的文件或目录 c。
如果路径不以 / 开头,则会相对于调用进程的当前目录进行解析,可以使用 chdir 系统调用更改当前目录。例如,以下两段代码打开同一个文件(假设相关目录均存在):
chdir("/a");
chdir("b");
open("c", O_RDONLY);
open("/a/b/c", O_RDONLY);
第一段代码将当前目录更改为 /a/b。
第二段代码既没有引用也没有更改当前目录。
创建新文件和目录
以下系统调用用于创建新文件和目录:
mkdir:创建新目录。
open(带有 O_CREATE 标志):创建新的数据文件。
mknod:创建新的设备文件。
示例代码:
mkdir("/dir");
fd = open("/dir/file", O_CREATE | O_WRONLY);
close(fd);
mknod("/console", 1, 1);
mknod 创建一个引用设备的特殊文件。
设备文件关联有主设备号和次设备号(mknod 的两个参数),用于唯一标识内核设备。
当进程随后打开设备文件时,内核将read和write系统调用重定向到内核设备的实现,而不是传递给文件系统。
文件名与文件本身
文件的名称与文件本身是分离的。
同一个底层文件(称为
inode
)可以有多个名称(称为链接)。每个链接由目录中的一个条目组成,该条目包含一个文件名和对
inode
的引用。
inode 包含以下元数据:
文件类型(文件、目录或设备)。
文件长度。
文件内容在磁盘上的位置。
文件的链接数量。
fstat 系统调用
fstat
系统调用从文件描述符引用的inode
中检索信息,返回一个struct stat
结构:
如下
#define T_DIR 1 // 目录
#define T_FILE 2 // 文件
#define T_DEVICE 3 // 设备
struct stat {
int dev; // 文件系统的磁盘设备
uint ino; // inode 编号
short type; // 文件类型
short nlink; // 文件链接数量
uint64 size; // 文件大小(字节)
};
文件操作的用户级程序
Unix 提供了可以从 shell 调用的文件操作工具(作为用户级程序),例如:
mkdir:创建目录。
ln:创建链接。
rm:删除文件。 这种设计允许用户通过添加新的用户级程序来扩展命令行接口。虽然在现代看来这是显而易见的,但当时许多系统将这些命令直接集成到 shell 或内核中。
特例:cd 命令
cd 是一个内置于 shell 的命令(见 user/sh.c:161)。
cd 必须更改 shell 本身的当前工作目录。如果 cd 作为常规命令运行,那么 shell 将 fork 一个子进程,子进程运行 cd 并更改其工作目录,但父进程(即 shell)的工作目录不会改变。这使得必须将 cd 实现为内置命令。
见 user/sh.c:161
// Read and run input commands.
while(getcmd(buf, sizeof(buf)) >= 0){
if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){
// Chdir must be called by the parent, not the child.
buf[strlen(buf)-1] = 0; // chop \n
if(chdir(buf+3) < 0)
fprintf(2, "cannot cd %s\n", buf+3);
continue;
}
以下是对代码的解析
while(getcmd(buf, sizeof(buf)) >= 0){
getcmd(buf, sizeof(buf)):从用户输入中读取命令,并将其存储到 buf 中。
如果读取成功(返回值 >= 0),进入循环处理命令
if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){
检查是否为 cd 命令
buf[strlen(buf)-1] = 0; // chop \n
处理换行符
用户输入通常以换行符 (\n) 结尾。
这行代码将换行符替换为字符串结束符 \0,清理用户输入。
if(chdir(buf+3) < 0)
fprintf(2, "cannot cd %s\n", buf+3);
chdir(buf+3):
buf+3 是跳过 "cd " 的部分,即用户输入的路径参数。
调用 chdir 系统调用尝试将工作目录更改为 buf+3 指定的路径。 错误处理:
如果 chdir 返回值小于 0,说明目录更改失败。
使用 fprintf输出错误消息到文件描述符2(标准错误输出),告知用户无法进入指定目录。