new xmalloc_readlink_follow() routine to fully expand trailing symlinks to get to a "real" file (or directory).
No binary (build failed)
—
(log yok)
| @@ -260,6 +260,7 @@ DIR *warn_opendir(const char *path); | |
| /* UNUSED: char *xmalloc_realpath(const char *path); */ | |
| char *xmalloc_readlink(const char *path); | |
| + | char *xmalloc_readlink_follow(const char *path); |
| char *xmalloc_readlink_or_warn(const char *path); | |
| char *xrealloc_getcwd_or_warn(char *cwd); | |
| @@ -32,6 +32,51 @@ char *xmalloc_readlink(const char *path) | |
| return buf; | |
| } | |
| + | /* |
| + | * this routine is not the same as realpath(), which canonicalizes |
| + | * the given path completely. this routine only follows trailing |
| + | * symlinks until a real file is reached, and returns its name. |
| + | * intermediate symlinks are not expanded. as above, a malloced |
| + | * char* is returned, which must be freed. |
| + | */ |
| + | char *xmalloc_readlink_follow(const char *path) |
| + | { |
| + | char *buf = NULL, *lpc, *linkpath; |
| + | int bufsize; |
| + | smallint looping = 0; |
| + | |
| + | buf = strdup(path); |
| + | bufsize = strlen(path) + 1; |
| + | |
| + | while(1) { |
| + | linkpath = xmalloc_readlink(buf); |
| + | if (!linkpath) { |
| + | if (errno == EINVAL) /* not a symlink */ |
| + | return buf; |
| + | free(buf); |
| + | return NULL; |
| + | } |
| + | |
| + | if (*linkpath == '/') { |
| + | free(buf); |
| + | buf = linkpath; |
| + | bufsize = strlen(linkpath) + 1; |
| + | } else { |
| + | bufsize += strlen(linkpath); |
| + | if (looping++ > MAXSYMLINKS) { |
| + | free(linkpath); |
| + | free(buf); |
| + | return NULL; |
| + | } |
| + | buf = xrealloc(buf, bufsize); |
| + | lpc = bb_get_last_path_component_strip(buf); |
| + | strcpy(lpc, linkpath); |
| + | free(linkpath); |
| + | } |
| + | } |
| + | |
| + | } |
| + | |
| char *xmalloc_readlink_or_warn(const char *path) | |
| { | |
| char *buf = xmalloc_readlink(path); | |