Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include <windows.h> | |
| 6 #include <stdio.h> | |
| 7 #include <stdlib.h> | |
| 8 #include <string> | |
| 9 | |
| 10 using namespace std; | |
| 11 | |
| 12 // Don't use stderr for errors because VS has large buffers on them, leading | |
| 13 // to confusing error output. | |
| 14 static void Fatal(const wchar_t* msg) { | |
| 15 wprintf(L"supalink fatal error: %s\n", msg); | |
| 16 exit(1); | |
| 17 } | |
| 18 | |
| 19 static wstring ErrorMessageToString(DWORD err) { | |
| 20 wchar_t* msg_buf = NULL; | |
| 21 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, | |
|
M-A Ruel
2011/09/28 00:33:27
You should still check the error code.
scottmg
2011/09/28 15:59:42
Done.
| |
| 22 NULL, | |
| 23 err, | |
| 24 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | |
| 25 reinterpret_cast<LPTSTR>(&msg_buf), | |
| 26 0, | |
| 27 NULL); | |
| 28 wstring ret(msg_buf); | |
| 29 LocalFree(msg_buf); | |
| 30 return ret; | |
| 31 } | |
| 32 | |
| 33 static const wchar_t* g_search_for[] = { | |
|
M-A Ruel
2011/09/28 00:33:27
that's not const. To be const, it must be:
static
scottmg
2011/09/28 15:59:42
Done.
| |
| 34 L"link.exe\" ", | |
| 35 L"LINK.EXE\" ", | |
| 36 L"link.EXE\" ", | |
| 37 L"link\" ", | |
| 38 L"LINK\" ", | |
| 39 L"link.exe ", | |
| 40 L"LINK.EXE ", | |
| 41 L"link.EXE ", | |
| 42 L"link ", | |
| 43 L"LINK ", | |
| 44 }; | |
| 45 | |
| 46 static void Fallback(const wchar_t* msg = 0) { | |
|
M-A Ruel
2011/09/28 00:33:27
NULL
scottmg
2011/09/28 15:59:42
Done.
| |
| 47 if (msg) { | |
| 48 wprintf(L"supalink failed (%s), trying to fallback to standard link.\n", | |
| 49 msg); | |
| 50 wprintf(L"Original command line: %s\n", GetCommandLine()); | |
| 51 fflush(stdout); | |
| 52 } | |
| 53 | |
| 54 STARTUPINFO startup_info = { sizeof(STARTUPINFO) }; | |
|
M-A Ruel
2011/09/28 00:33:27
then GetStartupInfo() to initialize it correctly.
scottmg
2011/09/28 15:59:42
Done. Why though? The 2 handles are initialized by
M-A Ruel
2011/09/28 18:17:14
So the child process is configured like if the par
scottmg
2011/09/28 21:47:56
Ah, got it, thank you. Done.
| |
| 55 PROCESS_INFORMATION process_info; | |
| 56 DWORD exit_code; | |
| 57 | |
| 58 wstring orig_cmd(GetCommandLine()); | |
|
M-A Ruel
2011/09/28 00:33:27
I feel like it's be much easier to search on the l
scottmg
2011/09/28 15:59:42
Yes, maybe. I would prefer not to rewrite it unles
M-A Ruel
2011/09/28 18:17:14
Link.exe, yes.
scottmg
2011/09/28 21:47:56
true, Done.
| |
| 59 wstring cmd; | |
| 60 wstring replace_with = L"link.exe.supalink_orig.exe"; | |
| 61 for (size_t i = 0; i < sizeof(g_search_for) / sizeof(g_search_for[0]); ++i) { | |
| 62 wstring linkexe = g_search_for[i]; | |
| 63 wstring::size_type at = orig_cmd.find(linkexe, 0); | |
| 64 if (at == wstring::npos) | |
| 65 continue; | |
| 66 if (linkexe[linkexe.size() - 2] == L'"') | |
| 67 replace_with += L"\" "; | |
| 68 else | |
| 69 replace_with += L" "; | |
| 70 cmd = orig_cmd.replace(at, linkexe.size(), replace_with); | |
| 71 break; | |
| 72 } | |
| 73 if (cmd == L"") { | |
| 74 wprintf(L"Original run '%s'\n", orig_cmd.c_str()); | |
| 75 Fatal(L"Couldn't find link.exe (or similar) in command line"); | |
| 76 } | |
| 77 | |
| 78 if (getenv("SUPALINK_DEBUG")) { | |
| 79 wprintf(L" running '%s'\n", cmd.c_str()); | |
| 80 fflush(stdout); | |
| 81 } | |
| 82 if (!CreateProcess(NULL, | |
| 83 reinterpret_cast<LPWSTR>(const_cast<wchar_t *>( | |
| 84 cmd.c_str())), | |
| 85 NULL, | |
| 86 NULL, | |
| 87 TRUE, | |
| 88 0, | |
| 89 NULL, | |
| 90 NULL, | |
| 91 &startup_info, &process_info)) { | |
| 92 wstring error = ErrorMessageToString(GetLastError()); | |
| 93 Fatal(error.c_str()); | |
| 94 } | |
| 95 WaitForSingleObject(process_info.hProcess, INFINITE); | |
| 96 GetExitCodeProcess(process_info.hProcess, &exit_code); | |
| 97 CloseHandle(process_info.hProcess); | |
| 98 CloseHandle(process_info.hThread); | |
|
M-A Ruel
2011/09/28 00:33:27
you can close it before line 95
scottmg
2011/09/28 15:59:42
Done.
| |
| 99 exit(exit_code); | |
| 100 } | |
| 101 | |
| 102 wstring SlurpFile(const wchar_t* path) { | |
| 103 FILE* f = _wfopen(path, L"rb, ccs=UNICODE"); | |
| 104 if (!f) Fallback(L"couldn't read file"); | |
| 105 fseek(f, 0, SEEK_END); | |
| 106 long len = ftell(f); | |
| 107 rewind(f); | |
| 108 wchar_t* data = reinterpret_cast<wchar_t*>(malloc(len)); | |
| 109 fread(data, 1, len, f); | |
| 110 fclose(f); | |
| 111 wstring ret(data, len/sizeof(wchar_t)); | |
| 112 free(data); | |
| 113 return ret; | |
| 114 } | |
| 115 | |
| 116 void DumpFile(const wchar_t* path, wstring& contents) { | |
| 117 FILE* f = _wfopen(path, L"wb, ccs=UTF-16LE"); | |
| 118 if (!f) Fallback(L"couldn't write file"); | |
| 119 | |
| 120 fwrite(contents.c_str(), sizeof(wchar_t), contents.size(), f); | |
| 121 if (ferror(f)) | |
| 122 Fatal(L"failed during response rewrite"); | |
| 123 fclose(f); | |
| 124 } | |
| 125 | |
| 126 // Input command line is assumed to be of the form: | |
| 127 // | |
| 128 // link.exe @C:\src\...\RSP00003045884740.rsp /NOLOGO /ERRORREPORT:PROMPT | |
| 129 // | |
| 130 // Specifically, we parse & hack the contents of argv[1] and pass the rest | |
| 131 // onwards. | |
| 132 int main(int argc, wchar_t** argv) { | |
| 133 ULONGLONG start_time = 0, end_time; | |
| 134 | |
| 135 int rsp_file_index = -1; | |
| 136 | |
| 137 if (argc < 2) | |
| 138 Fallback(L"too few commmand line args"); | |
| 139 | |
| 140 for (int i = 1; i < argc; ++i) { | |
| 141 if (argv[i][0] == '@') { | |
| 142 rsp_file_index = i; | |
| 143 break; | |
| 144 } | |
| 145 } | |
| 146 | |
| 147 if (rsp_file_index == -1) | |
| 148 Fallback(L"couldn't find a response file in argv"); | |
| 149 | |
| 150 if (getenv("SUPALINK_DEBUG")) | |
| 151 start_time = GetTickCount64(); | |
| 152 | |
| 153 wstring rsp = SlurpFile(&argv[rsp_file_index][1]); | |
| 154 | |
| 155 // The first line of this file is all we try to fix. It's a bunch of | |
| 156 // quoted space separated items. Simplest thing seems to be replacing " " | |
| 157 // with "\n". So, just slurp the file, replace, spit it out to the same | |
| 158 // file and continue on our way. | |
| 159 | |
| 160 // Took about .5s when using the naive .replace loop to replace " " with | |
| 161 // "\r\n" so write the silly loop instead. | |
| 162 wstring fixed; | |
| 163 fixed.reserve(rsp.size() * 2); | |
| 164 | |
| 165 for (const wchar_t* s = rsp.c_str(); *s;) { | |
| 166 if (*s == '"' && *(s + 1) == ' ' && *(s + 2) == '"') { | |
| 167 fixed += L"\"\r\n\""; | |
| 168 s += 3; | |
| 169 } else { | |
| 170 fixed += *s++; | |
| 171 } | |
| 172 } | |
| 173 | |
| 174 DumpFile(&argv[rsp_file_index][1], fixed); | |
| 175 | |
| 176 if (getenv("SUPALINK_DEBUG")) { | |
| 177 wstring backup_copy(&argv[rsp_file_index][1]); | |
| 178 backup_copy += L".copy"; | |
| 179 DumpFile(backup_copy.c_str(), fixed); | |
| 180 | |
| 181 end_time = GetTickCount64(); | |
| 182 | |
| 183 wprintf(L" took %.2fs to modify @rsp file\n", | |
| 184 (end_time - start_time) / 1000.0); | |
| 185 } | |
| 186 | |
| 187 Fallback(); | |
| 188 } | |
| OLD | NEW |