* Improve the way we create bootcd, livecd and bootcdregtest. The effort results in ~28% *smaller* build folder, and *much* faster generation of the ISOs.

[CDMAKE]
* Introduce a way to create an iso using a file map instead of the current on-disk layout. This allows us to massively reduce the IO and the disk space needed to perform the creation of the 3 ISOs, and at the same time speed up the process. Brought to you by Art Yerkes (arty) with review/bug fix by Thomas Faber.
[CMAKE]
* Leverage the newly introduced cdmake feature.
* Silence cdmake verbosity.
* Write the contents of the file lists at once, instead of appending to it one item by one.
[VGAFONTS]
* Don't include the cab file twice.

svn path=/trunk/; revision=59547
This commit is contained in:
Amine Khaldi 2013-07-21 13:33:03 +00:00
parent 95ba3e574b
commit fe0958fb25
9 changed files with 545 additions and 84 deletions

View file

@ -235,6 +235,9 @@ else()
add_subdirectory(subsystems) add_subdirectory(subsystems)
add_subdirectory(win32ss) add_subdirectory(win32ss)
# Create {bootcd, livecd, bootcdregtest}.lst
create_iso_lists()
file(MAKE_DIRECTORY ${REACTOS_BINARY_DIR}/include/reactos) file(MAKE_DIRECTORY ${REACTOS_BINARY_DIR}/include/reactos)
add_dependency_footer() add_dependency_footer()

View file

@ -1,50 +1,27 @@
##bootcd ##bootcd
#clear it out #clear it out
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bootcd.cmake file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bootcd.lst "")
"file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bootcd)\n")
add_custom_target(bootcd add_custom_target(bootcd
${CMAKE_COMMAND} -D CD_DIR=${CMAKE_CURRENT_BINARY_DIR}/bootcd 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
-P ${CMAKE_CURRENT_BINARY_DIR}/bootcd.cmake
COMMAND native-cdmake -v -j -m -b ${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/isoboot.bin ${CMAKE_CURRENT_BINARY_DIR}/bootcd REACTOS ${REACTOS_BINARY_DIR}/bootcd.iso
DEPENDS native-cdmake DEPENDS native-cdmake
VERBATIM) VERBATIM)
##bootcdregtest ##bootcdregtest
#clear it out #clear it out
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bootcdregtest.cmake file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bootcdregtest.lst "")
"file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bootcdregtest)\n")
add_custom_target(bootcdregtest add_custom_target(bootcdregtest
${CMAKE_COMMAND} -D CD_DIR=${CMAKE_CURRENT_BINARY_DIR}/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
-P ${CMAKE_CURRENT_BINARY_DIR}/bootcdregtest.cmake
COMMAND native-cdmake -v -j -m -b ${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/isobtrt.bin ${CMAKE_CURRENT_BINARY_DIR}/bootcdregtest REACTOS ${REACTOS_BINARY_DIR}/bootcdregtest.iso
DEPENDS native-cdmake DEPENDS native-cdmake
VERBATIM) VERBATIM)
##livecd ##livecd
#clear it out #clear it out and create the empty Desktop folder
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/livecd.cmake file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/livecd.lst "Profiles/Default User/Desktop\n")
"file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/livecd)\n")
#create profiles directories too
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/livecd.cmake
"file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/livecd/Profiles)\n")
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/livecd.cmake
"file(MAKE_DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}/livecd/Profiles/All Users\")\n")
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/livecd.cmake
"file(MAKE_DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}/livecd/Profiles/All Users/Desktop\")\n")
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/livecd.cmake
"file(MAKE_DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}/livecd/Profiles/Default User\")\n")
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/livecd.cmake
"file(MAKE_DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}/livecd/Profiles/Default User/Desktop\")\n")
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/livecd.cmake
"file(MAKE_DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}/livecd/Profiles/Default User/My Documents\")\n")
add_custom_target(livecd add_custom_target(livecd
${CMAKE_COMMAND} -D CD_DIR=${CMAKE_CURRENT_BINARY_DIR}/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
-P ${CMAKE_CURRENT_BINARY_DIR}/livecd.cmake
COMMAND native-cdmake -v -j -m -b ${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/isoboot.bin ${CMAKE_CURRENT_BINARY_DIR}/livecd REACTOS ${REACTOS_BINARY_DIR}/livecd.iso
DEPENDS native-cdmake DEPENDS native-cdmake
VERBATIM) VERBATIM)

View file

@ -227,13 +227,14 @@ function(add_cd_file)
if(_CD_NO_CAB) if(_CD_NO_CAB)
#directly on cd #directly on cd
foreach(item ${_CD_FILE}) foreach(item ${_CD_FILE})
file(APPEND ${REACTOS_BINARY_DIR}/boot/bootcd.cmake "file(COPY \"${item}\" DESTINATION \"\${CD_DIR}/${_CD_DESTINATION}\")\n")
endforeach()
if(_CD_NAME_ON_CD) if(_CD_NAME_ON_CD)
get_filename_component(__file ${_CD_FILE} NAME)
#rename it in the cd tree #rename it in the cd tree
file(APPEND ${REACTOS_BINARY_DIR}/boot/bootcd.cmake "file(RENAME \${CD_DIR}/${_CD_DESTINATION}/${__file} \${CD_DIR}/${_CD_DESTINATION}/${_CD_NAME_ON_CD})\n") set(__file ${_CD_NAME_ON_CD})
else()
get_filename_component(__file ${item} NAME)
endif() endif()
set_property(GLOBAL APPEND PROPERTY BOOTCD_FILE_LIST "${_CD_DESTINATION}/${__file}=${item}")
endforeach()
if(_CD_TARGET) if(_CD_TARGET)
#manage dependency #manage dependency
add_dependencies(bootcd ${_CD_TARGET}) add_dependencies(bootcd ${_CD_TARGET})
@ -259,13 +260,14 @@ function(add_cd_file)
add_dependencies(livecd ${_CD_TARGET}) add_dependencies(livecd ${_CD_TARGET})
endif() endif()
foreach(item ${_CD_FILE}) foreach(item ${_CD_FILE})
file(APPEND ${REACTOS_BINARY_DIR}/boot/livecd.cmake "file(COPY \"${item}\" DESTINATION \"\${CD_DIR}/${_CD_DESTINATION}\")\n")
endforeach()
if(_CD_NAME_ON_CD) if(_CD_NAME_ON_CD)
get_filename_component(__file ${_CD_FILE} NAME)
#rename it in the cd tree #rename it in the cd tree
file(APPEND ${REACTOS_BINARY_DIR}/boot/livecd.cmake "file(RENAME \${CD_DIR}/${_CD_DESTINATION}/${__file} \${CD_DIR}/${_CD_DESTINATION}/${_CD_NAME_ON_CD})\n") set(__file ${_CD_NAME_ON_CD})
else()
get_filename_component(__file ${item} NAME)
endif() endif()
set_property(GLOBAL APPEND PROPERTY LIVECD_FILE_LIST "${_CD_DESTINATION}/${__file}=${item}")
endforeach()
endif() #end livecd endif() #end livecd
#do we add it to regtest? #do we add it to regtest?
@ -275,13 +277,14 @@ function(add_cd_file)
if(_CD_NO_CAB) if(_CD_NO_CAB)
#directly on cd #directly on cd
foreach(item ${_CD_FILE}) foreach(item ${_CD_FILE})
file(APPEND ${REACTOS_BINARY_DIR}/boot/bootcdregtest.cmake "file(COPY \"${item}\" DESTINATION \"\${CD_DIR}/${_CD_DESTINATION}\")\n")
endforeach()
if(_CD_NAME_ON_CD) if(_CD_NAME_ON_CD)
get_filename_component(__file ${_CD_FILE} NAME)
#rename it in the cd tree #rename it in the cd tree
file(APPEND ${REACTOS_BINARY_DIR}/boot/bootcdregtest.cmake "file(RENAME \${CD_DIR}/${_CD_DESTINATION}/${__file} \${CD_DIR}/${_CD_DESTINATION}/${_CD_NAME_ON_CD})\n") set(__file ${_CD_NAME_ON_CD})
else()
get_filename_component(__file ${item} NAME)
endif() endif()
set_property(GLOBAL APPEND PROPERTY BOOTCDREGTEST_FILE_LIST "${_CD_DESTINATION}/${__file}=${item}")
endforeach()
if(_CD_TARGET) if(_CD_TARGET)
#manage dependency #manage dependency
add_dependencies(bootcdregtest ${_CD_TARGET}) add_dependencies(bootcdregtest ${_CD_TARGET})
@ -298,6 +301,23 @@ function(add_cd_file)
endif() #end bootcd endif() #end bootcd
endfunction() endfunction()
function(create_iso_lists)
get_property(_filelist GLOBAL PROPERTY BOOTCD_FILE_LIST)
string(REPLACE ";" "\n" _filelist "${_filelist}")
file(APPEND ${REACTOS_BINARY_DIR}/boot/bootcd.lst "${_filelist}")
unset(_filelist)
get_property(_filelist GLOBAL PROPERTY LIVECD_FILE_LIST)
string(REPLACE ";" "\n" _filelist "${_filelist}")
file(APPEND ${REACTOS_BINARY_DIR}/boot/livecd.lst "${_filelist}")
unset(_filelist)
get_property(_filelist GLOBAL PROPERTY BOOTCDREGTEST_FILE_LIST)
string(REPLACE ";" "\n" _filelist "${_filelist}")
file(APPEND ${REACTOS_BINARY_DIR}/boot/bootcdregtest.lst "${_filelist}")
unset(_filelist)
endfunction()
# Create module_clean targets # Create module_clean targets
function(add_clean_target _target) function(add_clean_target _target)
set(_clean_working_directory ${CMAKE_CURRENT_BINARY_DIR}) set(_clean_working_directory ${CMAKE_CURRENT_BINARY_DIR})

View file

@ -18,4 +18,3 @@ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/vgafonts.cab
add_custom_target(vgafonts DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/vgafonts.cab) add_custom_target(vgafonts DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/vgafonts.cab)
add_cd_file(TARGET vgafonts FILE ${CMAKE_CURRENT_BINARY_DIR}/vgafonts.cab DESTINATION reactos NO_CAB FOR all) add_cd_file(TARGET vgafonts FILE ${CMAKE_CURRENT_BINARY_DIR}/vgafonts.cab DESTINATION reactos NO_CAB FOR all)
add_cd_file(TARGET vgafonts FILE ${CMAKE_CURRENT_BINARY_DIR}/vgafonts.cab DESTINATION reactos FOR all)

View file

@ -1,2 +1,2 @@
add_executable(cdmake cdmake.c dirhash.c llmosrt.c)
add_executable(cdmake cdmake.c llmosrt.c)

View file

@ -33,8 +33,13 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#ifdef _WIN32 #ifdef _WIN32
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# include <io.h> # include <io.h>
# include <dos.h> # include <dos.h>
# ifdef _MSC_VER
# define R_OK 4
# endif
#else #else
# if defined(__FreeBSD__) || defined(__APPLE__) # if defined(__FreeBSD__) || defined(__APPLE__)
# include <sys/uio.h> # include <sys/uio.h>
@ -45,29 +50,20 @@
# include <sys/types.h> # include <sys/types.h>
# include <dirent.h> # include <dirent.h>
# include <unistd.h> # include <unistd.h>
# define TRUE 1
# define FALSE 0
#endif // _WIN32 #endif // _WIN32
#include <ctype.h> #include <ctype.h>
#include <setjmp.h> #include <setjmp.h>
#include <time.h> #include <time.h>
#ifndef _WIN32 #include "dirsep.h"
#ifndef MAX_PATH #include "dirhash.h"
#define MAX_PATH 260
#endif
#define DIR_SEPARATOR_CHAR '/'
#define DIR_SEPARATOR_STRING "/"
#else
#define DIR_SEPARATOR_CHAR '\\'
#define DIR_SEPARATOR_STRING "\\"
#endif
typedef unsigned char BYTE; typedef unsigned char BYTE;
typedef unsigned short WORD; typedef unsigned short WORD;
typedef unsigned long DWORD; typedef unsigned long DWORD;
typedef int BOOL; typedef int BOOL;
const BOOL TRUE = 1;
const BOOL FALSE = 0;
// file system parameters // file system parameters
#define MAX_LEVEL 8 #define MAX_LEVEL 8
@ -115,6 +111,7 @@ typedef struct directory_record
char extension[MAX_EXTENSION_LENGTH+1]; char extension[MAX_EXTENSION_LENGTH+1];
char extension_on_cd[MAX_CDEXTENSION_LENGTH+1]; char extension_on_cd[MAX_CDEXTENSION_LENGTH+1];
char *joliet_name; char *joliet_name;
const char *orig_name;
DATE_AND_TIME date_and_time; DATE_AND_TIME date_and_time;
DWORD sector; DWORD sector;
DWORD size; DWORD size;
@ -173,6 +170,8 @@ DWORD joliet_path_table_size;
DWORD joliet_little_endian_path_table_sector; DWORD joliet_little_endian_path_table_sector;
DWORD joliet_big_endian_path_table_sector; DWORD joliet_big_endian_path_table_sector;
struct target_dir_hash specified_files;
/*----------------------------------------------------------------------------- /*-----------------------------------------------------------------------------
This function edits a 32-bit unsigned number into a comma-delimited form, such This function edits a 32-bit unsigned number into a comma-delimited form, such
as 4,294,967,295 for the largest possible number, and returns a pointer to a as 4,294,967,295 for the largest possible number, and returns a pointer to a
@ -1068,6 +1067,159 @@ make_directory_records (PDIR_RECORD d)
#endif #endif
static PDIR_RECORD
new_empty_dirrecord(PDIR_RECORD d, BOOL directory)
{
PDIR_RECORD new_d;
new_d = malloc(sizeof(*new_d));
memset(new_d, 0, sizeof(*new_d));
new_d->parent = d;
new_d->level = d->level + 1;
new_d->next_in_directory = d->first_record;
d->first_record = new_d;
new_d->next_in_memory = root.next_in_memory;
root.next_in_memory = new_d;
if (directory)
{
new_d->flags |= DIRECTORY_FLAG;
new_d->next_in_path_table = root.next_in_path_table;
root.next_in_path_table = new_d;
}
return new_d;
}
#if _WIN32
static int
get_cd_file_time(HANDLE handle, DATE_AND_TIME *cd_time_info)
{
FILETIME file_time;
SYSTEMTIME sys_time;
if (!GetFileTime(handle, NULL, NULL, &file_time))
{
return -1;
}
FileTimeToSystemTime(&file_time, &sys_time);
memset(cd_time_info, 0, sizeof(*cd_time_info));
cd_time_info->year = sys_time.wYear;
cd_time_info->month = sys_time.wMonth - 1;
cd_time_info->day = sys_time.wDay;
cd_time_info->hour = sys_time.wHour;
cd_time_info->minute = sys_time.wMinute;
cd_time_info->second = sys_time.wSecond;
return 0;
}
#endif
static void
scan_specified_files(PDIR_RECORD d, struct target_dir_entry *dir)
{
PDIR_RECORD new_d;
#if _WIN32
HANDLE open_file;
LARGE_INTEGER file_size;
#else
struct stat stbuf;
#endif
struct target_file *file;
struct target_dir_entry *child;
d->first_record = NULL;
for (file = dir->head; file; file = file->next)
{
if (strcmp(file->target_name, DIRECTORY_TIMESTAMP) == 0)
{
#if _WIN32
if ((open_file = CreateFileA(file->source_name,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL)) == INVALID_HANDLE_VALUE)
{
error_exit("Can't open timestamp file %s\n", file->source_name);
}
if (get_cd_file_time(open_file, &d->date_and_time) == -1)
{
error_exit("Can't 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);
}
convert_date_and_time(&d->date_and_time, &stbuf.st_ctime);
#endif
}
else
{
if (verbosity == VERBOSE)
{
printf("%d: file %s (from %s)\n",
d->level,
file->target_name,
file->source_name);
}
new_d = new_empty_dirrecord(d, FALSE);
parse_filename_into_dirrecord(file->target_name, new_d, FALSE);
#if _WIN32
if ((open_file = CreateFileA(file->source_name,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL)) == INVALID_HANDLE_VALUE)
{
error_exit("Can't open file %s\n", file->source_name);
}
if (get_cd_file_time(open_file, &new_d->date_and_time) == -1)
{
error_exit("Can't 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);
}
new_d->size = new_d->joliet_size = file_size.QuadPart;
new_d->orig_name = file->source_name;
CloseHandle(open_file);
#else
if (stat(file->source_name, &stbuf) == -1)
{
error_exit("Can't find '%s' (target %s)\n",
file->source_name,
file->target_name);
}
convert_date_and_time(&new_d->date_and_time, &stbuf.st_mtime);
new_d->size = new_d->joliet_size = stbuf.st_size;
new_d->orig_name = file->source_name;
#endif
}
}
for (child = dir->child; child; child = child->next)
{
if (verbosity == VERBOSE)
{
printf("%d: directory %s\n", d->level, child->case_name);
}
new_d = new_empty_dirrecord(d, TRUE);
parse_filename_into_dirrecord(child->case_name, new_d, TRUE);
scan_specified_files(new_d, child);
}
/* sort directory */
d->first_record = sort_linked_list(d->first_record,
0,
compare_directory_order);
source[0] = 0;
end_source = source;
}
/*----------------------------------------------------------------------------- /*-----------------------------------------------------------------------------
This function loads the file specifications for the file or directory This function loads the file specifications for the file or directory
corresponding to the specified directory record into the source[] buffer. It corresponding to the specified directory record into the source[] buffer. It
@ -1455,14 +1607,23 @@ static void pass(void)
} }
else else
{ {
const char *file_source;
old_end_source = end_source; old_end_source = end_source;
if (!q->orig_name)
{
get_file_specifications(q); get_file_specifications(q);
*end_source = 0; *end_source = 0;
file_source = source;
}
else
{
file_source = q->orig_name;
}
if (verbosity == VERBOSE) if (verbosity == VERBOSE)
printf("Writing %s\n", source); printf("Writing contents of %s\n", file_source);
file = fopen(source, "rb"); file = fopen(file_source, "rb");
if (file == NULL) if (file == NULL)
error_exit("Can't open %s\n", source); error_exit("Can't open %s\n", file_source);
fseek(file, 0, SEEK_SET); fseek(file, 0, SEEK_SET);
while (size > 0) while (size > 0)
{ {
@ -1472,7 +1633,7 @@ static void pass(void)
if (fread (cd.buffer + cd.count, n, 1, file) < 1) if (fread (cd.buffer + cd.count, n, 1, file) < 1)
{ {
fclose(file); fclose(file);
error_exit("Read error in file %s\n", source); error_exit("Read error in file %s\n", file_source);
} }
cd.count += n; cd.count += n;
if (cd.count == BUFFER_SIZE) if (cd.count == BUFFER_SIZE)
@ -1626,22 +1787,70 @@ int main(int argc, char **argv)
if (cd.filespecs[0] == 0) if (cd.filespecs[0] == 0)
error_exit("Missing image file specifications"); error_exit("Missing image file specifications");
if (source[0] != '@')
// set source[] and end_source to source directory, with a terminating directory separator {
/* set source[] and end_source to source directory,
* with a terminating directory separator */
end_source = source + strlen(source); end_source = source + strlen(source);
if (end_source[-1] == ':') if (end_source[-1] == ':')
*end_source++ = '.'; *end_source++ = '.';
if (end_source[-1] != DIR_SEPARATOR_CHAR) if (end_source[-1] != DIR_SEPARATOR_CHAR)
*end_source++ = DIR_SEPARATOR_CHAR; *end_source++ = DIR_SEPARATOR_CHAR;
// scan all files and create directory structure in memory /* scan all files and create directory structure in memory */
make_directory_records(&root); make_directory_records(&root);
}
else
{
char *trimmedline, *targetname, *srcname, *eq;
char lineread[1024];
FILE *f = fopen(source+1, "r");
if (!f)
{
error_exit("Can't open cd description %s\n", source+1);
}
while (fgets(lineread, sizeof(lineread), f))
{
/* We treat these characters as line endings */
trimmedline = strtok(lineread, "\t\r\n;");
eq = strchr(trimmedline, '=');
if (!eq)
{
char *normdir;
/* Treat this as a directory name */
targetname = trimmedline;
normdir = strdup(targetname);
normalize_dirname(normdir);
dir_hash_create_dir(&specified_files, targetname, normdir);
free(normdir);
}
else
{
targetname = strtok(lineread, "=");
srcname = strtok(NULL, "");
// sort path table entries #if _WIN32
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);
#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);
#endif
}
}
fclose(f);
root.next_in_path_table = sort_linked_list(root.next_in_path_table, 1, /* scan all files and create directory structure in memory */
scan_specified_files(&root, &specified_files.root);
}
/* sort path table entries */
root.next_in_path_table = sort_linked_list(root.next_in_path_table,
1,
compare_path_table_order); compare_path_table_order);
// initialize CD-ROM write buffer // initialize CD-ROM write buffer
@ -1704,9 +1913,9 @@ int main(int argc, char **argv)
if (verbosity >= NORMAL) if (verbosity >= NORMAL)
puts("CD-ROM image made successfully"); puts("CD-ROM image made successfully");
dir_hash_destroy(&specified_files);
release_memory(); release_memory();
return 0; return 0;
} }
/* EOF */ /* EOF */

View file

@ -0,0 +1,205 @@
#include <string.h>
#include <malloc.h>
#include "dirsep.h"
#include "dirhash.h"
/* This is the famous DJB hash */
static unsigned int
djb_hash(const char *name)
{
unsigned int val = 5381;
int i = 0;
for (i = 0; name[i]; i++)
{
val = (33 * val) + name[i];
}
return val;
}
static const char *
chop_filename(const char *target)
{
char *last_slash = strrchr(target, '/');
if (!last_slash)
last_slash = strrchr(target, '\\');
if (last_slash)
return last_slash + 1;
else
return target;
}
static void
chop_dirname(const char *name, char **dirname)
{
char *last_slash = strrchr(name, '/');
if (!last_slash)
last_slash = strrchr(name, '\\');
if (!last_slash)
{
free(*dirname);
*dirname = malloc(1);
**dirname = 0;
}
else
{
char *newdata = malloc(last_slash - name + 1);
memcpy(newdata, name, last_slash - name);
newdata[last_slash - name] = 0;
free(*dirname);
*dirname = newdata;
}
}
static struct target_dir_entry *
get_entry_by_normname(struct target_dir_hash *dh, const char *norm)
{
unsigned int hashcode;
struct target_dir_entry *de;
hashcode = djb_hash(norm);
de = dh->buckets[hashcode % NUM_DIR_HASH_BUCKETS];
while (de && strcmp(de->normalized_name, norm))
de = de->next;
return de;
}
void normalize_dirname(char *filename)
{
int i, tgt;
int slash = 1;
for (i = 0, tgt = 0; filename[i]; i++) {
if (slash) {
if (filename[i] != '/' && filename[i] != '\\') {
filename[tgt++] = toupper(filename[i]);
slash = 0;
}
} else {
if (filename[i] == '/' || filename[i] == '\\') {
slash = 1;
filename[tgt++] = DIR_SEPARATOR_CHAR;
} else {
filename[tgt++] = toupper(filename[i]);
}
}
}
filename[tgt] = 0;
}
struct target_dir_entry *
dir_hash_create_dir(struct target_dir_hash *dh, const char *casename, const char *targetnorm)
{
unsigned int hashcode;
struct target_dir_entry *de, *parent_de;
char *parentname = NULL;
char *parentcase = NULL;
struct target_dir_entry **ent;
if (!dh->root.normalized_name)
{
dh->root.normalized_name = strdup("");
dh->root.case_name = strdup("");
hashcode = djb_hash("");
dh->buckets[hashcode % NUM_DIR_HASH_BUCKETS] = &dh->root;
}
de = get_entry_by_normname(dh, targetnorm);
if (de)
return de;
chop_dirname(targetnorm, &parentname);
chop_dirname(casename, &parentcase);
parent_de = dir_hash_create_dir(dh, parentcase, parentname);
free(parentname);
free(parentcase);
hashcode = djb_hash(targetnorm);
de = malloc(sizeof(*de));
memset(de, 0, sizeof(*de));
de->parent = parent_de;
de->normalized_name = strdup(targetnorm);
de->case_name = strdup(chop_filename(casename));
de->next = parent_de->child;
parent_de->child = de;
ent = &dh->buckets[hashcode % NUM_DIR_HASH_BUCKETS];
while ((*ent))
{
ent = &(*ent)->next;
}
*ent = de;
return de;
}
void dir_hash_add_file(struct target_dir_hash *dh, const char *source, const char *target)
{
unsigned int hashcode;
struct target_file *tf;
struct target_dir_entry *de;
const char *filename = chop_filename(target);
char *targetdir = NULL;
char *targetnorm;
chop_dirname(target, &targetdir);
targetnorm = strdup(targetdir);
normalize_dirname(targetnorm);
de = dir_hash_create_dir(dh, targetdir, targetnorm);
tf = malloc(sizeof(*tf));
memset(tf, 0, sizeof(*tf));
tf->next = de->head;
de->head = tf;
tf->source_name = strdup(source);
tf->target_name = strdup(filename);
}
struct target_dir_entry *
dir_hash_next_dir(struct target_dir_hash *dh, struct target_dir_traversal *t)
{
if (t->i == -1)
return NULL;
if (!t->it)
{
while (++t->i != NUM_DIR_HASH_BUCKETS)
{
if (dh->buckets[t->i])
{
t->it = dh->buckets[t->i];
return t->it;
}
}
t->i = -1;
return NULL;
}
else
{
t->it = t->it->next;
if (!t->it)
{
t->i = -1;
return NULL;
}
else
return t->it;
}
}
void dir_hash_destroy_dir(struct target_dir_entry *de)
{
struct target_file *tf;
struct target_dir_entry *te;
while ((te = de->child))
{
de->child = te->next;
dir_hash_destroy_dir(te);
free(te);
}
while ((tf = de->head))
{
de->head = tf->next;
free(tf->source_name);
free(tf->target_name);
free(tf);
}
free(de->normalized_name);
free(de->case_name);
}
void dir_hash_destroy(struct target_dir_hash *dh)
{
dir_hash_destroy_dir(&dh->root);
}

View file

@ -0,0 +1,38 @@
#ifndef _REACTOS_TOOLS_CDMAKE_DIRHASH_H_
#define _REACTOS_TOOLS_CDMAKE_DIRHASH_H_
#define NUM_DIR_HASH_BUCKETS 1024
struct target_file {
struct target_file *next;
char *source_name;
char *target_name;
};
struct target_dir_entry {
struct target_dir_entry *next;
struct target_dir_entry *parent;
struct target_dir_entry *child;
struct target_file *head;
char *normalized_name;
char *case_name;
};
struct target_dir_hash {
struct target_dir_entry *buckets[NUM_DIR_HASH_BUCKETS];
struct target_dir_entry root;
};
struct target_dir_traversal {
struct target_dir_entry *it;
int i;
};
void normalize_dirname(char *filename);
void dir_hash_add_file(struct target_dir_hash *dh, const char *source, const char *target);
struct target_dir_entry *
dir_hash_create_dir(struct target_dir_hash *dh, const char *casename, const char *targetnorm);
struct target_dir_entry *dir_hash_next_dir(struct target_dir_hash *dh, struct target_dir_traversal *t);
void dir_hash_destroy(struct target_dir_hash *dh);
#endif//_REACTOS_TOOLS_CDMAKE_DIRHASH_H_

View file

@ -0,0 +1,10 @@
#ifndef _WIN32
#ifndef MAX_PATH
#define MAX_PATH 260
#endif
#define DIR_SEPARATOR_CHAR '/'
#define DIR_SEPARATOR_STRING "/"
#else
#define DIR_SEPARATOR_CHAR '\\'
#define DIR_SEPARATOR_STRING "\\"
#endif