[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