Bindlink API 概述
绑定链接库允许管理员用户通过绑定筛选器(迷你筛选器 bindflt.sys)将文件系统命名空间绑定到本地虚拟路径。 绑定链接可提供从本地虚拟路径到本地或远程后备路径的文件系统重定向。 它们主要可实现两种场景:首先,可通过网络共享使远程文件显示为本地文件,从而提高应用兼容性;其次,它们可实现以下场景——应用程序希望来自不同位置的文件能出现在新的位置(可能具有不同名称和目录结构),但无需复制这些文件。 绑定链接对应用程序和所有现有 API 工作均透明,而无需了解此重定向。 不会为虚拟路径创建任何物理文件或目录,而绑定链接会将这些文件与目录的安全描述符和权限扩展到虚拟路径。
使用情况
API 集由 2 个相关函数组成:
- CreateBindLink – 此 API 允许管理员在虚拟路径与后备路径之间创建绑定链接。
- RemoveBindLink – 此 API 允许用户删除以前通过调用 CreateBindLink 而创建的链接。
有关这些函数的示例用法,请参阅绑定链接示例。
创建绑定链接
绑定链接对应用程序透明,且尽管这些链接存在,但所有操作均会应用于后备路径。 因此,DeleteFile 或 RemoveDirectory 会处理后备路径,从而有效删除后备路径,但不是链接。 如果用户没有管理员权限、用户无权打开虚拟路径或后备路径、备份路径不存在、此虚拟路径存在其他链接,或在设置链接时出现内部故障,此 API 则会失败。 具体而言,管理员用户应能附加筛选器(针对 FilterAttach 的权限)、连接到筛选器端口(针对 FilterConnectCommunicationPort 的权限),以及访问支持路径的根目录,否则此 API 将失败并显示 ERROR_ACCESS_DENIED。
如果应用尝试通过此链接来访问设置此链接后已删除的某一后备路径,该应用则会出现 ERROR_FILE_NOT_FOUND*。 稍后,如果再次创建此后备路径,则会将此链接应用于新的后备路径。 如果要在此链接存在的情况下在 virtualPath 中创建文件,则会在 virtualPath 中显示该文件(如果该链接已存在,但在后备路径上进行了物理创建)。 删除此链接后,该文件只会显示在后备路径上,且不再显示在 virtualPath 中。 此情况适用于下述所有类型的链接。
根据虚拟路径是否在磁盘上存在,生成的链接可能为无定位链接或影子链接。
无定位链接
无定位链接是指在创建链接之前且磁盘上不存在虚拟路径时所创建的绑定链接。 创建此类链接时,虚拟路径会合成到内存中,并像文件系统中的常规路径一样进行显示。 请注意,若要创建此类绑定链接,虚拟路径的父项必须以磁盘目录或以前创建的链接形式而存在。 例如,若要将 C:\Foo\Bar 用作虚拟路径,C:\Foo 则须为磁盘上的目录或是以前为其他链接而创建的虚拟路径。 由于卷没有父项,因此没有指向不存在卷的无定位链接。 例如,如果尚无名为“Z”的卷,创建包含虚拟路径“Z:”的绑定链接则会失败。
影子链接
影子链接是指在创建链接之前卷上已存在虚拟路径的绑定链接。 当此类虚拟路径用于创建链接时,虚拟路径的内容会隐藏,而后备路径的内容会在虚拟路径上变为可见。 例如:
- C:\Foo 存在于磁盘上,且其中包含两个文件 Cat.txt 和 Dog.txt
- C:\Bar 存在于磁盘上,且其中包含两个文件 Cow.txt 和 Mouse.txt
在将 C:\Foo 作为虚拟路径并将 C:\Bar 作为后备路径的情况下来创建链接时,C:\Foo 路径会向所有用户显示 Cow.txt 和 Mouse.txt,同时隐藏 Cat.txt 和 Dog.txt,直到删除该链接。
下图中的另一示例有助于区分影子链接和无定位链接。
枚举 C:\Foo 的用户即使在创建图中所示的任意绑定链接之前,也可找到该目录及其现有内容。 创建链接后,枚举 C:\Foo 时会显示 C:\Foo\Bar 和 Cow.txt。 由于 C:\Foo 存在于磁盘上或是没有此链接,因此 C:\Foo 与 \\Remote\Target 之间的链接为影子链接。
创建第二个绑定链接之前,枚举 C:\Foo 的用户不会看到 C:\Foo\Bar。 由于 C:\Foo\Bar 仅会在添加 C:\Foo\Bar 与 C:\Target2 之间的链接后进行显示,因此它为纯虚拟链接,且 C:\Foo\Bar 与 C:\Target2 之间的链接属于无定位链接。
请注意,对于这两种类型的链接,后备路径的安全描述符均适用。
可传入某些标志以更改默认行为,从而满足用户的需求。
CREATE_BIND_LINK_FLAG_MERGED 标志
合并链接类似于影子链接,但虚拟路径中的现有内容会与后备路径合并。 若要创建此类链接,应使用 CREATE_BIND_LINK_FLAG_MERGED 标志。
再次以针对影子链接的上一示例为例,同时添加此标志。
例如:
- C:\Foo 存在于磁盘上,且其中包含两个文件 Cat.txt 和 Dog.txt
- C:\Bar 存在于磁盘上,且其中包含两个文件 Cow.txt 和 Mouse.txt
在将 C:\Foo 作为虚拟路径、将 C:\Bar 作为后备路径并附带 CREATE_BIND_LINK_FLAG_MERGED 标志的情况下来创建链接时,C:\Foo 路径会显示 Cat.txt、Dog.txt、Cow.txt 和 Mouse.txt。
请务必记住,合并链接仅在虚拟路径为目录时才适用。 如果某一文件同时出现在后备路径和虚拟路径中,后备路径中的文件则优先;即,虚拟路径中的文件将被屏蔽。 此特性会以递归方式应用于虚拟路径中的所有目录。 由于此合并操作会应用于目录,因此当 virtualPath 和 backingPath 存在采用相同名称且位于同一级别的目录时,则会将此目录合并为该链接的其中一项结果。 如果此链接并非合并链接,backingPath 中的目录则优先且会覆盖 virtualPath 中的目录。 如果在合并链接存在时于合并路径上创建文件,则会在 backingPath 中以物理方式创建该文件(与涉及任意绑定链接的情况一样),并覆盖 virtualPath 中具有相同名称的文件。
以以下目录结构和两个不同链接为例:
- c:\Foo\Sub\Foo_sub.txt
- c:\Bar\Sub\Bar_sub.txt。
如果将 c:\Foo 链接到 c:\Bar 而不进行合并,c:\Foo\Sub 则仅会显示 Bar_sub.txt。 但是,如果已将 c:\Foo 链接到 c:\Bar 并进行合并,c:\Foo\Sub 则会显示 Foo_sub.txt 和 Bar_sub.txt。
由于绑定链接属于基于路径的链接,因此在创建链接后于后备路径中替换、修改或删除/重新创建文件时,虚拟路径均会指向访问该链接时所存在的文件。 出现此情况的原因在于,打开文件时会解析该链接。 因此,当后备路径中的某一文件由于此链接而屏蔽虚拟路径中的其他文件,以及已删除支持路径中的该文件时,旨在打开该文件的后续请求均会在虚拟路径中打开此文件。
CREATE_BIND_LINK_FLAG_READ_ONLY 标志
只读链接属于绑定链接,而在其中会阻止系统上的用户更改驻留在后备路径中的文件(如果这些用户会通过虚拟路径进行访问)。 这意味着,有权修改后备路径上文件的用户仍可通过后备路径访问该文件;但如果该用户通过虚拟路径访问该文件,则无法修改此文件。 通常,访问相应的虚拟路径时,会应用后备路径的权限;但在使用 CREATE_BIND_LINK_FLAG_READ_ONLY 标志时,则会屏蔽写入权限。 此特性可确保应用程序看到该文件处于 CREATE_BIND_LINK_FLAG_READ_ONLY。
请注意,只读限制仅适用于驻留在磁盘上的后备路径中的文件。 如果此链接已合并,且最初来自虚拟目录路径的文件处于可见状态,则仍可修改这些文件。
例如:
- C:\Foo 存在于包含文件 Cat.txt 的磁盘上
- C:\Bar 存在于包含文件 Cow.txt 的磁盘上
在将 C:\Foo 作为虚拟路径并将 C:\Bar 作为后备路径的情况下来创建链接,且该链接会被标记为只读且已合并时,Cat.txt 和 Cow.txt 将在 C:\Foo 中显示,但可修改 Cat.txt 而无法修改 Cow.txt。
此外,此 API 还支持其他几个链接场景。 后面的部分将介绍这些权限。
嵌套链接
绑定链接可进行嵌套。 这意味着虚拟路径的上级或后代组件也可作为自身链接的虚拟路径。
请注意,随后的循环链接不存在限制。
以上面的“嵌套绑定链接”图中的链接和链接顺序为例。
如果使用虚拟路径 C:\Foo\Bar 来创建链接,则可在将 C:\Foo 作为其虚拟路径的情况下创建另一链接,同时还可在将 C:\Foo\Bar\Baz 作为其虚拟路径的情况下创建另一链接。
例如:
- C:\Target 存在于包含文件 Cat.txt 的磁盘上
- C:\Target2 存在于包含文件 Dog.txt 的磁盘上
- C:\Foo 存在于包含目录 Bar 的磁盘上
如果 C:\Foo\Bar 已链接到 C:\Target(链接 1),然后 C:\Foo 已链接到 C:\Target2(链接 2),则枚举 C:\Foo 的用户将看到 Dog.txt 以及 Bar 目录,因为 Bar 是其自身链接的虚拟路径。 随后,如果 C:\Foo\Bar\Baz 已链接到 C:\Target2(链接 3),则枚举 c:\Foo\Bar 的用户将看到 Cat.txt 和 Baz 目录,因为 Baz 是其自身链接的虚拟路径。
其他绑定链接场景
以下几点十分重要,且应在决定某一链接或一组链接的结果时同时纳入考虑:
如果虚拟路径或链接中存在具有相同名称的实体,则后备路径始终优先且会进行覆盖。 此特性适用于所有类型的绑定链接。
例如,以以下链接为例:
c:\Foo 已链接到 c:\Target,其中 c:\Target 为一个文件。
在此情况下,c:\Foo 看似为一个文件,且其中包含针对无定位链接的 c:\Target 的内容。 即使 c:\Foo 为存在于本地的目录(影子链接),但当此链接和后备路径均存在时,上述链接也会使 c:\Foo 看似为一个文件。
出现冲突链接时,最近创建的链接更为优先。 但是,最近的链接无法隐藏以前的链接。
再比如,以以下链接为例。 第二个链接会更改命名空间的视图。
- 链接 1:c:\Foo 已链接到 c:\Target,其中 c:\Target 为一个目录。 c:\Target 包含 Bar 文件
- 链接 2:c:\Foo\Bar 已链接到 c:\Target2,其中 Target2 为包含文件 Cat.txt 的目录
在此情况下,创建链接 1 后,c:\Foo 将包含 Bar 文件。 但在链接 2 之后,c:\Foo 将显示包含文件 Cat.txt 的 Bar 目录。 同样,如果 c:\Target2 为一个文件,则 c:\Foo\Bar 将是包含 C:\Target2 的内容的一个文件
另一方面,如果颠倒这些链接的顺序(如下所示),c:\Foo\Bar 则仍会显示为一个目录,且其中会显示 c:\Target2 中的 Cat.txt。 后备路径优先于虚拟路径下的项目,但并不优先于虚拟路径根目录自身。
- 链接 1:c:\Foo\Bar 已链接到 c:\Target2,其中 Target2 为包含文件 Cat.txt 的目录
- 链接 2:c:\Foo 已链接到 c:\Target,其中 c:\Target 为一个目录。 c:\Target 包含 Bar 文件
若要成功创建链接,虚拟路径的父项应存在于本地,或因上一链接中的 backingPath 而显示,再或是作为链接中的虚拟路径自身。
例如,如果 c:\Foo 首先链接到 c:\Target,然后 c:\Foo\Bar\Baz 被链接到后备路径,则 c:\Foo\Bar\Baz 中的链接会成功(如果 c:\Foo\Bar 因出现以下某一情况而存在:)
- c:\Foo\Bar 存在于本地,且上一链接中出现的某一例外情况确保 c:\Foo\Bar 未被 c:\Target 隐藏(请参阅下一节中的“例外情况”),或是
- c:\Foo\Bar 因上一链接而存在(例如,如果 c:\Target 包含 Bar 目录),或是
- c:\Foo\Bar 为另一链接中的虚拟路径自身(c:\Foo\Bar ==> 某些内容)
注意
这意味着必须创建嵌套的无定位链接,且最深的链接在最后进行创建。 但是,影子链接没有此类限制,因为磁盘上已存在虚拟路径。
以按相同顺序创建的以下链接为例:
- C:\Foo 已链接到 C:\Target
- C:\Foo\Bar 已链接到 c:\Target2
创建链接不会影响后备路径的行为。 因此,Bar 虚拟目录会在 c:\Foo 中显示,而不在 c:\Target 中显示。 链接表如下所示:
- C:\Foo --> c:\Target、C:\Foo\Bar --> c:\Target2 而不是
- C:\Foo --> c:\Target、c:\Target\Bar --> c:\Target2
绑定链接的例外情况
(可选)可通过指定例外情况来限制所创建链接的范围。 例外路径为不会应用此链接的虚拟路径的后代。 例外路径可为文件或目录,但应为虚拟路径的后代。 API 要求在创建链接时可访问例外路径。 该例外情况会应用于例外路径的所有后代。 例如:
- C:\Foo 存在于磁盘上,且其中包含 Bar 目录和 Baz 目录
- C:\Foo\Bar 包含 Cat.txt
- C:\Foo\Baz 包含 Dog.txt
- C:\Target 存在于磁盘上并包含文件 Cow.txt
如果创建从 C:\Foo 到 C:\Target 的链接,但 C:\Foo\Baz 除外,用户则会看到以下内容:
- C:\Foo 将包含 C:\Target 中的文件 Cow.txt,以及 Baz 目录和其子项 Dog.txt。 请注意,C:\Foo\Bar 将不可见,因为它已被此链接隐藏。
下图表示上述场景:
最后,绑定链接例外情况不适用于无定位链接,因为无定位虚拟路径在定义上不存在后代,因此没有符合条件的路径。 如果尝试将例外情况传递给无定位链接,此 API 则会返回错误。