现在要去实现文件的这一层抽象,其基本过程:给出一个文件inode,给出一个字符流读写位置,根据inode中存放的索引信息找到文件读写位置所在的物理盘块号,利用盘块号调用bread。
文件实现的代码从sys_write开始,根据inode->i_mode进行分支判断,如果是普通文件,就转到file_write(inode, file, buf, count)执行。
//sys_write()函数部分代码(普通文件分支)
int sys_write(int fd, const char* buf, int count)
{
struct file *file = current->filp[fd];
struct m_inode *inode = file->inode;
if(S_ISREG(inode->imode))
return file_write(inode, file, buf, count);
}
根据上图,file_write要首先找到文件对应的字符流位置,该位置就是文件最近一次读写结束时停留的读写位置。这个位置记录在打开文件对应的file数据结构中,准确来说记录在数据结构的f_pos中。语句pos = filp->f_pos取出来的就是200。
//file_write()函数的代码实现
int file_write(struct m_inode *inode, struct file *filp, char *buf, int count)
{
off_t pos;
if(filp->f_flags & O_APPEND)
pos = inode->i_size;
else pos = filp->f_pos;
while(i < count)
{
block = create_block(inode, pos/BLOCK_SIZE);
bh = bread(inode->i_dev, block);
int c = pos%BLOCK_SIZE;
char *p = c + bh->b_data;
bh->b_dirt = 1;
c = BLOCK_SIZE - c;
pos += c;
while(c->0) *(p++) = get_fs_byte(buf++);
brelse(bh);
}
filp->f_pos = pos;
}
现在有了字符流的读写位置pos,接下来要根据pos和索引节点中的信息计算物理盘块号。函数create_block(inode, pos/BLOCK_SIZE)中会调用bamp完成这项工作,根据pos/BLOCK_SIZE获得逻辑块号去查找inode中的直接数据块、一阶或者二阶索引。
int bamp(m_inode *inode, int block, int create)
{
if(block < 7)//inode中直接数据块能映射出盘块号
if(create && !inode->i_zone[block])
{
inode->i_zone[block] = new_block(inode->i_dev);
inode->i_ctime = CURRENT_TIME;
inode->i_dirt = 1;
}
return inode->i_zone[block];
}
block -= 7;
if(block < 256)//逻辑盘块号存放在一阶索引中
{
bh = bread(inode->i_dev, inode->i_zone[7]);
......
}
}
struct d_inode
{
unsigned short i_mode;
......
unsigned short i_zone[9];
}