libbb: better coreutils compatibility for realpath
Add some tests which coreutils realpath pass but BusyBox realpath fails (bar one). Adjust xmalloc_realpath_coreutils() so the tests pass: - Expand symbolic links before testing whether the last path component exists. - When the link target is a relative path canonicalize it by passing it through xmalloc_realpath_coreutils() as already happens for absolute paths. - Ignore trailing slashes when finding the last path component and correctly handle the case where the only slash is at the start of the path. This requires ignoring superfluous leading slashes. - Undo all changes to the path so error messages from the caller show the original filename. function old new delta xmalloc_realpath_coreutils 214 313 +99 Signed-off-by: Ron Yorston <rmy@pobox.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
		
				
					committed by
					
						
						Denys Vlasenko
					
				
			
			
				
	
			
			
			
						parent
						
							86ba007b84
						
					
				
				
					commit
					94eb1c4dc6
				
			@@ -123,7 +123,7 @@ char* FAST_FUNC xmalloc_realpath(const char *path)
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char* FAST_FUNC xmalloc_realpath_coreutils(const char *path)
 | 
			
		||||
char* FAST_FUNC xmalloc_realpath_coreutils(char *path)
 | 
			
		||||
{
 | 
			
		||||
	char *buf;
 | 
			
		||||
 | 
			
		||||
@@ -137,32 +137,19 @@ char* FAST_FUNC xmalloc_realpath_coreutils(const char *path)
 | 
			
		||||
	 * (the directory must exist).
 | 
			
		||||
	 */
 | 
			
		||||
	if (!buf && errno == ENOENT) {
 | 
			
		||||
		char *last_slash = strrchr(path, '/');
 | 
			
		||||
		if (last_slash) {
 | 
			
		||||
			*last_slash++ = '\0';
 | 
			
		||||
			buf = xmalloc_realpath(path);
 | 
			
		||||
			if (buf) {
 | 
			
		||||
				unsigned len = strlen(buf);
 | 
			
		||||
				buf = xrealloc(buf, len + strlen(last_slash) + 2);
 | 
			
		||||
				buf[len++] = '/';
 | 
			
		||||
				strcpy(buf + len, last_slash);
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			char *target = xmalloc_readlink(path);
 | 
			
		||||
			if (target) {
 | 
			
		||||
				char *cwd;
 | 
			
		||||
				if (target[0] == '/') {
 | 
			
		||||
					/*
 | 
			
		||||
					 * $ ln -s /bin/qwe symlink  # note: /bin is a link to /usr/bin
 | 
			
		||||
					 * $ readlink -f symlink
 | 
			
		||||
					 * /usr/bin/qwe/target_does_not_exist
 | 
			
		||||
					 * $ realpath symlink
 | 
			
		||||
					 * /usr/bin/qwe/target_does_not_exist
 | 
			
		||||
					 */
 | 
			
		||||
					buf = xmalloc_realpath_coreutils(target);
 | 
			
		||||
					free(target);
 | 
			
		||||
					return buf;
 | 
			
		||||
				}
 | 
			
		||||
		char *target, c, *last_slash;
 | 
			
		||||
		size_t i;
 | 
			
		||||
 | 
			
		||||
		target = xmalloc_readlink(path);
 | 
			
		||||
		if (target) {
 | 
			
		||||
			/*
 | 
			
		||||
			 * $ ln -s /bin/qwe symlink  # note: /bin is a link to /usr/bin
 | 
			
		||||
			 * $ readlink -f symlink
 | 
			
		||||
			 * /usr/bin/qwe
 | 
			
		||||
			 * $ realpath symlink
 | 
			
		||||
			 * /usr/bin/qwe
 | 
			
		||||
			 */
 | 
			
		||||
			if (target[0] != '/') {
 | 
			
		||||
				/*
 | 
			
		||||
				 * $ ln -s target_does_not_exist symlink
 | 
			
		||||
				 * $ readlink -f symlink
 | 
			
		||||
@@ -170,13 +157,41 @@ char* FAST_FUNC xmalloc_realpath_coreutils(const char *path)
 | 
			
		||||
				 * $ realpath symlink
 | 
			
		||||
				 * /CURDIR/target_does_not_exist
 | 
			
		||||
				 */
 | 
			
		||||
				cwd = xrealloc_getcwd_or_warn(NULL);
 | 
			
		||||
				buf = concat_path_file(cwd, target);
 | 
			
		||||
				char *cwd = xrealloc_getcwd_or_warn(NULL);
 | 
			
		||||
				char *tmp = concat_path_file(cwd, target);
 | 
			
		||||
				free(cwd);
 | 
			
		||||
				free(target);
 | 
			
		||||
				return buf;
 | 
			
		||||
				target = tmp;
 | 
			
		||||
			}
 | 
			
		||||
			buf = xmalloc_realpath_coreutils(target);
 | 
			
		||||
			free(target);
 | 
			
		||||
			return buf;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* ignore leading and trailing slashes */
 | 
			
		||||
		while (path[0] == '/' && path[1] == '/')
 | 
			
		||||
			++path;
 | 
			
		||||
		i = strlen(path) - 1;
 | 
			
		||||
		while (i > 0 && path[i] == '/')
 | 
			
		||||
			i--;
 | 
			
		||||
		c = path[i + 1];
 | 
			
		||||
		path[i + 1] = '\0';
 | 
			
		||||
 | 
			
		||||
		last_slash = strrchr(path, '/');
 | 
			
		||||
		if (last_slash == path)
 | 
			
		||||
			buf = xstrdup(path);
 | 
			
		||||
		else if (last_slash) {
 | 
			
		||||
			*last_slash = '\0';
 | 
			
		||||
			buf = xmalloc_realpath(path);
 | 
			
		||||
			*last_slash++ = '/';
 | 
			
		||||
			if (buf) {
 | 
			
		||||
				unsigned len = strlen(buf);
 | 
			
		||||
				buf = xrealloc(buf, len + strlen(last_slash) + 2);
 | 
			
		||||
				buf[len++] = '/';
 | 
			
		||||
				strcpy(buf + len, last_slash);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		path[i + 1] = c;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return buf;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user