-
Notifications
You must be signed in to change notification settings - Fork 36
/
dyld-shared-cache-extractor.c
92 lines (76 loc) · 2.72 KB
/
dyld-shared-cache-extractor.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <assert.h>
#include <dlfcn.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syslimits.h>
#include <unistd.h>
__attribute__((noreturn))
__attribute__((__format__(__printf__, 1, 0))) static void
fail(const char *error, ...) {
va_list args;
va_start(args, error);
vfprintf(stderr, error, args);
va_end(args);
exit(EXIT_FAILURE);
}
static int (*extract)(const char *cache_path, const char *output_path,
void (^progress)(int, int));
static int get_library_path(const char *candidate, char *output) {
if (candidate) {
if (access(candidate, R_OK) != 0) {
fail("error: dsc_extractor.bundle not found at provided path: %s\n",
candidate);
}
strncpy(output, candidate, PATH_MAX);
return 0;
}
FILE *pipe = popen("xcrun --sdk iphoneos --show-sdk-platform-path", "r");
if (pipe && fgets(output, PATH_MAX, pipe) != NULL) {
output[strlen(output) - 1] = '\0';
strcat(output, "/usr/lib/dsc_extractor.bundle");
assert(pclose(pipe) == 0);
return 0;
}
const char *builtin = "/usr/lib/dsc_extractor.bundle";
if (access(builtin, R_OK) == 0) {
strncpy(output, builtin, PATH_MAX);
return 0;
}
return 1;
}
static int extract_shared_cache(const char *library_path,
const char *cache_path,
const char *output_path) {
void *handle = dlopen(library_path, RTLD_LAZY);
if (!handle)
fail("error: failed to load bundle: %s\n", library_path);
*(void **)(&extract) =
dlsym(handle, "dyld_shared_cache_extract_dylibs_progress");
if (!extract)
fail("error: failed to load function from bundle: %s\n", library_path);
return extract(cache_path, output_path, ^void(int completed, int total) {
printf("extracted %d/%d\n", completed, total);
});
}
int main(int argc, char *argv[]) {
if (!(argc == 3 || argc == 4))
fail("Usage: %s <shared-cache-path> <output-path> "
"[<dsc_extractor.bundle-path>]\n",
argv[0]);
const char *shared_cache = argv[1];
if (access(shared_cache, R_OK) != 0)
fail("error: shared cache path doesn't exist: %s\n", shared_cache);
const char *library_candidate = argc == 4 ? argv[3] : NULL;
char library_path[PATH_MAX];
if (get_library_path(library_candidate, library_path) != 0)
fail("error: failed to fetch Xcode path\n");
if (access(library_path, R_OK) != 0)
fail("error: dsc_extractor.bundle wasn't found at expected path %s. "
"Install Xcode or provide path as argument\n",
library_path);
printf("dsc_extractor.bundle found at %s\n", library_path);
const char *output_path = argv[2];
return extract_shared_cache(library_path, shared_cache, output_path);
}