Author: hbelusca
Date: Wed Sep 9 02:11:49 2015
New Revision: 69139
URL:
http://svn.reactos.org/svn/reactos?rev=69139&view=rev
Log:
OMGWTFBBQ!!!! We can now boot our ISOs on UEFI systems!!
Thanks gigaherz for the "fatten" utility!, and others for testing.
[CDMAKE]
- Add multi-boot CD support, following El-Torito specification, such that we can the usual
ISO boot sector on BIOS-based PCs, and the UEFI loader on UEFI-based PCs.
- Load segment should be stored in little endian.
- Fix the computation of the sector count (count in 512 byte sectors and rounded up).
- Rework the command-line options to make them more compatible with CDIMAGE / OSCDIMG.
CORE-10120
[BOOTDATA]
- Activate the UEFI boot support for our ISOs.
Modified:
trunk/reactos/boot/CMakeLists.txt
trunk/reactos/tools/cdmake/cdmake.c
trunk/reactos/tools/cdmake/config.h
trunk/reactos/tools/cdmake/dirhash.c
trunk/reactos/tools/cdmake/dirhash.h
Modified: trunk/reactos/boot/CMakeLists.txt
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/boot/CMakeLists.txt?rev=69…
==============================================================================
--- trunk/reactos/boot/CMakeLists.txt [iso-8859-1] (original)
+++ trunk/reactos/boot/CMakeLists.txt [iso-8859-1] Wed Sep 9 02:11:49 2015
@@ -16,7 +16,7 @@
endif()
add_custom_target(efisys
- COMMAND native-fatten ${CMAKE_CURRENT_BINARY_DIR}/efisys.bin -format 2880 -boot
${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/fat.bin -mkdir EFI -mkdir EFI/BOOT -add
$<TARGET_FILE:bootmgfw> EFI/BOOT/boot${EFI_PLATFORM_ID}.EFI
+ COMMAND native-fatten ${CMAKE_CURRENT_BINARY_DIR}/efisys.bin -format 2880 -boot
${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/fat.bin -mkdir EFI -mkdir EFI/BOOT -add
$<TARGET_FILE:bootmgfw> EFI/BOOT/boot${EFI_PLATFORM_ID}.efi
DEPENDS native-fatten bootmgfw fat
VERBATIM)
@@ -25,8 +25,7 @@
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bootcd.lst "")
add_custom_target(bootcd
-# COMMAND native-cdmake -j -m
-bootdata:2\#p0,e,b${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/isoboot.bin\#pEF,e,b${CMAKE_CURRENT_BINARY_DIR}/efisys.bin
@${CMAKE_CURRENT_BINARY_DIR}/bootcd.lst REACTOS ${REACTOS_BINARY_DIR}/bootcd.iso
- COMMAND native-cdmake -j -m -b
${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/isoboot.bin
@${CMAKE_CURRENT_BINARY_DIR}/bootcd.lst REACTOS ${REACTOS_BINARY_DIR}/bootcd.iso
+ COMMAND native-cdmake -j -m
-bootdata:2\#p0,e,b${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/isoboot.bin\#pEF,e,b${CMAKE_CURRENT_BINARY_DIR}/efisys.bin
@${CMAKE_CURRENT_BINARY_DIR}/bootcd.lst REACTOS ${REACTOS_BINARY_DIR}/bootcd.iso
DEPENDS native-cdmake efisys
VERBATIM)
@@ -35,8 +34,8 @@
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bootcdregtest.lst "")
add_custom_target(bootcdregtest
- COMMAND native-cdmake -j -m -b
${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/isobtrt.bin
@${CMAKE_CURRENT_BINARY_DIR}/bootcdregtest.lst REACTOS
${REACTOS_BINARY_DIR}/bootcdregtest.iso
- DEPENDS native-cdmake
+ COMMAND native-cdmake -j -m
-bootdata:2\#p0,e,b${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/isobtrt.bin\#pEF,e,b${CMAKE_CURRENT_BINARY_DIR}/efisys.bin
@${CMAKE_CURRENT_BINARY_DIR}/bootcdregtest.lst REACTOS
${REACTOS_BINARY_DIR}/bootcdregtest.iso
+ DEPENDS native-cdmake efisys
VERBATIM)
##livecd
@@ -49,8 +48,8 @@
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/livecd.lst "Profiles/Default User/Start
Menu/Programs\n")
add_custom_target(livecd
- COMMAND native-cdmake -j -m -b
${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/isoboot.bin
@${CMAKE_CURRENT_BINARY_DIR}/livecd.lst REACTOS ${REACTOS_BINARY_DIR}/livecd.iso
- DEPENDS native-cdmake
+ COMMAND native-cdmake -j -m
-bootdata:2\#p0,e,b${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/isoboot.bin\#pEF,e,b${CMAKE_CURRENT_BINARY_DIR}/efisys.bin
@${CMAKE_CURRENT_BINARY_DIR}/livecd.lst REACTOS ${REACTOS_BINARY_DIR}/livecd.iso
+ DEPENDS native-cdmake efisys
VERBATIM)
##hybridcd
@@ -63,11 +62,10 @@
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/hybridcd.lst "livecd/Profiles/Default
User/Start Menu/Programs\n")
add_custom_target(hybridcd
- COMMAND native-cdmake -j -m -b
${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/isoboot.bin
@${CMAKE_CURRENT_BINARY_DIR}/hybridcd.lst REACTOS ${REACTOS_BINARY_DIR}/hybridcd.iso
- DEPENDS native-cdmake bootcd livecd
+ COMMAND native-cdmake -j -m
-bootdata:2\#p0,e,b${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/isoboot.bin\#pEF,e,b${CMAKE_CURRENT_BINARY_DIR}/efisys.bin
@${CMAKE_CURRENT_BINARY_DIR}/hybridcd.lst REACTOS ${REACTOS_BINARY_DIR}/hybridcd.iso
+ DEPENDS native-cdmake efisys bootcd livecd
VERBATIM)
add_subdirectory(freeldr)
add_subdirectory(bootdata)
add_subdirectory(environ)
-
Modified: trunk/reactos/tools/cdmake/cdmake.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/tools/cdmake/cdmake.c?rev=…
==============================================================================
--- trunk/reactos/tools/cdmake/cdmake.c [iso-8859-1] (original)
+++ trunk/reactos/tools/cdmake/cdmake.c [iso-8859-1] Wed Sep 9 02:11:49 2015
@@ -68,6 +68,7 @@
#include "config.h"
#include "dirhash.h"
+// FIXME! FIXME! Do it in a portable way!!
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
@@ -83,8 +84,8 @@
#define SECTOR_SIZE 2048
#define BUFFER_SIZE (8 * SECTOR_SIZE)
-const BYTE HIDDEN_FLAG = 1;
-const BYTE DIRECTORY_FLAG = 2;
+#define HIDDEN_FLAG 1
+#define DIRECTORY_FLAG 2
struct cd_image
@@ -96,6 +97,35 @@
char filespecs[128];
BYTE *buffer;
};
+
+typedef struct _boot_validation_header
+{
+ BYTE header_id;
+ BYTE platform_id;
+} BOOT_VALIDATION_HEADER, *PBOOT_VALIDATION_HEADER;
+
+typedef struct boot_entry
+{
+ struct boot_entry *next_entry;
+ BYTE boot_id;
+ BYTE boot_emu_type;
+ WORD load_segment;
+ BYTE system_type;
+ WORD sector_count; // boot_image_size
+ DWORD load_rba; // boot_image_sector
+ // BYTE unused[20];
+ char bootimage[512];
+} BOOT_ENTRY, *PBOOT_ENTRY;
+
+typedef struct boot_header
+{
+ struct boot_header *next_header;
+ BYTE header_id;
+ BYTE platform_id;
+ WORD num_entries;
+ // char id_string[28];
+ PBOOT_ENTRY entry_list;
+} BOOT_HEADER, *PBOOT_HEADER;
typedef struct date_and_time
{
@@ -166,11 +196,12 @@
DWORD number_of_directories;
DWORD bytes_in_directories;
-BOOL eltorito;
+BOOL eltorito; // TRUE/FALSE: bootable/non-bootable CD-ROM
+BOOL multi_boot; // TRUE/FALSE: multi/single-boot CD-ROM
DWORD boot_catalog_sector;
-DWORD boot_image_sector;
-WORD boot_image_size; // counted in 512 byte sectors
-char bootimage[512];
+BOOT_VALIDATION_HEADER boot_validation_header;
+BOOT_ENTRY default_boot_entry;
+PBOOT_HEADER boot_header_list;
BOOL joliet;
DWORD joliet_path_table_size;
@@ -213,10 +244,24 @@
static void release_memory(void)
{
+ while (boot_header_list)
+ {
+ PBOOT_HEADER next_header = boot_header_list->next_header;
+
+ while (boot_header_list->entry_list)
+ {
+ PBOOT_ENTRY next_entry = boot_header_list->entry_list->next_entry;
+ free(boot_header_list->entry_list);
+ boot_header_list->entry_list = next_entry;
+ }
+
+ free(boot_header_list);
+ boot_header_list = next_header;
+ }
+
while (root.next_in_memory != NULL)
{
- struct directory_record *next =
- root.next_in_memory->next_in_memory;
+ PDIR_RECORD next = root.next_in_memory->next_in_memory;
if (joliet)
free(root.next_in_memory->joliet_name);
free(root.next_in_memory);
@@ -224,6 +269,7 @@
}
if (joliet)
free(root.joliet_name);
+
if (cd.buffer != NULL)
{
free(cd.buffer);
@@ -236,7 +282,7 @@
error exit point in main().
-----------------------------------------------------------------------------*/
-void error_exit(const char* fmt, ...)
+static void error_exit(const char* fmt, ...)
{
va_list arg;
@@ -356,7 +402,7 @@
write_byte(*s++);
}
-static void write_bytecounted_string(unsigned bytecount, char *s)
+static void write_bytecounted_string(unsigned bytecount, char *s, char padding)
{
while (*s != 0 && bytecount != 0)
{
@@ -365,7 +411,7 @@
}
while (bytecount != 0)
{
- write_byte(' ');
+ write_byte(padding);
bytecount--;
}
}
@@ -383,7 +429,7 @@
}
}
-static void write_bytecounted_string_as_big_endian_unicode(unsigned bytecount, char *s)
+static void write_bytecounted_string_as_big_endian_unicode(unsigned bytecount, char *s,
char padding)
{
unsigned wordcount = bytecount / 2;
@@ -394,12 +440,12 @@
}
while (wordcount != 0)
{
- write_big_endian_word(' ');
+ write_big_endian_word(padding);
wordcount--;
}
if (bytecount % 2 != 0)
- write_byte(' ');
+ write_byte(padding);
}
/*-----------------------------------------------------------------------------
@@ -497,7 +543,7 @@
write_byte(d->flags);
write_byte(0); // file unit size for an interleaved file
write_byte(0); // interleave gap size for an interleaved file
- write_both_endian_word((WORD) 1); // volume sequence number
+ write_both_endian_word(1); // volume sequence number
write_byte((BYTE)identifier_size);
switch (DirType)
{
@@ -575,7 +621,7 @@
#define strcasecmp stricmp
#endif//_WIN32
-BOOL cdname_exists(PDIR_RECORD d)
+static BOOL cdname_exists(PDIR_RECORD d)
{
PDIR_RECORD p = d->parent->first_record;
while (p)
@@ -589,7 +635,7 @@
return FALSE;
}
-void parse_filename_into_dirrecord(const char* filename, PDIR_RECORD d, BOOL dir)
+static void parse_filename_into_dirrecord(const char* filename, PDIR_RECORD d, BOOL dir)
{
const char *s = filename;
char *t = d->name_on_cd;
@@ -608,7 +654,8 @@
if ((size_t)(t-d->name_on_cd) < sizeof(d->name_on_cd)-1)
*t++ = check_for_punctuation(*s, filename);
else if (!joliet)
- error_exit("'%s' is not ISO-9660, aborting...", filename);
+ error_exit("'%s' is not ISO-9660, aborting...", filename);
+
if ((size_t)(n-d->name) < sizeof(d->name)-1)
*n++ = *s;
else if (!joliet)
@@ -914,7 +961,7 @@
else
{
if (!getcwd(buf, sizeof(buf)))
- error_exit("Can't get CWD: %s\n",
strerror(errno));
+ error_exit("Cannot get CWD: %s\n", strerror(errno));
strcat(buf, DIR_SEPARATOR_STRING);
strcat(buf, source);
strcat(buf, entry->d_name);
@@ -922,7 +969,7 @@
if (stat(buf, &stbuf) == -1)
{
- error_exit("Can't access '%s' (%s)\n", buf,
strerror(errno));
+ error_exit("Cannot access '%s' (%s)\n", buf,
strerror(errno));
return;
}
@@ -944,7 +991,7 @@
}
else
{
- error_exit("Can't open %s\n", source);
+ error_exit("Cannot open %s\n", source);
return;
}
@@ -976,14 +1023,14 @@
else
{
if (!getcwd(buf, sizeof(buf)))
- error_exit("Can't get CWD: %s\n",
strerror(errno));
+ error_exit("Cannot get CWD: %s\n",
strerror(errno));
strcat(buf, DIR_SEPARATOR_STRING);
strcat(buf, source);
}
if (stat(buf, &stbuf) == -1)
{
- error_exit("Can't access '%s' (%s)\n", buf,
strerror(errno));
+ error_exit("Cannot access '%s' (%s)\n", buf,
strerror(errno));
return;
}
new_d = new_directory_record(entry, &stbuf, d);
@@ -1004,7 +1051,7 @@
}
else
{
- error_exit("Can't open %s\n", source);
+ error_exit("Cannot open %s\n", source);
return;
}
@@ -1028,7 +1075,7 @@
else
{
if (!getcwd(buf, sizeof(buf)))
- error_exit("Can't get CWD: %s\n", strerror(errno));
+ error_exit("Cannot get CWD: %s\n", strerror(errno));
strcat(buf, DIR_SEPARATOR_STRING);
strcat(buf, source);
strcat(buf, entry->d_name);
@@ -1036,7 +1083,7 @@
if (stat(buf, &stbuf) == -1)
{
- error_exit("Can't access '%s' (%s)\n", buf,
strerror(errno));
+ error_exit("Cannot access '%s' (%s)\n", buf,
strerror(errno));
return;
}
@@ -1087,7 +1134,7 @@
}
else
{
- error_exit("Can't open %s\n", source);
+ error_exit("Cannot open %s\n", source);
return;
}
@@ -1172,18 +1219,18 @@
FILE_ATTRIBUTE_NORMAL,
NULL)) == INVALID_HANDLE_VALUE)
{
- error_exit("Can't open timestamp file %s\n",
file->source_name);
+ error_exit("Cannot open timestamp file %s\n",
file->source_name);
}
if (!get_cd_file_time(open_file, &d->date_and_time))
{
- error_exit("Can't stat timestamp file %s\n",
file->source_name);
+ error_exit("Cannot stat timestamp file %s\n",
file->source_name);
}
CloseHandle(open_file);
#else
if (stat(file->target_name, &stbuf) == -1)
{
- error_exit("Can't stat timestamp file %s\n",
file->source_name);
+ error_exit("Cannot stat timestamp file %s\n",
file->source_name);
}
convert_date_and_time(&d->date_and_time, &stbuf.st_ctime);
#endif
@@ -1208,15 +1255,15 @@
FILE_ATTRIBUTE_NORMAL,
NULL)) == INVALID_HANDLE_VALUE)
{
- error_exit("Can't open file %s\n", file->source_name);
+ error_exit("Cannot open file %s\n", file->source_name);
}
if (!get_cd_file_time(open_file, &new_d->date_and_time))
{
- error_exit("Can't stat file %s\n", file->source_name);
+ error_exit("Cannot stat file %s\n", file->source_name);
}
if (!GetFileSizeEx(open_file, &file_size))
{
- error_exit("Can't get file size of %s\n",
file->source_name);
+ error_exit("Cannot get file size of %s\n",
file->source_name);
}
new_d->size = new_d->joliet_size = file_size.QuadPart;
new_d->orig_name = file->source_name;
@@ -1224,7 +1271,7 @@
#else
if (stat(file->source_name, &stbuf) == -1)
{
- error_exit("Can't find '%s' (target %s)\n",
+ error_exit("Cannot find '%s' (target %s)\n",
file->source_name,
file->target_name);
}
@@ -1296,24 +1343,32 @@
static BOOL write_from_file(FILE *file, DWORD size)
{
- int n;
-
- fseek(file, 0, SEEK_SET);
- while (size > 0)
- {
- n = BUFFER_SIZE - cd.count;
- if ((DWORD)n > size)
- n = size;
-
- if (fread(cd.buffer + cd.count, n, 1, file) < 1)
- return FALSE;
-
- cd.count += n;
- if (cd.count == BUFFER_SIZE)
- flush_buffer();
- cd.sector += n / SECTOR_SIZE;
- cd.offset += n % SECTOR_SIZE;
- size -= n;
+ if (cd.file != NULL)
+ {
+ int n;
+
+ fseek(file, 0, SEEK_SET);
+ while (size > 0)
+ {
+ n = BUFFER_SIZE - cd.count;
+ if ((DWORD)n > size)
+ n = size;
+
+ if (fread(cd.buffer + cd.count, n, 1, file) < 1)
+ return FALSE;
+
+ cd.count += n;
+ if (cd.count == BUFFER_SIZE)
+ flush_buffer();
+ cd.sector += n / SECTOR_SIZE;
+ cd.offset += n % SECTOR_SIZE;
+ size -= n;
+ }
+ }
+ else
+ {
+ cd.sector += size / SECTOR_SIZE;
+ cd.offset += size % SECTOR_SIZE;
}
return TRUE;
@@ -1341,30 +1396,30 @@
write_string("\1CD001\1");
write_byte(0);
- write_bytecounted_string(32, ""); // system identifier
- write_bytecounted_string(32, volume_label); // volume label
+ write_bytecounted_string(32, "", ' '); // system
identifier
+ write_bytecounted_string(32, volume_label, ' '); // volume label
write_block(8, 0);
write_both_endian_dword(total_sectors);
write_block(32, 0);
- write_both_endian_word((WORD) 1); // volume set size
- write_both_endian_word((WORD) 1); // volume sequence number
- write_both_endian_word((WORD) 2048); // sector size
+ write_both_endian_word(1); // volume set size
+ write_both_endian_word(1); // volume sequence number
+ write_both_endian_word(2048); // sector size
write_both_endian_dword(path_table_size);
write_little_endian_dword(little_endian_path_table_sector);
- write_little_endian_dword((DWORD) 0); // second little endian path table
+ write_little_endian_dword(0); // second little endian path table
write_big_endian_dword(big_endian_path_table_sector);
- write_big_endian_dword((DWORD) 0); // second big endian path table
+ write_big_endian_dword(0); // second big endian path table
write_directory_record(&root, DOT_RECORD, FALSE);
- write_bytecounted_string(128, volume_label); // volume set identifier
- write_bytecounted_string(128, PUBLISHER_ID); // publisher identifier
- write_bytecounted_string(128, DATA_PREP_ID); // data preparer identifier
- write_bytecounted_string(128, APP_ID); // application identifier
-
- write_bytecounted_string(37, ""); // copyright file identifier
- write_bytecounted_string(37, ""); // abstract file identifier
- write_bytecounted_string(37, ""); // bibliographic file identifier
+ write_bytecounted_string(128, volume_label, ' '); // volume set identifier
+ write_bytecounted_string(128, PUBLISHER_ID, ' '); // publisher identifier
+ write_bytecounted_string(128, DATA_PREP_ID, ' '); // data preparer
identifier
+ write_bytecounted_string(128, APP_ID, ' '); // application identifier
+
+ write_bytecounted_string(37, "", ' '); // copyright file
identifier
+ write_bytecounted_string(37, "", ' '); // abstract file identifier
+ write_bytecounted_string(37, "", ' '); // bibliographic file
identifier
write_string(timestring); // volume creation
write_byte(0);
@@ -1382,10 +1437,9 @@
// Boot Volume Descriptor
if (eltorito)
{
- write_byte(0);
+ write_byte(0); // Boot record ID
write_string("CD001\1");
- write_string("EL TORITO SPECIFICATION"); // identifier
- write_block(9, 0); // padding
+ write_bytecounted_string(32, "EL TORITO SPECIFICATION", 0); //
El-Torito identifier
write_block(32, 0); // unused
write_little_endian_dword(boot_catalog_sector); // pointer to boot catalog
fill_sector();
@@ -1396,31 +1450,31 @@
{
write_string("\2CD001\1");
write_byte(0);
- write_bytecounted_string_as_big_endian_unicode(32, ""); //
system identifier
- write_bytecounted_string_as_big_endian_unicode(32, volume_label); // volume
label
+ write_bytecounted_string_as_big_endian_unicode(32, "", ' ');
// system identifier
+ write_bytecounted_string_as_big_endian_unicode(32, volume_label, ' '); //
volume label
write_block(8, 0);
write_both_endian_dword(total_sectors);
write_string("%/E");
write_block(29, 0);
- write_both_endian_word((WORD) 1); // volume set size
- write_both_endian_word((WORD) 1); // volume sequence number
- write_both_endian_word((WORD) 2048); // sector size
+ write_both_endian_word(1); // volume set size
+ write_both_endian_word(1); // volume sequence number
+ write_both_endian_word(2048); // sector size
write_both_endian_dword(joliet_path_table_size);
write_little_endian_dword(joliet_little_endian_path_table_sector);
- write_little_endian_dword((DWORD) 0); // second little endian path table
+ write_little_endian_dword(0); // second little endian path table
write_big_endian_dword(joliet_big_endian_path_table_sector);
- write_big_endian_dword((DWORD) 0); // second big endian path table
+ write_big_endian_dword(0); // second big endian path table
write_directory_record(&root, DOT_RECORD, TRUE);
- write_bytecounted_string_as_big_endian_unicode(128, volume_label); // volume set
identifier
- write_bytecounted_string_as_big_endian_unicode(128, PUBLISHER_ID); // publisher
identifier
- write_bytecounted_string_as_big_endian_unicode(128, DATA_PREP_ID); // data
preparer identifier
- write_bytecounted_string_as_big_endian_unicode(128, APP_ID); // application
identifier
-
- write_bytecounted_string_as_big_endian_unicode(37, ""); // copyright
file identifier
- write_bytecounted_string_as_big_endian_unicode(37, ""); // abstract
file identifier
- write_bytecounted_string_as_big_endian_unicode(37, ""); //
bibliographic file identifier
+ write_bytecounted_string_as_big_endian_unicode(128, volume_label, ' ');
// volume set identifier
+ write_bytecounted_string_as_big_endian_unicode(128, PUBLISHER_ID, ' ');
// publisher identifier
+ write_bytecounted_string_as_big_endian_unicode(128, DATA_PREP_ID, ' ');
// data preparer identifier
+ write_bytecounted_string_as_big_endian_unicode(128, APP_ID, ' ');
// application identifier
+
+ write_bytecounted_string_as_big_endian_unicode(37, "", ' '); //
copyright file identifier
+ write_bytecounted_string_as_big_endian_unicode(37, "", ' '); //
abstract file identifier
+ write_bytecounted_string_as_big_endian_unicode(37, "", ' '); //
bibliographic file identifier
write_string(timestring); // volume creation
write_byte(0);
@@ -1439,40 +1493,72 @@
write_string("\377CD001\1");
fill_sector();
- // Boot Catalog
+ // Boot Catalog and Images
if (eltorito)
{
+ PBOOT_HEADER header;
+ PBOOT_ENTRY entry;
+
+ // Boot Catalog
+
boot_catalog_sector = cd.sector;
- // Validation entry
- write_byte(1);
- write_byte(0); // x86 boot code
+ // Validation entry header
+ write_byte(boot_validation_header.header_id);
+ write_byte(boot_validation_header.platform_id);
write_little_endian_word(0); // reserved
- write_string("ReactOS Foundation");
- write_block(6, 0); // padding
+ write_bytecounted_string(24, MANUFACTURER_ID, 0); // Manufacturer identifier
write_little_endian_word(0x62E); // checksum // FIXME: This is hardcoded!!
write_little_endian_word(0xAA55); // signature
- // default entry
- write_byte(0x88); // bootable
- write_byte(0); // no emulation
- write_big_endian_word(0); // load segment = default (0x07c0)
+ // Default entry
+ write_byte(default_boot_entry.boot_id);
+ write_byte(default_boot_entry.boot_emu_type);
+ write_little_endian_word(default_boot_entry.load_segment);
write_byte(0); // partition type
write_byte(0); // unused
- write_little_endian_word(boot_image_size); // sector count
- write_little_endian_dword(boot_image_sector); // sector
+ write_little_endian_word(default_boot_entry.sector_count);
+ write_little_endian_dword(default_boot_entry.load_rba);
+ write_block(20, 0); // unused
+
+ // Loop through each boot header
+ header = boot_header_list;
+ while (header)
+ {
+ write_byte(header->header_id);
+ write_byte(header->platform_id);
+ write_little_endian_word(header->num_entries);
+ write_block(28, 0); // Identifier string (unused)
+
+ // Loop through each boot entry
+ entry = header->entry_list;
+ while (entry)
+ {
+ write_byte(entry->boot_id);
+ write_byte(entry->boot_emu_type);
+ write_little_endian_word(entry->load_segment);
+ write_byte(0); // partition type
+ write_byte(0); // unused
+ write_little_endian_word(entry->sector_count);
+ write_little_endian_dword(entry->load_rba);
+ write_block(20, 0); // Selection criteria (unused)
+
+ entry = entry->next_entry;
+ }
+
+ header = header->next_header;
+ }
fill_sector();
- }
-
- // Boot Image
- if (eltorito)
- {
- boot_image_sector = cd.sector;
-
- file = fopen(bootimage, "rb");
+
+
+ // Boot Images
+
+ default_boot_entry.load_rba = cd.sector;
+
+ file = fopen(default_boot_entry.bootimage, "rb");
if (file == NULL)
- error_exit("Can't open %s\n", bootimage);
+ error_exit("Cannot open %s\n", default_boot_entry.bootimage);
fseek(file, 0, SEEK_END);
size = ftell(file);
if (size == 0 || (size % 2048))
@@ -1480,13 +1566,50 @@
fclose(file);
error_exit("Invalid boot image size (%lu bytes)\n", size);
}
- boot_image_size = size / 512;
+ // Sector count in 512 byte sectors and rounded up
+ default_boot_entry.sector_count = (size + 511) / 512;
if (!write_from_file(file, size))
{
fclose(file);
- error_exit("Read error in file %s\n", bootimage);
+ error_exit("Read error in file %s\n",
default_boot_entry.bootimage);
}
fclose(file);
+
+ // Loop through each boot header
+ header = boot_header_list;
+ while (header)
+ {
+ // Loop through each boot entry
+ entry = header->entry_list;
+ while (entry)
+ {
+ entry->load_rba = cd.sector;
+
+ file = fopen(entry->bootimage, "rb");
+ if (file == NULL)
+ error_exit("Cannot open %s\n", entry->bootimage);
+ fseek(file, 0, SEEK_END);
+ size = ftell(file);
+ if (size == 0 || (size % 2048))
+ {
+ fclose(file);
+ error_exit("Invalid boot image size (%lu bytes)\n", size);
+ }
+ // Sector count in 512 byte sectors and rounded up
+ entry->sector_count = (size + 511) / 512;
+ if (!write_from_file(file, size))
+ {
+ fclose(file);
+ error_exit("Read error in file %s\n",
entry->bootimage);
+ }
+ fclose(file);
+
+ entry = entry->next_entry;
+ }
+
+ header = header->next_header;
+ }
+
// fill_sector();
}
@@ -1495,7 +1618,7 @@
write_byte(1);
write_byte(0); // number of sectors in extended attribute record
write_little_endian_dword(root.sector);
- write_little_endian_word((WORD) 1);
+ write_little_endian_word(1);
write_byte(0);
write_byte(0);
@@ -1524,7 +1647,7 @@
write_byte(1);
write_byte(0); // number of sectors in extended attribute record
write_big_endian_dword(root.sector);
- write_big_endian_word((WORD) 1);
+ write_big_endian_word(1);
write_byte(0);
write_byte(0);
@@ -1549,7 +1672,7 @@
write_byte(1);
write_byte(0); // number of sectors in extended attribute record
write_little_endian_dword(root.joliet_sector);
- write_little_endian_word((WORD) 1);
+ write_little_endian_word(1);
write_byte(0);
write_byte(0);
@@ -1573,7 +1696,7 @@
write_byte(1);
write_byte(0); // number of sectors in extended attribute record
write_big_endian_dword(root.joliet_sector);
- write_big_endian_word((WORD) 1);
+ write_big_endian_word(1);
write_byte(0);
write_byte(0);
@@ -1659,7 +1782,7 @@
printf("Writing contents of %s\n", file_source);
file = fopen(file_source, "rb");
if (file == NULL)
- error_exit("Can't open %s\n", file_source);
+ error_exit("Cannot open %s\n", file_source);
if (!write_from_file(file, size))
{
fclose(file);
@@ -1682,32 +1805,79 @@
"Copyright (C) Philip J. Erdelsky\n"
"Copyright (C) 2003-2015 ReactOS Team\n"
"\n\n"
- "CDMAKE [-q] [-v] [-p] [-s N] [-m] [-b bootimage] [-j] source volume
image\n"
+ "CDMAKE [-vN] [-p] [-s N] [-m] [-j] [-pN] [-eN] [-b bootimage]\n"
+ "
[-bootdata:N#<defaultBootEntry>#<bootEntry1>#...#<bootEntryN>]\n"
+ " source volume image\n"
"\n"
- " source Specifications of base directory containing all files
to\n"
- " be written to CD-ROM image\n"
- " volume Volume label\n"
- " image Image file or device\n"
- " -q Quiet mode - display nothing but error messages\n"
- " -v Verbose mode - display file information as files are\n"
- " scanned and written - overrides -p option\n"
- " -p Show progress while writing\n"
- " -s N Abort operation before beginning write if image will
be\n"
- " larger than N megabytes (i.e. 1024*1024*N bytes)\n"
- " -m Accept punctuation marks other than underscores in\n"
- " names and extensions\n"
- " -b bootimage Create bootable ElTorito CD-ROM using 'no emulation'
mode\n"
- " -j Generate Joliet filename records\n";
+ " -vN Verbosity level. Valid values for 'N' are:\n"
+ " 0: Quiet mode - display nothing but error
messages.\n"
+ " 1: Normal mode (default).\n"
+ " 2: Verbose mode - display file information as files
are\n"
+ " scanned and written. Overrides the -p option.\n"
+ " -p Show progress while writing.\n"
+ " -s N Abort operation before beginning write if image will be
larger\n"
+ " than N megabytes (i.e. 1024*1024*N bytes).\n"
+ " -m Accept punctuation marks other than underscores in names
and\n"
+ " extensions.\n"
+ " -j Generate Joliet filename records.\n"
+ "\n"
+ " -pN Boot platform ID in hex format (default: 00 for a BIOS
system).\n"
+ " -eN Boot media emulation. Valid values for 'N'
are:\n"
+ " 0 (or nothing): No emulation.\n"
+ " 1: 1.2Mb diskette.\n"
+ " 2: 1.44Mb diskette.\n"
+ " 3: 2.88Mb diskette.\n"
+ " 4: Hard disk.\n"
+ " -b bootimage Create a single-boot El-Torito image.\n"
+ " -bootdata: Create a multi-boot El-Torito image. This option cannot
be\n"
+ " combined with the -b option.\n"
+ " Syntax:\n"
+ "
-bootdata:N#<defaultBootEntry>#<bootEntry2>#...#<bootEntryN>\n"
+ " 'N': number of boot entries following.\n"
+ " defaultBootEntry: The default boot entry, needed in all
cases.\n"
+ " Used by BIOSes which do not support additional boot
entries.\n"
+ " bootEntryX: Additional boot entries.\n"
+ " - Do not use spaces.\n"
+ " - Each multi-boot entry must be delimited with a hash symbol
(#).\n"
+ " - Each option for a boot entry must be delimited with a comma
(,).\n"
+ " - Each boot entry must specify the platform ID.\n"
+ "\n"
+ " source Specifications of base directory containing all files to
be\n"
+ " written to CD-ROM image.\n"
+ " volume Volume label.\n"
+ " image Image file or device.\n";
/*-----------------------------------------------------------------------------
Program execution starts here.
-----------------------------------------------------------------------------*/
+char* strtok_s(char *str, const char *delim, char **ctx)
+{
+ if (delim == NULL || ctx == NULL || (str == NULL && *ctx == NULL))
+ {
+ return NULL;
+ }
+
+ if (!str)
+ str = *ctx;
+
+ while (*str && strchr(delim, *str))
+ str++;
+ if (!*str)
+ return NULL;
+
+ *ctx = str + 1;
+ while (**ctx && !strchr(delim, **ctx))
+ (*ctx)++;
+ if (**ctx)
+ *(*ctx)++ = '\0';
+
+ return str;
+}
+
int main(int argc, char **argv)
{
time_t timestamp = time(NULL);
- BOOL q_option = FALSE;
- BOOL v_option = FALSE;
int i;
char *t;
@@ -1717,7 +1887,7 @@
return 1;
}
- // initialize root directory
+ // Initialize root directory
cd.buffer = malloc(BUFFER_SIZE);
if (cd.buffer == NULL)
@@ -1728,27 +1898,57 @@
root.flags = DIRECTORY_FLAG;
convert_date_and_time(&root.date_and_time, ×tamp);
- // initialize CD-ROM write buffer
+ // Initialize CD-ROM write buffer
cd.file = NULL;
cd.filespecs[0] = 0;
- // initialize parameters
+ // Initialize parameters
verbosity = NORMAL;
+ show_progress = FALSE;
size_limit = 0;
- show_progress = FALSE;
accept_punctuation_marks = FALSE;
source[0] = 0;
volume_label[0] = 0;
- eltorito = FALSE;
-
- // scan command line arguments
+ // Initialize boot information
+ eltorito = FALSE;
+ multi_boot = FALSE;
+ boot_validation_header.header_id = 1; // Validation header ID
+ boot_validation_header.platform_id = 0; // x86/64 BIOS system
+ default_boot_entry.boot_id = 0x88; // Bootable entry
+ default_boot_entry.boot_emu_type = 0; // No emulation
+ default_boot_entry.load_segment = 0; // 0 --> use default 0x07C0
+ default_boot_entry.sector_count = 0;
+ default_boot_entry.load_rba = 0;
+ default_boot_entry.bootimage[0] = '\0';
+ boot_header_list = NULL;
+
+ // Scan command line arguments
for (i = 1; i < argc; i++)
{
- if (memcmp(argv[i], "-s", 2) == 0)
+ if (strncmp(argv[i], "-v", 2) == 0)
+ {
+ t = argv[i] + 2;
+ if (*t == 0) // Normal verbosity level.
+ verbosity = NORMAL;
+ else // Verbosity level in decimal
+ verbosity = strtoul(t, NULL, 10);
+
+ // Check for validity
+ if (verbosity > VERBOSE)
+ verbosity = NORMAL;
+
+ // Disable by default, unless we are in normal verbosity level.
+ // If progress is still wanted, use '-p'.
+ if (verbosity == QUIET || verbosity == VERBOSE)
+ show_progress = FALSE;
+ }
+ else if (strcmp(argv[i], "-p") == 0)
+ show_progress = TRUE;
+ else if (strncmp(argv[i], "-s", 2) == 0)
{
t = argv[i] + 2;
if (*t == 0)
@@ -1758,26 +1958,254 @@
else
error_exit("Missing size limit parameter");
}
+ // size_limit = strtoul(t, NULL, 10);
while (isdigit(*t))
size_limit = size_limit * 10 + *t++ - '0';
if (size_limit < 1 || size_limit > 800)
error_exit("Invalid size limit");
size_limit <<= 9; // convert megabyte to sector count
}
- else if (strcmp(argv[i], "-q") == 0)
- q_option = TRUE;
- else if (strcmp(argv[i], "-v") == 0)
- v_option = TRUE;
- else if (strcmp(argv[i], "-p") == 0)
- show_progress = TRUE;
else if (strcmp(argv[i], "-m") == 0)
accept_punctuation_marks = TRUE;
else if (strcmp(argv[i], "-j") == 0)
joliet = TRUE;
+ else if (strncmp(argv[i], "-e", 2) == 0)
+ {
+ // Check whether the multi-boot option '-bootdata:' was already set.
+ // If so, print an error and bail out.
+ if (eltorito && multi_boot)
+ error_exit("Single-boot and multi-boot entries cannot be
combined");
+
+ eltorito = TRUE;
+ multi_boot = FALSE;
+
+ t = argv[i] + 2;
+ if (*t == 0) // No emulation
+ default_boot_entry.boot_emu_type = 0;
+ else // ID in decimal
+ default_boot_entry.boot_emu_type = (BYTE)strtoul(t, NULL, 10);
+ }
+ else if (strncmp(argv[i], "-p", 2) == 0)
+ {
+ // Check whether the multi-boot option '-bootdata:' was already set.
+ // If so, print an error and bail out.
+ if (eltorito && multi_boot)
+ error_exit("Single-boot and multi-boot entries cannot be
combined");
+
+ eltorito = TRUE;
+ multi_boot = FALSE;
+
+ // Platform ID in hexadecimal
+ boot_validation_header.platform_id = (BYTE)strtoul(argv[i] + 2, NULL, 16);
+ }
else if (strcmp(argv[i], "-b") == 0)
{
- strcpy(bootimage, argv[++i]);
- eltorito = TRUE;
+ // Check whether the multi-boot option '-bootdata:' was already set.
+ // If so, print an error and bail out.
+ if (eltorito && multi_boot)
+ error_exit("Single-boot and multi-boot entries cannot be
combined");
+
+ eltorito = TRUE;
+ multi_boot = FALSE;
+
+ strncpy(default_boot_entry.bootimage, argv[++i],
sizeof(default_boot_entry.bootimage));
+ default_boot_entry.bootimage[sizeof(default_boot_entry.bootimage)-1] =
'\0';
+ }
+ else if (strncmp(argv[i], "-bootdata:", sizeof("-bootdata:")
- 1) == 0)
+ {
+ char *bootdata, *entry_ctx, *option_ctx;
+ DWORD num_boot_entries = 0;
+
+ BOOL default_entry = TRUE; // Start by setting the default boot entry
+ PBOOT_HEADER boot_header = NULL; // Current boot header
+ PBOOT_ENTRY boot_entry = NULL; // The last boot entry in the current boot
header
+ BYTE platform_id, old_platform_id = 0;
+ BYTE boot_emu_type;
+ WORD load_segment;
+ char bootimage[512];
+
+ // Check whether the single-boot option '-b' was already set.
+ // If so, print an error and bail out.
+ if (eltorito && !multi_boot)
+ error_exit("Single-boot and multi-boot entries cannot be
combined");
+
+ t = argv[i] + (sizeof("-bootdata:") - 1);
+ bootdata = strdup(t);
+ if (bootdata == NULL)
+ error_exit("Insufficient memory");
+
+ eltorito = TRUE;
+ multi_boot = TRUE;
+
+ // FIXME: Paths with '#' or ',' or ' ' inside are not
yet supported!!
+
+ // Start parsing...
+ t = strtok_s(bootdata, "#", &entry_ctx);
+ if (t == NULL)
+ {
+ free(bootdata);
+ error_exit("Malformed bootdata command");
+ }
+
+ num_boot_entries = strtoul(t, NULL, 10);
+
+ while (num_boot_entries--)
+ {
+ // Reset to default values
+ platform_id = 0; // x86/64 BIOS system
+ boot_emu_type = 0; // No emulation
+ load_segment = 0; // 0 --> use default 0x07C0
+ bootimage[0] = '\0';
+
+ t = strtok_s(NULL, "#", &entry_ctx);
+ if (t == NULL)
+ {
+ free(bootdata);
+ error_exit("Malformed bootdata command");
+ }
+
+ t = strtok_s(t, ",", &option_ctx);
+ while (t != NULL)
+ {
+ switch (*t++)
+ {
+ case 'b': // Boot sector file
+ {
+ char *q;
+
+ // Searches for any of the valid separators:
+ // '#' starts a new boot entry;
+ // ',' starts a new boot option;
+ // ' ' finishes the bootdata command.
+ q = strpbrk(t, "#, ");
+ if (!q) q = t + strlen(t);
+ strncpy(bootimage, t, q - t + 1);
+ break;
+ }
+
+ case 'p': // Platform ID
+ {
+ // Platform ID in hexadecimal
+ platform_id = (BYTE)strtoul(t, NULL, 16);
+ break;
+ }
+
+ case 'e': // No floppy-disk emulation
+ {
+ if (*t == 0) // No emulation
+ boot_emu_type = 0;
+ else // ID in decimal
+ boot_emu_type = (BYTE)strtoul(t, NULL, 10);
+
+ break;
+ }
+
+ case 't': // Loading segment
+ {
+ if (*t == 0) // Not specified --> use default 0x07C0
+ load_segment = 0;
+ else // Segment in hexadecimal
+ load_segment = (BYTE)strtoul(t, NULL, 16);
+
+ break;
+ }
+
+ default:
+ free(bootdata);
+ error_exit("Malformed bootdata command");
+ }
+
+ t = strtok_s(NULL, ",", &option_ctx);
+ }
+
+ // Create a new entry and possibly a boot header
+ if (default_entry)
+ {
+ // Initialize the default boot entry and header
+
+ boot_validation_header.header_id = 1; // Validation header ID
+ boot_validation_header.platform_id = platform_id;
+ default_boot_entry.boot_id = 0x88; // Bootable entry
+ default_boot_entry.boot_emu_type = boot_emu_type;
+ default_boot_entry.load_segment = load_segment;
+
+ strncpy(default_boot_entry.bootimage, bootimage,
sizeof(default_boot_entry.bootimage));
+ default_boot_entry.bootimage[sizeof(default_boot_entry.bootimage)-1]
= '\0';
+
+ // Default entry is now initialized.
+ default_entry = FALSE;
+ }
+ else
+ {
+ // Initialize a new boot entry
+ PBOOT_ENTRY old_boot_entry = boot_entry;
+
+ boot_entry = calloc(1, sizeof(*boot_entry));
+ if (boot_entry == NULL)
+ error_exit("Insufficient memory");
+ // boot_entry->next_entry = NULL;
+
+ boot_entry->boot_id = 0x88; // Bootable entry
+ boot_entry->boot_emu_type = boot_emu_type;
+ boot_entry->load_segment = load_segment;
+
+ strncpy(boot_entry->bootimage, bootimage,
sizeof(boot_entry->bootimage));
+ boot_entry->bootimage[sizeof(boot_entry->bootimage)-1] =
'\0';
+
+ // Create a new boot header if we don't have one yet
+ if (boot_header == NULL)
+ {
+ boot_header = calloc(1, sizeof(*boot_header));
+ if (boot_header == NULL)
+ error_exit("Insufficient memory");
+
+ boot_header->header_id = 0x91; // So far this is the last
boot header
+ boot_header->platform_id = platform_id;
+ // boot_header->next_header = NULL;
+ // boot_header->num_entries = 0;
+ // boot_header->entry_list = NULL;
+
+ old_boot_entry = NULL;
+ old_platform_id = platform_id;
+
+ boot_header_list = boot_header;
+ }
+ else
+ {
+ // Create a new boot header if we change the platform ID
+ if (old_platform_id != platform_id)
+ {
+ PBOOT_HEADER prev_boot_header = boot_header;
+
+ boot_header = calloc(1, sizeof(*boot_header));
+ if (boot_header == NULL)
+ error_exit("Insufficient memory");
+
+ boot_header->header_id = 0x91; // So far this is the
last boot header
+ boot_header->platform_id = platform_id;
+ // boot_header->next_header = NULL;
+ // boot_header->num_entries = 0;
+ // boot_header->entry_list = NULL;
+
+ old_boot_entry = NULL;
+ old_platform_id = platform_id;
+
+ // Link into the header list
+ prev_boot_header->header_id = 0x90; // The previous boot
header was not the last one
+ prev_boot_header->next_header = boot_header;
+ }
+ }
+
+ // Add the entry into the header
+ ++boot_header->num_entries;
+ if (old_boot_entry == NULL)
+ boot_header->entry_list = boot_entry;
+ else
+ old_boot_entry->next_entry = boot_entry;
+ }
+ }
+
+ free(bootdata);
}
else if (i + 2 < argc)
{
@@ -1788,16 +2216,7 @@
else
error_exit("Missing command line argument");
}
- if (v_option)
- {
- show_progress = FALSE;
- verbosity = VERBOSE;
- }
- else if (q_option)
- {
- verbosity = QUIET;
- show_progress = FALSE;
- }
+
if (source[0] == 0)
error_exit("Missing source directory");
if (volume_label[0] == 0)
@@ -1820,13 +2239,13 @@
}
else
{
- char *trimmedline, *targetname, *srcname, *eq;
+ char *trimmedline, *targetname, *srcname, *eq, *normdir;
char lineread[1024];
FILE *f = fopen(source+1, "r");
if (!f)
{
- error_exit("Can't open cd description %s\n", source+1);
+ error_exit("Cannot open cd description %s\n", source+1);
}
while (fgets(lineread, sizeof(lineread), f))
{
@@ -1835,7 +2254,6 @@
eq = strchr(trimmedline, '=');
if (!eq)
{
- char *normdir;
/* Treat this as a directory name */
targetname = trimmedline;
normdir = strdup(targetname);
@@ -1852,12 +2270,12 @@
if (_access(srcname, R_OK) == 0)
dir_hash_add_file(&specified_files, srcname, targetname);
else
- error_exit("can't access file '%s' (target
%s)\n", srcname, targetname);
+ error_exit("Cannot access file '%s' (target %s)\n",
srcname, targetname);
#else
if (access(srcname, R_OK) == 0)
dir_hash_add_file(&specified_files, srcname, targetname);
else
- error_exit("can't access file '%s' (target
%s)\n", srcname, targetname);
+ error_exit("Cannot access file '%s' (target %s)\n",
srcname, targetname);
#endif
}
}
@@ -1877,7 +2295,7 @@
cd.file = NULL;
cd.sector = 0;
cd.offset = 0;
- cd.count = 0;
+ cd.count = 0;
// make non-writing pass over directory structure to obtain the proper
// sector numbers and offsets and to determine the size of the image
@@ -1909,10 +2327,10 @@
cd.file = fopen(cd.filespecs, "w+b");
if (cd.file == NULL)
- error_exit("Can't open image file %s", cd.filespecs);
+ error_exit("Cannot open image file %s", cd.filespecs);
cd.sector = 0;
cd.offset = 0;
- cd.count = 0;
+ cd.count = 0;
// make writing pass over directory structure
Modified: trunk/reactos/tools/cdmake/config.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/tools/cdmake/config.h?rev=…
==============================================================================
--- trunk/reactos/tools/cdmake/config.h [iso-8859-1] (original)
+++ trunk/reactos/tools/cdmake/config.h [iso-8859-1] Wed Sep 9 02:11:49 2015
@@ -9,6 +9,7 @@
#define DIR_SEPARATOR_STRING "\\"
#endif
+#define MANUFACTURER_ID "ReactOS Foundation"
#define PUBLISHER_ID "ReactOS Foundation"
#define DATA_PREP_ID "ReactOS Foundation"
#define APP_ID "CDMAKE CD-ROM Premastering Utility"
Modified: trunk/reactos/tools/cdmake/dirhash.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/tools/cdmake/dirhash.c?rev…
==============================================================================
--- trunk/reactos/tools/cdmake/dirhash.c [iso-8859-1] (original)
+++ trunk/reactos/tools/cdmake/dirhash.c [iso-8859-1] Wed Sep 9 02:11:49 2015
@@ -1,3 +1,10 @@
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS CD-ROM Maker
+ * FILE: tools/cdmake/dirhash.c
+ * PURPOSE: CD-ROM Premastering Utility - Directory names hashing
+ * PROGRAMMERS: Art Yerkes
+ */
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
Modified: trunk/reactos/tools/cdmake/dirhash.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/tools/cdmake/dirhash.h?rev…
==============================================================================
--- trunk/reactos/tools/cdmake/dirhash.h [iso-8859-1] (original)
+++ trunk/reactos/tools/cdmake/dirhash.h [iso-8859-1] Wed Sep 9 02:11:49 2015
@@ -1,3 +1,10 @@
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS CD-ROM Maker
+ * FILE: tools/cdmake/dirhash.h
+ * PURPOSE: CD-ROM Premastering Utility - Directory names hashing
+ * PROGRAMMERS: Art Yerkes
+ */
#ifndef _DIRHASH_H_
#define _DIRHASH_H_