发布时间:2010-2-12 10:50
分类名称:Private
本文件详细描述了在ePass系列产品的PKI设计/实现中, token内部文件系统的设计与实现。
在本文中,“文件”特指我们自己实现的FAT8文件系统中的文件,“物理文件”特指由token中COS管理的文件。
之所以不直接使用物理文件,是出于以下几个原因:
在确定了使用大的物理文件来保存数据的策略后,进一步考虑物理文件中数据的管理方式。数据的管理应该满足下列需求:
有鉴于此,我们决定采用FAT的文件系统来管理物理文件内部的数据,即,将一个物理文件按照FAT文件系统的概念划分成簇,具有自己的FAT表,而文件相 对于物理文件来说,只是一个或者多个小数据块。仅仅使用各种token COS都会提供的读写二进制文件的功能,就可以满足我们动态增加/删除文件的需求。
决定使用FAT文件系统之后,需要确定文件系统的实现方式。1.44Mb软盘采用的是FAT12的文件系统,早期的DOS采用FAT16的文件系 统,Windows98开始使用FAT32文件系统。由于token中的存储区都比较小,一般为8k~32k,所以我们采用FAT8文件系统。
在ePass使用的FAT8文件系统中,我们对常见意义上的文件系统作了大规模的削减,因为我们没有必要支持目录结构,而且没有必要支持以字符串作为文件 名等特性。所以在ePass的FAT8文件系统中,只有文件,没有目录,而且文件以一个唯一的序号作为标识。
FAT8文件系统最多支持创建28=256个文件项,每个文件项的标识仅需要一个字节。事实上,文件系统内部使用了几个字节用于管 理,所以实际能够创建的文件数目256-3=253个,下文将详细描述。
我们可以把一个物理文件看作是一个虚拟的磁盘,其上有文件分配表(File Allocation Table, FAT),数据簇等等。
下面是文件系统的构造:
图1 FAT8 文件系统内部结构
如图,一个文件系统由三大部分组成:文件头、FAT、数据簇。
文件头(16字节)标识了以下内容:
typedef struct
{
UCHAR pucFlag[3]; // 文件系统标记,ePass1000/2000中目前使用'NFS'
UCHAR ucSizeOfCluster; // 每簇字节数
DWORD dwVersion; // 文件系统版本号
UCHAR ucTotalCluster; // 虚拟磁盘的总簇数
UCHAR ucFreeCluster; // 虚拟磁盘的可用簇数
UCHAR ucNumberOfFDT; // FDT 表中已创建文件数
UCHAR pucReserve[5]; // 保留未用
}FS_HEADER;
紧接着文件头之后是256字节的FAT,每一个字节对应一个簇的状态,即第0个字节标识第0个簇的状态,第1个字节标识第1个簇的状态,以此类推。FAT 中每一个字节的含义如下:
图3 已经创建了文件的FAT8文件系统的FAT
如图3所示就是已经创建了几个文件的FAT内容,下面以这个FAT为例,说明一下FAT的构造。
由图3中的FAT可以看出,文件系统中至少已经创建了3个文件(之所以说“至少”,是因为创建的文件可能并没有分配空间,详细信息请查阅本文后续的FDT 内容)。
从上面的例子中我们可以知道每个文件占用的簇在文件系统中的分布,但是一个文件不可能一定恰好占用一个或者多个完整的簇。有可能一个文件占用了多个完整的 簇,但是其在占用的最后一个簇中仅使用了3个字节,为了解决这个问题,我们必须引入FDT的概念。
除了FAT之外,我们还需要记录每一个创建的文件的信息,例如文件的ID,起始簇的序号,文件的大小及附加属性等,每个文件需要5个字节来保存信息,如下 所示:
typedef struct
{
UCHAR ucID; // 文件ID
UCHAR ucStartCluster; // 开始簇
USHORT usSize; // 文件大小
UCHAR ucAttr; // 文件属性
}FS_FDT;
所有已经创建的文件的信息被保存到一个文件中,这个文件被称为FDT(File Descript Table)。特别地,FDT文件的ID固定为0×00,FDT文件中的第一个文件描述项就是其自身。FDT文件随着FAT8文件系统中创建的文件的数目 增加而增大,FDT文件本身除文件ID固定为0×00之外,其余同普通文件一致。
对于一个文件,如果其“开始簇”(即ucStartCluster)为0xFE,则表示这个文件尚未分配空间,与之对应的,其“文件大小”(即 usSize)必然为0。
由上述所描述的信息,我们就可以创建/删除/读写文件了,并且文件的大小是可以动态指定的,也即是说,如果需要,随时可以更改文件的大小(如果是增大文 件,则需要有足够的剩余簇)。
同时,我们知道,因为0×00/0xFE/0xFF具有特殊用途,所以,真正可以使用的簇无法达到256个。实际上,一般情况下也不会真正划分256个 簇,详细情况请查阅“访问/格式化/簇的大小”一节。
要使用磁盘来存储数据,必须先格式化,我们的FAT8文件系统也不例外。为了提供文件访问功能,我们必须先将存储空间按照我们制定的格式填充。
首先是16字节的文件头。这里主要要注意的是关于簇的信息。
簇的大小:簇的大小是经过计算得来的。因为对于给定的存储空间,我们知道文件头和FAT需要占用16+256=272字节,剩下的数据空间 才是真正划分为簇的。为了访问方便,我们将每个簇划分为32的整数倍大小。这样做会导致一般情况下,并不会真正划分256个簇。
簇的数目: 真正用于保存数据的空间大小除以256之后,得到粗略的簇的大小,然后将这个粗略值向上取到32的整数倍,得到真正划分时簇的大小,然后再将真正用于保存 数据的空间大小除以真正的簇大小,才得到实际划分的簇的数目。
对于FAT,只需要全部填为0×00即可。
在格式化的时候,我们需要创建一个文件,即FDT。创建FDT按照创建普通文件的方式操作即可。
首先确认指定的ID尚未被使用。然后确认FDT文件有足够的空间可以保存新的文件的描述信息(5个字节),如果FDT文件不够大,会自动分配一个簇。然后 保存该文件的描述信息,其中文件的起始簇设为0xFE,表示尚未为该文件分配空间。直到调用者设置文件大小,才为该文件分配空间。 分配空间的过程为:查看FAT,找到第一个尚未分配的簇,即FAT中为0×00的那个字节所对应的簇。根据需要找到足够的尚未分配的簇,将FAT中这些簇 对应的字节,按照链接的方式修改其内容,然后修改该文件的描述信息,将起始簇改为
(未完,待续…)