fix realpath builtin’s handling of (source) pathnames with a trailing slash
as per POSIX (if a trailing slash is part of the symlink target it fails as well, like GNU readlink -f does)
This commit is contained in:
		
							
								
								
									
										75
									
								
								check.t
									
									
									
									
									
								
							
							
						
						
									
										75
									
								
								check.t
									
									
									
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| # $MirOS: src/bin/mksh/check.t,v 1.386 2010/07/25 11:35:38 tg Exp $ | ||||
| # $MirOS: src/bin/mksh/check.t,v 1.387 2010/08/24 14:42:00 tg Exp $ | ||||
| # $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $ | ||||
| # $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $ | ||||
| # $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $ | ||||
| @@ -25,7 +25,7 @@ | ||||
| # http://www.research.att.com/~gsf/public/ifs.sh | ||||
|  | ||||
| expected-stdout: | ||||
| 	@(#)MIRBSD KSH R39 2010/07/25 | ||||
| 	@(#)MIRBSD KSH R39 2010/08/24 | ||||
| description: | ||||
| 	Check version of shell. | ||||
| stdin: | ||||
| @@ -7372,3 +7372,74 @@ stdin: | ||||
| expected-stdout: | ||||
| 	1 . | ||||
| --- | ||||
| name: realpath-1 | ||||
| description: | ||||
| 	Check proper return values for realpath | ||||
| stdin: | ||||
| 	wd=$(realpath .) | ||||
| 	mkdir dir | ||||
| 	:>file | ||||
| 	:>dir/file | ||||
| 	ln -s dir lndir | ||||
| 	ln -s file lnfile | ||||
| 	ln -s nix lnnix | ||||
| 	ln -s . lnself | ||||
| 	i=0 | ||||
| 	chk() { | ||||
| 		typeset x y | ||||
| 		x=$(realpath "$wd/$1" 2>&1); y=$? | ||||
| 		print $((++i)) "?$1" =${x##*$wd/} !$y | ||||
| 	} | ||||
| 	chk dir | ||||
| 	chk dir/ | ||||
| 	chk dir/file | ||||
| 	chk dir/nix | ||||
| 	chk file | ||||
| 	chk file/ | ||||
| 	chk file/file | ||||
| 	chk file/nix | ||||
| 	chk nix | ||||
| 	chk nix/ | ||||
| 	chk nix/file | ||||
| 	chk nix/nix | ||||
| 	chk lndir | ||||
| 	chk lndir/ | ||||
| 	chk lndir/file | ||||
| 	chk lndir/nix | ||||
| 	chk lnfile | ||||
| 	chk lnfile/ | ||||
| 	chk lnfile/file | ||||
| 	chk lnfile/nix | ||||
| 	chk lnnix | ||||
| 	chk lnnix/ | ||||
| 	chk lnnix/file | ||||
| 	chk lnnix/nix | ||||
| 	chk lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself | ||||
| 	rm lnself | ||||
| expected-stdout: | ||||
| 	1 ?dir =dir !0 | ||||
| 	2 ?dir/ =dir !0 | ||||
| 	3 ?dir/file =dir/file !0 | ||||
| 	4 ?dir/nix =dir/nix !0 | ||||
| 	5 ?file =file !0 | ||||
| 	6 ?file/ =file/: Not a directory !20 | ||||
| 	7 ?file/file =file/file: Not a directory !20 | ||||
| 	8 ?file/nix =file/nix: Not a directory !20 | ||||
| 	9 ?nix =nix !0 | ||||
| 	10 ?nix/ =nix !0 | ||||
| 	11 ?nix/file =nix/file: No such file or directory !2 | ||||
| 	12 ?nix/nix =nix/nix: No such file or directory !2 | ||||
| 	13 ?lndir =dir !0 | ||||
| 	14 ?lndir/ =dir !0 | ||||
| 	15 ?lndir/file =dir/file !0 | ||||
| 	16 ?lndir/nix =dir/nix !0 | ||||
| 	17 ?lnfile =file !0 | ||||
| 	18 ?lnfile/ =lnfile/: Not a directory !20 | ||||
| 	19 ?lnfile/file =lnfile/file: Not a directory !20 | ||||
| 	20 ?lnfile/nix =lnfile/nix: Not a directory !20 | ||||
| 	21 ?lnnix =nix !0 | ||||
| 	22 ?lnnix/ =nix !0 | ||||
| 	23 ?lnnix/file =lnnix/file: No such file or directory !2 | ||||
| 	24 ?lnnix/nix =lnnix/nix: No such file or directory !2 | ||||
| 	25 ?lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself =lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself/lnself: Too many levels of symbolic links !62 | ||||
| --- | ||||
|   | ||||
							
								
								
									
										20
									
								
								funcs.c
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								funcs.c
									
									
									
									
									
								
							| @@ -25,7 +25,7 @@ | ||||
|  | ||||
| #include "sh.h" | ||||
|  | ||||
| __RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.156 2010/07/17 22:09:34 tg Exp $"); | ||||
| __RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.157 2010/08/24 14:42:01 tg Exp $"); | ||||
|  | ||||
| #if HAVE_KILLPG | ||||
| /* | ||||
| @@ -290,7 +290,7 @@ do_realpath(const char *upath) | ||||
| 			 */ | ||||
| 			xp = (ldest[0] == '/') ? Xstring(xs, xp) : | ||||
| 			    Xrestpos(xs, xp, pos); | ||||
| 			tp = shf_smprintf("%s/%s", ldest, ip); | ||||
| 			tp = shf_smprintf("%s%s%s", ldest, *ip ? "/" : "", ip); | ||||
| 			afree(ipath, ATEMP); | ||||
| 			ip = ipath = tp; | ||||
| 		} | ||||
| @@ -309,6 +309,22 @@ do_realpath(const char *upath) | ||||
| 		Xput(xs, xp, '/'); | ||||
| 	Xput(xs, xp, '\0'); | ||||
|  | ||||
| 	/* | ||||
| 	 * if source path had a trailing slash, check if target path | ||||
| 	 * is not a non-directory existing file | ||||
| 	 */ | ||||
| 	if (ip > ipath && ip[-1] == '/') { | ||||
| 		if (stat(Xstring(xs, xp), &sb)) { | ||||
| 			if (errno != ENOENT) | ||||
| 				goto notfound; | ||||
| 		} else if (!S_ISDIR(sb.st_mode)) { | ||||
| 			errno = ENOTDIR; | ||||
| 			goto notfound; | ||||
| 		} | ||||
| 		/* target now either does not exist or is a directory */ | ||||
| 	} | ||||
|  | ||||
| 	/* return target path */ | ||||
| 	if (ldest != NULL) | ||||
| 		afree(ldest, ATEMP); | ||||
| 	afree(ipath, ATEMP); | ||||
|   | ||||
							
								
								
									
										12
									
								
								mksh.1
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								mksh.1
									
									
									
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| .\" $MirOS: src/bin/mksh/mksh.1,v 1.234 2010/08/14 20:13:10 tg Exp $ | ||||
| .\" $MirOS: src/bin/mksh/mksh.1,v 1.235 2010/08/24 14:42:03 tg Exp $ | ||||
| .\" $OpenBSD: ksh.1,v 1.136 2010/07/15 20:04:35 schwarze Exp $ | ||||
| .\"- | ||||
| .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 | ||||
| @@ -71,7 +71,7 @@ | ||||
| .\" with -mandoc, it might implement .Mx itself, but we want to | ||||
| .\" use our own definition. And .Dd must come *first*, always. | ||||
| .\" | ||||
| .Dd $Mdocdate: August 14 2010 $ | ||||
| .Dd $Mdocdate: August 24 2010 $ | ||||
| .\" | ||||
| .\" Check which macro package we use | ||||
| .\" | ||||
| @@ -3629,6 +3629,14 @@ printed. | ||||
| .Xc | ||||
| Prints the resolved absolute pathname corresponding to | ||||
| .Ar name . | ||||
| If | ||||
| .Ar name | ||||
| ends with a slash | ||||
| .Pq Sq / , | ||||
| it's also checked for existence and whether it is a directory; otherwise, | ||||
| .Ic realpath | ||||
| returns 0 if the pathname either exists or can be created immediately, | ||||
| i.e. all but the last component exist and are directories. | ||||
| .Pp | ||||
| .It Ic rename Ar from to | ||||
| Renames the file | ||||
|   | ||||
							
								
								
									
										4
									
								
								sh.h
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								sh.h
									
									
									
									
									
								
							| @@ -150,9 +150,9 @@ | ||||
| #endif | ||||
|  | ||||
| #ifdef EXTERN | ||||
| __RCSID("$MirOS: src/bin/mksh/sh.h,v 1.403 2010/08/14 21:35:13 tg Exp $"); | ||||
| __RCSID("$MirOS: src/bin/mksh/sh.h,v 1.404 2010/08/24 14:42:04 tg Exp $"); | ||||
| #endif | ||||
| #define MKSH_VERSION "R39 2010/07/25" | ||||
| #define MKSH_VERSION "R39 2010/08/24" | ||||
|  | ||||
| #ifndef MKSH_INCLUDES_ONLY | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user