diff options
| -rw-r--r-- | include/libbb.h | 1 | ||||
| -rw-r--r-- | libbb/xreadlink.c | 45 | 
2 files changed, 46 insertions, 0 deletions
diff --git a/include/libbb.h b/include/libbb.h index f79d80d7f..0170085cb 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -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); diff --git a/libbb/xreadlink.c b/libbb/xreadlink.c index 98b795f56..2f6b1e237 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);  | 
