Author: akhaldi Date: Sun Jul 21 13:33:03 2013 New Revision: 59547
URL: http://svn.reactos.org/svn/reactos?rev=59547&view=rev Log: * 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.
Added: trunk/reactos/tools/cdmake/dirhash.c (with props) trunk/reactos/tools/cdmake/dirhash.h (with props) trunk/reactos/tools/cdmake/dirsep.h (with props) Modified: trunk/reactos/CMakeLists.txt trunk/reactos/boot/CMakeLists.txt trunk/reactos/cmake/CMakeMacros.cmake trunk/reactos/media/vgafonts/CMakeLists.txt trunk/reactos/tools/cdmake/CMakeLists.txt trunk/reactos/tools/cdmake/cdmake.c
Modified: trunk/reactos/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/reactos/CMakeLists.txt?rev=59547&am... ============================================================================== --- trunk/reactos/CMakeLists.txt [iso-8859-1] (original) +++ trunk/reactos/CMakeLists.txt [iso-8859-1] Sun Jul 21 13:33:03 2013 @@ -235,6 +235,9 @@ add_subdirectory(subsystems) add_subdirectory(win32ss)
+ # Create {bootcd, livecd, bootcdregtest}.lst + create_iso_lists() + file(MAKE_DIRECTORY ${REACTOS_BINARY_DIR}/include/reactos)
add_dependency_footer()
Modified: trunk/reactos/boot/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/reactos/boot/CMakeLists.txt?rev=595... ============================================================================== --- trunk/reactos/boot/CMakeLists.txt [iso-8859-1] (original) +++ trunk/reactos/boot/CMakeLists.txt [iso-8859-1] Sun Jul 21 13:33:03 2013 @@ -1,50 +1,27 @@ ##bootcd #clear it out -file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bootcd.cmake - "file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bootcd)\n") +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bootcd.lst "")
add_custom_target(bootcd - ${CMAKE_COMMAND} -D CD_DIR=${CMAKE_CURRENT_BINARY_DIR}/bootcd - -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 + 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 DEPENDS native-cdmake VERBATIM) - + ##bootcdregtest #clear it out -file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bootcdregtest.cmake - "file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bootcdregtest)\n") +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/bootcdregtest.lst "")
add_custom_target(bootcdregtest - ${CMAKE_COMMAND} -D CD_DIR=${CMAKE_CURRENT_BINARY_DIR}/bootcdregtest - -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 + 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 VERBATIM) -
##livecd -#clear it out -file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/livecd.cmake - "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") +#clear it out and create the empty Desktop folder +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/livecd.lst "Profiles/Default User/Desktop\n")
add_custom_target(livecd - ${CMAKE_COMMAND} -D CD_DIR=${CMAKE_CURRENT_BINARY_DIR}/livecd - -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 + 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 VERBATIM)
Modified: trunk/reactos/cmake/CMakeMacros.cmake URL: http://svn.reactos.org/svn/reactos/trunk/reactos/cmake/CMakeMacros.cmake?rev... ============================================================================== --- trunk/reactos/cmake/CMakeMacros.cmake [iso-8859-1] (original) +++ trunk/reactos/cmake/CMakeMacros.cmake [iso-8859-1] Sun Jul 21 13:33:03 2013 @@ -227,13 +227,14 @@ if(_CD_NO_CAB) #directly on cd foreach(item ${_CD_FILE}) - file(APPEND ${REACTOS_BINARY_DIR}/boot/bootcd.cmake "file(COPY "${item}" DESTINATION "${CD_DIR}/${_CD_DESTINATION}")\n") + if(_CD_NAME_ON_CD) + #rename it in the cd tree + set(__file ${_CD_NAME_ON_CD}) + else() + get_filename_component(__file ${item} NAME) + endif() + set_property(GLOBAL APPEND PROPERTY BOOTCD_FILE_LIST "${_CD_DESTINATION}/${__file}=${item}") endforeach() - if(_CD_NAME_ON_CD) - get_filename_component(__file ${_CD_FILE} NAME) - #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") - endif() if(_CD_TARGET) #manage dependency add_dependencies(bootcd ${_CD_TARGET}) @@ -259,13 +260,14 @@ add_dependencies(livecd ${_CD_TARGET}) endif() foreach(item ${_CD_FILE}) - file(APPEND ${REACTOS_BINARY_DIR}/boot/livecd.cmake "file(COPY "${item}" DESTINATION "${CD_DIR}/${_CD_DESTINATION}")\n") + if(_CD_NAME_ON_CD) + #rename it in the cd tree + set(__file ${_CD_NAME_ON_CD}) + else() + get_filename_component(__file ${item} NAME) + endif() + set_property(GLOBAL APPEND PROPERTY LIVECD_FILE_LIST "${_CD_DESTINATION}/${__file}=${item}") endforeach() - if(_CD_NAME_ON_CD) - get_filename_component(__file ${_CD_FILE} NAME) - #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") - endif() endif() #end livecd
#do we add it to regtest? @@ -275,13 +277,14 @@ if(_CD_NO_CAB) #directly on cd foreach(item ${_CD_FILE}) - file(APPEND ${REACTOS_BINARY_DIR}/boot/bootcdregtest.cmake "file(COPY "${item}" DESTINATION "${CD_DIR}/${_CD_DESTINATION}")\n") + if(_CD_NAME_ON_CD) + #rename it in the cd tree + set(__file ${_CD_NAME_ON_CD}) + else() + get_filename_component(__file ${item} NAME) + endif() + set_property(GLOBAL APPEND PROPERTY BOOTCDREGTEST_FILE_LIST "${_CD_DESTINATION}/${__file}=${item}") endforeach() - if(_CD_NAME_ON_CD) - get_filename_component(__file ${_CD_FILE} NAME) - #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") - endif() if(_CD_TARGET) #manage dependency add_dependencies(bootcdregtest ${_CD_TARGET}) @@ -296,6 +299,23 @@ #endif() endif() endif() #end bootcd +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
Modified: trunk/reactos/media/vgafonts/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/reactos/media/vgafonts/CMakeLists.t... ============================================================================== --- trunk/reactos/media/vgafonts/CMakeLists.txt [iso-8859-1] (original) +++ trunk/reactos/media/vgafonts/CMakeLists.txt [iso-8859-1] Sun Jul 21 13:33:03 2013 @@ -18,4 +18,3 @@ 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 FOR all)
Modified: trunk/reactos/tools/cdmake/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/reactos/tools/cdmake/CMakeLists.txt... ============================================================================== --- trunk/reactos/tools/cdmake/CMakeLists.txt [iso-8859-1] (original) +++ trunk/reactos/tools/cdmake/CMakeLists.txt [iso-8859-1] Sun Jul 21 13:33:03 2013 @@ -1,2 +1,2 @@ +add_executable(cdmake cdmake.c dirhash.c llmosrt.c)
-add_executable(cdmake cdmake.c llmosrt.c)
Modified: trunk/reactos/tools/cdmake/cdmake.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/tools/cdmake/cdmake.c?rev=5... ============================================================================== --- trunk/reactos/tools/cdmake/cdmake.c [iso-8859-1] (original) +++ trunk/reactos/tools/cdmake/cdmake.c [iso-8859-1] Sun Jul 21 13:33:03 2013 @@ -33,8 +33,13 @@ #include <stdlib.h> #include <string.h> #ifdef _WIN32 +# define WIN32_LEAN_AND_MEAN +# include <windows.h> # include <io.h> # include <dos.h> +# ifdef _MSC_VER +# define R_OK 4 +# endif #else # if defined(__FreeBSD__) || defined(__APPLE__) # include <sys/uio.h> @@ -45,28 +50,19 @@ # include <sys/types.h> # include <dirent.h> # include <unistd.h> +# define TRUE 1 +# define FALSE 0 #endif // _WIN32 #include <ctype.h> #include <setjmp.h> #include <time.h> -#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 +#include "dirsep.h" +#include "dirhash.h"
typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned long DWORD; typedef int BOOL; - -const BOOL TRUE = 1; -const BOOL FALSE = 0;
// file system parameters
@@ -115,6 +111,7 @@ char extension[MAX_EXTENSION_LENGTH+1]; char extension_on_cd[MAX_CDEXTENSION_LENGTH+1]; char *joliet_name; + const char *orig_name; DATE_AND_TIME date_and_time; DWORD sector; DWORD size; @@ -172,6 +169,8 @@ DWORD joliet_path_table_size; DWORD joliet_little_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 @@ -1067,6 +1066,159 @@ }
#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 @@ -1455,14 +1607,23 @@ } else { + const char *file_source; old_end_source = end_source; - get_file_specifications(q); - *end_source = 0; + if (!q->orig_name) + { + get_file_specifications(q); + *end_source = 0; + file_source = source; + } + else + { + file_source = q->orig_name; + } if (verbosity == VERBOSE) - printf("Writing %s\n", source); - file = fopen(source, "rb"); + printf("Writing contents of %s\n", file_source); + file = fopen(file_source, "rb"); 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); while (size > 0) { @@ -1472,7 +1633,7 @@ if (fread (cd.buffer + cd.count, n, 1, file) < 1) { fclose(file); - error_exit("Read error in file %s\n", source); + error_exit("Read error in file %s\n", file_source); } cd.count += n; if (cd.count == BUFFER_SIZE) @@ -1626,23 +1787,71 @@ if (cd.filespecs[0] == 0) error_exit("Missing image file specifications");
- - // set source[] and end_source to source directory, with a terminating directory separator - - end_source = source + strlen(source); - if (end_source[-1] == ':') - *end_source++ = '.'; - if (end_source[-1] != DIR_SEPARATOR_CHAR) - *end_source++ = DIR_SEPARATOR_CHAR; - - // scan all files and create directory structure in memory - - make_directory_records(&root); - - // sort path table entries - - root.next_in_path_table = sort_linked_list(root.next_in_path_table, 1, - compare_path_table_order); + if (source[0] != '@') + { + /* set source[] and end_source to source directory, + * with a terminating directory separator */ + end_source = source + strlen(source); + if (end_source[-1] == ':') + *end_source++ = '.'; + if (end_source[-1] != DIR_SEPARATOR_CHAR) + *end_source++ = DIR_SEPARATOR_CHAR; + + /* scan all files and create directory structure in memory */ + 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, ""); + +#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); + + /* 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);
// initialize CD-ROM write buffer
@@ -1704,9 +1913,9 @@ if (verbosity >= NORMAL) puts("CD-ROM image made successfully");
+ dir_hash_destroy(&specified_files); release_memory(); return 0; }
- /* EOF */
Added: 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 (added) +++ trunk/reactos/tools/cdmake/dirhash.c [iso-8859-1] Sun Jul 21 13:33:03 2013 @@ -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); +}
Propchange: trunk/reactos/tools/cdmake/dirhash.c ------------------------------------------------------------------------------ svn:eol-style = native
Added: 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 (added) +++ trunk/reactos/tools/cdmake/dirhash.h [iso-8859-1] Sun Jul 21 13:33:03 2013 @@ -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_
Propchange: trunk/reactos/tools/cdmake/dirhash.h ------------------------------------------------------------------------------ svn:eol-style = native
Added: trunk/reactos/tools/cdmake/dirsep.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/tools/cdmake/dirsep.h?rev=5... ============================================================================== --- trunk/reactos/tools/cdmake/dirsep.h (added) +++ trunk/reactos/tools/cdmake/dirsep.h [iso-8859-1] Sun Jul 21 13:33:03 2013 @@ -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
Propchange: trunk/reactos/tools/cdmake/dirsep.h ------------------------------------------------------------------------------ svn:eol-style = native