blob: a8460a16bc8ec94a76b4ddf044326d0f17cd2ad9 [file] [log] [blame]
Lenny Komow10ec1212016-08-09 15:56:15 -06001/******************************************************************************
2 * Copyright (c) 2016 The Khronos Group
3 * Copyright (c) 2016 Valve Corporation
4 * Copyright (c) 2016 LunarG, Inc.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you man not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * https://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is destributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language govering permissions and
16 * limitations under the License.
17 *
18 * Author: Lenny Komow <lenny@lunarg.com>
19 *
20 *****************************************************************************/
21
22/*
23 * This program is used by the Vulkan Runtime Installer/Uninstaller to:
24 * - Copy the most recent vulkan<majorabi>-*.dll in C:\Windows\System32
25 * to vulkan<majorabi>.dll
26 * - Copy the most recent version of vulkaninfo-<abimajor>-*.exe in
27 * C:\Windows\System32 to vulkaninfo.exe
28 * - The same thing is done for those files in C:\Windows\SysWOW64, but
29 * only on a 64-bit target
30 * - Set the layer registry entried to point to the layer json files in
31 * the Vulkan SDK associated with the most recent vulkan*.dll
32 *
Lenny Komow769b9df2016-08-12 13:26:20 -060033 * The program must be called with the following parameters:
Lenny Komow10ec1212016-08-09 15:56:15 -060034 * --major-abi: A single number specifying the major abi version
Lenny Komow10ec1212016-08-09 15:56:15 -060035 */
36
37// Compile with: `cl.exe configure_runtime.c /link advapi32.lib`
38// Be sure to use the x86 version of cl.exe
39
40#include <stdbool.h>
41#include <stdint.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include <windows.h>
46
47// This hack gets Visual Studio 2013 to handle C99 stuff properly
48// If we drop support for 2013, it would be a good idea to remove this
49#if _MSC_VER < 1900
50#define inline __inline
51#define snprintf _snprintf
52#endif
53
Lenny Komow769b9df2016-08-12 13:26:20 -060054#if defined(_WIN64)
55#error "This program is designed only as a 32-bit program. It should not be built as 64-bit."
56#endif
57
Lenny Komow10ec1212016-08-09 15:56:15 -060058#define COPY_BUFFER_SIZE (1024)
59#define CHECK_ERROR(statement) { int error = (statement); if(error) return error; }
60#define CHECK_ERROR_HANDLED(statement, handler) { int error = (statement); if(error) { { handler } return error; } }
61#define SDK_VERSION_BUFFER_SIZE (64)
62
63enum Platform
64{
65 PLATFORM_X64,
66 PLATFORM_X86,
67};
68
69#pragma pack(1)
70struct SDKVersion
71{
72 long major;
73 long minor;
74 long patch;
75 long build;
76 char extended[SDK_VERSION_BUFFER_SIZE];
77};
78
79const char* FLAG_ABI_MAJOR = "--abi-major";
Lenny Komow10ec1212016-08-09 15:56:15 -060080const char* PATH_SYSTEM32 = "\\SYSTEM32\\";
81const char* PATH_SYSWOW64 = "\\SysWOW64\\";
82
83inline size_t max_s(size_t a, size_t b) { return a > b ? a : b; }
84inline size_t min_s(size_t a, size_t b) { return a > b ? a : b; }
85
86// Add the registry entries for all explicit layers
87//
88// log (input) - Logging file stream
89// install_path (input) - The installation path of the SDK which provides the layers
90// platform (input) - The platform to set the installation for (x64 or x86)
91// Returns: Zero on success, an error code on failure
92int add_explicit_layers(FILE* log, const char* install_path, enum Platform platform);
93
94// Compare two sdk versions
95//
96// Returns: Zero if they are equal, below zero if a predates b, greater than zero if b predates a
97int compare_versions(const struct SDKVersion* a, const struct SDKVersion* b);
98
Lenny Komow10ec1212016-08-09 15:56:15 -060099// Locate all of the SDK installations
100//
101// install_paths (output) - A poiner to an array of the installations paths
102// install_versions (output) - A pointer to an array of the SDK versions
103// count (output) - A pointer to the number of items in each array
104// Returns: Zero on success, an error code on failure
105//
106// Both install_paths and install_versions are allocated on the heap. To free them properly,
107// call free_installations(), even if this function returned an error code. The orders of
108// install_paths and install_versions match, so (*install_paths)[2] is guaranteed to match
109// (*install_versions)[2]
110int find_installations(char*** install_paths, struct SDKVersion** install_versions, size_t* count);
111
112// Free the memory allocated by find_installations()
113void free_installations(char** install_paths, struct SDKVersion* install_versions, size_t count);
114
115// Parse command line arguments for the program
116//
117// log (input) - Logging file stream
118// argc (input) - The argument count
119// argv (input) - An array of argument strings
120// abi_major (output) - The major abi version from the arguments
121// Returns: Zero on success, an error code on failure
122int parse_arguments(FILE* log, int argc, char** argv, long* abi_major);
123
124// Read the version from a string
125//
126// version_string (input) - A string in the format <abi>.<major>.<minor>.<patch>.<build>.<extended>
127// version (output) - The version indicated by the input string
128// Returns: Zero on success, an error code on failure
129int read_version(const char* version_string, struct SDKVersion* version);
130
131// Read the version from a filename
132//
133// filename (input) - The name of a .dll or .exe file, in the format
134// somename-<abi>-<major>-<minor>-<path>-<build>-<extended>.dll
135// version (output) - The versions indicated by the input string
136// Returns: Zero on success, an error code on failure
137int read_version_from_filename(const char* filename, struct SDKVersion* version);
138
139// Remove explicit layers from the Windows registry
140//
141// log (input) - Loggin file stream
142// install_paths (input) - An array of every vulkan installation path
143// count (input) - The number of vulkan installations
144// platform (input) - The platform (x64 or x86) of the registry to use (both exist on x64)
145// Returns: Zero on success, an error code on failure
146int remove_explicit_layers(FILE* log, const char** install_paths, size_t count, enum Platform platform);
147
148// Update all explicity layers in the windows registry
149//
150// log (input) - Logging file stream
151// platform (input) - The platform of the OS (both registries will be modified if this is x64)
152// version (input) - The version that should be set to current (if it exists)
153// Returns: Zero on success, an error code on failure
154int update_registry_layers(FILE* log, enum Platform platform, const struct SDKVersion* version);
155
156// Update a single vulkan system file (vulkan.dll or vulkaninfo.exe)
157//
158// log (input) - Loggin file stream
159// name (input) - The name (excuding file extension) of the file to be updated
160// extension (input) - The file extensions of the file to be updated
161// path (input) - The directory of the file (usually System32 or SysWOW64)
162// abi_major (input) - The ABI major version to be updated
Lenny Komow28e06f72016-08-17 14:50:13 -0600163// append_abi_major (input) - Whether or not the ABI number should be appended to the filename
Lenny Komow10ec1212016-08-09 15:56:15 -0600164// latest_version (output) - The version of the runtime which the file was updated to
165// Returns: Zero on success, an error code on failure
166int update_system_file(FILE* log, const char* name, const char* extension, const char* path,
Lenny Komow28e06f72016-08-17 14:50:13 -0600167 long abi_major, bool append_abi_major, struct SDKVersion* latest_version);
Lenny Komow10ec1212016-08-09 15:56:15 -0600168
169// Update vulkan.dll and vulkaninfo.exe in all of the windows directories (System32 and SysWOW64)
170//
171// log (input) - Loging file stream
172// abi_major (input) - The ABI major version of the files that should be used
173// platform (input) - The platform for the current OS
174// latest_runtime_version (output) - The version that the runtime files were updated to
175int update_windows_directories(FILE* log, long abi_major, enum Platform platform,
176 struct SDKVersion* latest_runtime_version);
177
178int main(int argc, char** argv)
179{
180 // Get the OS platform (x86 or x64)
181 BOOL is_64_bit;
182 IsWow64Process(GetCurrentProcess(), &is_64_bit);
183 enum Platform platform = is_64_bit ? PLATFORM_X64 : PLATFORM_X86;
184
185 FILE* log = fopen("configure_rt.log", "w");
186 if(log == NULL) {
187 return 10;
188 }
189
190 // Parse the arguments to get the abi version and the number of bits of the OS
191 long abi_major;
192 CHECK_ERROR_HANDLED(parse_arguments(log, argc, argv, &abi_major), { fclose(log); });
193
194 // This makes System32 and SysWOW64 not do any redirection (well, until 128-bit is a thing)
195 Wow64DisableWow64FsRedirection(NULL);
196
197 // Update System32 (on all systems) and SysWOW64 on 64-bit system
198 struct SDKVersion latest_runtime_version;
199 CHECK_ERROR_HANDLED(update_windows_directories(log, abi_major, platform, &latest_runtime_version),
200 { fclose(log); });
201
202 // Update the explicit layers that are set in the windows registry
203 CHECK_ERROR_HANDLED(update_registry_layers(log, platform, &latest_runtime_version), { fclose(log); });
204
205 fclose(log);
206 return 0;
207}
208
209int add_explicit_layers(FILE* log, const char* install_path, enum Platform platform)
210{
211 switch(platform)
212 {
213 case PLATFORM_X64:
214 fprintf(log, "Updating x64 explicit layers to path: %s\n", install_path);
215 break;
216 case PLATFORM_X86:
217 fprintf(log, "Updating x86 explicit layers to path: %s\n", install_path);
218 break;
219 }
220
Lenny Komow769b9df2016-08-12 13:26:20 -0600221 // If this is a 32 bit system, we allow redirection to point this at the 32-bit registries.
222 // If not, we add the flag KEY_WOW64_64KEY, to disable redirection for this node.
Lenny Komow10ec1212016-08-09 15:56:15 -0600223 HKEY hKey;
224 REGSAM flags = KEY_ALL_ACCESS;
225 if(platform == PLATFORM_X64) {
226 flags |= KEY_WOW64_64KEY;
227 }
Lenny Komow28e06f72016-08-17 14:50:13 -0600228
229 // Create (if needed) and open the explicit layer key
230 if(RegCreateKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Khronos\\Vulkan\\ExplicitLayers",
231 0, NULL, REG_OPTION_NON_VOLATILE, flags, NULL, &hKey, NULL) != ERROR_SUCCESS) {
Lenny Komow10ec1212016-08-09 15:56:15 -0600232 return 20;
233 }
234
235 const char* pattern = platform == PLATFORM_X64 ? "%s\\Bin\\VkLayer*.json" : "%s\\Bin32\\VkLayer*.json";
236 int filter_size = snprintf(NULL, 0, pattern, install_path) + 1;
237 if(filter_size < 0) {
238 return 30;
239 }
240 char* filter = malloc(filter_size);
241 snprintf(filter, filter_size, pattern, install_path);
242
243 WIN32_FIND_DATA find_data;
244 HANDLE find = FindFirstFile(filter, &find_data);
245 free(filter);
246 for(bool at_end = (find != INVALID_HANDLE_VALUE); at_end;
247 at_end = FindNextFile(find, &find_data)) {
248
249 const char* layer_pattern = platform == PLATFORM_X64 ? "%s\\Bin\\%s" : "%s\\Bin32\\%s";
250 int layer_size = snprintf(NULL, 0, layer_pattern, install_path, find_data.cFileName) + 1;
251 if(layer_size < 0) {
252 return 40;
253 }
254 char* layer = malloc(layer_size);
255 snprintf(layer, layer_size, layer_pattern, install_path, find_data.cFileName);
256
257 fprintf(log, "Adding explicit layer: %s\n", layer);
258
259 DWORD zero = 0;
260 LSTATUS err = RegSetValueEx(hKey, layer, zero, REG_DWORD, (BYTE*) &zero, sizeof(DWORD));
261 free(layer);
262 if(err != ERROR_SUCCESS) {
263 return 50;
264 }
265 }
266
267 RegCloseKey(hKey);
268 return 0;
269}
270
271int compare_versions(const struct SDKVersion* a, const struct SDKVersion* b)
272{
Lenny Komow21fe80e2016-09-02 14:05:45 -0600273 // Compare numerical versions
Lenny Komow10ec1212016-08-09 15:56:15 -0600274 for(int i = 0; i < 4; ++i) {
275 long* a_current = ((long*) a) + i;
276 long* b_current = ((long*) b) + i;
277
278 if(*a_current < *b_current) {
279 return -4 + i;
280 } else if(*b_current < *a_current) {
281 return 4 - i;
282 }
283 }
284
Lenny Komow21fe80e2016-09-02 14:05:45 -0600285 // An empty string should be considered greater (and therefore more recent) than one with test
286 if(a->extended[0] == '\0' && b->extended[0] != '\0') {
287 return 1;
288 } else if(b->extended[0] == '\0' && a->extended[0] != '\0') {
289 return -1;
290 }
291
292 // Otherwise, just do a strncmp
Lenny Komow10ec1212016-08-09 15:56:15 -0600293 return strncmp(a->extended, b->extended, SDK_VERSION_BUFFER_SIZE);
294}
295
Lenny Komow10ec1212016-08-09 15:56:15 -0600296int find_installations(char*** install_paths, struct SDKVersion** install_versions, size_t* count)
297{
298 *install_paths = malloc(sizeof(char*) * 64);
299 *install_versions = malloc(sizeof(struct SDKVersion) * 64);
300 *count = 0;
301
Lenny Komow769b9df2016-08-12 13:26:20 -0600302 // We want the 64-bit registries on 64-bit windows, and the 32-bit registries on 32-bit Windows.
303 // KEY_WOW64_64KEY accomplishes this because it gets ignored on 32-bit Windows.
Lenny Komow10ec1212016-08-09 15:56:15 -0600304 HKEY hKey;
305 if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall",
306 0, KEY_READ | KEY_WOW64_64KEY, &hKey) != ERROR_SUCCESS) {
307 return 90;
308 }
309
310 DWORD keyCount, keyLen;
311 RegQueryInfoKey(hKey, NULL, NULL, NULL, &keyCount, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
312 for(int i = 0; i < keyCount; ++i) {
313 TCHAR name[COPY_BUFFER_SIZE];
314 DWORD nameSize = COPY_BUFFER_SIZE;
315 RegEnumKeyEx(hKey, i, name, &nameSize, NULL, NULL, NULL, NULL);
316
317 if(strncmp("VulkanSDK", name, 9)) {
318 continue;
319 }
320
321 HKEY subKey;
322 if(RegOpenKeyEx(hKey, name, 0, KEY_READ | KEY_WOW64_64KEY, &subKey) != ERROR_SUCCESS) {
323 continue;
324 }
325
326 bool found_installation = false, found_version = false;
327 DWORD valueCount;
328 RegQueryInfoKey(subKey, NULL, NULL, NULL, NULL, NULL, NULL, &valueCount, NULL, NULL, NULL, NULL);
329 for(int j = 0; j < valueCount; ++j) {
330
331 TCHAR name[COPY_BUFFER_SIZE], value[COPY_BUFFER_SIZE];
332 DWORD type, buffSize = COPY_BUFFER_SIZE;
333 RegEnumValue(subKey, j, name, &buffSize, NULL, &type, value, &buffSize);
334 if(type == REG_SZ && !strcmp("InstallDir", name)) {
335 *install_paths = realloc(*install_paths, sizeof(char*) * ((*count) + 1));
336 (*install_paths)[*count] = malloc(sizeof(char) * COPY_BUFFER_SIZE);
337 strcpy((*install_paths)[*count], value);
338 found_installation = true;
339 } else if(type == REG_SZ && !strncmp("DisplayVersion", name, 8)) {
340 *install_versions = realloc(*install_versions, sizeof(struct SDKVersion) * ((*count) + 1));
341 CHECK_ERROR(read_version(value, (*install_versions) + *count));
342 found_version = true;
343 }
344
345 if(found_installation && found_version) {
346 ++(*count);
347 break;
348 }
349 }
350 RegCloseKey(subKey);
351
352 if(!(found_installation && found_version)) {
353 RegCloseKey(hKey);
354 return 100;
355 }
356 }
357 RegCloseKey(hKey);
358
359 return 0;
360}
361
362void free_installations(char** install_paths, struct SDKVersion* install_versions, size_t count)
363{
364 for(size_t i = 0; i < count; ++i) {
365 free(install_paths[i]);
366 }
367 free(install_paths);
368 free(install_versions);
369}
370
371int parse_arguments(FILE* log, int argc, char** argv, long* abi_major)
372{
373 *abi_major = 0;
374
375 // Parse arguments
376 for(int i = 0; i < argc; ++i) {
377 if(!strcmp(argv[i], FLAG_ABI_MAJOR)) {
378 if(i + 1 == argc) {
379 fprintf(log, "ERROR: No value given for flag %s.\n", FLAG_ABI_MAJOR);
380 return 110;
381 }
382 *abi_major = strtol(argv[++i], NULL, 10);
383 if(*abi_major == 0) {
384 fprintf(log, "ERROR: Unable to parse ABI major version as integer.\n");
385 return 120;
386 }
387 }
388 }
389
390 // Check that we have everything we need
391 if(*abi_major == 0 ) {
392 fprintf(log, "ERROR: Flag %s must be provided.\n", FLAG_ABI_MAJOR);
393 return 130;
394 }
395
396 // It all worked fine
397 fprintf(log, "Found ABI: %ld\n\n", *abi_major);
398 return 0;
399}
400
401int read_version(const char* version_string, struct SDKVersion* version)
402{
403 size_t borders[4], dot_count = 0, i;
404 for(i = 0; dot_count < 3 && version_string[i] != '\0'; ++i) {
405 if(version_string[i] == '.') {
406 borders[dot_count++] = i + 1;
407 }
408 }
409 borders[3] = i + 1;
410
411 if(dot_count < 3) {
412 return 140;
413 }
414
415 // Read the version number
416 version->major = strtol(version_string, NULL, 10);
417 version->minor = strtol(version_string + borders[0], NULL, 10);
418 version->patch = strtol(version_string + borders[1], NULL, 10);
419 version->build = strtol(version_string + borders[2], NULL, 10);
420
421 strncpy(version->extended, version_string + borders[3] + 1,
422 min_s(SDK_VERSION_BUFFER_SIZE - 1, strlen(version_string + borders[3] + 1)));
423
424 return 0;
425}
426
427int read_version_from_filename(const char* filename, struct SDKVersion* version)
428{
429 size_t borders[5], dash_count = 0;
430
431 // Locate all of the dashes that divides different version numbers
432 size_t i;
433 for(i = 0; dash_count < 5; ++i) {
434 if(filename[i] == '-' && dash_count == 0) {
435 ++dash_count;
436 } else if(filename[i] == '-') {
437 borders[dash_count++ - 1] = i + 1;
438 } else if(filename[i] == '\0') {
439 return 150;
440 }
441 }
442 borders[4] = i + 1;
443
444 // Read the version number
445 version->major = strtol(filename + borders[0], NULL, 10);
446 version->minor = strtol(filename + borders[1], NULL, 10);
447 version->patch = strtol(filename + borders[2], NULL, 10);
448 version->build = strtol(filename + borders[3], NULL, 10);
449
450 if(strcmp(filename + borders[4] + 1, "dll") && strcmp(filename + borders[4] + 1, "exe")) {
451 strncpy(version->extended, filename + borders[4] + 1, SDK_VERSION_BUFFER_SIZE - 1);
452 size_t file_len = strlen(filename + borders[4] + 1);
453 if(file_len - 4 < SDK_VERSION_BUFFER_SIZE) {
454 version->extended[file_len - 4] = '\0';
455 }
456 } else {
457 version->extended[0] = '\0';
458 }
459
460 for(size_t i = 0; version->extended[i] != '\0' && i < SDK_VERSION_BUFFER_SIZE; ++i) {
461 if(version->extended[i] == '-') {
462 version->extended[i] = '.';
463 }
464 }
465
466 return 0;
467}
468
469int remove_explicit_layers(FILE* log, const char** install_paths, size_t count, enum Platform platform)
470{
471 switch(platform)
472 {
473 case PLATFORM_X64:
474 fprintf(log, "Removing x64 explicit layers from registry\n");
475 break;
476 case PLATFORM_X86:
477 fprintf(log, "Removing x86 explicit layers from registry\n");
478 break;
479 }
480
481 bool removed_one;
482 do {
Lenny Komow769b9df2016-08-12 13:26:20 -0600483 // If this is a 32 bit system, we allow redirection to point this at the 32-bit registries.
484 // If not, we add the flag KEY_WOW64_64KEY, to disable redirection for this node.
Lenny Komow10ec1212016-08-09 15:56:15 -0600485 HKEY hKey;
486 REGSAM flags = KEY_ALL_ACCESS;
487 if(platform == PLATFORM_X64) {
488 flags |= KEY_WOW64_64KEY;
489 }
Lenny Komow28e06f72016-08-17 14:50:13 -0600490
491 // Create (if needed) and open the explicit layer key
492 if(RegCreateKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Khronos\\Vulkan\\ExplicitLayers",
493 0, NULL, REG_OPTION_NON_VOLATILE, flags, NULL, &hKey, NULL) != ERROR_SUCCESS) {
Lenny Komow10ec1212016-08-09 15:56:15 -0600494 return 160;
495 }
496
497 removed_one = false;
498 DWORD valueCount;
499 RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &valueCount, NULL, NULL, NULL, NULL);
500 for(DWORD i = 0; i < valueCount; ++i) {
501 TCHAR name[COPY_BUFFER_SIZE];
502 DWORD type, buffSize = COPY_BUFFER_SIZE;
503 RegEnumValue(hKey, i, name, &buffSize, NULL, &type, NULL, NULL);
504
505 for(size_t j = 0; j < count; ++j) {
506 if(strncmp(install_paths[j], name, strlen(install_paths[j])) == 0) {
507 fprintf(log, "Removing explicit layer entry: %s\n", name);
508 LSTATUS err = RegDeleteValue(hKey, name);
509 if(err != ERROR_SUCCESS) {
510 return 170;
511 }
512 removed_one = true;
513 break;
514 }
515 }
516 if(removed_one) {
517 break;
518 }
519 }
520
521 RegCloseKey(hKey);
522 } while(removed_one);
523
524 return 0;
525}
526
527int update_registry_layers(FILE* log, enum Platform platform, const struct SDKVersion* version)
528{
529 char** install_paths;
530 struct SDKVersion* install_versions;
531 size_t count;
532 CHECK_ERROR_HANDLED(find_installations(&install_paths, &install_versions, &count),
533 { free_installations(install_paths, install_versions, count); });
534 for(size_t i = 0; i < count; ++i) {
535 fprintf(log, "Found installation of %ld.%ld.%ld.%ld in: %s\n", install_versions[i].major,
536 install_versions[i].minor, install_versions[i].patch, install_versions[i].build, install_paths[i]);
537 }
538 fprintf(log, "\n");
539 if(platform == PLATFORM_X64) {
540 CHECK_ERROR_HANDLED(remove_explicit_layers(log, install_paths, count, PLATFORM_X64),
541 { free_installations(install_paths, install_versions, count); });
542 fprintf(log, "\n");
543 }
544 CHECK_ERROR_HANDLED(remove_explicit_layers(log, install_paths, count, PLATFORM_X86),
545 { free_installations(install_paths, install_versions, count); });
546 fprintf(log, "\n");
547
548 if(version->major == 0 && version->minor == 0 && version->patch == 0 && version->build == 0) {
549 free_installations(install_paths, install_versions, count);
550 return 0;
551 }
552
553 for(size_t i = 0; i < count; ++i) {
554 if(compare_versions(install_versions + i, version) == 0) {
555 if(platform == PLATFORM_X64) {
556 CHECK_ERROR_HANDLED(add_explicit_layers(log, install_paths[i], PLATFORM_X64),
557 { free_installations(install_paths, install_versions, count); });
558 fprintf(log, "\n");
559 }
560 CHECK_ERROR_HANDLED(add_explicit_layers(log, install_paths[i], PLATFORM_X86),
561 { free_installations(install_paths, install_versions, count); });
562 break;
563 }
564 }
565 free_installations(install_paths, install_versions, count);
566 return 0;
567}
568
Lenny Komow28e06f72016-08-17 14:50:13 -0600569//int update_system_file(FILE* log, const char* name, const char* extension, const char* path,
570// long abi_major, bool append_abi_major, struct SDKVersion* latest_version)
Lenny Komow10ec1212016-08-09 15:56:15 -0600571int update_system_file(FILE* log, const char* name, const char* extension, const char* path,
Lenny Komow769b9df2016-08-12 13:26:20 -0600572 long abi_major, bool leave_abi_major, struct SDKVersion* latest_version)
Lenny Komow10ec1212016-08-09 15:56:15 -0600573{
574 // Generate the filter string
Lenny Komow769b9df2016-08-12 13:26:20 -0600575 const char* pattern = "%s%s-%ld-*-*-*-*%s";
576 int filter_size = snprintf(NULL, 0, pattern, path, name, abi_major, extension) + 1;
577 if(filter_size < 0) {
578 return 180;
Lenny Komow10ec1212016-08-09 15:56:15 -0600579 }
Lenny Komow769b9df2016-08-12 13:26:20 -0600580 char* filter = malloc(filter_size);
581 snprintf(filter, filter_size, pattern, path, name, abi_major, extension);
Lenny Komow10ec1212016-08-09 15:56:15 -0600582
583 // Find all of the files that match the pattern
584 char* latest_filename = malloc(64);
585 memset(latest_version, 0, sizeof(struct SDKVersion));
586 WIN32_FIND_DATA find_data;
587 HANDLE find = FindFirstFile(filter, &find_data);
588 free(filter);
589 for(bool at_end = (find != INVALID_HANDLE_VALUE); at_end;
590 at_end = FindNextFile(find, &find_data)) {
591
592 struct SDKVersion version;
593 CHECK_ERROR_HANDLED(read_version_from_filename(find_data.cFileName, &version), { free(latest_filename); });
594
595 // Decide if this is the latest file
596 if(compare_versions(latest_version, &version) < 0) {
597 *latest_version = version;
Lenny Komow769b9df2016-08-12 13:26:20 -0600598 const char* latestPattern = "%s%s";
599 int size = snprintf(NULL, 0, latestPattern, path, find_data.cFileName) + 1;
Lenny Komow10ec1212016-08-09 15:56:15 -0600600 if(size < 0) {
601 free(latest_filename);
602 return 200;
603 }
604 latest_filename = realloc(latest_filename, size);
Lenny Komow769b9df2016-08-12 13:26:20 -0600605 snprintf(latest_filename, size, latestPattern, path, find_data.cFileName);
Lenny Komow10ec1212016-08-09 15:56:15 -0600606 }
607 }
608 FindClose(find);
609
610 // Make sure something was found
611 if(latest_version->major == 0 && latest_version->minor == 0 && latest_version->patch == 0 &&
612 latest_version->build == 0) {
613 fprintf(log, "Didn't find any version of %s%s\n", name, extension);
614 return 0;
615 }
616
617 fprintf(log, "Found latest version of %s%s: %ld.%ld.%ld.%ld\n", name, extension, latest_version->major,
618 latest_version->minor, latest_version->patch, latest_version->build);
619
620 // Generate output filename
Lenny Komow769b9df2016-08-12 13:26:20 -0600621 char* output_filename;
622 if(leave_abi_major) {
623 const char* outPattern = "%s%s-%ld%s";
624 int out_size = snprintf(NULL, 0, outPattern, path, name, abi_major, extension) + 1;
625 if(out_size < 0) {
626 free(latest_filename);
627 return 205;
628 }
629 output_filename = malloc(out_size);
630 snprintf(output_filename, out_size, outPattern, path, name, abi_major, extension);
631 } else {
632 const char* outPattern = "%s%s%s";
633 int out_size = snprintf(NULL, 0, outPattern, path, name, extension) + 1;
634 if(out_size < 0) {
635 free(latest_filename);
636 return 210;
637 }
638 output_filename = malloc(out_size);
639 snprintf(output_filename, out_size, outPattern, path, name, extension);
Lenny Komow10ec1212016-08-09 15:56:15 -0600640 }
Lenny Komow10ec1212016-08-09 15:56:15 -0600641
642 // Remove any older version of the output file
643 if(remove(output_filename) == 0) {
644 fprintf(log, "Removed file %s\n", output_filename);
645 } else {
646 fprintf(log, "Did not remove file %s\n", output_filename);
647 }
648
649 fprintf(log, "Attempting to copy file %s to %s\n", latest_filename, output_filename);
Lenny Komow769b9df2016-08-12 13:26:20 -0600650 if(CopyFile(latest_filename, output_filename, false) == 0) {
651 free(latest_filename);
652 free(output_filename);
653 return 215;
654 }
Lenny Komow10ec1212016-08-09 15:56:15 -0600655
656 free(latest_filename);
Lenny Komow769b9df2016-08-12 13:26:20 -0600657 free(output_filename);
Lenny Komow10ec1212016-08-09 15:56:15 -0600658 return 0;
659}
660
661int update_windows_directories(FILE* log, long abi_major, enum Platform platform, struct SDKVersion* latest_runtime_version)
662{
663 struct SDKVersion version;
664 unsigned windows_path_size = GetWindowsDirectory(NULL, 0); // Size includes null terminator
665 char* system_path = malloc(windows_path_size +
666 max_s(strlen(PATH_SYSTEM32), strlen(PATH_SYSWOW64)));
667 GetWindowsDirectory(system_path, windows_path_size);
668
669 strcpy(system_path + windows_path_size - 1, PATH_SYSTEM32);
670 fprintf(log, "Updating system directory: %s\n", system_path);
Lenny Komow769b9df2016-08-12 13:26:20 -0600671 CHECK_ERROR_HANDLED(update_system_file(log, "vulkan", ".dll", system_path, abi_major, true,
Lenny Komow10ec1212016-08-09 15:56:15 -0600672 latest_runtime_version), { free(system_path); });
Lenny Komow769b9df2016-08-12 13:26:20 -0600673 CHECK_ERROR_HANDLED(update_system_file(log, "vulkaninfo", ".exe", system_path, abi_major, false,
Lenny Komow10ec1212016-08-09 15:56:15 -0600674 &version), { free(system_path); });
675 if(compare_versions(latest_runtime_version, &version) != 0) {
Lenny Komow769b9df2016-08-12 13:26:20 -0600676 free(system_path);
Lenny Komow10ec1212016-08-09 15:56:15 -0600677 return 220;
678 }
679
680 if(platform == PLATFORM_X64) {
681 strcpy(system_path + windows_path_size - 1, PATH_SYSWOW64);
682 fprintf(log, "\nUpdating system directory: %s\n", system_path);
Lenny Komow769b9df2016-08-12 13:26:20 -0600683 CHECK_ERROR_HANDLED(update_system_file(log, "vulkan", ".dll", system_path, abi_major,
684 true, &version), { free(system_path); });
Lenny Komow10ec1212016-08-09 15:56:15 -0600685 if(compare_versions(latest_runtime_version, &version) != 0) {
Lenny Komow769b9df2016-08-12 13:26:20 -0600686 free(system_path);
Lenny Komow10ec1212016-08-09 15:56:15 -0600687 return 230;
688 }
689 CHECK_ERROR_HANDLED(update_system_file(log, "vulkaninfo", ".exe", system_path, abi_major,
Lenny Komow769b9df2016-08-12 13:26:20 -0600690 false, &version), { free(system_path); });
Lenny Komow10ec1212016-08-09 15:56:15 -0600691 if(compare_versions(latest_runtime_version, &version) != 0) {
Lenny Komow769b9df2016-08-12 13:26:20 -0600692 free(system_path);
Lenny Komow10ec1212016-08-09 15:56:15 -0600693 return 240;
694 }
695 }
696
697 free(system_path);
698 fprintf(log, "\nUpdate of system directories succeeded.\n\n");
699 return 0;
700}