如何使用 readlink 进行动态内存分配
问题:
在 Linux 机器上我想读取链接的目标字符串。从文档中我找到了以下代码示例(没有错误处理):
struct stat sb;
ssize_t r;
char * linkname;
lstat("<some link>", &sb);
linkname = malloc(sb.st_size + 1);
r = readlink("/proc/self/exe", linkname, sb.st_size + 1);
问题是 sb.st_size 在我的系统上为链接返回 0。
那么如何在此类系统上为 readline 动态分配内存呢?
非常感谢!
一种可能的解决方案:
供将来参考。使用 jilles 提出的观点:
struct stat sb;
ssize_t r = INT_MAX;
int linkSize = 0;
const int growthRate = 255;
char * linkTarget = NULL;
// get length of the pathname the link points to
if (lstat("/proc/self/exe", &sb) == -1) { // could not lstat: insufficient permissions on directory?
perror("lstat");
return;
}
// read the link target into a string
linkSize = sb.st_size + 1 - growthRate;
while (r >= linkSize) { // i.e. symlink increased in size since lstat() or non-POSIX compliant filesystem
// allocate sufficient memory to hold the link
linkSize += growthRate;
free(linkTarget);
linkTarget = malloc(linkSize);
if (linkTarget == NULL) { // insufficient memory
fprintf(stderr, "setProcessName(): insufficient memory\n");
return;
}
// read the link target into variable linkTarget
r = readlink("/proc/self/exe", linkTarget, linkSize);
if (r < 0) { // readlink failed: link was deleted?
perror("lstat");
return;
}
}
linkTarget[r] = '\0'; // readlink does not null-terminate the string
Problem:
On a linux machine I want to read the target string of a link. From documentation I have found the following code sample (without error processing):
struct stat sb;
ssize_t r;
char * linkname;
lstat("<some link>", &sb);
linkname = malloc(sb.st_size + 1);
r = readlink("/proc/self/exe", linkname, sb.st_size + 1);
The probelm is that sb.st_size returns 0 for links on my system.
So how does one allocate memory dynamically for readline on such systems?
Many thanks!
One possible solution:
For future reference. Using the points made by jilles:
struct stat sb;
ssize_t r = INT_MAX;
int linkSize = 0;
const int growthRate = 255;
char * linkTarget = NULL;
// get length of the pathname the link points to
if (lstat("/proc/self/exe", &sb) == -1) { // could not lstat: insufficient permissions on directory?
perror("lstat");
return;
}
// read the link target into a string
linkSize = sb.st_size + 1 - growthRate;
while (r >= linkSize) { // i.e. symlink increased in size since lstat() or non-POSIX compliant filesystem
// allocate sufficient memory to hold the link
linkSize += growthRate;
free(linkTarget);
linkTarget = malloc(linkSize);
if (linkTarget == NULL) { // insufficient memory
fprintf(stderr, "setProcessName(): insufficient memory\n");
return;
}
// read the link target into variable linkTarget
r = readlink("/proc/self/exe", linkTarget, linkSize);
if (r < 0) { // readlink failed: link was deleted?
perror("lstat");
return;
}
}
linkTarget[r] = '\0'; // readlink does not null-terminate the string
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
POSIX 规定符号链接的
st_size
字段应设置为链接中路径名的长度(不带'\0'
)。但是,Linux 上的/proc
文件系统不符合 POSIX 标准。 (它有更多的违规行为,例如一次一个字节地读取某些文件。)您可以分配一定大小的缓冲区,尝试
readlink()
并使用更大的缓冲区重试如果缓冲区不够大(readlink()
返回缓冲区中适合的字节数),直到缓冲区足够大。或者,您可以使用 PATH_MAX 并中断对系统的可移植性,因为它不是编译时常量或路径名可能比该常量长(POSIX 允许)。
POSIX says the
st_size
field for a symlink shall be set to the length of the pathname in the link (without'\0'
). However, the/proc
filesystem on Linux is not POSIX-compliant. (It has more violations than just this one, such as when reading certain files one byte at a time.)You can allocate a buffer of a certain size, try
readlink()
and retry with a larger buffer if the buffer was not large enough (readlink()
returned as many bytes as fit in the buffer), until the buffer is large enough.Alternatively you can use
PATH_MAX
and break portability to systems where it is not a compile-time constant or where the pathname may be longer than that (POSIX permits either).其他答案没有提到它,但是有
realpath
函数,它完全可以完成您想要的操作,这是由 POSIX.1-2001 指定的。从联机帮助页:
如果您愿意,
realpath
还可以为您处理动态内存分配。再次,摘录自联机帮助页:举一个简单、完整的例子:
The other answers don't mention it, but there is the
realpath
function, that does exactly what you want, which is specified by POSIX.1-2001.from the manpage:
realpath
also handles the dynamic memory allocation for you, if you want. Again, excerpt from the manpage:As a simple, complete example:
st_size 在 /proc 上没有给出正确的答案。
相反,您可以 malloc PATH_MAX 或 pathconf(_PC_PATH_MAX) 字节。对于大多数情况来说这应该足够了。如果您希望能够处理比这更长的路径,则可以在循环中调用 readlink 并在 readlink 返回值指示缓冲区太短时重新分配缓冲区。请注意,许多其他 POSIX 函数只是假设 PATH_MAX 就足够了。
st_size does not give the correct answer on /proc.
Instead you can malloc PATH_MAX, or pathconf(_PC_PATH_MAX) bytes. That should be enough for most cases. If you want to be able to handle paths longer than that, you can call readlink in a loop and reallocate your buffer if the readlink return value indicates that the buffer is too short. Note though that many other POSIX functions simply assume PATH_MAX is enough.
我有点困惑为什么
st_size
为零。根据 POSIX:来源:http://pubs.opengroup.org/onlinepubs/9699919799/functions/lstat .html
如果
st_size
不起作用,我认为您唯一的选择是动态分配缓冲区并不断调整其大小,只要因为 readlink 的返回值等于缓冲区大小。I'm a bit puzzled as to why
st_size
is zero. Per POSIX:Source: http://pubs.opengroup.org/onlinepubs/9699919799/functions/lstat.html
If
st_size
does not work, I think your only option is to dynamically allocate a buffer and keep resizing it larger as long as the return value ofreadlink
is equal to the buffer size.readlink(2)
的联机帮助页表示它将默默截断如果缓冲区太小。如果您确实想要不受限制(并且不介意为额外工作付出一些成本),您可以从给定的分配大小开始,不断增加它并重新尝试readlink
调用。当下次调用 readlink 返回与上次迭代相同的字符串时,您可以停止增长缓冲区。The manpage for
readlink(2)
says it will silently truncate if the buffer is too small. If you truly want to be unbounded (and don't mind paying some cost for extra work) you can start with a given allocation size and keep increasing it and re-trying thereadlink
call. You can stop growing the buffer when the next call toreadlink
returns the same string it did for the last iteration.您到底想通过 lstat 实现什么目的?
您应该能够通过以下内容获得目标
如果您想获取文件名大小的长度,我认为 st_size 不是正确的变量...但这可能是一个不同的问题。
What exactly are you trying to achieve with the lstat?
You should be able to get the target with just the following
If you're trying to get the length of the file name size, I don't think st_size is the right variable for that... But that's possibly a different question.