• rewrite simplify_path() to keep more in line with do_realpath()
• add regression test to ensure that //foo pathnames are never simplified
This commit is contained in:
parent
7d86eaba8c
commit
a55de5f840
11
check.t
11
check.t
@ -1,4 +1,4 @@
|
||||
# $MirOS: src/bin/mksh/check.t,v 1.435 2011/03/26 16:19:29 tg Exp $
|
||||
# $MirOS: src/bin/mksh/check.t,v 1.436 2011/03/26 21:09:06 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 $
|
||||
@ -8581,6 +8581,12 @@ stdin:
|
||||
realpath t2
|
||||
realpath t3
|
||||
rm -f t1 t2 t3
|
||||
cd //usr/bin
|
||||
pwd
|
||||
cd ../lib
|
||||
pwd
|
||||
cd -P ../libexec
|
||||
pwd
|
||||
expected-stdout:
|
||||
/bin
|
||||
//bin
|
||||
@ -8591,6 +8597,9 @@ expected-stdout:
|
||||
/bin
|
||||
//bin
|
||||
/bin
|
||||
//usr/bin
|
||||
//usr/bin/../lib
|
||||
//usr/libexec
|
||||
---
|
||||
name: crash-1
|
||||
description:
|
||||
|
140
misc.c
140
misc.c
@ -29,7 +29,7 @@
|
||||
#include <grp.h>
|
||||
#endif
|
||||
|
||||
__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.161 2011/03/26 19:43:48 tg Exp $");
|
||||
__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.162 2011/03/26 21:09:09 tg Exp $");
|
||||
|
||||
/* type bits for unsigned char */
|
||||
unsigned char chtypes[UCHAR_MAX + 1];
|
||||
@ -1511,78 +1511,104 @@ make_path(const char *cwd, const char *file,
|
||||
return (rval);
|
||||
}
|
||||
|
||||
/*
|
||||
/*-
|
||||
* Simplify pathnames containing "." and ".." entries.
|
||||
* ie, simplify_path("/a/b/c/./../d/..") returns "/a/b"
|
||||
* but simplify_path("//./C/foo/bar/../baz") stays as it is
|
||||
*
|
||||
* simplify_path(this) = that
|
||||
* /a/b/c/./../d/.. /a/b
|
||||
* //./C/foo/bar/../baz //./C/foo/bar/../baz
|
||||
* /foo/ /foo
|
||||
* /foo/../../bar /bar
|
||||
* /foo/./blah/.. /foo
|
||||
* . .
|
||||
* .. ..
|
||||
* ./foo foo
|
||||
* foo/../../../bar ../../bar
|
||||
*/
|
||||
void
|
||||
simplify_path(char *pathl)
|
||||
simplify_path(char *p)
|
||||
{
|
||||
char *cur, *t;
|
||||
bool isrooted;
|
||||
char *very_start = pathl, *start;
|
||||
char *dp, *ip, *sp, *tp;
|
||||
size_t len;
|
||||
bool needslash;
|
||||
|
||||
if (!*pathl)
|
||||
switch (*p) {
|
||||
case 0:
|
||||
return;
|
||||
case '/':
|
||||
/* exactly two leading slashes? (SUSv4 3.266) */
|
||||
if (p[1] == '/' && p[2] != '/')
|
||||
/* implementation defined, we CANNOT simplify this */
|
||||
return;
|
||||
needslash = true;
|
||||
break;
|
||||
default:
|
||||
needslash = false;
|
||||
}
|
||||
dp = ip = sp = p;
|
||||
|
||||
if ((isrooted = pathl[0] == '/'))
|
||||
very_start++;
|
||||
/* exactly two leading slashes? (SUSv4 3.266) */
|
||||
if (isrooted && pathl[1] == '/' && pathl[2] != '/')
|
||||
/* implementation defined, we CANNOT simplify this */
|
||||
return;
|
||||
|
||||
/*-
|
||||
* Before After
|
||||
* /foo/ /foo
|
||||
* /foo/../../bar /bar
|
||||
* /foo/./blah/.. /foo
|
||||
* . .
|
||||
* .. ..
|
||||
* ./foo foo
|
||||
* foo/../../../bar ../../bar
|
||||
*/
|
||||
|
||||
for (cur = t = start = very_start; ; ) {
|
||||
/* treat multiple '/'s as one '/' */
|
||||
while (*t == '/')
|
||||
t++;
|
||||
|
||||
if (*t == '\0') {
|
||||
if (cur == pathl)
|
||||
/* convert empty path to dot */
|
||||
*cur++ = '.';
|
||||
*cur = '\0';
|
||||
while (*ip) {
|
||||
/* skip slashes in input */
|
||||
while (*ip == '/')
|
||||
++ip;
|
||||
if (!*ip)
|
||||
break;
|
||||
}
|
||||
|
||||
if (t[0] == '.') {
|
||||
if (!t[1] || t[1] == '/') {
|
||||
t += 1;
|
||||
/* get next pathname component from input */
|
||||
tp = ip;
|
||||
while (*ip && *ip != '/')
|
||||
++ip;
|
||||
len = ip - tp;
|
||||
|
||||
/* check input for "." and ".." */
|
||||
if (tp[0] == '.') {
|
||||
if (len == 1)
|
||||
/* just continue with the next one */
|
||||
continue;
|
||||
} else if (t[1] == '.' && (!t[2] || t[2] == '/')) {
|
||||
if (!isrooted && cur == start) {
|
||||
if (cur != very_start)
|
||||
*cur++ = '/';
|
||||
*cur++ = '.';
|
||||
*cur++ = '.';
|
||||
start = cur;
|
||||
} else if (cur != start)
|
||||
while (--cur > start && *cur != '/')
|
||||
;
|
||||
t += 2;
|
||||
else if (len == 2 && tp[1] == '.') {
|
||||
/* parent level, but how? */
|
||||
if (*p == '/')
|
||||
/* absolute path, only one way */
|
||||
goto strip_last_component;
|
||||
else if (dp > sp) {
|
||||
/* relative path, with subpaths */
|
||||
needslash = false;
|
||||
strip_last_component:
|
||||
/* strip off last pathname component */
|
||||
while (dp > sp)
|
||||
if (*--dp == '/')
|
||||
break;
|
||||
} else {
|
||||
/* relative path, at its beginning */
|
||||
if (needslash)
|
||||
/* or already dotdot-slash'd */
|
||||
*dp++ = '/';
|
||||
/* keep dotdot-slash if not absolute */
|
||||
*dp++ = '.';
|
||||
*dp++ = '.';
|
||||
needslash = true;
|
||||
sp = dp;
|
||||
}
|
||||
/* then continue with the next one */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (cur != very_start)
|
||||
*cur++ = '/';
|
||||
if (needslash)
|
||||
*dp++ = '/';
|
||||
|
||||
/* find/copy next component of pathname */
|
||||
while (*t && *t != '/')
|
||||
*cur++ = *t++;
|
||||
/* append next pathname component to output */
|
||||
memmove(dp, tp, len);
|
||||
dp += len;
|
||||
|
||||
/* append slash if we continue */
|
||||
needslash = true;
|
||||
/* try next component */
|
||||
}
|
||||
if (dp == p)
|
||||
/* empty path -> dot */
|
||||
*dp++ = needslash ? '/' : '.';
|
||||
*dp = '\0';
|
||||
}
|
||||
|
||||
void
|
||||
|
Loading…
Reference in New Issue
Block a user