| ... | @@ -965,56 +965,90 @@ pub const ChildProcess = struct { | ... | @@ -965,56 +965,90 @@ pub const ChildProcess = struct { |
| 965 | const cmd_line_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, cmd_line); | 965 | const cmd_line_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, cmd_line); |
| 966 | defer self.allocator.free(cmd_line_w); | 966 | defer self.allocator.free(cmd_line_w); |
| 967 | | 967 | |
| 968 | windowsCreateProcess(app_path_w.ptr, cmd_line_w.ptr, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo) catch |no_path_err| { | 968 | exec: { |
| 969 | if (no_path_err != error.FileNotFound and no_path_err != error.InvalidExe) return no_path_err; | 969 | windowsCreateProcess(app_path_w.ptr, cmd_line_w.ptr, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo) catch |no_path_err| { |
| 970 | | 970 | switch (no_path_err) { |
| 971 | const PATH: [:0]const u16 = std.os.getenvW(unicode.utf8ToUtf16LeStringLiteral("PATH")) orelse &[_:0]u16{}; | 971 | error.FileNotFound, error.InvalidExe => {}, |
| 972 | const PATHEXT: [:0]const u16 = std.os.getenvW(unicode.utf8ToUtf16LeStringLiteral("PATHEXT")) orelse &[_:0]u16{}; | 972 | else => |e| return e, |
| 973 | | | |
| 974 | var path_buf = std.ArrayListUnmanaged(u16){}; | | |
| 975 | defer path_buf.deinit(self.allocator); | | |
| 976 | | | |
| 977 | const app_name = self.argv[0]; | | |
| 978 | const app_name_trimmed_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, mem.trimLeft(u8, app_name, "\\/")); | | |
| 979 | defer self.allocator.free(app_name_trimmed_w); | | |
| 980 | | | |
| 981 | var it = mem.tokenize(u16, PATH, &[_]u16{';'}); | | |
| 982 | retry: while (it.next()) |search_path| { | | |
| 983 | path_buf.clearRetainingCapacity(); | | |
| 984 | const search_path_trimmed = mem.trimRight(u16, search_path, &[_]u16{ '\\', '/' }); | | |
| 985 | try path_buf.appendSlice(self.allocator, search_path_trimmed); | | |
| 986 | try path_buf.append(self.allocator, fs.path.sep); | | |
| 987 | try path_buf.appendSlice(self.allocator, app_name_trimmed_w); | | |
| 988 | try path_buf.append(self.allocator, 0); | | |
| 989 | const path_no_ext = path_buf.items[0 .. path_buf.items.len - 1 :0]; | | |
| 990 | | | |
| 991 | if (windowsCreateProcess(path_no_ext.ptr, cmd_line_w.ptr, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo)) |_| { | | |
| 992 | break :retry; | | |
| 993 | } else |err| switch (err) { | | |
| 994 | error.FileNotFound, error.AccessDenied, error.InvalidExe => {}, | | |
| 995 | else => return err, | | |
| 996 | } | 973 | } |
| 997 | | 974 | |
| 998 | var ext_it = mem.tokenize(u16, PATHEXT, &[_]u16{';'}); | 975 | const PATH: [:0]const u16 = std.os.getenvW(unicode.utf8ToUtf16LeStringLiteral("PATH")) orelse &[_:0]u16{}; |
| 999 | while (ext_it.next()) |ext| { | 976 | const PATHEXT: [:0]const u16 = std.os.getenvW(unicode.utf8ToUtf16LeStringLiteral("PATHEXT")) orelse &[_:0]u16{}; |
| 1000 | path_buf.shrinkRetainingCapacity(path_no_ext.len); | 977 | |
| 1001 | try path_buf.appendSlice(self.allocator, ext); | 978 | var path_buf = std.ArrayListUnmanaged(u16){}; |
| | 979 | defer path_buf.deinit(self.allocator); |
| | 980 | |
| | 981 | // Try again with PATHEXT's extensions appended |
| | 982 | { |
| | 983 | try path_buf.appendSlice(self.allocator, app_path_w); |
| | 984 | var ext_it = mem.tokenize(u16, PATHEXT, &[_]u16{';'}); |
| | 985 | while (ext_it.next()) |ext| { |
| | 986 | path_buf.shrinkRetainingCapacity(app_path_w.len); |
| | 987 | try path_buf.appendSlice(self.allocator, ext); |
| | 988 | try path_buf.append(self.allocator, 0); |
| | 989 | const path_with_ext = path_buf.items[0 .. path_buf.items.len - 1 :0]; |
| | 990 | |
| | 991 | if (windowsCreateProcess(path_with_ext.ptr, cmd_line_w.ptr, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo)) |_| { |
| | 992 | break :exec; |
| | 993 | } else |err| switch (err) { |
| | 994 | error.FileNotFound, error.AccessDenied, error.InvalidExe => {}, |
| | 995 | else => return err, |
| | 996 | } |
| | 997 | } |
| | 998 | } |
| | 999 | |
| | 1000 | // app_path_w has the cwd prepended to it if cwd is non-null, so when |
| | 1001 | // searching the PATH we should make sure we use the app_name verbatim. |
| | 1002 | var app_name_w_needs_free = false; |
| | 1003 | const app_name_w = x: { |
| | 1004 | if (self.cwd) |_| { |
| | 1005 | app_name_w_needs_free = true; |
| | 1006 | break :x try unicode.utf8ToUtf16LeWithNull(self.allocator, self.argv[0]); |
| | 1007 | } else { |
| | 1008 | break :x app_path_w; |
| | 1009 | } |
| | 1010 | }; |
| | 1011 | defer if (app_name_w_needs_free) self.allocator.free(app_name_w); |
| | 1012 | |
| | 1013 | var it = mem.tokenize(u16, PATH, &[_]u16{';'}); |
| | 1014 | while (it.next()) |search_path| { |
| | 1015 | path_buf.clearRetainingCapacity(); |
| | 1016 | const search_path_trimmed = mem.trimRight(u16, search_path, &[_]u16{ '\\', '/' }); |
| | 1017 | try path_buf.appendSlice(self.allocator, search_path_trimmed); |
| | 1018 | try path_buf.append(self.allocator, fs.path.sep); |
| | 1019 | const app_name_trimmed = mem.trimLeft(u16, app_name_w, &[_]u16{ '\\', '/' }); |
| | 1020 | try path_buf.appendSlice(self.allocator, app_name_trimmed); |
| 1002 | try path_buf.append(self.allocator, 0); | 1021 | try path_buf.append(self.allocator, 0); |
| 1003 | const joined_path = path_buf.items[0 .. path_buf.items.len - 1 :0]; | 1022 | const path_no_ext = path_buf.items[0 .. path_buf.items.len - 1 :0]; |
| 1004 | | 1023 | |
| 1005 | if (windowsCreateProcess(joined_path.ptr, cmd_line_w.ptr, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo)) |_| { | 1024 | if (windowsCreateProcess(path_no_ext.ptr, cmd_line_w.ptr, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo)) |_| { |
| 1006 | break :retry; | 1025 | break :exec; |
| 1007 | } else |err| switch (err) { | 1026 | } else |err| switch (err) { |
| 1008 | error.FileNotFound => continue, | 1027 | error.FileNotFound, error.AccessDenied, error.InvalidExe => {}, |
| 1009 | error.AccessDenied => continue, | | |
| 1010 | error.InvalidExe => continue, | | |
| 1011 | else => return err, | 1028 | else => return err, |
| 1012 | } | 1029 | } |
| | 1030 | |
| | 1031 | var ext_it = mem.tokenize(u16, PATHEXT, &[_]u16{';'}); |
| | 1032 | while (ext_it.next()) |ext| { |
| | 1033 | path_buf.shrinkRetainingCapacity(path_no_ext.len); |
| | 1034 | try path_buf.appendSlice(self.allocator, ext); |
| | 1035 | try path_buf.append(self.allocator, 0); |
| | 1036 | const joined_path = path_buf.items[0 .. path_buf.items.len - 1 :0]; |
| | 1037 | |
| | 1038 | if (windowsCreateProcess(joined_path.ptr, cmd_line_w.ptr, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo)) |_| { |
| | 1039 | break :exec; |
| | 1040 | } else |err| switch (err) { |
| | 1041 | error.FileNotFound => continue, |
| | 1042 | error.AccessDenied => continue, |
| | 1043 | error.InvalidExe => continue, |
| | 1044 | else => return err, |
| | 1045 | } |
| | 1046 | } |
| | 1047 | } else { |
| | 1048 | return no_path_err; // return the original error |
| 1013 | } | 1049 | } |
| 1014 | } else { | 1050 | }; |
| 1015 | return no_path_err; // return the original error | 1051 | } |
| 1016 | } | | |
| 1017 | }; | | |
| 1018 | | 1052 | |
| 1019 | if (g_hChildStd_IN_Wr) |h| { | 1053 | if (g_hChildStd_IN_Wr) |h| { |
| 1020 | self.stdin = File{ .handle = h }; | 1054 | self.stdin = File{ .handle = h }; |