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