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