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: 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
View File

@ -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
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 $
.\"-
.\" 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
View File

@ -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