[prev in list] [next in list] [prev in thread] [next in thread] 

List:       busybox
Subject:    Re: [PATCH] libbb: better coreutils compatibility for realpath
From:       Denys Vlasenko <vda.linux () googlemail ! com>
Date:       2021-10-08 23:52:40
Message-ID: CAK1hOcPYocQWEn7c01=szkWzQBw6jjA-X0+YqBpCFDoH2QF3pQ () mail ! gmail ! com
[Download RAW message or body]

Applied, thanks.

On Sat, Jul 31, 2021 at 2:52 PM Ron Yorston <rmy@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 <rmy@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 <rmy@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


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic