Contents of /trunk/linterm_tools/fw_builder/bundle-tools/fwextract.c
Parent Directory | Revision Log
Revision 658 -
(show annotations)
(download)
Mon Jan 14 16:57:24 2008 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 6780 byte(s)
Mon Jan 14 16:57:24 2008 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 6780 byte(s)
initial import
1 | /* |
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 | } |