int vim_format_help_cmd(const char topic[], char cmd[], size_t cmd_size) { int bg; #ifndef _WIN32 char *const escaped_rtp = shell_like_escape(PACKAGE_DATA_DIR, 0); char *const escaped_args = shell_like_escape(topic, 0); snprintf(cmd, cmd_size, "%s -c 'set runtimepath+=%s/vim-doc' -c help\\ %s -c only", cfg_get_vicmd(&bg), escaped_rtp, escaped_args); free(escaped_args); free(escaped_rtp); #else char exe_dir[PATH_MAX]; char *escaped_rtp; (void)get_exe_dir(exe_dir, sizeof(exe_dir)); escaped_rtp = shell_like_escape(exe_dir, 0); snprintf(cmd, cmd_size, "%s -c \"set runtimepath+=%s/data/vim-doc\" -c \"help %s\" -c only", cfg_get_vicmd(&bg), escaped_rtp, topic); free(escaped_rtp); #endif return bg; }
/* Composes command to be run using terminal multiplexer. Returns newly * allocated string that should be freed by the caller. */ static char * gen_term_multiplexer_cmd(const char cmd[], int pause) { char *title_arg; char *raw_shell_cmd; char *escaped_shell_cmd; char *shell_cmd = NULL; if(curr_stats.term_multiplexer != TM_TMUX && curr_stats.term_multiplexer != TM_SCREEN) { assert(0 && "Unexpected active terminal multiplexer value."); return NULL; } title_arg = gen_term_multiplexer_title_arg(cmd); raw_shell_cmd = format_str("%s%s", cmd, pause ? PAUSE_STR : ""); escaped_shell_cmd = shell_like_escape(raw_shell_cmd, 0); if(curr_stats.term_multiplexer == TM_TMUX) { char *const arg = format_str("%s -c %s", cfg.shell, escaped_shell_cmd); char *const escaped_arg = shell_like_escape(arg, 0); shell_cmd = format_str("tmux new-window %s %s", title_arg, escaped_arg); free(escaped_arg); free(arg); } else if(curr_stats.term_multiplexer == TM_SCREEN) { set_pwd_in_screen(flist_get_dir(curr_view)); shell_cmd = format_str("screen %s %s -c %s", title_arg, cfg.shell, escaped_shell_cmd); } else { assert(0 && "Unsupported terminal multiplexer type."); } free(escaped_shell_cmd); free(raw_shell_cmd); free(title_arg); return shell_cmd; }
/* Configures environment variables before shellout. Should be used in pair * with cleanup_shellout_env(). */ static void setup_shellout_env(void) { const char *mount_file; const char *term_multiplexer_fmt; char *escaped_path; char *cmd; /* Need to use internal value instead of getcwd() for a symlink directory. */ env_set("PWD", curr_view->curr_dir); mount_file = fuse_get_mount_file(curr_view->curr_dir); if(mount_file == NULL) { env_remove(FUSE_FILE_ENVVAR); return; } env_set(FUSE_FILE_ENVVAR, mount_file); switch(curr_stats.term_multiplexer) { case TM_TMUX: term_multiplexer_fmt = "tmux set-environment %s %s"; break; case TM_SCREEN: term_multiplexer_fmt = "screen -X setenv %s %s"; break; default: return; } escaped_path = shell_like_escape(mount_file, 0); cmd = format_str(term_multiplexer_fmt, FUSE_FILE_ENVVAR, escaped_path); (void)vifm_system(cmd); free(cmd); free(escaped_path); }
/* Handles current content of the menu to Vim as quickfix list. */ static void cmd_v(key_info_t key_info, keys_info_t *keys_info) { int bg; const char *vi_cmd; FILE *vim_stdin; char *cmd; int i; int qf = 1; /* If both first and last lines do not contain colons, treat lines as list of * file names. */ if(strchr(menu->items[0], ':') == NULL && strchr(menu->items[menu->len - 1], ':') == NULL) { qf = 0; } ui_shutdown(); curr_stats.need_update = UT_FULL; vi_cmd = cfg_get_vicmd(&bg); if(!qf) { char *const arg = shell_like_escape("+exe 'bd!|args' " "join(map(getline('1','$'),'fnameescape(v:val)'))", 0); cmd = format_str("%s %s +argument%d -", vi_cmd, arg, menu->pos + 1); free(arg); } else if(menu->pos == 0) { /* For some reason +cc1 causes noisy messages on status line, so handle this * case separately. */ cmd = format_str("%s +cgetbuffer +bd! +cfirst -", vi_cmd); } else { cmd = format_str("%s +cgetbuffer +bd! +cfirst +cc%d -", vi_cmd, menu->pos + 1); } vim_stdin = popen(cmd, "w"); free(cmd); if(vim_stdin == NULL) { recover_after_shellout(); show_error_msg("Vim QuickFix", "Failed to send list of files to editor."); return; } for(i = 0; i < menu->len; ++i) { fputs(menu->items[i], vim_stdin); putc('\n', vim_stdin); } pclose(vim_stdin); recover_after_shellout(); }
int vim_view_file(const char filename[], int line, int column, int allow_forking) { char vicmd[PATH_MAX]; char cmd[PATH_MAX + 5]; const char *fork_str = allow_forking ? "" : "--nofork"; char *escaped; int bg; int result; cmd[0] = '\0'; if(!path_exists(filename, DEREF)) { if(path_exists(filename, NODEREF)) { show_error_msg("Broken Link", "Link destination doesn't exist"); } else { show_error_msg("Wrong Path", "File doesn't exist"); } return 1; } #ifndef _WIN32 escaped = shell_like_escape(filename, 0); #else escaped = (char *)enclose_in_dquotes(filename); #endif copy_str(vicmd, sizeof(vicmd), cfg_get_vicmd(&bg)); trim_right(vicmd); if(!allow_forking) { char *p = strrchr(vicmd, ' '); if(p != NULL && strstr(p, "remote")) { *p = '\0'; } } if(line < 0 && column < 0) snprintf(cmd, sizeof(cmd), "%s %s %s", vicmd, fork_str, escaped); else if(column < 0) snprintf(cmd, sizeof(cmd), "%s %s +%d %s", vicmd, fork_str, line, escaped); else snprintf(cmd, sizeof(cmd), "%s %s \"+call cursor(%d, %d)\" %s", vicmd, fork_str, line, column, escaped); #ifndef _WIN32 free(escaped); #endif result = run_vim(cmd, bg && allow_forking, allow_forking); curs_set(FALSE); return result; }
/* Changes $PWD in running GNU/screen session to the specified path. Needed for * symlink directories and sshfs mounts. */ static void set_pwd_in_screen(const char path[]) { char *const escaped_dir = shell_like_escape(path, 0); char *const set_pwd = format_str("screen -X setenv PWD %s", escaped_dir); (void)vifm_system(set_pwd); free(set_pwd); free(escaped_dir); }
/* Runs the cmd in a split window of terminal multiplexer. Runs shell, if cmd * is NULL. */ static void run_in_split(const FileView *view, const char cmd[]) { char *const escaped_cmd = (cmd == NULL) ? strdup(cfg.shell) : shell_like_escape(cmd, 0); setup_shellout_env(); if(curr_stats.term_multiplexer == TM_TMUX) { char cmd[1024]; snprintf(cmd, sizeof(cmd), "tmux split-window %s", escaped_cmd); (void)vifm_system(cmd); } else if(curr_stats.term_multiplexer == TM_SCREEN) { char cmd[1024]; /* "eval" executes each argument as a separate argument, but escaping rules * are not exactly like in shell, so last command is run separately. */ char *const escaped_dir = shell_like_escape(flist_get_dir(view), 0); snprintf(cmd, sizeof(cmd), "screen -X eval chdir\\ %s 'focus bottom' " "split 'focus bottom'", escaped_dir); free(escaped_dir); (void)vifm_system(cmd); snprintf(cmd, sizeof(cmd), "screen -X screen vifm-screen-split %s", escaped_cmd); (void)vifm_system(cmd); } else { assert(0 && "Unexpected active terminal multiplexer value."); } cleanup_shellout_env(); free(escaped_cmd); }
/* Executes file, specified by the full_path. Changes type of slashes on * Windows. */ static void execute_file(const char full_path[], int elevate) { #ifndef _WIN32 char *const escaped = shell_like_escape(full_path, 0); shellout(escaped, PAUSE_ALWAYS, 1); free(escaped); #else char *const dquoted_full_path = strdup(enclose_in_dquotes(full_path)); to_back_slash(dquoted_full_path); run_win_executable(dquoted_full_path, elevate); free(dquoted_full_path); #endif }
void vim_edit_files(int nfiles, char *files[]) { char cmd[PATH_MAX]; size_t len; int i; int bg; len = snprintf(cmd, sizeof(cmd), "%s ", cfg_get_vicmd(&bg)); for(i = 0; i < nfiles && len < sizeof(cmd) - 1; ++i) { char *escaped = shell_like_escape(files[i], 0); len += snprintf(cmd + len, sizeof(cmd) - len, "%s ", escaped); free(escaped); } run_vim(cmd, bg, 1); }
/* Composes title for window of a terminal multiplexer from a command. Returns * newly allocated string that should be freed by the caller. */ static char * gen_term_multiplexer_title_arg(const char cmd[]) { int bg; const char *const vicmd = cfg_get_vicmd(&bg); const char *const visubcmd = strstr(cmd, vicmd); char *command_name = NULL; const char *title; char *title_arg; if(visubcmd != NULL) { title = skip_whitespace(visubcmd + strlen(vicmd) + 1); } else { char *const separator = strchr(cmd, ' '); if(separator != NULL) { *separator = '\0'; command_name = strdup(cmd); *separator = ' '; } title = command_name; } if(is_null_or_empty(title)) { title_arg = strdup(""); } else { const char opt_c = (curr_stats.term_multiplexer == TM_SCREEN) ? 't' : 'n'; char *const escaped_title = shell_like_escape(title, 0); title_arg = format_str("-%c %s", opt_c, escaped_title); free(escaped_title); } free(command_name); return title_arg; }
char * commands_escape_for_insertion(const char cmd_line[], int pos, const char str[]) { const CmdLineLocation ipt = get_cmdline_location(cmd_line, cmd_line + pos); switch(ipt) { case CLL_R_QUOTING: /* XXX: Use of filename escape, while special one might be needed. */ case CLL_OUT_OF_ARG: case CLL_NO_QUOTING: return shell_like_escape(str, 0); case CLL_S_QUOTING: return escape_for_squotes(str, 0); case CLL_D_QUOTING: return escape_for_dquotes(str, 0); default: return NULL; } }
/* Appends the path to the expanded string with either proper escaping or * quoting. Returns NULL on not enough memory error. */ static char * append_path_to_expanded(char expanded[], int quotes, const char path[]) { if(quotes) { const char *const dquoted = enclose_in_dquotes(path); expanded = append_to_expanded(expanded, dquoted); } else { char *const escaped = shell_like_escape(path, 0); if(escaped == NULL) { show_error_msg("Memory Error", "Unable to allocate enough memory"); free(expanded); return NULL; } expanded = append_to_expanded(expanded, escaped); free(escaped); } return expanded; }
static int op_removesl(ops_t *ops, void *data, const char *src, const char *dst) { const char *const delete_prg = (ops == NULL) ? cfg.delete_prg : ops->delete_prg; if(delete_prg[0] != '\0') { #ifndef _WIN32 char *escaped; char cmd[2*PATH_MAX + 1]; const int cancellable = (data == NULL); escaped = shell_like_escape(src, 0); if(escaped == NULL) { return -1; } snprintf(cmd, sizeof(cmd), "%s %s", delete_prg, escaped); free(escaped); LOG_INFO_MSG("Running trash command: \"%s\"", cmd); return run_operation_command(ops, cmd, cancellable); #else char cmd[PATH_MAX*2 + 1]; snprintf(cmd, sizeof(cmd), "%s \"%s\"", delete_prg, src); to_back_slash(cmd); return os_system(cmd); #endif } if(!ops_uses_syscalls(ops)) { #ifndef _WIN32 char *escaped; char cmd[16 + PATH_MAX]; int result; const int cancellable = data == NULL; escaped = shell_like_escape(src, 0); if(escaped == NULL) return -1; snprintf(cmd, sizeof(cmd), "rm -rf %s", escaped); LOG_INFO_MSG("Running rm command: \"%s\"", cmd); result = run_operation_command(ops, cmd, cancellable); free(escaped); return result; #else if(is_dir(src)) { char path[PATH_MAX]; int err; copy_str(path, sizeof(path), src); to_back_slash(path); wchar_t *utf16_path = utf8_to_utf16(path); /* SHFileOperationW requires pFrom to be double-nul terminated. */ const size_t len = wcslen(utf16_path); utf16_path = reallocarray(utf16_path, len + 1U + 1U, sizeof(*utf16_path)); utf16_path[len + 1U] = L'\0'; SHFILEOPSTRUCTW fo = { .hwnd = NULL, .wFunc = FO_DELETE, .pFrom = utf16_path, .pTo = NULL, .fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI, }; err = SHFileOperationW(&fo); log_msg("Error: %d", err); free(utf16_path); return err; } else { int ok; wchar_t *const utf16_path = utf8_to_utf16(src); DWORD attributes = GetFileAttributesW(utf16_path); if(attributes & FILE_ATTRIBUTE_READONLY) { SetFileAttributesW(utf16_path, attributes & ~FILE_ATTRIBUTE_READONLY); } ok = DeleteFileW(utf16_path); if(!ok) { LOG_WERROR(GetLastError()); } free(utf16_path); return !ok; } #endif }
static int op_removesl(ops_t *ops, void *data, const char *src, const char *dst) { if(cfg.delete_prg[0] != '\0') { #ifndef _WIN32 char *escaped; char cmd[2*PATH_MAX + 1]; const int cancellable = (data == NULL); escaped = shell_like_escape(src, 0); if(escaped == NULL) { return -1; } snprintf(cmd, sizeof(cmd), "%s %s", cfg.delete_prg, escaped); free(escaped); LOG_INFO_MSG("Running trash command: \"%s\"", cmd); return background_and_wait_for_errors(cmd, cancellable); #else char cmd[PATH_MAX*2 + 1]; snprintf(cmd, sizeof(cmd), "%s \"%s\"", cfg.delete_prg, src); to_back_slash(cmd); return os_system(cmd); #endif } if(!cfg.use_system_calls) { #ifndef _WIN32 char *escaped; char cmd[16 + PATH_MAX]; int result; const int cancellable = data == NULL; escaped = shell_like_escape(src, 0); if(escaped == NULL) return -1; snprintf(cmd, sizeof(cmd), "rm -rf %s", escaped); LOG_INFO_MSG("Running rm command: \"%s\"", cmd); result = background_and_wait_for_errors(cmd, cancellable); free(escaped); return result; #else if(is_dir(src)) { char path[PATH_MAX]; int err; copy_str(path, sizeof(path), src); to_back_slash(path); wchar_t *const utf16_path = utf8_to_utf16(path); SHFILEOPSTRUCTW fo = { .hwnd = NULL, .wFunc = FO_DELETE, .pFrom = utf16_path, .pTo = NULL, .fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI, }; err = SHFileOperationW(&fo); log_msg("Error: %d", err); free(utf16_path); return err; } else { int ok; wchar_t *const utf16_path = utf8_to_utf16(src); DWORD attributes = GetFileAttributesW(utf16_path); if(attributes & FILE_ATTRIBUTE_READONLY) { SetFileAttributesW(utf16_path, attributes & ~FILE_ATTRIBUTE_READONLY); } ok = DeleteFileW(utf16_path); if(!ok) { LOG_WERROR(GetLastError()); } free(utf16_path); return !ok; } #endif }
int iop_cp(io_args_t *const args) { const char *const src = args->arg1.src; const char *const dst = args->arg2.dst; const IoCrs crs = args->arg3.crs; const io_confirm confirm = args->confirm; const int cancellable = args->cancellable; struct stat st; char block[BLOCK_SIZE]; FILE *in, *out; size_t nread; int error; struct stat src_st; const char *open_mode = "wb"; ioeta_update(args->estim, src, dst, 0, 0); #ifdef _WIN32 if(is_symlink(src) || crs != IO_CRS_APPEND_TO_FILES) { DWORD flags; int error; wchar_t *utf16_src, *utf16_dst; flags = COPY_FILE_COPY_SYMLINK; if(crs == IO_CRS_FAIL) { flags |= COPY_FILE_FAIL_IF_EXISTS; } else if(path_exists(dst, DEREF)) { /* Ask user whether to overwrite destination file. */ if(confirm != NULL && !confirm(args, src, dst)) { return 0; } } utf16_src = utf8_to_utf16(src); utf16_dst = utf8_to_utf16(dst); error = CopyFileExW(utf16_src, utf16_dst, &win_progress_cb, args, NULL, flags) == 0; if(error) { /* FIXME: use real system error message here. */ (void)ioe_errlst_append(&args->result.errors, dst, IO_ERR_UNKNOWN, "Copy file failed"); } free(utf16_src); free(utf16_dst); ioeta_update(args->estim, NULL, NULL, 1, 0); return error; } #endif /* Create symbolic link rather than copying file it points to. This check * should go before directory check as is_dir() resolves symbolic links. */ if(is_symlink(src)) { char link_target[PATH_MAX]; int error; io_args_t ln_args = { .arg1.path = link_target, .arg2.target = dst, .arg3.crs = crs, .cancellable = cancellable, .result = args->result, }; if(get_link_target(src, link_target, sizeof(link_target)) != 0) { (void)ioe_errlst_append(&args->result.errors, src, IO_ERR_UNKNOWN, "Failed to get symbolic link target"); return 1; } error = iop_ln(&ln_args); args->result = ln_args.result; if(error != 0) { (void)ioe_errlst_append(&args->result.errors, src, IO_ERR_UNKNOWN, "Failed to make symbolic link"); return 1; } return 0; } if(is_dir(src)) { (void)ioe_errlst_append(&args->result.errors, src, EISDIR, strerror(EISDIR)); return 1; } if(os_stat(src, &st) != 0) { (void)ioe_errlst_append(&args->result.errors, src, errno, strerror(errno)); return 1; } #ifndef _WIN32 /* Fifo/socket/device files don't need to be opened, their content is not * accessed. */ if(S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode) || S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)) { in = NULL; } else #endif { in = os_fopen(src, "rb"); if(in == NULL) { (void)ioe_errlst_append(&args->result.errors, src, errno, strerror(errno)); return 1; } } if(crs == IO_CRS_APPEND_TO_FILES) { open_mode = "ab"; } else if(crs != IO_CRS_FAIL) { int ec; if(path_exists(dst, DEREF)) { /* Ask user whether to overwrite destination file. */ if(confirm != NULL && !confirm(args, src, dst)) { if(in != NULL && fclose(in) != 0) { (void)ioe_errlst_append(&args->result.errors, src, errno, strerror(errno)); } return 0; } } ec = unlink(dst); if(ec != 0 && errno != ENOENT) { (void)ioe_errlst_append(&args->result.errors, dst, errno, strerror(errno)); if(in != NULL && fclose(in) != 0) { (void)ioe_errlst_append(&args->result.errors, src, errno, strerror(errno)); } return ec; } /* XXX: possible improvement would be to generate temporary file name in the * destination directory, write to it and then overwrite destination file, * but this approach has disadvantage of requiring more free space on * destination file system. */ } else if(path_exists(dst, DEREF)) { (void)ioe_errlst_append(&args->result.errors, src, EEXIST, strerror(EEXIST)); if(in != NULL && fclose(in) != 0) { (void)ioe_errlst_append(&args->result.errors, src, errno, strerror(errno)); } return 1; } #ifndef _WIN32 /* Replicate fifo without even opening it. */ if(S_ISFIFO(st.st_mode)) { if(mkfifo(dst, st.st_mode & 07777) != 0) { (void)ioe_errlst_append(&args->result.errors, src, errno, strerror(errno)); return 1; } return 0; } /* Replicate socket or device file without even opening it. */ if(S_ISSOCK(st.st_mode) || S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)) { if(mknod(dst, st.st_mode & (S_IFMT | 07777), st.st_rdev) != 0) { (void)ioe_errlst_append(&args->result.errors, src, errno, strerror(errno)); return 1; } return 0; } #endif out = os_fopen(dst, open_mode); if(out == NULL) { (void)ioe_errlst_append(&args->result.errors, dst, errno, strerror(errno)); if(fclose(in) != 0) { (void)ioe_errlst_append(&args->result.errors, src, errno, strerror(errno)); } return 1; } error = 0; if(crs == IO_CRS_APPEND_TO_FILES) { fpos_t pos; /* The following line is required for stupid Windows sometimes. Why? * Probably because it's stupid... Won't harm other systems. */ fseek(out, 0, SEEK_END); error = fgetpos(out, &pos) != 0 || fsetpos(in, &pos) != 0; if(!error) { ioeta_update(args->estim, NULL, NULL, 0, get_file_size(dst)); } } /* TODO: use sendfile() if platform supports it. */ while((nread = fread(&block, 1, sizeof(block), in)) != 0U) { if(cancellable && ui_cancellation_requested()) { error = 1; break; } if(fwrite(&block, 1, nread, out) != nread) { (void)ioe_errlst_append(&args->result.errors, dst, errno, strerror(errno)); error = 1; break; } ioeta_update(args->estim, NULL, NULL, 0, nread); } if(nread == 0U && !feof(in) && ferror(in)) { (void)ioe_errlst_append(&args->result.errors, src, errno, strerror(errno)); } if(fclose(in) != 0) { (void)ioe_errlst_append(&args->result.errors, src, errno, strerror(errno)); } if(fclose(out) != 0) { (void)ioe_errlst_append(&args->result.errors, dst, errno, strerror(errno)); } if(error == 0 && os_lstat(src, &src_st) == 0) { error = os_chmod(dst, src_st.st_mode & 07777); if(error != 0) { (void)ioe_errlst_append(&args->result.errors, dst, errno, strerror(errno)); } } ioeta_update(args->estim, NULL, NULL, 1, 0); return error; } #ifdef _WIN32 static DWORD CALLBACK win_progress_cb(LARGE_INTEGER total, LARGE_INTEGER transferred, LARGE_INTEGER stream_size, LARGE_INTEGER stream_transfered, DWORD stream_num, DWORD reason, HANDLE src_file, HANDLE dst_file, LPVOID param) { static LONGLONG last_size; io_args_t *const args = param; const char *const src = args->arg1.src; const char *const dst = args->arg2.dst; ioeta_estim_t *const estim = args->estim; if(transferred.QuadPart < last_size) { last_size = 0; } ioeta_update(estim, src, dst, 0, transferred.QuadPart - last_size); last_size = transferred.QuadPart; if(args->cancellable && ui_cancellation_requested()) { return PROGRESS_CANCEL; } return PROGRESS_CONTINUE; } #endif /* TODO: implement iop_chown(). */ int iop_chown(io_args_t *const args); /* TODO: implement iop_chgrp(). */ int iop_chgrp(io_args_t *const args); /* TODO: implement iop_chmod(). */ int iop_chmod(io_args_t *const args); int iop_ln(io_args_t *const args) { const char *const path = args->arg1.path; const char *const target = args->arg2.target; const int overwrite = args->arg3.crs != IO_CRS_FAIL; int result; #ifdef _WIN32 char cmd[6 + PATH_MAX*2 + 1]; char *escaped_path, *escaped_target; char base_dir[PATH_MAX + 2]; #endif #ifndef _WIN32 result = symlink(path, target); if(result != 0 && errno == EEXIST && overwrite && is_symlink(target)) { result = remove(target); if(result == 0) { result = symlink(path, target); if(result != 0) { (void)ioe_errlst_append(&args->result.errors, path, errno, strerror(errno)); } } else { (void)ioe_errlst_append(&args->result.errors, target, errno, strerror(errno)); } } else if(result != 0 && errno != 0) { (void)ioe_errlst_append(&args->result.errors, target, errno, strerror(errno)); } #else if(!overwrite && path_exists(target, DEREF)) { (void)ioe_errlst_append(&args->result.errors, target, EEXIST, strerror(EEXIST)); return -1; } if(overwrite && !is_symlink(target)) { (void)ioe_errlst_append(&args->result.errors, target, IO_ERR_UNKNOWN, "Target is not a symbolic link"); return -1; } escaped_path = shell_like_escape(path, 0); escaped_target = shell_like_escape(target, 0); if(escaped_path == NULL || escaped_target == NULL) { (void)ioe_errlst_append(&args->result.errors, target, IO_ERR_UNKNOWN, "Not enough memory"); free(escaped_target); free(escaped_path); return -1; } if(GetModuleFileNameA(NULL, base_dir, ARRAY_LEN(base_dir)) == 0) { (void)ioe_errlst_append(&args->result.errors, target, IO_ERR_UNKNOWN, "Failed to find win_helper"); free(escaped_target); free(escaped_path); return -1; } break_atr(base_dir, '\\'); snprintf(cmd, sizeof(cmd), "%s\\win_helper -s %s %s", base_dir, escaped_path, escaped_target); result = os_system(cmd); if(result != 0) { (void)ioe_errlst_append(&args->result.errors, target, IO_ERR_UNKNOWN, "Running win_helper has failed"); } free(escaped_target); free(escaped_path); #endif return result; }
show_locate_menu(FileView *view, const char args[]) { enum { M_a, M_u, M_U, }; char *cmd; char *margs; int save_msg; custom_macro_t macros[] = { [M_a] = { .letter = 'a', .value = args, .uses_left = 1, .group = -1 }, [M_u] = { .letter = 'u', .value = "", .uses_left = 1, .group = -1 }, [M_U] = { .letter = 'U', .value = "", .uses_left = 1, .group = -1 }, }; static menu_info m; margs = (args[0] == '-') ? strdup(args) : shell_like_escape(args, 0); init_menu_info(&m, format_str("Locate %s", margs), strdup("No files found")); m.args = margs; m.execute_handler = &execute_locate_cb; m.key_handler = &filelist_khandler; cmd = expand_custom_macros(cfg.locate_prg, ARRAY_LEN(macros), macros); status_bar_message("locate..."); save_msg = capture_output(view, cmd, 0, &m, macros[M_u].explicit_use, macros[M_U].explicit_use); free(cmd); return save_msg; }
/* Returns increment for curr_y. */ static int show_file_type(FileView *view, int curr_y) { const dir_entry_t *curr; int x; int old_curr_y = curr_y; x = getmaxx(menu_win); curr = get_current_entry(view); mvwaddstr(menu_win, curr_y, 2, "Type: "); if(curr->type == FT_LINK) { char full_path[PATH_MAX]; char linkto[PATH_MAX + NAME_MAX]; get_current_full_path(view, sizeof(full_path), full_path); mvwaddstr(menu_win, curr_y, 8, "Link"); curr_y += 2; mvwaddstr(menu_win, curr_y, 2, "Link To: "); if(get_link_target(full_path, linkto, sizeof(linkto)) == 0) { mvwaddnstr(menu_win, curr_y, 11, linkto, x - 11); if(!path_exists(linkto, DEREF)) { mvwaddstr(menu_win, curr_y - 2, 12, " (BROKEN)"); } } else { mvwaddstr(menu_win, curr_y, 11, "Couldn't Resolve Link"); } } else if(curr->type == FT_EXEC || curr->type == FT_REG) { #ifdef HAVE_FILE_PROG char full_path[PATH_MAX]; FILE *pipe; char command[1024]; char buf[NAME_MAX]; char *escaped_full_path; get_current_full_path(view, sizeof(full_path), full_path); /* Use the file command to get file information. */ escaped_full_path = shell_like_escape(full_path, 0); snprintf(command, sizeof(command), "file %s -b", escaped_full_path); free(escaped_full_path); if((pipe = popen(command, "r")) == NULL) { mvwaddstr(menu_win, curr_y, 8, "Unable to open pipe to read file"); return 2; } if(fgets(buf, sizeof(buf), pipe) != buf) strcpy(buf, "Pipe read error"); pclose(pipe); mvwaddnstr(menu_win, curr_y, 8, buf, x - 9); if(x > 9 && strlen(buf) > (size_t)(x - 9)) { mvwaddnstr(menu_win, curr_y + 1, 8, buf + x - 9, x - 9); } #else /* #ifdef HAVE_FILE_PROG */ if(curr->type == FT_EXEC) mvwaddstr(menu_win, curr_y, 8, "Executable"); else mvwaddstr(menu_win, curr_y, 8, "Regular File"); #endif /* #ifdef HAVE_FILE_PROG */ } else if(curr->type == FT_DIR) { mvwaddstr(menu_win, curr_y, 8, "Directory"); } #ifndef _WIN32 else if(curr->type == FT_CHAR_DEV || curr->type == FT_BLOCK_DEV) { const char *const type = (curr->type == FT_CHAR_DEV) ? "Character Device" : "Block Device"; char full_path[PATH_MAX]; struct stat st; mvwaddstr(menu_win, curr_y, 8, type); get_current_full_path(view, sizeof(full_path), full_path); if(os_stat(full_path, &st) == 0) { char info[64]; snprintf(info, sizeof(info), "Device Id: 0x%x:0x%x", major(st.st_rdev), minor(st.st_rdev)); curr_y += 2; mvwaddstr(menu_win, curr_y, 2, info); } } else if(curr->type == FT_SOCK) { mvwaddstr(menu_win, curr_y, 8, "Socket"); } #endif else if(curr->type == FT_FIFO) { mvwaddstr(menu_win, curr_y, 8, "Fifo Pipe"); } else { mvwaddstr(menu_win, curr_y, 8, "Unknown"); } curr_y += 2; return curr_y - old_curr_y; }