Skip to content

Commit a23bace

Browse files
authored
Drop Windows 7 support (#6325)
Git for Windows dropped Windows 7 support a long time ago. There is a patch (introduced in #5042 and in #5059) to detect when Git LFS failed to start because of lack of Windows 7 support (which was lost somewhat surprisingly, via a Go upgrade that slipped that change in), and to provid a helpful message to the user in that instance. Since Git for Windows itself does not support Windows 7 anymore, that patch is no longer necessary, either.
2 parents 734639a + e9d0fac commit a23bace

4 files changed

Lines changed: 0 additions & 210 deletions

File tree

compat/win32/path-utils.c

Lines changed: 0 additions & 199 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22

33
#include "../../git-compat-util.h"
44
#include "../../environment.h"
5-
#include "../../wrapper.h"
6-
#include "../../strbuf.h"
7-
#include "../../versioncmp.h"
85

96
int win32_has_dos_drive_prefix(const char *path)
107
{
@@ -92,199 +89,3 @@ int win32_fspathcmp(const char *a, const char *b)
9289
{
9390
return win32_fspathncmp(a, b, (size_t)-1);
9491
}
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-
}

compat/win32/path-utils.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,4 @@ int win32_fspathcmp(const char *a, const char *b);
3434
int win32_fspathncmp(const char *a, const char *b, size_t count);
3535
#define fspathncmp win32_fspathncmp
3636

37-
void win32_warn_about_git_lfs_on_windows7(int exit_code, const char *argv0);
38-
#define warn_about_git_lfs_on_windows7 win32_warn_about_git_lfs_on_windows7
39-
4037
#endif

git-compat-util.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -263,13 +263,6 @@ static inline int git_offset_1st_component(const char *path)
263263
#define fspathncmp git_fspathncmp
264264
#endif
265265

266-
#ifndef warn_about_git_lfs_on_windows7
267-
static inline void warn_about_git_lfs_on_windows7(int exit_code UNUSED,
268-
const char *argv0 UNUSED)
269-
{
270-
}
271-
#endif
272-
273266
#ifndef is_valid_path
274267
#define is_valid_path(path) 1
275268
#endif

run-command.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,6 @@ static int wait_or_whine(pid_t pid, const char *argv0, int in_signal)
582582
*/
583583
code += 128;
584584
} else if (WIFEXITED(status)) {
585-
warn_about_git_lfs_on_windows7(status, argv0);
586585
code = WEXITSTATUS(status);
587586
} else {
588587
if (!in_signal)

0 commit comments

Comments
 (0)