Annotation of /trunk/linterm_tools/fw_builder/bundle-tools/fwextract.c
Parent Directory | Revision Log
Revision 658 -
(hide annotations)
(download)
Mon Jan 14 16:57:24 2008 UTC (16 years, 4 months ago) by niro
File MIME type: text/plain
File size: 6780 byte(s)
Mon Jan 14 16:57:24 2008 UTC (16 years, 4 months ago) by niro
File MIME type: text/plain
File size: 6780 byte(s)
initial import
1 | niro | 658 | /* |
2 | A small tool to read/edit Wyse WinTerm firmware upgrade/add-on images | ||
3 | Copyright (C) 2005 Wilmer van der Gaast <wilmer@gaast.net> | ||
4 | |||
5 | This program is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the second version of the GNU | ||
7 | General Public License as published by the Free Software | ||
8 | Foundation. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <sys/types.h> | ||
23 | #include <sys/stat.h> | ||
24 | #include <fcntl.h> | ||
25 | #include <unistd.h> | ||
26 | #include <string.h> | ||
27 | #include <errno.h> | ||
28 | |||
29 | #include "fwstruct.h" | ||
30 | |||
31 | #define BUFSIZE 512 | ||
32 | |||
33 | int main( int argc, char *argv[] ) | ||
34 | { | ||
35 | struct index *idx = NULL; | ||
36 | int fd; | ||
37 | |||
38 | structcheck(); | ||
39 | |||
40 | if( argc < 3 ) | ||
41 | { | ||
42 | fprintf( stderr, "extract - Read/Edit WYSE Winterm firmware bundles\n" | ||
43 | "\n" | ||
44 | "Syntax: %s <file> extract - Extract all files\n" | ||
45 | " %s <file> list - List contents\n" | ||
46 | " %s <file> insert <file> <slot> - Replace <slot> in archive with <file>\n", | ||
47 | argv[0], argv[0], argv[0] ); | ||
48 | return( 1 ); | ||
49 | } | ||
50 | |||
51 | fd = open( argv[1], O_RDONLY ); | ||
52 | if( fd < 0 ) | ||
53 | { | ||
54 | perror( "open" ); | ||
55 | return( 1 ); | ||
56 | } | ||
57 | |||
58 | lseek( fd, 0x59, SEEK_SET ); | ||
59 | |||
60 | printf( "%-8s %-8s %-8s %-6s %-8s %-8s %-s\n", | ||
61 | "Offset", "Size", "Checksum", "SysFlg", "BiosFlag", "Time", "Filename" ); | ||
62 | |||
63 | while( 1 ) | ||
64 | { | ||
65 | struct header *head; | ||
66 | struct index *tmp; | ||
67 | off_t offset; | ||
68 | |||
69 | head = malloc( sizeof( struct header ) ); | ||
70 | |||
71 | offset = lseek( fd, 0, SEEK_CUR ); | ||
72 | if( read( fd, head, sizeof( struct header ) ) != sizeof( struct header ) ) | ||
73 | { | ||
74 | perror( "read" ); | ||
75 | return( 1 ); | ||
76 | } | ||
77 | cvtheader( head ); | ||
78 | |||
79 | /* End of index? */ | ||
80 | if( head->hsize == 0 ) | ||
81 | break; | ||
82 | |||
83 | head = realloc( head, head->hsize + 1 ); | ||
84 | head->fn[head->fnlen] = 0; | ||
85 | if( read( fd, head->fn, head->fnlen ) != head->fnlen ) | ||
86 | { | ||
87 | perror( "read" ); | ||
88 | return( 1 ); | ||
89 | } | ||
90 | |||
91 | printf( "%08x %08x %08x %02x%02x%02x %08x %08x %s\n", | ||
92 | head->offset, head->fsize, head->checksum, head->sys_flag[0], | ||
93 | head->sys_flag[1], head->sys_flag[2], head->bios_flag, head->time, head->fn ); | ||
94 | |||
95 | /* Remember that here the new file gets inserted at the | ||
96 | beginning of the list, so the whole list will be in | ||
97 | reversed order. The rest of the code might break if you | ||
98 | change this... */ | ||
99 | tmp = malloc( sizeof( struct index ) ); | ||
100 | tmp->h = head; | ||
101 | tmp->next = idx; | ||
102 | tmp->idx_offset = offset; | ||
103 | idx = tmp; | ||
104 | } | ||
105 | |||
106 | if( strcmp( argv[2], "list" ) == 0 ) | ||
107 | { | ||
108 | /* Do nothing */ | ||
109 | } | ||
110 | else if( strcmp( argv[2], "insert" ) == 0 ) | ||
111 | { | ||
112 | #if BYTE_ORDER != BIG_ENDIAN | ||
113 | struct index *tmp; | ||
114 | struct stat src_info; | ||
115 | unsigned int slot_cs, arch_cs, buf; | ||
116 | int sfd, size; | ||
117 | |||
118 | /* Warning: This code is "reasonably" dirty. :-) */ | ||
119 | |||
120 | if( argc < 5 ) | ||
121 | { | ||
122 | fprintf( stderr, "Not enough arguments\n" ); | ||
123 | return( 1 ); | ||
124 | } | ||
125 | |||
126 | /* Find the slot */ | ||
127 | for( tmp = idx; tmp; tmp = tmp->next ) | ||
128 | if( strcmp( tmp->h->fn, argv[4] ) == 0 ) | ||
129 | break; | ||
130 | |||
131 | if( tmp == NULL ) | ||
132 | { | ||
133 | fprintf( stderr, "Slot does not exist\n" ); | ||
134 | return( 1 ); | ||
135 | } | ||
136 | |||
137 | /* Open the file to be inserted */ | ||
138 | if( ( sfd = open( argv[3], O_RDONLY ) ) == -1 ) | ||
139 | { | ||
140 | perror( "open" ); | ||
141 | return( 1 ); | ||
142 | } | ||
143 | |||
144 | /* Check if sizes are okay */ | ||
145 | fstat( sfd, &src_info ); | ||
146 | if( tmp->h->fsize < src_info.st_size ) | ||
147 | { | ||
148 | fprintf( stderr, "Can't insert file, slot is too small\n" ); | ||
149 | return( 1 ); | ||
150 | } | ||
151 | |||
152 | /* To recalculate the new total-checksum, get the current one | ||
153 | and "remove" the existing file from it. */ | ||
154 | lseek( fd, -4, SEEK_END ); | ||
155 | read( fd, &arch_cs, 4 ); | ||
156 | |||
157 | /* Note that the checksums are per-word and these things aren't | ||
158 | necessarily word-aligned, so we have to handle this correctly. */ | ||
159 | lseek( fd, tmp->h->offset & ~3, SEEK_SET ); | ||
160 | for( size = src_info.st_size + ( tmp->h->offset & 3 ); size > 0; size -= 4 ) | ||
161 | { | ||
162 | read( fd, &buf, 4 ); | ||
163 | arch_cs += buf; | ||
164 | } | ||
165 | |||
166 | /* Also "remove" the index entry from the checksum. */ | ||
167 | lseek( fd, tmp->idx_offset & ~3, SEEK_SET ); | ||
168 | for( size = tmp->h->fsize + ( tmp->h->fsize & 3 ); size > 0; size -= 4 ) | ||
169 | { | ||
170 | read( fd, &buf, 4 ); | ||
171 | arch_cs += buf; | ||
172 | } | ||
173 | |||
174 | /* Oh yes, we want to write now... */ | ||
175 | close( fd ); | ||
176 | if( ( fd = open( argv[1], O_RDWR ) ) < 0 ) | ||
177 | { | ||
178 | perror( "open" ); | ||
179 | return( 1 ); | ||
180 | } | ||
181 | lseek( fd, tmp->h->offset, SEEK_SET ); | ||
182 | |||
183 | /* We're doing this in small 4-byte blocks. This is slow, but | ||
184 | it's more convenient because of the checkum calculation. */ | ||
185 | slot_cs = 0xFFFE1000; | ||
186 | while( 1 ) | ||
187 | { | ||
188 | unsigned int n; | ||
189 | |||
190 | buf = 0; | ||
191 | n = read( sfd, &buf, 4 ); | ||
192 | |||
193 | if( n == 0 ) | ||
194 | break; | ||
195 | |||
196 | slot_cs -= buf; | ||
197 | // arch_cs -= buf; | ||
198 | write( fd, &buf, 4 ); | ||
199 | } | ||
200 | |||
201 | /* Write the new slot checksum */ | ||
202 | tmp->h->checksum = slot_cs; | ||
203 | tmp->h->fsize = src_info.st_size; | ||
204 | lseek( fd, tmp->idx_offset, SEEK_SET ); | ||
205 | write( fd, tmp->h, tmp->h->fsize ); | ||
206 | |||
207 | /* "Add" the new contents to the checksum */ | ||
208 | lseek( fd, tmp->h->offset & ~3, SEEK_SET ); | ||
209 | for( size = src_info.st_size + ( tmp->h->offset & 3 ); size > 0; size -= 4 ) | ||
210 | { | ||
211 | read( fd, &buf, 4 ); | ||
212 | arch_cs -= buf; | ||
213 | } | ||
214 | |||
215 | /* Don't forget the index entry, it also changed. */ | ||
216 | lseek( fd, tmp->idx_offset & ~3, SEEK_SET ); | ||
217 | for( size = tmp->h->fsize + ( tmp->h->fsize & 3 ); size > 0; size -= 4 ) | ||
218 | { | ||
219 | read( fd, &buf, 4 ); | ||
220 | arch_cs -= buf; | ||
221 | } | ||
222 | |||
223 | /* Write the new archive checksum */ | ||
224 | lseek( fd, -4, SEEK_END ); | ||
225 | write( fd, &arch_cs, 4 ); | ||
226 | #else | ||
227 | fprintf( stderr, "Big-endian version doesn't support inserting, sorry.\n" ); | ||
228 | #endif | ||
229 | } | ||
230 | else | ||
231 | { | ||
232 | while( idx ) /* Default action: We're extracting */ | ||
233 | { | ||
234 | char buf[BUFSIZE]; | ||
235 | int len, toread, ofd; | ||
236 | |||
237 | lseek( fd, idx->h->offset, SEEK_SET ); | ||
238 | len = idx->h->fsize; | ||
239 | |||
240 | ofd = open( idx->h->fn, O_WRONLY | O_CREAT | O_EXCL, 0644 ); | ||
241 | if( ofd < 0 ) | ||
242 | { | ||
243 | if( errno == EEXIST ) | ||
244 | { | ||
245 | printf( "Warning: File already exists: %s\n", idx->h->fn ); | ||
246 | idx = idx->next; | ||
247 | continue; | ||
248 | } | ||
249 | else | ||
250 | { | ||
251 | perror( "open" ); | ||
252 | return( 1 ); | ||
253 | } | ||
254 | } | ||
255 | |||
256 | while( len > 0 ) | ||
257 | { | ||
258 | toread = len > BUFSIZE ? BUFSIZE : len; | ||
259 | |||
260 | if( read( fd, buf, toread ) != toread ) | ||
261 | { | ||
262 | perror( "read" ); | ||
263 | return( 1 ); | ||
264 | } | ||
265 | |||
266 | if( write( ofd, buf, toread ) != toread ) | ||
267 | { | ||
268 | perror( "write" ); | ||
269 | return( 1 ); | ||
270 | } | ||
271 | |||
272 | len -= toread; | ||
273 | } | ||
274 | |||
275 | close( ofd ); | ||
276 | |||
277 | idx = idx->next; | ||
278 | } | ||
279 | } | ||
280 | |||
281 | return( 0 ); | ||
282 | } |