如何使用 readlink 进行动态内存分配

发布于 2025-01-07 19:05:55 字数 1519 浏览 0 评论 0原文

问题:

在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

只是我以为 2025-01-14 19:05:55

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).

凉城已无爱 2025-01-14 19:05:55

其他答案没有提到它,但是有 realpath 函数,它完全可以完成您想要的操作,这是由 POSIX.1-2001 指定的。

char *realpath(const char *path, char *resolved_path);

从联机帮助页:

realpath() 展开所有符号链接并解析对
/./、/../ 以及名为 null 终止的字符串中额外的“/”字符
按路径生成规范化的绝对​​路径名。

如果您愿意,realpath 还可以为您处理动态内存分配。再次,摘录自联机帮助页:

如果resolved_pa​​th指定为NULL,则realpath()使用
malloc(3) 分配最多 PATH_MAX 字节的缓冲区来保存
解析路径名,并返回指向此缓冲区的指针。来电者
应使用 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;
}

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.

char *realpath(const char *path, char *resolved_path);

from the manpage:

realpath() expands all symbolic links and resolves references to
/./, /../ and extra '/' characters in the null-terminated string named
by path to produce a canonicalized absolute pathname.

realpath also handles the dynamic memory allocation for you, if you want. Again, excerpt from the manpage:

If resolved_path is specified as NULL, then realpath() uses
malloc(3) to allocate a buffer of up to PATH_MAX bytes to hold the
resolved pathname, and returns a pointer to this buffer. The caller
should deallocate this buffer using free(3).

As a simple, complete example:

#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;
}
因为看清所以看轻 2025-01-14 19:05:55

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.

极致的悲 2025-01-14 19:05:55

我有点困惑为什么 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 的返回值等于缓冲区大小。

I'm a bit puzzled as to why st_size is zero. Per POSIX:

For symbolic links, the st_mode member shall contain meaningful information when used with the file type macros. The file mode bits in st_mode are unspecified. The structure members st_ino, st_dev, st_uid, st_gid, st_atim, st_ctim, and st_mtim shall have meaningful values and the value of the st_nlink member shall be set to the number of (hard) links to the symbolic link. The value of the st_size member shall be set to the length of the pathname contained in the symbolic link not including any terminating null byte.

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 of readlink is equal to the buffer size.

千と千尋 2025-01-14 19:05:55

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 the readlink call. You can stop growing the buffer when the next call to readlink returns the same string it did for the last iteration.

高冷爸爸 2025-01-14 19:05:55

您到底想通过 lstat 实现什么目的?

您应该能够通过以下内容获得目标

char buffer[1024];
ssize_t r = readlink ("/proc/self/exe", buffer, 1024);
buffer[r] = 0;

printf ("%s\n", buffer);

如果您想获取文件名大小的长度,我认为 st_size 不是正确的变量...但这可能是一个不同的问题。

What exactly are you trying to achieve with the lstat?

You should be able to get the target with just the following

char buffer[1024];
ssize_t r = readlink ("/proc/self/exe", buffer, 1024);
buffer[r] = 0;

printf ("%s\n", buffer);

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文