* 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(win32ss)
# Create {bootcd, livecd, bootcdregtest}.lst
create_iso_lists()
file(MAKE_DIRECTORY ${REACTOS_BINARY_DIR}/include/reactos)
add_dependency_footer()

View file

@ -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)

View file

@ -227,13 +227,14 @@ function(add_cd_file)
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 @@ function(add_cd_file)
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 @@ function(add_cd_file)
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})
@ -298,6 +301,23 @@ function(add_cd_file)
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
function(add_clean_target _target)
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_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 <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,29 +50,20 @@
# 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
#define MAX_LEVEL 8
@ -115,6 +111,7 @@ typedef struct directory_record
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;
@ -173,6 +170,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
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
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
corresponding to the specified directory record into the source[] buffer. It
@ -1455,14 +1607,23 @@ static void pass(void)
}
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 @@ static void pass(void)
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 @@ int main(int argc, char **argv)
if (cd.filespecs[0] == 0)
error_exit("Missing image file specifications");
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;
// set source[] and end_source to source directory, with a terminating directory separator
/* 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, "");
end_source = source + strlen(source);
if (end_source[-1] == ':')
*end_source++ = '.';
if (end_source[-1] != DIR_SEPARATOR_CHAR)
*end_source++ = DIR_SEPARATOR_CHAR;
#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 all files and create directory structure in memory */
scan_specified_files(&root, &specified_files.root);
}
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);
/* 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 @@ int main(int argc, char **argv)
if (verbosity >= NORMAL)
puts("CD-ROM image made successfully");
dir_hash_destroy(&specified_files);
release_memory();
return 0;
}
/* 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