GNU find 中的“已启用功能”是什么意思?

GNU find 中的“已启用功能”是什么意思?

当我find --version与 GNU find 一起使用时,我得到如下信息:

find (GNU findutils) 4.5.9     
[license text]
Features enabled: D_TYPE O_NOFOLLOW(enabled) LEAF_OPTIMISATION FTS(FTS_CWDFD) CBO(level=2)

这些“特征”是什么意思?中提到了O_NOFOLLOW一种安全措施man find,并且提到了一种优化,可以节省叶节点上的LEAF_OPTIMISATION一些调用。lstat但我找不到任何关于FTS,D_TYPE或 的信息CBO

答案1

这是来自 Ketan 和 daniel kullman 的答案以及我自己的研究的完整答案。

大多数“功能”都是查询优化,因为find通常能够在文件系统上进行(几乎)任意复杂的查询。


D_类型

该功能的存在D_TYPE意味着它是在find支持.该字段是 Linux 也采用的 BSD 扩展,它提供了从andfriends 返回的结构体中的文件类型(目录、文件、管道、套接字、字符/块设备等)。作为一种优化,可以使用它来减少或消除用作过滤表达式时的调用。d_typestruct direntreaddirfindlstat-type

readdir可能并不总是填充d_type在某些文件系统上,因此有时lstat仍然需要。

更多信息来自官方文档:https://www.gnu.org/software/findutils/manual/html_node/find_html/d_005ftype-Optimization.html

O_NOFOLLOW

该选项将显示为(enabled)(disabled)。如果存在并启用,此功能将实施一项安全措施,防止find某些 TOCTTOU 竞争攻击。具体来说,它可以防止find在执行目录遍历时遍历符号链接,如果在检查目录的文件类型之后但在输入目录之前用符号链接替换目录,则可能会发生这种情况。

启用此选项后,findopen(..., O_NOFOLLOW)在目录上使用仅打开真实目录,然后用于openat打开该目录中的文件。

LEAF_OPTIMISATION

这种稍微晦涩的优化允许find使用父目录的链接计数来推断父目录的哪些子目录是目录,因为子目录将贡献父目录的链接计数(通过链接..)。在某些情况下,它将允许find省略stat呼叫。但是,如果文件系统或操作系统错误地表示st_nlinks,则可能会导致find产生虚假结果(值得庆幸的是,这种情况很少发生)。

更多信息参见官方文档:https://www.gnu.org/software/findutils/manual/html_node/find_html/Leaf-Optimization.html

FTS

启用后,该FTS功能会导致find使用fts用于遍历文件层次结构的 API,而不是直接递归实现。

我不清楚它的优点fts是什么,但基本上是迄今为止我见过的FTS所有默认版本的默认设置。find

更多信息:https://www.gnu.org/software/findutils/manual/html_node/find_html/fts.html,http://man7.org/linux/man-pages/man3/fts.3.html

国会预算办公室

事实证明(在阅读了finddaniel kullman 建议的源代码之后)“CBO”指的是查询优化级别(它代表“基于成本的优化器”)。例如,如果我这样做find -O9001 --version,我会得到

Features enabled: D_TYPE O_NOFOLLOW(enabled) LEAF_OPTIMISATION FTS() CBO(level=9001) 

看看-O中的选项man find,我明白了

-Olevel
  Enables query optimisation.   The find program reorders tests to speed up execution  while  preserving  the  overall
  effect; that is, predicates with side effects are not reordered relative to each other.  The optimisations performed
  at each optimisation level are as follows.

  0      Equivalent to optimisation level 1.

  1      This is the default optimisation level  and  corresponds  to  the  traditional  behaviour.   Expressions  are
         reordered  so that tests based only on the names of files (for example -name and -regex) are performed first.

  2      Any -type or -xtype tests are performed after any tests based only on the names  of  files,  but  before  any
         tests  that  require information from the inode.  On many modern versions of Unix, file types are returned by
         readdir() and so these predicates are faster to evaluate than predicates which need to stat the file first.

  3      At this optimisation level, the full cost-based query optimiser is enabled.  The order of tests  is  modified
         so  that  cheap  (i.e. fast) tests are performed first and more expensive ones are performed later, if neces-
         sary.  Within each cost band, predicates are evaluated earlier or later according to whether they are  likely
         to  succeed or not.  For -o, predicates which are likely to succeed are evaluated earlier, and for -a, predi-
         cates which are likely to fail are evaluated earlier.

  The cost-based optimiser has a fixed idea of how likely any given test is to succeed.  In some cases the probability
  takes  account of the specific nature of the test (for example, -type f is assumed to be more likely to succeed than
  -type c).  The cost-based optimiser is currently being evaluated.   If it does not actually improve the  performance
  of find, it will be removed again.  Conversely, optimisations that prove to be reliable, robust and effective may be
  enabled at lower optimisation levels over time.  However, the default behaviour (i.e. optimisation level 1) will not
  be  changed  in  the 4.3.x release series.  The findutils test suite runs all the tests on find at each optimisation
  level and ensures that the result is the same.

谜团已揭开!有点奇怪的是,该选项是一个运行时值;通常我希望--version输出仅反映编译时选项。

答案2

有关信息在以下页面O_NOFOLLOW中给出:infofind

9.2.1.1 O_NOFOLLOW

......................

如果您的系统支持 O_NOFOLLOW 标志 (1),则open(2)' system call,find' 在安全更改目录时会使用它。首先打开目标目录,然后find' changes working directory with the调用 fchdir()' 系统调用。这确保了符号链接不被遵循,从而防止使用符号链接的竞争条件攻击。

...

从源代码树来看,CBO仅出现在文件中parser.c

 printf("CBO(level=%d) ", (int)(options.optimisation_level)); 

表明它是基于成本的优化(我的最佳猜测)。

D_TYPE出现在源树中的多个位置,似乎与目录条目类型有关:

$ grep 'D_TYPE' */**

产量:

find/parser.c:#if defined USE_STRUCT_DIRENT_D_TYPE && defined HAVE_STRUCT_DIRENT_D_TYPE
lib/savedirinfo.c:#if defined HAVE_STRUCT_DIRENT_D_TYPE && defined USE_STRUCT_DIRENT_D_TYPE

以及更多条目。你可以找到源码这里

答案3

当查看 findutils 源代码树时(http://git.savannah.gnu.org/cgit/findutils.git/tree/),我发现了以下内容:

  • configure.ac: --enable-d_type-optimization,利用readdir()在struct dirent.d_type中返回的文件类型数据),
  • m4/withfts.m4: --without-fts 使用旧的机制来搜索文件系统,而不是使用 fts()

我没有找到任何关于 CBO 的信息;您可能需要下载源代码并搜索该术语..

相关内容