Applied, thanks.
On Sat, Jul 31, 2021 at 2:52 PM Ron Yorston <r...@pobox.com> wrote: > > 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 <r...@pobox.com> > --- > include/libbb.h | 2 +- > libbb/xreadlink.c | 75 ++++++++++++++++++++++++---------------- > testsuite/realpath.tests | 45 ++++++++++++++++++++++++ > 3 files changed, 91 insertions(+), 31 deletions(-) > create mode 100755 testsuite/realpath.tests > > diff --git a/include/libbb.h b/include/libbb.h > index 7d6ab4a93..3c9ed792e 100644 > --- a/include/libbb.h > +++ b/include/libbb.h > @@ -561,7 +561,7 @@ DIR *xopendir(const char *path) FAST_FUNC; > DIR *warn_opendir(const char *path) FAST_FUNC; > > char *xmalloc_realpath(const char *path) FAST_FUNC RETURNS_MALLOC; > -char *xmalloc_realpath_coreutils(const char *path) FAST_FUNC RETURNS_MALLOC; > +char *xmalloc_realpath_coreutils(char *path) FAST_FUNC RETURNS_MALLOC; > char *xmalloc_readlink(const char *path) FAST_FUNC RETURNS_MALLOC; > char *xmalloc_readlink_or_warn(const char *path) FAST_FUNC RETURNS_MALLOC; > /* !RETURNS_MALLOC: it's a realloc-like function */ > diff --git a/libbb/xreadlink.c b/libbb/xreadlink.c > index a18dd0748..2682f6975 100644 > --- a/libbb/xreadlink.c > +++ b/libbb/xreadlink.c > @@ -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; > diff --git a/testsuite/realpath.tests b/testsuite/realpath.tests > new file mode 100755 > index 000000000..0e68e0279 > --- /dev/null > +++ b/testsuite/realpath.tests > @@ -0,0 +1,45 @@ > +#!/bin/sh > + > +# Realpath tests. > +# Copyright 2006 by Natanael Copa <n...@tanael.org> > +# Copyright 2021 by Ron Yorston <r...@pobox.com> > +# Licensed under GPLv2, see file LICENSE in this source tree. > + > +. ./testing.sh > + > +unset LC_ALL > +unset LC_MESSAGES > +unset LANG > +unset LANGUAGE > + > +TESTDIR=realpath_testdir > +TESTLINK1="link1" > +TESTLINK2="link2" > + > +# create the dir and test files > +mkdir -p "./$TESTDIR" > +ln -s "./$TESTDIR/not_file" "./$TESTLINK1" > +ln -s "./$TESTDIR/not_file/not_dir" "./$TESTLINK2" > + > +# shell's $PWD may leave symlinks unresolved. > +# "pwd" may be a built-in and have the same problem. > +# External pwd _can't_ have that problem (current dir on Unix is physical). > +pwd=`which pwd` > +pwd=`$pwd` > +testing "realpath on non-existent absolute path 1" "realpath /not_file" > "/not_file\n" "" "" > +testing "realpath on non-existent absolute path 2" "realpath /not_file/" > "/not_file\n" "" "" > +testing "realpath on non-existent absolute path 3" "realpath //not_file" > "/not_file\n" "" "" > +testing "realpath on non-existent absolute path 4" "realpath > /not_dir/not_file 2>&1" "realpath: /not_dir/not_file: No such file or > directory\n" "" "" > + > +testing "realpath on non-existent local file 1" "realpath $TESTDIR/not_file" > "$pwd/$TESTDIR/not_file\n" "" "" > +testing "realpath on non-existent local file 2" "realpath > $TESTDIR/not_dir/not_file 2>&1" "realpath: $TESTDIR/not_dir/not_file: No such > file or directory\n" "" "" > + > +testing "realpath on link to non-existent file 1" "realpath $TESTLINK1" > "$pwd/$TESTDIR/not_file\n" "" "" > +testing "realpath on link to non-existent file 2" "realpath $TESTLINK2 2>&1" > "realpath: $TESTLINK2: No such file or directory\n" "" "" > +testing "realpath on link to non-existent file 3" "realpath ./$TESTLINK1" > "$pwd/$TESTDIR/not_file\n" "" "" > +testing "realpath on link to non-existent file 4" "realpath ./$TESTLINK2 > 2>&1" "realpath: ./$TESTLINK2: No such file or directory\n" "" "" > + > +# clean up > +rm -r "$TESTLINK1" "$TESTLINK2" "$TESTDIR" > + > +exit $((FAILCOUNT <= 255 ? FAILCOUNT : 255)) > -- > 2.31.1 > > _______________________________________________ > busybox mailing list > busybox@busybox.net > http://lists.busybox.net/mailman/listinfo/busybox _______________________________________________ busybox mailing list busybox@busybox.net http://lists.busybox.net/mailman/listinfo/busybox