分类: LINUX
2013-12-23 15:55:55
原文地址:如何写一个简易的文件系统(3):ls命令 作者:mournjust
以前两节基本可以挂在一个文件系统了,一方面注册一个文件系统类型,另外一个方面在挂在的时候读出超级块的信息,并构造一个根目录项的相关信息。
这样可以通过
Mount –t myfs /dev/mtdblk3 /mnt
来挂载文件系统了,先别急着ls,因为相关的接口函数还没完成呢!
上一节提到了文件系统中的三大操作结构体,为了满足大家ls的愿望,我们就先从文件夹的操作结构体开始吧。
static const struct file_operations myfs_dir_operations = {
.read = generic_read_dir,
.readdir = myfs_readdir,
.llseek = generic_file_llseek,
};
其实这个里面基本就实现了一个函数readdir,其实ls就是使用的这个接口函数。
static int myfs_readdir(struct file *f, void *dirent, filldir_t filldir)
{
unsigned int offset,last,page_index,page_offset,inode_per_page,retlen,p;
unsigned int err = 0,i ;
struct inode *inode = f->f_dentry->d_inode;
struct myfs_inode *llf_inode;
struct myfs_sb_info *sbi = MYFS_S(inode->i_sb);
struct mtd_info *mtd = sbi->mtd;
offset = f->f_pos;//Linux中有“一切皆是文件”的概念,这个虽然是要读取一个文件夹下面的子文件的操作,但是传入参数还是一个file类型的指针。
//注意这儿的f->f_pos,在常规的文件中,这个字段用于保存我们读取,写入的offset。也可以通过lseek来改变这个字段。但是在文件夹中这个字段没有任何意义,因为文件夹的大小始终为0。但是在readdir中利用这个字段来保存每次读取的子文件的index。
//如果大家稍微baidu看一下上层应用程序是如何使用readdir这个系统调用的话就大体知道这个函数应该如何来实现。
while((p_dirent=readdir(p_dir)))
{
printf("%s\n",p_dirent->d_name);
}
Readdir系统调用每次读取一个文件的信息,通过while来循环读取,当没有文件可读时,返回NULL
if(!offset)
offset++;
myfs_trace("myfs_readdir: starting at %d", (int)offset);
/* If the directory has changed since the open or last call to
readdir, rewind to after the 2 canned entries. */
if(offset >= MYFS_MAX_INODE_NUM)
return err;
inode_per_page = sbi->myfs_sb.page_size/sizeof(struct myfs_inode); //myfs只支持一级目录,所有的文件都存在于根目录之下。这儿计算每一个page可以容纳多少个目录inode节点,inode number为offset的文件应该处于存储介质的什么位置。
page_index = offset/inode_per_page;
page_offset = offset%inode_per_page;
last = mtd->writesize/sizeof(struct myfs_inode);
for(p = page_index ; p
err = mtd->read(mtd,mtd->erasesize+p*mtd->writesize,mtd->writesize,&retlen,sbi->buf);
if(err){
myfs_trace("%s,mtd->read failed",__func__);
goto out;
}
llf_inode = (struct myfs_inode*)sbi->buf;
llf_inode += page_offset;
for( i = page_offset ;i < last ;i++,offset++,llf_inode++){
/*root->i_ino == 0*/
if(llf_inode->attr != MYFS_ATTR_FILE )
continue;
myfs_trace("find new file:%s",llf_inode->name);
/*find new file*/
if(filldir(,llf_inode->name,strlen(llf_inode->name),offset,llf_inode->inode_no,DT_REG) < 0){//找到新文件啦,那么就把文件系统填充在dirent,然后系统调用就会返回给应用程序。
goto out;
}
}
}
f->f_pos = offset;//这儿可以看出f->f_pos存储的是上一次找到文件的位置,那么下一次就接着从这个位置开始往后找。
out:
return err;
}
好了,这样我们在挂载之后就可以使用ls命令来列出根目录下面的所有文件啦!!