]>
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> | |
7215c018 | 7 | #include <stdint.h> |
1f1fa7b6 MG |
8 | #include <strings.h> |
9 | #include <string.h> | |
10 | #include <unistd.h> | |
11 | #include <errno.h> | |
12 | #include <libgen.h> | |
13 | #include "rsb-lz.h" | |
e8563c43 | 14 | #include "filesystem.h" |
1f1fa7b6 | 15 | |
7215c018 | 16 | struct file_entry* get_next_file(uint8_t *fw, int32_t len) |
81a1093d | 17 | { |
7215c018 MG |
18 | static uint8_t *pos; |
19 | static uint8_t *start; | |
20 | static uint8_t *end; | |
81a1093d | 21 | static struct file_entry fent; |
7215c018 | 22 | int32_t name_length; |
81a1093d MG |
23 | |
24 | if (fw != NULL && len != 0) { | |
25 | pos = fw + 0x28; | |
26 | ||
8658e967 | 27 | #if 0 |
7215c018 | 28 | printf("Start of filesystem: 0x%08x\n", *((uint32_t*)pos)); |
8658e967 | 29 | #endif |
b5163e0d | 30 | start = fw; |
7215c018 | 31 | pos = fw + *((uint32_t*)pos); |
81a1093d MG |
32 | end = fw + len; |
33 | } | |
34 | ||
35 | fent.unknown = *pos; | |
36 | pos++; | |
37 | ||
b5163e0d MG |
38 | if (fent.unknown == 0x00) { |
39 | /* EOF */ | |
7215c018 MG |
40 | int32_t fill = (4 - ((pos - start) % 4)) % 4; |
41 | int32_t i; | |
b5163e0d MG |
42 | |
43 | for (i = 0; i < fill; i++) { | |
44 | if (*pos != 0xff) { | |
45 | fprintf(stderr, "Wrong fill byte after EOF: 0x%02x, aborting!\n", *pos); | |
46 | exit(1); | |
47 | } | |
48 | pos++; | |
49 | } | |
50 | ||
51 | if (pos != end) { | |
52 | fprintf(stderr, "EOF marker not at end-of-file %p <-> %p, aborting!\n", pos, end); | |
53 | exit(1); | |
54 | } | |
55 | ||
56 | return NULL; | |
57 | } | |
58 | ||
59 | ||
7215c018 | 60 | name_length = *((uint32_t*)pos); |
81a1093d MG |
61 | pos += 4; |
62 | ||
7215c018 | 63 | fent.length = *((uint32_t*)pos); |
81a1093d MG |
64 | pos += 4; |
65 | ||
66 | if ((fent.length > (end - pos)) || | |
67 | (name_length > (end - pos))) { | |
b5163e0d MG |
68 | printf("EOF reached without hitting EOF marker, aborting " |
69 | "(unknown: 0x%02x, namelen: 0x%08x, contentlen: 0x%08x!\n", | |
70 | fent.unknown, name_length, fent.length); | |
71 | exit(1); | |
81a1093d MG |
72 | } |
73 | ||
74 | fent.name = (char*)pos; | |
75 | pos += name_length; | |
76 | ||
77 | fent.start = pos; | |
78 | pos += fent.length; | |
79 | ||
80 | return &fent; | |
81 | } | |
82 | ||
7215c018 | 83 | void extract_files(uint8_t *fw, int32_t len) |
1f1fa7b6 | 84 | { |
81a1093d | 85 | struct file_entry *fent; |
358935b6 | 86 | |
81a1093d MG |
87 | fent = get_next_file(fw, len); |
88 | ||
89 | while (fent) { | |
3de486ae | 90 | printf("%s: unknown: 0x%02x, length: %d, ", |
81a1093d | 91 | fent->name, fent->unknown, fent->length); |
1f1fa7b6 | 92 | |
81a1093d | 93 | if (fent->length > 0) { |
3de486ae | 94 | write_file(extracted_file(fent->name), fent->start, fent->length); |
7215c018 | 95 | if (*((uint32_t*)fent->start) == LZ_MAGIC) { |
1f1fa7b6 | 96 | char *lzname; |
7215c018 MG |
97 | uint8_t *outbuf; |
98 | uint32_t outlen; | |
1f1fa7b6 | 99 | |
81a1093d | 100 | if ((lzname = strdup(fent->name)) == NULL) { |
1f1fa7b6 MG |
101 | perror("strdup"); |
102 | exit(1); | |
103 | } | |
104 | ||
105 | if (!strcmp(lzname + strlen(lzname) - 4 , ".lz")) { | |
106 | fprintf(stderr, "Ugh, can't derive filename...\n"); | |
107 | exit(1); | |
108 | } | |
109 | lzname[strlen(lzname) - 3] = 0x00; | |
110 | ||
3de486ae | 111 | printf("%s: packed file found, ", lzname); |
1f1fa7b6 | 112 | |
e726b380 MG |
113 | outbuf = extract_lz_file(fent->start, &outlen, 0); |
114 | write_file(extracted_file((char*)lzname), outbuf, outlen); | |
115 | ||
116 | free(outbuf); | |
1f1fa7b6 | 117 | free(lzname); |
81a1093d | 118 | } else if (!strcmp(fent->name, "firmware")) { |
7215c018 | 119 | uint8_t *lzpos; |
1f1fa7b6 MG |
120 | char lzname[128]; |
121 | ||
122 | bzero(lzname, sizeof(lzname)); | |
123 | strcpy(lzname, "firmware."); | |
124 | ||
7215c018 | 125 | lzpos = fent->start + *((uint32_t*)(fent->start + 0x20)); |
1f1fa7b6 MG |
126 | memcpy(lzname + strlen(lzname), lzpos - 4, 4); |
127 | lzpos += 4; | |
7215c018 MG |
128 | if (*((uint32_t*)(lzpos)) == LZ_MAGIC) { |
129 | uint8_t *outbuf; | |
130 | uint32_t outlen; | |
e726b380 MG |
131 | |
132 | printf("%s: compressed firmware part found", lzname); | |
133 | outbuf = extract_lz_file(lzpos, &outlen, 1); | |
134 | printf(", "); | |
135 | write_file(extracted_file((char*)lzname), outbuf, outlen); | |
136 | ||
137 | free(outbuf); | |
1f1fa7b6 MG |
138 | } |
139 | } | |
395daefd MG |
140 | } else { |
141 | printf(", ignoring...\n"); | |
1f1fa7b6 | 142 | } |
81a1093d | 143 | fent = get_next_file(NULL, 0); |
1f1fa7b6 MG |
144 | } |
145 | } | |
146 | ||
7215c018 | 147 | void replace_add_file(uint8_t *fw, int32_t len, char *fwname, char *lname) |
505ad254 MG |
148 | { |
149 | fprintf(stderr, "%s: Implement me!\n", __func__); | |
150 | exit(1); | |
151 | } | |
152 | ||
7215c018 | 153 | void list_files(uint8_t *fw, int32_t len) |
e5be7964 MG |
154 | { |
155 | struct file_entry *fent; | |
156 | ||
157 | for (fent = get_next_file(fw, len); fent != NULL; fent = get_next_file(NULL, 0)) { | |
158 | printf("0x%x %8d %s\n", fent->unknown, fent->length, fent->name); | |
159 | } | |
160 | ||
161 | } | |
162 | ||
1f1fa7b6 MG |
163 | void mkdir_p(char *dir) |
164 | { | |
62b8ccf0 | 165 | char *parent; |
1f1fa7b6 MG |
166 | |
167 | if ((dir == NULL) || (!strcmp(dir, "."))) | |
168 | return; | |
169 | ||
62b8ccf0 MG |
170 | parent = strdup(dirname(dir)); |
171 | if (parent == NULL) { | |
1f1fa7b6 MG |
172 | perror("strdup"); |
173 | exit(1); | |
174 | } | |
62b8ccf0 | 175 | |
1f1fa7b6 MG |
176 | mkdir_p(parent); |
177 | ||
178 | errno = 0; | |
179 | if (mkdir(dir, 0755) == -1) { | |
180 | if (errno != EEXIST) { | |
181 | fprintf(stderr, "%s: ", dir); | |
182 | perror("mkdir"); | |
183 | exit(1); | |
184 | } | |
185 | } | |
62b8ccf0 | 186 | free(parent); |
1f1fa7b6 MG |
187 | } |
188 | ||
7215c018 | 189 | void write_file(char *fname, uint8_t *buf, int32_t len) |
1f1fa7b6 | 190 | { |
1f1fa7b6 | 191 | char *filename_c, *dirn; |
7215c018 MG |
192 | int32_t fd; |
193 | int32_t remaining; | |
194 | int32_t ret; | |
1f1fa7b6 | 195 | |
3de486ae | 196 | if ((filename_c = strdup(fname)) == NULL) { |
1f1fa7b6 MG |
197 | perror("strdup"); |
198 | exit(1); | |
199 | } | |
62b8ccf0 MG |
200 | dirn = strdup(dirname(filename_c)); |
201 | if (dirn == NULL) { | |
202 | perror("strdup"); | |
203 | exit(1); | |
204 | } | |
1f1fa7b6 | 205 | mkdir_p(dirn); |
62b8ccf0 | 206 | free(dirn); |
1f1fa7b6 MG |
207 | free(filename_c); |
208 | ||
3de486ae MG |
209 | if ((fd = open(fname, O_WRONLY|O_CREAT, 0644)) == -1) { |
210 | fprintf(stderr, "%s: ", fname); | |
1f1fa7b6 MG |
211 | perror("open"); |
212 | exit(1); | |
213 | } | |
214 | ||
215 | remaining = len; | |
216 | ||
217 | while(remaining) { | |
218 | ret = write(fd, buf + (len - remaining), remaining); | |
219 | if (ret < 0) { | |
220 | perror("write"); | |
221 | exit(1); | |
222 | } | |
223 | remaining -= ret; | |
224 | } | |
225 | ||
3de486ae | 226 | printf("%s written.\n", fname); |
1f1fa7b6 MG |
227 | |
228 | close(fd); | |
229 | } | |
3de486ae MG |
230 | |
231 | char *extracted_file(char *fname) | |
232 | { | |
233 | static char filename[PATH_MAX]; | |
234 | ||
235 | strcpy(filename, "extracted/"); | |
236 | strcat(filename, fname); | |
237 | ||
238 | return filename; | |
239 | } |