From fa96aa8d70eb1dfd7b3550fab417a43b3a507a6d Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sat, 5 Jan 2019 14:16:50 +0000 Subject: busybox: add --uninstall option Add an option to allow hard links to be removed. busybox --uninstall file removes all hard links to the given file (including the file itself.) Since Microsoft Windows refuses to delete a running executable a BusyBox binary is unable to remove links to itself. busybox --uninstall -n file displays the names of all hard links to the given file. Although this feature is couched in terms of uninstalling BusyBox it's actually quite general: it can be used to delete or display hard links to any file. --- include/mingw.h | 1 + libbb/appletlib.c | 34 ++++++++++++++++++++++++++++++++-- win32/mingw.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 2 deletions(-) diff --git a/include/mingw.h b/include/mingw.h index cef53a7c9..b712e4ec0 100644 --- a/include/mingw.h +++ b/include/mingw.h @@ -482,3 +482,4 @@ ULONGLONG CompatGetTickCount64(void); #define GetTickCount64 CompatGetTickCount64 ssize_t get_random_bytes(void *buf, ssize_t count); +int enumerate_links(const char *file, char *name); diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 11136de11..8a66b3303 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -776,7 +776,8 @@ static void install_links(const char *busybox, while (*appname) { fpc = xasprintf("%s/%s.exe", custom_install_dir, appname); rc = link(busybox, fpc); - if (rc != 0 && errno != EEXIST) { + if (rc != 0 && (errno != EEXIST || + strcmp("busybox.exe", bb_basename(fpc)) != 0)) { bb_simple_perror_msg(fpc); } free(fpc); @@ -885,7 +886,13 @@ int busybox_main(int argc UNUSED_PARAM, char **argv) " or: busybox --show SCRIPT\n" # endif IF_FEATURE_INSTALLER( - " or: busybox --install "IF_NOT_PLATFORM_MINGW32("[-s] ")"[DIR]\n" + IF_NOT_PLATFORM_MINGW32( + " or: busybox --install [-s] [DIR]\n" + ) + IF_PLATFORM_MINGW32( + " or: busybox --install [DIR]\n" + " or: busybox --uninstall [-n] file\n" + ) ) " or: function [arguments]...\n" "\n" @@ -1016,6 +1023,29 @@ int busybox_main(int argc UNUSED_PARAM, char **argv) return 0; } +#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_INSTALLER + if (strcmp(argv[1], "--uninstall") == 0) { + char name[PATH_MAX]; + int dry_run = (argv[2] && strcmp(argv[2], "-n") == 0 && ++argv); + const char *file = argv[2]; + + if (!argv[2]) + bb_error_msg_and_die(bb_msg_requires_arg, "--uninstall"); + + while (enumerate_links(file, name)) { + if (dry_run) { + full_write1_str(name); + full_write1_str("\n"); + } + else if (unlink(name) != 0) { + bb_simple_perror_msg(name); + } + file = NULL; + } + return 0; + } +#endif + if (strcmp(argv[1], "--help") == 0) { /* "busybox --help []" */ if (!argv[2]) diff --git a/win32/mingw.c b/win32/mingw.c index c420992d5..8d1da5199 100644 --- a/win32/mingw.c +++ b/win32/mingw.c @@ -1289,3 +1289,42 @@ ULONGLONG CompatGetTickCount64(void) return GetTickCount64(); } #endif + +#if ENABLE_FEATURE_INSTALLER +/* + * Enumerate the names of all hard links to a file. The first call + * provides the file name as the first argument; subsequent calls must + * set the first argument to NULL. Returns 0 on error or when there are + * no more links. + */ +int enumerate_links(const char *file, char *name) +{ + static HANDLE h = INVALID_HANDLE_VALUE; + char aname[PATH_MAX]; + wchar_t wname[PATH_MAX]; + DWORD length = PATH_MAX; + DECLARE_PROC_ADDR(HANDLE, FindFirstFileNameW, LPCWSTR, DWORD, LPDWORD, + PWSTR); + DECLARE_PROC_ADDR(BOOL, FindNextFileNameW, HANDLE, LPDWORD, PWSTR); + + if (!INIT_PROC_ADDR(kernel32.dll, FindFirstFileNameW) || + !INIT_PROC_ADDR(kernel32.dll, FindNextFileNameW)) + return 0; + + if (file != NULL) { + wchar_t wfile[PATH_MAX]; + MultiByteToWideChar(CP_ACP, 0, file, -1, wfile, PATH_MAX); + h = FindFirstFileNameW(wfile, 0, &length, wname); + if (h == INVALID_HANDLE_VALUE) + return 0; + } + else if (!FindNextFileNameW(h, &length, wname)) { + FindClose(h); + h = INVALID_HANDLE_VALUE; + return 0; + } + WideCharToMultiByte(CP_ACP, 0, wname, -1, aname, PATH_MAX, NULL, NULL); + realpath(aname, name); + return 1; +} +#endif -- cgit v1.2.3-55-g6feb