Bootcd target
Modified: trunk/reactos/ReactOS.xml
Added: trunk/reactos/bootdata/
Added: trunk/reactos/bootdata/bootcd/
Added: trunk/reactos/bootdata/bootcd/bootcd.xml
Added: trunk/reactos/bootdata/bootdata.xml
Added: trunk/reactos/tools/cdmake/
Added: trunk/reactos/tools/cdmake/cdmake.c
Added: trunk/reactos/tools/cdmake/cdmake.mak
Added: trunk/reactos/tools/cdmake/llmosrt.c
Added: trunk/reactos/tools/cdmake/readme.txt
Modified: trunk/reactos/tools/rbuild/backend/mingw/modulehandler.cpp
Modified: trunk/reactos/tools/tools.mak
Property changes on: trunk/reactos
___________________________________________________________________
Name: svn:ignore
   + reactos
obj-i386
output-i386
makefile.auto
ReactOS.iso

Modified: trunk/reactos/ReactOS.xml
--- trunk/reactos/ReactOS.xml	2006-01-27 22:10:19 UTC (rev 4)
+++ trunk/reactos/ReactOS.xml	2006-01-27 22:21:26 UTC (rev 5)
@@ -43,9 +43,11 @@
 	<directory name="boot">
 		<xi:include href="boot/boot.xml" />
 	</directory>
+-->
 	<directory name="bootdata">
 		<xi:include href="bootdata/bootdata.xml" />
 	</directory>
+<!--
 	<directory name="drivers">
 		<xi:include href="drivers/directory.xml" />
 	</directory>

Added: trunk/reactos/bootdata/bootcd/bootcd.xml
--- trunk/reactos/bootdata/bootcd/bootcd.xml	2006-01-27 22:10:19 UTC (rev 4)
+++ trunk/reactos/bootdata/bootcd/bootcd.xml	2006-01-27 22:21:26 UTC (rev 5)
@@ -0,0 +1,2 @@
+<module name="bootcd" type="iso">
+</module>

Added: trunk/reactos/bootdata/bootdata.xml
--- trunk/reactos/bootdata/bootdata.xml	2006-01-27 22:10:19 UTC (rev 4)
+++ trunk/reactos/bootdata/bootdata.xml	2006-01-27 22:21:26 UTC (rev 5)
@@ -0,0 +1,5 @@
+<group>
+<directory name="bootcd">
+	<xi:include href="bootcd/bootcd.xml" />
+</directory>
+</group>

Added: trunk/reactos/tools/cdmake/cdmake.c
--- trunk/reactos/tools/cdmake/cdmake.c	2006-01-27 22:10:19 UTC (rev 4)
+++ trunk/reactos/tools/cdmake/cdmake.c	2006-01-27 22:21:26 UTC (rev 5)
@@ -0,0 +1,1675 @@
+/*
+ * CD-ROM Maker
+ * by Philip J. Erdelsky
+ * pje@acm.org
+ * http://www.alumni.caltech.edu/~pje/
+ *
+ * ElTorito-Support
+ * by Eric Kohl
+ * ekohl@rz-online.de
+ *
+ * Linux port
+ * by Casper S. Hornstrup
+ * chorns@users.sourceforge.net
+ *
+ * Joliet support
+ * by Filip Navara
+ * xnavara@volny.cz
+ * Limitations:
+ * - No Joliet file name validations
+ * - Very bad ISO file name generation
+ *
+ * 
+ * convert long filename to iso9660 file name by Magnus Olsen
+ * magnus@greatlord.com
+ *
+ * $Id: cdmake.c 18952 2005-11-02 16:13:00Z gvg $
+ */
+
+/* According to his website, this file was released into the public domain by Phillip J. Erdelsky */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef WIN32
+# include <io.h>
+# include <dos.h>
+#else
+# ifdef __FreeBSD__
+#  include <sys/uio.h>
+# else
+#  include <sys/io.h>
+# endif // __FreeBSD__
+# include <errno.h>
+# include <sys/types.h>
+# include <dirent.h>
+# include <unistd.h>
+#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
+
+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
+#define MAX_NAME_LENGTH		64
+#define MAX_CDNAME_LENGTH	8
+#define MAX_EXTENSION_LENGTH	10
+#define MAX_CDEXTENSION_LENGTH	3
+#define SECTOR_SIZE		2048
+#define BUFFER_SIZE		(8 * SECTOR_SIZE)
+
+const BYTE HIDDEN_FLAG    = 1;
+const BYTE DIRECTORY_FLAG = 2;
+
+
+struct cd_image
+{
+  FILE *file;
+  DWORD sector;         // sector to receive next byte
+  int offset;           // offset of next byte in sector
+  int count;            // number of bytes in buffer
+  char filespecs[128];
+  BYTE *buffer;
+};
+
+typedef struct date_and_time
+{
+  BYTE second;
+  BYTE minute;
+  BYTE hour;
+  BYTE day;
+  BYTE month;
+  WORD year;
+} DATE_AND_TIME, *PDATE_AND_TIME;
+
+typedef struct directory_record
+{
+  struct directory_record *next_in_directory;
+  struct directory_record *next_in_path_table; /* directory record only */
+  struct directory_record *next_in_memory;
+  struct directory_record *first_record;       /* directory record only */
+  struct directory_record *parent;
+  BYTE flags;
+  char name[MAX_NAME_LENGTH+1];
+  char name_on_cd[MAX_CDNAME_LENGTH+1];
+  char extension[MAX_EXTENSION_LENGTH+1];
+  char extension_on_cd[MAX_CDEXTENSION_LENGTH+1];
+  char *joliet_name;
+  DATE_AND_TIME date_and_time;
+  DWORD sector;
+  DWORD size;
+  DWORD joliet_sector;
+  DWORD joliet_size;
+  unsigned level;                             /* directory record only */
+  WORD path_table_index;                      /* directory record only */
+} DIR_RECORD, *PDIR_RECORD;
+
+
+typedef enum directory_record_type
+{
+  DOT_RECORD,
+  DOT_DOT_RECORD,
+  SUBDIRECTORY_RECORD,
+  FILE_RECORD
+} DIR_RECORD_TYPE, *PDIR_RECORD_TYPE;
+
+
+PDIR_RECORD sort_linked_list(PDIR_RECORD,
+    unsigned, int (*)(PDIR_RECORD, PDIR_RECORD));
+
+
+static char DIRECTORY_TIMESTAMP[] = "~Y$'KOR$.3K&";
+
+static jmp_buf error;
+static struct cd_image cd;
+
+char volume_label[32];
+DIR_RECORD root;
+char source[512];
+char *end_source;
+enum {QUIET, NORMAL, VERBOSE} verbosity;
+BOOL show_progress;
+DWORD size_limit;
+BOOL accept_punctuation_marks;
+
+DWORD total_sectors;
+DWORD path_table_size;
+DWORD little_endian_path_table_sector;
+DWORD big_endian_path_table_sector;
+DWORD number_of_files;
+DWORD bytes_in_files;
+DWORD unused_bytes_at_ends_of_files;
+DWORD number_of_directories;
+DWORD bytes_in_directories;
+
+char bootimage[512];
+BOOL eltorito;
+DWORD boot_catalog_sector;
+DWORD boot_image_sector;
+WORD boot_image_size;  // counted in 512 byte sectors
+
+BOOL joliet;
+DWORD joliet_path_table_size;
+DWORD joliet_little_endian_path_table_sector;
+DWORD joliet_big_endian_path_table_sector;
+
+/*-----------------------------------------------------------------------------
+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
+static buffer containing the result. It suppresses leading zeros and commas,
+but optionally pads the result with blanks at the left so the result is always
+exactly 13 characters long (excluding the terminating zero).
+
+CAUTION: A statement containing more than one call on this function, such as
+printf("%s, %s", edit_with_commas(a), edit_with_commas(b)), will produce
+incorrect results because all calls use the same static bufffer.
+-----------------------------------------------------------------------------*/
+
+static char *edit_with_commas(DWORD x, BOOL pad)
+{
+  static char s[14];
+  unsigned i = 13;
+  do
+  {
+    if (i % 4 == 2) s[--i] = ',';
+    s[--i] = (char)(x % 10 + '0');
+  } while ((x/=10) != 0);
+  if (pad)
+  {
+    while (i > 0) s[--i] = ' ';
+  }
+  return s + i;
+}
+
+/*-----------------------------------------------------------------------------
+This function releases all allocated memory blocks.
+-----------------------------------------------------------------------------*/
+
+static void release_memory(void)
+{
+  while (root.next_in_memory != NULL)
+  {
+    struct directory_record *next =
+      root.next_in_memory->next_in_memory;
+    if (joliet)
+      free (root.joliet_name);
+    free (root.next_in_memory);
+    root.next_in_memory = next;
+  }
+  if (cd.buffer != NULL)
+  {
+    free (cd.buffer);
+    cd.buffer = NULL;
+  }
+}
+
+/*-----------------------------------------------------------------------------
+This function edits and displays an error message and then jumps back to the
+error exit point in main().
+-----------------------------------------------------------------------------*/
+
+void error_exit ( const char* fmt, ... )
+{
+  va_list arg;
+
+  va_start(arg, fmt);
+  vprintf(fmt, arg);
+  va_end(arg);
+  printf("\n");
+  if (cd.file != NULL)
+    fclose(cd.file);
+  release_memory();
+  exit(1);
+}
+
+/*-----------------------------------------------------------------------------
+This function, which is called only on the second pass, and only when the
+buffer is not empty, flushes the buffer to the CD-ROM image.
+-----------------------------------------------------------------------------*/
+
+static void flush_buffer(void)
+{
+  if (fwrite(cd.buffer, cd.count, 1, cd.file) < 1)
+    error_exit("File write error");
+  cd.count = 0;
+  if (show_progress)
+  {
+    printf("\r%s ",
+      edit_with_commas((total_sectors - cd.sector) * SECTOR_SIZE, TRUE));
+  }
+}
+
+/*-----------------------------------------------------------------------------
+This function writes a single byte to the CD-ROM image. On the first pass (in
+which cd.handle < 0), it does not actually write anything but merely updates
+the file pointer as though the byte had been written.
+-----------------------------------------------------------------------------*/
+
+static void write_byte(BYTE x)
+{
+  if (cd.file != NULL)
+  {
+    cd.buffer[cd.count] = x;
+    if (++cd.count == BUFFER_SIZE)
+      flush_buffer();
+  }
+  if (++cd.offset == SECTOR_SIZE)
+  {
+    cd.sector++;
+    cd.offset = 0;
+  }
+}
+
+/*-----------------------------------------------------------------------------
+These functions write a word or double word to the CD-ROM image with the
+specified endianity.
+-----------------------------------------------------------------------------*/
+
+static void write_little_endian_word(WORD x)
+{
+  write_byte((BYTE)x);
+  write_byte((BYTE)(x >> 8));
+}
+
+static void write_big_endian_word(WORD x)
+{
+  write_byte((BYTE)(x >> 8));
+  write_byte((BYTE)x);
+}
+
+static void write_both_endian_word(WORD x)
+{
+  write_little_endian_word(x);
+  write_big_endian_word(x);
+}
+
+static void write_little_endian_dword(DWORD x)
+{
+  write_byte((BYTE)x);
+  write_byte((BYTE)(x >> 8));
+  write_byte((BYTE)(x >> 16));
+  write_byte((BYTE)(x >> 24));
+}
+
+static void write_big_endian_dword(DWORD x)
+{
+  write_byte((BYTE)(x >> 24));
+  write_byte((BYTE)(x >> 16));
+  write_byte((BYTE)(x >> 8));
+  write_byte((BYTE)x);
+}
+
+static void write_both_endian_dword(DWORD x)
+{
+  write_little_endian_dword(x);
+  write_big_endian_dword(x);
+}
+
+/*-----------------------------------------------------------------------------
+This function writes enough zeros to fill out the end of a sector, and leaves
+the file pointer at the beginning of the next sector. If the file pointer is
+already at the beginning of a sector, it writes nothing.
+-----------------------------------------------------------------------------*/
+
+static void fill_sector(void)
+{
+  while (cd.offset != 0)
+    write_byte(0);
+}
+
+/*-----------------------------------------------------------------------------
+This function writes a string to the CD-ROM image. The terminating \0 is not
+written.
+-----------------------------------------------------------------------------*/
+
+static void write_string(char *s)
+{
+  while (*s != 0)
+    write_byte(*s++);
+}
+
+/*-----------------------------------------------------------------------------
+This function writes a ansi string as a big endian unicode string to the CD-ROM
+image. The terminating \0 is not written.
+-----------------------------------------------------------------------------*/
+
+static void write_string_as_big_endian_unicode(char *s)
+{
+  while (*s != 0)
+    {
+      write_byte(0);
+      write_byte(*s++);
+    }
+}
+
+/*-----------------------------------------------------------------------------
+This function writes a block of identical bytes to the CD-ROM image.
+-----------------------------------------------------------------------------*/
+
+static void write_block(unsigned count, BYTE value)
+{
+  while (count != 0)
+    {
+      write_byte(value);
+      count--;
+    }
+}
+
+/*-----------------------------------------------------------------------------
+This function writes a block of identical bige endian words to the CD-ROM image.
+-----------------------------------------------------------------------------*/
+
+static void write_word_block(unsigned count, WORD value)
+{
+  while (count != 0)
+    {
+      write_big_endian_word(value);
+      count--;
+    }
+}
+
+/*-----------------------------------------------------------------------------
+This function writes a directory record to the CD_ROM image.
+-----------------------------------------------------------------------------*/
+
+static void
+write_directory_record(PDIR_RECORD d,
+		       DIR_RECORD_TYPE DirType,
+		       BOOL joliet)
+{
+  unsigned identifier_size;
+  unsigned record_size;
+
+  if (joliet)
+  {
+    if (DirType == DOT_RECORD || DirType == DOT_DOT_RECORD)
+      identifier_size = 1;
+    else
+      identifier_size = strlen(d->joliet_name) * 2;
+  }
+  else
+  {
+    switch (DirType)
+    {
+      case DOT_RECORD:
+      case DOT_DOT_RECORD:
+        identifier_size = 1;
+        break;
+      case SUBDIRECTORY_RECORD:
+        /*printf ( "Subdir: %s\n", d->name_on_cd );*/
+        identifier_size = strlen(d->name_on_cd);
+        break;
+      case FILE_RECORD:
+        /*printf ( "File: %s.%s -> %s.%s\n", d->name, d->extension, d->name_on_cd, d->extension_on_cd );*/
+        identifier_size = strlen(d->name_on_cd) + 2;
+        if (d->extension_on_cd[0] != 0)
+          identifier_size += 1 + strlen(d->extension_on_cd);
+        break;
+      default:
+        identifier_size = 1;
+        break;
+    }
+  }
+  record_size = 33 + identifier_size;
+  if ((identifier_size & 1) == 0)
+    record_size++;
+  if (cd.offset + record_size > SECTOR_SIZE)
+    fill_sector();
+  write_byte((BYTE)record_size);
+  write_byte(0); // number of sectors in extended attribute record
+  if (joliet)
+  {
+    write_both_endian_dword(d->joliet_sector);
+    write_both_endian_dword(d->joliet_size);
+  }
+  else
+  {
+    write_both_endian_dword(d->sector);
+    write_both_endian_dword(d->size);
+  }
+  write_byte((BYTE)(d->date_and_time.year - 1900));
+  write_byte(d->date_and_time.month);
+  write_byte(d->date_and_time.day);
+  write_byte(d->date_and_time.hour);
+  write_byte(d->date_and_time.minute);
+  write_byte(d->date_and_time.second);
+  write_byte(0);  // GMT offset
+  write_byte(d->flags);
+  write_byte(0);  // file unit size for an interleaved file
+  write_byte(0);  // interleave gap size for an interleaved file
+  write_both_endian_word((WORD) 1); // volume sequence number
+  write_byte((BYTE)identifier_size);
+  switch (DirType)
+  {
+    case DOT_RECORD:
+      write_byte(0);
+      break;
+    case DOT_DOT_RECORD:
+      write_byte(1);
+      break;
+    case SUBDIRECTORY_RECORD:
+      if (joliet)
+        write_string_as_big_endian_unicode(d->joliet_name);
+      else
+        write_string(d->name_on_cd);
+      break;
+    case FILE_RECORD:
+      if (joliet)
+      {
+        write_string_as_big_endian_unicode(d->joliet_name);
+      }
+      else
+      {
+        write_string(d->name_on_cd);
+        if (d->extension_on_cd[0] != 0)
+        {
+          write_byte('.');
+          write_string(d->extension_on_cd);
+        }
+        write_string(";1");
+      }
+      break;
+  }
+  if ((identifier_size & 1) == 0)
+    write_byte(0);
+}
+
+/*-----------------------------------------------------------------------------
+This function converts the date and time words from an ffblk structure and
+puts them into a date_and_time structure.
+-----------------------------------------------------------------------------*/
+
+static void convert_date_and_time(PDATE_AND_TIME dt, time_t *time)
+{
+  struct tm *timedef;
+
+  timedef = localtime(time);
+
+  dt->second = timedef->tm_sec;
+  dt->minute = timedef->tm_min;
+  dt->hour = timedef->tm_hour;
+  dt->day = timedef->tm_mday;
+  dt->month = timedef->tm_mon + 1;
+  dt->year = timedef->tm_year + 1900;
+}
+
+/*-----------------------------------------------------------------------------
+This function checks the specified character, if necessary, and
+generates an error if it is a punctuation mark other than an underscore.
+It also converts small letters to capital letters and returns the
+result.
+-----------------------------------------------------------------------------*/
+
+static int check_for_punctuation(int c, const char *name)
+{
+  c = toupper(c & 0xFF);
+  if (!accept_punctuation_marks && !isalnum(c) && c != '_')
+    error_exit("Punctuation mark in %s", name);
+  return c;
+}
+
+#if WIN32
+#define strcasecmp stricmp
+#endif//WIN32
+
+/*-----------------------------------------------------------------------------
+This function checks to see if there's a cdname conflict.
+-----------------------------------------------------------------------------*/
+
+int cdname_exists ( PDIR_RECORD d )
+{
+  PDIR_RECORD p = d->parent->first_record;
+  while ( p )
+  {
+    if ( p != d
+      && !strcasecmp ( p->name_on_cd, d->name_on_cd )
+      && !strcasecmp ( p->extension_on_cd, d->extension_on_cd ) )
+      return 1;
+    p = p->next_in_directory;
+  }
+  return 0;
+}
+
+void parse_filename_into_dirrecord ( const char* filename, PDIR_RECORD d, BOOL dir )
+{
+  const char *s = filename;
+  char *t = d->name_on_cd;
+  char *n = d->name;
+  int joliet_length;    
+  int filename_counter;  
+  filename_counter = 1;
+  while (*s != 0)
+  {
+    if (*s == '.')
+    {
+      s++;
+      break;
+    }
+     
+    if ( (t-d->name_on_cd) < sizeof(d->name_on_cd)-1 )
+      *t++ = check_for_punctuation(*s, filename);
+    else if (!joliet)
+    error_exit ("'%s' is not ISO-9660, aborting...", filename );
+    if ( (n-d->name) < sizeof(d->name)-1 )
+      *n++ = *s;
+    else if (!joliet)
+      error_exit ( "'%s' is not ISO-9660, aborting...", filename );
+    s++;
+  }
+  if (strlen(s) > MAX_EXTENSION_LENGTH)
+    {
+      error_exit ( "'%s' has too long extension for cdmake, aborting...", filename );
+    }
+  *t = 0;
+  strcpy(d->extension, s);
+  t = d->extension_on_cd;
+  while ( *s != 0 )
+  {
+    if ( (t-d->extension_on_cd) < (sizeof(d->extension_on_cd)-1) )
+      *t++ = check_for_punctuation(*s, filename);
+    else if (!joliet)
+      error_exit ( "'%s' is not ISO-9660, aborting...", filename );
+    s++;
+  }
+  *t = 0;
+  *n = 0;
+
+  if ( dir )
+  {
+    if (d->extension[0] != 0)
+    {
+      if (joliet)
+        d->extension_on_cd[0] = 0;
+      else
+        error_exit("Directory with extension %s", filename);
+    }
+    d->flags = DIRECTORY_FLAG;
+  } else
+    d->flags = 0;
+
+
+  filename_counter = 1;
+  while  ( cdname_exists ( d ) )
+  {
+	   
+   // the file name must be least 8 char long 
+   if (strlen(d->name_on_cd)<8) 
+	   error_exit ( "'%s' is a duplicate file name, aborting...", filename );   	
+
+   if ((d->name_on_cd[8] == '.') && (strlen(d->name_on_cd) < 13)) 
+       error_exit ( "'%s' is a duplicate file name, aborting...", filename );   	
+   
+   // max 255 times for equal short filename 
+   if (filename_counter>255) error_exit ( "'%s' is a duplicate file name, aborting...", filename );   		       
+   d->name_on_cd[8] = '~';
+   memset(&d->name_on_cd[9],0,5);   
+   sprintf(&d->name_on_cd[9],"%d",filename_counter);   
+   filename_counter++;     		       
+   
+  }
+
+  if ( joliet )
+  {
+    joliet_length = strlen(filename);
+    if (joliet_length > 64)
+      error_exit ( "'%s' is not Joliet, aborting...", filename );
+    d->joliet_name = malloc(joliet_length + 1);
+    strcpy(d->joliet_name, filename);
+  }
+}
+
+/*-----------------------------------------------------------------------------
+This function creates a new directory record with the information from the
+specified ffblk. It links it into the beginning of the directory list
+for the specified parent and returns a pointer to the new record.
+-----------------------------------------------------------------------------*/
+
+#if WIN32
+
+/* Win32 version */
+PDIR_RECORD
+new_directory_record (struct _finddata_t *f,
+		      PDIR_RECORD parent)
+{
+  PDIR_RECORD d;
+
+  d = malloc(sizeof(DIR_RECORD));
+  if (d == NULL)
+    error_exit("Insufficient memory");
+  memset ( d, 0, sizeof(DIR_RECORD) );
+  d->next_in_memory = root.next_in_memory;
+  root.next_in_memory = d;
+
+  /* I need the parent set before calling parse_filename_into_dirrecord(),
+  because that functions checks for duplicate file names*/
+  d->parent = parent;
+  parse_filename_into_dirrecord ( f->name, d, f->attrib & _A_SUBDIR );
+
+  convert_date_and_time(&d->date_and_time, &f->time_write);
+  d->flags |= f->attrib & _A_HIDDEN ? HIDDEN_FLAG : 0;
+  d->size = d->joliet_size = f->size;
+  d->next_in_directory = parent->first_record;
+  parent->first_record = d;
+  return d;
+}
+
+#else
+
+/* Linux version */
+PDIR_RECORD
+new_directory_record (struct dirent *entry,
+		      struct stat *stbuf,
+		      PDIR_RECORD parent)
+{
+  PDIR_RECORD d;
+	/*
+  char *s;
+  char *t;
+  char *n;
+	*/
+
+  d = malloc(sizeof(DIR_RECORD));
+  if (d == NULL)
+    error_exit("Insufficient memory");
+  memset ( d, 0, sizeof(DIR_RECORD) );
+  d->next_in_memory = root.next_in_memory;
+  root.next_in_memory = d;
+
+  /* I need the parent set before calling parse_filename_into_dirrecord(),
+  because that functions checks for duplicate file names*/
+  d->parent = parent;
+#ifdef HAVE_D_TYPE
+  parse_filename_into_dirrecord ( entry->d_name, d, entry->d_type == DT_DIR );
+#else
+  parse_filename_into_dirrecord ( entry->d_name, d, S_ISDIR(stbuf->st_mode) );
+#endif
+
+  convert_date_and_time(&d->date_and_time, &stbuf->st_mtime);
+  d->flags |= entry->d_name[0] == '.' ? HIDDEN_FLAG : 0;
+  d->size = d->joliet_size = stbuf->st_size;
+  d->next_in_directory = parent->first_record;
+  parent->first_record = d;
+  return d;
+}
+
+#endif
+
+/*-----------------------------------------------------------------------------
+This function compares two directory records according to the ISO9660 rules
+for directory sorting and returns a negative value if p is before q, or a
+positive value if p is after q.
+-----------------------------------------------------------------------------*/
+
+static int compare_directory_order(PDIR_RECORD p, PDIR_RECORD q)
+{
+  int n = strcmp(p->name_on_cd, q->name_on_cd);
+  if (n == 0)
+    n = strcmp(p->extension_on_cd, q->extension_on_cd);
+  return n;
+}
+
+/*-----------------------------------------------------------------------------
+This function compares two directory records (which must represent
+directories) according to the ISO9660 rules for path table sorting and returns
+a negative value if p is before q, or a positive vlaue if p is after q.
+-----------------------------------------------------------------------------*/
+
+static int compare_path_table_order(PDIR_RECORD p, PDIR_RECORD q)
+{
+  int n = p->level - q->level;
+  if (p == q)
+    return 0;
+  if (n == 0)
+  {
+    n = compare_path_table_order(p->parent, q->parent);
+    if (n == 0)
+      n = compare_directory_order(p, q);
+  }
+  return n;
+}
+
+/*-----------------------------------------------------------------------------
+This function appends the specified string to the buffer source[].
+-----------------------------------------------------------------------------*/
+
+static void append_string_to_source(char *s)
+{
+  while (*s != 0)
+    *end_source++ = *s++;
+}
+
+/*-----------------------------------------------------------------------------
+This function scans all files from the current source[] (which must end in \,
+and represents a directory already in the database as d),
+and puts the appropriate directory records into the database in memory, with
+the specified root. It calls itself recursively to scan all subdirectories.
+-----------------------------------------------------------------------------*/
+
+#ifdef WIN32
+
+static void
+make_directory_records (PDIR_RECORD d)
+{
+  PDIR_RECORD new_d;
+  struct _finddata_t f;
+  char *old_end_source;
+  int findhandle;
+
+  d->first_record = NULL;
+  strcpy(end_source, "*.*");
+
+  findhandle =_findfirst(source, &f);
+  if (findhandle != 0)
+    {
+      do
+	{
+	  if ((f.attrib & (_A_HIDDEN | _A_SUBDIR)) == 0 && f.name[0] != '.')
+	    {
+	      if (strcmp(f.name, DIRECTORY_TIMESTAMP) == 0)
+		{
+		  convert_date_and_time(&d->date_and_time, &f.time_write);
+		}
+	      else
+		{
+		  if (verbosity == VERBOSE)
+		    {
+		      old_end_source = end_source;
+		      strcpy(end_source, f.name);
+		      printf("%d: file %s\n", d->level, source);
+		      end_source = old_end_source;
+		    }
+		  (void) new_directory_record(&f, d);
+		}
+	    }
+	}
+       while (_findnext(findhandle, &f) == 0);
+
+      _findclose(findhandle);
+    }
+
+  strcpy(end_source, "*.*");
+  findhandle= _findfirst(source, &f);
+  if (findhandle)
+    {
+      do
+	{
+	  if (f.attrib & _A_SUBDIR && f.name[0] != '.')
+	    {
+	      old_end_source = end_source;
+	      append_string_to_source(f.name);
+	      *end_source++ = DIR_SEPARATOR_CHAR;
+	      if (verbosity == VERBOSE)
+		{
+		  *end_source = 0;
+		  printf("%d: directory %s\n", d->level + 1, source);
+		}
+	      if (d->level < MAX_LEVEL)
+		{
+		  new_d = new_directory_record(&f, d);
+		  new_d->next_in_path_table = root.next_in_path_table;
+		  root.next_in_path_table = new_d;
+		  new_d->level = d->level + 1;
+		  make_directory_records(new_d);
+		}
+	      else
+		{
+		  error_exit("Directory is nested too deep");
+		}
+	      end_source = old_end_source;
+	    }
+	}
+       while (_findnext(findhandle, &f) == 0);
+
+      _findclose(findhandle);
+    }
+
+  // sort directory
+  d->first_record = sort_linked_list(d->first_record, 0, compare_directory_order);
+}
+
+#else
+
+/* Linux version */
+static void
+make_directory_records (PDIR_RECORD d)
+{
+  PDIR_RECORD new_d;
+  DIR *dirp;
+  struct dirent *entry;
+  char *old_end_source;
+  struct stat stbuf;
+  char buf[MAX_PATH];
+
+  d->first_record = NULL;
+
+#ifdef HAVE_D_TYPE
+  dirp = opendir(source);
+  if (dirp != NULL)
+    {
+      while ((entry = readdir (dirp)) != NULL)
+        {
+          if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
+            continue; // skip self and parent
+
+          if (entry->d_type == DT_REG) // normal file
+            {
+              // Check for an absolute path
+              if (source[0] == DIR_SEPARATOR_CHAR)
+                {
+                  strcpy(buf, source);
+                  strcat(buf, DIR_SEPARATOR_STRING);
+                  strcat(buf, entry->d_name);
+                }
+              else
+                {
+                  getcwd(buf, sizeof(buf));
+                  strcat(buf, DIR_SEPARATOR_STRING);
+                  strcat(buf, source);
+                  strcat(buf, entry->d_name);
+                }
+
+              if (stat(buf, &stbuf) == -1)
+                {
+                  error_exit("Can't access '%s' (%s)\n", buf, strerror(errno));
+                  return;
+                }
+
+              if (strcmp(entry->d_name, DIRECTORY_TIMESTAMP) == 0)
+                {
+                  convert_date_and_time(&d->date_and_time, &stbuf.st_ctime);
+                }
+              else
+                {
+                  if (verbosity == VERBOSE)
+                    {
+                      printf("%d: file %s\n", d->level, buf);
+                    }
+                  (void) new_directory_record(entry, &stbuf, d);
+                }
+         }
+      }
+      closedir(dirp);
+    }
+  else
+    {
+      error_exit("Can't open %s\n", source);
+      return;
+    }
+
+  dirp = opendir(source);
+  if (dirp != NULL)
+    {
+      while ((entry = readdir (dirp)) != NULL)
+        {
+          if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
+            continue; // skip self and parent
+
+          if (entry->d_type == DT_DIR) // directory
+            {
+              old_end_source = end_source;
+              append_string_to_source(entry->d_name);
+              *end_source++ = DIR_SEPARATOR_CHAR;
+              *end_source = 0;
+              if (verbosity == VERBOSE)
+                {
+                  printf("%d: directory %s\n", d->level + 1, source);
+                }
+              if (d->level < MAX_LEVEL)
+                {
+                  // Check for an absolute path
+                  if (source[0] == DIR_SEPARATOR_CHAR)
+                    {
+                      strcpy(buf, source);
+                    }
+                  else
+                    {
+                      getcwd(buf, sizeof(buf));
+                      strcat(buf, DIR_SEPARATOR_STRING);
+                      strcat(buf, source);
+                    }
+
+                  if (stat(buf, &stbuf) == -1)
+                    {
[truncated at 1000 lines; 1037 more skipped]