14.9 实现文件读写指针定位功能
这是一个网站有所有小节的代码实现,同时也包含了Bochs等文件
实现系统调用lseek,这里是模仿的Linux下的系统调用。Iseek 原型是off_t lseek(int32_t fd, int32_t offset, uint8_t whence)
,fd
是文件描述符, offset
是偏移量, whence
是 offset
的“参照物",函数功能是设置文件读写指针fd_pos
为参照物+偏移量的值,也就是说,文件指针具体的位置不仅取决于 offset
,还取决于 whence
。其中off_t
是 typedef
自定义的类型,相当于 signed int,
有符号整型,因此 offset 是可正可负的值 。
whence
取值有三种取值。
SEEK_SET
, offset
的参照物是文件开始处,也就是将读写位置指针设置为距文件开头偏移 offset
个字节处。
SEEK_CUR
, offset
的参照物是当前读写位置,也就是将读写位置指针设置为当前位置+offset
。
SEEK_END
, offset
的参照物是文件尺寸大小,即文件最后一个字节的下一个字节,也就是将读写位置指针设置为文件尺寸+offset
。
//fs.c
/*重置用于文件读写操作的偏移指针。成功时返回新的偏移量,出错时返回-1*/
int32_t sys_lseek(int32_t fd, int32_t offset, uint8_t whence){
if(fd<0){
printk("sys_lseek:fd error\n");
return -1;
}
ASSERT(whence>0 &&whence<4);
uint32_t _fd = fd_local2global(fd);
struct file* pf = &file_table[_fd];
int32_t new_pos = 0; //新的偏移量必须位于文件大小之内
int32_t file_size = (uint32_t)pf->fd_inode->i_size;
switch (whence){
/*SEEK_SET新的读写位置是相对于文件开头再增加 offset 个位移量*/
case SEEK_SET:
new_pos = offset;
break;
/*SEEK_CUR新的读写位置是相对于当前的位置增加 offset 个位移量*/
case SEEK_CUR:
new_pos = (int32_t)pf->fd_pos+offset;
break;
/*SEEK_END新的读写位置是相对于文件尺寸再增加 off set 个位移量*/
case SEEK_END:
new_pos = file_size + offset;
break;
}
if(new_pos<0||new_pos>(file_size-1)) return -1;
pf->fd_pos=new_pos;
return pf->fd_pos;
}
sys_lseek
用于根据传入的参照物与偏移,重置传入的文件描述符对应的全局打开文件结构中的fd_pos
。核心原理:根据传入的文件描述符,调用fd_local2global
将文件描述符转换成指定的全局打开文件结构数组索引,然后switch case对传入的参照物情况进行选择,以对fd_pos
做不同处理。参照物为SEET_SET
,那么新的fd_pos
就等于传入的偏移;参照物为SEET_CUR
,那么新的fd_pos
= 原来fd_pos
+ 传入偏移;参照物为SEET_END
,那么新的fd_pos
为原来文件大小 + 偏移(此时偏移量不出意外的话是负数)。