Magellan Linux

Contents of /trunk/linterm_tools/fw_builder/bundle-tools/fwextract.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 658 - (show annotations) (download)
Mon Jan 14 16:57:24 2008 UTC (16 years, 3 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 }