前序

上一篇分析了格式化一个磁盘的时候发生了什么,在格式化一个磁盘之后,就要将磁盘进行挂载,“挂载”这个词听起来很抽象,但是在软件代码上,到底发生了什么?

分析假设

(1)假设一个磁盘就一个分区。

(2)只分析FAT32文件系统相关的代码。

(3)函数的大部分分析,都写入代码注释中

f_mount()函数全部代码

为了方便分析,排除视觉障碍,已经删除了不在假设范围内代码。

FRESULT f_mount (FATFS* fs,          /* fat文件系统描述的一个结构体,需要用户进行分配,然后会被记录在全局的FATFS[]这个数组中 */const TCHAR* path, /* 物理磁盘 */BYTE opt          /* 挂载选项,1-代表立马挂载,从代码分析中知,这个值必须传入1 */
)
{FATFS *cfs;int vol;FRESULT res;const TCHAR *rp = path;/* 获取驱动号,为了找到FatFs[]数组中的空闲项 */vol = get_ldnumber(&rp);if (vol < 0) return FR_INVALID_DRIVE;cfs = FatFs[vol];                   /* Pointer to fs object */if (cfs) {
#if _FS_LOCK != 0clear_lock(cfs);
#endif
#if _FS_REENTRANT                       /* Discard sync object of the current volume */if (!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR;
#endifcfs->fs_type = 0;             /* Clear old fs object */}if (fs) {fs->fs_type = 0;             /* Clear new fs object */
#if _FS_REENTRANT                       /* Create sync object for the new volume */if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR;
#endif}/* 把用户分配的FATFS结构图放入全局数组指针中 */FatFs[vol] = fs;                   /* Register new fs object */if (!fs || opt != 1) return FR_OK; /* Do not mount now, it will be mounted later *//* 这个函数才是挂载时的关键所在 */res = find_volume(&path, &fs, 0);  /* Force mounted the volume */LEAVE_FF(fs, res);
}

从f_mount函数分析中可知,find_volume()函数才是挂载的核心代码,


static
FRESULT find_volume (   /* FR_OK(0): successful, !=0: any error occurred */const TCHAR** path, /* 硬件磁盘,与f_mount函数的参数是一致的 */FATFS** rfs,        /* 与f_mount函数的fs参数是一致的 */BYTE mode          /* 这个传入的是0 */
)
{BYTE fmt, *pt;int vol;DSTATUS stat;DWORD bsect, fasize, tsect, sysect, nclst, szbfat, br[4];WORD nrsv;FATFS *fs;UINT i;/* Get logical drive number */*rfs = 0;vol = get_ldnumber(path);if (vol < 0) return FR_INVALID_DRIVE;/* Check if the file system object is valid or not *//* 1.找到用户分配的FATFS结构体 */fs = FatFs[vol];                 /* Get pointer to the file system object */if (!fs) return FR_NOT_ENABLED;      /* Is the file system object available? */ENTER_FF(fs);                     /* Lock the volume */*rfs = fs;                            /* Return pointer to the file system object */mode &= (BYTE)~FA_READ;              /* Desired access mode, write access or not *//* 判定磁盘当前状态,如果磁盘被初始化过,那么就判定是挂载过了,直接返回OK */if (fs->fs_type) {                   /* If the volume has been mounted */stat = disk_status(fs->drv);if (!(stat & STA_NOINIT)) {     /* and the physical drive is kept initialized */if (!_FS_READONLY && mode && (stat & STA_PROTECT)) {    /* Check write protection if needed */return FR_WRITE_PROTECTED;}return FR_OK;              /* The file system object is valid */}}/* The file system object is not valid. *//* Following code attempts to mount the volume. (analyze BPB and initialize the fs object) *//* 2.进行FATFS结构体填充 */fs->fs_type = 0;                  /* Clear the file system object */fs->drv = LD2PD(vol);             /* Bind the logical drive and a physical drive *//* 2.1初始化磁盘 */stat = disk_initialize(fs->drv); /* Initialize the physical drive */if (stat & STA_NOINIT) {             /* Check if the initialization succeeded */return FR_NOT_READY;         /* Failed to initialize due to no medium or hard error */}if (!_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check disk write protection if needed */return FR_WRITE_PROTECTED;}/* Find an FAT partition on the drive. Supports only generic partitioning, FDISK and SFD. */bsect = 0;/* 2.2 check_fs()函数会把磁盘的第1个扇区(就是MBR)读入到fs->win[]数组中, 判断MBR是否是合法的MBR*/fmt = check_fs(fs, bsect);         /* Load sector 0 and check if it is an FAT-VBR as SFD *//* 2.3 fmt=0,说明是FAT32文件系统 */if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) {  /* Not an FAT-VBR or forced partition number */for (i = 0; i < 4; i++) {          /* Get partition offset */pt = fs->win + (MBR_Table + i * SZ_PTE);br[i] = pt[PTE_System] ? ld_dword(pt + PTE_StLba) : 0;}i = LD2PT(vol);                       /* Partition number: 0:auto, 1-4:forced */if (i) i--;do {                               /* Find an FAT volume */bsect = br[i];fmt = bsect ? check_fs(fs, bsect) : 3;  /* Check the partition */} while (!LD2PT(vol) && fmt >= 2 && ++i < 4);}if (fmt == 4) return FR_DISK_ERR;     /* An error occured in the disk I/O layer */if (fmt >= 2) return FR_NO_FILESYSTEM;  /* No FAT volume is found *//* An FAT volume is found. Following code initializes the file system object */{/* 读取MBR中的BPB_BytsPerSec域,判断扇区大小是否是512(SS(fs)) */if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_BytsPerSec must be equal to the physical sector size) *//* 2.4获取FAT表的大小、FAT表的个数、每个簇的扇区数、根目录项数(对于FAT32不存在这个)、磁盘簇的个数、MBR、FAT表、数据区的位置、 */fasize = ld_word(fs->win + BPB_FATSz16);         /* Number of sectors per FAT */if (fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32);fs->fsize = fasize;fs->n_fats = fs->win[BPB_NumFATs];                    /* Number of FATs */if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM;    /* (Must be 1 or 2) */fasize *= fs->n_fats;                             /* Number of sectors for FAT area */fs->csize = fs->win[BPB_SecPerClus];             /* Cluster size */if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM;  /* (Must be power of 2) */fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt);    /* Number of root directory entries */if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM;    /* (Must be sector aligned) */tsect = ld_word(fs->win + BPB_TotSec16);         /* Number of sectors on the volume */if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32);nrsv = ld_word(fs->win + BPB_RsvdSecCnt);         /* Number of reserved sectors */if (nrsv == 0) return FR_NO_FILESYSTEM;               /* (Must not be 0) *//* Determine the FAT sub type */sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE);  /* RSV + FAT + DIR */if (tsect < sysect) return FR_NO_FILESYSTEM;      /* (Invalid volume size) */nclst = (tsect - sysect) / fs->csize;                /* Number of clusters */if (nclst == 0) return FR_NO_FILESYSTEM;          /* (Invalid volume size) */fmt = FS_FAT32;if (nclst <= MAX_FAT16) fmt = FS_FAT16;if (nclst <= MAX_FAT12) fmt = FS_FAT12;/* Boundaries and Limits */fs->n_fatent = nclst + 2;                            /* Number of FAT entries */fs->volbase = bsect;                             /* Volume start sector */fs->fatbase = bsect + nrsv;                       /* FAT start sector */fs->database = bsect + sysect;                       /* Data start sector */if (fmt == FS_FAT32) {if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM;   /* (Must be FAT32 revision 0.0) */if (fs->n_rootdir) return FR_NO_FILESYSTEM;        /* (BPB_RootEntCnt must be 0) */fs->dirbase = ld_dword(fs->win + BPB_RootClus32);   /* Root directory start cluster */szbfat = fs->n_fatent * 4;                        /* (Needed FAT size) */} else {if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM;/* (BPB_RootEntCnt must not be 0) */fs->dirbase = fs->fatbase + fasize;             /* Root directory start sector */szbfat = (fmt == FS_FAT16) ?                    /* (Needed FAT size) */fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);}if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM;    /* (BPB_FATSz must not be less than the size needed) */#if !_FS_READONLY/* Get FSINFO if available */fs->last_clst = fs->free_clst = 0xFFFFFFFF;        /* Initialize cluster allocation information */fs->fsi_flag = 0x80;
#if (_FS_NOFSINFO & 3) != 3/* 2.5判断是否存在FSINFO扇区,如果存在则读出可用簇数、下一个可用簇号到FATFS结构体中 */if (fmt == FS_FAT32              /* Enable FSINFO only if FAT32 and BPB_FSInfo32 == 1 */&& ld_word(fs->win + BPB_FSInfo32) == 1&& move_window(fs, bsect + 1) == FR_OK){fs->fsi_flag = 0;if (ld_word(fs->win + BS_55AA) == 0xAA55    /* Load FSINFO data if available */&& ld_dword(fs->win + FSI_LeadSig) == 0x41615252&& ld_dword(fs->win + FSI_StrucSig) == 0x61417272){
#if (_FS_NOFSINFO & 1) == 0fs->free_clst = ld_dword(fs->win + FSI_Free_Count);
#endif
#if (_FS_NOFSINFO & 2) == 0fs->last_clst = ld_dword(fs->win + FSI_Nxt_Free);
#endif}}
#endif  /* (_FS_NOFSINFO & 3) != 3 */
#endif  /* !_FS_READONLY */}fs->fs_type = fmt;  /* FAT sub-type */fs->id = ++Fsid;    /* File system mount ID */
#if _USE_LFN == 1fs->lfnbuf = LfnBuf; /* Static LFN working buffer */
#if _FS_EXFATfs->dirbuf = DirBuf;   /* Static directory block working buuffer */
#endif
#endif
#if _FS_RPATH != 0fs->cdir = 0;        /* Initialize current directory */
#endif
#if _FS_LOCK != 0      /* Clear file lock semaphores */clear_lock(fs);
#endifreturn FR_OK;
}

总结

f_mount函数就是读出MBR扇区的内容放入FATFS结构图中,供以后使用。

fatfs文件系统详解之f_mount函数分析相关推荐

  1. fatfs文件系统详解之f_mkfs函数分析

    前序 前面两篇文章分析了FAT文件系统,没有代码总感觉很空虚寂寞冷,fatfs正好是一个开源专门应对fat文件系统的代码,从这篇文章开始分析fatfs代码,"理论+实践"才是悟道的 ...

  2. fatfs文件系统详解之f_read函数分析

    前序 文件系统的最终目的是为了进行文件的管理,文件的管理就是读写.删除等操作,文件打开后,本篇继续分析读操作. 分析假设 (1)假设一个磁盘就一个分区. (2)只分析FAT32文件系统相关的代码. ( ...

  3. fatfs文件系统详解之f_write函数分析

    前序 本篇分析f_write()函数,fatfs文件系统对应的不知道文件的读写,也对应了文件的其他的操作,也有文件夹的操作,函数分析确实是一个非常耗时耗精力的事情,此函数分析完之后,就结束函数分析. ...

  4. FATFS文件系统详解

    一.文件系统 负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统.即在磁盘上组织文件的方法. 常用的文件系统: FAT / FATFS NTFS: 基于安全性的文件系统,是Windows ...

  5. 国产超低功耗华大单片启动文件详解及SystemInit函数分析

    启动代码文件名一般可命名为如startup_hc32xxxx.s.启动代码作用一般是: 1) 堆和栈的初始化 包括堆栈的大小,MSP(main stack pointer)值等.MSP的初始值在复位阶 ...

  6. 004:STM32启动文件详解及SystemInit函数分析(转)

    1 ;先在RAM中分配系统使用的栈,RAM的起始地址为0x2000_0000 2 ;然后在RAM中分配变量使用的堆 3 ;然后在CODE区(flash)分配中断向量表,flash的起始地址为0x080 ...

  7. STM32启动文件详解及SystemInit函数分析

    1 ;先在RAM中分配系统使用的栈,RAM的起始地址为0x2000_0000 2 ;然后在RAM中分配变量使用的堆 3 ;然后在CODE区(flash)分配中断向量表,flash的起始地址为0x080 ...

  8. Linux系统调用详解(实现机制分析)

    为什么需要系统调用   linux内核中设置了一组用于实现系统功能的子程序,称为系统调用.系统调用和普通库函数调用非常相似,只是系统调用由操作系统核心提供,运行于内核态,而普通的函数调用由函数库或用户 ...

  9. [自制操作系统] JOS文件系统详解支持工作路径MSH

    本文分为两部分: 第一部分将详细分析JOS的文件系统及文件描述符的实现方法. 第二部分将实现工作路径,提供新的系统调用,完善用户空间工具. 本文中支持的新特性: 支持进程工作目录 提供getcwd与c ...

最新文章

  1. 计算机文字识别的过程包括哪些步骤,电脑上的文字识别工具怎么使用?
  2. java怎么添加地图_javaweb怎样添加百度地图
  3. C# 模拟 Post
  4. linux基础-第十五单元 软件包的管理
  5. python 锁 多进程
  6. matlab的灰色关联,五种灰色关联度分析matlab代码
  7. python编写四位数验证码
  8. 小度智能音响拆解 芯片_不拆不快:小度音箱拆解测评
  9. Parcel极速零配置Web应用打包工具
  10. [SCOI2003]严格N元树
  11. list scala 当前位置 遍历_Scala学习七之集合了解
  12. linux怎么查看vip地址,rac环境vip在linux下的连接信息
  13. 用给出的Cramer规则解线性方程组
  14. C语言求解圆周率近似值
  15. LTE基本结构(常见接口)
  16. spring configuration注解原理
  17. VS应用程序无法正常启动0xc0150002
  18. Micrium 开放了µC/OS-III源代码
  19. /*CS5460_Note_3*/
  20. 苹果开发 笔记(69)SVProgressHUD

热门文章

  1. 【渝粤教育】国家开放大学2018年秋季 2745T农村经济管理 参考试题
  2. lambda表达式双冒号使用条件_java_java基础_lambda表达式双冒号用法
  3. Ubuntu18.04 64 位系统 安装32位支持库
  4. 系统工作开发流程规范
  5. ffmpeg 硬件加速 wmv 视频转码
  6. vue支付宝html,vue 解决在微信内置浏览器中调用支付宝支付的情况
  7. xctf攻防世界 MISC高手进阶区 打野
  8. Android高仿苹果计算器
  9. cve-2019-0192一把梭
  10. 计算机基础知识在教学的应用,计算机基础知识中项目教学法的应用