int ConfirmOverwrite(const CTar32CmdInfo &cmdinfo,EXTRACTINGINFOEX64 &ExtractingInfoEx64) { extern HINSTANCE dll_instance; extern HWND g_hwndOwnerWindow; std::string path=ExtractingInfoEx64.szDestFileName; convert_slash_to_backslash(path); //存在確認 if(PathFileExists(path.c_str()) && !PathIsDirectory(path.c_str())){ HWND hWnd=NULL; if(cmdinfo.hTar32StatusDialog){ hWnd=cmdinfo.hTar32StatusDialog; }else if(g_hwndOwnerWindow){ hWnd=g_hwndOwnerWindow; } get_full_path(path.c_str(),path); std::stringstream msg; msg << "File " << path << " already exists.\r\n" << "Do you want to overwrite?"; int ret=::DialogBoxParam(dll_instance,MAKEINTRESOURCE(IDD_CONFIRM_OVERWRITE),hWnd,Tar32ConfirmOverwriteDialogProc,(LPARAM)(const char*)(msg.str().c_str())); switch(ret){ case IDCANCEL: return -1; case IDC_BUTTON_OVERWRITE: return 0; case IDC_BUTTON_OVERWRITE_ALL: return 1; default: return 0; } } return 0; }
int main(int argc, char *argv[]) { if (argc < 1) { dprintf(STDERR_FILENO, "wrun called without argument\n"); terminate_nocore(); } shift(&argc, &argv); if (argc > 1 && !strcmp(argv[0], "--tool_name")) { shift(&argc, &argv); tool_name = shift(&argc, &argv); } fill_std_fd_info_identity(STDIN_FILENO); fill_std_fd_info_identity(STDOUT_FILENO); fill_std_fd_info_identity(STDERR_FILENO); bool force_redirects = false; bool silent_breakaway = false; int port; bool terminate = !get_outbash_infos(&port, &force_redirects); struct string outbash_command = string_create(""); if (argc && !strcmp(argv[0], ":")) { shift(&argc, &argv); string_append(&outbash_command, "cd:~\n"); } else { char* cwd = agetcwd(); if (is_absolute_drive_fs_path(cwd)) { char* cwd_win32 = convert_drive_fs_path_to_win32(cwd); string_append(&outbash_command, "cd:"); string_append(&outbash_command, cwd_win32); string_append(&outbash_command, "\n"); free(cwd_win32); } free(cwd); } while (argc && !strncmp(argv[0], "--", 2)) { if (!strcmp(argv[0], "--")) { shift(&argc, &argv); break; } if (!strcmp(argv[0], "--env")) { shift(&argc, &argv); while (argc && strncmp(argv[0], "--", 2) != 0 && *argv[0] != '\0' && strchr(argv[0] + 1, '=')) { string_append(&outbash_command, "env:"); string_append(&outbash_command, argv[0]); string_append(&outbash_command, "\n"); shift(&argc, &argv); } } else if (!strcmp(argv[0], "--force-redirects")) { force_redirects = true; shift(&argc, &argv); } else if (!strcmp(argv[0], "--silent-breakaway")) { silent_breakaway = true; shift(&argc, &argv); } else if (!strcmp(argv[0], "--help")) { print_help(); exit(1); } else { dprintf(STDERR_FILENO, "%s: unknown command line option: %s\n", tool_name, argv[0]); dprintf(STDERR_FILENO, "type %s --help for more information.\n", tool_name); terminate_nocore(); } } if (terminate) terminate_nocore(); check_argc(argc); decide_will_redirect(STDIN_FILENO, force_redirects); decide_will_redirect(STDOUT_FILENO, force_redirects); decide_will_redirect(STDERR_FILENO, force_redirects); int sock_ctrl = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock_ctrl < 0) { dprintf(STDERR_FILENO, "%s: socket() failed: %s\n", tool_name, my_strerror(errno)); terminate_nocore(); } #define STDIN_NEEDS_SOCKET_REDIRECT 1 #define STDOUT_NEEDS_SOCKET_REDIRECT 2 #define STDERR_NEEDS_SOCKET_REDIRECT 4 #define STDERR_SOCKREDIR_TO_STDOUT 8 int redirects = (needs_socket_redirect(STDIN_FILENO) ? STDIN_NEEDS_SOCKET_REDIRECT : 0) | (needs_socket_redirect(STDOUT_FILENO) ? STDOUT_NEEDS_SOCKET_REDIRECT : 0); if (needs_socket_redirect(STDERR_FILENO)) { if ((redirects & STDOUT_NEEDS_SOCKET_REDIRECT) && are_stdfd_to_same_thing(STDOUT_FILENO, STDERR_FILENO)) redirects |= STDERR_SOCKREDIR_TO_STDOUT; else redirects |= STDERR_NEEDS_SOCKET_REDIRECT; } struct listening_socket lsock_in = NO_LISTENING_SOCKET; struct listening_socket lsock_out = NO_LISTENING_SOCKET; struct listening_socket lsock_err = NO_LISTENING_SOCKET; if (redirects & STDIN_NEEDS_SOCKET_REDIRECT) lsock_in = socket_listen_one_loopback(); if (redirects & STDOUT_NEEDS_SOCKET_REDIRECT) lsock_out = socket_listen_one_loopback(); if (redirects & STDERR_NEEDS_SOCKET_REDIRECT) lsock_err = socket_listen_one_loopback(); ask_redirect(&outbash_command, "stdin:", STDIN_FILENO, lsock_in.port); ask_redirect(&outbash_command, "stdout:", STDOUT_FILENO, lsock_out.port); ask_redirect(&outbash_command, "stderr:", STDERR_FILENO, (redirects & STDERR_NEEDS_SOCKET_REDIRECT) ? lsock_err.port : lsock_out.port); if (silent_breakaway) string_append(&outbash_command, "silent_breakaway:1\n"); char* win32_module; if (is_absolute_drive_fs_path(argv[0])) { win32_module = convert_drive_fs_path_to_win32(argv[0]); string_append(&outbash_command, "module:"); string_append(&outbash_command, win32_module); string_append(&outbash_command, "\n"); } else { win32_module = convert_slash_to_backslash(argv[0]); } const bool module_need_quotes = (NULL != strpbrk(win32_module, " \t")); string_append(&outbash_command, "run:"); if (module_need_quotes) string_append(&outbash_command, "\""); string_append(&outbash_command, win32_module); if (module_need_quotes) string_append(&outbash_command, "\""); free(win32_module); for (int i = 1; i < argc; i++) { string_append(&outbash_command, " "); string_append(&outbash_command, argv[i]); } string_append(&outbash_command, "\n\n"); //dprintf(STDOUT_FILENO, "%s", outbash_command.str); //return EXIT_FAILURE; signal(SIGPIPE, SIG_IGN); sigset_t signal_set, orig_mask; //////////////////////////// unblock SIGUSR1 sigemptyset(&signal_set); sigaddset(&signal_set, SIGUSR1); pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL); //////////////////////////// block SIGTSTP sigemptyset(&signal_set); sigaddset(&signal_set, SIGTSTP); pthread_sigmask(SIG_BLOCK, &signal_set, &orig_mask); //////////////////////////// install custom SIGTSTP handler if signal was not ignored struct sigaction sa; sigaction(SIGTSTP, NULL, &sa); const bool ignore_sigtstp = (sa.sa_handler == SIG_IGN); if (!ignore_sigtstp) { sa.sa_handler = tstop_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGTSTP, &sa, NULL); } //////////////////////////// install custom SIGUSR1 handler to wake-up blocked IO forwarding threads // NOTE: the handler itself do nothing, but any blocked syscall will return with EINTR error sa.sa_handler = noop_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGUSR1, &sa, NULL); struct sockaddr_in serv_addr; memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); serv_addr.sin_port = htons(port); if (connect(sock_ctrl, (const struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) { // NOTE: I'm not sure that WSL does what Linux does concerning // http://www.madore.org/~david/computers/connect-intr.html // for now we do not expect to recover after an interruption here. dprintf(STDERR_FILENO, "%s: connect() failed: %s\n", tool_name, my_strerror(errno)); terminate_nocore(); } if (send_all(sock_ctrl, outbash_command.str, outbash_command.length, 0) < 0) { dprintf(STDERR_FILENO, "%s: send_all() failed: %s\n", tool_name, my_strerror(errno)); terminate_nocore(); } string_destroy(&outbash_command); static struct forward_state fs[3]; fs_init_accept_as_needed(&fs[STDIN_FILENO], &lsock_in, redirects & STDIN_NEEDS_SOCKET_REDIRECT, STDIN_FILENO, "stdin"); fs_init_accept_as_needed(&fs[STDOUT_FILENO], &lsock_out, redirects & STDOUT_NEEDS_SOCKET_REDIRECT, STDOUT_FILENO, "stdout"); fs_init_accept_as_needed(&fs[STDERR_FILENO], &lsock_err, redirects & STDERR_NEEDS_SOCKET_REDIRECT, STDERR_FILENO, "stderr"); char *line = ctrl_readln(sock_ctrl, NULL); if (!line || strcmp(line, "connected")) { dprintf(STDERR_FILENO, "%s: did not receive connection validation from outbash.exe\n", tool_name); terminate_nocore(); } close_listener(&lsock_in); close_listener(&lsock_out); close_listener(&lsock_err); enum state_e state = RUNNING; int program_return_code = 255; pthread_t forward_threads[3]; bool active_threads[3] = {0}; for (int i = 0; i < 3; i++) { if ((!fs[i].dead_in) || (!fs[i].dead_out)) { int err = pthread_create(&forward_threads[i], NULL, forward_one_stream, &fs[i]); if (err != 0) { dprintf(STDERR_FILENO, "%s: pthread_create() failed: %s\n", tool_name, my_strerror(err)); terminate_nocore(); } active_threads[i] = true; } } int nfds = sock_ctrl + 1; while (state != TERMINATED) { fd_set rfds; FD_ZERO(&rfds); if (sock_ctrl < 0 || sock_ctrl >= FD_SETSIZE) { dprintf(STDERR_FILENO, "%s: sock_ctrl=%d out of range\n", tool_name, sock_ctrl); abort(); } FD_SET(sock_ctrl, &rfds); int pselect_res = pselect(nfds, &rfds, NULL, NULL, NULL, &orig_mask); // tstop_handler can run here int pselect_errno = errno; if (tstop_req && state == RUNNING) { int r = send_all(sock_ctrl, "suspend\n", strlen("suspend\n"), 0); if (r < 0 && err_is_connection_broken(errno)) { // We will never be able to ask outbash to suspend the // Windows process, the expected reason is that it actually // has already terminated and we don't know yet about that, // so stop the suspend forwarding mechanism and suspend // ourselves immediately. shutdown(sock_ctrl, SHUT_WR); // also we can't send anything anymore // XXX to comment for WSL bug workaround? proba low here... signal(SIGTSTP, SIG_DFL); state = DYING; raise(SIGTSTP); pthread_sigmask(SIG_SETMASK, &orig_mask, NULL); } else if (r < 0) { // other errors dprintf(STDERR_FILENO, "%s: send_all(\"suspend\\n\") failed: %s\n", tool_name, my_strerror(errno)); abort(); } else { // OK // It's up to outbash now, just wait for its "suspend_ok" // answer after it has suspended the Windows process. state = SUSPEND_PENDING; } } if (pselect_res < 0 && pselect_errno == EINTR) { // "On error, -1 is returned, and errno is set appropriately; // the sets and timeout become undefined, so do not rely on // their contents after an error." continue; } if (pselect_res < 0) { dprintf(STDERR_FILENO, "%s: pselect() failed: %s\n", tool_name, my_strerror(pselect_errno)); abort(); } if (FD_ISSET(sock_ctrl, &rfds)) { while (1) { int nonblock_marker; line = ctrl_readln(sock_ctrl, &nonblock_marker); if (!line && nonblock_marker) break; if (line && !strcmp(line, "suspend_ok")) { if (state == SUSPEND_PENDING) { signal(SIGTSTP, SIG_DFL); raise(SIGTSTP); sigset_t previous_mask; pthread_sigmask(SIG_SETMASK, &orig_mask, &previous_mask); // >>> Process will Stop here, until SIGCONT <<< pthread_sigmask(SIG_SETMASK, &previous_mask, NULL); tstop_req = 0; int r = send_all(sock_ctrl, "resume\n", strlen("resume\n"), 0); if (r < 0 && err_is_connection_broken(errno)) { // killed when suspended (if this is possible?) // or maybe just before an attempt? shutdown(sock_ctrl, SHUT_WR); // XXX to comment for WSL bug workaround? proba low here... state = DYING; pthread_sigmask(SIG_SETMASK, &orig_mask, NULL); } else if (r < 0) { dprintf(STDERR_FILENO, "%s: send_all(\"resume\\n\") failed: %s\n", tool_name, my_strerror(errno)); abort(); } else { state = RUNNING; sa.sa_handler = tstop_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGTSTP, &sa, NULL); } } else { dprintf(STDERR_FILENO, "%s: spurious \"suspend_ok\" received\n", tool_name); } } else { // not "suspend_ok" => for now only other cases are exit conditions program_return_code = get_return_code(line); shutdown(sock_ctrl, SHUT_RDWR); signal(SIGTSTP, ignore_sigtstp ? SIG_IGN : SIG_DFL); if ((tstop_req && state == RUNNING) || state == SUSPEND_PENDING) { // We expect to stop soon, but not without flushing the OS TCP // buffers and our owns, and other WSL processes in a pipe might // already be suspended, so we better honor suspend requests ASAP. raise(SIGTSTP); } pthread_sigmask(SIG_SETMASK, &orig_mask, NULL); tstop_req = 0; state = TERMINATED; break; } } } } // XXX: this is not ideal if the Win32 side managed to maintain the // redirection socket beyond the lifetime of the launched process, // however things seem to already be not reliable for Windows reasons // in this case if (active_threads[0]) { __sync_fetch_and_add(&fs[0].ask_terminate, 1); useconds_t usec_sleep = 1000; while (!__sync_fetch_and_add(&fs[0].finished, 0)) { pthread_kill(forward_threads[0], SIGUSR1); usleep(usec_sleep); usec_sleep *= 2; if (usec_sleep > 60000000) usec_sleep = 60000000; } } for (int i = 0; i < 3; i++) if (active_threads[i]) pthread_join(forward_threads[i], NULL); return program_return_code; }