在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
答案 0 :(得分:6)
POSIX表示符号链接的st_size
字段应设置为链接中路径名的长度(不含'\0'
)。但是,Linux上的/proc
文件系统不符合POSIX标准。 (它有更多的违规,而不仅仅是这个,例如一次读取一个字节的某些文件。)
您可以分配一定大小的缓冲区,尝试readlink()
并在缓冲区不够大的情况下使用更大的缓冲区重试(readlink()
返回缓冲区中适合的字节数),直到缓冲区足够大。
或者,您可以使用PATH_MAX
并将可移植性分解为不是编译时常量或路径名可能长于此值的系统(POSIX允许)。
答案 1 :(得分:2)
其他答案没有提及,但有realpath
函数,它完全符合您的要求,由POSIX.1-2001指定。
char *realpath(const char *path, char *resolved_path);
来自联机帮助页:
如果需要,realpath()展开所有符号链接并解析对其的引用 /./,/../和名为的以null结尾的字符串中的额外'/'字符 通过路径生成规范化的绝对路径名。
realpath
还可以为您处理动态内存分配。再次,摘自联机帮助页:
如果resolve_path指定为NULL,则realpath()使用 malloc(3)分配一个最多为PATH_MAX字节的缓冲区来保存 解析了pathname,并返回指向此缓冲区的指针。呼叫者,召集者 应该使用free(3)释放此缓冲区。
作为一个简单,完整的例子:
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
int
resolve_link (const char *filename)
{
char *res = realpath(filename, NULL);
if (res == NULL)
{
perror("realpath failed");
return -1;
}
printf("%s -> %s\n", filename, res);
free(res);
return 0;
}
int
main (void)
{
resolve_link("/proc/self/exe");
return 0;
}
答案 2 :(得分:1)
st_size没有在/ proc。上给出正确答案。
相反,您可以使用malloc PATH_MAX或pathconf(_PC_PATH_MAX)字节。对大多数情况来说这应该足够了。如果您希望能够处理比这更长的路径,则可以在循环中调用readlink并在readlink返回值指示缓冲区太短时重新分配缓冲区。注意,虽然许多其他POSIX函数只是假设PATH_MAX就足够了。
答案 3 :(得分:0)
为什么st_size
为零,我有点疑惑。按POSIX:
对于符号链接,当与文件类型宏一起使用时,st_mode成员应包含有意义的信息。 st_mode中的文件模式位未指定。结构成员st_ino,st_dev,st_uid,st_gid,st_atim,st_ctim和st_mtim应具有有意义的值,并且st_nlink成员的值应设置为符号链接的(硬)链接数。 st_size成员的值应设置为符号链接中包含的路径名的长度,不包括任何终止空字节。
来源:http://pubs.opengroup.org/onlinepubs/9699919799/functions/lstat.html
如果st_size
不起作用,我认为你唯一的选择就是动态分配一个缓冲区,并且只要readlink
的返回值等于缓冲区大小,就不断调整它的大小。
答案 4 :(得分:0)
manpage for readlink(2)
表示如果缓冲区太小,它会静默截断。如果你真的想要无限制(并且不介意为额外的工作支付一些费用),你可以从给定的分配大小开始并继续增加它并重新尝试readlink
调用。当下一次调用readlink
返回与上次迭代时相同的字符串时,您可以停止增长缓冲区。
答案 5 :(得分:-1)
你想用lstat实现什么目标?
你应该能够通过以下
获得目标char buffer[1024];
ssize_t r = readlink ("/proc/self/exe", buffer, 1024);
buffer[r] = 0;
printf ("%s\n", buffer);
如果你试图获取文件名大小的长度,我认为st_size不是正确的变量......但这可能是一个不同的问题。