|
2 | 2 |
|
3 | 3 | #include "../../git-compat-util.h" |
4 | 4 | #include "../../environment.h" |
5 | | -#include "../../wrapper.h" |
6 | | -#include "../../strbuf.h" |
7 | | -#include "../../versioncmp.h" |
8 | 5 |
|
9 | 6 | int win32_has_dos_drive_prefix(const char *path) |
10 | 7 | { |
@@ -92,199 +89,3 @@ int win32_fspathcmp(const char *a, const char *b) |
92 | 89 | { |
93 | 90 | return win32_fspathncmp(a, b, (size_t)-1); |
94 | 91 | } |
95 | | - |
96 | | -static int read_at(int fd, char *buffer, size_t offset, size_t size) |
97 | | -{ |
98 | | - if (lseek(fd, offset, SEEK_SET) < 0) { |
99 | | - fprintf(stderr, "could not seek to 0x%x\n", (unsigned int)offset); |
100 | | - return -1; |
101 | | - } |
102 | | - |
103 | | - return read_in_full(fd, buffer, size); |
104 | | -} |
105 | | - |
106 | | -static size_t le16(const char *buffer) |
107 | | -{ |
108 | | - unsigned char *u = (unsigned char *)buffer; |
109 | | - return u[0] | (u[1] << 8); |
110 | | -} |
111 | | - |
112 | | -static size_t le32(const char *buffer) |
113 | | -{ |
114 | | - return le16(buffer) | (le16(buffer + 2) << 16); |
115 | | -} |
116 | | - |
117 | | -/* |
118 | | - * Determine the Go version of a given executable, if it was built with Go. |
119 | | - * |
120 | | - * This recapitulates the logic from |
121 | | - * https://github.com/golang/go/blob/master/src/cmd/go/internal/version/version.go |
122 | | - * (without requiring the user to install `go.exe` to find out). |
123 | | - */ |
124 | | -static ssize_t get_go_version(const char *path, char *go_version, size_t go_version_size) |
125 | | -{ |
126 | | - int fd = open(path, O_RDONLY); |
127 | | - char buffer[1024]; |
128 | | - off_t offset; |
129 | | - size_t num_sections, opt_header_size, i; |
130 | | - char *p = NULL, *q; |
131 | | - ssize_t res = -1; |
132 | | - |
133 | | - if (fd < 0) |
134 | | - return -1; |
135 | | - |
136 | | - if (read_in_full(fd, buffer, 2) < 0) |
137 | | - goto fail; |
138 | | - |
139 | | - /* |
140 | | - * Parse the PE file format, for more details, see |
141 | | - * https://en.wikipedia.org/wiki/Portable_Executable#Layout and |
142 | | - * https://learn.microsoft.com/en-us/windows/win32/debug/pe-format |
143 | | - */ |
144 | | - if (buffer[0] != 'M' || buffer[1] != 'Z') |
145 | | - goto fail; |
146 | | - |
147 | | - if (read_at(fd, buffer, 0x3c, 4) < 0) |
148 | | - goto fail; |
149 | | - |
150 | | - /* Read the `PE\0\0` signature and the COFF file header */ |
151 | | - offset = le32(buffer); |
152 | | - if (read_at(fd, buffer, offset, 24) < 0) |
153 | | - goto fail; |
154 | | - |
155 | | - if (buffer[0] != 'P' || buffer[1] != 'E' || buffer[2] != '\0' || buffer[3] != '\0') |
156 | | - goto fail; |
157 | | - |
158 | | - num_sections = le16(buffer + 6); |
159 | | - opt_header_size = le16(buffer + 20); |
160 | | - offset += 24; /* skip file header */ |
161 | | - |
162 | | - /* |
163 | | - * Validate magic number 0x10b or 0x20b, for full details see |
164 | | - * https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#optional-header-standard-fields-image-only |
165 | | - */ |
166 | | - if (read_at(fd, buffer, offset, 2) < 0 || |
167 | | - ((i = le16(buffer)) != 0x10b && i != 0x20b)) |
168 | | - goto fail; |
169 | | - |
170 | | - offset += opt_header_size; |
171 | | - |
172 | | - for (i = 0; i < num_sections; i++) { |
173 | | - if (read_at(fd, buffer, offset + i * 40, 40) < 0) |
174 | | - goto fail; |
175 | | - |
176 | | - /* |
177 | | - * For full details about the section headers, see |
178 | | - * https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#section-table-section-headers |
179 | | - */ |
180 | | - if ((le32(buffer + 36) /* characteristics */ & ~0x600000) /* IMAGE_SCN_ALIGN_32BYTES */ == |
181 | | - (/* IMAGE_SCN_CNT_INITIALIZED_DATA */ 0x00000040 | |
182 | | - /* IMAGE_SCN_MEM_READ */ 0x40000000 | |
183 | | - /* IMAGE_SCN_MEM_WRITE */ 0x80000000)) { |
184 | | - size_t size = le32(buffer + 16); /* "SizeOfRawData " */ |
185 | | - size_t pointer = le32(buffer + 20); /* "PointerToRawData " */ |
186 | | - |
187 | | - /* |
188 | | - * Skip the section if either size or pointer is 0, see |
189 | | - * https://github.com/golang/go/blob/go1.21.0/src/debug/buildinfo/buildinfo.go#L333 |
190 | | - * for full details. |
191 | | - * |
192 | | - * Merely seeing a non-zero size will not actually do, |
193 | | - * though: he size must be at least `buildInfoSize`, |
194 | | - * i.e. 32, and we expect a UVarint (at least another |
195 | | - * byte) _and_ the bytes representing the string, |
196 | | - * which we expect to start with the letters "go" and |
197 | | - * continue with the Go version number. |
198 | | - */ |
199 | | - if (size < 32 + 1 + 2 + 1 || !pointer) |
200 | | - continue; |
201 | | - |
202 | | - p = malloc(size); |
203 | | - |
204 | | - if (!p || read_at(fd, p, pointer, size) < 0) |
205 | | - goto fail; |
206 | | - |
207 | | - /* |
208 | | - * Look for the build information embedded by Go, see |
209 | | - * https://github.com/golang/go/blob/go1.21.0/src/debug/buildinfo/buildinfo.go#L165-L175 |
210 | | - * for full details. |
211 | | - * |
212 | | - * Note: Go contains code to enforce alignment along a |
213 | | - * 16-byte boundary. In practice, no `.exe` has been |
214 | | - * observed that required any adjustment, therefore |
215 | | - * this here code skips that logic for simplicity. |
216 | | - */ |
217 | | - q = memmem(p, size - 18, "\xff Go buildinf:", 14); |
218 | | - if (!q) |
219 | | - goto fail; |
220 | | - /* |
221 | | - * Decode the build blob. For full details, see |
222 | | - * https://github.com/golang/go/blob/go1.21.0/src/debug/buildinfo/buildinfo.go#L177-L191 |
223 | | - * |
224 | | - * Note: The `endianness` values observed in practice |
225 | | - * were always 2, therefore the complex logic to handle |
226 | | - * any other value is skipped for simplicty. |
227 | | - */ |
228 | | - if ((q[14] == 8 || q[14] == 4) && q[15] == 2) { |
229 | | - /* |
230 | | - * Only handle a Go version string with fewer |
231 | | - * than 128 characters, so the Go UVarint at |
232 | | - * q[32] that indicates the string's length must |
233 | | - * be only one byte (without the high bit set). |
234 | | - */ |
235 | | - if ((q[32] & 0x80) || |
236 | | - !q[32] || |
237 | | - (q + 33 + q[32] - p) > (ssize_t)size || |
238 | | - q[32] + 1 > (ssize_t)go_version_size) |
239 | | - goto fail; |
240 | | - res = q[32]; |
241 | | - memcpy(go_version, q + 33, res); |
242 | | - go_version[res] = '\0'; |
243 | | - break; |
244 | | - } |
245 | | - } |
246 | | - } |
247 | | - |
248 | | -fail: |
249 | | - free(p); |
250 | | - close(fd); |
251 | | - return res; |
252 | | -} |
253 | | - |
254 | | -void win32_warn_about_git_lfs_on_windows7(int exit_code, const char *argv0) |
255 | | -{ |
256 | | - char buffer[128], *git_lfs = NULL; |
257 | | - const char *p; |
258 | | - |
259 | | - /* |
260 | | - * Git LFS v3.5.1 fails with an Access Violation on Windows 7; That |
261 | | - * would usually show up as an exit code 0xc0000005. For some reason |
262 | | - * (probably because at this point, we no longer have the _original_ |
263 | | - * HANDLE that was returned by `CreateProcess()`) we observe other |
264 | | - * values like 0xb00 and 0x2 instead. Since the exact exit code |
265 | | - * seems to be inconsistent, we check for a non-zero exit status. |
266 | | - */ |
267 | | - if (exit_code == 0) |
268 | | - return; |
269 | | - if (GetVersion() >> 16 > 7601) |
270 | | - return; /* Warn only on Windows 7 or older */ |
271 | | - if (!istarts_with(argv0, "git-lfs ") && |
272 | | - strcasecmp(argv0, "git-lfs")) |
273 | | - return; |
274 | | - if (!(git_lfs = locate_in_PATH("git-lfs"))) |
275 | | - return; |
276 | | - if (get_go_version(git_lfs, buffer, sizeof(buffer)) > 0 && |
277 | | - skip_prefix(buffer, "go", &p) && |
278 | | - versioncmp("1.21.0", p) <= 0) |
279 | | - warning("This program was built with Go v%s\n" |
280 | | - "i.e. without support for this Windows version:\n" |
281 | | - "\n\t%s\n" |
282 | | - "\n" |
283 | | - "To work around this, you can download and install a " |
284 | | - "working version from\n" |
285 | | - "\n" |
286 | | - "\thttps://github.com/git-lfs/git-lfs/releases/tag/" |
287 | | - "v3.4.1\n", |
288 | | - p, git_lfs); |
289 | | - free(git_lfs); |
290 | | -} |
0 commit comments