[PATCH] reimplement dirname v2
Tito
farmatito at tiscali.it
Wed Sep 7 20:29:25 UTC 2011
Ops...and now with text :-)
Hi,
in my attempt to reinvent the wheel I've come up
with a nice implementation of dirname for busybox.
The pros are:
1) you can have it the GNU's way and modify the path passed
2) or the *BSD way and work with a malloced copy of path
that you have to free yourself.
3) it covers all test cases i was able to think of:
* path dirname
* "/usr/lib" "/usr"
* "/usr/" "/"
* "/" "/"
* "usr" "."
* "." "."
* ".." "."
* This examples are from coreutils dirname:
* "usr/lib "usr"
* "" "."
* " " "."
* "//usr//bin//" "//usr"
* "////" "/"
* "/è/è//" "/è"
* This example is added by me:
* NULL "."
4) you don't need to declare libgen.h
The contras:
1) it doesn't handle dir separators other than '/' (but
seems to me that we don't do that also in other
functions)
2) it increases binary size a little
scripts/bloat-o-meter busybox_ref busybox_unstripped
function old new delta
bb_dirname - 90 +90
xmalloc_dirname - 10 +10
syslogd_main 1862 1867 +5
dirname_main 28 26 -2
udhcp_get_option 215 211 -4
unzip_create_leading_dirs 53 46 -7
install_main 697 690 -7
unicode_conv_to_printable2 194 186 -8
sv_main 1200 1191 -9
cp_main 354 344 -10
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 1/7 up/down: 105/-47) Total: 58 bytes
I was not able to shrink the code more than that.
Hints, critics, improvements are welcome.
The bb *dirname functions are tested against the
test cases shown above. The changes to the apps
are trivial but not tested so "CAVEAT" just in case
this will be really checked in, which I don't believe ;-)
Ciao,
Tito
char* FAST_FUNC bb_dirname(char *s) {
char *p;
int firstrun = 0;
if (!s || !*s)
return xstrdup(".");
STRIP_TRAILING_SLASHES_BUT_LAST:
while ((p = last_char_is(s,'/')) != NULL && p != s)
*p = '\0';
if (!firstrun) {
p = strrchr(s, '/');
if (p) {
*++p = '\0';
firstrun++;
goto STRIP_TRAILING_SLASHES_BUT_LAST;
} else {
s[0] = '.';
s[1] = '\0';
}
}
return s;
}
char* FAST_FUNC xmalloc_dirname(const char *path) {
return bb_dirname(xstrdup(path));
}
On Wednesday 07 September 2011 21:37:02 Tito wrote:
> Alternative dirname implementation for busybox
>
> Signed-off-by Tito Ragusa <farmatito at tiscali.it>
>
> --- include/libbb.h.original 2011-08-29 01:52:50.000000000 +0200
> +++ include/libbb.h 2011-09-01 21:21:19.000000000 +0200
> @@ -133,12 +133,9 @@ int vdprintf(int d, const char *format,
> #endif
> /* klogctl is in libc's klog.h, but we cheat and not #include that */
> int klogctl(int type, char *b, int len);
> -/* This is declared here rather than #including <libgen.h> in order to avoid
> - * confusing the two versions of basename. See the dirname/basename man page
> - * for details. */
> -#if !defined __FreeBSD__
> -char *dirname(char *path);
> -#endif
> +
> +char *bb_dirname(char *path) FAST_FUNC;
> +char *xmalloc_dirname(const char *path) FAST_FUNC;
> #ifndef PATH_MAX
> # define PATH_MAX 256
> #endif
> --- libbb/Kbuild.src.original 2011-08-29 01:51:59.000000000 +0200
> +++ libbb/Kbuild.src 2011-08-29 01:33:13.000000000 +0200
> @@ -29,6 +29,7 @@ lib-y += copyfd.o
> lib-y += crc32.o
> lib-y += create_icmp6_socket.o
> lib-y += create_icmp_socket.o
> +lib-y += dirname.o
> lib-y += default_error_retval.o
> lib-y += device_open.o
> lib-y += dump.o
> --- coreutils/dirname.c.original 2011-08-18 14:07:40.000000000 +0200
> +++ coreutils/dirname.c 2011-09-05 22:34:48.000000000 +0200
> @@ -28,6 +28,6 @@
> int dirname_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
> int dirname_main(int argc UNUSED_PARAM, char **argv)
> {
> - puts(dirname(single_argv(argv)));
> + puts(bb_dirname(single_argv(argv)));
> return fflush_all();
> }
> --- coreutils/cp.c.original 2011-08-18 14:07:40.000000000 +0200
> +++ coreutils/cp.c 2011-09-01 16:34:42.000000000 +0200
> @@ -178,15 +178,13 @@ int cp_main(int argc, char **argv)
> while (1) {
> #if ENABLE_FEATURE_CP_LONG_OPTIONS
> if (flags & OPT_parents) {
> - char *dest_dup;
> char *dest_dir;
> dest = concat_path_file(last, *argv);
> - dest_dup = xstrdup(dest);
> - dest_dir = dirname(dest_dup);
> + dest_dir = xmalloc_dirname(dest);
> if (bb_make_directory(dest_dir, -1, FILEUTILS_RECUR)) {
> return EXIT_FAILURE;
> }
> - free(dest_dup);
> + free(dest_dir);
> goto DO_COPY;
> }
> #endif
> --- coreutils/install.c.original 2011-09-01 16:35:03.000000000 +0200
> +++ coreutils/install.c 2011-09-01 16:35:56.000000000 +0200
> @@ -177,8 +177,8 @@ int install_main(int argc, char **argv)
> }
> } else {
> if (opts & OPT_MKDIR_LEADING) {
> - char *ddir = xstrdup(dest);
> - bb_make_directory(dirname(ddir), 0755, FILEUTILS_RECUR);
> + char *ddir = xmalloc_dirname(dest);
> + bb_make_directory(ddir, 0755, FILEUTILS_RECUR);
> /* errors are not checked. copy_file
> * will fail if dir is not created. */
> free(ddir);
> --- coreutils/rmdir.c.original 2011-09-06 21:55:05.000000000 +0200
> +++ coreutils/rmdir.c 2011-09-01 21:04:22.000000000 +0200
> @@ -69,7 +69,7 @@ int rmdir_main(int argc UNUSED_PARAM, ch
> status = EXIT_FAILURE;
> } else if (flags & PARENTS) {
> /* Note: path was not "" since rmdir succeeded. */
> - path = dirname(path);
> + path = bb_dirname(path);
> /* Path is now just the parent component. Dirname
> * returns "." if there are no parents.
> */
> --- archival/unzip.c.original 2011-06-22 14:29:58.000000000 +0200
> +++ archival/unzip.c 2011-09-01 16:37:52.000000000 +0200
> @@ -233,8 +233,8 @@ static void unzip_skip(off_t skip)
> static void unzip_create_leading_dirs(const char *fn)
> {
> /* Create all leading directories */
> - char *name = xstrdup(fn);
> - if (bb_make_directory(dirname(name), 0777, FILEUTILS_RECUR)) {
> + char *name = xmalloc_dirname(fn);
> + if (bb_make_directory(name, 0777, FILEUTILS_RECUR)) {
> bb_error_msg_and_die("exiting"); /* bb_make_directory is noisy */
> }
> free(name);
> --- /dev/null 2011-09-07 20:21:14.435919408 +0200
> +++ libbb/dirname.c 2011-09-07 20:59:21.000000000 +0200
> @@ -0,0 +1,60 @@
> +/* vi: set sw=4 ts=4: */
> +/*
> + * Alternative dirname implementation for busybox
> + *
> + * Copyright (C) 2011 Tito Ragusa <farmatito at tiscali.it>
> + *
> + * Licensed under GPLv2 or later, see file LICENSE in this source tree.
> + */
> +
> +#include "libbb.h"
> +
> +/* The following list of examples (taken from SUSv2) shows the strings
> + * returned by dirname() for different paths:
> + *
> + * path dirname
> + * "/usr/lib" "/usr"
> + * "/usr/" "/"
> + * "/" "/"
> + * "usr" "."
> + * "." "."
> + * ".." "."
> + * This examples are from coreutils dirname:
> + * "usr/lib "usr"
> + * "" "."
> + * " " "."
> + * "//usr//bin//" "//usr"
> + * "////" "/"
> + * "/è/è//" "/è"
> + * This example is added by me:
> + * NULL "."
> + */
> +
> +char* FAST_FUNC bb_dirname(char *s) {
> + char *p;
> + int firstrun = 0;
> +
> + if (!s || !*s)
> + return xstrdup(".");
> +
> + STRIP_TRAILING_SLASHES_BUT_LAST:
> + while ((p = last_char_is(s,'/')) != NULL && p != s)
> + *p = '\0';
> +
> + if (!firstrun) {
> + p = strrchr(s, '/');
> + if (p) {
> + *++p = '\0';
> + firstrun++;
> + goto STRIP_TRAILING_SLASHES_BUT_LAST;
> + } else {
> + s[0] = '.';
> + s[1] = '\0';
> + }
> + }
> + return s;
> +}
> +
> +char* FAST_FUNC xmalloc_dirname(const char *path) {
> + return bb_dirname(xstrdup(path));
> +}
>
More information about the busybox
mailing list