当前位置: 首页 > news >正文

【FATFS】f_mount函数详细解析

 FATFS f_mount函数详细解析

    f_mount 函数是 FatFs 文件系统库中的一个关键函数,主要用于挂载卸载一个逻辑卷(文件系统)。它的作用是将一个文件系统对象与一个逻辑驱动器关联起来,使得后续的文件操作能够在该驱动器上进行。

FRESULT f_mount (FATFS* fs,            /* 指向文件系统对象的指针 (如果为 NULL 表示卸载) */const TCHAR* path,    /* 要挂载或卸载的逻辑驱动器号 */BYTE opt              /* 挂载选项:0 = 延迟挂载,1 = 立即挂载 */
)
{FATFS *cfs;int vol;FRESULT res;const TCHAR *rp = path;/* 获取逻辑驱动器号 */vol = get_ldnumber(&rp);if (vol < 0) return FR_INVALID_DRIVE;  /* 如果驱动器号无效,返回错误代码 */cfs = FatFs[vol];  /* 获取当前卷的文件系统对象指针 */if (cfs) {  /* 如果当前卷已经注册了文件系统对象,执行卸载操作 */FatFs[vol] = 0;  /* 将当前卷的文件系统对象置空 */
#if FF_FS_LOCKclear_share(cfs); /* 清除与该卷相关的文件锁 */
#endif
#if FF_FS_REENTRANT  /* 如果启用了可重入性支持 */ff_mutex_delete(vol); /* 删除卷的互斥锁 */
#endifcfs->fs_type = 0;  /* 将文件系统类型设置为0,表示该文件系统对象已失效 */}if (fs) {  /* 如果提供了新的文件系统对象 fs,则注册该对象 */fs->pdrv = LD2PD(vol); /* 设置卷的物理驱动器号 */
#if FF_FS_REENTRANT  /* 如果启用了可重入性支持 */fs->ldrv = (BYTE)vol;  /* 设置卷的逻辑驱动器号 */if (!ff_mutex_create(vol)) return FR_INT_ERR; /* 创建卷的互斥锁 */
#if FF_FS_LOCKif (SysLock == 0) {  /* 如果系统锁还未创建,则创建系统锁 */if (!ff_mutex_create(FF_VOLUMES)) {ff_mutex_delete(vol); /* 创建失败时删除卷的互斥锁 */return FR_INT_ERR;    /* 返回内部错误 */}SysLock = 1; /* 设置系统锁已就绪的标志 */}
#endif
#endiffs->fs_type = 0; /* 将新文件系统对象的类型设置为 0(无效状态) */FatFs[vol] = fs; /* 将新文件系统对象注册到对应的逻辑驱动器号 */}if (opt == 0) return FR_OK; /* 如果 opt 为 0,表示不立即挂载,返回成功 */res = mount_volume(&path, &fs, 0); /* 强制挂载该卷 */LEAVE_FF(fs, res); /* 返回挂载结果 */
}

在代码中可以看到,核心的代码就是mount_volume

static FRESULT mount_volume (	/* FR_OK(0): 成功,!=0: 发生错误 */const TCHAR** path,			/* 指向路径名称的指针(含驱动器号) */FATFS** rfs,				/* 指向找到的文件系统对象的指针 */BYTE mode					/* 要检查的访问模式(是否需要写保护) */
)
{int vol;                    /* 逻辑驱动器号 */FATFS *fs;                  /* 文件系统对象指针 */DSTATUS stat;               /* 物理驱动器状态 */LBA_t bsect;                /* 起始扇区号 */DWORD tsect, sysect, fasize, nclst, szbfat; /* 用于存储文件系统的相关信息 */WORD nrsv;                  /* 保留扇区数 */UINT fmt;                   /* 文件系统格式 (FAT12, FAT16, FAT32, exFAT) *//* 获取逻辑驱动器号 */*rfs = 0;                    /* 初始化返回的文件系统对象指针为 NULL */vol = get_ldnumber(path);     /* 从路径中获取逻辑驱动器号 */if (vol < 0) return FR_INVALID_DRIVE;  /* 如果驱动器号无效,返回错误 *//* 检查文件系统对象是否有效 */fs = FatFs[vol];				/* 获取当前逻辑卷的文件系统对象 */if (!fs) return FR_NOT_ENABLED; /* 如果文件系统对象不可用,返回错误 */
#if FF_FS_REENTRANTif (!lock_volume(fs, 1)) return FR_TIMEOUT; /* 锁定该卷以确保多线程环境下的安全性 */
#endif*rfs = fs;					/* 返回文件系统对象指针 */mode &= (BYTE)~FA_READ;		/* 检查是否需要写访问模式 */if (fs->fs_type != 0) {		/* 如果文件系统已经挂载 */stat = disk_status(fs->pdrv); /* 获取物理驱动器状态 */if (!(stat & STA_NOINIT)) {	/* 检查驱动器是否已经初始化 */if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* 检查写保护 */return FR_WRITE_PROTECTED; /* 如果写保护,返回错误 */}return FR_OK;		/* 文件系统对象有效,返回成功 */}}/* 文件系统对象无效,尝试挂载该卷 */fs->fs_type = 0;				/* 将文件系统对象标记为无效 */stat = disk_initialize(fs->pdrv);	/* 初始化物理驱动器 */if (stat & STA_NOINIT) { 		/* 检查初始化是否成功 */return FR_NOT_READY;		/* 驱动器未准备好,返回错误 */}if (!FF_FS_READONLY && mode && (stat & STA_PROTECT)) { /* 检查写保护 */return FR_WRITE_PROTECTED;}
#if FF_MAX_SS != FF_MIN_SS				/* 如果支持多种扇区大小 */if (disk_ioctl(fs->pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK) return FR_DISK_ERR; /* 获取扇区大小 */if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; /* 扇区大小不合法 */
#endif/* 查找 FAT 卷 */fmt = find_volume(fs, LD2PT(vol)); /* 尝试识别文件系统格式 */if (fmt == 4) return FR_DISK_ERR;		/* 如果发生磁盘 I/O 错误,返回错误 */if (fmt >= 2) return FR_NO_FILESYSTEM;	/* 没有找到有效的 FAT 文件系统,返回错误 */bsect = fs->winsect;					/* 存储文件系统的起始扇区 *//* 初始化 FAT 文件系统对象 */
#if FF_FS_EXFATif (fmt == 1) { /* 如果是 exFAT 文件系统 */QWORD maxlba;DWORD so, cv, bcl, i;/* 检查 exFAT 的 BPB (BIOS Parameter Block) */for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ;	/* 检查填充区是否为零 */if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM; /* 如果不是,返回错误 */if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM;	/* 检查 exFAT 版本是否为 1.0 *//* 检查扇区大小是否正确 */if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) {	return FR_NO_FILESYSTEM;}maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect;	/* 获取卷的最后一个 LBA 扇区 */if (!FF_LBA64 && maxlba >= 0x100000000) return FR_NO_FILESYSTEM;	/* 超过 32 位 LBA 限制,返回错误 */fs->fsize = ld_dword(fs->win + BPB_FatSzEx);	/* 获取 FAT 区大小 */fs->n_fats = fs->win[BPB_NumFATsEx];			/* 获取 FAT 数量 */if (fs->n_fats != 1) return FR_NO_FILESYSTEM;	/* 仅支持单 FAT */fs->csize = 1 << fs->win[BPB_SecPerClusEx];		/* 获取簇大小 */if (fs->csize == 0)	return FR_NO_FILESYSTEM;	/* 簇大小无效,返回错误 */nclst = ld_dword(fs->win + BPB_NumClusEx);		/* 获取簇的总数 */if (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM;	/* 超过最大簇数,返回错误 */fs->n_fatent = nclst + 2; /* 设置 FAT 表条目数 *//* 设置卷的边界和限制 */fs->volbase = bsect;fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx); /* 数据区起始扇区 */fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx);	 /* FAT 区起始扇区 */if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* 检查卷大小是否足够 */fs->dirbase = ld_dword(fs->win + BPB_RootClusEx); /* 根目录起始簇 *//* 检查位图是否连续 */so = i = 0;for (;;) {	/* 在根目录中查找位图条目 */if (i == 0) {if (so >= fs->csize) return FR_NO_FILESYSTEM;	/* 没有找到位图条目,返回错误 */if (move_window(fs, clst2sect(fs, (DWORD)fs->dirbase) + so) != FR_OK) return FR_DISK_ERR;so++;}if (fs->win[i] == ET_BITMAP) break; /* 找到位图条目 */i = (i + SZDIRE) % SS(fs); /* 继续寻找下一个条目 */}bcl = ld_dword(fs->win + i + 20);	/* 获取位图所在的簇 */if (bcl < 2 || bcl >= fs->n_fatent) return FR_NO_FILESYSTEM;	/* 无效簇号,返回错误 */fs->bitbase = fs->database + fs->csize * (bcl - 2);	/* 位图起始扇区 *//* 检查位图是否连续 */for (;;) {	if (move_window(fs, fs->fatbase + bcl / (SS(fs) / 4)) != FR_OK) return FR_DISK_ERR;cv = ld_dword(fs->win + bcl % (SS(fs) / 4) * 4); /* 读取 FAT 条目 */if (cv == 0xFFFFFFFF) break;	/* 如果到达最后一个条目,退出循环 */if (cv != ++bcl) return FR_NO_FILESYSTEM;	/* 位图不是连续的,返回错误 */}#if !FF_FS_READONLYfs->last_clst = fs->free_clst = 0xFFFFFFFF; /* 初始化簇分配信息 */
#endiffmt = FS_EXFAT;	/* 设置为 exFAT 文件系统 */} else
#endif /* FF_FS_EXFAT */{/* FAT12/16/32 文件系统初始化 */if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM;	/* 检查扇区大小是否匹配 */fasize = ld_word(fs->win + BPB_FATSz16);	/* 获取 FAT 区大小 */if (fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32); /* 如果是 FAT32,使用更大的大小字段 */fs->fsize = fasize;fs->n_fats = fs->win[BPB_NumFATs]; /* 获取 FAT 区数量 */if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM; /* FAT 数量必须为 1 或 2 */fs->csize = fs->win[BPB_SecPerClus]; /* 获取每簇扇区数 */if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM; /* 检查簇大小是否为 2 的幂 */fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* 获取根目录项数 */if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* 检查根目录项数是否对齐 */tsect = ld_word(fs->win + BPB_TotSec16); /* 获取卷的总扇区数 */if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32);nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* 获取保留扇区数 */if (nrsv == 0) return FR_NO_FILESYSTEM; /* 保留扇区数不能为 0 *//* 确定 FAT 文件系统类型(FAT12、FAT16、FAT32) */sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* 计算系统区大小 */if (tsect < sysect) return FR_NO_FILESYSTEM; /* 扇区数不足,返回错误 */nclst = (tsect - sysect) / fs->csize; /* 计算簇的数量 */if (nclst == 0) return FR_NO_FILESYSTEM; /* 无效簇数,返回错误 */fmt = 0;if (nclst <= MAX_FAT32) fmt = FS_FAT32; /* 符合 FAT32 标准 */if (nclst <= MAX_FAT16) fmt = FS_FAT16; /* 符合 FAT16 标准 */if (nclst <= MAX_FAT12) fmt = FS_FAT12; /* 符合 FAT12 标准 */if (fmt == 0) return FR_NO_FILESYSTEM; /* 无法识别文件系统类型 *//* 设置文件系统对象的边界和限制 */fs->n_fatent = nclst + 2; /* FAT 表中的条目数 */fs->volbase = bsect; /* 卷的起始扇区 */fs->fatbase = bsect + nrsv; /* FAT 区的起始扇区 */fs->database = bsect + sysect; /* 数据区的起始扇区 */if (fmt == FS_FAT32) { /* 如果是 FAT32 */if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* 检查 FAT32 版本 */fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* 根目录起始簇 */szbfat = fs->n_fatent * 4; /* 计算 FAT 大小 */} else {fs->dirbase = fs->fatbase + fasize; /* 根目录的起始扇区 */szbfat = (fmt == FS_FAT16) ? /* 计算 FAT 大小 */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; /* FAT 大小不足,返回错误 */#if !FF_FS_READONLY/* 获取 FSInfo 信息(如果可用) */fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* 初始化簇分配信息 */fs->fsi_flag = 0x80;
#if (FF_FS_NOFSINFO & 3) != 3if (fmt == FS_FAT32 && ld_word(fs->win + BPB_FSInfo32) == 1 && move_window(fs, bsect + 1) == FR_OK) {/* 检查并加载 FSInfo 数据 */fs->fsi_flag = 0;if (ld_word(fs->win + BS_55AA) == 0xAA55 && ld_dword(fs->win + FSI_LeadSig) == 0x41615252&& ld_dword(fs->win + FSI_StrucSig) == 0x61417272) {
#if (FF_FS_NOFSINFO & 1) == 0fs->free_clst = ld_dword(fs->win + FSI_Free_Count);
#endif
#if (FF_FS_NOFSINFO & 2) == 0fs->last_clst = ld_dword(fs->win + FSI_Nxt_Free);
#endif}}
#endif /* (FF_FS_NOFSINFO & 3) != 3 */
#endif /* !FF_FS_READONLY */}fs->fs_type = (BYTE)fmt; /* 设置文件系统类型 */fs->id = ++Fsid; /* 增加文件系统的挂载 ID */
#if FF_USE_LFN == 1fs->lfnbuf = LfnBuf; /* 为长文件名分配缓冲区 */
#if FF_FS_EXFATfs->dirbuf = DirBuf; /* 为 exFAT 分配目录缓冲区 */
#endif
#endif
#if FF_FS_RPATH != 0fs->cdir = 0; /* 初始化当前目录为根目录 */
#endif
#if FF_FS_LOCKclear_share(fs); /* 清除文件锁 */
#endifreturn FR_OK; /* 挂载成功,返回 FR_OK */
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Python+Pytest框架,“api_key.py文件怎么编写“?
  • Ubuntu下beanstalkd无法绑定局域网IP地址以及消息队列beanstalkd上的error: JOB_TOO_BIG的解决
  • ZYNQ LWIP(RAW API) TCP函数学习
  • 每日OJ_牛客_点击消除(栈)
  • 反激电路中TL431光耦反馈参数的计算,环路设计思路
  • Stream流的思想和获取Stream流
  • 极越造车2.0:01销量回暖,07杀出血路,ASD抢跑FSD
  • 实战外网配置——光猫桥接+路由器PPPoE拨号+防火墙外网链路健康检查+外网流量负载均衡
  • 【Go】-基于Gin和GORM的小清单项目
  • PPStructure核心源码研究(三)LayoutPredictor类详解
  • 昇思MindSpore AI框架MindFormers实践3:ChatGLM3-6B对一段文字进行提取
  • Qt 边框border - qss样式
  • 如何从github上clone项目
  • 品牌借势华为三折叠手机上市热点文案
  • 基于Java+Mysql实现(web)大型企业管理系统
  • Android系统模拟器绘制实现概述
  • Flex布局到底解决了什么问题
  • SpringBoot 实战 (三) | 配置文件详解
  • Stream流与Lambda表达式(三) 静态工厂类Collectors
  • Vim 折腾记
  • 基于axios的vue插件,让http请求更简单
  • 检测对象或数组
  • 聊聊directory traversal attack
  • 容器服务kubernetes弹性伸缩高级用法
  • 想晋级高级工程师只知道表面是不够的!Git内部原理介绍
  • 在 Chrome DevTools 中调试 JavaScript 入门
  • HanLP分词命名实体提取详解
  • ​【数据结构与算法】冒泡排序:简单易懂的排序算法解析
  • ​ArcGIS Pro 如何批量删除字段
  • ​数据链路层——流量控制可靠传输机制 ​
  • # Java NIO(一)FileChannel
  • # Maven错误Error executing Maven
  • # Panda3d 碰撞检测系统介绍
  • (2)STM32单片机上位机
  • (2015)JS ES6 必知的十个 特性
  • (52)只出现一次的数字III
  • (翻译)terry crowley: 写给程序员
  • (附源码)SSM环卫人员管理平台 计算机毕设36412
  • (附源码)ssm经济信息门户网站 毕业设计 141634
  • (附源码)ssm学生管理系统 毕业设计 141543
  • (四) Graphivz 颜色选择
  • (四)Controller接口控制器详解(三)
  • (四)js前端开发中设计模式之工厂方法模式
  • (转)c++ std::pair 与 std::make
  • (转)linux下的时间函数使用
  • .Net - 类的介绍
  • .Net Core 微服务之Consul(二)-集群搭建
  • .net 无限分类
  • .NET/C# 避免调试器不小心提前计算本应延迟计算的值
  • .net程序集学习心得
  • .net中我喜欢的两种验证码
  • .stream().map与.stream().flatMap的使用
  • @SuppressLint(NewApi)和@TargetApi()的区别
  • [ A*实现 ] C++,矩阵地图
  • [2019红帽杯]Snake