如何使用readlink和动态内存分配

时间:2012-02-21 21:24:29

标签: c linux glibc uclibc

问题:

在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

6 个答案:

答案 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不是正确的变量......但这可能是一个不同的问题。