diff --git a/ChangeLog b/ChangeLog index fad59f3ef..1d57e0a01 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 0.10 to current + Resolve symbolic links for mime-type matchers. Thanks to Vigi. + + Try to preserve symbolic links in current path when starting vifm by + checking value of $PWD. Thanks to Vigi. + Fixed `:tabnew ..` not working due to use of uninitialized data. Fixed access to uninitialized memory on clearing view after graphical @@ -8,6 +13,9 @@ Fixed possible crashes after certain patterns of using view mode and closing tabs. + Fixed some resources (like output pipe for --choose-files and + --choose-dir) being inherited by child processes. Thanks to Vigi. + 0.10-beta to 0.10 (2018-11-11) Display list of files in removal confirmation dialog. Thanks to ovk. diff --git a/THANKS b/THANKS index 00e21b2ae..815a9b780 100644 --- a/THANKS +++ b/THANKS @@ -172,6 +172,7 @@ Tomek K. (TomiCode) tYGjQCsvVI Tyler Spivey Valery Ushakov (nbuwe) +Vigi Vlad Glagolev (Stealth) Von Welch vzel diff --git a/src/background.c b/src/background.c index 1c1b8a8ac..a5296e8a5 100644 --- a/src/background.c +++ b/src/background.c @@ -637,6 +637,7 @@ bg_run_and_capture(char cmd[], int user_sh, FILE **out, FILE **err) } sh = user_sh ? get_execv_path(cfg.shell) : "/bin/sh"; + prepare_for_exec(); execvp(sh, make_execv_array(sh, cmd)); _Exit(127); } @@ -826,6 +827,7 @@ bg_run_external(const char cmd[], int skip_errors) setpgid(0, 0); + prepare_for_exec(); execve(get_execv_path(cfg.shell), make_execv_array(cfg.shell, command), environ); _Exit(127); diff --git a/src/int/file_magic.c b/src/int/file_magic.c index b7a76f965..3893790c7 100644 --- a/src/int/file_magic.c +++ b/src/int/file_magic.c @@ -54,28 +54,31 @@ static void parse_app_dir(const char directory[], const char mime_type[], assoc_records_t get_magic_handlers(const char file[]) { - char real_path[PATH_MAX + 1]; - char *const symlink_base = strdup(file); + return get_handlers(get_mimetype(file, 1)); +} - if(!is_root_dir(symlink_base)) - { - remove_last_path_component(symlink_base); - } +const char * +get_mimetype(const char file[], int resolve_symlinks) +{ + static char mimetype[128]; - if(get_link_target_abs(file, symlink_base, real_path, sizeof(real_path)) != 0) + char target[PATH_MAX + 1]; + if(resolve_symlinks) { - copy_str(real_path, sizeof(real_path), file); - } + char *const symlink_base = strdup(file); - free(symlink_base); + if(!is_root_dir(symlink_base)) + { + remove_last_path_component(symlink_base); + } - return get_handlers(get_mimetype(real_path)); -} + if(get_link_target_abs(file, symlink_base, target, sizeof(target)) == 0) + { + file = target; + } -const char * -get_mimetype(const char file[]) -{ - static char mimetype[128]; + free(symlink_base); + } if(get_gtk_mimetype(file, mimetype, sizeof(mimetype)) == -1) { diff --git a/src/int/file_magic.h b/src/int/file_magic.h index 8bdeaea8a..49202d9b6 100644 --- a/src/int/file_magic.h +++ b/src/int/file_magic.h @@ -21,9 +21,10 @@ #include "../filetype.h" -/* Retrieves mime type of the file specified by its path. Returns pointer to a - * statically allocated buffer. */ -const char * get_mimetype(const char file[]); +/* Retrieves mime type of the file specified by its path. The resolve_symlinks + * argument controls whether mime-type of the link should be that of its target. + * Returns pointer to a statically allocated buffer. */ +const char * get_mimetype(const char file[], int resolve_symlinks); /* Retrieves system-wide desktop file associations. Caller shouldn't free * anything. */ diff --git a/src/int/fuse.c b/src/int/fuse.c index 584d6287f..223684177 100644 --- a/src/int/fuse.c +++ b/src/int/fuse.c @@ -629,6 +629,7 @@ run_fuse_command(char cmd[], const cancellation_t *cancellation, int *cancelled) (void)set_sigchld(0); + prepare_for_exec(); (void)execve(get_execv_path(cfg.shell), make_execv_array(cfg.shell, cmd), environ); _Exit(127); diff --git a/src/modes/file_info.c b/src/modes/file_info.c index be9897831..e2fa77e17 100644 --- a/src/modes/file_info.c +++ b/src/modes/file_info.c @@ -361,7 +361,7 @@ show_mime_type(view_t *view, int curr_y) const char *mimetype = NULL; get_current_full_path(view, sizeof(full_path), full_path); - mimetype = get_mimetype(full_path); + mimetype = get_mimetype(full_path, 0); mvwaddstr(menu_win, curr_y, 2, "Mime Type: "); diff --git a/src/utils/matcher.c b/src/utils/matcher.c index 8e05100ac..319dc6f7b 100644 --- a/src/utils/matcher.c +++ b/src/utils/matcher.c @@ -351,7 +351,7 @@ matcher_matches(const matcher_t *matcher, const char path[]) if(matcher->type == MT_MIME) { - path = get_mimetype(path); + path = get_mimetype(path, 1); if(path == NULL) { return matcher->negated; diff --git a/src/utils/utils_nix.c b/src/utils/utils_nix.c index 12a42a629..0c8eaffb8 100644 --- a/src/utils/utils_nix.c +++ b/src/utils/utils_nix.c @@ -45,7 +45,7 @@ #include /* SIG* SIG_* sigset_t kill() sigaddset() sigemptyset() sigfillset() signal() sigprocmask() */ #include /* NULL size_t */ -#include /* FILE stderr fdopen() fprintf() snprintf() */ +#include /* FILE stderr fclose() fdopen() fprintf() snprintf() */ #include /* atoi() free() */ #include /* strchr() strdup() strerror() strlen() strncmp() */ @@ -54,6 +54,7 @@ #include "../compat/mntent.h" /* mntent setmntent() getmntent() endmntent() */ #include "../compat/os.h" #include "../compat/reallocarray.h" +#include "../ui/tabs.h" #include "../ui/ui.h" #include "../running.h" #include "../status.h" @@ -136,6 +137,7 @@ run_in_shell_no_cls(char command[]) signal(SIGINT, SIG_DFL); (void)set_sigchld(0); + prepare_for_exec(); execve(get_execv_path(cfg.shell), make_execv_array(cfg.shell, command), environ); _Exit(127); @@ -274,10 +276,32 @@ run_from_fork(int pipe[2], int err_only, int preserve_stdin, char cmd[]) (void)close(null_fd); } + prepare_for_exec(); execvp(get_execv_path(cfg.shell), make_execv_array(cfg.shell, cmd)); _Exit(127); } +void +prepare_for_exec(void) +{ + if(curr_stats.original_stdout != NULL) + { + (void)fclose(curr_stats.original_stdout); + } + + /* More generic cleanup functions aren't called here to do not waste time on + * freeing resources which will be replaced by exec(). */ + tab_info_t tab_info; + int i; + for(i = 0; tabs_get(curr_view, i, &tab_info); ++i) + { + view_t *view = tab_info.view; + fswatch_free(view->watch); + fswatch_free(view->left_column.watch); + fswatch_free(view->right_column.watch); + } +} + char * get_execv_path(char shell[]) { diff --git a/src/utils/utils_nix.h b/src/utils/utils_nix.h index 1b3a39e24..849038c17 100644 --- a/src/utils/utils_nix.h +++ b/src/utils/utils_nix.h @@ -45,6 +45,11 @@ int get_proc_exit_status(pid_t pid); void _gnuc_noreturn run_from_fork(int pipe[2], int err_only, int preserve_stdin, char cmd[]); +/* Frees some resources before exec(), which shouldn't be inherited and remain + * allocated in child process or it might make those resources appear busy + * (e.g., pipe not being closed, directory being still in use). */ +void prepare_for_exec(void); + /* Extracts name of the shell to be used with execv*() function. Returns * pointer to statically allocated buffer. */ char * get_execv_path(char shell[]); diff --git a/src/vifm.c b/src/vifm.c index dce4796ae..b2981e315 100644 --- a/src/vifm.c +++ b/src/vifm.c @@ -62,6 +62,7 @@ #include "ui/statusbar.h" #include "ui/tabs.h" #include "ui/ui.h" +#include "utils/env.h" #include "utils/fs.h" #include "utils/log.h" #include "utils/macros.h" @@ -96,6 +97,7 @@ #include "undo.h" static int vifm_main(int argc, char *argv[]); +static int get_start_cwd(char buf[], size_t buf_len); static int undo_perform_func(OPS op, void *data, const char src[], const char dst[]); static void parse_received_arguments(char *args[]); @@ -155,18 +157,16 @@ vifm_main(int argc, char *argv[]) static const int quit = 0; - char dir[PATH_MAX + 1]; char **files = NULL; int nfiles = 0; int lwin_cv, rwin_cv; - if(get_cwd(dir, sizeof(dir)) == NULL) + char dir[PATH_MAX + 1]; + if(get_start_cwd(dir, sizeof(dir)) != 0) { - perror("getcwd"); return -1; } - (void)vifm_chdir(dir); args_parse(&vifm_args, argc, argv, dir); args_process(&vifm_args, 1); @@ -347,6 +347,28 @@ vifm_main(int argc, char *argv[]) return 0; } +/* Loads original working directory of the process attempting to avoid resolving + * symbolic links in the path. Returns zero on success, otherwise non-zero is + * returned. */ +static int +get_start_cwd(char buf[], size_t buf_len) +{ + if(get_cwd(buf, buf_len) == NULL) + { + perror("getcwd"); + return -1; + } + + /* If $PWD points to the same location as CWD, use its value to preserve + * symbolic links in the path. */ + const char *pwd = env_get("PWD"); + if(pwd != NULL && paths_are_same(pwd, buf)) + { + copy_str(buf, buf_len, pwd); + } + return 0; +} + /* perform_operation() interface adaptor for the undo unit. */ static int undo_perform_func(OPS op, void *data, const char src[], const char dst[]) diff --git a/tests/filetype/filetype.c b/tests/filetype/filetype.c index 7178304ac..6e2e50e31 100644 --- a/tests/filetype/filetype.c +++ b/tests/filetype/filetype.c @@ -157,7 +157,7 @@ TEST(pattern_list, IF(has_mime_type_detection)) char cmd[1024]; snprintf(cmd, sizeof(cmd), "<%s>{binary-data}", - get_mimetype(TEST_DATA_PATH "/read/binary-data")); + get_mimetype(TEST_DATA_PATH "/read/binary-data", 0)); set_programs(cmd, "prog", 0, 0); assert_string_equal("prog", diff --git a/tests/filetype/test.c b/tests/filetype/test.c index ed76b699b..693386a6d 100644 --- a/tests/filetype/test.c +++ b/tests/filetype/test.c @@ -31,7 +31,7 @@ set_viewers(const char pattern[], const char viewers[]) int has_mime_type_detection(void) { - return get_mimetype(TEST_DATA_PATH "/read/dos-line-endings") != NULL; + return get_mimetype(TEST_DATA_PATH "/read/dos-line-endings", 0) != NULL; } /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */ diff --git a/tests/filetype/viewers.c b/tests/filetype/viewers.c index 2d3993804..42892e095 100644 --- a/tests/filetype/viewers.c +++ b/tests/filetype/viewers.c @@ -98,7 +98,7 @@ TEST(pattern_list, IF(has_mime_type_detection)) char cmd[1024]; snprintf(cmd, sizeof(cmd), "<%s>{binary-data}", - get_mimetype(TEST_DATA_PATH "/read/binary-data")); + get_mimetype(TEST_DATA_PATH "/read/binary-data", 0)); set_viewers(cmd, "prog1"); ft_init(&prog1_available); diff --git a/tests/misc/commands_filetype.c b/tests/misc/commands_filetype.c index e11faa119..6c83d7f19 100644 --- a/tests/misc/commands_filetype.c +++ b/tests/misc/commands_filetype.c @@ -77,11 +77,11 @@ TEST(pattern_anding_and_orring, IF(has_mime_type_detection)) snprintf(cmd, sizeof(cmd), "filetype {two-lines},<%s>{binary-data} app", - get_mimetype(TEST_DATA_PATH "/read/binary-data")); + get_mimetype(TEST_DATA_PATH "/read/binary-data", 0)); assert_success(exec_commands(cmd, &lwin, CIT_COMMAND)); snprintf(cmd, sizeof(cmd), "fileviewer {two-lines},<%s>{binary-data} viewer", - get_mimetype(TEST_DATA_PATH "/read/binary-data")); + get_mimetype(TEST_DATA_PATH "/read/binary-data", 0)); assert_success(exec_commands(cmd, &lwin, CIT_COMMAND)); ft = ft_get_all_programs(TEST_DATA_PATH "/read/two-lines"); @@ -137,7 +137,7 @@ prog_exists(const char name[]) static int has_mime_type_detection(void) { - return get_mimetype(TEST_DATA_PATH "/read/dos-line-endings") != NULL; + return get_mimetype(TEST_DATA_PATH "/read/dos-line-endings", 0) != NULL; } /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */ diff --git a/tests/misc/file_magic.c b/tests/misc/file_magic.c index 52053bb4d..64b255588 100644 --- a/tests/misc/file_magic.c +++ b/tests/misc/file_magic.c @@ -49,7 +49,7 @@ TEST(relatively_large_file_name_does_not_crash, SANDBOX_PATH "/B", path, sizeof(path))); assert_success(chdir(SANDBOX_PATH "/B")); - assert_non_null(get_mimetype(get_last_path_component(path))); + assert_non_null(get_mimetype(get_last_path_component(path), 0)); restore_cwd(saved_cwd); @@ -66,7 +66,7 @@ check_empty_file(const char fname[]) if(f != NULL) { fclose(f); - assert_non_null(get_mimetype(fname)); + assert_non_null(get_mimetype(fname, 0)); assert_success(unlink(fname)); } } @@ -80,7 +80,7 @@ has_mime_type_detection_and_symlinks(void) static int has_mime_type_detection(void) { - return get_mimetype(TEST_DATA_PATH "/read/dos-line-endings") != NULL; + return get_mimetype(TEST_DATA_PATH "/read/dos-line-endings", 0) != NULL; } /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */ diff --git a/tests/stic/stic.h b/tests/stic/stic.h index 6f6a1f846..b6e55fabe 100644 --- a/tests/stic/stic.h +++ b/tests/stic/stic.h @@ -12,7 +12,7 @@ /* Global data. */ -#define STIC_VERSION "0.5.2" +#define STIC_VERSION "0.6" #define STIC_PROJECT_HOME "https://github.com/xaizek/stic" #define STIC_PRINT_BUFFER_SIZE 100000 diff --git a/tests/utils/matcher.c b/tests/utils/matcher.c index e92261ddd..feb7a665b 100644 --- a/tests/utils/matcher.c +++ b/tests/utils/matcher.c @@ -1,13 +1,19 @@ #include +#include /* symlink() */ + +#include /* remove() */ #include /* free() */ #include "../../src/int/file_magic.h" #include "../../src/utils/matcher.h" +#include "utils.h" + static void check_glob(matcher_t *m); static void check_regexp(matcher_t *m); static int has_mime_type_detection(void); +static int has_mime_type_detection_and_not_windows(void); TEST(empty_matcher_can_be_created) { @@ -371,6 +377,25 @@ TEST(mime_type_inclusion, IF(has_mime_type_detection)) matcher_free(m); } +TEST(mime_type_of_link_is_that_of_its_target, + IF(has_mime_type_detection_and_not_windows)) +{ + char *error; + matcher_t *m; + + /* symlink() is not available on Windows, but the rest of the code is fine. */ +#ifndef _WIN32 + assert_success(symlink(".", "link")); +#endif + + assert_non_null(m = matcher_alloc("", 0, 1, "", &error)); + assert_null(error); + assert_true(matcher_matches(m, "link")); + matcher_free(m); + + assert_success(remove("link")); +} + static void check_glob(matcher_t *m) { @@ -396,7 +421,13 @@ check_regexp(matcher_t *m) static int has_mime_type_detection(void) { - return get_mimetype(TEST_DATA_PATH "/read/dos-line-endings") != NULL; + return get_mimetype(TEST_DATA_PATH "/read/dos-line-endings", 0) != NULL; +} + +static int +has_mime_type_detection_and_not_windows(void) +{ + return has_mime_type_detection() && not_windows(); } /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */