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:
tg 2010-08-24 14:42:04 +00:00
parent 8b946de857
commit 7fdc42cead
4 changed files with 103 additions and 8 deletions

75
check.t
View File

@ -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: 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: 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 $ # $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 # http://www.research.att.com/~gsf/public/ifs.sh
expected-stdout: expected-stdout:
@(#)MIRBSD KSH R39 2010/07/25 @(#)MIRBSD KSH R39 2010/08/24
description: description:
Check version of shell. Check version of shell.
stdin: stdin:
@ -7372,3 +7372,74 @@ stdin:
expected-stdout: expected-stdout:
1 . 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
View File

@ -25,7 +25,7 @@
#include "sh.h" #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 #if HAVE_KILLPG
/* /*
@ -290,7 +290,7 @@ do_realpath(const char *upath)
*/ */
xp = (ldest[0] == '/') ? Xstring(xs, xp) : xp = (ldest[0] == '/') ? Xstring(xs, xp) :
Xrestpos(xs, xp, pos); Xrestpos(xs, xp, pos);
tp = shf_smprintf("%s/%s", ldest, ip); tp = shf_smprintf("%s%s%s", ldest, *ip ? "/" : "", ip);
afree(ipath, ATEMP); afree(ipath, ATEMP);
ip = ipath = tp; ip = ipath = tp;
} }
@ -309,6 +309,22 @@ do_realpath(const char *upath)
Xput(xs, xp, '/'); Xput(xs, xp, '/');
Xput(xs, xp, '\0'); 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) if (ldest != NULL)
afree(ldest, ATEMP); afree(ldest, ATEMP);
afree(ipath, ATEMP); afree(ipath, ATEMP);

12
mksh.1
View File

@ -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 $ .\" $OpenBSD: ksh.1,v 1.136 2010/07/15 20:04:35 schwarze Exp $
.\"- .\"-
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 .\" 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 .\" with -mandoc, it might implement .Mx itself, but we want to
.\" use our own definition. And .Dd must come *first*, always. .\" 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 .\" Check which macro package we use
.\" .\"
@ -3629,6 +3629,14 @@ printed.
.Xc .Xc
Prints the resolved absolute pathname corresponding to Prints the resolved absolute pathname corresponding to
.Ar name . .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 .Pp
.It Ic rename Ar from to .It Ic rename Ar from to
Renames the file Renames the file

4
sh.h
View File

@ -150,9 +150,9 @@
#endif #endif
#ifdef EXTERN #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 #endif
#define MKSH_VERSION "R39 2010/07/25" #define MKSH_VERSION "R39 2010/08/24"
#ifndef MKSH_INCLUDES_ONLY #ifndef MKSH_INCLUDES_ONLY