xref: /PHP-7.4/win32/winutil.c (revision 8c6d006b)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) The PHP Group                                          |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Author: Zeev Suraski <zeev@php.net>                                  |
16    *         Pierre Joye <pierre@php.net>                                 |
17    +----------------------------------------------------------------------+
18  */
19 
20 #include "php.h"
21 #include "winutil.h"
22 #include "codepage.h"
23 #include <bcrypt.h>
24 #include <lmcons.h>
25 #include <imagehlp.h>
26 
27 
php_win32_error_to_msg(HRESULT error)28 PHP_WINUTIL_API char *php_win32_error_to_msg(HRESULT error)
29 {/*{{{*/
30 	wchar_t *bufw = NULL;
31 	char *buf;
32 
33 	DWORD ret = FormatMessageW(
34 		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
35 		NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),	(LPWSTR)&bufw, 0, NULL
36 	);
37 
38 	if (!ret || !bufw) {
39 		return "";
40 	}
41 
42 	buf = php_win32_cp_conv_w_to_any(bufw, ret, PHP_WIN32_CP_IGNORE_LEN_P);
43 
44 	LocalFree(bufw);
45 
46 	return (buf ? buf : "");
47 }/*}}}*/
48 
php_win32_error_msg_free(char * msg)49 PHP_WINUTIL_API void php_win32_error_msg_free(char *msg)
50 {/*{{{*/
51 	if (msg && msg[0]) {
52 		free(msg);
53 	}
54 }/*}}}*/
55 
php_win32_check_trailing_space(const char * path,const size_t path_len)56 int php_win32_check_trailing_space(const char * path, const size_t path_len)
57 {/*{{{*/
58 	if (path_len > MAXPATHLEN - 1) {
59 		return 1;
60 	}
61 	if (path) {
62 		if (path[0] == ' ' || path[path_len - 1] == ' ') {
63 			return 0;
64 		} else {
65 			return 1;
66 		}
67 	} else {
68 		return 0;
69 	}
70 }/*}}}*/
71 
72 static BCRYPT_ALG_HANDLE bcrypt_algo;
73 static BOOL has_bcrypt_algo = 0;
74 
75 #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
76 
77 #ifdef PHP_EXPORTS
php_win32_shutdown_random_bytes(void)78 BOOL php_win32_shutdown_random_bytes(void)
79 {/*{{{*/
80 	BOOL ret = TRUE;
81 
82 	if (has_bcrypt_algo) {
83 		ret = NT_SUCCESS(BCryptCloseAlgorithmProvider(bcrypt_algo, 0));
84 		has_bcrypt_algo = 0;
85 	}
86 
87 	return ret;
88 }/*}}}*/
89 
php_win32_init_random_bytes(void)90 BOOL php_win32_init_random_bytes(void)
91 {/*{{{*/
92 	if (has_bcrypt_algo) {
93 		return TRUE;
94 	}
95 
96 	has_bcrypt_algo = NT_SUCCESS(BCryptOpenAlgorithmProvider(&bcrypt_algo, BCRYPT_RNG_ALGORITHM, NULL, 0));
97 
98 	return has_bcrypt_algo;
99 }/*}}}*/
100 #endif
101 
php_win32_get_random_bytes(unsigned char * buf,size_t size)102 PHP_WINUTIL_API int php_win32_get_random_bytes(unsigned char *buf, size_t size)
103 {  /* {{{ */
104 
105 	BOOL ret;
106 
107 #if 0
108 	/* Currently we fail on startup, with CNG API it shows no regressions so far and is secure.
109 		Should switch on and try to reinit, if it fails too often on startup. This means also
110 		bringing locks back. */
111 	if (has_bcrypt_algo == 0) {
112 		return FAILURE;
113 	}
114 #endif
115 
116 	/* No sense to loop here, the limit is huge enough. */
117 	ret = NT_SUCCESS(BCryptGenRandom(bcrypt_algo, buf, (ULONG)size, 0));
118 
119 	return ret ? SUCCESS : FAILURE;
120 }
121 /* }}} */
122 
123 
124 /*
125 * This functions based on the code from the UNIXem project under
126 * the BSD like license. Modified for PHP by ab@php.net
127 *
128 * Home:    http://synesis.com.au/software/
129 *
130 * Copyright (c) 2005-2010, Matthew Wilson and Synesis Software
131 */
132 
php_win32_code_to_errno(unsigned long w32Err)133 PHP_WINUTIL_API int php_win32_code_to_errno(unsigned long w32Err)
134 {/*{{{*/
135     size_t  i;
136 
137     struct code_to_errno_map
138     {
139         unsigned long   w32Err;
140         int             eerrno;
141     };
142 
143     static const struct code_to_errno_map errmap[] =
144     {
145         /*   1 */       {   ERROR_INVALID_FUNCTION          ,   EINVAL          }
146         /*   2 */   ,   {   ERROR_FILE_NOT_FOUND            ,   ENOENT          }
147         /*   3 */   ,   {   ERROR_PATH_NOT_FOUND            ,   ENOENT          }
148         /*   4 */   ,   {   ERROR_TOO_MANY_OPEN_FILES       ,   EMFILE          }
149         /*   5 */   ,   {   ERROR_ACCESS_DENIED             ,   EACCES          }
150         /*   6 */   ,   {   ERROR_INVALID_HANDLE            ,   EBADF           }
151         /*   7 */   ,   {   ERROR_ARENA_TRASHED             ,   ENOMEM          }
152         /*   8 */   ,   {   ERROR_NOT_ENOUGH_MEMORY         ,   ENOMEM          }
153         /*   9 */   ,   {   ERROR_INVALID_BLOCK             ,   ENOMEM          }
154         /*  10 */   ,   {   ERROR_BAD_ENVIRONMENT           ,   E2BIG           }
155         /*  11 */   ,   {   ERROR_BAD_FORMAT                ,   ENOEXEC         }
156         /*  12 */   ,   {   ERROR_INVALID_ACCESS            ,   EINVAL          }
157         /*  13 */   ,   {   ERROR_INVALID_DATA              ,   EINVAL          }
158         /*  14 */   ,   {   ERROR_OUTOFMEMORY               ,   ENOMEM          }
159         /*  15 */   ,   {   ERROR_INVALID_DRIVE             ,   ENOENT          }
160         /*  16 */   ,   {   ERROR_CURRENT_DIRECTORY         ,   ECURDIR         }
161         /*  17 */   ,   {   ERROR_NOT_SAME_DEVICE           ,   EXDEV           }
162         /*  18 */   ,   {   ERROR_NO_MORE_FILES             ,   ENOENT          }
163         /*  19 */   ,   {   ERROR_WRITE_PROTECT             ,   EROFS           }
164         /*  20 */   ,   {   ERROR_BAD_UNIT                  ,   ENXIO           }
165         /*  21 */   ,   {   ERROR_NOT_READY                 ,   EBUSY           }
166         /*  22 */   ,   {   ERROR_BAD_COMMAND               ,   EIO             }
167         /*  23 */   ,   {   ERROR_CRC                       ,   EIO             }
168         /*  24 */   ,   {   ERROR_BAD_LENGTH                ,   EIO             }
169         /*  25 */   ,   {   ERROR_SEEK                      ,   EIO             }
170         /*  26 */   ,   {   ERROR_NOT_DOS_DISK              ,   EIO             }
171         /*  27 */   ,   {   ERROR_SECTOR_NOT_FOUND          ,   ENXIO           }
172         /*  28 */   ,   {   ERROR_OUT_OF_PAPER              ,   EBUSY           }
173         /*  29 */   ,   {   ERROR_WRITE_FAULT               ,   EIO             }
174         /*  30 */   ,   {   ERROR_READ_FAULT                ,   EIO             }
175         /*  31 */   ,   {   ERROR_GEN_FAILURE               ,   EIO             }
176         /*  32 */   ,   {   ERROR_SHARING_VIOLATION         ,   EAGAIN          }
177         /*  33 */   ,   {   ERROR_LOCK_VIOLATION            ,   EACCES          }
178         /*  34 */   ,   {   ERROR_WRONG_DISK                ,   ENXIO           }
179         /*  35 */   ,   {   35                              ,   ENFILE          }
180         /*  36 */   ,   {   ERROR_SHARING_BUFFER_EXCEEDED   ,   ENFILE          }
181         /*  37 */   ,   {   ERROR_HANDLE_EOF                ,   EINVAL          }
182         /*  38 */   ,   {   ERROR_HANDLE_DISK_FULL          ,   ENOSPC          }
183 #if 0
184         /*  39 */   ,   {   0                               ,   0               }
185         /*  40 */   ,   {   0                               ,   0               }
186         /*  41 */   ,   {   0                               ,   0               }
187         /*  42 */   ,   {   0                               ,   0               }
188         /*  43 */   ,   {   0                               ,   0               }
189         /*  44 */   ,   {   0                               ,   0               }
190         /*  45 */   ,   {   0                               ,   0               }
191         /*  46 */   ,   {   0                               ,   0               }
192         /*  47 */   ,   {   0                               ,   0               }
193         /*  48 */   ,   {   0                               ,   0               }
194         /*  49 */   ,   {   0                               ,   0               }
195 #endif
196         /*  50 */   ,   {   ERROR_NOT_SUPPORTED             ,   ENOSYS          }
197 #if 0
198         /*  51 */   ,   {   0                               ,   0               }
199         /*  52 */   ,   {   0                               ,   0               }
200 #endif
201         /*  53 */   ,   {   ERROR_BAD_NETPATH               ,   ENOENT          }
202 #if 0
203         /*  54 */   ,   {   0                               ,   0               }
204         /*  55 */   ,   {   0                               ,   0               }
205         /*  56 */   ,   {   0                               ,   0               }
206         /*  57 */   ,   {   0                               ,   0               }
207         /*  58 */   ,   {   0                               ,   0               }
208         /*  59 */   ,   {   0                               ,   0               }
209         /*  60 */   ,   {   0                               ,   0               }
210         /*  61 */   ,   {   0                               ,   0               }
211         /*  62 */   ,   {   0                               ,   0               }
212         /*  63 */   ,   {   0                               ,   0               }
213         /*  64 */   ,   {   0                               ,   0               }
214 #endif
215         /*  65 */   ,   {   ERROR_NETWORK_ACCESS_DENIED     ,   EACCES          }
216 #if 0
217         /*  66 */   ,   {   0                               ,   0               }
218 #endif
219         /*  67 */   ,   {   ERROR_BAD_NET_NAME              ,   ENOENT          }
220 #if 0
221         /*  68 */   ,   {   0                               ,   0               }
222         /*  69 */   ,   {   0                               ,   0               }
223         /*  70 */   ,   {   0                               ,   0               }
224         /*  71 */   ,   {   0                               ,   0               }
225         /*  72 */   ,   {   0                               ,   0               }
226         /*  73 */   ,   {   0                               ,   0               }
227         /*  74 */   ,   {   0                               ,   0               }
228         /*  75 */   ,   {   0                               ,   0               }
229         /*  76 */   ,   {   0                               ,   0               }
230         /*  77 */   ,   {   0                               ,   0               }
231         /*  78 */   ,   {   0                               ,   0               }
232         /*  79 */   ,   {   0                               ,   0               }
233 #endif
234         /*  80 */   ,   {   ERROR_FILE_EXISTS               ,   EEXIST          }
235 #if 0
236         /*  81 */   ,   {   0                               ,   0               }
237 #endif
238         /*  82 */   ,   {   ERROR_CANNOT_MAKE               ,   EACCES          }
239         /*  83 */   ,   {   ERROR_FAIL_I24                  ,   EACCES          }
240 #if 0
241         /*  84 */   ,   {   0                               ,   0               }
242         /*  85 */   ,   {   0                               ,   0               }
243         /*  86 */   ,   {   0                               ,   0               }
244 #endif
245         /*  87 */   ,   {   ERROR_INVALID_PARAMETER         ,   EINVAL          }
246 #if 0
247         /*  88 */   ,   {   0                               ,   0               }
248 #endif
249         /*  89 */   ,   {   ERROR_NO_PROC_SLOTS             ,   EAGAIN          }
250 #if 0
251         /*  90 */   ,   {   0                               ,   0               }
252         /*  91 */   ,   {   0                               ,   0               }
253         /*  92 */   ,   {   0                               ,   0               }
254         /*  93 */   ,   {   0                               ,   0               }
255         /*  94 */   ,   {   0                               ,   0               }
256         /*  95 */   ,   {   0                               ,   0               }
257         /*  96 */   ,   {   0                               ,   0               }
258         /*  97 */   ,   {   0                               ,   0               }
259         /*  98 */   ,   {   0                               ,   0               }
260         /*  99 */   ,   {   0                               ,   0               }
261         /* 100 */   ,   {   0                               ,   0               }
262         /* 101 */   ,   {   0                               ,   0               }
263         /* 102 */   ,   {   0                               ,   0               }
264         /* 103 */   ,   {   0                               ,   0               }
265         /* 104 */   ,   {   0                               ,   0               }
266         /* 105 */   ,   {   0                               ,   0               }
267         /* 106 */   ,   {   0                               ,   0               }
268         /* 107 */   ,   {   0                               ,   0               }
269 #endif
270         /* 108 */   ,   {   ERROR_DRIVE_LOCKED              ,   EACCES          }
271         /* 109 */   ,   {   ERROR_BROKEN_PIPE               ,   EPIPE           }
272 #if 0
273         /* 110 */   ,   {   0                               ,   0               }
274 #endif
275         /* 111 */   ,   {   ERROR_BUFFER_OVERFLOW           ,   ENAMETOOLONG    }
276         /* 112 */   ,   {   ERROR_DISK_FULL                 ,   ENOSPC          }
277 #if 0
278         /* 113 */   ,   {   0                               ,   0               }
279 #endif
280         /* 114 */   ,   {   ERROR_INVALID_TARGET_HANDLE     ,   EBADF           }
281 #if 0
282         /* 115 */   ,   {   0                               ,   0               }
283         /* 116 */   ,   {   0                               ,   0               }
284         /* 117 */   ,   {   0                               ,   0               }
285         /* 118 */   ,   {   0                               ,   0               }
286         /* 119 */   ,   {   0                               ,   0               }
287         /* 120 */   ,   {   0                               ,   0               }
288         /* 121 */   ,   {   0                               ,   0               }
289 #endif
290         /* 122 */   ,   {   ERROR_INSUFFICIENT_BUFFER       ,   ERANGE          }
291         /* 123 */   ,   {   ERROR_INVALID_NAME              ,   ENOENT          }
292         /* 124 */   ,   {   ERROR_INVALID_HANDLE            ,   EINVAL          }
293 #if 0
294         /* 125 */   ,   {   0                               ,   0               }
295 #endif
296         /* 126 */   ,   {   ERROR_MOD_NOT_FOUND             ,   ENOENT          }
297         /* 127 */   ,   {   ERROR_PROC_NOT_FOUND            ,   ENOENT          }
298         /* 128 */   ,   {   ERROR_WAIT_NO_CHILDREN          ,   ECHILD          }
299         /* 129 */   ,   {   ERROR_CHILD_NOT_COMPLETE        ,   ECHILD          }
300         /* 130 */   ,   {   ERROR_DIRECT_ACCESS_HANDLE      ,   EBADF           }
301         /* 131 */   ,   {   ERROR_NEGATIVE_SEEK             ,   EINVAL          }
302         /* 132 */   ,   {   ERROR_SEEK_ON_DEVICE            ,   EACCES          }
303 #if 0
304         /* 133 */   ,   {   0                               ,   0               }
305         /* 134 */   ,   {   0                               ,   0               }
306         /* 135 */   ,   {   0                               ,   0               }
307         /* 136 */   ,   {   0                               ,   0               }
308         /* 137 */   ,   {   0                               ,   0               }
309         /* 138 */   ,   {   0                               ,   0               }
310         /* 139 */   ,   {   0                               ,   0               }
311         /* 140 */   ,   {   0                               ,   0               }
312         /* 141 */   ,   {   0                               ,   0               }
313         /* 142 */   ,   {   0                               ,   0               }
314         /* 143 */   ,   {   0                               ,   0               }
315         /* 144 */   ,   {   0                               ,   0               }
316 #endif
317         /* 145 */   ,   {   ERROR_DIR_NOT_EMPTY             ,   ENOTEMPTY       }
318 #if 0
319         /* 146 */   ,   {   0                               ,   0               }
320         /* 147 */   ,   {   0                               ,   0               }
321         /* 148 */   ,   {   0                               ,   0               }
322         /* 149 */   ,   {   0                               ,   0               }
323         /* 150 */   ,   {   0                               ,   0               }
324         /* 151 */   ,   {   0                               ,   0               }
325         /* 152 */   ,   {   0                               ,   0               }
326         /* 153 */   ,   {   0                               ,   0               }
327         /* 154 */   ,   {   0                               ,   0               }
328         /* 155 */   ,   {   0                               ,   0               }
329         /* 156 */   ,   {   0                               ,   0               }
330         /* 157 */   ,   {   0                               ,   0               }
331 #endif
332         /* 158 */   ,   {   ERROR_NOT_LOCKED                ,   EACCES          }
333 #if 0
334         /* 159 */   ,   {   0                               ,   0               }
335         /* 160 */   ,   {   0                               ,   0               }
336 #endif
337         /* 161 */   ,   {   ERROR_BAD_PATHNAME              ,   ENOENT          }
338 #if 0
339         /* 162 */   ,   {   0                               ,   0               }
340         /* 163 */   ,   {   0                               ,   0               }
341 #endif
342         /* 164 */   ,   {   ERROR_MAX_THRDS_REACHED         ,   EAGAIN          }
343 #if 0
344         /* 165 */   ,   {   0                               ,   0               }
345         /* 166 */   ,   {   0                               ,   0               }
346 #endif
347         /* 167 */   ,   {   ERROR_LOCK_FAILED               ,   EACCES          }
348 #if 0
349         /* 168 */   ,   {   0                               ,   0               }
350         /* 169 */   ,   {   0                               ,   0               }
351         /* 170 */   ,   {   0                               ,   0               }
352         /* 171 */   ,   {   0                               ,   0               }
353         /* 172 */   ,   {   0                               ,   0               }
354         /* 173 */   ,   {   0                               ,   0               }
355         /* 174 */   ,   {   0                               ,   0               }
356         /* 175 */   ,   {   0                               ,   0               }
357         /* 176 */   ,   {   0                               ,   0               }
358         /* 177 */   ,   {   0                               ,   0               }
359         /* 178 */   ,   {   0                               ,   0               }
360         /* 179 */   ,   {   0                               ,   0               }
361         /* 180 */   ,   {   0                               ,   0               }
362         /* 181 */   ,   {   0                               ,   0               }
363         /* 182 */   ,   {   0                               ,   0               }
364 #endif
365         /* 183 */   ,   {   ERROR_ALREADY_EXISTS            ,   EEXIST          }
366 #if 0
367         /* 184 */   ,   {   0                               ,   0               }
368         /* 185 */   ,   {   0                               ,   0               }
369         /* 186 */   ,   {   0                               ,   0               }
370         /* 187 */   ,   {   0                               ,   0               }
371         /* 188 */   ,   {   0                               ,   0               }
372         /* 189 */   ,   {   0                               ,   0               }
373         /* 190 */   ,   {   0                               ,   0               }
374         /* 191 */   ,   {   0                               ,   0               }
375         /* 192 */   ,   {   0                               ,   0               }
376         /* 193 */   ,   {   0                               ,   0               }
377         /* 194 */   ,   {   0                               ,   0               }
378         /* 195 */   ,   {   0                               ,   0               }
379         /* 196 */   ,   {   0                               ,   0               }
380         /* 197 */   ,   {   0                               ,   0               }
381         /* 198 */   ,   {   0                               ,   0               }
382         /* 199 */   ,   {   0                               ,   0               }
383 #endif
384 
385         /* 206 */   ,   {   ERROR_FILENAME_EXCED_RANGE      ,   ENAMETOOLONG    }
386 
387         /* 215 */   ,   {   ERROR_NESTING_NOT_ALLOWED       ,   EAGAIN          }
388 		/* 258 */   ,   { WAIT_TIMEOUT, ETIME}
389 
390         /* 267 */   ,   {   ERROR_DIRECTORY                 ,   ENOTDIR         }
391 		/* 336 */   ,   {   ERROR_DIRECTORY_NOT_SUPPORTED   ,   EISDIR          }
392 
393         /* 996 */   ,   {   ERROR_IO_INCOMPLETE             ,   EAGAIN          }
394         /* 997 */   ,   {   ERROR_IO_PENDING                ,   EAGAIN          }
395 
396         /* 1004 */   ,  {   ERROR_INVALID_FLAGS             ,   EINVAL          }
397         /* 1113 */   ,  {   ERROR_NO_UNICODE_TRANSLATION    ,   EINVAL          }
398         /* 1168 */   ,  {   ERROR_NOT_FOUND                 ,   ENOENT          }
399         /* 1224 */   ,  {   ERROR_USER_MAPPED_FILE          ,   EACCES          }
400         /* 1314 */   ,  {   ERROR_PRIVILEGE_NOT_HELD        ,   EACCES          }
401         /* 1816 */  ,   {   ERROR_NOT_ENOUGH_QUOTA          ,   ENOMEM          }
402 					,   {   ERROR_ABANDONED_WAIT_0          ,   EIO }
403 		/* 1464 */	,	{	ERROR_SYMLINK_NOT_SUPPORTED		,	EINVAL			}
404 		/* 4390 */	,	{	ERROR_NOT_A_REPARSE_POINT		,	EINVAL			}
405     };
406 
407     for(i = 0; i < sizeof(errmap)/sizeof(struct code_to_errno_map); ++i)
408     {
409         if(w32Err == errmap[i].w32Err)
410         {
411             return errmap[i].eerrno;
412         }
413     }
414 
415     assert(!"Unrecognised value");
416 
417     return EINVAL;
418 }/*}}}*/
419 
php_win32_get_username(void)420 PHP_WINUTIL_API char *php_win32_get_username(void)
421 {/*{{{*/
422 	wchar_t unamew[UNLEN + 1];
423 	size_t uname_len;
424 	char *uname;
425 	DWORD unsize = UNLEN;
426 
427 	GetUserNameW(unamew, &unsize);
428 	uname = php_win32_cp_conv_w_to_any(unamew, unsize - 1, &uname_len);
429 	if (!uname) {
430 		return NULL;
431 	}
432 
433 	/* Ensure the length doesn't overflow. */
434 	if (uname_len > UNLEN) {
435 		uname[uname_len] = '\0';
436 	}
437 
438 	return uname;
439 }/*}}}*/
440 
is_compatible(const char * name,BOOL is_smaller,char * format,char ** err)441 static zend_always_inline BOOL is_compatible(const char *name, BOOL is_smaller, char *format, char **err)
442 {/*{{{*/
443 	/* work around ImageLoad() issue */
444 	char *name_stripped = name;
445 	if (name[0] == '.' && IS_SLASH(name[1])) {
446 		name_stripped += 2;
447 	}
448 
449 	PLOADED_IMAGE img = ImageLoad(name_stripped, NULL);
450 
451 	if (!img) {
452 		DWORD _err = GetLastError();
453 		char *err_txt = php_win32_error_to_msg(_err);
454 		spprintf(err, 0, "Failed to load %s, %s", name, err_txt);
455 		free(err_txt);
456 		return FALSE;
457 	}
458 
459 	DWORD major = img->FileHeader->OptionalHeader.MajorLinkerVersion;
460 	DWORD minor = img->FileHeader->OptionalHeader.MinorLinkerVersion;
461 
462 #if PHP_LINKER_MAJOR == 14
463 	/* VS 2015, 2017 and 2019 are binary compatible, but only forward compatible.
464 		It should be fine, if we load a module linked with an older one into
465 		the core linked with the newer one, but not the otherway round.
466 		Analogously, it should be fine, if a PHP build linked with an older version
467 		is used with a newer CRT, but not the other way round.
468 		Otherwise, if the linker major version is not same, it is an error, as
469 		per the current knowledge.
470 
471 		This check is to be extended as new VS versions come out. */
472 	DWORD core_minor = (DWORD)(PHP_LINKER_MINOR/10);
473 	DWORD comp_minor = (DWORD)(minor/10);
474 	if (14 == major && (is_smaller ? core_minor < comp_minor : core_minor > comp_minor) || PHP_LINKER_MAJOR != major)
475 #else
476 	if (PHP_LINKER_MAJOR != major)
477 #endif
478 	{
479 		spprintf(err, 0, format, name, major, minor, PHP_LINKER_MAJOR, PHP_LINKER_MINOR);
480 		ImageUnload(img);
481 		return FALSE;
482 	}
483 	ImageUnload(img);
484 
485 	return TRUE;
486 }/*}}}*/
487 
php_win32_image_compatible(const char * name,char ** err)488 PHP_WINUTIL_API BOOL php_win32_image_compatible(const char *name, char **err)
489 {/*{{{*/
490 	return is_compatible(name, TRUE, "Can't load module '%s' as it's linked with %u.%u, but the core is linked with %d.%d", err);
491 }/*}}}*/
492 
493 /* Expect a CRT name DLL. */
php_win32_crt_compatible(const char * name,char ** err)494 PHP_WINUTIL_API BOOL php_win32_crt_compatible(const char *name, char **err)
495 {/*{{{*/
496 	return is_compatible(name, FALSE, "'%s' %u.%u is not compatible with this PHP build linked with %d.%d", err);
497 }/*}}}*/
498 
499