--------------------------------------------------------
文件系统读写接口
--------------------------------------------------------
这节我们接着为文件系统添加读写接口!
·TestA 函数
void TestA()
{
int fd;
int n;
const char filename[] = "blah";
const char bufw[] = "Hello World!!";
const int rd_bytes = strlen(bufw);
char bufr[rd_bytes + 1];
assert(rd_bytes <= strlen(bufw));
/* create */
fd = open(filename, O_CREAT | O_RDWR);
assert(fd != -1);
printf("File created. fd: %d\n", fd);
/* write */
n = write(fd, bufw, strlen(bufw));
assert(n == strlen(bufw));
/* close */
close(fd);
/* open */
fd = open(filename, O_RDWR);
assert(fd != -1);
printf("File opened. fd: %d\n", fd);
/* read */
n = read(fd, bufr, rd_bytes);
assert(n == rd_bytes);
bufr[n + 1] = 0;
printf("%d bytes read: %s\n", n, bufr);
/* close */
close(fd);
spin("TestA");
}
·do_rdwt 函数
PUBLIC int do_rdwt()
{
int fd = fs_msg.FD; /* 文件描述符 */
void *buf = fs_msg.BUF; /* 读写缓冲区 */
int len = fs_msg.CNT; /* 长度 */
int src = fs_msg.source; /* caller proc nr. */
assert((pcaller->filp[fd] >= &f_desc_table[0]) &&
(pcaller->filp[fd] < &f_desc_table[NR_FILE_DESC]));
// 检测文件描述符标志
if (!(pcaller->filp[fd]->fd_mode & O_RDWR))
return -1;
int pos = pcaller->filp[fd]->fd_pos;
struct inode *pin = pcaller->filp[fd]->fd_inode;
assert(pin >= &inode_table[0] && pin < &inode_table[NR_INODE]);
int imode = pin->i_mode & I_TYPE_MASK;
if (imode == I_CHAR_SPECIAL)
{
int t = fs_msg.type == READ ? DEV_READ : DEV_WRITE;
fs_msg.type = t;
int dev = pin->i_start_sect;
assert(MAJOR(dev) == 4);
fs_msg.DEVICE = MINOR(dev);
fs_msg.BUF = buf;
fs_msg.CNT = len;
fs_msg.PROC_NR = src;
assert(dd_map[MAJOR(dev)].driver_nr != INVALID_DRIVER);
send_recv(BOTH, dd_map[MAJOR(dev)].driver_nr, &fs_msg);
assert(fs_msg.CNT == len);
return fs_msg.CNT;
}
else
{
assert(pin->i_mode == I_REGULAR || pin->i_mode == I_DIRECTORY);
assert((fs_msg.type == READ) || (fs_msg.type == WRITE));
// 预防读写情况下的 pos_end
int pos_end;
if (fs_msg.type == READ) /* READ */
pos_end = min(pos + len, pin->i_size); /* 这句话的意思是读的时候只能读到 i_size */
else /* WRITE */
pos_end = min(pos + len, pin->i_nr_sects * SECTOR_SIZE); /* 这句话的意思是写的时候可以写到 2048 sectors */
// 根据长度计算需要读取多少扇区从磁盘中
int off = pos % SECTOR_SIZE;
int rw_sect_min = pin->i_start_sect + (pos >> SECTOR_SIZE_SHIFT); /* 从哪个扇区开始读 */
int rw_sect_max = pin->i_start_sect + (pos_end >> SECTOR_SIZE_SHIFT); /* 可以读止哪个扇区 */
int chunk = min(rw_sect_max - rw_sect_min + 1, /* 一共要读多少块 */
FSBUF_SIZE >> SECTOR_SIZE_SHIFT); /* FSBUF_SIZE >> SECTOR_SIZE_SHIFT == 2048 */
int bytes_rw = 0;
int bytes_left = len;
int i;
for (i = rw_sect_min; i <= rw_sect_max; i += chunk) /* 循环无用 */
{
/* read/write this amount of bytes every time */
int bytes = min(bytes_left, chunk * SECTOR_SIZE - off);
rw_sector(DEV_READ,
pin->i_dev,
i * SECTOR_SIZE, /* 起始扇区 */
chunk * SECTOR_SIZE, /* 这不就是一次将要读的扇区都读出来吗 */
TASK_FS,
fsbuf);
if (fs_msg.type == READ) /* 将要求长度的数据赋值到用户缓冲区中 */
{
phys_copy((void *)va2la(src, buf + bytes_rw),
(void *)va2la(TASK_FS, fsbuf + off), /* 注意这里的 fsbuf + off 关键 */
bytes); /* 但是 对 fsbuf va2la 没有必要 */
}
else /* 将要求长度的数据写到 buf 缓冲区中并刷新到磁盘中 */
{
phys_copy((void *)va2la(TASK_FS, fsbuf + off),
(void *)va2la(src, buf + bytes_rw),
bytes);
// 刷新到磁盘中
rw_sector(DEV_WRITE,
pin->i_dev,
i * SECTOR_SIZE,
chunk * SECTOR_SIZE,
TASK_FS,
fsbuf);
}
off = 0;
bytes_rw += bytes; /* 记录已经写了 / 读了多少字节 */
pcaller->filp[fd]->fd_pos += bytes; /* 更新文件描述符的 pos(注意不是 inode 的 size) */
bytes_left -= bytes;
}
if (pcaller->filp[fd]->fd_pos > pin->i_size) /* 写到了超过 inode 本来的 size */
{ /* 就要更新 i_size ,其余情况不需要更新 i_size */
pin->i_size = pcaller->filp[fd]->fd_pos;
sync_inode(pin);
}
return bytes_rw;
}
}
——其中的循环没有存在的必要,到时候可以去掉!
运行
可以看到,确实读出了我们写进磁盘的字符串,每次打开文件 pos 都是在起始位置的!