diff options
author | Paul Fox | 2007-11-08 01:11:41 +0000 |
---|---|---|
committer | Paul Fox | 2007-11-08 01:11:41 +0000 |
commit | 459a2ba1efa9b84bf12c2f5b8a23fd89912b47ea (patch) | |
tree | 5c69b3f763a62d9dd394c1a36bfcfc0f96c07060 /libbb | |
parent | 49cce2b8384d2b425a91785ebf155a692df6986c (diff) | |
download | busybox-459a2ba1efa9b84bf12c2f5b8a23fd89912b47ea.zip busybox-459a2ba1efa9b84bf12c2f5b8a23fd89912b47ea.tar.gz |
new xmalloc_readlink_follow() routine to fully expand trailing symlinks
to get to a "real" file (or directory).
Diffstat (limited to 'libbb')
-rw-r--r-- | libbb/xreadlink.c | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/libbb/xreadlink.c b/libbb/xreadlink.c index 98b795f..2f6b1e2 100644 --- a/libbb/xreadlink.c +++ b/libbb/xreadlink.c @@ -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); |