wok view syslinux/stuff/iso2exe/iso2exe.c @ rev 19877
syslinux/iso2exe: fix floppyset
author | Pascal Bellard <pascal.bellard@slitaz.org> |
---|---|
date | Fri Mar 31 18:37:37 2017 +0200 (2017-03-31) |
parents | 3432c28d8372 |
children | d33c3c211ef8 |
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 int ftruncate(int fd, long newsize)
14 {
15 if (lseek(fd, newsize, SEEK_SET) != -1L)
16 return write(fd, NULL, 0);
17 return -1;
18 }
19 #endif
20 #ifdef __MINGW32__
21 #define ftruncate chsize
22 #endif
23 #if !defined(__MSDOS__) && !defined(WIN32)
24 #define O_BINARY 0
25 #endif
26 typedef unsigned char uint8_t;
27 typedef unsigned long uint32_t;
28 #include "iso2exe.h"
30 static int fd, forced, uninstall;
31 static unsigned status = 1;
32 static char *append, *initrd;
33 static char tazlitoinfo[0x8000U - BOOTISOSZ];
34 #define buffer tazlitoinfo
35 #define BUFFERSZ 2048
36 #define BYTE(n) * (unsigned char *) (n)
37 #define WORD(n) * (unsigned short *) (n)
38 #define LONG(n) * (unsigned long *) (n)
40 static void readsector(unsigned long sector)
41 {
42 if (lseek(fd, sector * BUFFERSZ, SEEK_SET) == -1 ||
43 read(fd, buffer, BUFFERSZ) != BUFFERSZ) {
44 puts(bootiso+READSECTORERR);
45 exit(1);
46 }
47 }
49 static unsigned long getcustomsector(void)
50 {
51 readsector(16UL);
52 return LONG(buffer + 80);
53 }
55 static int skipmd5 = 0;
56 #define ALIGN1
58 typedef struct {
59 uint32_t l;
60 uint32_t h;
61 } uint64_t;
62 static uint8_t wbuffer[64]; /* always correctly aligned for uint64_t */
63 static uint64_t total64; /* must be directly before hash[] */
64 static uint32_t hash[8]; /* 4 elements for md5, 5 for sha1, 8 for sha256 */
66 /* #define rotl32(x,n) (((x) << (n)) | ((x) >> (32 - (n)))) */
67 static uint32_t rotl32(uint32_t x, unsigned n)
68 {
69 return (x << n) | (x >> (32 - n));
70 }
72 static void md5_process_block64(void);
74 /* Feed data through a temporary buffer.
75 * The internal buffer remembers previous data until it has 64
76 * bytes worth to pass on.
77 */
78 static void common64_hash(const void *buffer, size_t len)
79 {
80 unsigned bufpos = total64.l & 63;
82 total64.l += len; if (total64.l < len) total64.h++;
84 while (1) {
85 unsigned remaining = 64 - bufpos;
86 if (remaining > len)
87 remaining = len;
88 /* Copy data into aligned buffer */
89 memcpy(wbuffer + bufpos, buffer, remaining);
90 len -= remaining;
91 buffer = (const char *)buffer + remaining;
92 bufpos += remaining;
93 /* clever way to do "if (bufpos != 64) break; ... ; bufpos = 0;" */
94 bufpos -= 64;
95 if (bufpos != 0)
96 break;
97 /* Buffer is filled up, process it */
98 md5_process_block64();
99 /*bufpos = 0; - already is */
100 }
101 }
103 /* Process the remaining bytes in the buffer */
104 static void common64_end(void)
105 {
106 unsigned bufpos = total64.l & 63;
107 /* Pad the buffer to the next 64-byte boundary with 0x80,0,0,0... */
108 wbuffer[bufpos++] = 0x80;
110 /* This loop iterates either once or twice, no more, no less */
111 while (1) {
112 unsigned remaining = 64 - bufpos;
113 memset(wbuffer + bufpos, 0, remaining);
114 /* Do we have enough space for the length count? */
115 if (remaining >= 8) {
116 /* Store the 64-bit counter of bits in the buffer */
117 /* uint64_t t = total64 << 3; */
118 uint32_t *t = (uint32_t *) (&wbuffer[64 - 8]);
119 /* wbuffer is suitably aligned for this */
120 /* *(uint64_t *) (&wbuffer[64 - 8]) = t; */
121 t[0] = total64.l << 3;
122 t[1] = (total64.h << 3) | (total64.l >> 29);
123 }
124 md5_process_block64();
125 if (remaining >= 8)
126 break;
127 bufpos = 0;
128 }
129 }
131 /* These are the four functions used in the four steps of the MD5 algorithm
132 * and defined in the RFC 1321. The first function is a little bit optimized
133 * (as found in Colin Plumbs public domain implementation).
134 * #define FF(b, c, d) ((b & c) | (~b & d))
135 */
136 #undef FF
137 #undef FG
138 #undef FH
139 #undef FI
140 #define FF(b, c, d) (d ^ (b & (c ^ d)))
141 #define FG(b, c, d) FF(d, b, c)
142 #define FH(b, c, d) (b ^ c ^ d)
143 #define FI(b, c, d) (c ^ (b | ~d))
145 /* Hash a single block, 64 bytes long and 4-byte aligned */
146 static void md5_process_block64(void)
147 {
148 uint32_t *words = (void*) wbuffer;
149 uint32_t A = hash[0];
150 uint32_t B = hash[1];
151 uint32_t C = hash[2];
152 uint32_t D = hash[3];
154 const uint32_t *pc;
155 const char *pp;
156 const char *ps;
157 int i;
158 uint32_t temp;
161 pc = C_array;
162 pp = P_array;
163 ps = S_array - 4;
165 for (i = 0; i < 64; i++) {
166 if ((i & 0x0f) == 0)
167 ps += 4;
168 temp = A;
169 switch (i >> 4) {
170 case 0:
171 temp += FF(B, C, D);
172 break;
173 case 1:
174 temp += FG(B, C, D);
175 break;
176 case 2:
177 temp += FH(B, C, D);
178 break;
179 case 3:
180 temp += FI(B, C, D);
181 }
182 temp += words[(int) (*pp++)] + *pc++;
183 temp = rotl32(temp, ps[i & 3]);
184 temp += B;
185 A = D;
186 D = C;
187 C = B;
188 B = temp;
189 }
190 /* Add checksum to the starting values */
191 hash[0] += A;
192 hash[1] += B;
193 hash[2] += C;
194 hash[3] += D;
196 }
197 #undef FF
198 #undef FG
199 #undef FH
200 #undef FI
202 /* Initialize structure containing state of computation.
203 * (RFC 1321, 3.3: Step 3)
204 */
205 static void md5_begin(void)
206 {
207 hash[0] = 0x67452301;
208 hash[1] = 0xefcdab89;
209 hash[2] = 0x98badcfe;
210 hash[3] = 0x10325476;
211 total64.l = total64.h = 0;
212 }
214 /* Used also for sha1 and sha256 */
215 #define md5_hash common64_hash
217 /* Process the remaining bytes in the buffer and put result from CTX
218 * in first 16 bytes following RESBUF. The result is always in little
219 * endian byte order, so that a byte-wise output yields to the wanted
220 * ASCII representation of the message digest.
221 */
222 #define md5_end common64_end
224 static int writenhash(void *buffer, size_t len)
225 {
226 md5_hash(buffer, len);
227 return write(fd, buffer, len);
228 }
230 static void md5sum(void)
231 {
232 unsigned long sectors = 0;
233 int count;
235 lseek(fd, 32768UL, SEEK_SET);
237 md5_begin();
238 while ((count = read(fd, buffer, BUFFERSZ)) > 0) {
239 if (sectors == 0)
240 sectors = LONG(buffer + 80) - 16UL;
241 md5_hash(buffer, count);
242 if (--sectors == 0)
243 break;
244 }
246 if (count < 0)
247 return;
249 md5_end();
251 lseek(fd, 32752UL, SEEK_SET);
252 write(fd, hash, 16);
253 memcpy(bootiso + BOOTISOSZ - 16, hash, 16);
254 }
256 static unsigned chksum(unsigned start, unsigned stop)
257 {
258 unsigned i, n = 0;
260 lseek(fd, 0UL /* (unsigned long) (start / BUFFERSZ) */, SEEK_SET);
261 while (1) {
262 if (read(fd, buffer, BUFFERSZ) != BUFFERSZ)
263 return 0;
264 for (i = start % BUFFERSZ; i < BUFFERSZ; i += 2, start += 2) {
265 if (start >= stop)
266 return - n;
267 n += WORD(buffer + i);
268 }
269 }
270 }
272 static unsigned clear_config(unsigned i)
273 {
274 for (;i % 512; i++) {
275 /* clear custom config */
276 write(fd, buffer + 2048, 2048);
277 }
278 return i;
279 }
281 static unsigned install(char *filename)
282 {
283 #define heads 64
284 #define sectors 32
285 #define partition (446+16)
286 #define trksz (512UL * heads * sectors)
287 unsigned long size, catalog, lba;
288 int cylinders, i, j, isohybrid;
289 unsigned n;
290 if (!filename)
291 return USAGE;
292 fd = open(filename,O_RDWR|O_BINARY);
293 if (fd == -1)
294 return OPENERR;
296 if (uninstall) {
297 struct { char check[sizeof(tazlitoinfo) - BUFFERSZ - 1024]; };
298 readsector(0UL);
299 n = BUFFERSZ; /* fill with zeros */
300 if (WORD(buffer) == 23117) {
301 /* restore isolinux hybrid boot */
302 readsector((unsigned long) buffer[417]);
303 n = 0; /* fill with hybrid boot */
304 }
305 lseek(fd, 0UL, SEEK_SET);
306 for (i = 0; i < 32; i++, n = BUFFERSZ) {
307 write(fd, buffer + n, BUFFERSZ);
308 }
309 lseek(fd, getcustomsector() << 11, SEEK_SET);
310 i = clear_config(i);
311 ftruncate(fd, i * 2048UL);
312 close(fd);
313 status = 0;
314 return UNINSTALLMSG;
315 }
317 readsector(0UL);
318 if (buffer[0] == 'M' && buffer[1] == 'Z') {
319 if (forced == 0)
320 return ALREADYEXEERR;
321 n = (buffer[417] + 1) * 512;
322 i = 0x8000 - 1024;
323 if (i > sizeof(tazlitoinfo))
324 i = sizeof(tazlitoinfo);
325 if (lseek(fd, n, SEEK_SET) == -1 ||
326 read(fd, tazlitoinfo, sizeof(tazlitoinfo)) != sizeof(tazlitoinfo) ||
327 lseek(fd, 1024UL, SEEK_SET) == -1 ||
328 write(fd, tazlitoinfo, i) != i) {
329 puts(bootiso+READSECTORERR);
330 exit(1);
331 }
332 }
334 do {
335 /* Install hybridiso boot sector */
336 readsector(17UL);
337 status = ELTORITOERR;
338 if (strncmp(buffer+7, bootiso+ELTORITOERR+ELTORITOOFS, 23))
339 break;
340 catalog = LONG(buffer + 71);
341 readsector(catalog);
342 status = CATALOGERR;
343 if (LONG(buffer) != 1 || LONG(buffer + 30) != 0x88AA55UL)
344 break;
345 lba = LONG(buffer + 40);
346 readsector(lba);
347 status = HYBRIDERR;
348 if (LONG(buffer + 64) != 1886961915UL)
349 break;
350 isohybrid = bootiso[417] * 512;
351 LONG(bootiso + isohybrid + 432) = lba * 4;
352 LONG(bootiso + isohybrid + 440) = rand();
353 LONG(bootiso + isohybrid + partition) = 0x10080UL;
354 WORD(bootiso + isohybrid + 510) = 0xAA55U;
355 #if 0
356 size = lseek(fd, 0UL, SEEK_END);
357 size += 0x000FFFFFUL;
358 size &= 0xFFF00000UL;
359 #else
360 for (size = 0x000FFFFFUL; /* 1M - 1 */
361 read(fd, tazlitoinfo, 1024) == 1024;
362 size += 1024);
363 size &= 0xFFF00000UL; /* round */
364 #endif
365 cylinders = (size >> 20) - 1;
366 bootiso[isohybrid + partition + 4] = 23; /* "Windows hidden IFS" */
367 bootiso[isohybrid + partition + 5] = heads - 1;
368 bootiso[isohybrid + partition + 6] = ((cylinders & 0x300) >> 2) + sectors;
369 bootiso[isohybrid + partition + 7] = cylinders & 0xFF;
370 LONG(bootiso + isohybrid + partition + 8) = 0;
371 LONG(bootiso + isohybrid + partition + 12) = (size >> 9);
373 /* Copy the partition table */
374 memcpy(bootiso + 0x1BE, bootiso + isohybrid + 0x1BE, 66);
375 status = 0;
376 } while (0);
378 if (forced == 0 && status)
379 return status;
381 status = 1;
382 if (append || initrd) {
383 unsigned long pos = getcustomsector() * 2048UL;
384 lseek(fd, pos, SEEK_SET);
385 clear_config(pos);
386 lseek(fd, pos, SEEK_SET);
387 write(fd, bootiso+CUSTOM_HEADER, 40);
388 n = pos + 40;
389 md5_begin();
390 if (append) {
391 i = strlen(append);
392 writenhash(bootiso+CMDLINE_TAG, 7);
393 writenhash(append, i);
394 writenhash("\n", 1);
395 n += i + 8;
396 }
397 if (initrd) {
398 char number[16], *p;
399 unsigned long end, x;
400 int data = open(initrd,O_RDONLY|O_BINARY);
401 if (data == -1)
402 return OPENINITRDERR;
403 for (end = 0;; end += i) {
404 i = read(data, buffer, BUFFERSZ);
405 if (i <= 0)
406 break;
407 }
408 p = number + sizeof(number) -1;
409 x = end; *p-- = '\n';
410 do {
411 *p-- = '0' + (x % 10);
412 x /= 10;
413 } while (x);
414 if (*++p != '0') {
415 writenhash(bootiso+INITRD_TAG, 7);
416 i = number - p + sizeof(number);
417 writenhash(p, i);
418 n += i + 7;
419 lseek(data, 0UL, SEEK_SET);
420 do {
421 i = read(data, buffer, BUFFERSZ);
422 if (i <= 0)
423 break;
424 if (i > end)
425 i = end;
426 writenhash(buffer, i);
427 n += i;
428 end -= i;
429 } while (end != 0);
430 }
431 close(data);
432 }
433 while (n & 0x000FFFFFUL) {
434 unsigned long i = 0x100000UL - (n & 0x000FFFFFUL);
435 if (i > BUFFERSZ)
436 i = BUFFERSZ;
437 i = write(fd, buffer + BUFFERSZ, i);
438 if (i <= 0)
439 break;
440 n += i;
441 }
442 ftruncate(fd, n);
443 md5_end();
444 {
445 static char h[] = "0123456789abcdef";
446 char string[32], *s = string + 30;
447 unsigned char *p = (void *) hash;
449 lseek(fd, 7 + pos, SEEK_SET);
450 for (p += 15; s >= string; p--, s -= 2) {
451 s[1] = h[ *p & 15 ];
452 s[0] = h[ *p >> 4 ];
453 }
454 write(fd, string, 32);
455 }
457 /* Update partition size */
458 n = 1+((n - 1) >> 20);
459 BYTE(bootiso + partition + 7) =
460 BYTE(bootiso + isohybrid + partition + 7) = n -1;
461 LONG(bootiso + partition + 12) =
462 LONG(bootiso + isohybrid + partition + 12) = n * 2048;
463 }
465 /* Install iso2exe boot sector */
466 LONG(bootiso + 440) = time(NULL);
468 /* read tazlito flavor data */
469 lseek(fd, 1024UL, SEEK_SET);
470 read(fd, tazlitoinfo, sizeof(tazlitoinfo));
472 /* Update iso image */
473 n = (bootiso[417] + 1) * 512;
474 lseek(fd, 0UL, SEEK_SET);
475 write(fd, bootiso, n); /* EXE/PE + isohybrid mbr */
476 write(fd, tazlitoinfo, sizeof(tazlitoinfo));
477 write(fd, bootiso + n, BOOTISOSZ - n); /* COM + rootfs + EXE/DOS */
479 /* Compute the boot checksums */
480 if (!skipmd5) {
481 puts(bootiso + MD5MSG);
482 md5sum();
483 lseek(fd, 0UL, SEEK_SET);
484 write(fd, bootiso, 512);
485 n = WORD(bootiso + 2) - 512*(WORD(bootiso + 4) - 1);
486 WORD(bootiso + 18) = chksum(0, (unsigned short) n) - 1;
487 }
488 lseek(fd, 0UL, SEEK_SET);
489 write(fd, bootiso, 512);
490 close(fd);
491 status = 0;
492 return SUCCESSMSG;
493 }
495 static unsigned short files[] = {
496 WIN32_EXE, /* 0 */
497 SYSLINUX_MBR, /* 1 */
498 FLAVOR_INFO, /* 2 */
499 FLOPPY_BOOT, /* 3 */
500 TAZBOOT_COM, /* 4 */
501 ROOTFS_GZ, /* 5 */
502 DOSSTUB, /* 6 */
503 BOOT_MD5, /* 7 */
504 FS_ISO, /* 8 */
505 CUSTOM_MAGIC, /* 9 */
506 CUSTOM_APPEND, /* 10 */
507 CUSTOM_INITRD /* 11 */
508 };
510 static long file_offset, file_size;
511 static void fileofs(int number)
512 {
513 unsigned long i, c, stub;
514 char *s;
516 c = getcustomsector();
517 readsector(0UL);
518 i = 1024;
519 if (WORD(buffer+1024) != 35615) i = 512 * (1 + BYTE(buffer+417));
520 stub = WORD(buffer+20) - 0xC0;
521 file_size = file_offset = 0;
522 switch (files[number]) {
523 case WIN32_EXE: /* win32.exe */
524 if (i != 1024) file_size = i - 512; break;
525 case SYSLINUX_MBR: /* syslinux.mbr */
526 if (i != 1024) file_offset = i - 512;
527 file_size = 512; break;
528 case FLAVOR_INFO: /* flavor.info */
529 file_offset = i; file_size = 0; break;
530 case FLOPPY_BOOT: /* floppy.boot */
531 file_size = BYTE(buffer+26)*512;
532 file_offset = WORD(buffer+64) - 0xC0 - file_size; break;
533 case TAZBOOT_COM: /* tazboot.com */
534 file_offset = WORD(buffer+64) - 0xC0;
535 file_size = stub - WORD(buffer+24) - file_offset; break;
536 case ROOTFS_GZ: /* rootfs.gz */
537 file_size = WORD(buffer+24);
538 file_offset = stub - file_size; break;
539 case DOSSTUB: /* dosstub */
540 file_offset = stub;
541 file_size = 0x8000U - file_offset; break;
542 case BOOT_MD5: /* boot.md5 */
543 file_offset = 0x7FF0U; file_size = 16; break;
544 case FS_ISO: /* fs.iso */
545 file_offset = 0x8000U; file_size = 2048*c - file_offset; break;
546 case CUSTOM_MAGIC: /* custom.magic */
547 readsector(c);
548 if (!strncmp(buffer, bootiso+CUSTOM_HEADER, 6)) {
549 file_size = 39; file_offset = 2048*c;
550 }; break;
551 case CUSTOM_APPEND: /* custom.append */
552 readsector(c);
553 file_offset = 2048*c + 47; s = strstr(buffer, "append=");
554 if (s) file_size = strchr(s,'\n') - s - 7;
555 break;
556 case CUSTOM_INITRD: /* custom.initrd */
557 readsector(c);
558 s = strstr(buffer,"initrd:");
559 if (!s) break;
560 file_size = atoi(s + 7);
561 s = strchr(s,'\n') + 1;
562 file_offset = 2048*c + (s - buffer);
563 }
564 }
566 static long heap = 0;
567 static void show_free(void)
568 {
569 if (file_offset > heap && (file_offset - heap) > 16)
570 printf(bootiso + FREE_FORMAT, file_offset - heap,
571 heap, file_offset);
572 }
574 static void list(void)
575 {
576 int num;
578 for (num = 0; num < sizeof(files)/sizeof(files[0]); num++) {
579 fileofs(num);
580 if (file_size <= 0 || file_offset > 0x3FFFFFFFUL) continue;
581 readsector(file_offset / 2048);
582 if (WORD(buffer + file_offset % 2048) == 0) continue;
583 show_free();
584 if (file_offset >= heap) heap = file_offset + file_size;
585 printf(bootiso + USED_FORMAT, bootiso + files[num],
586 file_offset, file_size);
587 }
588 #ifdef __MSDOS__
589 file_offset = (heap + 0xFFFFFUL) & 0xFFF00000UL;
590 #else
591 file_offset=lseek(fd, 0UL, SEEK_END);
592 #endif
593 show_free();
594 }
596 static void extract(char *name)
597 {
598 int num;
600 for (num = sizeof(files)/sizeof(files[0]) - 1;
601 strcmp(name,bootiso + files[num]); num--) if (num <= 0) return;
602 fileofs(num);
603 if (file_size == 0) return;
604 lseek(fd, file_offset, SEEK_SET);
605 num = open(name, O_WRONLY|O_BINARY|O_CREAT, 0x644);
606 while (file_size > 0) {
607 int n = read(fd, buffer, BUFFERSZ);
608 if (n <= 0) break;
609 if (n > file_size) n = file_size;
610 write(num,buffer,n);
611 file_size -= n;
612 }
613 close(num);
614 }
616 int main(int argc, char *argv[])
617 {
618 int i;
619 char *s;
621 data_fixup();
622 for (i = 0; argc > 2;) {
623 s = argv[1];
624 if (*s != '-') break;
625 while (*s == '-') s++;
626 switch (*s | 0x20) {
627 case 'a' : append=argv[2]; break;
628 case 'i' : initrd=argv[2]; break;
629 case 'r' : case 'l' :
630 i++; argv++; argc--; continue;
631 }
632 argv += 2;
633 argc -= 2;
634 }
635 if (i != 0) {
636 fd = open(argv[i],O_RDONLY|O_BINARY);
637 if (fd == -1) puts(bootiso + OPENERR);
638 else if (argc <= 2) list();
639 else for (i = 2; i < argc; i++) extract(argv[i]);
640 return 0;
641 }
642 for (i = 2; i < argc; i++) {
643 char *s = argv[i];
644 while ((unsigned)(*s - '-') <= ('/' - '-')) s++;
645 switch (*s | 0x20) {
646 case 'f' : forced++; break;
647 case 'q' : skipmd5++; break;
648 case 'u' : uninstall++; break;
649 }
650 }
651 puts(bootiso + install(argv[1]));
652 if (status > 1)
653 puts(bootiso + FORCEMSG);
654 #ifdef WIN32
655 Sleep(2000);
656 #endif
657 return status;
658 }