ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

cdmake.c
Go to the documentation of this file.
00001 /*
00002  * CD-ROM Maker
00003  * by Philip J. Erdelsky
00004  * pje@acm.org
00005  * http://www.alumni.caltech.edu/~pje/
00006  *
00007  * ElTorito-Support
00008  * by Eric Kohl
00009  *
00010  * Linux port
00011  * by Casper S. Hornstrup
00012  * chorns@users.sourceforge.net
00013  *
00014  * Joliet support
00015  * by Filip Navara
00016  * xnavara@volny.cz
00017  * Limitations:
00018  * - No Joliet file name validations
00019  * - Very bad ISO file name generation
00020  *
00021  *
00022  * convert long filename to iso9660 file name by Magnus Olsen
00023  * magnus@greatlord.com
00024  *
00025  * $Id: cdmake.c 54866 2012-01-07 17:45:26Z tfaber $
00026  */
00027 
00028 /* According to his website, this file was released into the public domain by Phillip J. Erdelsky */
00029 
00030 #include <stdio.h>
00031 #include <fcntl.h>
00032 #include <sys/stat.h>
00033 #include <stdarg.h>
00034 #include <stdlib.h>
00035 #include <string.h>
00036 #ifdef _WIN32
00037 # include <io.h>
00038 # include <dos.h>
00039 #else
00040 # if defined(__FreeBSD__) || defined(__APPLE__)
00041 #  include <sys/uio.h>
00042 # else
00043 #  include <sys/io.h>
00044 # endif // __FreeBSD__
00045 # include <errno.h>
00046 # include <sys/types.h>
00047 # include <dirent.h>
00048 # include <unistd.h>
00049 #endif // _WIN32
00050 #include <ctype.h>
00051 #include <setjmp.h>
00052 #include <time.h>
00053 #ifndef _WIN32
00054 #ifndef MAX_PATH
00055 #define MAX_PATH 260
00056 #endif
00057 #define DIR_SEPARATOR_CHAR '/'
00058 #define DIR_SEPARATOR_STRING "/"
00059 #else
00060 #define DIR_SEPARATOR_CHAR '\\'
00061 #define DIR_SEPARATOR_STRING "\\"
00062 #endif
00063 
00064 typedef unsigned char BYTE;
00065 typedef unsigned short WORD;
00066 typedef unsigned long DWORD;
00067 typedef int BOOL;
00068 
00069 const BOOL TRUE  = 1;
00070 const BOOL FALSE = 0;
00071 
00072 // file system parameters
00073 
00074 #define MAX_LEVEL       8
00075 #define MAX_NAME_LENGTH     64
00076 #define MAX_CDNAME_LENGTH   8
00077 #define MAX_EXTENSION_LENGTH    10
00078 #define MAX_CDEXTENSION_LENGTH  3
00079 #define SECTOR_SIZE     2048
00080 #define BUFFER_SIZE     (8 * SECTOR_SIZE)
00081 
00082 const BYTE HIDDEN_FLAG    = 1;
00083 const BYTE DIRECTORY_FLAG = 2;
00084 
00085 
00086 struct cd_image
00087 {
00088   FILE *file;
00089   DWORD sector;         // sector to receive next byte
00090   int offset;           // offset of next byte in sector
00091   int count;            // number of bytes in buffer
00092   char filespecs[128];
00093   BYTE *buffer;
00094 };
00095 
00096 typedef struct date_and_time
00097 {
00098   BYTE second;
00099   BYTE minute;
00100   BYTE hour;
00101   BYTE day;
00102   BYTE month;
00103   WORD year;
00104 } DATE_AND_TIME, *PDATE_AND_TIME;
00105 
00106 typedef struct directory_record
00107 {
00108   struct directory_record *next_in_directory;
00109   struct directory_record *next_in_path_table; /* directory record only */
00110   struct directory_record *next_in_memory;
00111   struct directory_record *first_record;       /* directory record only */
00112   struct directory_record *parent;
00113   BYTE flags;
00114   char name[MAX_NAME_LENGTH+1];
00115   char name_on_cd[MAX_CDNAME_LENGTH+1];
00116   char extension[MAX_EXTENSION_LENGTH+1];
00117   char extension_on_cd[MAX_CDEXTENSION_LENGTH+1];
00118   char *joliet_name;
00119   DATE_AND_TIME date_and_time;
00120   DWORD sector;
00121   DWORD size;
00122   DWORD joliet_sector;
00123   DWORD joliet_size;
00124   unsigned level;                             /* directory record only */
00125   WORD path_table_index;                      /* directory record only */
00126 } DIR_RECORD, *PDIR_RECORD;
00127 
00128 
00129 typedef enum directory_record_type
00130 {
00131   DOT_RECORD,
00132   DOT_DOT_RECORD,
00133   SUBDIRECTORY_RECORD,
00134   FILE_RECORD
00135 } DIR_RECORD_TYPE, *PDIR_RECORD_TYPE;
00136 
00137 
00138 PDIR_RECORD sort_linked_list(PDIR_RECORD,
00139     unsigned, int (*)(PDIR_RECORD, PDIR_RECORD));
00140 
00141 
00142 static char DIRECTORY_TIMESTAMP[] = "~Y$'KOR$.3K&";
00143 
00144 static jmp_buf error;
00145 static struct cd_image cd;
00146 
00147 char volume_label[32];
00148 DIR_RECORD root;
00149 char source[512];
00150 char *end_source;
00151 enum {QUIET, NORMAL, VERBOSE} verbosity;
00152 BOOL show_progress;
00153 DWORD size_limit;
00154 BOOL accept_punctuation_marks;
00155 
00156 DWORD total_sectors;
00157 DWORD path_table_size;
00158 DWORD little_endian_path_table_sector;
00159 DWORD big_endian_path_table_sector;
00160 DWORD number_of_files;
00161 DWORD bytes_in_files;
00162 DWORD unused_bytes_at_ends_of_files;
00163 DWORD number_of_directories;
00164 DWORD bytes_in_directories;
00165 
00166 char bootimage[512];
00167 BOOL eltorito;
00168 DWORD boot_catalog_sector;
00169 DWORD boot_image_sector;
00170 WORD boot_image_size;  // counted in 512 byte sectors
00171 
00172 BOOL joliet;
00173 DWORD joliet_path_table_size;
00174 DWORD joliet_little_endian_path_table_sector;
00175 DWORD joliet_big_endian_path_table_sector;
00176 
00177 /*-----------------------------------------------------------------------------
00178 This function edits a 32-bit unsigned number into a comma-delimited form, such
00179 as 4,294,967,295 for the largest possible number, and returns a pointer to a
00180 static buffer containing the result. It suppresses leading zeros and commas,
00181 but optionally pads the result with blanks at the left so the result is always
00182 exactly 13 characters long (excluding the terminating zero).
00183 
00184 CAUTION: A statement containing more than one call on this function, such as
00185 printf("%s, %s", edit_with_commas(a), edit_with_commas(b)), will produce
00186 incorrect results because all calls use the same static bufffer.
00187 -----------------------------------------------------------------------------*/
00188 
00189 static char *edit_with_commas(DWORD x, BOOL pad)
00190 {
00191   static char s[14];
00192   unsigned i = 13;
00193   do
00194   {
00195     if (i % 4 == 2) s[--i] = ',';
00196     s[--i] = (char)(x % 10 + '0');
00197   } while ((x/=10) != 0);
00198   if (pad)
00199   {
00200     while (i > 0) s[--i] = ' ';
00201   }
00202   return s + i;
00203 }
00204 
00205 /*-----------------------------------------------------------------------------
00206 This function releases all allocated memory blocks.
00207 -----------------------------------------------------------------------------*/
00208 
00209 static void release_memory(void)
00210 {
00211   while (root.next_in_memory != NULL)
00212   {
00213     struct directory_record *next =
00214       root.next_in_memory->next_in_memory;
00215     if (joliet)
00216       free (root.joliet_name);
00217     free (root.next_in_memory);
00218     root.next_in_memory = next;
00219   }
00220   if (cd.buffer != NULL)
00221   {
00222     free (cd.buffer);
00223     cd.buffer = NULL;
00224   }
00225 }
00226 
00227 /*-----------------------------------------------------------------------------
00228 This function edits and displays an error message and then jumps back to the
00229 error exit point in main().
00230 -----------------------------------------------------------------------------*/
00231 
00232 void error_exit ( const char* fmt, ... )
00233 {
00234   va_list arg;
00235 
00236   va_start(arg, fmt);
00237   vprintf(fmt, arg);
00238   va_end(arg);
00239   printf("\n");
00240   if (cd.file != NULL)
00241     fclose(cd.file);
00242   release_memory();
00243   exit(1);
00244 }
00245 
00246 /*-----------------------------------------------------------------------------
00247 This function, which is called only on the second pass, and only when the
00248 buffer is not empty, flushes the buffer to the CD-ROM image.
00249 -----------------------------------------------------------------------------*/
00250 
00251 static void flush_buffer(void)
00252 {
00253   if (fwrite(cd.buffer, cd.count, 1, cd.file) < 1)
00254     error_exit("File write error");
00255   cd.count = 0;
00256   if (show_progress)
00257   {
00258     printf("\r%s ",
00259       edit_with_commas((total_sectors - cd.sector) * SECTOR_SIZE, TRUE));
00260   }
00261 }
00262 
00263 /*-----------------------------------------------------------------------------
00264 This function writes a single byte to the CD-ROM image. On the first pass (in
00265 which cd.handle < 0), it does not actually write anything but merely updates
00266 the file pointer as though the byte had been written.
00267 -----------------------------------------------------------------------------*/
00268 
00269 static void write_byte(BYTE x)
00270 {
00271   if (cd.file != NULL)
00272   {
00273     cd.buffer[cd.count] = x;
00274     if (++cd.count == BUFFER_SIZE)
00275       flush_buffer();
00276   }
00277   if (++cd.offset == SECTOR_SIZE)
00278   {
00279     cd.sector++;
00280     cd.offset = 0;
00281   }
00282 }
00283 
00284 /*-----------------------------------------------------------------------------
00285 These functions write a word or double word to the CD-ROM image with the
00286 specified endianity.
00287 -----------------------------------------------------------------------------*/
00288 
00289 static void write_little_endian_word(WORD x)
00290 {
00291   write_byte((BYTE)x);
00292   write_byte((BYTE)(x >> 8));
00293 }
00294 
00295 static void write_big_endian_word(WORD x)
00296 {
00297   write_byte((BYTE)(x >> 8));
00298   write_byte((BYTE)x);
00299 }
00300 
00301 static void write_both_endian_word(WORD x)
00302 {
00303   write_little_endian_word(x);
00304   write_big_endian_word(x);
00305 }
00306 
00307 static void write_little_endian_dword(DWORD x)
00308 {
00309   write_byte((BYTE)x);
00310   write_byte((BYTE)(x >> 8));
00311   write_byte((BYTE)(x >> 16));
00312   write_byte((BYTE)(x >> 24));
00313 }
00314 
00315 static void write_big_endian_dword(DWORD x)
00316 {
00317   write_byte((BYTE)(x >> 24));
00318   write_byte((BYTE)(x >> 16));
00319   write_byte((BYTE)(x >> 8));
00320   write_byte((BYTE)x);
00321 }
00322 
00323 static void write_both_endian_dword(DWORD x)
00324 {
00325   write_little_endian_dword(x);
00326   write_big_endian_dword(x);
00327 }
00328 
00329 /*-----------------------------------------------------------------------------
00330 This function writes enough zeros to fill out the end of a sector, and leaves
00331 the file pointer at the beginning of the next sector. If the file pointer is
00332 already at the beginning of a sector, it writes nothing.
00333 -----------------------------------------------------------------------------*/
00334 
00335 static void fill_sector(void)
00336 {
00337   while (cd.offset != 0)
00338     write_byte(0);
00339 }
00340 
00341 /*-----------------------------------------------------------------------------
00342 This function writes a string to the CD-ROM image. The terminating \0 is not
00343 written.
00344 -----------------------------------------------------------------------------*/
00345 
00346 static void write_string(char *s)
00347 {
00348   while (*s != 0)
00349     write_byte(*s++);
00350 }
00351 
00352 /*-----------------------------------------------------------------------------
00353 This function writes a ansi string as a big endian unicode string to the CD-ROM
00354 image. The terminating \0 is not written.
00355 -----------------------------------------------------------------------------*/
00356 
00357 static void write_string_as_big_endian_unicode(char *s)
00358 {
00359   while (*s != 0)
00360     {
00361       write_byte(0);
00362       write_byte(*s++);
00363     }
00364 }
00365 
00366 /*-----------------------------------------------------------------------------
00367 This function writes a block of identical bytes to the CD-ROM image.
00368 -----------------------------------------------------------------------------*/
00369 
00370 static void write_block(unsigned count, BYTE value)
00371 {
00372   while (count != 0)
00373     {
00374       write_byte(value);
00375       count--;
00376     }
00377 }
00378 
00379 /*-----------------------------------------------------------------------------
00380 This function writes a block of identical bige endian words to the CD-ROM image.
00381 -----------------------------------------------------------------------------*/
00382 
00383 static void write_word_block(unsigned count, WORD value)
00384 {
00385   while (count != 0)
00386     {
00387       write_big_endian_word(value);
00388       count--;
00389     }
00390 }
00391 
00392 /*-----------------------------------------------------------------------------
00393 This function writes a directory record to the CD_ROM image.
00394 -----------------------------------------------------------------------------*/
00395 
00396 static void
00397 write_directory_record(PDIR_RECORD d,
00398                DIR_RECORD_TYPE DirType,
00399                BOOL joliet)
00400 {
00401   unsigned identifier_size;
00402   unsigned record_size;
00403 
00404   if (joliet)
00405   {
00406     if (DirType == DOT_RECORD || DirType == DOT_DOT_RECORD)
00407       identifier_size = 1;
00408     else
00409       identifier_size = strlen(d->joliet_name) * 2;
00410   }
00411   else
00412   {
00413     switch (DirType)
00414     {
00415       case DOT_RECORD:
00416       case DOT_DOT_RECORD:
00417         identifier_size = 1;
00418         break;
00419       case SUBDIRECTORY_RECORD:
00420         /*printf ( "Subdir: %s\n", d->name_on_cd );*/
00421         identifier_size = strlen(d->name_on_cd);
00422         break;
00423       case FILE_RECORD:
00424         /*printf ( "File: %s.%s -> %s.%s\n", d->name, d->extension, d->name_on_cd, d->extension_on_cd );*/
00425         identifier_size = strlen(d->name_on_cd) + 2;
00426         if (d->extension_on_cd[0] != 0)
00427           identifier_size += 1 + strlen(d->extension_on_cd);
00428         break;
00429       default:
00430         identifier_size = 1;
00431         break;
00432     }
00433   }
00434   record_size = 33 + identifier_size;
00435   if ((identifier_size & 1) == 0)
00436     record_size++;
00437   if (cd.offset + record_size > SECTOR_SIZE)
00438     fill_sector();
00439   write_byte((BYTE)record_size);
00440   write_byte(0); // number of sectors in extended attribute record
00441   if (joliet)
00442   {
00443     write_both_endian_dword(d->joliet_sector);
00444     write_both_endian_dword(d->joliet_size);
00445   }
00446   else
00447   {
00448     write_both_endian_dword(d->sector);
00449     write_both_endian_dword(d->size);
00450   }
00451   write_byte((BYTE)(d->date_and_time.year - 1900));
00452   write_byte(d->date_and_time.month);
00453   write_byte(d->date_and_time.day);
00454   write_byte(d->date_and_time.hour);
00455   write_byte(d->date_and_time.minute);
00456   write_byte(d->date_and_time.second);
00457   write_byte(0);  // GMT offset
00458   write_byte(d->flags);
00459   write_byte(0);  // file unit size for an interleaved file
00460   write_byte(0);  // interleave gap size for an interleaved file
00461   write_both_endian_word((WORD) 1); // volume sequence number
00462   write_byte((BYTE)identifier_size);
00463   switch (DirType)
00464   {
00465     case DOT_RECORD:
00466       write_byte(0);
00467       break;
00468     case DOT_DOT_RECORD:
00469       write_byte(1);
00470       break;
00471     case SUBDIRECTORY_RECORD:
00472       if (joliet)
00473         write_string_as_big_endian_unicode(d->joliet_name);
00474       else
00475         write_string(d->name_on_cd);
00476       break;
00477     case FILE_RECORD:
00478       if (joliet)
00479       {
00480         write_string_as_big_endian_unicode(d->joliet_name);
00481       }
00482       else
00483       {
00484         write_string(d->name_on_cd);
00485         if (d->extension_on_cd[0] != 0)
00486         {
00487           write_byte('.');
00488           write_string(d->extension_on_cd);
00489         }
00490         write_string(";1");
00491       }
00492       break;
00493   }
00494   if ((identifier_size & 1) == 0)
00495     write_byte(0);
00496 }
00497 
00498 /*-----------------------------------------------------------------------------
00499 This function converts the date and time words from an ffblk structure and
00500 puts them into a date_and_time structure.
00501 -----------------------------------------------------------------------------*/
00502 
00503 static void convert_date_and_time(PDATE_AND_TIME dt, time_t *time)
00504 {
00505   struct tm *timedef;
00506 
00507   timedef = localtime(time);
00508 
00509   dt->second = timedef->tm_sec;
00510   dt->minute = timedef->tm_min;
00511   dt->hour = timedef->tm_hour;
00512   dt->day = timedef->tm_mday;
00513   dt->month = timedef->tm_mon + 1;
00514   dt->year = timedef->tm_year + 1900;
00515 }
00516 
00517 /*-----------------------------------------------------------------------------
00518 This function checks the specified character, if necessary, and
00519 generates an error if it is a punctuation mark other than an underscore.
00520 It also converts small letters to capital letters and returns the
00521 result.
00522 -----------------------------------------------------------------------------*/
00523 
00524 static int check_for_punctuation(int c, const char *name)
00525 {
00526   c = toupper(c & 0xFF);
00527   if (!accept_punctuation_marks && !isalnum(c) && c != '_')
00528     error_exit("Punctuation mark in %s", name);
00529   return c;
00530 }
00531 
00532 #if _WIN32
00533 #define strcasecmp stricmp
00534 #endif//_WIN32
00535 
00536 /*-----------------------------------------------------------------------------
00537 This function checks to see if there's a cdname conflict.
00538 -----------------------------------------------------------------------------*/
00539 
00540 int cdname_exists ( PDIR_RECORD d )
00541 {
00542   PDIR_RECORD p = d->parent->first_record;
00543   while ( p )
00544   {
00545     if ( p != d
00546       && !strcasecmp ( p->name_on_cd, d->name_on_cd )
00547       && !strcasecmp ( p->extension_on_cd, d->extension_on_cd ) )
00548       return 1;
00549     p = p->next_in_directory;
00550   }
00551   return 0;
00552 }
00553 
00554 void parse_filename_into_dirrecord ( const char* filename, PDIR_RECORD d, BOOL dir )
00555 {
00556   const char *s = filename;
00557   char *t = d->name_on_cd;
00558   char *n = d->name;
00559   int joliet_length;
00560   int filename_counter;
00561   filename_counter = 1;
00562   while (*s != 0)
00563   {
00564     if (*s == '.')
00565     {
00566       s++;
00567       break;
00568     }
00569 
00570     if ( (size_t)(t-d->name_on_cd) < sizeof(d->name_on_cd)-1 )
00571       *t++ = check_for_punctuation(*s, filename);
00572     else if (!joliet)
00573     error_exit ("'%s' is not ISO-9660, aborting...", filename );
00574     if ( (size_t)(n-d->name) < sizeof(d->name)-1 )
00575       *n++ = *s;
00576     else if (!joliet)
00577       error_exit ( "'%s' is not ISO-9660, aborting...", filename );
00578     s++;
00579   }
00580   if (strlen(s) > MAX_EXTENSION_LENGTH)
00581     {
00582       error_exit ( "'%s' has too long extension for cdmake, aborting...", filename );
00583     }
00584   *t = 0;
00585   strcpy(d->extension, s);
00586   t = d->extension_on_cd;
00587   while ( *s != 0 )
00588   {
00589     if ( (size_t)(t-d->extension_on_cd) < sizeof(d->extension_on_cd)-1 )
00590       *t++ = check_for_punctuation(*s, filename);
00591     else if (!joliet)
00592       error_exit ( "'%s' is not ISO-9660, aborting...", filename );
00593     s++;
00594   }
00595   *t = 0;
00596   *n = 0;
00597 
00598   if ( dir )
00599   {
00600     if (d->extension[0] != 0)
00601     {
00602       if (!joliet)
00603         error_exit("Directory with extension %s", filename);
00604     }
00605     d->flags = DIRECTORY_FLAG;
00606   } else
00607     d->flags = 0;
00608 
00609 
00610   filename_counter = 1;
00611   while  ( cdname_exists ( d ) )
00612   {
00613 
00614    // the file name must be least 8 char long
00615    if (strlen(d->name_on_cd)<8)
00616        error_exit ( "'%s' is a duplicate file name, aborting...", filename );
00617 
00618    if ((d->name_on_cd[8] == '.') && (strlen(d->name_on_cd) < 13))
00619        error_exit ( "'%s' is a duplicate file name, aborting...", filename );
00620 
00621    // max 255 times for equal short filename
00622    if (filename_counter>255) error_exit ( "'%s' is a duplicate file name, aborting...", filename );
00623    d->name_on_cd[8] = '~';
00624    memset(&d->name_on_cd[9],0,5);
00625    sprintf(&d->name_on_cd[9],"%d",filename_counter);
00626    filename_counter++;
00627 
00628   }
00629 
00630   if ( joliet )
00631   {
00632     joliet_length = strlen(filename);
00633     if (joliet_length > 64)
00634       error_exit ( "'%s' is not Joliet, aborting...", filename );
00635     d->joliet_name = malloc(joliet_length + 1);
00636     if (d->joliet_name == NULL)
00637       error_exit("Insufficient memory");
00638     strcpy(d->joliet_name, filename);
00639   }
00640 }
00641 
00642 /*-----------------------------------------------------------------------------
00643 This function creates a new directory record with the information from the
00644 specified ffblk. It links it into the beginning of the directory list
00645 for the specified parent and returns a pointer to the new record.
00646 -----------------------------------------------------------------------------*/
00647 
00648 #if _WIN32
00649 
00650 /* Win32 version */
00651 PDIR_RECORD
00652 new_directory_record (struct _finddata_t *f,
00653               PDIR_RECORD parent)
00654 {
00655   PDIR_RECORD d;
00656 
00657   d = malloc(sizeof(DIR_RECORD));
00658   if (d == NULL)
00659     error_exit("Insufficient memory");
00660   memset ( d, 0, sizeof(DIR_RECORD) );
00661   d->next_in_memory = root.next_in_memory;
00662   root.next_in_memory = d;
00663 
00664   /* I need the parent set before calling parse_filename_into_dirrecord(),
00665   because that functions checks for duplicate file names*/
00666   d->parent = parent;
00667   parse_filename_into_dirrecord ( f->name, d, f->attrib & _A_SUBDIR );
00668 
00669   convert_date_and_time(&d->date_and_time, &f->time_write);
00670   d->flags |= f->attrib & _A_HIDDEN ? HIDDEN_FLAG : 0;
00671   d->size = d->joliet_size = f->size;
00672   d->next_in_directory = parent->first_record;
00673   parent->first_record = d;
00674   return d;
00675 }
00676 
00677 #else
00678 
00679 /* Linux version */
00680 PDIR_RECORD
00681 new_directory_record (struct dirent *entry,
00682               struct stat *stbuf,
00683               PDIR_RECORD parent)
00684 {
00685   PDIR_RECORD d;
00686     /*
00687   char *s;
00688   char *t;
00689   char *n;
00690     */
00691 
00692   d = malloc(sizeof(DIR_RECORD));
00693   if (d == NULL)
00694     error_exit("Insufficient memory");
00695   memset ( d, 0, sizeof(DIR_RECORD) );
00696   d->next_in_memory = root.next_in_memory;
00697   root.next_in_memory = d;
00698 
00699   /* I need the parent set before calling parse_filename_into_dirrecord(),
00700   because that functions checks for duplicate file names*/
00701   d->parent = parent;
00702 #ifdef HAVE_D_TYPE
00703   parse_filename_into_dirrecord ( entry->d_name, d, entry->d_type == DT_DIR );
00704 #else
00705   parse_filename_into_dirrecord ( entry->d_name, d, S_ISDIR(stbuf->st_mode) );
00706 #endif
00707 
00708   convert_date_and_time(&d->date_and_time, &stbuf->st_mtime);
00709   d->flags |= entry->d_name[0] == '.' ? HIDDEN_FLAG : 0;
00710   d->size = d->joliet_size = stbuf->st_size;
00711   d->next_in_directory = parent->first_record;
00712   parent->first_record = d;
00713   return d;
00714 }
00715 
00716 #endif
00717 
00718 /*-----------------------------------------------------------------------------
00719 This function compares two directory records according to the ISO9660 rules
00720 for directory sorting and returns a negative value if p is before q, or a
00721 positive value if p is after q.
00722 -----------------------------------------------------------------------------*/
00723 
00724 static int compare_directory_order(PDIR_RECORD p, PDIR_RECORD q)
00725 {
00726   int n = strcmp(p->name_on_cd, q->name_on_cd);
00727   if (n == 0)
00728     n = strcmp(p->extension_on_cd, q->extension_on_cd);
00729   return n;
00730 }
00731 
00732 /*-----------------------------------------------------------------------------
00733 This function compares two directory records (which must represent
00734 directories) according to the ISO9660 rules for path table sorting and returns
00735 a negative value if p is before q, or a positive vlaue if p is after q.
00736 -----------------------------------------------------------------------------*/
00737 
00738 static int compare_path_table_order(PDIR_RECORD p, PDIR_RECORD q)
00739 {
00740   int n = p->level - q->level;
00741   if (p == q)
00742     return 0;
00743   if (n == 0)
00744   {
00745     n = compare_path_table_order(p->parent, q->parent);
00746     if (n == 0)
00747       n = compare_directory_order(p, q);
00748   }
00749   return n;
00750 }
00751 
00752 /*-----------------------------------------------------------------------------
00753 This function appends the specified string to the buffer source[].
00754 -----------------------------------------------------------------------------*/
00755 
00756 static void append_string_to_source(char *s)
00757 {
00758   while (*s != 0)
00759     *end_source++ = *s++;
00760 }
00761 
00762 /*-----------------------------------------------------------------------------
00763 This function scans all files from the current source[] (which must end in \,
00764 and represents a directory already in the database as d),
00765 and puts the appropriate directory records into the database in memory, with
00766 the specified root. It calls itself recursively to scan all subdirectories.
00767 -----------------------------------------------------------------------------*/
00768 
00769 #ifdef _WIN32
00770 
00771 static void
00772 make_directory_records (PDIR_RECORD d)
00773 {
00774   PDIR_RECORD new_d;
00775   struct _finddata_t f;
00776   char *old_end_source;
00777   int findhandle;
00778 
00779   d->first_record = NULL;
00780   strcpy(end_source, "*.*");
00781 
00782   findhandle =_findfirst(source, &f);
00783   if (findhandle != 0)
00784     {
00785       do
00786     {
00787       if ((f.attrib & (_A_HIDDEN | _A_SUBDIR)) == 0 && f.name[0] != '.')
00788         {
00789           if (strcmp(f.name, DIRECTORY_TIMESTAMP) == 0)
00790         {
00791           convert_date_and_time(&d->date_and_time, &f.time_write);
00792         }
00793           else
00794         {
00795           if (verbosity == VERBOSE)
00796             {
00797               old_end_source = end_source;
00798               strcpy(end_source, f.name);
00799               printf("%d: file %s\n", d->level, source);
00800               end_source = old_end_source;
00801             }
00802           (void) new_directory_record(&f, d);
00803         }
00804         }
00805     }
00806        while (_findnext(findhandle, &f) == 0);
00807 
00808       _findclose(findhandle);
00809     }
00810 
00811   strcpy(end_source, "*.*");
00812   findhandle= _findfirst(source, &f);
00813   if (findhandle)
00814     {
00815       do
00816     {
00817       if (f.attrib & _A_SUBDIR && f.name[0] != '.')
00818         {
00819           old_end_source = end_source;
00820           append_string_to_source(f.name);
00821           *end_source++ = DIR_SEPARATOR_CHAR;
00822           if (verbosity == VERBOSE)
00823         {
00824           *end_source = 0;
00825           printf("%d: directory %s\n", d->level + 1, source);
00826         }
00827           if (d->level < MAX_LEVEL)
00828         {
00829           new_d = new_directory_record(&f, d);
00830           new_d->next_in_path_table = root.next_in_path_table;
00831           root.next_in_path_table = new_d;
00832           new_d->level = d->level + 1;
00833           make_directory_records(new_d);
00834         }
00835           else
00836         {
00837           error_exit("Directory is nested too deep");
00838         }
00839           end_source = old_end_source;
00840         }
00841     }
00842        while (_findnext(findhandle, &f) == 0);
00843 
00844       _findclose(findhandle);
00845     }
00846 
00847   // sort directory
00848   d->first_record = sort_linked_list(d->first_record, 0, compare_directory_order);
00849 }
00850 
00851 #else
00852 
00853 /* Linux version */
00854 static void
00855 make_directory_records (PDIR_RECORD d)
00856 {
00857   PDIR_RECORD new_d;
00858   DIR *dirp;
00859   struct dirent *entry;
00860   char *old_end_source;
00861   struct stat stbuf;
00862   char buf[MAX_PATH];
00863 
00864   d->first_record = NULL;
00865 
00866 #ifdef HAVE_D_TYPE
00867   dirp = opendir(source);
00868   if (dirp != NULL)
00869     {
00870       while ((entry = readdir (dirp)) != NULL)
00871         {
00872           if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
00873             continue; // skip self and parent
00874 
00875           if (entry->d_type == DT_REG) // normal file
00876             {
00877               // Check for an absolute path
00878               if (source[0] == DIR_SEPARATOR_CHAR)
00879                 {
00880                   strcpy(buf, source);
00881                   strcat(buf, DIR_SEPARATOR_STRING);
00882                   strcat(buf, entry->d_name);
00883                 }
00884               else
00885                 {
00886                   if (!getcwd(buf, sizeof(buf)))
00887                     error_exit("Can't get CWD: %s\n", strerror(errno));
00888                   strcat(buf, DIR_SEPARATOR_STRING);
00889                   strcat(buf, source);
00890                   strcat(buf, entry->d_name);
00891                 }
00892 
00893               if (stat(buf, &stbuf) == -1)
00894                 {
00895                   error_exit("Can't access '%s' (%s)\n", buf, strerror(errno));
00896                   return;
00897                 }
00898 
00899               if (strcmp(entry->d_name, DIRECTORY_TIMESTAMP) == 0)
00900                 {
00901                   convert_date_and_time(&d->date_and_time, &stbuf.st_ctime);
00902                 }
00903               else
00904                 {
00905                   if (verbosity == VERBOSE)
00906                     {
00907                       printf("%d: file %s\n", d->level, buf);
00908                     }
00909                   (void) new_directory_record(entry, &stbuf, d);
00910                 }
00911          }
00912       }
00913       closedir(dirp);
00914     }
00915   else
00916     {
00917       error_exit("Can't open %s\n", source);
00918       return;
00919     }
00920 
00921   dirp = opendir(source);
00922   if (dirp != NULL)
00923     {
00924       while ((entry = readdir (dirp)) != NULL)
00925         {
00926           if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
00927             continue; // skip self and parent
00928 
00929           if (entry->d_type == DT_DIR) // directory
00930             {
00931               old_end_source = end_source;
00932               append_string_to_source(entry->d_name);
00933               *end_source++ = DIR_SEPARATOR_CHAR;
00934               *end_source = 0;
00935               if (verbosity == VERBOSE)
00936                 {
00937                   printf("%d: directory %s\n", d->level + 1, source);
00938                 }
00939               if (d->level < MAX_LEVEL)
00940                 {
00941                   // Check for an absolute path
00942                   if (source[0] == DIR_SEPARATOR_CHAR)
00943                     {
00944                       strcpy(buf, source);
00945                     }
00946                   else
00947                     {
00948                       if (!getcwd(buf, sizeof(buf)))
00949                         error_exit("Can't get CWD: %s\n", strerror(errno));
00950                       strcat(buf, DIR_SEPARATOR_STRING);
00951                       strcat(buf, source);
00952                     }
00953 
00954                   if (stat(buf, &stbuf) == -1)
00955                     {
00956                       error_exit("Can't access '%s' (%s)\n", buf, strerror(errno));
00957                       return;
00958                     }
00959           new_d = new_directory_record(entry, &stbuf, d);
00960           new_d->next_in_path_table = root.next_in_path_table;
00961           root.next_in_path_table = new_d;
00962           new_d->level = d->level + 1;
00963           make_directory_records(new_d);
00964         }
00965           else
00966         {
00967           error_exit("Directory is nested too deep");
00968         }
00969           end_source = old_end_source;
00970           *end_source = 0;
00971         }
00972         }
00973       closedir(dirp);
00974     }
00975   else
00976     {
00977       error_exit("Can't open %s\n", source);
00978       return;
00979     }
00980 
00981 #else
00982 
00983   dirp = opendir(source);
00984   if (dirp != NULL)
00985     {
00986       while ((entry = readdir (dirp)) != NULL)
00987         {
00988           if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
00989             continue; // skip self and parent
00990 
00991           // Check for an absolute path
00992           if (source[0] == DIR_SEPARATOR_CHAR)
00993             {
00994               strcpy(buf, source);
00995               strcat(buf, DIR_SEPARATOR_STRING);
00996               strcat(buf, entry->d_name);
00997             }
00998           else
00999             {
01000               if (!getcwd(buf, sizeof(buf)))
01001                 error_exit("Can't get CWD: %s\n", strerror(errno));
01002               strcat(buf, DIR_SEPARATOR_STRING);
01003               strcat(buf, source);
01004               strcat(buf, entry->d_name);
01005             }
01006 
01007           if (stat(buf, &stbuf) == -1)
01008             {
01009               error_exit("Can't access '%s' (%s)\n", buf, strerror(errno));
01010               return;
01011             }
01012 
01013           if (S_ISDIR(stbuf.st_mode))
01014             {
01015               old_end_source = end_source;
01016               append_string_to_source(entry->d_name);
01017               *end_source++ = DIR_SEPARATOR_CHAR;
01018               *end_source = 0;
01019               if (verbosity == VERBOSE)
01020         {
01021           printf("%d: directory %s\n", d->level + 1, source);
01022         }
01023 
01024           if (d->level < MAX_LEVEL)
01025         {
01026           new_d = new_directory_record(entry, &stbuf, d);
01027           new_d->next_in_path_table = root.next_in_path_table;
01028           root.next_in_path_table = new_d;
01029           new_d->level = d->level + 1;
01030           make_directory_records(new_d);
01031         }
01032           else
01033         {
01034           error_exit("Directory is nested too deep");
01035         }
01036 
01037               end_source = old_end_source;
01038               *end_source = 0;
01039             }
01040           else if (S_ISREG(stbuf.st_mode))
01041             {
01042               if (strcmp(entry->d_name, DIRECTORY_TIMESTAMP) == 0)
01043         {
01044           convert_date_and_time(&d->date_and_time, &stbuf.st_ctime);
01045         }
01046           else
01047         {
01048           if (verbosity == VERBOSE)
01049             {
01050               printf("%d: file %s\n", d->level, buf);
01051             }
01052           (void) new_directory_record(entry, &stbuf, d);
01053         }
01054         }
01055         }
01056       closedir (dirp);
01057     }
01058   else
01059     {
01060       error_exit("Can't open %s\n", source);
01061       return;
01062     }
01063 
01064 #endif
01065 
01066   // sort directory
01067   d->first_record = sort_linked_list(d->first_record, 0, compare_directory_order);
01068 }
01069 
01070 #endif
01071 
01072 /*-----------------------------------------------------------------------------
01073 This function loads the file specifications for the file or directory
01074 corresponding to the specified directory record into the source[] buffer. It
01075 is recursive.
01076 -----------------------------------------------------------------------------*/
01077 
01078 static void get_file_specifications(PDIR_RECORD d)
01079 {
01080   if (d != &root)
01081   {
01082     get_file_specifications(d->parent);
01083     if (d->joliet_name == NULL)
01084         append_string_to_source(d->name);
01085     else
01086         append_string_to_source(d->joliet_name);
01087 
01088     if (((d->flags & DIRECTORY_FLAG) == 0 || joliet) && d->extension[0] != 0)
01089     {
01090       if (d->joliet_name == NULL)
01091       {
01092          *end_source++ = '.';
01093          append_string_to_source(d->extension);
01094       }
01095     }
01096     if (d->flags & DIRECTORY_FLAG)
01097       *end_source++ = DIR_SEPARATOR_CHAR;
01098   }
01099 }
01100 
01101 static void pass(void)
01102 {
01103   PDIR_RECORD d;
01104   PDIR_RECORD q;
01105   unsigned int i;
01106   char *t;
01107   unsigned int index;
01108   unsigned int name_length;
01109   DWORD size;
01110   DWORD number_of_sectors;
01111   char *old_end_source;
01112   int n;
01113   FILE *file;
01114 
01115   // first 16 sectors are zeros
01116 
01117   write_block(16 * SECTOR_SIZE, 0);
01118 
01119   // Primary Volume Descriptor
01120 
01121   write_string("\1CD001\1");
01122   write_byte(0);
01123   write_block(32, ' ');  // system identifier
01124 
01125   t = volume_label;
01126   for (i = 0; i < 32; i++)
01127     write_byte( (BYTE)( (*t != 0) ? toupper(*t++) : ' ' ) );
01128 
01129   write_block(8, 0);
01130   write_both_endian_dword(total_sectors);
01131   write_block(32, 0);
01132   write_both_endian_word((WORD) 1); // volume set size
01133   write_both_endian_word((WORD) 1); // volume sequence number
01134   write_both_endian_word((WORD) 2048); // sector size
01135   write_both_endian_dword(path_table_size);
01136   write_little_endian_dword(little_endian_path_table_sector);
01137   write_little_endian_dword((DWORD) 0);  // second little endian path table
01138   write_big_endian_dword(big_endian_path_table_sector);
01139   write_big_endian_dword((DWORD) 0);  // second big endian path table
01140   write_directory_record(&root, DOT_RECORD, FALSE);
01141   write_block(128, ' ');      // volume set identifier
01142   write_block(128, ' ');      // publisher identifier
01143   write_block(128, ' ');      // data preparer identifier
01144   write_block(128, ' ');      // application identifier
01145   write_block(37, ' ');       // copyright file identifier
01146   write_block(37, ' ');       // abstract file identifier
01147   write_block(37, ' ');       // bibliographic file identifier
01148   write_string("0000000000000000");  // volume creation
01149   write_byte(0);
01150   write_string("0000000000000000");  // most recent modification
01151   write_byte(0);
01152   write_string("0000000000000000");  // volume expires
01153   write_byte(0);
01154   write_string("0000000000000000");  // volume is effective
01155   write_byte(0);
01156   write_byte(1);
01157   write_byte(0);
01158   fill_sector();
01159 
01160 
01161   // Boot Volume Descriptor
01162 
01163   if (eltorito == TRUE)
01164     {
01165       write_byte(0);
01166       write_string("CD001\1");
01167       write_string("EL TORITO SPECIFICATION");  // identifier
01168       write_block(9, 0);  // padding
01169       write_block(32, 0);  // unused
01170       write_little_endian_dword(boot_catalog_sector);  // pointer to boot catalog
01171       fill_sector();
01172     }
01173 
01174   // Supplementary Volume Descriptor
01175 
01176   if (joliet)
01177   {
01178     write_string("\2CD001\1");
01179     write_byte(0);
01180 
01181     write_word_block(16, L' '); // system identifier
01182 
01183     t = volume_label;
01184     for (i = 0; i < 16; i++)
01185       write_big_endian_word( (BYTE)( (*t != 0) ? *t++ : ' ' ) );
01186 
01187     write_block(8, 0);
01188     write_both_endian_dword(total_sectors);
01189     write_string("%/E");
01190     write_block(29, 0);
01191     write_both_endian_word((WORD) 1); // volume set size
01192     write_both_endian_word((WORD) 1); // volume sequence number
01193     write_both_endian_word((WORD) 2048); // sector size
01194     write_both_endian_dword(joliet_path_table_size);
01195     write_little_endian_dword(joliet_little_endian_path_table_sector);
01196     write_little_endian_dword((DWORD) 0);  // second little endian path table
01197     write_big_endian_dword(joliet_big_endian_path_table_sector);
01198     write_big_endian_dword((DWORD) 0);  // second big endian path table
01199     write_directory_record(&root, DOT_RECORD, TRUE);
01200     write_word_block(64, ' ');      // volume set identifier
01201     write_word_block(64, ' ');      // publisher identifier
01202     write_word_block(64, ' ');      // data preparer identifier
01203     write_word_block(64, ' ');      // application identifier
01204     write_block(37, ' ');       // copyright file identifier
01205     write_block(37, ' ');       // abstract file identifier
01206     write_block(37, ' ');       // bibliographic file identifier
01207     write_string("0000000000000000");  // volume creation
01208     write_byte(0);
01209     write_string("0000000000000000");  // most recent modification
01210     write_byte(0);
01211     write_string("0000000000000000");  // volume expires
01212     write_byte(0);
01213     write_string("0000000000000000");  // volume is effective
01214     write_byte(0);
01215     write_byte(1);
01216     write_byte(0);
01217     fill_sector();
01218   }
01219 
01220 
01221   // Volume Descriptor Set Terminator
01222   write_string("\377CD001\1");
01223   fill_sector();
01224 
01225   // Boot Catalog
01226   if (eltorito == TRUE)
01227     {
01228       boot_catalog_sector = cd.sector;
01229 
01230       // Validation entry
01231       write_byte(1);
01232       write_byte(0);  // x86 boot code
01233       write_little_endian_word(0);  // reserved
01234       write_string("ReactOS Foundation");
01235       write_block(6, 0); // padding
01236       write_little_endian_word(0x62E);  // checksum
01237       write_little_endian_word(0xAA55);  // signature
01238 
01239       // default entry
01240       write_byte(0x88);  // bootable
01241       write_byte(0);  // no emulation
01242       write_big_endian_word(0);  // load segment = default (0x07c0)
01243       write_byte(0);  // partition type
01244       write_byte(0);  // unused
01245       write_little_endian_word(boot_image_size);  // sector count
01246       write_little_endian_dword(boot_image_sector);  // sector
01247 
01248       fill_sector();
01249     }
01250 
01251   // Boot Image
01252   if (eltorito == TRUE)
01253     {
01254       boot_image_sector = cd.sector;
01255 
01256       file = fopen(bootimage, "rb");
01257       if (file == NULL)
01258         error_exit("Can't open %s\n", bootimage);
01259       fseek(file, 0, SEEK_END);
01260       size = ftell(file);
01261       fseek(file, 0, SEEK_SET);
01262       if (size == 0 || (size % 2048))
01263       {
01264         fclose(file);
01265         error_exit("Invalid boot image size (%lu bytes)\n", size);
01266       }
01267       boot_image_size = size / 512;
01268       while (size > 0)
01269       {
01270         n = BUFFER_SIZE - cd.count;
01271         if ((DWORD) n > size)
01272           n = size;
01273         if (fread (cd.buffer + cd.count, n, 1, file) < 1)
01274         {
01275           fclose(file);
01276           error_exit("Read error in file %s\n", bootimage);
01277         }
01278         cd.count += n;
01279         if (cd.count == BUFFER_SIZE)
01280           flush_buffer();
01281         cd.sector += n / SECTOR_SIZE;
01282         cd.offset += n % SECTOR_SIZE;
01283         size -= n;
01284       }
01285       fclose(file);
01286 //      fill_sector();
01287     }
01288 
01289   // Little Endian Path Table
01290   little_endian_path_table_sector = cd.sector;
01291   write_byte(1);
01292   write_byte(0);  // number of sectors in extended attribute record
01293   write_little_endian_dword(root.sector);
01294   write_little_endian_word((WORD) 1);
01295   write_byte(0);
01296   write_byte(0);
01297 
01298   index = 1;
01299   root.path_table_index = 1;
01300   for (d = root.next_in_path_table; d != NULL; d = d->next_in_path_table)
01301     {
01302       name_length = strlen(d->name_on_cd);
01303       write_byte((BYTE)name_length);
01304       write_byte(0);  // number of sectors in extended attribute record
01305       write_little_endian_dword(d->sector);
01306       write_little_endian_word(d->parent->path_table_index);
01307       write_string(d->name_on_cd);
01308       if (name_length & 1)
01309         write_byte(0);
01310       d->path_table_index = ++index;
01311     }
01312 
01313   path_table_size = (cd.sector - little_endian_path_table_sector) *
01314       SECTOR_SIZE + cd.offset;
01315   fill_sector();
01316 
01317   // Big Endian Path Table
01318 
01319   big_endian_path_table_sector = cd.sector;
01320   write_byte(1);
01321   write_byte(0);  // number of sectors in extended attribute record
01322   write_big_endian_dword(root.sector);
01323   write_big_endian_word((WORD) 1);
01324   write_byte(0);
01325   write_byte(0);
01326 
01327   for (d = root.next_in_path_table; d != NULL; d = d->next_in_path_table)
01328     {
01329       name_length = strlen(d->name_on_cd);
01330       write_byte((BYTE)name_length);
01331       write_byte(0);  // number of sectors in extended attribute record
01332       write_big_endian_dword(d->sector);
01333       write_big_endian_word(d->parent->path_table_index);
01334       write_string(d->name_on_cd);
01335       if (name_length & 1)
01336         write_byte(0);
01337     }
01338   fill_sector();
01339 
01340   if (joliet)
01341   {
01342     // Little Endian Path Table
01343 
01344     joliet_little_endian_path_table_sector = cd.sector;
01345     write_byte(1);
01346     write_byte(0);  // number of sectors in extended attribute record
01347     write_little_endian_dword(root.joliet_sector);
01348     write_little_endian_word((WORD) 1);
01349     write_byte(0);
01350     write_byte(0);
01351 
01352     for (d = root.next_in_path_table; d != NULL; d = d->next_in_path_table)
01353       {
01354         name_length = strlen(d->joliet_name) * 2;
01355         write_byte((BYTE)name_length);
01356         write_byte(0);  // number of sectors in extended attribute record
01357         write_little_endian_dword(d->joliet_sector);
01358         write_little_endian_word(d->parent->path_table_index);
01359         write_string_as_big_endian_unicode(d->joliet_name);
01360       }
01361 
01362     joliet_path_table_size = (cd.sector - joliet_little_endian_path_table_sector) *
01363         SECTOR_SIZE + cd.offset;
01364     fill_sector();
01365 
01366     // Big Endian Path Table
01367 
01368     joliet_big_endian_path_table_sector = cd.sector;
01369     write_byte(1);
01370     write_byte(0);  // number of sectors in extended attribute record
01371     write_big_endian_dword(root.joliet_sector);
01372     write_big_endian_word((WORD) 1);
01373     write_byte(0);
01374     write_byte(0);
01375 
01376     for (d = root.next_in_path_table; d != NULL; d = d->next_in_path_table)
01377       {
01378         name_length = strlen(d->joliet_name) * 2;
01379         write_byte((BYTE)name_length);
01380         write_byte(0);  // number of sectors in extended attribute record
01381         write_big_endian_dword(d->joliet_sector);
01382         write_big_endian_word(d->parent->path_table_index);
01383         write_string_as_big_endian_unicode(d->joliet_name);
01384       }
01385     fill_sector();
01386   }
01387 
01388   // directories and files
01389   for (d = &root; d != NULL; d = d->next_in_path_table)
01390     {
01391       // write directory
01392       d->sector = cd.sector;
01393       write_directory_record(d, DOT_RECORD, FALSE);
01394       write_directory_record(d == &root ? d : d->parent, DOT_DOT_RECORD, FALSE);
01395       for (q = d->first_record; q != NULL; q = q->next_in_directory)
01396         {
01397           write_directory_record(q,
01398                                  q->flags & DIRECTORY_FLAG ? SUBDIRECTORY_RECORD : FILE_RECORD,
01399                                  FALSE);
01400         }
01401       fill_sector();
01402       d->size = (cd.sector - d->sector) * SECTOR_SIZE;
01403 
01404       // write directory for joliet
01405       if (joliet)
01406       {
01407         d->joliet_sector = cd.sector;
01408         write_directory_record(d, DOT_RECORD, TRUE);
01409         write_directory_record(d == &root ? d : d->parent, DOT_DOT_RECORD, TRUE);
01410         for (q = d->first_record; q != NULL; q = q->next_in_directory)
01411           {
01412             write_directory_record(q,
01413                                    q->flags & DIRECTORY_FLAG ? SUBDIRECTORY_RECORD : FILE_RECORD,
01414                                    TRUE);
01415           }
01416         fill_sector();
01417         d->joliet_size = (cd.sector - d->joliet_sector) * SECTOR_SIZE;
01418         bytes_in_directories += d->joliet_size;
01419       }
01420 
01421       number_of_directories++;
01422       bytes_in_directories += d->size;
01423 
01424       // write file data
01425       for (q = d->first_record; q != NULL; q = q->next_in_directory)
01426       {
01427         if ((q->flags & DIRECTORY_FLAG) == 0)
01428         {
01429           q->sector = q->joliet_sector = cd.sector;
01430           size = q->size;
01431           if (cd.file == NULL)
01432           {
01433             number_of_sectors = (size + SECTOR_SIZE - 1) / SECTOR_SIZE;
01434             cd.sector += number_of_sectors;
01435             number_of_files++;
01436             bytes_in_files += size;
01437             unused_bytes_at_ends_of_files +=
01438               number_of_sectors * SECTOR_SIZE - size;
01439           }
01440           else
01441           {
01442             old_end_source = end_source;
01443             get_file_specifications(q);
01444             *end_source = 0;
01445             if (verbosity == VERBOSE)
01446               printf("Writing %s\n", source);
01447             file = fopen(source, "rb");
01448             if (file == NULL)
01449               error_exit("Can't open %s\n", source);
01450             fseek(file, 0, SEEK_SET);
01451             while (size > 0)
01452             {
01453               n = BUFFER_SIZE - cd.count;
01454               if ((DWORD) n > size)
01455                 n = size;
01456               if (fread (cd.buffer + cd.count, n, 1, file) < 1)
01457               {
01458                 fclose(file);
01459                 error_exit("Read error in file %s\n", source);
01460               }
01461               cd.count += n;
01462               if (cd.count == BUFFER_SIZE)
01463                 flush_buffer();
01464               cd.sector += n / SECTOR_SIZE;
01465               cd.offset += n % SECTOR_SIZE;
01466               size -= n;
01467             }
01468             fclose(file);
01469             end_source = old_end_source;
01470             fill_sector();
01471           }
01472         }
01473       }
01474     }
01475 
01476   total_sectors = (DWORD)cd.sector;
01477 }
01478 
01479 static char HELP[] =
01480   "CDMAKE  [-q] [-v] [-p] [-s N] [-m] [-b bootimage] [-j]  source  volume  image\n"
01481   "\n"
01482   "  source        specifications of base directory containing all files to\n"
01483   "                be written to CD-ROM image\n"
01484   "  volume        volume label\n"
01485   "  image         image file or device\n"
01486   "  -q            quiet mode - display nothing but error messages\n"
01487   "  -v            verbose mode - display file information as files are\n"
01488   "                scanned and written - overrides -p option\n"
01489   "  -p            show progress while writing\n"
01490   "  -s N          abort operation before beginning write if image will be\n"
01491   "                larger than N megabytes (i.e. 1024*1024*N bytes)\n"
01492   "  -m            accept punctuation marks other than underscores in\n"
01493   "                names and extensions\n"
01494   "  -b bootimage  create bootable ElTorito CD-ROM using 'no emulation' mode\n"
01495   "  -j            generate Joliet filename records\n";
01496 
01497 /*-----------------------------------------------------------------------------
01498 Program execution starts here.
01499 -----------------------------------------------------------------------------*/
01500 
01501 int main(int argc, char **argv)
01502 {
01503   BOOL q_option = FALSE;
01504   BOOL v_option = FALSE;
01505   int i;
01506   char *t;
01507 
01508   if (argc < 2)
01509   {
01510     puts(HELP);
01511     return 1;
01512   }
01513 
01514   if (setjmp(error))
01515     return 1;
01516 
01517   // initialize root directory
01518 
01519   cd.buffer = malloc (BUFFER_SIZE);
01520   if (cd.buffer == NULL)
01521     error_exit("Insufficient memory");
01522 
01523   memset(&root, 0, sizeof(root));
01524   root.level = 1;
01525   root.flags = DIRECTORY_FLAG;
01526 
01527   // initialize CD-ROM write buffer
01528 
01529   cd.file = NULL;
01530   cd.filespecs[0] = 0;
01531 
01532   // initialize parameters
01533 
01534   verbosity = NORMAL;
01535   size_limit = 0;
01536   show_progress = FALSE;
01537   accept_punctuation_marks = FALSE;
01538   source[0] = 0;
01539   volume_label[0] = 0;
01540 
01541   eltorito = FALSE;
01542 
01543   // scan command line arguments
01544 
01545   for (i = 1; i < argc; i++)
01546     {
01547       if (memcmp(argv[i], "-s", 2) == 0)
01548       {
01549         t = argv[i] + 2;
01550         if (*t == 0)
01551         {
01552           if (++i < argc)
01553             t = argv[i];
01554           else
01555             error_exit("Missing size limit parameter");
01556         }
01557         while (isdigit(*t))
01558           size_limit = size_limit * 10 + *t++ - '0';
01559         if (size_limit < 1 || size_limit > 800)
01560           error_exit("Invalid size limit");
01561         size_limit <<= 9;  // convert megabyte to sector count
01562       }
01563       else if (strcmp(argv[i], "-q") == 0)
01564         q_option = TRUE;
01565       else if (strcmp(argv[i], "-v") == 0)
01566         v_option = TRUE;
01567       else if (strcmp(argv[i], "-p") == 0)
01568         show_progress = TRUE;
01569       else if (strcmp(argv[i], "-m") == 0)
01570         accept_punctuation_marks = TRUE;
01571       else if (strcmp(argv[i], "-j") == 0)
01572         joliet = TRUE;
01573       else if (strcmp(argv[i], "-b") == 0)
01574       {
01575         strcpy(bootimage, argv[++i]);
01576         eltorito = TRUE;
01577       }
01578       else if (i + 2 < argc)
01579       {
01580         strcpy(source, argv[i++]);
01581         strncpy(volume_label, argv[i++], sizeof(volume_label) - 1);
01582         strcpy(cd.filespecs, argv[i]);
01583       }
01584       else
01585         error_exit("Missing command line argument");
01586     }
01587   if (v_option)
01588     {
01589       show_progress = FALSE;
01590       verbosity = VERBOSE;
01591     }
01592   else if (q_option)
01593     {
01594       verbosity = QUIET;
01595       show_progress = FALSE;
01596     }
01597   if (source[0] == 0)
01598     error_exit("Missing source directory");
01599   if (volume_label[0] == 0)
01600     error_exit("Missing volume label");
01601   if (cd.filespecs[0] == 0)
01602     error_exit("Missing image file specifications");
01603 
01604 
01605   // set source[] and end_source to source directory, with a terminating directory separator
01606 
01607   end_source = source + strlen(source);
01608   if (end_source[-1] == ':')
01609     *end_source++ = '.';
01610   if (end_source[-1] != DIR_SEPARATOR_CHAR)
01611     *end_source++ = DIR_SEPARATOR_CHAR;
01612 
01613   // scan all files and create directory structure in memory
01614 
01615   make_directory_records(&root);
01616 
01617   // sort path table entries
01618 
01619   root.next_in_path_table = sort_linked_list(root.next_in_path_table, 1,
01620     compare_path_table_order);
01621 
01622   // initialize CD-ROM write buffer
01623 
01624   cd.file = NULL;
01625   cd.sector = 0;
01626   cd.offset = 0;
01627   cd.count = 0;
01628 
01629   // make non-writing pass over directory structure to obtain the proper
01630   // sector numbers and offsets and to determine the size of the image
01631 
01632   number_of_files = bytes_in_files = number_of_directories =
01633     bytes_in_directories = unused_bytes_at_ends_of_files =0;
01634   pass();
01635 
01636   if (verbosity >= NORMAL)
01637     {
01638       printf("%s bytes ", edit_with_commas(bytes_in_files, TRUE));
01639       printf("in %s files\n", edit_with_commas(number_of_files, FALSE));
01640       printf("%s unused bytes at ends of files\n",
01641         edit_with_commas(unused_bytes_at_ends_of_files, TRUE));
01642       printf("%s bytes ", edit_with_commas(bytes_in_directories, TRUE));
01643       printf("in %s directories\n",
01644         edit_with_commas(number_of_directories, FALSE));
01645       printf("%s other bytes\n", edit_with_commas(root.sector * SECTOR_SIZE, TRUE));
01646       puts("-------------");
01647       printf("%s total bytes\n",
01648         edit_with_commas(total_sectors * SECTOR_SIZE, TRUE));
01649       puts("=============");
01650     }
01651 
01652   if (size_limit != 0 && total_sectors > size_limit)
01653     error_exit("Size limit exceeded");
01654 
01655   // re-initialize CD-ROM write buffer
01656 
01657   cd.file = fopen(cd.filespecs, "w+b");
01658   if (cd.file == NULL)
01659     error_exit("Can't open image file %s", cd.filespecs);
01660   cd.sector = 0;
01661   cd.offset = 0;
01662   cd.count = 0;
01663 
01664 
01665   // make writing pass over directory structure
01666 
01667   pass();
01668 
01669   if (cd.count > 0)
01670     flush_buffer();
01671   if (show_progress)
01672     printf("\r             \n");
01673   if (fclose(cd.file) != 0)
01674     {
01675       cd.file = NULL;
01676       error_exit("File write error in image file %s", cd.filespecs);
01677     }
01678 
01679   if (verbosity >= NORMAL)
01680     puts("CD-ROM image made successfully");
01681 
01682   release_memory();
01683   return 0;
01684 }
01685 
01686 
01687 /* EOF */

Generated on Sun May 27 2012 04:37:45 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.