const char * apply_mods(const char path[], const char parent[], const char mod[], int for_shell) { static char buf[PATH_MAX]; int napplied = 0; copy_str(buf, sizeof(buf), path); while(*mod != '\0') { int mod_len; const char *const p = apply_mod(buf, parent, mod, &mod_len, for_shell); if(p == NULL) { break; } copy_str(buf, sizeof(buf), p); mod += mod_len; napplied++; } #ifdef _WIN32 /* This is needed to run something like explorer.exe, which isn't smart enough * to understand forward slashes. */ if(for_shell && curr_stats.shell_type != ST_CMD && napplied == 0) { to_back_slash(buf); } #endif return buf; }
/* Copies file/directory overwriting destination files if requested. Returns * non-zero on error, otherwise zero is returned. */ static int op_cp(void *data, const char src[], const char dst[], int overwrite) { #ifndef _WIN32 char *escaped_src, *escaped_dst; char cmd[6 + PATH_MAX*2 + 1]; int result; escaped_src = escape_filename(src, 0); escaped_dst = escape_filename(dst, 0); if(escaped_src == NULL || escaped_dst == NULL) { free(escaped_dst); free(escaped_src); return -1; } snprintf(cmd, sizeof(cmd), "cp %s -R " PRESERVE_FLAGS " %s %s", overwrite ? "" : NO_CLOBBER, escaped_src, escaped_dst); LOG_INFO_MSG("Running cp command: \"%s\"", cmd); result = background_and_wait_for_errors(cmd); free(escaped_dst); free(escaped_src); return result; #else int ret; if(is_dir(src)) { char cmd[6 + PATH_MAX*2 + 1]; snprintf(cmd, sizeof(cmd), "xcopy \"%s\" \"%s\" ", src, dst); to_back_slash(cmd); if(is_vista_and_above()) strcat(cmd, "/B "); if(overwrite) { strcat(cmd, "/Y "); } strcat(cmd, "/E /I /H /R > NUL"); ret = system(cmd); } else { ret = (CopyFileA(src, dst, 0) == 0); } return ret; #endif }
/* Applies one filename modifiers per call. */ static const char * apply_mod(const char *path, const char *parent, const char *mod, int *mod_len, int for_shell) { char path_buf[PATH_MAX]; static char buf[PATH_MAX]; snprintf(path_buf, sizeof(path_buf), "%s", path); #ifdef _WIN32 to_forward_slash(path_buf); #endif *mod_len = 2; if(starts_with_lit(mod, ":p")) *mod_len += apply_p_mod(path_buf, parent, buf, sizeof(buf)); else if(starts_with_lit(mod, ":~")) *mod_len += apply_tilde_mod(path_buf, buf, sizeof(buf)); else if(starts_with_lit(mod, ":.")) *mod_len += apply_dot_mod(path_buf, buf, sizeof(buf)); else if(starts_with_lit(mod, ":h")) *mod_len += apply_h_mod(path_buf, buf, sizeof(buf)); #ifdef _WIN32 else if(starts_with_lit(mod, ":u")) *mod_len += apply_u_mod(path_buf, buf, sizeof(buf)); #endif else if(starts_with_lit(mod, ":t")) *mod_len += apply_t_mod(path_buf, buf, sizeof(buf)); else if(starts_with_lit(mod, ":r")) *mod_len += apply_r_mod(path_buf, buf, sizeof(buf)); else if(starts_with_lit(mod, ":e")) *mod_len += apply_e_mod(path_buf, buf, sizeof(buf)); else if(starts_with_lit(mod, ":s") || starts_with_lit(mod, ":gs")) *mod_len += apply_s_gs_mod(path_buf, mod, buf, sizeof(buf)); else return NULL; #ifdef _WIN32 /* This is needed to run something like explorer.exe, which isn't smart enough * to understand forward slashes. */ if(for_shell && curr_stats.shell_type != ST_CMD) { if(!starts_with_lit(mod, ":s") && !starts_with_lit(mod, ":gs")) { to_back_slash(buf); } } #endif return buf; }
static char * expand_directory_path(FileView *view, char *expanded, int quotes, const char *mod, int for_shell) { const char *const modified = apply_mods(flist_get_dir(view), "/", mod, for_shell); char *const result = append_path_to_expanded(expanded, quotes, modified); #ifdef _WIN32 if(for_shell && curr_stats.shell_type == ST_CMD) { to_back_slash(result); } #endif return result; }
/* 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 }
/* Adds a path to PATH environment variable. */ static void add_to_path(const char *path) { const char *old_path; char *new_path; old_path = env_get("PATH"); new_path = malloc(strlen(path) + 1 + strlen(old_path) + 1); #ifndef _WIN32 sprintf(new_path, "%s:%s", path, old_path); #else sprintf(new_path, "%s;%s", path, old_path); to_back_slash(new_path); #endif env_set("PATH", new_path); free(new_path); }
TSTATIC char * append_selected_files(FileView *view, char expanded[], int under_cursor, int quotes, const char mod[], int for_shell) { const PathType type = (view == other_view) ? PT_FULL : (flist_custom_active(view) ? PT_REL : PT_NAME); #ifdef _WIN32 size_t old_len = strlen(expanded); #endif if(view->selected_files && !under_cursor) { int n = 0; dir_entry_t *entry = NULL; while(iter_selected_entries(view, &entry)) { expanded = append_entry(view, expanded, type, entry, quotes, mod, for_shell); if(++n != view->selected_files) { expanded = append_to_expanded(expanded, " "); } } } else { expanded = append_entry(view, expanded, type, get_current_entry(view), quotes, mod, for_shell); } #ifdef _WIN32 if(for_shell && curr_stats.shell_type == ST_CMD) { to_back_slash(expanded + old_len); } #endif return expanded; }
/* Expands content of a register specified by the key argument considering * filename-modifiers. If key is unknown, falls back to the default register. * Sets *well_formed to non-zero for valid value of the key. Reallocates the * expanded string and returns result (possibly NULL). */ static char * expand_register(const char curr_dir[], char expanded[], int quotes, const char mod[], int key, int *well_formed, int for_shell) { int i; reg_t *reg; *well_formed = 1; reg = regs_find(tolower(key)); if(reg == NULL) { *well_formed = 0; reg = regs_find(DEFAULT_REG_NAME); assert(reg != NULL); mod--; } for(i = 0; i < reg->nfiles; ++i) { const char *const modified = apply_mods(reg->files[i], curr_dir, mod, for_shell); expanded = append_path_to_expanded(expanded, quotes, modified); if(i != reg->nfiles - 1) { expanded = append_to_expanded(expanded, " "); } } #ifdef _WIN32 if(for_shell && curr_stats.shell_type == ST_CMD) { to_back_slash(expanded); } #endif return expanded; }
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 }
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 }