理解
Windows CE .NET
中的文件系统体系结构
发布日期:
7/19/2004
|
更新日期:
7/19/2004
Mike Hall
Microsoft Corporation
Microsoft Corporation
Steve Maillet
Entelechy Consulting
Entelechy Consulting
摘要:
在本月的文章中,我们将介绍
Windows CE .NET
文件系统及其组件,并介绍如何扩展该文件系统。
如果您定期阅读
Microsoft Windows CE .NET
的
Microsoft
新闻组,您将发现一组有关文件系统的重复出现的问题,尤其是有关基于配置单元的注册表的问题。(如果您不是该新闻组的定期读者,则会错过很多有用的信息!)在这个月的文章中,我们将深入讨论为了实现这些功能所涉及的系统不同部分的详细信息。我们将首先介绍
Windows CE .NET
中的文件系统体系结构,因为它是我们所讨论的其余功能的基础。在随后的文章中,我们将考查对象存储以及系统注册表是如何工作的。
Windows CE .NET
文件系统是一种灵活的模块化设计,它允许自定义文件系统、筛选器和多种不同的块设备类型。文件系统和所有与文件相关的
API
都是通过
FileSys.exe
进程来管理的。这个模块实现了对象存储和存储管理器(我们将稍微讨论一下对象存储),并将所有文件系统统一到一个根
“
/
”
下面的单个系统中。在
Windows CE .NET
中,所有文件和文件系统都存在于从
“
/
”
作为根开始的单个命名空间中。所有文件均以在层次结构树中从根开始的唯一路径进行标识。这类似于桌面计算机版本的
Windows
,只是没有驱动器号。在
Windows CE
中,驱动器作为文件夹装入根的下面。因此,添加到系统中的新存储卡将装入树的根中,其路径类似于
“
/Storage Card
”
。
FileSys.exe
由下列几个组件组成:
•
|
ROM
文件系统
|
•
|
存储管理器
|
•
|
对象存储
|
对象存储是一个内存堆,由
FileSys.exe
控制。对象存储包含
RAM
系统注册表、
RAM
文件系统和属性数据库。它们都是
FileSys.exe
模块的可选组件。
RAM
文件系统和属性数据库是完全可选的,并且在某些系统中可以根本不存在。对每个
Windows CE
设备来说,以某些形式存在的注册表是必需的。直到
Windows CE
的
4.0
版本,它总是驻留在对象存储中。使用
Windows CE .NET
,它可以作为文件存在于外部装入的文件系统(例如磁盘)中。随后,我们将了解注册表和文件系统是如何产生联系的。
基于
RAM
的文件系统通常连接到呈现给应用程序的统一文件系统的根。就是说,文件
“
/MyFile.txt
”
位于统一系统的根和
RAM
文件系统的根中。
ROM
文件系统连接到统一文件系统中的
“
/Windows
”
文件夹。这意味着,
ROM
中的所有
文件均可作为
“
/Windows
”
文件夹中的只读文件来访问。
存储管理器
(Storage Manager)
是
Windows CE .NET
的新功能。如名称所示,它负责管理系统中的存储设备,以及用于访问它们的文件系统。存储管理器处理
4
种主要项目:
•
|
存储驱动程序。
它们是物理存储介质的设备驱动程序。它们有时称为
“
块驱动程序
”
,这是因为它们提供对数据存储的随机寻址块的访问。
|
•
|
分区驱动程序。
它们为单个存储设备上的多个分区提供管理。
Windows CE .NET
允许物理磁盘包含多个分区,并且每个分区可以格式化为不同的文件系统。分区驱动程序实际上是存储驱动程序的转换器。它公开与存储驱动程序相同的接口,并将分区的块地址转换为存储设备块的真实地址。然后,它将调用传递给存储驱动程序。
|
•
|
文件系统驱动程序。
这些驱动程序将存储设备上的数据组织为文件和文件夹。
Windows CE .NET
附带了几个不同的系统,包括用于
CD
和
DVD
的
UDFS
,以及
FATFS
(包括
FAT32
支持)。在
4.2
版本中,有一个新的系统,称为事务安全
FAT
文件系统
(TFAT)
。(我们可能在以后的文章中讨论它;同样,如果您对此有兴趣,请告诉我们。)
|
•
|
文件系统筛选器。
文件系统筛选器用于处理对文件系统的调用,此后,文件系统才能获得这些调用。这就允许对文件访问进行某些特殊的处理,以便进行数据加密、压缩和使用统计数据进行监视。
|
正如谚语所说,百闻不如一见,下图说明了文件系统的各个组件之间的关系。
图
1. Windows CE
文件系统概述
有关该结构,一个要注意到的重要事情是文件系统筛选器工作于存储管理器的下面,并且无法应用于对象存储中的
ROM
文件系统或
RAM
文件系统。此时,
Microsoft
没有为筛选对这些系统的访问提供机制。因此,在本文中我们将重点讨论上图右侧的内容。为了让您看得更清楚,下图放大了这片区域。
图
2.
存储管理器和相关组件
在上图中可以看见,并非所有文件系统驱动程序都使用了物理设备,即使使用,也可能没有使用分区驱动程序。这就提供了巨大的灵活性。例如,负责提供网络共享访问的网络重定向器使用
WinSock
通过网络与远程服务器通信,并且它在
Windows CE
设备上没有物理磁盘。
既然我们可以看见大多数项目是什么,以及它们是如何相互关联的,下面我们将讨论系统如何加载所有各项。操作系统启动时,
NK.exe
将直接从
ROM
文件系统加载
FileSys.exe
。然后,
FileSys.exe
从
ROM
文件系统内的默认注册表对注册表进行初始化。(这里,在使用配置单元注册表时有一个类似
“
先有鸡还是先有蛋
”
的问题,这是因为注册表在磁盘上的文件中,而文件系统还没有装入。在随后的文章介绍配置单元注册表时,我们将介绍操作系统是如何解决这个问题的。)
然后,
FileSys.exe
将读取注册表项,以便启动各种应用程序。首先列在注册表中的一个应用程序通常是
Device.exe
,即设备管理器。设备管理器从
HKEY_LOCAL_MACHINE/Driver/BuiltIn
项加载驱动程序。正常情况下,任何内置的磁盘设备(例如,硬盘)列在该项下面,所以将加载块驱动程序。块驱动程序通告一个特定的设备类标识符
BLOCK_DRIVER_GUID {A4E7EDDA-E575-4252-9D6B-4195D48BB865}
。
内置到
FileSys.exe
中的存储管理器向设备管理器通知系统注册,以便接收有关块驱动程序加载和卸载的通知。然后,存储管理器打开块驱动程序,并向它查询配置文件名称。每个块设备类型都有一个与它相关的配置文件。
PROFILE
是一个注册表项,用于指定特定类型设备的分区驱动程序和默认文件系统。(我们将对配置文件的注册表项的细节稍加介绍。)
存储管理器读取有关设备的分区驱动程序的信息,并加载适当的驱动程序。(
Microsoft
提供了一个称为
“
mspar
”
的分区驱动程序,用于通过磁盘的主启动记录中的分区表进行标准硬盘分区。当然,如果需要,您可以随便创建您自己的分区,也可以根本不使用它。)
一旦分区驱动程序已加载,然后存储管理器将请求分区驱动程序枚举磁盘上的分区,并标识每个分区上的文件系统。分区驱动程序将从主启动记录
(MBR)
中读取有关分区和文件系统的信息,并向存储管理器提供信息,然后,存储管理器使用该信息来加载每个分区的文件系统驱动程序,并将文件系统装入到统一文件系统的根中。虽然这似乎有很多步骤,但它允许完全在同一个框架中灵活地支持网络重定向器
FATFS
和
DVD ROM
。
在了解
FileSys.exe
如何加载各种组件的步骤以后,我们将更为详细地介绍文件系统驱动程序和文件系统驱动程序管理器
(FSDMGR)
的角色。
FSDMGR
是存储管理器(在该操作系统以前的版本中它是设备管理器的一部分)的一部分,负责向文件系统驱动程序提供服务。因为文件系统将不需要知道数据是否来自磁盘上的分区、或者直接来自磁盘,所以,
FSDMGR
对文件系统驱动程序进行包装,以便为驱动程序的高端或低端提供接口。下图说明这是如何工作的。
图
3.
存储管理器
存储管理器调用文件系统驱动程序
(FSD)
,而
FSD
使用
FSDMGR_ API
从设备检索数据。如果是
CD
(没有分区),则设备通过
FSDMGR
与块驱动程序通信。如果它是有多个分区的硬盘,那么它以同样方式使用
FSDMGR_ API
。但这之后
FSDMGR
会将工作转交给适当的分区驱动程序。
我们已经讨论了存储管理器、
FSDMGR
、
FSD
、分区驱动程序和块驱动程序如何交互和互操作。让我们回过来详细讨论它们是如何加载的,并考查注册表中的配置文件的细节。前面已经提到过,配置文件只是一组注册表值,用于定义有关块设备和应当如何在系统中使用它的信息。配置文件位于以下项的下面:
HKEY_LOCAL_MACHINE/System/StorageManager/Profiles
每个配置文件都是位于基本配置文件项的下面,以此配置文件名称标识的项。例如,如果
Windows CE .NET
设备上有一个硬盘,并且它确实使用硬盘配置文件,则配置文件位于
HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/Hard Disk
下面。所有配置文件信息都包含在该配置文件项下面的命名值中。下表列出了各种值及其目的。
表
1.
配置文件注册表项
值
|
类型
|
说明
|
Folder
|
REG_SZ
|
在
Windows
资源管理器中显示给用户的文件夹名称。对于多个实例,将自动追加整数。(例如,
Storage Card
、
Storage Card2
等等。)
|
FileSystem
|
REG_SZ
|
用作磁盘的默认文件系统的名称。(如果使用了分区驱动程序,则通常不使用它。)
|
PartitionDriver
|
REG_SZ
|
列出如果默认驱动程序不合适时要使用的分区驱动程序。如果该字符串为空,则不加载任何分区驱动程序。如果该值不出现,则使用默认分区驱动程序。
|
AutoFormat
|
REG_DWORD
|
如果磁盘没有格式化,则自动执行格式化
|
AutoPart
|
REG_DWORD
|
如果磁盘没有分区,则自动将它分区,并且其中一个分区占据最大数量的可用磁盘空间。
|
AutoMount
|
REG_DWORD
|
当存储设备驱动程序加载时,自动装入文件系统。
|
Name
|
REG_SZ
|
显示在控制面板
UI
中的配置文件名称。
|
MountFlags
|
REG_DWORD
|
用于确定如何装入文件系统的标志。(详细信息,请参阅下表。)
|
需要特别注意
MountFlags
值。它是下表中的值的位掩码。
表
2. MountFlags
注册表项的标志
标志
|
说明
|
1
|
隐藏文件系统。
|
2
|
可以包含配置单元注册表。
|
4
|
作为文件系统的根(
“
/
”
)装入。
|
8
|
隐藏
ROM
文件系统。(只与
[4]
一起使用。)
|
将文件系统标记为隐藏可以防止它被任何标准的文件和文件夹枚举发现。(例如
FindFirstFile
等等。)存储管理器独立完成该操作,以便设备驱动程序和应用程序可以检测到是否特定系统正在使用存储管理器。(由于较旧版本的操作系统没有它,所以某些驱动程序可能需要与旧的
LoadFSD(Ex)
机制相兼容,以用于加载文件系统。)虽然无法使用
FindFirstFile
来枚举任意的隐藏系统,但如果知道文件系统的名称,则可以在任何会使用文件路径的地方使用它。以下示例显示了如何检测存储管理器是否正在使用某个系统。
BOOL IsStorageManagerRunning()
{
DWORD attr = GetFileAttributes( _T("//StoreMgr") );
if( (attr != -1) && (attr & FILE_ATTRIBUTE_TEMPORARY) )
return TRUE;
return FALSE;
}
MountFlags
的下一位指示文件系统是否可包含基于配置单元的注册表。这使
FileSys.exe
能够管理先前提到的
“
先有鸡还是先有蛋
”
的问题。(因为需要注册表才能加载访问可能在磁盘上的注册表配置单元文件所需的组件
……
)我们将在随后的有关配置单元注册表的文章中介绍如何使用这一位。
后面两位是相关的,当您希望将外部文件系统作为统一文件系统的根装入时,则需要使用它们。可以回想起,通常统一系统的根是
RAM
文件系统。这对电池供电的手持设备很有效,但对有时会关闭的交流电源供电的设备却无效,因为
RAM
内容每次关闭时都会丢失。作为根标志的装入文件系统允许您通过将外部存储作为根进行连接来避免这个问题,因为这样一来,文件
/MyDataFile.TXT
将驻留在外部存储设备的根中。隐藏
ROM
文件系统将隐藏
ROM
文件系统数据文件(但不执行适当的
EXE
和
DLL
),以便允许您更新
ROM
中的所有文件。这就允许您在闪存中使用非常小的操作系统映像,而将大多数可执行文件放在磁盘上,只在需要时才加载它们。(现在很像桌面计算机系统。)
如果特定配置文件的任何值都不存在,则存储管理器将使用
HKEY_LOCAL_MACHINE/System/StorageManager/Profiles
项中的默认值。可以重写的默认值位于
COMMON.REG
中。您应当使用您的
PLATFORM.REG
或
PROJECT.REG
进行重写。(记住,不应当改变
COMMON.REG
!)下表显示了
COMMON.REG
中的默认值。
值
|
默认值
|
Folder
|
LOC_STORE_DEFAULT_FOLDER
(用于设备的
.STR
文件中一个字符串的标识符;在英文内部版本中通常是
“
Storage Card
”
。)
|
FileSystem
|
FATFS
|
PartitionDriver
|
Mspart.dll
|
AutoFormat
|
0
|
AutoPart
|
0
|
AutoMount
|
1
|
MountFlags
|
0
|
小结
Windows CE
文件系统体系结构是灵活的和可扩展的,并且支持:
•
|
多个块设备。
|
•
|
每个块设备支持多个分区。
|
•
|
每个分区支持不同文件系统。
|
•
|
将外部设备文件系统作为根系统装入。
|
注册表是让加载和运行文件系统的过程具有正确的(或期望的)行为的关键。基于配置单元的注册表确实对我们有所帮助。为了使您不再对
“
装入
”
产生恐惧,我们将在随后的文章中使用某些真实的示例来详细考查配置单元注册表。