是否可以在不复制参数字符串的情况下读取符号链接值?

时间:2016-04-24 02:20:02

标签: linux linux-kernel system-calls

Linux系统调用readlink读取符号链接的原型为:

ssize_t readlink(const char *pathname, char *buf, size_t bufsiz);

在通常的用法中,当一个人编写一个函数来访问由一个以空字符结尾的常量字符串给出的文件路径时,路径中的目录可能是必须首先遵循的符号链接才能到达该文件。例如,参见函数open的原型:

int open(const char *pathname, int flags);

当路径以空值终止时,其中的目录由/终止,并且必须将它们作为参数提供给readlink。由于路径字符是"只读",即使是暂时的,也不能将/字符替换为0.

这意味着必须首先复制目录,附加0,然后应用readlink。与临时替换一个角色相比,这个速度较慢。

我觉得很奇怪,所有现有的Linux库都必须这样做,而且没有办法更快地完成这项工作。

我需要编写一个函数来尽可能快地访问文件路径。没有其他方法可以关注目录符号链接,而不是复制要应用于readlink的目录字符串吗?

补充:一个例子 - 让我们说我想编写函数open。这个函数必须遍历给它的路径,每当它看到一个目录时,它必须看看它是否是符号链接,如果是,请阅读并遵循它。

1 个答案:

答案 0 :(得分:1)

您想要实现类似于以下的功能:

int open(const char *pathname, int flags);

您决定使用以下方法在路径的每个级别跟踪符号链接:

ssize_t readlink(const char *pathname, char *buf, size_t bufsiz);

您希望避免复制pathname,但仍然可以将其前缀传递给readlink()

我挖掘了readlink()的源代码,希望找到我们可以根据您的目的轻松修改它的克隆。我的想法是,也许有一个潜在的函数可以给pathname一个明确的长度,而不是依赖于null终止符。

但我没有这么幸运。例如:https://fossies.org/dox/glibc-2.23/sysdeps_2unix_2sysv_2linux_2generic_2readlink_8c_source.html

由于以null结尾的字符串是C语言中的通用语,因此您可能会有点不幸。我能给你的最佳建议是:

  1. 更改您的open() - 类似于将pathname视为非常量。这可能会强制一些调用者复制参数,但至少那些已经持有非const字符串的人可以直接使用它。

  2. 使用PATH_MAX中预先分配的长度为open()的字符串的池(每个线程一个,因此请考虑使用线程局部存储)。在已经分配目标时复制字符串的速度并不慢,而且您只需要按open()执行一次(之后您可以在/之间交换'\0',如问题中所述。

  3. 使用realpath()代替readlink()。它会立即规范化整个路径,因此您可能不必担心复制realpath()本身内部的单个副本(您还会遇到readlink())。