2014-09-12 147 views
0

我想存储符号链接指向的文件的路径为bufff。这适用于我当前使用readlink的实施方式,但它捕获了我不需要的额外数据,因为我的bufsize是任意估价的。我不知道如何根据符号链接指向的路径来确定它的大小,因为我拥有的只是通往符号链接的路径。这存储在path这是一个字符数组。如果我拥有的是符号链接的路径,我如何知道链接的直接路径字符串的大小为bufff检索符号链接的路径

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

回答

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

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

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

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

+0

我经常'path'缓冲区'readlink'用'memset'之前,而不是明确的。所以即使在'readlink'失败时,'path'也有一个明显的NUL终止的字符串。失败时,你的'pathlength'是-1,'buff [pathlength]'赋值是*未定义行为*(如果不幸的话,[太阳系可能会崩溃](http://stackoverflow.com/a/25636788/841108) – 2014-09-12 21:48:18

0

基于蒂博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(""); 
}