型号: PXF0251
第五章 Windows CE的储存管理
本章将介绍Windows CE 的储存管理。我们将本章内容分为两大部分,前半部会依序介绍 Windows CE的档案系统类型、 Windows CE储存管理结构和每一个层次、以及如何自行开发档案系统并加载之,后半部则以Ramdisk上的档案系统为例,实际分析储存管理相关的原始程序代码与数据型态。
5.1 Windows CE的储存管理架构
5.1.1 概述
Windows CE提供了三种类型的档案系统:RAM-based 档案系统、ROM-based 档案系统、以及用于支持ATA (Advanced Technology Attachment) 装置和SRAM卡等外围储存装置的FAT档案系统。其中,前两种档案系统属于 Windows CE的内建档案系统,后者属于可安装性档案系统。另外,嵌入式系统的开发人员也可以编写自己的档案系统,并在系统中注册使用。Windows CE提供了platform-independent API,不论是何种储存装置,所有对档案系统的存取都是透过Win32 API完成。
Windows CE预设的储存装置为最大可达256MB的RAM内存。RAM被分割为程序空间 (program memory) 和对象空间 (object store) 。程序空间和一般计算机系统中RAM的使用类似,用来储存执行程序及所需数据。对象空间则类似一般计算机系统中的硬盘,用来储存应用程序及档案。对象空间中存放的数据可分为三大类: (1) 档案系统 (file system) , (2) 注册信息 (registry) , (3) Windows CE数据库 (Windows CE database) 。Windows CE系统的电源管理机制,即使在关机状态时,仍旧有少量的电力从电池供应RAM,以保留储存在其中的数据。只有在电池电力完全耗尽时,RAM中储存的数据才会消失。
与对象空间相关的RAM-based档案系统和ROM-based档案系统,是 Windows CE预设支持的内建档案系统。除此之外,使用者还可以安装用于支持外围储存装置的档案系统,比如FAT、UDFS等等。对外围储存装置的存取,都是透过这种可安装性档案系统来完成的。另外,我们还可以将一个外围储存装置,分为多个volume(卷)并分别加载,其中每个volume可以使用不同的档案系统。Windows CE没有像Windows XP或Windows ME使用磁盘驱动器代号来表示volume,加载后的volume在Windows CE内以目录的形式呈现。
5.1.2 对象空间
如前所述,对象空间的数据分为三部分-档案系统、系统注册信息及数据库。然而,档案系统、数据库以及注册信息都不一定要储存在对象空间中,它们也可以被存放ROM或是外围储存装置中。数据的建立和使用,与实际的储存装置无关,只是依赖于储存的类型。
操作系统负责管理内存堆,在必要的时候会对档案进行压缩和解压缩。对象空间使用基于事务的数据管理机制。如果当数据写入对象空间时,发生了电源中断的情况,Windows CE会透过各种手段保证对象空间不被破坏,例如在系统重启后继续完成该写操作,或是恢复到电源中断前的状态。
在早期的Windows CE版本中,RAM档案系统和档案大小最大皆只能达16MB。到了Windows CE 3.0这个版本,RAM档案系统最大可达256MB,而档案大小最大也能达32MB。另外,对象空间中的对象数目也由原本的65,536增加到4,000,000左右。最新的Windows CE .NET允许档案最大可达4GB。
Windows CE为对象空间中的每个对象,都分配了一个唯一的对象识别码 (Windows CE object identifier, 简称CEOID) 。对象识别码的作用就是用于存取对象空间中的对象。在对象空间中,以下列出的各项都可以被定义为一个对象:
需要说明的一点是,Windows CE仅仅保证对象识别码在同一个volume中是唯一的,当有多个volume,可能在不同volume中发现相同对象识别码的对象。因此,Windows CE为每个数据库volume (database volume) 都分配了一个唯一的数据库识别码 (CEGUID)。数据库识别码和对象识别码的结合,就可以表示数据库volume中的某个对象了。
要对对象空间中的对象进行存取,第一步就是获得该对象的对象识别码。根据不同的对象类型,Windows CE提供了相对应的函式以获得该对象的对象识别码,参考表5.1。
表5.1 获得对象识别码函式
对象类型 |
获得对象识别码的方法 |
目录或档案 |
FindFirstFile和FindNextFile函式回传的WIN32_FIND_DATA结构的dwOID字段。GetFileInformationByHandle函式回传的BY_HANDLE_FILE_INFORMATION结构的dwOID字段。 |
数据库 |
CeCreateDatabaseEx2或CeFindNextDatabaseEx函式的回传值 |
数据库记录 |
CeSeekDatabaseEx、CeReadRecordPropsEx以及 CeWriteRecordProps函式的回传值。 |
已加载的数据库volume |
CeMountDBVol和CeEnumDBVolumes函式可以回传已挂载数据库volume中的数据库识别码。 |
有了对象识别码,就可以使用CeOidGetInfoEx函式得到该对象内的数据。CeOidGetInfoEx函式会回传一个CEOIDINFO结构 (结构原型列于程序代码5.1)。CEOIDINFO结构有一个wObjType字段说明了对象的类型。假如该字段的值为OBJTYPE_DATABASE,就指这是一个数据库对象。由wObjType可得知该对象是档案、目录、数据库还是数据库记录,同时也得知该对象的数据地址。例如,如果对一个数据库对象使用CeOidGetInfoEx的话,那么回传的类型值为OBJTYPE_DATABASE,而与之相关的数据库名称、类型识别码、记录的数目、数据库的大小以及排序方式等信息,都将保存在一个CEDBASEINFO结构中。
程序代码5.1 CEOIDINFO数据结构
typedef struct _CEOIDINFO {
WORD wObjType; //Type of object
// OBJTYPE_INVALID | There was no valid object
// with this CEOID
// OBJTYPE_FILE | The object is a file
// OBJTYPE_DIRECTORY | The object is a directory
// OBJTYPE_DATABASE | The object is a database
// OBJTYPE_RECORD | The object is a record inside
// a database
WORD wPad; // dword alignment
union { //This is a union
CEFILEINFO infFile; //Valid for file objects
CEDIRINFO infDirectory; //Valid for directory objects
// @CESYSGEN IF FILESYS_FSDBASE
CEDBASEINFO infDatabase; //Valid for database objects
CERECORDINFO infRecord; //Valid for record objects
// @CESYSGEN ENDIF
};
} CEOIDINFO, PCEOIDINFO;
5.1.3 储存管理程序
储存管理程序 (Storage Manager) 负责管理外围储存装置所使用的档案系统和区块装置驱动程序 (Block Device Driver) 。储存管理程序的功能实作位在fsdmgr.dll模块,它由三部分组成,包括区块装置管理程序 (Block Driver Manager) 、分割区管理程序 (Partition Manager) 以及档案系统管理程序 (File System Driver Manager,或简称FSD Manager) 。所有对档案和volume的处理,都是经由储存管理程序完成的,储存管理程序在永久性储存介质的存取过程中,扮演了很重要的角色。
图5.1 储存管理程序结构图
Windows CE的储存管理程序是一个分层结构 ,其结构如图5.1所示,因此做Disk I/O必需经过储存管理程序的各个阶层。首先是过滤器层 (File System Filter) ,在将I/O请求交由档案系统驱动程序处理之前,在过滤器这一层可以完成一些加密、压缩和病毒扫描等性质的额外工作。接下来是档案系统驱动程序 (File System Driver) ,在这里对参数进行格式化,将文件名称转换为区块装置驱动程序可以识别的物理地址。在这之后,就可以经分割区管理程序,或直接交由区块装置驱动程序,完成实体的I/O操作了。
在储存管理程序的启动过程中,有很多信息是从系统的注册信息中得到的。例如,下面的注册信息会告知系统加载储存管理程序模块:
[HKEY_LOCAL_MACHINESystemStorageManager]
"Dll"="fsdmgr.dll"
另外,每当系统检测到新的外围储存装置时,装置管理程序会自动加载支持该装置的区块装置驱动程序,之后向储存管理程序报告,该装置的配置信息在注册信息中的位置。储存管理程序就是根据这些信息,决定如何加载适当的分割区驱动程序 (partition driver) 和档案系统驱动程序。下面是所有装置都可使用的预设配置信息:
[HKEY_LOCAL_MACHINESystemStorageManagerProfiles]
"AutoMount"=dword:1
"AutoPart"=dword:0
"AutoFormat"=dword:0
"MountFlags"=dword:0
"DefaultFileSystem"="FATFS"
"PartitionDriver"="mspart.dll"
"Folder"="Mounted Volume"
其中AutoFormat表明是否对该装置进行自动格式化,AutoPart表明是否用该装置上的最大可用空间自动建立分割区,AutoMount表明是否自动挂载每个检测到的分割区,而MountFlags则指出了应如何对分割区进行挂载。
如果装置管理程序向储存管理程序,指定新装置的配置信息所在的位置,那么储存管理程序会使用该装置的指定配置信息。例如,硬盘的配置信息可能如下:
[HKEY_LOCAL_MACHINESystemStorageManagerProfilesHDProfile]
"Name"="
"Folder"="Hard Disk"
对于未提供一些配置信息,比如AutoFormat、AutoPart和AutoMount,则要使用系统提供的默认值。
当系统发现新的外围储存装置时,储存管理程序为其加载分割区驱动程序和档案系统驱动程序的程序如下:
1.装置管理程序负责加载区块装置的驱动程序,
2.由该装置发出一个通知,告知储存管理程序该装置的装置名称及其GUID,
3.储存管理程序根据注册信息中的配置信息,为该装置加载分割区驱动程序,
4.储存管理程序行举该装置上的所有分割区,
5.储存管理程序为每个分割区,加载档案系统驱动程序。
5.1.3.1 档案系统过滤器
档案系统过滤器和档案系统驱动程序类似,它们都有一组输出函式被CreateFile和 CreateDirectory这类的标准档案系统API映像到。二者不同之处在于,档案系统过滤器要提供HookVolume和UnhookVolume这两个函式,而档案系统驱动程序必须提供的是MountDisk和UnmountDisk这两个函式。档案系统驱动程序和档案系统过滤器的加载,都是透过档案系统管理程序完成的。
有关档案系统过滤器的信息,也是保存在注册信息中。档案系统管理程序需要到以下各处搜寻应加载的档案系统过滤器:
[HKEY_LOCAL_MACHINESystemStorageManagerAutoLoadFileSystem
Filters]
[HKEY_LOCAL_MACHINESystemStorageManagerProfilesProfileName
FileSystemFilters]
[HKEY_LOCAL_MACHINESystemStorageManagerFileSystemFilters]
[HKEY_LOCAL_MACHINESystemStorageManagerFilters]
此处,FileSystem代表档案系统在注册信息中所使用的名称,例如FATFS、UDFS等等。如果在
[HKEY_LOCAL_MACHINESystemStorageManagerAutoLoadFileSystem
Filters]
[HKEY_LOCAL_MACHINESystemStorageManagerProfilesProfileName
FileSystemFilters]
中出现了一个过滤器的话,那么所有使用该配置信息的档案系统,都将使用该过滤器。如果在
[HKEY_LOCAL_MACHINESystemStorageManagerFileSystemFilters]
中出现了一个过滤器的话,那么名为FileSystem的档案系统将使用该过滤器。如果一个过滤器出现在
[HKEY_LOCAL_MACHINESystemStorageManagerFilters]
中,那么所有的档案系统都将使用该过滤器。下面是一个注册信息中有关过滤器信息的例子:
[HKEY_LOCAL_MACHINESystemStorageManager...FiltersFilterName]
"dll"="filter.dll"
"Order"=dword:x
其中dll的值,是该过滤器所对应的动态链接库,Order的值,则是建造过滤器堆栈时各过滤器之间的顺序。
5.1.3.2 档案系统管理程序与档案系统驱动程序
首先来看一下档案系统驱动程序 (File System Driver-FSD) 。档案系统驱动程序只适用于区块装置。我们知道,任何装置加载系统后,都需要对应的装置驱动程序的配合才能得以工作,对于区块装置而言,自然也少不了区块装置驱动程序。但是与其它装置不同的是,区块装置除了需要直接和硬件沟通的区块装置驱动程序之外,还需要一个档案系统驱动程序,这是因为,虽然区块装置驱动程序已经向上层提供了各种函式接口,透过这些接口就可以对区块装置进行初始化、读写数据区块等等各种操作了,但是这种接口的操作对象却是数据区块,如果直接将这种接口提供给使用者使用的话,使用者所见到的区块装置就是一个杂乱无章、毫无规律的数据区块集合,这对使用者而言非常地不方便。因此必需将这些散乱的数据区块,组织成档案的形式,并向使用者提供一个按名存取的档案系统接口,这就是档案系统驱动程序的主要功能。意即档案系统驱动程序建立在区块装置驱动程序模块之上,负责对区块装置的进一步抽象,把毫无规律的数据区块,组织成对使用者来说,更为方便易用的档案,并向上提供了档案操作的函式接口。档案系统程序与区块装置驱动程序间的关系如图5.2所示。
图5.2 档案系统驱动程序和区块装置驱动程序关系图
Windows CE支持大多数Windows XP或Windows ME使用的档案I/O函式,例如CreateFile、ReadFile、WriteFile和CloseHandle等Win32 API呼叫。同时,Windows CE仍然遵循使用句柄对档案进行存取的传统方法。由CreateFile函式回传,新建立或打开的档案句柄,之后的读写操作,都使用该句柄来决定档案操作的对象。当然,对读写操作来说,还需要一个指标,来指出在档案中进行读写的位置。
系统中所有的可安装档案系统,都是由档案系统管理程序负责管理的。每个可安装档案系统,都对应着一个档案系统驱动程序,并且以动态链接库 (Dynamic Link Library) 的形式提供,它有一组输出函式被映像到标准的档案系统Win32 API上。像CreateFile、ReadFile、WriteFile和CloseHandle这些档案系统API的功能,最后都是呼叫某个档案系统驱动程序的函式MyFSD_CreateFileW、MyFSD_ReadFile、MyFSD_WriteFile和MyFSD_CloseFile完成的。另外值得注意的一点是,档案系统驱动程序的动态链接库的名字,与该档案系统驱动程序的输出函式的前缀 (prefix) 是相同的。例如,如果档案系统名为MyFSD,那么对应的动态链接库就是MyFSD.dll,其输出函式的前缀为MyFSD_*。
在应用程序中存取可安装档案系统,使用的是标准的档案系统Win32 API。例如,当应用程序想要在某个储存装置上建立一个目录时,可以呼叫CreateDirectory。之后由档案系统管理程序对CreateDirectory中指明的路径加以识别,如果发现该路径指向一个使用可安装档案系统的装置,便会呼叫相对应的档案系统驱动程序-MyFSD.dll内的建立目录函式MyFSD_CreateDirectoryW。也就是说,应用程序呼叫CreateDirectory的结果,是导致档案系统管理程序,呼叫相对应档案系统驱动程序的函式MyFSD_CreateDirectoryW。
在Windows CE中,负责管理档案系统驱动程序的模块,称为档案系统管理程序 (File System Driver Manager) 。由于现代操作系统一般都支持多个档案系统并存,因此需要对系统中用到的各个档案系统加以管理,这就是档案系统管理程序的作用。从功能上讲,Windows CE中的档案系统管理程序与Linux中的虚拟档案系统VFS类似,如图5.3所示。首先,作为不同的档案系统,它们向上层提供的函式接口必然也是不同的。但是,如果为了使用系统中不同的档案系统,就必须记忆多套不同的函式接口,这对使用者来说是难以接受的。我们所希望的是向使用者提供一套CreateFile、ReadFile、WriteFile和CloseHandle这样的标准接口,为使用者隐藏掉不同的档案系统间的差异。这个任务就是由档案系统管理程序来完成的。在Windows CE中,使用者见到的并不是档案系统驱动程序所提供的接口,而是经过档案系统管理程序统一包装过的Win32 API函式接口。这种统一接口的作法虽方便了使用者,但另一方面却又不可避免的带来了系统复杂性。对使用者而言,使用者根本不用关心,他所使用的档案所在的volume到底使用何种档案系统,因为档案系统管理程序已经为使用者隐藏了其中的细节,但是在进行的实际的档案操作时,我们又必须要能够找出对应的档案系统,这也是由档案系统管理程序来完成的。在Windows CE中没有目前目录 (current directory) 的概念,所有对档案的存取都必需提供完整路径名称。在为外围储存装置安装档案系统驱动程序的同时,档案系统管理程序会为其注册一个标识性的目录名称。如此一来,当使用者对外围储存装置上的档案进行存取时,档案系统管理程序就可以根据使用者提供的完整目录名称,分析出该档案所在的volume、使用的档案系统等。
图5.3 档案系统管理程序与档案系统驱动程序关系图
5.1.3.3 分割区管理程序与分割区驱动程序
一个储存装置是由多个扇区 (sector) 组成的,每个扇区包含了一组连续的字节,所有扇区的大小都是相同的。储存装置可能被划分为多个逻辑分割区,每个分割区由一组连续的扇区组成。分割区之间不能相互重迭,否则操作系统将停止响应。没有被划分到任何分割区中的储存空间属于未分割区空间。分割区管理程序是储存管理程序的一部分,它透过呼叫分割区驱动程序来完成对这些分割区的管理、挂载 (mount) 与卸载 (unmount)。
同一储存装置上的不同分割区可以使用不同的档案系统,每个分割区所使用的档案系统类型是在建立或格式化时就确定了。在对该分割区进行挂载时,分割区管理程序会通知储存管理程序启动对应的档案系统。
Windows CE可以同时支持多个分割区驱动程序,但是对于一个指定的储存装置来讲只能使用一个分割区驱动程序,由它为分割区管理程序解释该装置上的所有分割区。
如前所述,分割区是对储存装置进行逻辑划分的结果。在Windows CE中,多个分割区既可以使用相同的档案系统,也可以使用不同的档案系统。分割区管理程序透过呼叫分割区驱动程序完成对分割区的操作。分割区驱动程序也是以动态链接库的形式提供的,在Windows CE中预设的分割区驱动程序是MSPart.dll,它输出了一组API。使用者也可以编写自己的分割区驱动程序,只要该分割区驱动程序支持与MSPart.dll http://www.51lm.cn/p/templates/cn/show.php?cid=0&aid=251