搜索exfat资料时,找到一篇老外的反编译exfat的文件,对我们学习代码很有帮助

文章名是reverse-engineering-microsoft-exfat-file-system_33274.pdf。

至于exfat的文件系统代码,可以从github上获取到,github地址是:https://github.com/dorimanx/exfat-nofuse

结合资料和code开启我的exfat之旅

获取到exfat-nofuse代码后,先看看代码中自带的README.md文档,check发现该开源代码是在linux系统中以命令modprobe exfat方式load the driver manually,然后使用标准的mount加载exfat文件系统。

modprobe exfat的控制主要是运行代码exfat_super.c中module_init(init_exfat_fs)的函数。

init_exfat_fs函数主要功能:

1. FsInit------exfat文件系统全局变量初始化以及一些文件系统定义边界检查

2.exfat_init_inodecache------exfat文件系统创建专属的高速缓冲

3.register_filesystem(&exfat_fs_type)------注册exfat文件系统到linux的VFS系统体系中

相关code如下:

static int __init init_exfat_fs(void)
{
 int err;
 
 printk(KERN_INFO "exFAT: Core Version %s\n", EXFAT_VERSION);

err = FsInit();
 if (err) {
  if (err == FFS_MEMORYERR)
   return -ENOMEM;
  else
   return -EIO;
 }

err = exfat_init_inodecache();
 if (err)
  goto out;

err = register_filesystem(&exfat_fs_type);
 if (err)
  goto out;

return 0;
out:
 FsShutdown();
 return err;
}

这里需要注意的数据结构如下:

static struct file_system_type exfat_fs_type = {
 .owner       = THIS_MODULE,
 .name        = "exfat",
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37)
 .get_sb      = exfat_get_sb,
#else
 .mount       = exfat_fs_mount,//根据目前的kernel版本,我们要使用这个函数probe文件系统(mount命令加载exfat时会使用调用到这个最终实际加载的文件系统函数)
#endif
#if EXFAT_CONFIG_KERNEL_DEBUG
 .kill_sb    = exfat_debug_kill_sb,
#else
 .kill_sb    = kill_block_super,
#endif
 .fs_flags    = FS_REQUIRES_DEV,
};

这个数据结构中

.name        = "exfat",-------------标示新添加的文件系统名字,比如ext4,ext3......

.mount       = exfat_fs_mount,------------这个函数会注册到文件系统中,在mount时调用加载,后续详细介绍。

上一章强调了exfat_fs_mount在linux mount的时候会调用到,本章节将详细描述这个函数的执行过程。

在安装exFAT(mount)的时候,存放exFAT文件系统的磁盘分区上的大部分数据结构的信息都会被拷贝到RAM(操作系统内存)中,从而使得内核避免了许多后续的操作,变得简单。由于exFAT磁盘数据结构都保存在exFAT磁盘分区的块中,所以当需要经常更新一些数据结构时,内核会利用页高速缓存来实现。

在实际mount一个文件系统的时候,exFAT文件系统依赖于虚拟文件系统的一个标准函数(mount_bdev)来实现文件系统信息的装载。

在我们的exfat-nofuse代码中,函数exfat_fs_mount调用mount_bdev(fs_type, flags, dev_name, data, exfat_fill_super);来实现,在mount_bdev函数中通过exfat_fill_super函数来填充VFS中一个超级块对象,代码实现如下:

static struct dentry *exfat_fs_mount(struct file_system_type *fs_type,
          int flags, const char *dev_name,
          void *data) {
 return mount_bdev(fs_type, flags, dev_name, data, exfat_fill_super);
}

现在我们来详细描述exfat_fill_super函数的功能:

1.分配exfat的super_block的私有数据(struct exfat_sb_info *sbi)需要用到的内存,并进行初始化

struct exfat_sb_info *sbi;

sbi = kzalloc(sizeof(struct exfat_sb_info), GFP_KERNEL);

sb->s_fs_info = sbi;

mutex_init(&sbi->s_lock);

................

parse_options(data, silent, &debug, &sbi->options);/*解析mount exfat时传入的参数*/

2.初始化exfat的super_block的数据

sb->s_fs_info = sbi;
 sb->s_flags |= MS_NODIRATIME;
 sb->s_magic = EXFAT_SUPER_MAGIC;
 sb->s_op = &exfat_sops;

sb->s_d_op = &exfat_ci_dentry_ops;

这里需要注意exfat_sops和exfat_ci_dentry_ops的实现内容

const struct super_operations exfat_sops = {
 .alloc_inode   = exfat_alloc_inode,
 .destroy_inode = exfat_destroy_inode,
 .write_inode   = exfat_write_inode,
 .evict_inode  = exfat_evict_inode,
 .put_super     = exfat_put_super,
 .sync_fs       = exfat_sync_fs,
 .statfs        = exfat_statfs,
 .remount_fs    = exfat_remount,
 .show_options  = exfat_show_options,
};

static const struct dentry_operations exfat_ci_dentry_ops = {
 .d_revalidate   = exfat_revalidate_ci,
 .d_hash         = exfat_d_hashi,
 .d_compare      = exfat_cmpi,
};

3.FsMountVol函数加载exfat分区的Volume Boot Record(VBR)数据以及exfat特定分区数据,然后初始化exfat的super_block数据以及super_block的私有数据以及exfat文件系统必要的数据(后面专门一章再详细描述这个函数的实现)

4.exfat_hash_init函数初始化inode的hash table

5.在exfat文件系统中做codepage的初始化

6.创建exfat的root inode以及初始化,并把root inode挂载到hash table

注意exfat root inode的初始化

inode->i_op = &exfat_dir_inode_operations;
 inode->i_fop = &exfat_dir_operations;

const struct inode_operations exfat_dir_inode_operations = {
 .create        = exfat_create,
 .lookup        = exfat_lookup,
 .unlink        = exfat_unlink,
 .symlink       = exfat_symlink,
 .mkdir         = exfat_mkdir,
 .rmdir         = exfat_rmdir,
 .rename        = exfat_rename,
 .setattr       = exfat_setattr,
 .getattr       = exfat_getattr,
#ifdef CONFIG_EXFAT_VIRTUAL_XATTR
 .setxattr = exfat_setxattr,
 .getxattr = exfat_getxattr,
 .listxattr = exfat_listxattr,
 .removexattr = exfat_removexattr,
#endif
};

const struct file_operations exfat_dir_operations = {
 .llseek     = generic_file_llseek,
 .read       = generic_read_dir,
 .readdir    = exfat_readdir,
 .unlocked_ioctl = exfat_generic_ioctl,
 .fsync      = exfat_file_fsync,
};

7. 通过root inode创建root dentry

8. 完成

code如下:

static int exfat_fill_super(struct super_block *sb, void *data, int silent)

{
 struct inode *root_inode = NULL;
 struct exfat_sb_info *sbi;
 int debug, ret;
 long error;
 char buf[50];

exfat_mnt_msg(sb, 1, 0, "trying to mount...");
 /*
  * GFP_KERNEL is ok here, because while we do hold the
  * supeblock lock, memory pressure can't call back into
  * the filesystem, since we're only just about to mount
  * it and have no inodes etc active!
  */
 sbi = kzalloc(sizeof(struct exfat_sb_info), GFP_KERNEL);/*分配exfat私有的super_block的数据需要用到的内存*/
 if (!sbi) {
  exfat_mnt_msg(sb, 1, 0, "failed to mount! (ENOMEM)");
  return -ENOMEM;
 }
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
 mutex_init(&sbi->s_lock);
#endif
 sb->s_fs_info = sbi;
 sb->s_flags |= MS_NODIRATIME;
 sb->s_magic = EXFAT_SUPER_MAGIC;
 sb->s_op = &exfat_sops;

error = parse_options(data, silent, &debug, &sbi->options);/*解析mount exfat时传入的参数*/
 if (error)
  goto out_fail;

setup_dops(sb);

error = -EIO;
 sb_min_blocksize(sb, 512);
 sb->s_maxbytes = 0x7fffffffffffffffLL;    /* maximum file size */

ret = FsMountVol(sb);//wangxf14_study
 if (ret) {
  if (!silent)
   printk(KERN_ERR "[EXFAT] FsMountVol failed\n");

goto out_fail;
 }

/* set up enough so that it can read an inode */
 exfat_hash_init(sb);

/*
  * The low byte of FAT's first entry must have same value with
  * media-field.  But in real world, too many devices is
  * writing wrong value.  So, removed that validity check.
  *
  * if (FAT_FIRST_ENT(sb, media) != first)
  */

/* codepage is not meaningful in exfat */
 error = -EINVAL;
 sprintf(buf, "cp%d", sbi->options.codepage);
 sbi->nls_disk = load_nls(buf);
 if (!sbi->nls_disk) {
  printk(KERN_ERR "[EXFAT] Codepage %s not found\n", buf);
  goto out_fail2;
 }

sbi->nls_io = load_nls(sbi->options.iocharset);

if (!sbi->nls_io) {
  printk(KERN_ERR "[EXFAT] IO charset %s not found\n",
      sbi->options.iocharset);
  goto out_fail2;
 }

error = -ENOMEM;
 root_inode = new_inode(sb);/*创建一个inode节点,这个函数就是在fs/inode.c中的new_inode函数*/
 if (!root_inode)
  goto out_fail2;
 root_inode->i_ino = EXFAT_ROOT_INO;
 root_inode->i_version = 1;
 error = exfat_read_root(root_inode); //wangxf14_study
 if (error < 0)
  goto out_fail2;
 error = -ENOMEM;
 exfat_attach(root_inode, EXFAT_I(root_inode)->i_pos);
 insert_inode_hash(root_inode);/*将这个新的inode内存节点挂在hashtable中,这个函数在fs/inode.c中的insert_inode_hash函数*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,4,00)
 sb->s_root = d_make_root(root_inode);
#else
 sb->s_root = d_alloc_root(root_inode);
#endif
 if (!sb->s_root) {
  printk(KERN_ERR "[EXFAT] Getting the root inode failed\n");
  goto out_fail2;
 }

exfat_mnt_msg(sb, 1, 0, "mounted successfully!");

return 0;

out_fail2:
 FsUmountVol(sb);
out_fail:
 exfat_mnt_msg(sb, 1, 0, "failed to mount!");

if (root_inode)
  iput(root_inode);
 if (sbi->nls_io)
  unload_nls(sbi->nls_io);
 if (sbi->nls_disk)
  unload_nls(sbi->nls_disk);
 if (sbi->options.iocharset != exfat_default_iocharset)
  kfree(sbi->options.iocharset);
 sb->s_fs_info = NULL;
 kfree(sbi);
 return error;
}

exFAT文件系统2相关推荐

  1. ExFat文件系统DBR受损恢复案例

    ExFat文件系统DBR受损恢复案例 ExFat文件系统也FAT32相类似,同时也结合着NTFS中的知识. 下面我们手工分析EXFat文件系统DBR受损手工分析案例 手工恢复受损的DBR需要计算一下参 ...

  2. linux内核 fat,微软宣布exFAT文件系统规范,希望被Linux内核接纳

    对于那些经常需要在 Linux 和 Windows 10 之间切换工作的人们来说,作为 FAT32 继任者的 exFAT 文件系统,能够为用户带来更好的体验.近日,微软宣布了 exFAT 文件系统规范 ...

  3. Android5.1设备无法识别exFAT文件系统的64G TF卡问题

    64G TF卡刚买回来的时候默认exFAT文件系统,在电脑端(XP和WIN7)可以识别,但在我们Android5.1S设备无法识别,采用guiformat工具格式化为FAT32文件系统后才可以正常识别 ...

  4. FAT和EXFAT文件系统

    源:FAT和EXFAT文件系统 转载于:https://www.cnblogs.com/LittleTiger/p/8022450.html

  5. linux 下exfat分区,exFAT 文件系统指南

    国庆假期,我拍了一些手机视频,打算存到新买的移动硬盘. 然后,就傻眼了.我的 Mac 电脑无法写入移动硬盘,因为移动硬盘的默认文件系统是 NTFS,Mac 不支持写入 NTFS. 虽然可以买一个软件解 ...

  6. exfat文件系统(一)

    由于工作需要,开始研究exfat文件系统. 从网络上获取到exfat文件系统的介绍 http://www.ntfs.com/exfat-overview.htm 同时在csdn上找到一篇文章针对这个翻 ...

  7. Android 7.0支持exfat文件系统

    网上看了一圈,关于Android移植exfat支持的文章大多停留在Android 4.x,Android 6.0或7.0以上的基本空缺,所以决定自己写一篇,本文实践环境是MTK的Android 7.0 ...

  8. Android 11.0 支持exFAT文件系统

    Android 11.0 支持exFAT文件系统 U盘常见文件系统类型有FAT32.NTFS.exFAT, Android默认支持FAT32,  一般也有NTFS类型编译选项, 但是exFAT由于版权 ...

  9. EXFAT文件系统的数据恢复教程-李林峰-专题视频课程

    EXFAT文件系统的数据恢复教程-5673人已学习 课程介绍         本套课程讲的是用winhex磁盘编辑软件,手工恢复EXFAT文件系统中的数据. 课程收益     学习EXFAT文件系统的 ...

最新文章

  1. Java 分布式 RPC 框架性能大比拼,Dubbo 排第几?
  2. 全面理解ERC721的实现机制
  3. python如何进行双色球预测最准确_【原创】python基于大数据现实双色球预测
  4. Walking Robot
  5. coco 语义分割_YOLACT++:目前最热门的实时实例分割开源库
  6. JAVA正则表达式4种常用功能 [转]
  7. 谈谈tmpdir与innodb_tmpdir的区别和用处
  8. 什么是机器学习?机器学习的工作原理是什么?
  9. js传参不是数字_js中函数传参方式
  10. 计算机硬盘图标闪烁,电脑本地磁盘图标显示异常如何解决
  11. 快捷方式和活动桌面小贴
  12. Android videoView闪屏
  13. IntelliJ配置jenkins服务的Crumb Data
  14. 如何在word文档里复选框里打勾?
  15. 公众号和视频号互相绑定带来的功能
  16. 千牛挂“虹(Rainbow)”,域和角色不胜数
  17. CCF基础P29练习题解
  18. 深入理解矩阵的特征值和特征向量
  19. 关于很狗的军训qwq
  20. 小红帽 oracle,linux 小红帽 一键安装ffmpeg

热门文章

  1. Linux征途——总结与扩展
  2. 青春亦不在,无法在挥霍
  3. 【华为机试真题 Python实现】免单统计
  4. LVS-NAT网络地址转换模式
  5. pycharm安装requests库一直报错
  6. 解放双手,Android开发应该尝试的UI自动化测试
  7. 通过 zerotier 访问所在局域网的其他设备
  8. Graph Neural Networks for Social Recommendation(GraphRec2019)阅读笔记
  9. 关于JDBC连接MySQL的时候出现警告:Establishing SSL connection without server‘s identity verification is not recom
  10. 使用NATS消息中间件实现云边协同