mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 16:36:33 +00:00
* 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:
parent
95ba3e574b
commit
fe0958fb25
9 changed files with 545 additions and 84 deletions
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
add_executable(cdmake cdmake.c dirhash.c llmosrt.c)
|
||||
|
||||
add_executable(cdmake cdmake.c llmosrt.c)
|
||||
|
|
|
@ -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 */
|
||||
|
|
205
reactos/tools/cdmake/dirhash.c
Normal file
205
reactos/tools/cdmake/dirhash.c
Normal 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);
|
||||
}
|
38
reactos/tools/cdmake/dirhash.h
Normal file
38
reactos/tools/cdmake/dirhash.h
Normal 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_
|
10
reactos/tools/cdmake/dirsep.h
Normal file
10
reactos/tools/cdmake/dirsep.h
Normal 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
|
Loading…
Reference in a new issue