]>
Commit | Line | Data |
---|---|---|
1f1fa7b6 MG |
1 | #include <sys/stat.h> |
2 | #include <sys/types.h> | |
3 | #include <limits.h> | |
4 | #include <fcntl.h> | |
5 | #include <stdio.h> | |
6 | #include <stdlib.h> | |
7 | #include <strings.h> | |
8 | #include <string.h> | |
9 | #include <unistd.h> | |
10 | #include <errno.h> | |
11 | #include <libgen.h> | |
12 | #include "rsb-lz.h" | |
13 | #include "extract.h" | |
14 | ||
81a1093d MG |
15 | struct file_entry* get_next_file(unsigned char *fw, int len) |
16 | { | |
17 | static unsigned char *pos; | |
18 | static unsigned char *end; | |
19 | static struct file_entry fent; | |
20 | int name_length; | |
21 | ||
22 | if (fw != NULL && len != 0) { | |
23 | pos = fw + 0x28; | |
24 | ||
8658e967 | 25 | #if 0 |
81a1093d | 26 | printf("Start of filesystem: 0x%08x\n", *((unsigned int*)pos)); |
8658e967 | 27 | #endif |
81a1093d MG |
28 | pos = fw + *((unsigned int*)pos); |
29 | end = fw + len; | |
30 | } | |
31 | ||
32 | fent.unknown = *pos; | |
33 | pos++; | |
34 | ||
35 | name_length = *((unsigned int*)pos); | |
36 | pos += 4; | |
37 | ||
38 | fent.length = *((unsigned int*)pos); | |
39 | pos += 4; | |
40 | ||
41 | if ((fent.length > (end - pos)) || | |
42 | (name_length > (end - pos))) { | |
8658e967 | 43 | #if 0 |
81a1093d | 44 | printf("EOF reached\n"); |
8658e967 | 45 | #endif |
81a1093d MG |
46 | return NULL; |
47 | } | |
48 | ||
49 | fent.name = (char*)pos; | |
50 | pos += name_length; | |
51 | ||
52 | fent.start = pos; | |
53 | pos += fent.length; | |
54 | ||
55 | return &fent; | |
56 | } | |
57 | ||
1f1fa7b6 MG |
58 | void extract_files(unsigned char *fw, int len) |
59 | { | |
81a1093d | 60 | struct file_entry *fent; |
358935b6 | 61 | |
81a1093d MG |
62 | fent = get_next_file(fw, len); |
63 | ||
64 | while (fent) { | |
358935b6 | 65 | printf("%s: unknown: 0x%02x, length: %d", |
81a1093d | 66 | fent->name, fent->unknown, fent->length); |
1f1fa7b6 | 67 | |
81a1093d MG |
68 | if (fent->length > 0) { |
69 | write_file(fent->name, fent->start, fent->length); | |
70 | if (*((unsigned int*)fent->start) == LZ_MAGIC) { | |
1f1fa7b6 MG |
71 | char *lzname; |
72 | ||
81a1093d | 73 | if ((lzname = strdup(fent->name)) == NULL) { |
1f1fa7b6 MG |
74 | perror("strdup"); |
75 | exit(1); | |
76 | } | |
77 | ||
78 | if (!strcmp(lzname + strlen(lzname) - 4 , ".lz")) { | |
79 | fprintf(stderr, "Ugh, can't derive filename...\n"); | |
80 | exit(1); | |
81 | } | |
82 | lzname[strlen(lzname) - 3] = 0x00; | |
83 | ||
84 | printf("%s: packed file found", lzname); | |
85 | ||
81a1093d | 86 | extract_lz_file(fent->start, (unsigned char*)lzname); |
1f1fa7b6 | 87 | free(lzname); |
81a1093d | 88 | } else if (!strcmp(fent->name, "firmware")) { |
1f1fa7b6 MG |
89 | unsigned char *lzpos; |
90 | char lzname[128]; | |
91 | ||
92 | bzero(lzname, sizeof(lzname)); | |
93 | strcpy(lzname, "firmware."); | |
94 | ||
81a1093d | 95 | lzpos = fent->start + *((unsigned int*)(fent->start + 0x20)); |
1f1fa7b6 MG |
96 | memcpy(lzname + strlen(lzname), lzpos - 4, 4); |
97 | lzpos += 4; | |
98 | if (*((unsigned int*)(lzpos)) == LZ_MAGIC) { | |
99 | printf("%s: compressed firmware part found", lzname); | |
100 | extract_lz_file(lzpos, (unsigned char*)lzname); | |
101 | } | |
102 | } | |
395daefd MG |
103 | } else { |
104 | printf(", ignoring...\n"); | |
1f1fa7b6 | 105 | } |
81a1093d | 106 | fent = get_next_file(NULL, 0); |
1f1fa7b6 MG |
107 | } |
108 | } | |
109 | ||
110 | void mkdir_p(char *dir) | |
111 | { | |
112 | char *copy, *parent; | |
113 | ||
114 | if ((dir == NULL) || (!strcmp(dir, "."))) | |
115 | return; | |
116 | ||
117 | if ((copy = strdup(dir)) == NULL) { | |
118 | perror("strdup"); | |
119 | exit(1); | |
120 | } | |
121 | parent = dirname(copy); | |
122 | mkdir_p(parent); | |
123 | ||
124 | errno = 0; | |
125 | if (mkdir(dir, 0755) == -1) { | |
126 | if (errno != EEXIST) { | |
127 | fprintf(stderr, "%s: ", dir); | |
128 | perror("mkdir"); | |
129 | exit(1); | |
130 | } | |
131 | } | |
132 | free(copy); | |
133 | } | |
134 | ||
135 | void write_file(char *fname, unsigned char *buf, int len) | |
136 | { | |
137 | char filename[PATH_MAX]; | |
138 | char *filename_c, *dirn; | |
139 | int fd; | |
140 | int remaining; | |
141 | int ret; | |
142 | ||
143 | strcpy(filename, "extracted/"); | |
144 | strcat(filename, fname); | |
145 | ||
146 | if ((filename_c = strdup(filename)) == NULL) { | |
147 | perror("strdup"); | |
148 | exit(1); | |
149 | } | |
150 | dirn = dirname(filename_c); | |
151 | mkdir_p(dirn); | |
152 | free(filename_c); | |
153 | ||
154 | if ((fd = open(filename, O_WRONLY|O_CREAT, 0644)) == -1) { | |
155 | fprintf(stderr, "%s: ", filename); | |
156 | perror("open"); | |
157 | exit(1); | |
158 | } | |
159 | ||
160 | remaining = len; | |
161 | ||
162 | while(remaining) { | |
163 | ret = write(fd, buf + (len - remaining), remaining); | |
164 | if (ret < 0) { | |
165 | perror("write"); | |
166 | exit(1); | |
167 | } | |
168 | remaining -= ret; | |
169 | } | |
170 | ||
171 | printf(", %s written.\n", filename); | |
172 | ||
173 | close(fd); | |
174 | } |