void setup_signals(void) { LOG_FUNC_ENTER; #ifndef _WIN32 struct sigaction handle_signal_action; handle_signal_action.sa_handler = handle_signal; sigemptyset(&handle_signal_action.sa_mask); handle_signal_action.sa_flags = SA_RESTART; sigaction(SIGCHLD, &handle_signal_action, NULL); sigaction(SIGHUP, &handle_signal_action, NULL); sigaction(SIGQUIT, &handle_signal_action, NULL); sigaction(SIGCONT, &handle_signal_action, NULL); sigaction(SIGTERM, &handle_signal_action, NULL); sigaction(SIGWINCH, &handle_signal_action, NULL); signal(SIGUSR1, SIG_IGN); signal(SIGUSR2, SIG_IGN); signal(SIGALRM, SIG_IGN); signal(SIGTSTP, SIG_IGN); #else if(!SetConsoleCtrlHandler(ctrl_handler, TRUE)) { LOG_WERROR(GetLastError()); } #endif signal(SIGINT, SIG_IGN); }
/* Returns non-zero on error, otherwise zero is returned. */ static int run_win_executable_as_evaluated(const char full_path[]) { wchar_t *utf16_path; SHELLEXECUTEINFOW sei; utf16_path = utf8_to_utf16(full_path); memset(&sei, 0, sizeof(sei)); sei.cbSize = sizeof(sei); sei.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS; sei.lpVerb = L"runas"; sei.lpFile = utf16_path; sei.lpParameters = NULL; sei.nShow = SW_SHOWNORMAL; if(!ShellExecuteExW(&sei)) { const DWORD last_error = GetLastError(); free(utf16_path); LOG_WERROR(last_error); return last_error != ERROR_CANCELLED; } free(utf16_path); CloseHandle(sei.hProcess); return 0; }
/* performs properties change with support of undoing */ static void file_attrib(char *path, DWORD add, DWORD sub, int recurse_dirs) { /* FIXME: set attributes recursively. */ DWORD attrs = GetFileAttributes(path); if(attrs == INVALID_FILE_ATTRIBUTES) { LOG_WERROR(GetLastError()); return; } if(add != 0) { const size_t wadd = add; if(perform_operation(OP_ADDATTR, NULL, (void *)wadd, path, NULL) == 0) { add_operation(OP_ADDATTR, (void *)wadd, (void *)(~attrs & wadd), path, ""); } } if(sub != 0) { const size_t wsub = sub; if(perform_operation(OP_SUBATTR, NULL, (void *)wsub, path, NULL) == 0) { add_operation(OP_SUBATTR, (void *)wsub, (void *)(~attrs & wsub), path, ""); } } }
int is_symlink(const char path[]) { #ifndef _WIN32 struct stat st; return os_lstat(path, &st) == 0 && S_ISLNK(st.st_mode); #else char filename[PATH_MAX]; DWORD attr; wchar_t *utf16_filename; HANDLE hfind; WIN32_FIND_DATAW ffd; attr = win_get_file_attrs(path); if(attr == INVALID_FILE_ATTRIBUTES) { LOG_WERROR(GetLastError()); return 0; } if(!(attr & FILE_ATTRIBUTE_REPARSE_POINT)) { return 0; } copy_str(filename, sizeof(filename), path); chosp(filename); utf16_filename = utf8_to_utf16(path); hfind = FindFirstFileW(utf16_filename, &ffd); free(utf16_filename); if(hfind == INVALID_HANDLE_VALUE) { LOG_WERROR(GetLastError()); return 0; } if(!FindClose(hfind)) { LOG_WERROR(GetLastError()); } return ffd.dwReserved0 == IO_REPARSE_TAG_SYMLINK; #endif }
static int op_subattr(void *data, const char *src, const char *dst) { const DWORD sub_mask = (size_t)data; const DWORD attrs = GetFileAttributesA(src); if(attrs == INVALID_FILE_ATTRIBUTES) { LOG_WERROR(GetLastError()); return -1; } if(!SetFileAttributesA(src, attrs & ~sub_mask)) { LOG_WERROR(GetLastError()); return -1; } return 0; }
static int op_removesl(void *data, const char *src, const char *dst) { #ifndef _WIN32 char *escaped; char cmd[16 + PATH_MAX]; int result; escaped = escape_filename(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); free(escaped); return result; #else if(is_dir(src)) { char buf[PATH_MAX]; int err; int i; snprintf(buf, sizeof(buf), "%s%c", src, '\0'); for(i = 0; buf[i] != '\0'; i++) if(buf[i] == '/') buf[i] = '\\'; SHFILEOPSTRUCTA fo = { .hwnd = NULL, .wFunc = FO_DELETE, .pFrom = buf, .pTo = NULL, .fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI, }; err = SHFileOperation(&fo); log_msg("Error: %d", err); return err; } else { int ok; DWORD attributes = GetFileAttributesA(src); if(attributes & FILE_ATTRIBUTE_READONLY) SetFileAttributesA(src, attributes & ~FILE_ATTRIBUTE_READONLY); ok = DeleteFile(src); if(!ok) LOG_WERROR(GetLastError()); return !ok; } #endif }
/* Runs a Windows executable handling errors and rights elevation. */ static void run_win_executable(char full_path[], int elevate) { int running_error = 0; int running_error_code = NO_ERROR; if(elevate && is_vista_and_above()) { running_error = run_win_executable_as_evaluated(full_path); } else { int returned_exit_code; const int error = win_exec_cmd(full_path, &returned_exit_code); if(error != 0 && !returned_exit_code) { if(error == ERROR_ELEVATION_REQUIRED && is_vista_and_above()) { const int user_response = prompt_msg("Program running error", "Executable requires rights elevation. Run with elevated rights?"); if(user_response != 0) { running_error = run_win_executable_as_evaluated(full_path); } } else { running_error = 1; running_error_code = error; } } update_screen(UT_FULL); } if(running_error) { char err_msg[512]; err_msg[0] = '\0'; if(running_error_code != NO_ERROR && FormatMessageA( FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, NULL, running_error_code, 0, err_msg, sizeof(err_msg), NULL) == 0) { LOG_WERROR(GetLastError()); } show_error_msgf("Program running error", "Can't run an executable%s%s", (err_msg[0] == '\0') ? "." : ": ", err_msg); } }
void setup_signals(void) { LOG_FUNC_ENTER; #ifndef _WIN32 struct sigaction handle_signal_action; handle_signal_action.sa_handler = &handle_signal; sigemptyset(&handle_signal_action.sa_mask); handle_signal_action.sa_flags = SA_RESTART; /* Assumption: we work under shell with job control support. If it's not the * case, this code enables handling of terminal related signals the shell * wanted us to have disabled (e.g. the app will catch Ctrl-C send to another * process). */ sigaction(SIGCHLD, &handle_signal_action, NULL); sigaction(SIGHUP, &handle_signal_action, NULL); sigaction(SIGINT, &handle_signal_action, NULL); sigaction(SIGQUIT, &handle_signal_action, NULL); sigaction(SIGCONT, &handle_signal_action, NULL); sigaction(SIGTERM, &handle_signal_action, NULL); sigaction(SIGWINCH, &handle_signal_action, NULL); signal(SIGUSR1, SIG_IGN); signal(SIGUSR2, SIG_IGN); signal(SIGALRM, SIG_IGN); signal(SIGTSTP, SIG_IGN); #else if(!SetConsoleCtrlHandler(ctrl_handler, TRUE)) { LOG_WERROR(GetLastError()); } signal(SIGINT, SIG_IGN); #endif }
int get_link_target(const char *link, char *buf, size_t buf_len) { LOG_FUNC_ENTER; #ifndef _WIN32 char *filename; ssize_t len; if(buf_len == 0) { return -1; } filename = strdup(link); chosp(filename); len = readlink(filename, buf, buf_len - 1); free(filename); if(len == -1) { return -1; } buf[len] = '\0'; return 0; #else char filename[PATH_MAX]; DWORD attr; wchar_t *utf16_filename; HANDLE hfile; char rdb[2048]; char *t; REPARSE_DATA_BUFFER *sbuf; WCHAR *path; if(!is_symlink(link)) { return -1; } copy_str(filename, sizeof(filename), link); chosp(filename); utf16_filename = utf8_to_utf16(filename); hfile = CreateFileW(utf16_filename, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL); free(utf16_filename); if(hfile == INVALID_HANDLE_VALUE) { LOG_WERROR(GetLastError()); return -1; } if(!DeviceIoControl(hfile, FSCTL_GET_REPARSE_POINT, NULL, 0, rdb, sizeof(rdb), &attr, NULL)) { LOG_WERROR(GetLastError()); CloseHandle(hfile); return -1; } CloseHandle(hfile); sbuf = (REPARSE_DATA_BUFFER *)rdb; path = sbuf->SymbolicLinkReparseBuffer.PathBuffer; path[sbuf->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR) + sbuf->SymbolicLinkReparseBuffer.PrintNameLength/sizeof(WCHAR)] = L'\0'; t = to_multibyte(path + sbuf->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR)); if(strncmp(t, "\\??\\", 4) == 0) strncpy(buf, t + 4, buf_len); else strncpy(buf, t, buf_len); buf[buf_len - 1] = '\0'; free(t); to_forward_slash(buf); return 0; #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 }
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 }