
文件系统源码分析之普通文件读写
发布日期:2021-05-09 16:03:01
浏览次数:11
分类:精选文章
本文共 5461 字,大约阅读时间需要 18 分钟。
文件读写主要是通过inode结构里的数据,读取或者写入到底层的硬盘中,并更新相应的属性。
/* * linux/fs/read_write.c * * (C) 1991 Linus Torvalds */#include#include #include #include #include #include extern int rw_char(int rw,int dev, char * buf, int count, off_t * pos);extern int read_pipe(struct m_inode * inode, char * buf, int count);extern int write_pipe(struct m_inode * inode, char * buf, int count);extern int block_read(int dev, off_t * pos, char * buf, int count);extern int block_write(int dev, off_t * pos, char * buf, int count);extern int file_read(struct m_inode * inode, struct file * filp, char * buf, int count);extern int file_write(struct m_inode * inode, struct file * filp, char * buf, int count);int sys_lseek(unsigned int fd,off_t offset, int origin){ struct file * file; int tmp; if (fd >= NR_OPEN || !(file=current->filp[fd]) || !(file->f_inode) || !IS_SEEKABLE(MAJOR(file->f_inode->i_dev))) return -EBADF; if (file->f_inode->i_pipe) return -ESPIPE; // SEEK_SET,SEEK_CUR和SEEK_END和依次为0,1和2 switch (origin) { case 0: if (offset<0) return -EINVAL; file->f_pos=offset; break; case 1: // 这个时候可以offset可以传负数,但是不能大于当前偏移 if (file->f_pos+offset<0) return -EINVAL; file->f_pos += offset; break; case 2: if ((tmp=file->f_inode->i_size+offset) < 0) return -EINVAL; file->f_pos = tmp; break; default: return -EINVAL; } return file->f_pos;}int sys_read(unsigned int fd,char * buf,int count){ struct file * file; struct m_inode * inode; if (fd>=NR_OPEN || count<0 || !(file=current->filp[fd])) return -EINVAL; if (!count) return 0; verify_area(buf,count); inode = file->f_inode; // 该文件描述符对应的是一个管道文件,并且是读端则读管道 if (inode->i_pipe) return (file->f_mode&1)?read_pipe(inode,buf,count):-EIO; if (S_ISCHR(inode->i_mode)) return rw_char(READ,inode->i_zone[0],buf,count,&file->f_pos); if (S_ISBLK(inode->i_mode)) return block_read(inode->i_zone[0],&file->f_pos,buf,count); if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode)) { // 读的长度不能大于剩下的可读长度 if (count+file->f_pos > inode->i_size) count = inode->i_size - file->f_pos; // 到底了 if (count<=0) return 0; return file_read(inode,file,buf,count); } printk("(Read)inode->i_mode=%06o\n\r",inode->i_mode); return -EINVAL;}int sys_write(unsigned int fd,char * buf,int count){ struct file * file; struct m_inode * inode; if (fd>=NR_OPEN || count <0 || !(file=current->filp[fd])) return -EINVAL; if (!count) return 0; inode=file->f_inode; if (inode->i_pipe) return (file->f_mode&2)?write_pipe(inode,buf,count):-EIO; if (S_ISCHR(inode->i_mode)) return rw_char(WRITE,inode->i_zone[0],buf,count,&file->f_pos); if (S_ISBLK(inode->i_mode)) return block_write(inode->i_zone[0],&file->f_pos,buf,count); if (S_ISREG(inode->i_mode)) return file_write(inode,file,buf,count); printk("(Write)inode->i_mode=%06o\n\r",inode->i_mode); return -EINVAL;}
/* * linux/fs/file_dev.c * * (C) 1991 Linus Torvalds */#include#include #include #include #include #define MIN(a,b) (((a)<(b))?(a):(b))#define MAX(a,b) (((a)>(b))?(a):(b))int file_read(struct m_inode * inode, struct file * filp, char * buf, int count){ int left,chars,nr; struct buffer_head * bh; if ((left=count)<=0) return 0; while (left) { // bmap取得该文件偏移对应的硬盘块号,然后读进来 if (nr = bmap(inode,(filp->f_pos)/BLOCK_SIZE)) { if (!(bh=bread(inode->i_dev,nr))) break; } else bh = NULL; // 偏移 nr = filp->f_pos % BLOCK_SIZE; // 读进来的数据中,可读的长度和还需要读的长度,取小的,如果还没读完继续把块从硬盘读进来 chars = MIN( BLOCK_SIZE-nr , left ); filp->f_pos += chars; // 更新偏移指针 left -= chars; // 更新还需药读取的长度 if (bh) { char * p = nr + bh->b_data; while (chars-->0) put_fs_byte(*(p++),buf++); //复制到buf里 brelse(bh); } else { while (chars-->0) put_fs_byte(0,buf++); } } // 更新访问时间 inode->i_atime = CURRENT_TIME; // 返回读取的长度,如果一个都没读则返回错误 return (count-left)?(count-left):-ERROR;}int file_write(struct m_inode * inode, struct file * filp, char * buf, int count){ off_t pos; int block,c; struct buffer_head * bh; char * p; int i=0;/* * ok, append may not work when many processes are writing at the same time * but so what. That way leads to madness anyway. */ // 如果设置了追加标记位,则更新当前位置指针到文件最后一个字节 if (filp->f_flags & O_APPEND) pos = inode->i_size; else pos = filp->f_pos; // i为已经写入的长度,count为需要写入的长度 while (i i_dev,block))) break; c = pos % BLOCK_SIZE; p = c + bh->b_data; // 开始写入数据的位置 bh->b_dirt = 1; // 标记数据需要回写硬盘 c = BLOCK_SIZE-c; // 算出能写的长度 if (c > count-i) c = count-i; // 比较能写的长度和还需要写的长度,取小的 pos += c; // 更新偏移指针,c为准备写入的长度 // 如果超过原来长度则需要更新i_size字段,标记inode需要回写 if (pos > inode->i_size) { inode->i_size = pos; inode->i_dirt = 1; } i += c; // 更新已经写入的长度 while (c-->0) *(p++) = get_fs_byte(buf++); brelse(bh); } inode->i_mtime = CURRENT_TIME; if (!(filp->f_flags & O_APPEND)) { filp->f_pos = pos; inode->i_ctime = CURRENT_TIME; } return (i?i:-1);}
static void cp_stat(struct m_inode * inode, struct stat * statbuf){ struct stat tmp; int i; verify_area(statbuf,sizeof (* statbuf)); tmp.st_dev = inode->i_dev; tmp.st_ino = inode->i_num; tmp.st_mode = inode->i_mode; tmp.st_nlink = inode->i_nlinks; tmp.st_uid = inode->i_uid; tmp.st_gid = inode->i_gid; tmp.st_rdev = inode->i_zone[0]; tmp.st_size = inode->i_size; tmp.st_atime = inode->i_atime; tmp.st_mtime = inode->i_mtime; tmp.st_ctime = inode->i_ctime; for (i=0 ; i= NR_OPEN || !(f=current->filp[fd]) || !(inode=f->f_inode)) return -EBADF; cp_stat(inode,statbuf); return 0;}
欢迎关注公众号
发表评论
最新留言
哈哈,博客排版真的漂亮呢~
[***.90.31.176]2025年04月27日 08时14分55秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
对比讲解lambda表达式与传统接口函数实现方式
2021-05-09
真的简单,文本文件逐行处理–用java8 Stream流的方式
2021-05-09
使用java8API遍历过滤文件目录及子目录及隐藏文件
2021-05-09
精讲响应式WebClient第2篇-GET请求阻塞与非阻塞调用方法详解
2021-05-09
java9系列第二篇-资源自动关闭的语法增强
2021-05-09
go语言系列--golang在windows上的安装和开发环境goland的配置
2021-05-09
CoreCLR源码探索(八) JIT的工作原理(详解篇)
2021-05-09
【数组】59. 螺旋矩阵 II
2021-05-09
【哈希表】1. 两数之和
2021-05-09
【字符串】28. 实现 strStr()
2021-05-09
【栈和队列】232. 用栈实现队列
2021-05-09
WIFI6 基本知识(二)
2021-05-09
安装Pyte失败的解决方法
2021-05-09
flink 1.7.2 安装详解
2021-05-09
linux权限管理
2021-05-09
linux之压缩和解压
2021-05-09
linux&shell学习系列
2021-05-09
搞懂ELK并不是一件特别难的事(ELK)
2021-05-09