wok-next view syslinux/stuff/iso2exe/iso2exe.c @ rev 18775

syslinux/isohybrid.exe: add -a & -i support
author Pascal Bellard <pascal.bellard@slitaz.org>
date Fri Jan 01 10:53:50 2016 +0100 (2016-01-01)
parents 6a2e6eb35735
children 4145d548de53
line source
1 #ifdef __TURBOC__
2 #include <io.h>
3 #endif
4 #include <sys/types.h>
5 #include <fcntl.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #ifdef WIN32
10 #include <windows.h>
11 #endif
12 #ifdef __MSDOS__
13 #define ftruncate(a,b)
14 #endif
15 #ifdef __MINGW32__
16 #define ftruncate chsize
17 #endif
18 #if !defined(__MSDOS__) && !defined(WIN32)
19 #define O_BINARY 0
20 #endif
21 typedef unsigned char uint8_t;
22 typedef unsigned long uint32_t;
23 #include "iso2exe.h"
25 static int fd, forced, uninstall, status = 1;
26 static char *append, *initrd;
27 static char tazlitoinfo[0x8000U - BOOTISOSZ];
28 #define buffer tazlitoinfo
29 #define BUFFERSZ 2048
30 #define WORD(n) * (unsigned short *) (n)
31 #define LONG(n) * (unsigned long *) (n)
33 static void readsector(unsigned long sector)
34 {
35 if (lseek(fd, sector * BUFFERSZ, SEEK_SET) == -1 ||
36 read(fd, buffer, BUFFERSZ) != BUFFERSZ) {
37 puts(bootiso+READSECTORERR);
38 exit(1);
39 }
40 }
42 static unsigned long getcustomsector(void)
43 {
44 readsector(16UL);
45 return 16UL + LONG(buffer + 80);
46 }
48 static int skipmd5 = 0;
49 #define ALIGN1
51 typedef struct {
52 uint32_t l;
53 uint32_t h;
54 } uint64_t;
55 static uint8_t wbuffer[64]; /* always correctly aligned for uint64_t */
56 static uint64_t total64; /* must be directly before hash[] */
57 static uint32_t hash[8]; /* 4 elements for md5, 5 for sha1, 8 for sha256 */
59 //#define rotl32(x,n) (((x) << (n)) | ((x) >> (32 - (n))))
60 static uint32_t rotl32(uint32_t x, unsigned n)
61 {
62 return (x << n) | (x >> (32 - n));
63 }
65 static void md5_process_block64(void);
67 /* Feed data through a temporary buffer.
68 * The internal buffer remembers previous data until it has 64
69 * bytes worth to pass on.
70 */
71 static void common64_hash(const void *buffer, size_t len)
72 {
73 unsigned bufpos = total64.l & 63;
75 total64.l += len; if (total64.l < len) total64.h++;
77 while (1) {
78 unsigned remaining = 64 - bufpos;
79 if (remaining > len)
80 remaining = len;
81 /* Copy data into aligned buffer */
82 memcpy(wbuffer + bufpos, buffer, remaining);
83 len -= remaining;
84 buffer = (const char *)buffer + remaining;
85 bufpos += remaining;
86 /* clever way to do "if (bufpos != 64) break; ... ; bufpos = 0;" */
87 bufpos -= 64;
88 if (bufpos != 0)
89 break;
90 /* Buffer is filled up, process it */
91 md5_process_block64();
92 /*bufpos = 0; - already is */
93 }
94 }
96 /* Process the remaining bytes in the buffer */
97 static void common64_end(void)
98 {
99 unsigned bufpos = total64.l & 63;
100 /* Pad the buffer to the next 64-byte boundary with 0x80,0,0,0... */
101 wbuffer[bufpos++] = 0x80;
103 /* This loop iterates either once or twice, no more, no less */
104 while (1) {
105 unsigned remaining = 64 - bufpos;
106 memset(wbuffer + bufpos, 0, remaining);
107 /* Do we have enough space for the length count? */
108 if (remaining >= 8) {
109 /* Store the 64-bit counter of bits in the buffer */
110 //uint64_t t = total64 << 3;
111 uint32_t *t = (uint32_t *) (&wbuffer[64 - 8]);
112 /* wbuffer is suitably aligned for this */
113 //*(uint64_t *) (&wbuffer[64 - 8]) = t;
114 t[0] = total64.l << 3;
115 t[1] = (total64.h << 3) | (total64.l >> 29);
116 }
117 md5_process_block64();
118 if (remaining >= 8)
119 break;
120 bufpos = 0;
121 }
122 }
124 /* These are the four functions used in the four steps of the MD5 algorithm
125 * and defined in the RFC 1321. The first function is a little bit optimized
126 * (as found in Colin Plumbs public domain implementation).
127 * #define FF(b, c, d) ((b & c) | (~b & d))
128 */
129 #undef FF
130 #undef FG
131 #undef FH
132 #undef FI
133 #define FF(b, c, d) (d ^ (b & (c ^ d)))
134 #define FG(b, c, d) FF(d, b, c)
135 #define FH(b, c, d) (b ^ c ^ d)
136 #define FI(b, c, d) (c ^ (b | ~d))
138 /* Hash a single block, 64 bytes long and 4-byte aligned */
139 static void md5_process_block64(void)
140 {
141 uint32_t *words = (void*) wbuffer;
142 uint32_t A = hash[0];
143 uint32_t B = hash[1];
144 uint32_t C = hash[2];
145 uint32_t D = hash[3];
147 const uint32_t *pc;
148 const char *pp;
149 const char *ps;
150 int i;
151 uint32_t temp;
154 pc = C_array;
155 pp = P_array;
156 ps = S_array - 4;
158 for (i = 0; i < 64; i++) {
159 if ((i & 0x0f) == 0)
160 ps += 4;
161 temp = A;
162 switch (i >> 4) {
163 case 0:
164 temp += FF(B, C, D);
165 break;
166 case 1:
167 temp += FG(B, C, D);
168 break;
169 case 2:
170 temp += FH(B, C, D);
171 break;
172 case 3:
173 temp += FI(B, C, D);
174 }
175 temp += words[(int) (*pp++)] + *pc++;
176 temp = rotl32(temp, ps[i & 3]);
177 temp += B;
178 A = D;
179 D = C;
180 C = B;
181 B = temp;
182 }
183 /* Add checksum to the starting values */
184 hash[0] += A;
185 hash[1] += B;
186 hash[2] += C;
187 hash[3] += D;
189 }
190 #undef FF
191 #undef FG
192 #undef FH
193 #undef FI
195 /* Initialize structure containing state of computation.
196 * (RFC 1321, 3.3: Step 3)
197 */
198 static void md5_begin(void)
199 {
200 hash[0] = 0x67452301;
201 hash[1] = 0xefcdab89;
202 hash[2] = 0x98badcfe;
203 hash[3] = 0x10325476;
204 total64.l = total64.h = 0;
205 }
207 /* Used also for sha1 and sha256 */
208 #define md5_hash common64_hash
210 /* Process the remaining bytes in the buffer and put result from CTX
211 * in first 16 bytes following RESBUF. The result is always in little
212 * endian byte order, so that a byte-wise output yields to the wanted
213 * ASCII representation of the message digest.
214 */
215 #define md5_end common64_end
217 static int writenhash(void *buffer, size_t len)
218 {
219 md5_hash(buffer, len);
220 return write(fd, buffer, len);
221 }
223 static void md5sum(void)
224 {
225 unsigned long sectors = 0;
226 int count;
228 lseek(fd, 32768UL, SEEK_SET);
230 md5_begin();
231 while ((count = read(fd, buffer, BUFFERSZ)) > 0) {
232 if (sectors == 0)
233 sectors = LONG(buffer + 80);
234 md5_hash(buffer, count);
235 if (--sectors == 0)
236 break;
237 }
239 if (count < 0)
240 return;
242 md5_end();
244 lseek(fd, 32752UL, SEEK_SET);
245 write(fd, hash, 16);
246 memcpy(bootiso + BOOTISOSZ - 16, hash, 16);
247 }
249 static unsigned chksum(unsigned start, unsigned stop)
250 {
251 unsigned i, n = 0;
253 lseek(fd, 0UL /* (unsigned long) (start / BUFFERSZ) */, SEEK_SET);
254 while (1) {
255 if (read(fd, buffer, BUFFERSZ) != BUFFERSZ)
256 return 0;
257 for (i = start % BUFFERSZ; i < BUFFERSZ; i += 2, start += 2) {
258 if (start >= stop)
259 return - n;
260 n += WORD(buffer + i);
261 }
262 }
263 }
265 static unsigned install(char *filename)
266 {
267 #define heads 64
268 #define sectors 32
269 #define partition (446+16)
270 #define trksz (512UL * heads * sectors)
271 unsigned long size, catalog, lba;
272 int cylinders, i, j, isohybrid;
273 unsigned n;
274 #ifdef __MSDOS__
275 for (bootiso = (char *) install;
276 bootiso[0] != 'M' || bootiso[1] != 'Z' || bootiso[2] != '\xEB';
277 bootiso++) if (bootiso < (char *) install) {
278 bootiso = "No bootiso data";
279 return 0;
280 }
281 #endif
282 if (!filename)
283 return USAGE;
284 fd = open(filename,O_RDWR|O_BINARY);
285 if (fd == -1)
286 return OPENERR;
288 if (uninstall) {
289 struct { char check[sizeof(tazlitoinfo) - BUFFERSZ - 1024]; };
290 readsector(0UL);
291 n = BUFFERSZ; /* fill with zeros */
292 if (WORD(buffer) == 23117) {
293 /* restore isolinux hybrid boot */
294 readsector((unsigned long) buffer[417]);
295 n = 0; /* fill with hybrid boot */
296 }
297 lseek(fd, 0UL, SEEK_SET);
298 for (i = 0; i < 32; i++, n = BUFFERSZ) {
299 write(fd, buffer + n, 1024);
300 }
301 i = getcustomsector();
302 lseek(fd, i * 2048UL, SEEK_SET);
303 for (;i % 512; i++) {
304 /* clear custom config */
305 write(fd, buffer + 2048, 2048);
306 }
307 ftruncate(fd, i * 2048UL);
308 close(fd);
309 status = 0;
310 return UNINSTALLMSG;
311 }
313 if (append || initrd) {
314 unsigned long pos = getcustomsector() * 2048UL;
315 lseek(fd, pos, SEEK_SET);
316 write(fd, "#!boot 00000000000000000000000000000000\n", 40);
317 md5_begin();
318 if (append) {
319 writenhash("append=", 7);
320 writenhash(append, strlen(append));
321 writenhash("\n", 1);
322 }
323 if (initrd) {
324 char number[16], *p;
325 unsigned long end, x;
326 int data = open(initrd,O_RDONLY|O_BINARY);
327 if (data == -1)
328 return OPENINITRDERR;
329 for (end = 0;; end += i) {
330 i = read(data, buffer, BUFFERSZ);
331 if (i <= 0)
332 break;
333 }
334 p = number + sizeof(number) -1;
335 x = end; *p-- = '\n';
336 do {
337 *p-- = '0' + (x % 10);
338 x /= 10;
339 } while (x);
340 if (*++p != '0') {
341 writenhash("initrd:", 7);
342 i = number - p + sizeof(number);
343 writenhash(p, i);
344 lseek(data, 0UL, SEEK_SET);
345 do {
346 i = read(data, buffer, BUFFERSZ);
347 if (i <= 0)
348 break;
349 if (i > end)
350 i = end;
351 writenhash(buffer, i);
352 end -= i;
353 } while (end != 0);
354 }
355 close(data);
356 }
357 md5_end();
358 {
359 static char h[] = "0123456789ABCDEF";
360 char string[32], *s = string + 30;
361 unsigned char *p = (void *) hash;
363 lseek(fd, 7 + pos, SEEK_SET);
364 for (p += 15; s >= string; p--, s -= 2) {
365 s[1] = h[ *p & 15 ];
366 s[0] = h[ *p >> 4 ];
367 }
368 write(fd, string, 32);
369 }
370 }
372 if (forced == 0) {
373 status = 2;
374 /* Install hybridiso boot sector */
375 readsector(17UL);
376 if (strncmp(buffer+7, bootiso+ELTORITOERR+ELTORITOOFS, 23))
377 return ELTORITOERR;
378 catalog = LONG(buffer + 71);
379 readsector(catalog);
380 if (LONG(buffer) != 1 || LONG(buffer + 30) != 0x88AA55UL)
381 return CATALOGERR;
382 lba = LONG(buffer + 40);
383 readsector(lba);
384 if (LONG(buffer + 64) != 1886961915UL)
385 return HYBRIDERR;
386 isohybrid = bootiso[417] * 512;
387 LONG(bootiso + isohybrid + 432) = lba * 4;
388 LONG(bootiso + isohybrid + 440) = rand();
389 LONG(bootiso + isohybrid + partition) = 0x10080UL;
390 WORD(bootiso + isohybrid + 510) = 0xAA55U;
391 #if 0
392 size = lseek(fd, 0UL, SEEK_END);
393 size += 0x000FFFFFUL;
394 size &= 0xFFF00000UL;
395 #else
396 for (size = 0x000FFFFFUL; /* 1M - 1 */
397 read(fd, tazlitoinfo, 1024) == 1024;
398 size += 1024);
399 size &= 0xFFF00000UL; /* round */
400 #endif
401 cylinders = (size >> 20) - 1;
402 bootiso[isohybrid + partition + 4] = 23; /* "Windows hidden IFS" */
403 bootiso[isohybrid + partition + 5] = heads - 1;
404 bootiso[isohybrid + partition + 6] = ((cylinders & 0x300) >> 2) + sectors;
405 bootiso[isohybrid + partition + 7] = cylinders & 0xFF;
406 LONG(bootiso + isohybrid + partition + 8) = 0;
407 LONG(bootiso + isohybrid + partition + 12) = (size >> 9);
409 /* Copy the partition table */
410 memcpy(bootiso + 0x1BE, bootiso + isohybrid + 0x1BE, 66);
411 }
413 /* Install iso2exe boot sector */
414 LONG(bootiso + 440) = time(NULL);
416 /* read tazlito flavor data */
417 lseek(fd, 1024UL, SEEK_SET);
418 read(fd, tazlitoinfo, sizeof(tazlitoinfo));
420 /* Update iso image */
421 n = (bootiso[417] + 1) * 512;
422 lseek(fd, 0UL, SEEK_SET);
423 write(fd, bootiso, n); /* EXE/PE + isohybrid mbr */
424 write(fd, tazlitoinfo, sizeof(tazlitoinfo));
425 write(fd, bootiso + n, BOOTISOSZ - n); /* COM + rootfs + EXE/DOS */
427 /* Compute the boot checksums */
428 if (!skipmd5) {
429 puts(bootiso + MD5MSG);
430 md5sum();
431 lseek(fd, 0UL, SEEK_SET);
432 write(fd, bootiso, 512);
433 n = WORD(bootiso + 2) - 512*(WORD(bootiso + 4) - 1);
434 WORD(bootiso + 18) = chksum(0, (unsigned short) n) - 1;
435 }
436 lseek(fd, 0UL, SEEK_SET);
437 write(fd, bootiso, 512);
438 close(fd);
439 status = 0;
440 return SUCCESSMSG;
441 }
443 int main(int argc, char *argv[])
444 {
445 int i;
446 char *s;
448 while (argc > 2) {
449 s = argv[1];
450 if (*s != '-') break;
451 while (*s == '-') s++;
452 switch (*s | 0x20) {
453 case 'a' : append=argv[2]; break;
454 case 'i' : initrd=argv[2]; break;
455 }
456 argv += 2;
457 argc -= 2;
458 }
459 for (i = 2; i < argc; i++) {
460 char *s = argv[i];
461 while ((unsigned)(*s - '-') <= ('/' - '-')) s++;
462 switch (*s | 0x20) {
463 case 'f' : forced++; break;
464 case 'q' : skipmd5++; break;
465 case 'u' : uninstall++; break;
466 }
467 }
468 puts(bootiso + install(argv[1]));
469 if (status > 1)
470 puts(bootiso + FORCEMSG);
471 #ifdef WIN32
472 Sleep(2000);
473 #endif
474 return status;
475 }