检索符号链接的路径

时间:2014-09-12 21:14:42

标签: c linux path size symlink

我想将符号链接指向的文件的路径存储到bufff中。这适用于我当前使用readlink的实现,但它抓取了我不需要的额外数据,因为我的bufsize是任意值的。我不确定如何根据符号链接指向的路径来调整大小,因为我所拥有的只是符号链接的路径。它存储在path中,这是一个char数组。如果只有符号链接的路径,我怎么知道用链接的直接路径字符串的大小来bufff呢?

char bufff[100];
size_t bufsize = 100;
readlink(path,bufff,bufsize);

3 个答案:

答案 0 :(得分:2)

readlink()返回路径的长度,它不会将尾随的NUL放入缓冲区。你需要自己做:

size_t pathlength = readlink(path, bufff, sizeof(bufff)-1);
bufff[pathlength] = 0;

请注意,我从缓冲区的大小中减去1,以确保NUL有空间。

答案 1 :(得分:2)

readlink()函数返回复制到缓冲区的字节数,而不是最终的\0。这意味着如果使用100字节的缓冲区调用readlink()并且readlink()返回100,则需要更多空间(即使路径正好是100字节,您仍然需要至少1个字节才能添加最后一个空字符。)

解决方案是在循环中增加缓冲区:

size_t bufsize = 255; /* Initial buffer size */
ssize_t result;
char* buf = malloc(bufsize); /* Initial buffer allocation */
while ((result = readlink(path, buf, bufsize)) >= bufsize) {
    /* We double the buffer size, so next call should succeed ! */
    bufsize *= 2;
    buf = realloc(buf, bufsize);
}
buf[result] = '\0';

警告:这只是一个示例,如果出现错误,我们不会检查readlink是否返回-1。 mallocrealloc也是如此。你应该检查现实世界中的错误。

答案 2 :(得分:0)

基于Thibaut D。答案的完整功能:

char *do_get_symlink(char *path, struct stat attr) {

  /*
   * a much more elegant solution would be to use realpath(),
   * but it is 35% slower and produces different results on /proc
   */

  if (S_ISLNK(attr.st_mode)) {
    /*
     * st_size appears to be an unreliable source of the link length
     * PATH_MAX is artificial and not used by the GNU C Library
     */
    ssize_t length;
    size_t buffer = 128;
    char *symlink = malloc(sizeof(char) * buffer);

    if (!symlink) {
      fprintf(stderr, "%s: malloc(): %s\n", program, strerror(errno));
      return strdup("");
    }

    /*
     * if readlink() fills the buffer, double it and run again
     * even if it equals, because we need a character for the termination
     */
    while ((length = readlink(path, symlink, buffer)) > 0 && (size_t)length >= buffer) {
      buffer *= 2;
      symlink = realloc(symlink, buffer);

      if (!symlink) {
        fprintf(stderr, "%s: realloc(): %s\n", program, strerror(errno));
        return strdup("");
      }
    }

    if (length < 0) {
      fprintf(stderr, "%s: readlink(%s): %s\n", program, path, strerror(errno));
      free(symlink);
      return strdup("");
    }

    symlink[length] = '\0';
    return symlink;
  }

  /*
   * the entry is not a symlink
   * strdup is needed to keep the output free-able
   */
  return strdup("");
}