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

Reply via email to