Magellan Linux

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

Parent Directory Parent Directory | Revision Log 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)
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     }