fatfs文件系统源码分析

fatfs文件系统源码分析
fatfs文件系统源码分析

fatfs文件系统源码分析

一、概述

1、目的

在移植之前,先将源代码大概的阅读一遍,主要是了解文件系统的结构、各个函数的功能和接口、与移植相关的代码等等。

2、准备工作

在官方网站下载了0.07c版本的源代码,利用记事本进行阅读。

二、源代码的结构

1、源代码组成

源代码压缩包解压后,共两个文件夹,doc是说明,src里就是代码。src文件夹里共五个文件和一个文件夹。文件夹是option,还有00readme.txt、diskio.c、diskio.h、ff.c、ff.h、integer.h。对比网上的文章,版本已经不同了,已经没有所谓的tff.c和tff.h了,估计现在都采用条件编译解决这个问题了,当然文件更少,可能编译选项可能越复杂。

2、00readme.txt的说明

Low level disk I/O module is not included in this archive because the FatFs module is only a generic file system layer and not depend on any specific storage device. You have to provide a low level disk I/O module that written to control your storage device.主要是说不包含底层IO代码,这是个通用文件系统可以在各种介质上使用。我们移植时针对具体存储设备提供底层代码。接下来做了版权声明-可以自由使用和传播。然后对版本的变迁做了说明。

3、源代码阅读次序

先读integer.h,了解所用的数据类型,然后是ff.h,了解文件系统所用的数据结构和各种函数声明,然后是diskio.h,了解与介质相关的数据结构和操作函数。再把ff.c和diskio.c两个文件所实现的函数大致扫描一遍。最后根据用户应用层程序调用函数的次序仔细阅读相关代码。

三、源代码阅读

1、integer.h头文件

这个文件主要是类型声明。以下是部分代码。

typedef int INT;

typedef unsigned int UINT;

typedef signed char CHAR;/* These types must be 8-bit integer */

都是用typedef做类型定义。移植时可以修改这部分代码,特别是某些定义与你所在工程的类型定义有冲突的时候。

2、ff.h头文件

以下是部分代码的分析

#include “integer.h”使用integer.h的类型定义

#ifndef _FATFS

#define _FATFS 0x007C 版本号007c,0.07c

#define _WORD_ACCESS 0 //如果定义为1,则可以使用word访问。中间有一些看着说明很容易弄清楚意思。这里就不例举了。

#define _CODE_PAGE 936

/* The _CODE_PAGE specifies the OEM code page to be used on the target system. / 936 – Simplified Chinese GBK (DBCS, OEM, Windows)跟据这个中国应该是936.

打开option文件夹看一下。打开cc936.c文件,里面有一个很大的数组static const WCHAR uni2oem[] 。

根据英文说明,这个数组用于unicode码和OEM码之间的相互转换。

接下来又有两个函数ff_convert()和ff_wtoupper()具体执行码型转换和将字符转换为大写。百度一下:看OEM码什么意思。

unicode是一种双字节字符编码,无论中文还是英文,或者其他语言统一到2个字节。与现有的任何编码(ASCII,GB等)都不兼容。WindowsNT(2000)的内核即使用该编码,所有数据进入内核前转换成UNICODE,退出内核后在转换成版本相关的编码(通常称为OEM,在简体中文版下即为GB).(百度所得)

继续往下阅读。

#define _USE_LFN 1 //这个估计是长文件名支持了,以前的0.06版本好像是不支持。#define _MAX_LFN 255 //最长支持255个双字节字符。

#define _FS_RPATH 0 //是否文件相对路径选项。

/* When _FS_RPATH is set to 1, relative path feature is enabled and f_chdir,

/ f_chdrive function are available. //有些函数会受影响。

/ Note that output of the f_readdir fnction is affected by this option. */

#define _FS_REENTRANT 0 //如果要支持文件系统可重入,必须加入几个函数。

#define _TIMEOUT 1000 /* Timeout period in unit of time ticks of the OS */

#define _SYNC_t HANDLE /* Type of sync object used on the OS. e.g. HANDLE,

OS_EVENT*, ID and etc.. */

/* To make the FatFs module re-entrant, set _FS_REENTRANT to 1 and add user / provided synchronization handlers, ff_req_grant, ff_rel_grant, ff_del_syncobj / and ff_cre_syncobj function to the project. */

#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */

#define _DF1S 0×81

#define _DF1E 0xFE

#define _DS1S 0×40

#define _DS1E 0x7E

#define _DS2S 0×80

#define _DS2E 0xFE

接下来很大一部分都是与语言相关的因素,略过。

/* Character code support macros */ 三个宏判断是否大写、小写、数字。

#define IsUpper(c) (((c)>=’A')&&((c)<=’Z'))

#define IsLower(c) (((c)>=’a')&&((c)<=’z'))

#define IsDigit(c) (((c)>=’0′)&&((c)<=’9′))

#if _DF1S /* DBCS configuration */双字节编码相关的设定,暂时不理会它。

#if _MULTI_PARTITION /* Multiple partition configuration */

//该变量定义为1时,支持一个磁盘的多个分区。

typedef struct _PARTITION {

BYTE pd; /* Physical drive# */

BYTE pt; /* Partition # (0-3) */

} PARTITION;

Extern const PARTITION Drives[];//如果支持分区,则声明变量Drivers

#define LD2PD(drv) (Drives[drv].pd) /* 获得磁盘对应的物理磁盘

#define LD2PT(drv) (Drives[drv].pt) /*获得磁盘对应的分区

#else /* Single partition configuration */

#define LD2PD(drv) (drv) /* Physical drive# is equal to the logical drive# */ #define LD2PT(drv) 0 /* Always mounts the 1st partition */

#if _MAX_SS == 512 //一般扇区长度取512字节。

#define SS(fs) 512U

#if _LFN_UNICODE && _USE_LFN

typedef WCHAR XCHAR; /* Unicode */ XCHAR是文件名的码型所用。

#else

typedef char XCHAR; /* SBCS, DBCS */

#endif

typedef struct _FATFS_ {

BYTE fs_type; /* FAT sub type */

BYTE drive; /*对应实际驱动号01— */

BYTE csize; /* 每个簇的扇区数目*/

先查一下簇的含义:应该是文件数据分配的基本单位。

BYTE n_fats; /* 文件分配表的数目*/

FAT文件系统依次应该是:引导扇区、文件分配表两个、根目录区和数据区。

BYTE wflag; /* win[] dirty flag (1:must be written back) */ //文件是否改动的标志,为1时要回写。

WORD id; /* File system mount ID 文件系统加载ID*/

WORD n_rootdir; /* 根目录区目录项的数目*/

#if _FS_REENTRANT

_SYNC_t sobj; /* 允许重入,则定义同步对象*/

#endif

#if _MAX_SS != 512

WORD s_size; /* Sector size */

#endif

#if !_FS_READONLY //文件为可写

BYTE fsi_flag; /* fsinfo dirty flag (1:must be written back) */

//文件需要回写的标志

DWORD last_clust; /* Last allocated cluster */

DWORD free_clust; /* Number of free clusters */

DWORD fsi_sector; /* fsinfo sector */

#endif

#if _FS_RPATH

DWORD cdir; /* 使用相对路径,则要存储文件系统当前目录

#endif

DWORD sects_fat; /*文件分配表占用的扇区

DWORD max_clust; /* 最大簇数

DWORD fatbase; /*文件分配表开始扇区

DWORD dirbase; /* 如果是FAT32,根目录开始扇区需要首先得到。

DWORD database; /* 数据区开始扇区

DWORD winsect; /* Current sector appearing in the win[] */

//目前的扇区在win[]里面,这个win[]数组暂时还不知道含义。

BYTE win[_MAX_SS];/* Disk access window for Directory/FAT */

//这是一个win[512]数组,存储着一个扇区,好像作为扇区缓冲使用。

} FATFS;

typedef struct _DIR_ {

FATFS* fs;/* Pointer to the owner file system object */指向相应文件系统对象。

WORD id; /* 文件系统加载ID*/

WORD index; /* Current read/write index number */目前读写索引代码

DWORD sclust; /* Table start cluster (0:Static table) */文件数据区开始簇DWORD clust; /* Current cluster */ 目前处理的簇

DWORD sect; /* Current sector */ 目前簇里对应的扇区

BYTE* dir; /* Pointer to the current SFN entry in the win[] */

BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */ #if _USE_LFN

WCHAR* lfn; /* Pointer to the LFN working buffer */ 指向长文件名缓冲。

WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */

#endif

} DIR;

typedef struct _FIL_ {

FATFS* fs; /* Pointer to the owner file system object */

WORD id; /* Owner file system mount ID */

BYTE flag; /* File status flags */文件状态标志

BYTE csect; /* Sector address in the cluster */扇区偏移

DWORD fptr; /* File R/W pointer */ 读写指针

DWORD fsize; /* File size */

DWORD org_clust; /* File start cluster */文件开始簇

DWORD curr_clust; /* Current cluster */当前簇

DWORD dsect; /* Current data sector */文件当前扇区

#if !_FS_READONLY

DWORD dir_sect; /* Sector containing the directory entry */该文件目录项对应所在的扇区

BYTE* dir_ptr; /* Ponter to the directory entry in the window */

#endif

#if !_FS_TINY

BYTE buf[_MAX_SS];/* File R/W buffer */文件读写缓冲

#endif

} FIL;

/* File status structure */

typedef struct _FILINFO_ {

DWORD fsize; /* File size */

WORD fdate; /* Last modified date */

WORD ftime; /* Last modified time */

BYTE fattrib; /* Attribute */

char fname[13]; /* Short file name (8.3 format) */

#if _USE_LFN

XCHAR* lfname; /* Pointer to the LFN buffer */

int lfsize; /* Size of LFN buffer [chrs] */

#endif

} FILINFO; 这个结构主要描述文件的状态信息,包括文件名13个字符(8+.+3+\0)、属性、修改时间等。

接下来是函数的定义,先大概浏览一遍。

FRESULT f_mount (BYTE, FATFS*); //加载文件系统,BYTE参数是ID,后一个是文件系统定义。

FRESULT f_open (FIL*, const XCHAR*, BYTE);//打开文件,第一个参数是文件信息结构,第二个参数是文件名,第三是文件打开模式

FRESULT f_read (FIL*, void*, UINT, UINT*); //文件读取函数,参数1为文件对象(文件打开函数中得到),参数2为文件读取缓冲区,参数3为读取的字节数,参数4意义不清晰,等读到源代码就清楚了。

FRESULT f_write (FIL*, const void*, UINT, UINT*);//写文件,参数跟读差不多FRESULT f_lseek (FIL*, DWORD); //移动文件的读写指针,参数2应该是移动的数目。FRESULT f_close (FIL*); /* Close an open file object */

FRESULT f_opendir (DIR*, const XCHAR*); 打开目录,返回目录对象

FRESULT f_readdir (DIR*, FILINFO*); 读取目录,获得文件信息

FRESULT f_stat (const XCHAR*, FILINFO*); /* Get file status */ FRESULT f_getfree (const XCHAR*, DWORD*, FATFS**); /* Get number of free clusters on the drive */

FRESULT f_truncate (FIL*); /* Truncate file */

FRESULT f_sync (FIL*); /* Flush cached data of a writing file */将缓冲区数据写回文件FRESULT f_unlink (const XCHAR*); 删除目录中的一个文件

FRESULT f_mkdir (const XCHAR*); /* Create a new directory */ FRESULT f_chmod (const XCHAR*, BYTE, BYTE); /* Change attriburte of the file/dir */ FRESULT f_utime (const XCHAR*, const FILINFO*); /* Change timestamp of the file/dir */

FRESULT f_rename (const XCHAR*, const XCHAR*); /* Rename/Move a file or directory */

FRESULT f_forward (FIL*, UINT(*)(const BYTE*,UINT), UINT, UINT*); /* Forward data to the stream */ 这个函数还要提供一个回调函数。

FRESULT f_mkfs (BYTE, BYTE, WORD); /* Create a file system on the drive */ FRESULT f_chdir (const XCHAR*); /* Change current directory */改变当前目录FRESULT f_chdrive (BYTE); /* Change current drive */

应该说基本能明白这些函数用于干什么。

#if _USE_STRFUNC

int f_putc (int, FIL*); /* Put a character to the file */ int f_puts (const char*, FIL*); /* Put a string to the file */ int f_printf (FIL*, const char*, …); /* Put a formatted string to the file */

char* f_gets (char*, int, FIL*); /* Get a string from the file */

#define f_eof(fp) (((fp)->fptr == (fp)->fsize) ? 1 : 0)

#define f_error(fp) (((fp)->flag & FA__ERROR) ? 1 : 0)

#if _FS_REENTRANT //如果定义了重入,则需要实现以下四个函数

BOOL ff_cre_syncobj(BYTE, _SYNC_t*); 创建同步对象

BOOL ff_del_syncobj(_SYNC_t); 删除同步对象

BOOL ff_req_grant(_SYNC_t); 申请同步对象

void ff_rel_grant(_SYNC_t); 释放同步对象。

#endif

3、diskio.h文件

typedef BYTE DSTATUS;

typedef DRESULT; //首先定义了两个变量,各个函数都有用到。

BOOL assign_drives (int argc, char *argv[]); //这个函数不知道干吗

DSTATUS disk_initialize (BYTE); //磁盘初始化

DSTATUS disk_status (BYTE); //获取磁盘状态

DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);

#if _READONLY == 0

DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);

#endif

DRESULT disk_ioctl (BYTE, BYTE, void*); //磁盘控制

接下来还有一些常数的定义,具体用到时在看。

4、diskio.c的结构

DSTATUS disk_initialize ( BYTE drv /* Physical drive nmuber (0..) */) {

DSTATUS stat;

int result;

switch (drv) {

case ATA :

result = ATA_disk_initialize();

// translate the reslut code here

return stat;

case MMC :

result = MMC_disk_initialize();

// translate the reslut code here

return stat;

case USB :

result = USB_disk_initialize();

// translate the reslut code here

return stat;

}

return STA_NOINIT;

}

函数基本都像这样,drv表示磁盘的类型。没有实现,用户必须实现这部分代码。5、ff.c文件简单浏览

#include “ff.h”/* FatFs configurations and declarations */

#include “diskio.h”/* Declarations of low level disk I/O functions */

#define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; } //获取文件系统同步对象,不成功返回超时,成功,继续执行。

#define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } //释放文件系统同步对象。

Static FATFS *FatFs[_DRIVES]; //定义一个文件系统对象指针数组,当然一般我们也就用到一个元素。

Static WORD LfnBuf[_MAX_LFN + 1]; //这个是与长文件名支持相关的。

#define NAMEBUF(sp,lp) BYTE sp[12]; WCHAR *lp = LfnBuf

#define INITBUF(dj,sp,lp) dj.fn = sp; dj.lfn = lp

下面都是函数的定义,很多只在内部使用。

Static void mem_cpy (void* dst, const void* src, int cnt) {

char *d = (char*)dst;

const char *s = (const char *)src;

while (cnt–) *d++ = *s++;

} //接下来还定义了几个内存操作的函数,这个函数实现了从一块内存到另一块的复制,下面还有mem_set()对一块内存进行清0或设置操作;mem_cmp()比较内存的多个字节是否相同,相同返回0;chk_chr()检测字符串中是否存在某个字符,存在则返回该字符。

FRESULT move_window (

FATFS *fs, /* File system object */

DWORD sector /* Sector number to make apperance in the fs->win[] */

)//简单阅读了一下源代码,应该是改变文件系统的当前工作扇区,如果想要操作的扇区就是当前扇区,什么事不做;如果不是,则将原扇区写回;如果是FAT表,还得写入备份区。这个函数内部使用,外部无法引用。

FRESULT sync ( /* FR_OK: successful, FR_DISK_ERR: failed */

FATFS *fs /* File system object */

)//这个函数用于更新FAT32文件系统的FSI_Sector。什么含义还不太清楚。

DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Interal error, Else:Cluster status */ FATFS *fs, /* File system object */

DWORD clst /* Cluster# to get the link information */

)

if (move_window(fs, fsect + (clst / (SS(fs) / 4)))) break; 获取簇号码对应的FAT扇区

return LD_DWORD(&fs->win[((WORD)clst * 4) & (SS(fs) - 1)]) & 0x0FFFFFFF; //这个函数应该是获取簇的下一个连接簇。

综合起来,这个函数应该是获取下一簇,感觉这个函数名起得不太好。get_nextcluster感觉更好一点。

FRESULT put_fat (

FATFS *fs, /* File system object */

DWORD clst, /* Cluster# to be changed in range of 2 to fs->max_clust – 1 */

DWORD val /* New value to mark the cluster */

)//上个函数是获取连接簇,这个是写入新的连接信息。

FRESULT remove_chain (

FATFS *fs, /* File system object */

DWORD clst /* Cluster# to remove a chain from */

)//将下一簇号写为0,也就是该文件的簇到此为止,同时系统的自由簇增加1. DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */

FATFS *fs, /* File system object */

DWORD clst /* Cluster# to stretch. 0 means create a new chain. */ )//跟上一个相反,在该簇的位置写入新的下一簇簇号。

DWORD clust2sect ( /* !=0: Sector number, 0: Failed – invalid cluster# */ FATFS *fs, /* File system object */

DWORD clst /* Cluster# to be converted */

) //这个函数是将簇号转变为对应的扇区号。

clst * fs->csize + fs->database; //这个是算法

FRESULT dir_seek (

DIR *dj, /* Pointer to directory object */

WORD idx /* Directory index number */

)//这个函数的最终目的是根据索引号找到目录项所在簇、所在扇区、并是目录对象的对象指针指向文件系统对象窗口扇区的对应位置。

FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:EOT and could not streach */

DIR *dj, /* Pointer to directory object */

BOOL streach /* FALSE: Do not streach table, TRUE: Streach table if needed /

) //移动当前目录项,根据索引,源代码简单看了一下,作用还不是很清晰,先放过。

接下来有5个函数与长文件名有关,这里先跳过。

FRESULT dir_find (

DIR *dj /* Pointer to the directory object linked to the file name */ )//

FRESULT dir_read (

DIR *dj /* Pointer to the directory object that pointing the entry to be read */

)

FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many SFN collision, FR_DISK_ERR:Disk error */

DIR *dj /* Target directory with object name to be created */ )

FRESULT dir_remove ( /* FR_OK: Successful, FR_DISK_ERR: A disk error */ DIR *dj /* Directory object pointing the entry to be removed */ )

//以上这些函数都是对目录项的操作函数。

FRESULT create_name (

DIR *dj, /* Pointer to the directory object */

const XCHAR **path /* Pointer to pointer to the segment in the path string */)

//这个函数太长了,具体用到的时候再说吧。

void get_fileinfo ( /* No return code */

DIR *dj, /* Pointer to the directory object */

FILINFO *fno /* Pointer to store the file information */)

该函数用于获取文件状态信息。主要是从文件的目录项中获取信息。

FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ DIR *dj, /* Directory object to return last directory and found object */

const XCHAR *path /* Full-path string to find a file or directory */

)

该函数给定一个全路径,得到相应的目录对象。

BYTE check_fs ( /* 0:The FAT boot record, 1:Valid boot record but not an FAT,

2:Not a boot record, 3:Error */

FATFS *fs, /* File system object */

DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */) 该函数用于读取BOOT扇区,检查是否FAT文件系统。

FRESULT auto_mount ( /* FR_OK(0): successful, !=0: any error occured */ const XCHAR **path, /* Pointer to pointer to the path name (drive number) */

FATFS **rfs, /* Pointer to pointer to the found file system object */

BYTE chk_wp /* !=0: Check media write protection for write access */)

这个函数的功能不太明白。

FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */

FATFS *fs, /* Pointer to the file system object */

WORD id /* Member id of the target object to be checked */

操作系统课程设计-模拟文件系统

目录 第1章需求分析 (1) 第2章概要设计 (1) 系统的主要功能 (1) 系统模块功能结构 (1) 运行环境要求 (2) 数据结构设计 (2) 第3章详细设计 (3) 模块设计 (3) 算法流程图 (3) 第4章系统源代码 (4) 第5章系统测试及调试 (4) 运行结果及分析 (4) 系统测试结论 (5) 第6章总结与体会 (6) 第7章参考文献 (6) 附录 (7)

第1章需求分析 通过模拟文件系统的实现,深入理解操作系统中文件系统的理论知识, 加深对教材中的重要算法的理解。同时通过编程实现这些算法,更好地掌握操作系统的原理及实现方法,提高综合运用各专业课知识的能力;掌握操作系统结构、实现机理和各种典型算法,系统地了解操作系统的设计和实现思路,并了解操作系统的发展动向和趋势。 模拟二级文件管理系统的课程设计目的是通过研究Linux的文件系统结构,模拟设计一个简单的二级文件系统,第一级为主目录文件,第二级为用户文件。 第2章概要设计 系统的主要功能 1) 系统运行时根据输入的用户数目创建主目录 2) 能够实现下列命令: Login 用户登录 Create 建立文件 Read 读取文件 Write 写入文件 Delete 删除文件 Mkdir 建立目录 Cd 切换目录 Logout 退出登录 系统模块功能结构

运行环境要求 操作系统windows xp ,开发工具vc++ 数据结构设计 用户结构:账号与密码结构 typedef struct users { char name[8]; char pwd[10]; }users; 本系统有8个默认的用户名,前面是用户名,后面为密码,用户登陆时只要输入正确便可进入系统,否则提示失败要求重新输入。 users usrarray[8] = { "usr1","usr1", "usr2","usr2", "usr3","usr3", "usr4","usr4",

Ext2数据块分配

Ext2数据块分配 跟索引节点一样,Ext2也对磁盘数据块进行分配与释放。在详细分析相关代码之前,先引出两个重要的预备,一个是数据块寻址,一个是文件的洞 1 数据块寻址 每个非空的普通文件都由一组数据块组成。这些块或者由文件内的相对位置(它们的文件块号)来标识,或者由磁盘分区内的位置(它们的逻辑块号)来标识。 从文件内的偏移量f 导出相应数据块的逻辑块号需要两个 步骤: 1. 从偏移量f导出文件的块号,即在偏移量f处的字符所在的块索引。 2. 把文件的块号转化为相应的逻辑块号。 因为Unix文件不包含任何控制字符,因此,导出文件的第f 个字符所在的文件块号当容易的,只是用f除以文件系统块

的大小,并取整即可。 例如,让我们假定块的大小为4KB。如果f小于4096,那么这个字符就在文件的第一数据块中,其文件的块号为O。如果f等于或大于4096而小于8192,则这个字符就在文件块号为1的数据块中,以此类推。 得到了文件的块号是第一步。但是,由于Ext2文件的数据块在磁盘上不必是相邻的,因此把文件的块号转化为相应的逻辑块号可不是这么直截了当的了。 因此,Ext2文件系统必须提供一种方法,用这种方法可以在磁盘上建立每个文件块号与相应逻辑块号之间的关系。在索引节点内部部分实现了这种映射(回到了 AT&T Unix的早期版本)。这种映射也涉及一些包含额外指针的专用块,这些块用来处理大型文件的索引节点的扩展。 ext2磁盘索引节点ext2_inode的i_block字段是一个有EXT2_N_BLOCKS个元素且包含逻辑块号的数组。在下面的讨论中, 我们假定EXT2_N_BLOCKS的默认值为15(实际上到2.6.18这个值都一直是15)。如图所示,这个数组表示一个大型数据结构的初始化部分。

LINUX文件系统制作详细

Linux文件系统制作流程 关键词:ARM Linux yaffs文件系统移植 Linux文件系统简介 Linux支持多种文件系统,包括ext2、ext3、vfat、ntfs、iso9660、jffs、romfs和nfs等,为了对各类文件系统进行统一管理,Linux引入了虚拟文件系统VFS(Virtual File System),为各类文件系统提供一个统一的操作界面和应用编程接口。 Linux下的文件系统结构如下: Linux启动时,第一个必须挂载的是根文件系统;若系统不能从指定设备上挂载根文件系统,则系统会出错而退出启动。之后可以自动或手动挂载其他的文件系统。因此,一个系统中可以同时存在不同的文件系统。 不同的文件系统类型有不同的特点,因而根据存储设备的硬件特性、系统需求等有不同的应用场合。在嵌入式Linux应用中,主要的存储设备为RAM(DRAM,

SDRAM)和ROM(常采用FLASH存储器),常用的基于存储设备的文件系统类型包括:jffs2,yaffs,cramfs,romfs,ramdisk,ramfs/tmpfs等。 >基于FLASH的文件系统 Flash(闪存)作为嵌入式系统的主要存储媒介,有其自身的特性。Flash的写入操作只能把对应位置的1修改为0,而不能把0修改为1(擦除Flash就是把对应存储块的内容恢复为1),因此,一般情况下,向Flash写入内容时,需要先擦除对应的存储区间,这种擦除是以块(block)为单位进行的。 闪存主要有NOR和NAND两种技术(简单比较见附录)。Flash存储器的擦写次数是有限的,NAND闪存还有特殊的硬件接口和读写时序。因此,必须针对Flash 的硬件特性设计符合应用要求的文件系统;传统的文件系统如ext2等,用作Flash的文件系统会有诸多弊端。 在嵌入式Linux下,MTD(Memory Technology Device,存储技术设备)为底层硬件(闪存)和上层(文件系统)之间提供一个统一的抽象接口,即Flash的文件系统都是基于MTD驱动层的(参见上面的Linux下的文件系统结构图)。使用MTD 驱动程序的主要优点在于,它是专门针对各种非易失性存储器(以闪存为主)而设计的,因而它对Flash有更好的支持、管理和基于扇区的擦除、读/写操作接口。 顺便一提,一块Flash芯片可以被划分为多个分区,各分区可以采用不同的文件系统;两块Flash芯片也可以合并为一个分区使用,采用一个文件系统。即文件系统是针对于存储器分区而言的,而非存储芯片。 1.jffs2 JFFS文件系统最早是由瑞典Axis Communications公司基于Linux2.0的内核为嵌入式系统开发的文件系统。JFFS2是RedHat公司基于JFFS开发的闪存文件系统,最初是针对RedHat公司的嵌入式产品eCos开发的嵌入式文件系统,所以JFFS2也可以用在Linux,uCLinux中。 Jffs2:日志闪存文件系统版本2(Journalling Flash FileSystem v2) 主要用于NOR型闪存,基于MTD驱动层,特点是:可读写的、支持数据压缩的、基于哈希表的日志型文件系统,并提供了崩溃/掉电安全保护,提供“写平衡”支持等。缺点主要是当文件系统已满或接近满时,因为垃圾收集的关系而使jffs2的运行速度大大放慢。 目前jffs3正在开发中。关于jffs系列文件系统的使用详细文档,可参考MTD补丁包中mtd-jffs-HOWTO.txt。 jffsx不适合用于NAND闪存主要是因为NAND闪存的容量一般较大,这样导致jffs为维护日志节点所占用的内存空间迅速增大,另外,jffsx文件系统在

Linux 0.1.1文件系统的源码阅读

Linux 0.11文件系统的源码阅读总结 1.minix文件系统 对于linux 0.11内核的文件系统的开发,Linus主要参考了Andrew S.Tanenbaum 所写的《MINIX操作系统设计与实现》,使用的是其中的1.0版本的MINIX文件系统。而高速缓冲区的工作原理参见M.J.Bach的《UNIX操作系统设计》第三章内容。 通过对源代码的分析,我们可以将minix文件系统分为四个部分,如下如1-1。 ●高速缓冲区的管理程序。主要实现了对硬盘等块设备进行数据高速存取的函数。 ●文件系统的底层通用函数。包括文件索引节点的管理、磁盘数据块的分配和释放 以及文件名与i节点的转换算法。 ●有关对文件中的数据进行读写操作的函数。包括字符设备、块设备、管道、常规 文件的读写操作,由read_write.c函数进行总调度。 ●涉及到文件的系统调用接口的实现,这里主要涉及文件的打开、关闭、创建以及 文件目录等系统调用,分布在namei和inode等文件中。 图1-1 文件系统四部分之间关系图

1.1超级块 首先我们了解一下MINIX文件系统的组成,主要包括六部分。对于一个360K软盘,其各部分的分布如下图1-2所示: 图 1-2 建有MINIX文件系统的一个360K软盘中文件系统各部分的布局示意图 注释1:硬盘的一个扇区是512B,而文件系统的数据块正好是两个扇区。 注释2:引导块是计算机自动加电启动时可由ROM BIOS自动读入得执行代码和数据。 注释3:逻辑块一般是数据块的2幂次方倍数。MINIX文件系统的逻辑块和数据块同等大小 对于硬盘块设备,通常会划分几个分区,每个分区所存放的不同的文件系统。硬盘的第一个扇区是主引导扇区,其中存放着硬盘引导程序和分区表信息。分区表中得信息指明了硬盘上每个分区的类型、在硬盘中其实位置参数和结束位置参数以及占用的扇区总数。其结构如下图1-3所示。 图1-3 硬盘设备上的分区和文件系统 对于可以建立不同的多个文件系统的硬盘设备来说,minix文件系统引入超级块进行管理硬盘的文件系统结构信息。其结构如下图1-4所示。其中,s_ninodes表示设备上得i节点总数,s_nzones表示设备上的逻辑块为单位的总逻辑块数。s_imap_blocks 和s_zmap_blocks分别表示i节点位图和逻辑块位图所占用的磁盘块数。 s_firstdatazone表示设备上数据区开始处占用的第一个逻辑块块号。s_log_zone_size 是使用2为底的对数表示的每个逻辑块包含的磁盘块数。对于MINIX1.0文件系统该值为0,因此其逻辑块的大小就等于磁盘块大小。s_magic是文件系统魔幻数,用以指明文件系统的类型。对于MINIX1.0文件系统,它的魔幻数是0x137f。

实验四Linux内核移植实验

合肥学院 嵌入式系统设计实验报告 (2013- 2014第二学期) 专业: 实验项目:实验四 Linux内核移植实验 实验时间: 2014 年 5 月 12 实验成员: _____ 指导老师:干开峰 电子信息与电气工程系 2014年4月制

一、实验目的 1、熟悉嵌入式Linux的内核相关代码分布情况。 2、掌握Linux内核移植过程。 3、学会编译和测试Linux内核。 二、实验内容 本实验了解Linux2.6.32代码结构,基于S3C2440处理器,完成Linux2.6.32内核移植,并完成编译和在目标开发板上测试通过。 三、实验步骤 1、使用光盘自带源码默认配置Linux内核 ⑴在光盘linux文件夹中找到linux-2.6.32.2-mini2440.tar.gz源码文件。 输入命令:#tar –jxvf linux-2.6.32.2-mini2440-20110413.tar对其进行解压。 ⑵执行以下命令来使用缺省配置文件config_x35 输入命令#cp config_mini2440_x35 .config;(注意:x35后面有个空格,然后有个“.”开头的 config ) 然后执行“make menuconfig”命令,但是会出现出现缺少ncurses libraries的错误,如下图所示: 解决办法:输入sudo apt-get install libncurses5-dev 命令进行在线安装ncurses libraries服务。

安装好之后在make menuconfig一下就会出现如下图所示。 ⑶配置内核界面,不用做任何更改,在主菜单里选择退出,并选“Yes”保存设置返回到刚命令行界面,生成相应配置的头文件。 编译内核: #make clean #make zImage 在执行#make zImage命令时会出现如下错误: 错误:arch/arm/mach-s3c2440/mach-mini2440.c:156: error: unknown field 'sets' specified in initializer 通过网上查找资料 于是在自己的mach-mini2440.c中加入 #include

认识文件系统

认识文件系统 物联网学院平震宇

文件系统 文件系统是一套实现了数据的存储、分级组织、访问和获取等操作的抽象数据类型,一种存储和组织计算机文件和数据的方法,它使得对其访问和查找变得容易。 Linux 最早的文件系统是Minix,但是专门为Linux 设计的文件系统——扩展文件系统第二版 (EXT2)被设计出来并添加到Linux中,这对Linux产生了重大影响。EXT2文件系统功能强大、易扩充、性能上进行了全面优化,也是所有Linux发布和安装的标准文件系统类型。

虚拟文件系统 Linux支持ext,ext2,xia,minix,umsdos,msdes,fat32 ,ntfs,proc,stub,ncp,hpfs,affs 以及 ufs 等多种文件系统。 Linux 对所有的文件系统采用统一的文件界面,用户通过文件的操作界面来实现对不同文件系统的操作。对于用户来说,我们不要去关心不同文件系统的具体操作过程,而只是对一个虚拟的文件操作界面来进行操作,这个操作界面就是 Linux 的虚拟文件系统(VFS ) 。 VFS 作为 Linux内核中的一个软件层,用于给用户空间的程序提供文件系统接口,同时也提供了内核中的一个抽象功能,允许不同的文件系统很好地共存。VFS 使 Linux 同时安装、支持许多不同类型的文件系统成为可能。VFS 拥有关于各种特殊文件系统的公共界面,如超级块、inode、文件操作函数入口等。实际文件系统的细节,统一由 VFS 的公共界面来索引,它们对系统核心和用户进程来说是透明的。

Linux上有许多可用的文件系统。每个文件系统都有其特定的用途,以便于特定用户解决不同的问题。 ?要求文件系统在频繁的文件操作(例如,新建,删 除,截断)下能够保持较高的读写性能,要求低碎 片化。 ?Linux下的日志文件系统能保持数据的完整性,但消 耗过多系统资源,的弱点使之不能成为嵌入式系统中 的主流应用。并且这些都是专门为硬盘这类的存储 设备优化,对于flash这类的存储介质并不适用。

文件系统移植

嵌入式linux内核上文件系统的移植 实验目的:在已经能运行的内核上架构文件系统 其实,虽然 root_qtopia 这个文件系统的GUI 是基于Qtopia 的,但其初始化启动过程 却是由大部分由busybox 完成,Qtopia(qpe)只是在启动的最后阶段被开启。由于默认的内核命令行上有 init=/linuxrc, 因此,在文件系统被挂载后,运行的第一个程 序是根目录下的linuxrc。这是一个指向/bin/busybox 的链接,也就是说,系统起来后运行的 第一个程序也就是busybox 本身。 这种情况下,busybox 首先将试图解析/etc/inittab 来获取进一步的初始化配置信息(参 考busybox 源代码init/init.c 中的parse_inittab()函数)。而事实上,root_qtopia 中并没有/et c/inittab 这个配置文件,根据busybox 的逻辑,它将生成默认的配置 实验过程: 一、获取yaffs2源代码 现在大部分开发板都可以支持 yaffs2 文件系统,它是专门针对嵌入式设备,特别是使用nand flash 作为存储器的嵌入式设备而创建的一种 文件系统,早先的yaffs 仅支持小页(512byte/page)的nand flash,现 在的开发板大都配备了更大容量的nand flash,它们一般是大页模式 (2K/page),使用yaffs2 就可以支持大页的nand flash,下面是yaffs2 的移植详细步骤。 在https://www.360docs.net/doc/bd15398206.html,/node/346 可以下载到最新的yaffs2 源代码,需要使用git工具( 安装方法见本手册第一章),在命令行输入:#git clone git://https://www.360docs.net/doc/bd15398206.html,/yaffs2 稍等片刻,就可以下载到最新的yaffs2 的源代码目录,本光盘中也有单独的yaffs2 源代码包( 文件名为:yaffs2-src-20100329.tar.gz)

FAT文件系统原理详细介绍

FAT文件系统原理详细介绍 2012-03-29 23:09 434人阅读评论(0) 收藏举报 FAT文件起源于70年代末80年代初,用于微软的MS-DOS操作系统。它开始被设计成一个简单的文件系统用于小于500K的软件盘。后来被功能被大大增强用于支持越来越大的媒质。现在的文件系统有FAT12,FAT16和FAT32三种子类。 FAT12是最早的一版,主要用于软盘,它对簇的编址采用12bit宽度的数,所以称为FAT12。12bit的地址可以寻址4096个簇,事实上在FAT12中只能寻址4078个簇(在Linux 下可寻址4084个簇),有一些簇号是不能用的,在后面会给出具体的说明。磁盘的扇区是用16bit的数进行计算的,所以磁盘的容量就被局限在32M空间之内。 在FAT16中,采用了16bit宽的簇地址,32bit宽扇区地址。虽然32bit的扇区地址可以寻址2^32*512,约2个TB的容量,但于由规定每簇最大的容量不超过1024*32,所以FAT16文件系统的容量也就限制到了2^16*1024*32,大约2.1GB的空量,并且实际还达不到这个值。 FAT32文件系统使用了32bit宽的簇地址,所以称为FAT32。但在微软件的文件系统中只使用了低28位,最大容量为2^28*1024*32,约8.7TB的空量。有的人认为32bit全用,最大容量为2^32*1024*32,这种说法是不正确的。 虽然FAT32具有容纳近乎8.7TB的容量,但实际应用中通常不使用超过32GB的FAT32分区。WIN2000及之上的OS已经不直接支持对超过32GB的分区格式化成FAT32,但WIN98依然可以格式化大到127GB的FAT32分区,但不推荐这样做。 下面是一个FAT分区的构成概况 需要说明的是: 1.引导扇区和其他保留扇区一起称为保留扇区,而其他保留扇区是可选的,当没有时候,引导扇区后紧跟的就是FAT表1 2.根目录区是仅FAT12/16才有,FAT32的目录项位于数据区。由于FAT12/16的根目录区是一个固定的区域,所以它的根目录的项数是有限制的,意即不能在根录建立超过这个定数的目录项数。 (一)引导扇区与BPB BPB(BIOS Parametre Block)是FAT文件系统中第一个重要的数据结构,它位于该FAT分区的第一个扇区,同时也属于FAT文件系统基本区域的保留区, 在下面的描述中。凡名称以BPB_开头的都是BPB的一部分,凡名称与BS_开头的项

根文件系统移植

实验五根文件系统移植 实验目的: 通过本次实验,使大家学会根文件系统移植的具体步骤,并对根文件系统有更近一步的感官认识。让同学理解由于根文件系统是内核启动时挂在的第一个文件系统,那么根文件系统就要包括Linux启动时所必须的目录和关键性的文件,任何包括这些Linux 系统启动所必须的文件都可以成为根文件系统。 实验硬件条件: 1、实验PC机一台,TINY6410开发板一台 2、电源线,串口线,数据线。 实验软件条件: 1、VMware Workstation, 2、Ubuntu10.04 3、mktools-20110720.tar.gz 4、busybox-1.13.3-mini2440.tgz, 5、SecureCRT以及dnw烧写工具 实验步骤: 一、实验步骤 1.进入rootfs目录,查看压缩文件,具体操作指令如下:

2.发现有两个压缩文件夹,分别进行解压: 3.tar xvzf busybox-1.13.3-mini2440.tgz, 4.tar xvzf mktools-20110720.tar.gz,解压完成后, 5.查看文件夹#ls

二、实验步骤 1.修改架构,编译器#cd busybox-1.13.3/ 2.进入后查看#ls 3.#gedit Makefile 4.修改 164行 CROSS_COMPILE ?=arm-linux- 5.修改190行 ARCH ?= arm 6.保存后,退出!

三、实验步骤 1.修改配置 #make menuconfig 2.若出现如下提示

3.需调整到最大化。

4.把Busybox Settings -----→>Build Option ------→> Build BusyBox as astatic binary (no shared libs) 选择上,其他的默认即可。 然后一直退出,保存即可 5.接着执行 make接着执行 make install 6.最终生成的文件在_install 中 #cd _install

FATFS深入理解

一、通过格式化命令-看磁盘文件系统的建立过程 1、添加format命令,单步调试 所有的底层驱动函数都已经准备好。添加格式化命令format后,编译下载。 Format命令的执行主要是调用f_mkfs()函数,下面进行单步调试。 以下主要列出函数的主要执行步骤: res=f_mkfs( 0, 1, 4096 ); //1表示不需要引导扇区。4096是8个扇区。 进入f_mkfs()函数,这里只列出主要执行步骤: if (disk_ioctl(drv, GET_SECTOR_COUNT, &n_part) != RES_OK || n_part < MIN_SECTOR) return FR_MKFS_ABORTED;这个函数调用后,n_part=0x000F,3400 = 996 352,这是SD的总块数。allocsize /= SS(fs); 等于8/*Number of sectors per cluster */ n_clst = n_part / allocsize; //等于0x1E680 = 124 544 簇。 if (n_clst >= 0xFFF5) fmt = FS_FAT32; 所以文件系统确定为FAT32类型。 n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs); 等于0x3CE = 974,表示FAT要占据974个扇区。 n_rsv = 33 - partition; 保留扇区32个。 n_dir = 0; b_fat = b_part + n_rsv; /* FATs start sector 32扇区*/ b_dir = b_fat + n_fat * N_FATS; /* Directory start sector 0x3EE =1006,由于FAT表个数设为1个,所以目录区=FAT起始+FAT占用扇区数*/ b_data = b_dir + n_dir; /* Data start sector */ 以上三项确定FAT区域、根目录区、数据区的起始扇区。 disk_ioctl(drv, GET_BLOCK_SIZE, &n) != RES_OK,这个函数调用没有正确返回可擦出扇区的总数。接下来程序会出错,因此退出,修改disk_ioctl()函数后,再次分析。把这个函数返回值直接改为32。并且把FAT表的个数定义为2. N_FATS改为2后,根目录区、数据区的起始扇区的起始扇区变为0x7BC=1980扇区。继续往下执行。 n = (b_data + n - 1) & ~(n - 1); n_fat += (n - b_data) / N_FATS;这两句话对fat所占扇区数进行了修正,保证擦除时,以32个扇区为一个单位。 n_clst = (n_part - n_rsv - n_fat * N_FATS - n_dir) / allocsize; =0x1E588。 tbl = fs->win; /* Clear buffer */ mem_set(tbl, 0, SS(fs)); 清零文件系统缓冲区。 mem_set(tbl, 0, SS(fs)); ST_DWORD(tbl+BS_jmpBoot, 0x90FEEB); /* Boot code (jmp $, nop) */ ST_WORD(tbl+BPB_BytsPerSec, SS(fs)); /* Sector size */ tbl[BPB_SecPerClus] = (BYTE)allocsize; /* Sectors per cluster */ ST_WORD(tbl+BPB_RsvdSecCnt, n_rsv); /* Reserved sectors */ 上面的工作主要是填充引导扇区缓冲区,也就是常说的DBR扇区缓冲,等所有的参数写好,就可以写回磁盘。 ST_WORD(tbl+BS_55AA, 0xAA55); /* Signature */ if (disk_write(drv, tbl, b_part+0, 1) != RES_OK) return FR_DISK_ERR; //这就是在写有效引导标志sec[510]=0x55, sec[511]=0xAA。 if (fmt == FS_FAT32) disk_write(drv, tbl, b_part+6, 1); //FAT32在第六扇区有个备份引导扇区。 for (m = 0; m < N_FATS; m++) { mem_set(tbl, 0, SS(fs)); /* 1st sector of the FAT */ if (fmt != FS_FAT32) { n = (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00; n |= partition; ST_DWORD(tbl, n); /* Reserve cluster #0-1 (FAT12/16) */ } else { ST_DWORD(tbl+0, 0xFFFFFFF8); /* Reserve cluster #0-1 (FAT32) */

Ext3文件系统

EXT3文件系统 EXT2和EXT3是许多Linux操作系统发行版本的默认文件系统。EXT基于UFS,是一种快速、稳定的文件系统。 随着Linux系统在关键业务中的应用,Linux文件系统的弱点也渐渐显露出来了;其中EXT2文件系统是非日志式文件系统,这在关键行业的应用是一个致命的弱点,EXT3文件系统弥补了这一缺点。 EXT3文件系统是直接从EXT2文件系统发展而来,目前EXT3文件系统已经非常稳定可靠。它完全兼容EXT2文件系统。用户可以平滑地过渡到一个日志功能健全的文件系统中来。这实际上了也是EXT3日志文件系统初始设计的初衷。 Ext3文件系统属于一种日志文件系统,是对Ext2系统的扩展。Ext3系统兼容Ext2文件系统,二者之间的相互转换并不复杂。 Ext2是 GNU/Linux 系统中标准的文件系统,其簇快取层的优良设计使得Ext2系统存取文件的性能非常好,尤其是针对中小型的文件更显优势。 Ext3是一种日志式文件系统,日志文件系统比传统的文件系统安全,因为它用独立的日志文件跟踪磁盘内容的变化。就像关系型数据库(RDBMS),日志文件系统可以用事务处理的方式,提交或撤消文件系统的变化。由于文件系统都有快取层参与运作,不使用时必须将文件系统卸下,以便将快取层的资料写回磁盘中。因此每当系统要关机时,必须将其所有的文件系统全部关闭后才能进行关机。 如果在文件系统尚未关闭前就关机 (如停电) 时,下次重开机后会造成文件系统的资料不一致,故(所以)这时必须做文件系统的重整工作,将不一致与错误的地方修复。然而这一重整的工作是相当耗时的,特别是容量大的文件系统,而且也不能百分之百保证所有的资料都不会流失。 为了克服此问题,使用(便出现了)所谓的日志式文件系统 (Journal File System) 。此类文件系统最大的特色是,它会将整个磁盘的写入动作完整记录在磁盘的某个区域上,以便有需要时可以回溯追踪。 由于资料的写入动作包含许多的细节,如改变文件标头资料、搜寻磁盘可写入空间、一个个写入资料区段等等,每一个细节进行到一半若被中断,就会造成文件系统的不一致,因而需要重整。 然而在日志式文件系统中,由于详细纪录了每个细节,故当在某个过程中被中断时,系统可以根据这些记录直接回溯并重整被中断的部分,而不必花时间去检查其他的部分,故重整的工作速度相当快,几乎不需要花时间。 EXT3日志文件系统的特点 1、高可用性 系统使用了EXT3文件系统后,即使在非正常关机后,系统也不需要检查文件系统。宕机发生后,恢复EXT3文件系统的时间只要数十秒钟。 2、数据的完整性: EXT3文件系统能够极大地提高文件系统的完整性,避免了意外宕机对文件系统的破

FATFS文件系统移植和应用

FATFS文件系统的移植 作者:LJ 时间:2010年11月12日 随着信息技术的发展,目前常用文件系统主要有微软的FAT12、FAT16、FAT32、NTES文件系统,以及Linux系统的EXT2、EXT3等。由于Windows操作系统的广泛应用,当前很多嵌入式产品中用的最多的还是FAT文件系统。所以,选择一款容易移植和使用,并且占用资源少而功能全面的文件系统就显得非常重要了。 FATFS文件系统是一个完全免费且开源的FAT文件系统模块,由小日本工程师编写,它支持FAT12、FAT16和FAT32文件系统,专门为小型的嵌入式系统而设计。模块用标准的C语言编写,可以很容易地移植到各种硬件平台。 在“驱动程序”文件夹中有一个“FatFs R0.07c”文件夹,这是官方提供的FATFS文件系统的源码和文档,版本为R0.07c。打开“doc”文件夹下的“00index_e.html”英文网页文档,里面有FATFS文件系统的全部API函数说明,相对应的应用实例和如何编写硬件接口程序的说明。如果您的英文不怎么好,建议您先装一个有道词典,使用屏幕取词功能,能帮助我们阅读和理解。“00index_j.html”则是日文版的网页,毕竟是小日本写的。“src”文件夹存放有FATFS文件系统源码,下面是该文件夹下各个文件或文件夹存放的内容说明:“ff.h”文件:FATFS文件系统的配置和API函数声明; “ff.c”文件:FATFS源码;

“diskio.h”文件:FATFS与存储设备接口函数的声明; “diskio.c”文件:FATFS与存储设备接口函数; “integer.h”文件:FATFS用到的所有变量类型的定义; “option”文件夹:存放一些外接函数,下一实例有实际的讲解; “00readme.txt”文件:FATFS版本及相关信息说明; 编译工程,没有通过,根据编译信息提示在“diskio.c”文件中在几个函数没有定义。这很正常,因为我们还没有编写文件系统与存储设备的接口函数。下面来分析“diskio.c”文件中各个函数的功能:“DSTATUS disk_initialize ( BYTE drv )”是存储媒介的初始化函数,由于我们使用的是SD卡,所以实际上是对SD卡的初始化; “DSTATUS disk_status ( BYTE drv )”状态检测函数,检测是否支持当前的存储设备,支持返回0; “DRESULT disk_read (BYTE drv, BYTE *buff, DWORD sector, BYTE count)”是读扇区函数,drv是要读扇区的存储媒介号,*buff 存储读取的数据,sector是读数据的开始扇区,count是要读的扇区数。在SD卡的驱动程序中,分别提供了读一个扇区和读多个扇区的函数。当count == 1时,用读一个扇区函数;当 count > 1时,用读多个扇区的函数,这样提高了文件系统读效率。操作成功返回0。 “DRESULT disk_write(BYTE drv, BYTE *buff, DWORD sector, BYTE count)”写扇区函数,drv是要写扇区的存储媒介号,*buff存储写入的数据,sector是写开始扇区,count是要写的扇区数。同样在SD卡的驱动程序中,分别提供了写一个扇区和写多个扇区的函数。

FATFS文件系统剖析1

FATFS文件系统剖析1: FAT16: 数据按照其不同的特点和作用大致可分为5部分:MBR区、DBR区、FAT区、DIR区和DATA区,相比fat12多了DBR区 Main boot record: MBR(0--1bdh)磁盘参数存放 DPT(1beh--1fdh)磁盘分区表 55,aa 分区结束标志 DBR(Dos Boot Record)是操作系统引导记录区的意思 FAT区(有两个,一个备份):对于fat16,每一个fat项16位,所以可寻址的簇项数为65535(2的16次方)。而其每簇大小不超过32k,所以其每个分区最大容量为2G。fat32,每一个fat项32位,可寻址簇数目为2的32次方。 DIR区(根目录区):紧接着第二FAT表(即备份的FAT表)之后,记录着根目录下每个文件(目录)的起始单元,文件的属性等。定位文件位置时,操作系统根据DIR中的起始单元,结合FAT表就可以知道文件在硬盘中的具体位置和大小了。 DATA区:实际文件内容存放区。 FAT32: 暂时放在这里,不讨论! Fatfs:嵌入式fat文件系统,支持fat16,fat32。 包含有ff.h,diskio.h,integer.h,ffconf.h 四个头文件以及ff.c 文件系统实现。当然要实现具体的应用移植,自己要根据diskio.h实现其diskio。c 底层驱动。 diskio.h : 底层驱动头文件 ff.h : 文件系统实现头文件,定义有文件系统所需的数据结构 ff.c : 文件系统的具体实现

如下开始逐个文件加以分析: integer.h :仅实现数据类型重定义,增加系统的可移植性。 ffconf.h : 文件系统配置---逐个配置,先配置实现一个最小的fat文件系统,下面来分析各配置选项: #define _FFCONF 8255 //版本号 #define _FS_TINY 0 /* 0:Normal or 1:Tiny */ //在这里与先前版本有些许变化,是通过配置头配置两种不同大小的文件系统,这里配置为0。 #define _FS_READONLY 1//定义文件系统只读,也就不能写修改,在此定义为1,这样文件系统会大大缩小,简化学习理解过程。 #define _FS_MINIMIZE 3 /* 0 to 3 */ 这个选项是用于过滤掉一些文件系统功能,为0时是全功能,3是功能实现最小 #define _USE_STRFUNC 0 /* 0:Disable or 1/2:Enable */ 是否使用字符串文件接口,为0,不使用 #define _USE_MKFS 0 /* 0:Disable or 1:Enable */ 制作文件系统,这个功能实现是还要_FS_READONLY=0 #define _USE_FORWARD 0 /* 0:Disable or 1:Enable */ f_forward function 实现还需_FS_TINY =1 #define _USE_FASTSEEK 0 /* 0:Disable or 1:Enable */ 快速查找功 能 #define _CODE_PAGE 936 // 936 - Simplified Chinese GBK (DBCS, OEM, Windows) #define _USE_LFN 0/* 0 to 3 */ 0:不使用长文件名 #define _MAX_LFN 255/* Maximum LFN length to handle (12 to 255) */ #define _LFN_UNICODE 0 /* 0:ANSI/OEM or 1:Unicode */

stm32sdiofatfs文件系统源码分析

、概述 1、目的 在移植之前,先将源代码大概的阅读一遍,主要是了解文件系统的结构、 各个函数的功能和接口、与移植相关的代码等等。 2、准备工作 在官方网站下载了0.07c 版本的源代码,利用记事本进行阅读。 二、源代码的结构 1、源代码组成 源代码压缩包解压后,共两个文件夹,doc是说明,src里就是代码。src文件夹里共五个文件和一个文件夹。文件夹是option,还有OOreadme.txt、 diskio.c、diskio.h、ff.c、ff.h、integer.h。对比网上的文章,版本已经不同了,已经没有所谓的tff.c 和tff.h 了,估计现在都采用条件编译解决这个问题了,当然文件更少,可能编译选项可能越复杂。 2、00readme.txt 的说明 Low level disk I/O module is not included in this archive because the FatFs module is only a generic file system layer and not depend on any specific storage device. You have to provide a low level disk I/O module that written to control your storage device .主要是说不包含底层10代码,这是个通用文 件系统可以在各种介质上使用。我们移植时针对具体存储设备提供底层代码。 接下来做了版权声明-可以自由使用和传播。 然后对版本的变迁做了说明。 3、源代码阅读次序

先读integer.h,了解所用的数据类型,然后是ff.h, 了解文件系统所用的数据结构和各种函数声明,然后是diskio.h,了解与介质相关的数据结构和操作函数。再把ff.c和diskio.c两个文件所实现的函数大致扫描一遍。最后根据用户应用层程序调用函数的次序仔细阅读相关代码。 三、源代码阅读 1、integer.h 头文件 这个文件主要是类型声明。以下是部分代码。 typedef intINT; typedef unsigned int UINT; typedef signed charCHAR;/* These types must be 8-bit integer */ 都是用typedef 做类型定义。移植时可以修改这部分代码,特别是某些定义与你所在工程的类型定义有冲突的时候。 2、ff.h 头文件 以下是部分代码的分析 #include “ intege使用i n teger.h 的类型定义 #ifndef _FATFS #define _FATFS 0x007版本号007c, 0.07c #define _WORD_ACCESS 0如//果定义为1,则可以使用word 访问。 中间有一些看着说明很容易弄清楚意思。这里就不例举了。 #define _CODE_PAGE 936 /* The _CODE_PAGE specifies the OEM code page to be used on the target system. /936 -Simplified Chinese GBK (DBCS, OEM, WindoW跟据这个中国应该是936.

Ext2格式分析

Ext2格式分析 1、Ext2磁盘数据结构 任何Ext2分区中的第一个块从不受Ext2文件系统的管理,因为这一块是为分区的引导扇区所保留的。Ext2分区的其余部分被分成块组(block group),每个块组的分布图如图所示。正如你从图中所看到的,一些数据结构正好可以放在一块中,而另一些可能需要更多的块。在Ext2文件系统中的所有块组大小相同并被顺序存放,因此,内核可以从块组的整数索引很容易地得到磁盘中一个块组的位置: 由于内核尽可能地把属于同一个文件的数据块存放在同一块组中,所以块组减少了文件碎片。块组中的每个块包含下列信息之一: 1.文件系统的超级块的一个拷贝 2.一组块组描述符的拷贝 3.一个数据块位图 4.一个索引节点位图 5.一个索引节点表 6.属于文件的一大块数据,即数据块 如果一个块中不包含任何有意义的信息,就说这个块是空闲的。 从上图中可以看出,超级块与组描述符被复制到每个块组中。 其实呢,只有块组0中所包含超级块和组描述符才由内核使用,而其余的超级块和组描述符都保持不变;事实上,内核甚至不考虑它们。当e2fsck程序对Ext2文件系统的状态执行一致性检查时,就引用存放在块组0中的超级块和组描述符,然后把它们拷贝到其他所有的块组中。如果出现数据损坏,并且块组0 中的主超级块和主描述符变为无效,那么,系

统管理员就可以命令e2fsck引用存放在某个块组(除了第一个块组)中的超级块和组描述符的旧拷贝。通常情况下,这些多余的拷贝所存放的信息足以让e2fsck把Ext2分区带回到一个一致的状态。 那么有多少块组呢?这取决于分区的大小和块的大小。其主要限制在于块位图,因为块位图必须存放在一个单独的块中。块位图用来标识一个组中块的占用和空闲状况。所以,每组中至多可以有8×b个块,b是以字节为单位的块大小。例如,一个块是 1024 Byte,那么,一个块的位图就有8192个位,一个块组正好就对应8192个块(位图中的一个bit描述一个块)。 Ext2超块(super Block) Ext2超块中包含了描叙文件系统基本尺寸和形态的信息,是用定义在include/Linux /ext2_fs.h中ext2_supe_block数据结构描述的。文件系统管理器利用它们来使用和维护文件系统。通常安装文件系统时只读取数据块组0中的超块,但是为防止文件系统被破坏,每个数据块组都包含了它的拷贝。超块中的主要信息如下: Magic Number:文件系统安装软件用来检验是否是一个真正的EXl2文件系统超块。当前Exl2版本中为0xEF53。 Block Size:以字节记数的文件系统块大小,如1024字节。 Blocks per Group:每个组中块数目。当文件系统创建时此块大小被固定下来。 Free Blocks:文件系统中的空闲块数。 Free Inodes:文件系统中空闲Inode数。 First Inode:文件系统中第一个Inode号。EX配根文件系统中第一个Inode将是指向‘/’目录的人口。 ExT2组描述符(Group Descript) 每个数据块组都拥有一个描叙结构的组描叙符,它是定义在include/Linux/ext2一fs.h中的ext2一group—desc结构。组描叙符放置在一起形成了组描叙符表。每个数据块组在超块拷贝后包含整个组描叙符表。象超块一样,所有数据块组中的组描叙符表被复制到每个数据块组中以防文件系统崩溃。EX配文件系统仅使用第一个拷贝(在数据块组0中)。组描叙符主要包含以下信息: Blocks Bitm印:对应此数据块组的块分配位图的块号,在块分配和回收时使用。 Inode Bitmap:对应此数据块组的Inode分配位图的块号,在Inode分配和回收时使用。 Inode Table:对应数据块组的Inode表的起始块号。每个Inode用下面的EX佗Inode 结构来表示。

相关文档
最新文档