diff options
Diffstat (limited to 'win32')
-rw-r--r-- | win32/dirent.c | 28 | ||||
-rw-r--r-- | win32/mingw.c | 22 | ||||
-rw-r--r-- | win32/process.c | 44 |
3 files changed, 89 insertions, 5 deletions
diff --git a/win32/dirent.c b/win32/dirent.c index 795fc779c..f0e8deae2 100644 --- a/win32/dirent.c +++ b/win32/dirent.c | |||
@@ -3,7 +3,9 @@ | |||
3 | struct DIR { | 3 | struct DIR { |
4 | struct dirent dd_dir; | 4 | struct dirent dd_dir; |
5 | HANDLE dd_handle; /* FindFirstFile handle */ | 5 | HANDLE dd_handle; /* FindFirstFile handle */ |
6 | int dd_stat; /* 0-based index */ | 6 | int not_first; |
7 | int got_dot; | ||
8 | int got_dotdot; | ||
7 | }; | 9 | }; |
8 | 10 | ||
9 | static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata) | 11 | static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata) |
@@ -59,9 +61,11 @@ DIR *opendir(const char *name) | |||
59 | } | 61 | } |
60 | 62 | ||
61 | /* initialize DIR structure and copy first dir entry */ | 63 | /* initialize DIR structure and copy first dir entry */ |
62 | dir = xmalloc(sizeof(DIR)); | 64 | dir = xzalloc(sizeof(DIR)); |
63 | dir->dd_handle = h; | 65 | dir->dd_handle = h; |
64 | dir->dd_stat = 0; | 66 | /* dir->not_first = 0; */ |
67 | /* dir->got_dot = 0; */ | ||
68 | /* dir->got_dotdot = 0; */ | ||
65 | finddata2dirent(&dir->dd_dir, &fdata); | 69 | finddata2dirent(&dir->dd_dir, &fdata); |
66 | return dir; | 70 | return dir; |
67 | } | 71 | } |
@@ -74,11 +78,17 @@ struct dirent *readdir(DIR *dir) | |||
74 | } | 78 | } |
75 | 79 | ||
76 | /* if first entry, dirent has already been set up by opendir */ | 80 | /* if first entry, dirent has already been set up by opendir */ |
77 | if (dir->dd_stat) { | 81 | if (dir->not_first) { |
78 | /* get next entry and convert from WIN32_FIND_DATA to dirent */ | 82 | /* get next entry and convert from WIN32_FIND_DATA to dirent */ |
79 | WIN32_FIND_DATAA fdata; | 83 | WIN32_FIND_DATAA fdata; |
80 | if (FindNextFileA(dir->dd_handle, &fdata)) { | 84 | if (FindNextFileA(dir->dd_handle, &fdata)) { |
81 | finddata2dirent(&dir->dd_dir, &fdata); | 85 | finddata2dirent(&dir->dd_dir, &fdata); |
86 | } else if (!dir->got_dot) { | ||
87 | strcpy(dir->dd_dir.d_name, "."); | ||
88 | dir->dd_dir.d_type = DT_DIR; | ||
89 | } else if (!dir->got_dotdot) { | ||
90 | strcpy(dir->dd_dir.d_name, ".."); | ||
91 | dir->dd_dir.d_type = DT_DIR; | ||
82 | } else { | 92 | } else { |
83 | DWORD lasterr = GetLastError(); | 93 | DWORD lasterr = GetLastError(); |
84 | /* POSIX says you shouldn't set errno when readdir can't | 94 | /* POSIX says you shouldn't set errno when readdir can't |
@@ -89,7 +99,15 @@ struct dirent *readdir(DIR *dir) | |||
89 | } | 99 | } |
90 | } | 100 | } |
91 | 101 | ||
92 | ++dir->dd_stat; | 102 | /* Have we seen '.' or '..'? */ |
103 | if (dir->dd_dir.d_name[0] == '.') { | ||
104 | if (dir->dd_dir.d_name[1] == '\0') | ||
105 | dir->got_dot = TRUE; | ||
106 | else if (dir->dd_dir.d_name[1] == '.' && dir->dd_dir.d_name[2] == '\0') | ||
107 | dir->got_dotdot = TRUE; | ||
108 | } | ||
109 | |||
110 | dir->not_first = TRUE; | ||
93 | return &dir->dd_dir; | 111 | return &dir->dd_dir; |
94 | } | 112 | } |
95 | 113 | ||
diff --git a/win32/mingw.c b/win32/mingw.c index 7a5198ccf..cb1f84f30 100644 --- a/win32/mingw.c +++ b/win32/mingw.c | |||
@@ -2538,3 +2538,25 @@ char * FAST_FUNC exe_relative_path(const char *tail) | |||
2538 | free(exepath); | 2538 | free(exepath); |
2539 | return relpath; | 2539 | return relpath; |
2540 | } | 2540 | } |
2541 | |||
2542 | int mingw_shell_execute(SHELLEXECUTEINFO *info) | ||
2543 | { | ||
2544 | DECLARE_PROC_ADDR(BOOL, ShellExecuteExA, SHELLEXECUTEINFOA *); | ||
2545 | char *lpath; | ||
2546 | int ret; | ||
2547 | |||
2548 | if (!INIT_PROC_ADDR(shell32.dll, ShellExecuteExA)) { | ||
2549 | errno = ENOSYS; | ||
2550 | return FALSE; | ||
2551 | } | ||
2552 | |||
2553 | // ShellExecuteEx() needs backslash as separator in UNC paths. | ||
2554 | lpath = xstrdup(info->lpFile); | ||
2555 | slash_to_bs(lpath); | ||
2556 | info->lpFile = lpath; | ||
2557 | |||
2558 | ret = ShellExecuteExA(info); | ||
2559 | |||
2560 | free(lpath); | ||
2561 | return ret; | ||
2562 | } | ||
diff --git a/win32/process.c b/win32/process.c index e7c9ca187..33f45ee42 100644 --- a/win32/process.c +++ b/win32/process.c | |||
@@ -331,7 +331,9 @@ mingw_spawn_interpreter(int mode, const char *prog, char *const *argv, | |||
331 | } else { | 331 | } else { |
332 | errno = ENOENT; | 332 | errno = ENOENT; |
333 | } | 333 | } |
334 | #if ENABLE_FEATURE_PREFER_APPLETS && NUM_APPLETS > 1 | ||
334 | done: | 335 | done: |
336 | #endif | ||
335 | free(path); | 337 | free(path); |
336 | free(new_argv); | 338 | free(new_argv); |
337 | return ret; | 339 | return ret; |
@@ -499,6 +501,38 @@ static NORETURN void wait_for_child(HANDLE child, const char *cmd) | |||
499 | exit((int)code); | 501 | exit((int)code); |
500 | } | 502 | } |
501 | 503 | ||
504 | static intptr_t | ||
505 | shell_execute(const char *path, char *const *argv) | ||
506 | { | ||
507 | SHELLEXECUTEINFO info; | ||
508 | char *args; | ||
509 | |||
510 | memset(&info, 0, sizeof(SHELLEXECUTEINFO)); | ||
511 | info.cbSize = sizeof(SHELLEXECUTEINFO); | ||
512 | info.fMask = SEE_MASK_NOCLOSEPROCESS; | ||
513 | /* info.hwnd = NULL; */ | ||
514 | info.lpVerb = "runas"; | ||
515 | info.lpFile = path; | ||
516 | |||
517 | args = NULL; | ||
518 | if (*argv++) { | ||
519 | while (*argv) { | ||
520 | char *q = quote_arg(*argv++); | ||
521 | args = xappendword(args, q); | ||
522 | free(q); | ||
523 | } | ||
524 | } | ||
525 | |||
526 | info.lpParameters = args; | ||
527 | /* info.lpDirectory = NULL; */ | ||
528 | info.nShow = SW_SHOWNORMAL; | ||
529 | |||
530 | mingw_shell_execute(&info); | ||
531 | |||
532 | free(args); | ||
533 | return info.hProcess ? (intptr_t)info.hProcess : -1; | ||
534 | } | ||
535 | |||
502 | int | 536 | int |
503 | mingw_execvp(const char *cmd, char *const *argv) | 537 | mingw_execvp(const char *cmd, char *const *argv) |
504 | { | 538 | { |
@@ -512,6 +546,16 @@ int | |||
512 | mingw_execve(const char *cmd, char *const *argv, char *const *envp) | 546 | mingw_execve(const char *cmd, char *const *argv, char *const *envp) |
513 | { | 547 | { |
514 | intptr_t ret = mingw_spawn_interpreter(P_NOWAIT, cmd, argv, envp, 0); | 548 | intptr_t ret = mingw_spawn_interpreter(P_NOWAIT, cmd, argv, envp, 0); |
549 | |||
550 | if (ret == -1 && GetLastError() == ERROR_ELEVATION_REQUIRED) { | ||
551 | // Command exists but failed because it wants elevated privileges. | ||
552 | // Try again using ShellExecuteEx(). | ||
553 | SetLastError(0); | ||
554 | ret = shell_execute(cmd, argv); | ||
555 | if (GetLastError()) | ||
556 | exit(1); | ||
557 | } | ||
558 | |||
515 | if (ret != -1) | 559 | if (ret != -1) |
516 | wait_for_child((HANDLE)ret, cmd); | 560 | wait_for_child((HANDLE)ret, cmd); |
517 | return ret; | 561 | return ret; |