ReactOS  0.4.14-dev-49-gfb4591c
cdmake.c
Go to the documentation of this file.
1 /*
2  * CD-ROM Maker
3  * by Philip J. Erdelsky
4  * pje@acm.org
5  * http://alumnus.caltech.edu/~pje/
6  *
7  * http://alumnus.caltech.edu/~pje/cdmake.txt
8  *
9  * According to his website, this file was released into the public domain
10  * by Philip J. Erdelsky.
11  */
12 /*
13  * COPYRIGHT: See COPYING in the top level directory
14  * PROJECT: ReactOS CD-ROM Maker
15  * FILE: tools/cdmake/cdmake.c
16  * PURPOSE: CD-ROM Premastering Utility
17  * PROGRAMMERS: Eric Kohl
18  * Casper S. Hornstrup
19  * Filip Navara
20  * Magnus Olsen
21  * Hermes Belusca-Maito
22  *
23  * HISTORY:
24  *
25  * ElTorito-Support
26  * by Eric Kohl
27  *
28  * Linux port
29  * by Casper S. Hornstrup
30  * chorns@users.sourceforge.net
31  *
32  * Joliet support
33  * by Filip Navara
34  * xnavara@volny.cz
35  * Limitations:
36  * - No Joliet file name validations
37  * - Very bad ISO file name generation
38  *
39  * Convert long filename to ISO9660 file name by Magnus Olsen
40  * magnus@greatlord.com
41  */
42 
43 #include <stdio.h>
44 #include <fcntl.h>
45 #include <sys/stat.h>
46 #include <stdarg.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #ifdef _WIN32
50 # define WIN32_LEAN_AND_MEAN
51 # include <windows.h>
52 # include <io.h>
53 # include <dos.h>
54 # ifdef _MSC_VER
55 # define R_OK 4
56 # endif
57 #else
58 # if defined(__FreeBSD__) || defined(__APPLE__)
59 # include <sys/uio.h>
60 # else
61 # include <sys/io.h>
62 # endif // __FreeBSD__
63 # include <errno.h>
64 # include <sys/types.h>
65 # include <dirent.h>
66 # include <unistd.h>
67 # define TRUE 1
68 # define FALSE 0
69 #endif // _WIN32
70 #include <ctype.h>
71 #include <time.h>
72 #include "config.h"
73 #include "dirhash.h"
74 
75 // FIXME! FIXME! Do it in a portable way!!
76 typedef unsigned char BYTE;
77 typedef unsigned short WORD;
78 typedef unsigned long DWORD;
79 typedef int BOOL;
80 
81 // file system parameters
82 
83 #define MAX_LEVEL 8
84 #define MAX_NAME_LENGTH 64
85 #define MAX_CDNAME_LENGTH 8
86 #define MAX_EXTENSION_LENGTH 10
87 #define MAX_CDEXTENSION_LENGTH 3
88 #define SECTOR_SIZE 2048
89 #define BUFFER_SIZE (8 * SECTOR_SIZE)
90 
91 #define HIDDEN_FLAG 1
92 #define DIRECTORY_FLAG 2
93 
94 
95 struct cd_image
96 {
98  DWORD sector; // sector to receive next byte
99  int offset; // offset of next byte in sector
100  int count; // number of bytes in buffer
101  char filespecs[128];
103 };
104 
106 {
110 
111 typedef struct boot_entry
112 {
118  WORD sector_count; // boot_image_size
119  DWORD load_rba; // boot_image_sector
120  // BYTE unused[20];
121  char bootimage[512];
123 
124 typedef struct boot_header
125 {
130  // char id_string[28];
133 
134 typedef struct date_and_time
135 {
143 
144 typedef struct directory_record
145 {
147  struct directory_record *next_in_path_table; /* directory record only */
149  struct directory_record *first_record; /* directory record only */
156  char *joliet_name;
157  const char *orig_name;
163  unsigned level; /* directory record only */
164  WORD path_table_index; /* directory record only */
166 
168 {
174 
175 
177  unsigned, int (*)(PDIR_RECORD, PDIR_RECORD));
178 
179 
180 static char DIRECTORY_TIMESTAMP[] = "~Y$'KOR$.3K&";
181 
182 static struct cd_image cd;
184 
185 char volume_label[32];
186 char source[512];
188 
191 
193 // BOOL compute_crc = FALSE;
194 
195 /*
196  * ISO 9660 information
197  */
200 
205 
206 
207 /*
208  * Stats
209  */
215 
217 
218 
219 /*
220  * El-Torito boot information
221  */
222 BOOL eltorito; // TRUE/FALSE: bootable/non-bootable CD-ROM
223 BOOL multi_boot; // TRUE/FALSE: multi/single-boot CD-ROM
228 
229 /*
230  * Joliet information
231  */
236 
237 /*
238  * UDF information
239  */
240 BOOL make_bridged_udf = TRUE; // TRUE for "UDF-Bridge" (aka. UDF/ISO); FALSE for pure UDF.
241 
242 
243 /*-----------------------------------------------------------------------------
244 This function edits a 32-bit unsigned number into a comma-delimited form, such
245 as 4,294,967,295 for the largest possible number, and returns a pointer to a
246 static buffer containing the result. It suppresses leading zeros and commas,
247 but optionally pads the result with blanks at the left so the result is always
248 exactly 13 characters long (excluding the terminating zero).
249 
250 CAUTION: A statement containing more than one call on this function, such as
251 printf("%s, %s", edit_with_commas(a), edit_with_commas(b)), will produce
252 incorrect results because all calls use the same static bufffer.
253 -----------------------------------------------------------------------------*/
254 
256 {
257  static char s[14];
258  unsigned i = 13;
259  do
260  {
261  if (i % 4 == 2) s[--i] = ',';
262  s[--i] = (char)(x % 10 + '0');
263  } while ((x/=10) != 0);
264  if (pad)
265  {
266  while (i > 0) s[--i] = ' ';
267  }
268  return s + i;
269 }
270 
271 /*-----------------------------------------------------------------------------
272 This function releases all allocated memory blocks.
273 -----------------------------------------------------------------------------*/
274 
275 static void release_memory(void)
276 {
277  while (boot_header_list)
278  {
280 
282  {
285  boot_header_list->entry_list = next_entry;
286  }
287 
289  boot_header_list = next_header;
290  }
291 
292  while (root.next_in_memory != NULL)
293  {
294  PDIR_RECORD next = root.next_in_memory->next_in_memory;
295  if (joliet)
296  free(root.next_in_memory->joliet_name);
297  free(root.next_in_memory);
298  root.next_in_memory = next;
299  }
300  if (joliet)
301  free(root.joliet_name);
302 
303  if (cd.buffer != NULL)
304  {
305  free(cd.buffer);
306  cd.buffer = NULL;
307  }
308 }
309 
310 /*-----------------------------------------------------------------------------
311 This function edits and displays an error message and then jumps back to the
312 error exit point in main().
313 -----------------------------------------------------------------------------*/
314 
315 static void error_exit(const char* fmt, ...)
316 {
317  va_list arg;
318 
319  va_start(arg, fmt);
320  vprintf(fmt, arg);
321  va_end(arg);
322  printf("\n");
323  if (cd.file != NULL)
324  fclose(cd.file);
325  release_memory();
326  exit(1);
327 }
328 
329 /*-----------------------------------------------------------------------------
330 This function, which is called only on the second pass, and only when the
331 buffer is not empty, flushes the buffer to the CD-ROM image.
332 -----------------------------------------------------------------------------*/
333 
334 static void flush_buffer(void)
335 {
336  if (fwrite(cd.buffer, cd.count, 1, cd.file) < 1)
337  error_exit("File write error");
338  cd.count = 0;
339  if (show_progress)
340  {
341  printf("\r%s ",
343  }
344 }
345 
346 /*-----------------------------------------------------------------------------
347 This function writes a single byte to the CD-ROM image. On the first pass (in
348 which cd.handle < 0), it does not actually write anything but merely updates
349 the file pointer as though the byte had been written.
350 -----------------------------------------------------------------------------*/
351 
352 static void write_byte(BYTE x)
353 {
354  if (cd.file != NULL)
355  {
356  cd.buffer[cd.count] = x;
357  if (++cd.count == BUFFER_SIZE)
358  flush_buffer();
359  }
360  if (++cd.offset == SECTOR_SIZE)
361  {
362  cd.sector++;
363  cd.offset = 0;
364  }
365 }
366 
367 /*-----------------------------------------------------------------------------
368 These functions write a word or double word to the CD-ROM image with the
369 specified endianity.
370 -----------------------------------------------------------------------------*/
371 
373 {
374  write_byte((BYTE)x);
375  write_byte((BYTE)(x >> 8));
376 }
377 
379 {
380  write_byte((BYTE)(x >> 8));
381  write_byte((BYTE)x);
382 }
383 
385 {
388 }
389 
391 {
392  write_byte((BYTE)x);
393  write_byte((BYTE)(x >> 8));
394  write_byte((BYTE)(x >> 16));
395  write_byte((BYTE)(x >> 24));
396 }
397 
399 {
400  write_byte((BYTE)(x >> 24));
401  write_byte((BYTE)(x >> 16));
402  write_byte((BYTE)(x >> 8));
403  write_byte((BYTE)x);
404 }
405 
407 {
410 }
411 
412 /*-----------------------------------------------------------------------------
413 This function writes enough zeros to fill out the end of a sector, and leaves
414 the file pointer at the beginning of the next sector. If the file pointer is
415 already at the beginning of a sector, it writes nothing.
416 -----------------------------------------------------------------------------*/
417 
418 static void fill_sector(void)
419 {
420  while (cd.offset != 0)
421  write_byte(0);
422 }
423 
424 /*-----------------------------------------------------------------------------
425 This function writes a string to the CD-ROM image. The terminating \0 is not
426 written.
427 -----------------------------------------------------------------------------*/
428 
429 static void write_string(char *s)
430 {
431  while (*s != 0)
432  write_byte(*s++);
433 }
434 
435 static void write_bytecounted_string(unsigned bytecount, char *s, char padding)
436 {
437  while (*s != 0 && bytecount != 0)
438  {
439  write_byte(*s++);
440  bytecount--;
441  }
442  while (bytecount != 0)
443  {
445  bytecount--;
446  }
447 }
448 
449 /*-----------------------------------------------------------------------------
450 This function writes a ansi string as a big endian unicode string to the CD-ROM
451 image. The terminating \0 is not written.
452 -----------------------------------------------------------------------------*/
453 
455 {
456  while (*s != 0)
457  {
459  }
460 }
461 
462 static void write_bytecounted_string_as_big_endian_unicode(unsigned bytecount, char *s, char padding)
463 {
464  unsigned wordcount = bytecount / 2;
465 
466  while (*s != 0 && wordcount != 0)
467  {
469  wordcount--;
470  }
471  while (wordcount != 0)
472  {
474  wordcount--;
475  }
476 
477  if (bytecount % 2 != 0)
479 }
480 
481 /*-----------------------------------------------------------------------------
482 This function writes a block of identical bytes to the CD-ROM image.
483 -----------------------------------------------------------------------------*/
484 
485 static void write_block(unsigned count, BYTE value)
486 {
487  while (count != 0)
488  {
489  write_byte(value);
490  count--;
491  }
492 }
493 
494 /*-----------------------------------------------------------------------------
495 This function writes a block of identical big endian words to the CD-ROM image.
496 -----------------------------------------------------------------------------*/
497 
498 static void write_word_block(unsigned count, WORD value)
499 {
500  while (count != 0)
501  {
503  count--;
504  }
505 }
506 
507 /*-----------------------------------------------------------------------------
508 This function writes a directory record to the CD_ROM image.
509 -----------------------------------------------------------------------------*/
510 
511 static void
513  DIR_RECORD_TYPE DirType,
514  BOOL joliet)
515 {
516  unsigned identifier_size;
517  unsigned record_size;
518 
519  if (joliet)
520  {
521  if (DirType == DOT_RECORD || DirType == DOT_DOT_RECORD)
522  identifier_size = 1;
523  else
524  identifier_size = strlen(d->joliet_name) * 2;
525  }
526  else
527  {
528  switch (DirType)
529  {
530  case DOT_RECORD:
531  case DOT_DOT_RECORD:
532  identifier_size = 1;
533  break;
534  case SUBDIRECTORY_RECORD:
535  /*printf("Subdir: %s\n", d->name_on_cd);*/
536  identifier_size = strlen(d->name_on_cd);
537  break;
538  case FILE_RECORD:
539  /*printf("File: %s.%s -> %s.%s\n", d->name, d->extension, d->name_on_cd, d->extension_on_cd);*/
540  identifier_size = strlen(d->name_on_cd) + 2;
541  if (d->extension_on_cd[0] != 0)
542  identifier_size += 1 + strlen(d->extension_on_cd);
543  break;
544  default:
545  identifier_size = 1;
546  break;
547  }
548  }
549  record_size = 33 + identifier_size;
550  if ((identifier_size & 1) == 0)
551  record_size++;
552  if (cd.offset + record_size > SECTOR_SIZE)
553  fill_sector();
554  write_byte((BYTE)record_size);
555  write_byte(0); // number of sectors in extended attribute record
556  if (joliet)
557  {
558  write_both_endian_dword(d->joliet_sector);
559  write_both_endian_dword(d->joliet_size);
560  }
561  else
562  {
563  write_both_endian_dword(d->sector);
564  write_both_endian_dword(d->size);
565  }
566  write_byte((BYTE)(d->date_and_time.year - 1900));
567  write_byte(d->date_and_time.month);
568  write_byte(d->date_and_time.day);
569  write_byte(d->date_and_time.hour);
570  write_byte(d->date_and_time.minute);
571  write_byte(d->date_and_time.second);
572  write_byte(0); // GMT offset
573  write_byte(d->flags);
574  write_byte(0); // file unit size for an interleaved file
575  write_byte(0); // interleave gap size for an interleaved file
576  write_both_endian_word(1); // volume sequence number
577  write_byte((BYTE)identifier_size);
578  switch (DirType)
579  {
580  case DOT_RECORD:
581  write_byte(0);
582  break;
583  case DOT_DOT_RECORD:
584  write_byte(1);
585  break;
586  case SUBDIRECTORY_RECORD:
587  if (joliet)
589  else
590  write_string(d->name_on_cd);
591  break;
592  case FILE_RECORD:
593  if (joliet)
594  {
596  }
597  else
598  {
599  write_string(d->name_on_cd);
600  if (d->extension_on_cd[0] != 0)
601  {
602  write_byte('.');
603  write_string(d->extension_on_cd);
604  }
605  write_string(";1");
606  }
607  break;
608  }
609  if ((identifier_size & 1) == 0)
610  write_byte(0);
611 }
612 
613 /*-----------------------------------------------------------------------------
614 This function converts the date and time words from an ffblk structure and
615 puts them into a date_and_time structure.
616 -----------------------------------------------------------------------------*/
617 
619 {
620  struct tm *timedef;
621  timedef = gmtime(time);
622 
623  dt->second = timedef->tm_sec;
624  dt->minute = timedef->tm_min;
625  dt->hour = timedef->tm_hour;
626  dt->day = timedef->tm_mday;
627  dt->month = timedef->tm_mon + 1;
628  dt->year = timedef->tm_year + 1900;
629 }
630 
631 /*-----------------------------------------------------------------------------
632 This function checks the specified character, if necessary, and
633 generates an error if it is a punctuation mark other than an underscore.
634 It also converts small letters to capital letters and returns the
635 result.
636 -----------------------------------------------------------------------------*/
637 
638 static int check_for_punctuation(int c, const char *name)
639 {
640  c = toupper(c & 0xFF);
641  if (!accept_punctuation_marks && !isalnum(c) && c != '_')
642  error_exit("Punctuation mark in %s", name);
643  return c;
644 }
645 
646 /*-----------------------------------------------------------------------------
647 This function checks to see if there's a cdname conflict.
648 -----------------------------------------------------------------------------*/
649 
650 #if defined(_WIN32) && !defined(strcasecmp)
651 #define strcasecmp stricmp
652 #endif // _WIN32
653 
655 {
656  PDIR_RECORD p = d->parent->first_record;
657  while (p)
658  {
659  if ( p != d
660  && !strcasecmp(p->name_on_cd, d->name_on_cd)
661  && !strcasecmp(p->extension_on_cd, d->extension_on_cd) )
662  return TRUE;
663  p = p->next_in_directory;
664  }
665  return FALSE;
666 }
667 
669 {
670  const char *s = filename;
671  char *t = d->name_on_cd;
672  char *n = d->name;
673  int joliet_length;
674  int filename_counter;
675  filename_counter = 1;
676  while (*s != 0)
677  {
678  if (*s == '.')
679  {
680  s++;
681  break;
682  }
683 
684  if ((size_t)(t-d->name_on_cd) < sizeof(d->name_on_cd)-1)
686  else if (!joliet)
687  error_exit("'%s' is not ISO-9660, aborting...", filename);
688 
689  if ((size_t)(n-d->name) < sizeof(d->name)-1)
690  *n++ = *s;
691  else if (!joliet)
692  error_exit("'%s' is not ISO-9660, aborting...", filename);
693  s++;
694  }
695  // Check for extension length
696  if (!joliet && strlen(s) > MAX_EXTENSION_LENGTH)
697  {
698  error_exit("'%s' has too long extension, aborting...", filename);
699  }
700  *t = 0;
701  strcpy(d->extension, s);
702  t = d->extension_on_cd;
703  while (*s != 0)
704  {
705  if ((size_t)(t-d->extension_on_cd) < sizeof(d->extension_on_cd)-1)
707  else if (!joliet)
708  error_exit("'%s' is not ISO-9660, aborting...", filename);
709  s++;
710  }
711  *t = 0;
712  *n = 0;
713 
714  if (dir)
715  {
716  if (d->extension[0] != 0)
717  {
718  if (!joliet)
719  error_exit("Directory with extension '%s'", filename);
720  }
721  d->flags = DIRECTORY_FLAG;
722  } else
723  {
724  d->flags = 0;
725  }
726 
727  filename_counter = 1;
728  while (cdname_exists(d))
729  {
730  // the file name must be at least 8 chars long
731  if (strlen(d->name_on_cd)<8)
732  error_exit("'%s' is a duplicate file name, aborting...", filename);
733 
734  if ((d->name_on_cd[8] == '.') && (strlen(d->name_on_cd) < 13))
735  error_exit("'%s' is a duplicate file name, aborting...", filename);
736 
737  // max 255 times for equal short filename
738  if (filename_counter>255)
739  error_exit("'%s' is a duplicate file name, aborting...", filename);
740 
741  d->name_on_cd[8] = '~';
742  memset(&d->name_on_cd[9],0,5);
743  sprintf(&d->name_on_cd[9],"%d",filename_counter);
744  filename_counter++;
745  }
746 
747  if (joliet)
748  {
749  joliet_length = strlen(filename);
750  if (joliet_length > 64)
751  error_exit("'%s' is not Joliet, aborting...", filename);
752  d->joliet_name = malloc(joliet_length + 1);
753  if (d->joliet_name == NULL)
754  error_exit("Insufficient memory");
755  strcpy(d->joliet_name, filename);
756  }
757 }
758 
759 /*-----------------------------------------------------------------------------
760 This function creates a new directory record with the information from the
761 specified ffblk. It links it into the beginning of the directory list
762 for the specified parent and returns a pointer to the new record.
763 -----------------------------------------------------------------------------*/
764 
765 #ifdef _WIN32
766 
767 /* Win32 version */
771 {
772  PDIR_RECORD d;
773 
774  d = calloc(1, sizeof(*d));
775  if (d == NULL)
776  error_exit("Insufficient memory");
777  d->next_in_memory = root.next_in_memory;
778  root.next_in_memory = d;
779 
780  /* I need the parent set before calling parse_filename_into_dirrecord(),
781  because that functions checks for duplicate file names*/
782  d->parent = parent;
783  parse_filename_into_dirrecord(f->name, d, f->attrib & _A_SUBDIR);
784 
785  convert_date_and_time(&d->date_and_time, &f->time_write);
786  d->flags |= f->attrib & _A_HIDDEN ? HIDDEN_FLAG : 0;
787  d->size = d->joliet_size = f->size;
788  d->next_in_directory = parent->first_record;
789  parent->first_record = d;
790  return d;
791 }
792 
793 #else
794 
795 /* Linux version */
798  struct stat *stbuf,
800 {
801  PDIR_RECORD d;
802 
803  d = calloc(1, sizeof(*d));
804  if (d == NULL)
805  error_exit("Insufficient memory");
806  d->next_in_memory = root.next_in_memory;
807  root.next_in_memory = d;
808 
809  /* I need the parent set before calling parse_filename_into_dirrecord(),
810  because that functions checks for duplicate file names*/
811  d->parent = parent;
812 #ifdef HAVE_D_TYPE
813  parse_filename_into_dirrecord(entry->d_name, d, entry->d_type == DT_DIR);
814 #else
816 #endif
817 
818  convert_date_and_time(&d->date_and_time, &stbuf->st_mtime);
819  d->flags |= entry->d_name[0] == '.' ? HIDDEN_FLAG : 0;
820  d->size = d->joliet_size = stbuf->st_size;
821  d->next_in_directory = parent->first_record;
822  parent->first_record = d;
823  return d;
824 }
825 
826 #endif
827 
828 /*-----------------------------------------------------------------------------
829 This function compares two directory records according to the ISO9660 rules
830 for directory sorting and returns a negative value if p is before q, or a
831 positive value if p is after q.
832 -----------------------------------------------------------------------------*/
833 
835 {
836  int n = strcmp(p->name_on_cd, q->name_on_cd);
837  if (n == 0)
838  n = strcmp(p->extension_on_cd, q->extension_on_cd);
839  return n;
840 }
841 
842 /*-----------------------------------------------------------------------------
843 This function compares two directory records (which must represent
844 directories) according to the ISO9660 rules for path table sorting and returns
845 a negative value if p is before q, or a positive vlaue if p is after q.
846 -----------------------------------------------------------------------------*/
847 
849 {
850  int n = p->level - q->level;
851  if (p == q)
852  return 0;
853  if (n == 0)
854  {
855  n = compare_path_table_order(p->parent, q->parent);
856  if (n == 0)
858  }
859  return n;
860 }
861 
862 /*-----------------------------------------------------------------------------
863 This function appends the specified string to the buffer source[].
864 -----------------------------------------------------------------------------*/
865 
866 static void append_string_to_source(char *s)
867 {
868  while (*s != 0)
869  *end_source++ = *s++;
870 }
871 
872 /*-----------------------------------------------------------------------------
873 This function scans all files from the current source[] (which must end in \,
874 and represents a directory already in the database as d),
875 and puts the appropriate directory records into the database in memory, with
876 the specified root. It calls itself recursively to scan all subdirectories.
877 -----------------------------------------------------------------------------*/
878 
879 #ifdef _WIN32
880 
881 static void
883 {
884  PDIR_RECORD new_d;
885  struct _finddata_t f;
886  char *old_end_source;
887  int findhandle;
888 
889  d->first_record = NULL;
890  strcpy(end_source, "*.*");
891 
892  findhandle = _findfirst(source, &f);
893  if (findhandle != 0)
894  {
895  do
896  {
897  if ((f.attrib & (_A_HIDDEN | _A_SUBDIR)) == 0 && f.name[0] != '.')
898  {
899  if (strcmp(f.name, DIRECTORY_TIMESTAMP) == 0)
900  {
901  convert_date_and_time(&d->date_and_time, &f.time_write);
902  }
903  else
904  {
905  if (verbosity == VERBOSE)
906  {
907  old_end_source = end_source;
908  strcpy(end_source, f.name);
909  printf("%d: file %s\n", d->level, source);
910  end_source = old_end_source;
911  }
913  }
914  }
915  }
916  while (_findnext(findhandle, &f) == 0);
917 
918  _findclose(findhandle);
919  }
920 
921  strcpy(end_source, "*.*");
922  findhandle = _findfirst(source, &f);
923  if (findhandle)
924  {
925  do
926  {
927  if (f.attrib & _A_SUBDIR && f.name[0] != '.')
928  {
929  old_end_source = end_source;
932  if (verbosity == VERBOSE)
933  {
934  *end_source = 0;
935  printf("%d: directory %s\n", d->level + 1, source);
936  }
937  if (d->level < MAX_LEVEL)
938  {
939  new_d = new_directory_record(&f, d);
940  new_d->next_in_path_table = root.next_in_path_table;
941  root.next_in_path_table = new_d;
942  new_d->level = d->level + 1;
943  make_directory_records(new_d);
944  }
945  else
946  {
947  error_exit("Directory is nested too deep");
948  }
949  end_source = old_end_source;
950  }
951  }
952  while (_findnext(findhandle, &f) == 0);
953 
954  _findclose(findhandle);
955  }
956 
957  // sort directory
958  d->first_record = sort_linked_list(d->first_record, 0, compare_directory_order);
959 }
960 
961 #else
962 
963 /* Linux version */
964 static void
966 {
967  PDIR_RECORD new_d;
968  DIR *dirp;
969  struct dirent *entry;
970  char *old_end_source;
971  struct stat stbuf;
972  char buf[MAX_PATH];
973 
974  d->first_record = NULL;
975 
976 #ifdef HAVE_D_TYPE
977  dirp = opendir(source);
978  if (dirp != NULL)
979  {
980  while ((entry = readdir(dirp)) != NULL)
981  {
982  if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
983  continue; // skip self and parent
984 
985  if (entry->d_type == DT_REG) // normal file
986  {
987  // Check for an absolute path
988  if (source[0] == DIR_SEPARATOR_CHAR)
989  {
990  strcpy(buf, source);
992  strcat(buf, entry->d_name);
993  }
994  else
995  {
996  if (!getcwd(buf, sizeof(buf)))
997  error_exit("Cannot get CWD: %s\n", strerror(errno));
999  strcat(buf, source);
1000  strcat(buf, entry->d_name);
1001  }
1002 
1003  if (stat(buf, &stbuf) == -1)
1004  {
1005  error_exit("Cannot access '%s' (%s)\n", buf, strerror(errno));
1006  return;
1007  }
1008 
1009  if (strcmp(entry->d_name, DIRECTORY_TIMESTAMP) == 0)
1010  {
1011  convert_date_and_time(&d->date_and_time, &stbuf.st_ctime);
1012  }
1013  else
1014  {
1015  if (verbosity == VERBOSE)
1016  {
1017  printf("%d: file %s\n", d->level, buf);
1018  }
1019  (void) new_directory_record(entry, &stbuf, d);
1020  }
1021  }
1022  }
1023  closedir(dirp);
1024  }
1025  else
1026  {
1027  error_exit("Cannot open '%s'\n", source);
1028  return;
1029  }
1030 
1031  dirp = opendir(source);
1032  if (dirp != NULL)
1033  {
1034  while ((entry = readdir(dirp)) != NULL)
1035  {
1036  if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
1037  continue; // skip self and parent
1038 
1039  if (entry->d_type == DT_DIR) // directory
1040  {
1041  old_end_source = end_source;
1042  append_string_to_source(entry->d_name);
1044  *end_source = 0;
1045  if (verbosity == VERBOSE)
1046  {
1047  printf("%d: directory %s\n", d->level + 1, source);
1048  }
1049  if (d->level < MAX_LEVEL)
1050  {
1051  // Check for an absolute path
1052  if (source[0] == DIR_SEPARATOR_CHAR)
1053  {
1054  strcpy(buf, source);
1055  }
1056  else
1057  {
1058  if (!getcwd(buf, sizeof(buf)))
1059  error_exit("Cannot get CWD: %s\n", strerror(errno));
1061  strcat(buf, source);
1062  }
1063 
1064  if (stat(buf, &stbuf) == -1)
1065  {
1066  error_exit("Cannot access '%s' (%s)\n", buf, strerror(errno));
1067  return;
1068  }
1069  new_d = new_directory_record(entry, &stbuf, d);
1070  new_d->next_in_path_table = root.next_in_path_table;
1071  root.next_in_path_table = new_d;
1072  new_d->level = d->level + 1;
1073  make_directory_records(new_d);
1074  }
1075  else
1076  {
1077  error_exit("Directory is nested too deep");
1078  }
1079  end_source = old_end_source;
1080  *end_source = 0;
1081  }
1082  }
1083  closedir(dirp);
1084  }
1085  else
1086  {
1087  error_exit("Cannot open '%s'\n", source);
1088  return;
1089  }
1090 
1091 #else
1092 
1093  dirp = opendir(source);
1094  if (dirp != NULL)
1095  {
1096  while ((entry = readdir(dirp)) != NULL)
1097  {
1098  if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
1099  continue; // skip self and parent
1100 
1101  // Check for an absolute path
1102  if (source[0] == DIR_SEPARATOR_CHAR)
1103  {
1104  strcpy(buf, source);
1106  strcat(buf, entry->d_name);
1107  }
1108  else
1109  {
1110  if (!getcwd(buf, sizeof(buf)))
1111  error_exit("Cannot get CWD: %s\n", strerror(errno));
1113  strcat(buf, source);
1114  strcat(buf, entry->d_name);
1115  }
1116 
1117  if (stat(buf, &stbuf) == -1)
1118  {
1119  error_exit("Cannot access '%s' (%s)\n", buf, strerror(errno));
1120  return;
1121  }
1122 
1123  if (S_ISDIR(stbuf.st_mode))
1124  {
1125  old_end_source = end_source;
1126  append_string_to_source(entry->d_name);
1128  *end_source = 0;
1129  if (verbosity == VERBOSE)
1130  {
1131  printf("%d: directory %s\n", d->level + 1, source);
1132  }
1133 
1134  if (d->level < MAX_LEVEL)
1135  {
1136  new_d = new_directory_record(entry, &stbuf, d);
1137  new_d->next_in_path_table = root.next_in_path_table;
1138  root.next_in_path_table = new_d;
1139  new_d->level = d->level + 1;
1140  make_directory_records(new_d);
1141  }
1142  else
1143  {
1144  error_exit("Directory is nested too deep");
1145  }
1146 
1147  end_source = old_end_source;
1148  *end_source = 0;
1149  }
1150  else if (S_ISREG(stbuf.st_mode))
1151  {
1152  if (strcmp(entry->d_name, DIRECTORY_TIMESTAMP) == 0)
1153  {
1154  convert_date_and_time(&d->date_and_time, &stbuf.st_ctime);
1155  }
1156  else
1157  {
1158  if (verbosity == VERBOSE)
1159  {
1160  printf("%d: file %s\n", d->level, buf);
1161  }
1162  (void) new_directory_record(entry, &stbuf, d);
1163  }
1164  }
1165  }
1166  closedir(dirp);
1167  }
1168  else
1169  {
1170  error_exit("Cannot open '%s'\n", source);
1171  return;
1172  }
1173 
1174 #endif
1175 
1176  // sort directory
1177  d->first_record = sort_linked_list(d->first_record, 0, compare_directory_order);
1178 }
1179 
1180 #endif
1181 
1182 static PDIR_RECORD
1184 {
1185  PDIR_RECORD new_d;
1186  new_d = calloc(1, sizeof(*new_d));
1187  new_d->parent = d;
1188  new_d->level = d->level + 1;
1189  new_d->next_in_directory = d->first_record;
1190  d->first_record = new_d;
1191  new_d->next_in_memory = root.next_in_memory;
1192  root.next_in_memory = new_d;
1193  new_d->date_and_time = d->date_and_time;
1194  if (directory)
1195  {
1196  new_d->flags |= DIRECTORY_FLAG;
1197  new_d->next_in_path_table = root.next_in_path_table;
1198  root.next_in_path_table = new_d;
1199  }
1200  return new_d;
1201 }
1202 
1203 #ifdef _WIN32
1204 static BOOL
1205 get_cd_file_time(HANDLE handle, PDATE_AND_TIME cd_time_info)
1206 {
1207  FILETIME file_time;
1208  SYSTEMTIME sys_time;
1209 
1210  if (!GetFileTime(handle, NULL, NULL, &file_time))
1211  return FALSE;
1212 
1213  FileTimeToSystemTime(&file_time, &sys_time);
1214  memset(cd_time_info, 0, sizeof(*cd_time_info));
1215 
1216  cd_time_info->year = sys_time.wYear;
1217  cd_time_info->month = sys_time.wMonth;
1218  cd_time_info->day = sys_time.wDay;
1219  cd_time_info->hour = sys_time.wHour;
1220  cd_time_info->minute = sys_time.wMinute;
1221  cd_time_info->second = sys_time.wSecond;
1222 
1223  return TRUE;
1224 }
1225 #endif
1226 
1227 static void
1229 {
1230  PDIR_RECORD new_d;
1231 #ifdef _WIN32
1232  HANDLE open_file;
1234 #else
1235  struct stat stbuf;
1236 #endif
1237  struct target_file *file;
1238  struct target_dir_entry *child;
1239 
1240  d->first_record = NULL;
1241 
1242  for (file = dir->head; file; file = file->next)
1243  {
1244  if (strcmp(file->target_name, DIRECTORY_TIMESTAMP) == 0)
1245  {
1246 #ifdef _WIN32
1247  if ((open_file = CreateFileA(file->source_name,
1248  GENERIC_READ,
1250  NULL,
1251  OPEN_EXISTING,
1254  {
1255  error_exit("Cannot open timestamp file '%s'\n", file->source_name);
1256  }
1257 
1258  if (!get_cd_file_time(open_file, &d->date_and_time))
1259  {
1260  error_exit("Cannot stat timestamp file '%s'\n", file->source_name);
1261  }
1263 #else
1264  if (stat(file->target_name, &stbuf) == -1)
1265  {
1266  error_exit("Cannot stat timestamp file '%s'\n", file->source_name);
1267  }
1268  convert_date_and_time(&d->date_and_time, &stbuf.st_ctime);
1269 #endif
1270  }
1271  else
1272  {
1273  if (verbosity == VERBOSE)
1274  {
1275  printf("%d: file %s (from %s)\n",
1276  d->level,
1277  file->target_name,
1278  file->source_name);
1279  }
1280  new_d = new_empty_dirrecord(d, FALSE);
1281  parse_filename_into_dirrecord(file->target_name, new_d, FALSE);
1282 #ifdef _WIN32
1283  if ((open_file = CreateFileA(file->source_name,
1284  GENERIC_READ,
1286  NULL,
1287  OPEN_EXISTING,
1290  {
1291  error_exit("Cannot open file '%s'\n", file->source_name);
1292  }
1293  if (!get_cd_file_time(open_file, &new_d->date_and_time))
1294  {
1295  error_exit("Cannot stat file '%s'\n", file->source_name);
1296  }
1298  {
1299  error_exit("Cannot get file size of '%s'\n", file->source_name);
1300  }
1301  new_d->size = new_d->joliet_size = file_size.QuadPart;
1302  new_d->orig_name = file->source_name;
1304 #else
1305  if (stat(file->source_name, &stbuf) == -1)
1306  {
1307  error_exit("Cannot find '%s' (target '%s')\n",
1308  file->source_name,
1309  file->target_name);
1310  }
1311  convert_date_and_time(&new_d->date_and_time, &stbuf.st_mtime);
1312  new_d->size = new_d->joliet_size = stbuf.st_size;
1313  new_d->orig_name = file->source_name;
1314 #endif
1315  }
1316  }
1317 
1318  for (child = dir->child; child; child = child->next)
1319  {
1320  if (verbosity == VERBOSE)
1321  {
1322  printf("%d: directory %s\n", d->level, child->case_name);
1323  }
1324  new_d = new_empty_dirrecord(d, TRUE);
1325  parse_filename_into_dirrecord(child->case_name, new_d, TRUE);
1326  scan_specified_files(new_d, child);
1327  }
1328 
1329  /* sort directory */
1330  d->first_record = sort_linked_list(d->first_record,
1331  0,
1333  source[0] = 0;
1334  end_source = source;
1335 }
1336 
1337 /*-----------------------------------------------------------------------------
1338 This function loads the file specifications for the file or directory
1339 corresponding to the specified directory record into the source[] buffer. It
1340 is recursive.
1341 -----------------------------------------------------------------------------*/
1342 
1344 {
1345  if (d != &root)
1346  {
1347  get_file_specifications(d->parent);
1348  if (d->joliet_name == NULL)
1350  else
1351  append_string_to_source(d->joliet_name);
1352 
1353  if (((d->flags & DIRECTORY_FLAG) == 0 || joliet) && d->extension[0] != 0)
1354  {
1355  if (d->joliet_name == NULL)
1356  {
1357  *end_source++ = '.';
1358  append_string_to_source(d->extension);
1359  }
1360  }
1361  if (d->flags & DIRECTORY_FLAG)
1363  }
1364 }
1365 
1366 static void get_time_string(char *str)
1367 {
1368  sprintf(str, "%04d%02d%02d%02d%02d%02d00",
1369  root.date_and_time.year,
1370  root.date_and_time.month,
1371  root.date_and_time.day,
1372  root.date_and_time.hour,
1373  root.date_and_time.minute,
1374  root.date_and_time.second);
1375 }
1376 
1378 {
1379  if (cd.file != NULL)
1380  {
1381  int n;
1382 
1383  fseek(file, 0, SEEK_SET);
1384  while (size > 0)
1385  {
1386  n = BUFFER_SIZE - cd.count;
1387  if ((DWORD)n > size)
1388  n = size;
1389 
1390  if (fread(cd.buffer + cd.count, n, 1, file) < 1)
1391  return FALSE;
1392 
1393  cd.count += n;
1394  if (cd.count == BUFFER_SIZE)
1395  flush_buffer();
1396  cd.sector += n / SECTOR_SIZE;
1397  cd.offset += n % SECTOR_SIZE;
1398  size -= n;
1399  }
1400  }
1401  else
1402  {
1403  cd.sector += size / SECTOR_SIZE;
1404  cd.offset += size % SECTOR_SIZE;
1405  }
1406 
1407  return TRUE;
1408 }
1409 
1410 static void pass(void)
1411 {
1412  PDIR_RECORD d, q;
1413  unsigned int index;
1414  unsigned int name_length;
1415  DWORD size;
1416  DWORD number_of_sectors;
1417  char *old_end_source;
1418  FILE *file;
1419 
1422 
1423  char timestring[17];
1424 
1425  get_time_string(timestring);
1426 
1427  // first 16 sectors are zeros
1428  write_block(16 * SECTOR_SIZE, 0);
1429 
1430 
1431  // Primary Volume Descriptor
1432  if (make_bridged_udf)
1433  {
1434  write_string("\1CD001\1");
1435  write_byte(0);
1436  write_bytecounted_string(32, "", ' '); // system identifier
1437  write_bytecounted_string(32, volume_label, ' '); // volume label
1438 
1439  write_block(8, 0);
1441  write_block(32, 0);
1442  write_both_endian_word(1); // volume set size
1443  write_both_endian_word(1); // volume sequence number
1444  write_both_endian_word(2048); // sector size
1447  write_little_endian_dword(0); // second little endian path table
1449  write_big_endian_dword(0); // second big endian path table
1451 
1452  write_bytecounted_string(128, volume_label, ' '); // volume set identifier
1453  write_bytecounted_string(128, PUBLISHER_ID, ' '); // publisher identifier
1454  write_bytecounted_string(128, DATA_PREP_ID, ' '); // data preparer identifier
1455  write_bytecounted_string(128, APP_ID, ' '); // application identifier
1456 
1457  write_bytecounted_string(37, "", ' '); // copyright file identifier
1458  write_bytecounted_string(37, "", ' '); // abstract file identifier
1459  write_bytecounted_string(37, "", ' '); // bibliographic file identifier
1460 
1461  write_string(timestring); // volume creation
1462  write_byte(0);
1463  write_string(timestring); // most recent modification
1464  write_byte(0);
1465  write_string("0000000000000000"); // volume expires
1466  write_byte(0);
1467  write_string("0000000000000000"); // volume is effective
1468  write_byte(0);
1469  write_byte(1);
1470  write_byte(0);
1471  fill_sector();
1472  }
1473 
1474  // Boot Volume Descriptor
1475  if (eltorito)
1476  {
1477  write_byte(0); // Boot record ID
1478  write_string("CD001\1");
1479  write_bytecounted_string(32, "EL TORITO SPECIFICATION", 0); // El-Torito identifier
1480  write_block(32, 0); // unused
1481  write_little_endian_dword(boot_catalog_sector); // pointer to boot catalog
1482  fill_sector();
1483  }
1484 
1485  // Supplementary Volume Descriptor
1486  if (joliet)
1487  {
1488  write_string("\2CD001\1");
1489  write_byte(0);
1490  write_bytecounted_string_as_big_endian_unicode(32, "", ' '); // system identifier
1492 
1493  write_block(8, 0);
1495  write_string("%/E");
1496  write_block(29, 0);
1497  write_both_endian_word(1); // volume set size
1498  write_both_endian_word(1); // volume sequence number
1499  write_both_endian_word(2048); // sector size
1502  write_little_endian_dword(0); // second little endian path table
1504  write_big_endian_dword(0); // second big endian path table
1506 
1507  write_bytecounted_string_as_big_endian_unicode(128, volume_label, ' '); // volume set identifier
1508  write_bytecounted_string_as_big_endian_unicode(128, PUBLISHER_ID, ' '); // publisher identifier
1509  write_bytecounted_string_as_big_endian_unicode(128, DATA_PREP_ID, ' '); // data preparer identifier
1510  write_bytecounted_string_as_big_endian_unicode(128, APP_ID, ' '); // application identifier
1511 
1512  write_bytecounted_string_as_big_endian_unicode(37, "", ' '); // copyright file identifier
1513  write_bytecounted_string_as_big_endian_unicode(37, "", ' '); // abstract file identifier
1514  write_bytecounted_string_as_big_endian_unicode(37, "", ' '); // bibliographic file identifier
1515 
1516  write_string(timestring); // volume creation
1517  write_byte(0);
1518  write_string(timestring); // most recent modification
1519  write_byte(0);
1520  write_string("0000000000000000"); // volume expires
1521  write_byte(0);
1522  write_string("0000000000000000"); // volume is effective
1523  write_byte(0);
1524  write_byte(1);
1525  write_byte(0);
1526  fill_sector();
1527  }
1528 
1529  // Volume Descriptor Set Terminator
1530  if (make_bridged_udf)
1531  {
1532  write_string("\377CD001\1");
1533  fill_sector();
1534  }
1535 
1536  // TODO: Add UDF support!
1537 
1538  // Boot Catalog
1539  if (eltorito)
1540  {
1541  boot_catalog_sector = cd.sector;
1542 
1543  // Validation entry header
1546  write_little_endian_word(0); // reserved
1547  write_bytecounted_string(24, MANUFACTURER_ID, 0); // Manufacturer identifier
1548  write_little_endian_word(0x62E); // checksum // FIXME: This is hardcoded!!
1549  write_little_endian_word(0xAA55); // signature
1550 
1551  // Default entry
1555  write_byte(0); // partition type
1556  write_byte(0); // unused
1559  write_block(20, 0); // unused
1560 
1561  // Loop through each boot header
1563  while (header)
1564  {
1565  write_byte(header->header_id);
1566  write_byte(header->platform_id);
1567  write_little_endian_word(header->num_entries);
1568  write_block(28, 0); // Identifier string (unused)
1569 
1570  // Loop through each boot entry
1571  entry = header->entry_list;
1572  while (entry)
1573  {
1574  write_byte(entry->boot_id);
1575  write_byte(entry->boot_emu_type);
1576  write_little_endian_word(entry->load_segment);
1577  write_byte(0); // partition type
1578  write_byte(0); // unused
1579  write_little_endian_word(entry->sector_count);
1580  write_little_endian_dword(entry->load_rba);
1581  write_block(20, 0); // Selection criteria (unused)
1582 
1583  entry = entry->next_entry;
1584  }
1585 
1586  header = header->next_header;
1587  }
1588 
1589  fill_sector();
1590  }
1591 
1592 
1593  // Boot Images
1594  if (eltorito)
1595  {
1596  default_boot_entry.load_rba = cd.sector;
1597 
1599  if (file == NULL)
1600  error_exit("Cannot open '%s'\n", default_boot_entry.bootimage);
1601  fseek(file, 0, SEEK_END);
1602  size = ftell(file);
1603  if (size == 0 || (size % 2048))
1604  {
1605  fclose(file);
1606  error_exit("Invalid boot image size (%lu bytes)\n", size);
1607  }
1608  // Sector count in 512 byte sectors and rounded up
1609  default_boot_entry.sector_count = (size + 511) / 512;
1610  if (!write_from_file(file, size))
1611  {
1612  fclose(file);
1613  error_exit("Read error in file '%s'\n", default_boot_entry.bootimage);
1614  }
1615  fclose(file);
1616 
1617  // Loop through each boot header
1619  while (header)
1620  {
1621  // Loop through each boot entry
1622  entry = header->entry_list;
1623  while (entry)
1624  {
1625  entry->load_rba = cd.sector;
1626 
1627  file = fopen(entry->bootimage, "rb");
1628  if (file == NULL)
1629  error_exit("Cannot open '%s'\n", entry->bootimage);
1630  fseek(file, 0, SEEK_END);
1631  size = ftell(file);
1632  if (size == 0 || (size % 2048))
1633  {
1634  fclose(file);
1635  error_exit("Invalid boot image size (%lu bytes)\n", size);
1636  }
1637  // Sector count in 512 byte sectors and rounded up
1638  entry->sector_count = (size + 511) / 512;
1639  if (!write_from_file(file, size))
1640  {
1641  fclose(file);
1642  error_exit("Read error in file '%s'\n", entry->bootimage);
1643  }
1644  fclose(file);
1645 
1646  entry = entry->next_entry;
1647  }
1648 
1649  header = header->next_header;
1650  }
1651 
1652 // fill_sector();
1653  }
1654 
1655 
1656  // Little Endian Path Table
1657 
1659  write_byte(1);
1660  write_byte(0); // number of sectors in extended attribute record
1663  write_byte(0);
1664  write_byte(0);
1665 
1666  index = 1;
1667  root.path_table_index = 1;
1668  for (d = root.next_in_path_table; d != NULL; d = d->next_in_path_table)
1669  {
1670  name_length = strlen(d->name_on_cd);
1671  write_byte((BYTE)name_length);
1672  write_byte(0); // number of sectors in extended attribute record
1673  write_little_endian_dword(d->sector);
1674  write_little_endian_word(d->parent->path_table_index);
1675  write_string(d->name_on_cd);
1676  if (name_length & 1)
1677  write_byte(0);
1678  d->path_table_index = ++index;
1679  }
1680 
1682  SECTOR_SIZE + cd.offset;
1683  fill_sector();
1684 
1685 
1686  // Big Endian Path Table
1687 
1689  write_byte(1);
1690  write_byte(0); // number of sectors in extended attribute record
1691  write_big_endian_dword(root.sector);
1693  write_byte(0);
1694  write_byte(0);
1695 
1696  for (d = root.next_in_path_table; d != NULL; d = d->next_in_path_table)
1697  {
1698  name_length = strlen(d->name_on_cd);
1699  write_byte((BYTE)name_length);
1700  write_byte(0); // number of sectors in extended attribute record
1701  write_big_endian_dword(d->sector);
1702  write_big_endian_word(d->parent->path_table_index);
1703  write_string(d->name_on_cd);
1704  if (name_length & 1)
1705  write_byte(0);
1706  }
1707  fill_sector();
1708 
1709  if (joliet)
1710  {
1711  // Little Endian Path Table
1712 
1714  write_byte(1);
1715  write_byte(0); // number of sectors in extended attribute record
1716  write_little_endian_dword(root.joliet_sector);
1718  write_byte(0);
1719  write_byte(0);
1720 
1721  for (d = root.next_in_path_table; d != NULL; d = d->next_in_path_table)
1722  {
1723  name_length = strlen(d->joliet_name) * 2;
1724  write_byte((BYTE)name_length);
1725  write_byte(0); // number of sectors in extended attribute record
1726  write_little_endian_dword(d->joliet_sector);
1727  write_little_endian_word(d->parent->path_table_index);
1728  write_string_as_big_endian_unicode(d->joliet_name);
1729  }
1730 
1732  SECTOR_SIZE + cd.offset;
1733  fill_sector();
1734 
1735  // Big Endian Path Table
1736 
1738  write_byte(1);
1739  write_byte(0); // number of sectors in extended attribute record
1740  write_big_endian_dword(root.joliet_sector);
1742  write_byte(0);
1743  write_byte(0);
1744 
1745  for (d = root.next_in_path_table; d != NULL; d = d->next_in_path_table)
1746  {
1747  name_length = strlen(d->joliet_name) * 2;
1748  write_byte((BYTE)name_length);
1749  write_byte(0); // number of sectors in extended attribute record
1750  write_big_endian_dword(d->joliet_sector);
1751  write_big_endian_word(d->parent->path_table_index);
1752  write_string_as_big_endian_unicode(d->joliet_name);
1753  }
1754  fill_sector();
1755  }
1756 
1757  // TODO: Add UDF support!
1758 
1759 #if 0
1760  // Boot Images ??
1761 #endif
1762 
1763  // TODO: Add CRC block for header!
1764 
1765  // Directories and files
1766  for (d = &root; d != NULL; d = d->next_in_path_table)
1767  {
1768  // write directory
1769  d->sector = cd.sector;
1771  write_directory_record(d == &root ? d : d->parent, DOT_DOT_RECORD, FALSE);
1772  for (q = d->first_record; q != NULL; q = q->next_in_directory)
1773  {
1776  FALSE);
1777  }
1778  fill_sector();
1779  d->size = (cd.sector - d->sector) * SECTOR_SIZE;
1780 
1781  // write directory for joliet
1782  if (joliet)
1783  {
1784  d->joliet_sector = cd.sector;
1786  write_directory_record(d == &root ? d : d->parent, DOT_DOT_RECORD, TRUE);
1787  for (q = d->first_record; q != NULL; q = q->next_in_directory)
1788  {
1791  TRUE);
1792  }
1793  fill_sector();
1794  d->joliet_size = (cd.sector - d->joliet_sector) * SECTOR_SIZE;
1795  bytes_in_directories += d->joliet_size;
1796  }
1797 
1799  bytes_in_directories += d->size;
1800 
1801  // write file data
1802  for (q = d->first_record; q != NULL; q = q->next_in_directory)
1803  {
1804  if ((q->flags & DIRECTORY_FLAG) == 0)
1805  {
1806  q->sector = q->joliet_sector = cd.sector;
1807  size = q->size;
1808  if (cd.file == NULL)
1809  {
1810  number_of_sectors = (size + SECTOR_SIZE - 1) / SECTOR_SIZE;
1811  cd.sector += number_of_sectors;
1812  number_of_files++;
1813  bytes_in_files += size;
1815  number_of_sectors * SECTOR_SIZE - size;
1816  }
1817  else
1818  {
1819  const char *file_source;
1820  old_end_source = end_source;
1821  if (!q->orig_name)
1822  {
1824  *end_source = 0;
1825  file_source = source;
1826  }
1827  else
1828  {
1829  file_source = q->orig_name;
1830  }
1831  if (verbosity == VERBOSE)
1832  printf("Writing contents of %s\n", file_source);
1833  file = fopen(file_source, "rb");
1834  if (file == NULL)
1835  error_exit("Cannot open '%s'\n", file_source);
1836  if (!write_from_file(file, size))
1837  {
1838  fclose(file);
1839  error_exit("Read error in file '%s'\n", file_source);
1840  }
1841  fclose(file);
1842  end_source = old_end_source;
1843  fill_sector();
1844  }
1845  }
1846  }
1847  }
1848 
1849  // TODO: Add final CRC block!
1850 
1851  total_sectors = (DWORD)cd.sector;
1852 }
1853 
1854 static char HELP[] =
1855  "\n"
1856  "CDMAKE CD-ROM Premastering Utility\n"
1857  "Copyright (C) 1997 Philip J. Erdelsky\n"
1858  "Copyright (C) 2003-2016 ReactOS Team\n"
1859  "\n\n"
1860  "CDMAKE [-vN] [-p] [-s N] [-m] [-j] [-q] "
1861  // "[-x] "
1862  "[-pN] [-eN] [-b bootimage]\n"
1863  " [-bootdata:N#<defaultBootEntry>#<bootEntry1>#...#<bootEntryN>]\n"
1864  " source volume image\n"
1865  "\n"
1866  "Mandatory options:\n"
1867  " source Specifications of base directory containing all files to be\n"
1868  " written to CD-ROM image. Can be a directory, or a path to a\n"
1869  " file list (in which case the path must start with a '@').\n"
1870  " volume Volume label.\n"
1871  " image Image file or device.\n"
1872  "\n"
1873  "General options:\n"
1874  " -vN Verbosity level. Valid values for 'N' are:\n"
1875  " 0: Quiet mode - display nothing but error messages.\n"
1876  " 1: Normal mode (default).\n"
1877  " 2: Verbose mode - display file information as files are\n"
1878  " scanned and written. Overrides the -p option.\n"
1879  " -p Show progress while writing.\n"
1880  " -s N Abort operation before beginning write if image will be larger\n"
1881  " than N megabytes (i.e. 1024*1024*N bytes).\n"
1882  " -q Only scan the source files; do not create an image.\n"
1883  // " -x Compute and encode the AutoCRC value in the image.\n"
1884  "\n"
1885  "ISO 9660 and Joliet options:\n"
1886  " -m Accept punctuation marks other than underscores in names and\n"
1887  " extensions.\n"
1888  " -j Generate Joliet filename records.\n"
1889  "\n"
1890  // "UDF options:\n"
1891  // " Not implemented yet!\n"
1892  // "\n"
1893  "El-Torito boot options:\n"
1894  " -pN Boot platform ID in hex format (default: 00 for a BIOS system).\n"
1895  " -eN Boot media emulation. Valid values for 'N' are:\n"
1896  " 0 (or nothing): No emulation.\n"
1897  " 1: 1.2 MB diskette.\n"
1898  " 2: 1.44MB diskette.\n"
1899  " 3: 2.88MB diskette.\n"
1900  " 4: Hard disk.\n"
1901  " -b bootimage Create a single-boot El-Torito image.\n"
1902  " -bootdata: Create a multi-boot El-Torito image. This option cannot be\n"
1903  " combined with the -b option.\n"
1904  " Syntax:\n"
1905  " -bootdata:N#<defaultBootEntry>#<bootEntry2>#...#<bootEntryN>\n"
1906  " 'N': number of boot entries following.\n"
1907  " defaultBootEntry: The default boot entry, needed in all cases.\n"
1908  " Used by BIOSes which do not support additional boot entries.\n"
1909  " bootEntryX: Additional boot entries.\n"
1910  " - Do not use spaces.\n"
1911  " - Each multi-boot entry must be delimited with a hash symbol (#).\n"
1912  " - Each option for a boot entry must be delimited with a comma (,).\n"
1913  " - Each boot entry must specify the platform ID.\n";
1914 
1915 /*-----------------------------------------------------------------------------
1916 Program execution starts here.
1917 -----------------------------------------------------------------------------*/
1918 
1919 #if (defined(__GNUC__) || (_MSC_VER < 1900))
1920 char* strtok_s(char *str, const char *delim, char **ctx)
1921 {
1922  if (delim == NULL || ctx == NULL || (str == NULL && *ctx == NULL))
1923  {
1924  return NULL;
1925  }
1926 
1927  if (!str)
1928  str = *ctx;
1929 
1930  while (*str && strchr(delim, *str))
1931  str++;
1932  if (!*str)
1933  {
1934  *ctx = str;
1935  return NULL;
1936  }
1937 
1938  *ctx = str + 1;
1939  while (**ctx && !strchr(delim, **ctx))
1940  (*ctx)++;
1941  if (**ctx)
1942  *(*ctx)++ = '\0';
1943 
1944  return str;
1945 }
1946 #endif
1947 
1948 static void
1950  BYTE boot_emu_type, WORD load_segment,
1951  char* bootimage)
1952 {
1953  boot_entry->boot_id = 0x88; // Bootable entry
1954  boot_entry->boot_emu_type = boot_emu_type; // 0: No emulation, etc...
1955  boot_entry->load_segment = load_segment; // If 0 then use default 0x07C0
1956 
1957  boot_entry->bootimage[0] = '\0';
1958  strncpy(boot_entry->bootimage, bootimage, sizeof(boot_entry->bootimage));
1959  boot_entry->bootimage[sizeof(boot_entry->bootimage)-1] = '\0';
1960 }
1961 
1962 int main(int argc, char **argv)
1963 {
1965  int i;
1966  char *t;
1967 
1968  if (argc < 2)
1969  {
1970  puts(HELP);
1971  return 1;
1972  }
1973 
1974  // Initialize CD-ROM write buffer
1975 
1976  cd.file = NULL;
1977  cd.filespecs[0] = 0;
1978 
1979  cd.buffer = malloc(BUFFER_SIZE);
1980  if (cd.buffer == NULL)
1981  error_exit("Insufficient memory");
1982 
1983  // Initialize root directory
1984 
1985  memset(&root, 0, sizeof(root));
1986  root.level = 1;
1987  root.flags = DIRECTORY_FLAG;
1988  convert_date_and_time(&root.date_and_time, &timestamp);
1989 
1990  // Initialize parameters
1991 
1994  // compute_crc = FALSE;
1995 
1996  verbosity = NORMAL;
1997  show_progress = FALSE;
1998  size_limit = 0;
2000  source[0] = 0;
2001  volume_label[0] = 0;
2002 
2003  // Initialize boot information
2004  eltorito = FALSE;
2005  multi_boot = FALSE;
2006  boot_validation_header.header_id = 1; // Validation header ID
2007  boot_validation_header.platform_id = 0; // x86/64 BIOS system
2009  0, // No emulation
2010  0, // Use default 0x07C0
2011  "");
2015 
2016  // Scan command line arguments
2017 
2018  for (i = 1; i < argc; i++)
2019  {
2020  if (strncmp(argv[i], "-v", 2) == 0)
2021  {
2022  t = argv[i] + 2;
2023  if (*t == 0) // Normal verbosity level.
2024  verbosity = NORMAL;
2025  else // Verbosity level in decimal
2026  verbosity = strtoul(t, NULL, 10);
2027 
2028  // Check for validity
2029  if (verbosity > VERBOSE)
2030  verbosity = NORMAL;
2031 
2032  // Disable by default, unless we are in normal verbosity level.
2033  // If progress is still wanted, use '-p'.
2034  if (verbosity == QUIET || verbosity == VERBOSE)
2035  show_progress = FALSE;
2036  }
2037  else if (strcmp(argv[i], "-p") == 0)
2038  show_progress = TRUE;
2039  else if (strncmp(argv[i], "-s", 2) == 0)
2040  {
2041  t = argv[i] + 2;
2042  if (*t == 0)
2043  {
2044  if (++i < argc)
2045  t = argv[i];
2046  else
2047  error_exit("Missing size limit parameter");
2048  }
2049  // size_limit = strtoul(t, NULL, 10);
2050  while (isdigit(*t))
2051  size_limit = size_limit * 10 + *t++ - '0';
2052  if (size_limit < 1 || size_limit > 800)
2053  error_exit("Invalid size limit");
2054  size_limit <<= 9; // convert megabyte to sector count
2055  }
2056  else if (strcmp(argv[i], "-m") == 0)
2058  else if (strcmp(argv[i], "-j") == 0)
2059  joliet = TRUE;
2060  else if (strncmp(argv[i], "-e", 2) == 0)
2061  {
2062  // Check whether the multi-boot option '-bootdata:' was already set.
2063  // If so, print an error and bail out.
2064  if (eltorito && multi_boot)
2065  error_exit("Single-boot and multi-boot entries cannot be combined");
2066 
2067  eltorito = TRUE;
2068  multi_boot = FALSE;
2069 
2070  t = argv[i] + 2;
2071  if (*t == 0) // No emulation
2073  else // ID in decimal
2075  }
2076  else if (strncmp(argv[i], "-p", 2) == 0)
2077  {
2078  // Check whether the multi-boot option '-bootdata:' was already set.
2079  // If so, print an error and bail out.
2080  if (eltorito && multi_boot)
2081  error_exit("Single-boot and multi-boot entries cannot be combined");
2082 
2083  eltorito = TRUE;
2084  multi_boot = FALSE;
2085 
2086  // Platform ID in hexadecimal
2088  }
2089  else if (strcmp(argv[i], "-b") == 0)
2090  {
2091  // Check whether the multi-boot option '-bootdata:' was already set.
2092  // If so, print an error and bail out.
2093  if (eltorito && multi_boot)
2094  error_exit("Single-boot and multi-boot entries cannot be combined");
2095 
2096  eltorito = TRUE;
2097  multi_boot = FALSE;
2098 
2101  }
2102  else if (strncmp(argv[i], "-bootdata:", sizeof("-bootdata:") - 1) == 0)
2103  {
2104  char *bootdata, *entry_ctx, *option_ctx;
2105  DWORD num_boot_entries = 0;
2106 
2107  BOOL default_entry = TRUE; // Start by setting the default boot entry
2108  PBOOT_HEADER boot_header = NULL; // Current boot header
2109  PBOOT_ENTRY boot_entry = NULL; // The last boot entry in the current boot header
2110  BYTE platform_id, old_platform_id = 0;
2111  BYTE boot_emu_type;
2112  WORD load_segment;
2113  char bootimage[512];
2114 
2115  // Check whether the single-boot option '-b' was already set.
2116  // If so, print an error and bail out.
2117  if (eltorito && !multi_boot)
2118  error_exit("Single-boot and multi-boot entries cannot be combined");
2119 
2120  t = argv[i] + (sizeof("-bootdata:") - 1);
2121  bootdata = strdup(t);
2122  if (bootdata == NULL)
2123  error_exit("Insufficient memory");
2124 
2125  eltorito = TRUE;
2126  multi_boot = TRUE;
2127 
2128  // FIXME: Paths containing '#' or ',' or ' ' are not yet supported!!
2129 
2130  // Start parsing...
2131  t = strtok_s(bootdata, "#", &entry_ctx);
2132  if (t == NULL)
2133  {
2134  free(bootdata);
2135  error_exit("Malformed bootdata command");
2136  }
2137 
2138  num_boot_entries = strtoul(t, NULL, 10);
2139 
2140  while (num_boot_entries--)
2141  {
2142  // Reset to default values
2143  platform_id = 0; // x86/64 BIOS system
2144  boot_emu_type = 0; // No emulation
2145  load_segment = 0; // Use default 0x07C0
2146  bootimage[0] = '\0';
2147 
2148  t = strtok_s(NULL, "#", &entry_ctx);
2149  if (t == NULL)
2150  {
2151  free(bootdata);
2152  error_exit("Malformed bootdata command");
2153  }
2154 
2155  t = strtok_s(t, ",", &option_ctx);
2156  while (t != NULL)
2157  {
2158  switch (*t++)
2159  {
2160  case 'b': // Boot sector file
2161  {
2162  char *q;
2163 
2164  // Searches for any of the valid separators:
2165  // '#' starts a new boot entry;
2166  // ',' starts a new boot option;
2167  // ' ' finishes the bootdata command.
2168  q = strpbrk(t, "#, ");
2169  if (!q) q = t + strlen(t);
2170  strncpy(bootimage, t, q - t + 1);
2171  break;
2172  }
2173 
2174  case 'p': // Platform ID
2175  {
2176  // Platform ID in hexadecimal
2177  platform_id = (BYTE)strtoul(t, NULL, 16);
2178  break;
2179  }
2180 
2181  case 'e': // No floppy-disk emulation
2182  {
2183  if (*t == 0) // No emulation
2184  boot_emu_type = 0;
2185  else // ID in decimal
2186  boot_emu_type = (BYTE)strtoul(t, NULL, 10);
2187 
2188  break;
2189  }
2190 
2191  case 't': // Loading segment
2192  {
2193  if (*t == 0) // Not specified: use default 0x07C0
2194  load_segment = 0;
2195  else // Segment in hexadecimal
2196  load_segment = (BYTE)strtoul(t, NULL, 16);
2197 
2198  break;
2199  }
2200 
2201  default:
2202  free(bootdata);
2203  error_exit("Malformed bootdata command");
2204  }
2205 
2206  t = strtok_s(NULL, ",", &option_ctx);
2207  }
2208 
2209  // Create a new entry and possibly a boot header
2210  if (default_entry)
2211  {
2212  // Initialize the default boot entry and header
2213 
2214  boot_validation_header.header_id = 1; // Validation header ID
2215  boot_validation_header.platform_id = platform_id;
2216 
2217  init_boot_entry(&default_boot_entry, boot_emu_type, load_segment, bootimage);
2218 
2219  // Default entry is now initialized.
2220  default_entry = FALSE;
2221  }
2222  else
2223  {
2224  // Initialize a new boot entry
2225  PBOOT_ENTRY old_boot_entry = boot_entry;
2226 
2227  boot_entry = calloc(1, sizeof(*boot_entry));
2228  if (boot_entry == NULL)
2229  error_exit("Insufficient memory");
2230  // boot_entry->next_entry = NULL;
2231 
2232  init_boot_entry(boot_entry, boot_emu_type, load_segment, bootimage);
2233 
2234  // Create a new boot header if we don't have one yet
2235  if (boot_header == NULL)
2236  {
2237  boot_header = calloc(1, sizeof(*boot_header));
2238  if (boot_header == NULL)
2239  error_exit("Insufficient memory");
2240 
2241  boot_header->header_id = 0x91; // So far this is the last boot header
2242  boot_header->platform_id = platform_id;
2243  // boot_header->next_header = NULL;
2244  // boot_header->num_entries = 0;
2245  // boot_header->entry_list = NULL;
2246 
2247  old_boot_entry = NULL;
2248  old_platform_id = platform_id;
2249 
2251  }
2252  else
2253  {
2254  // Create a new boot header if we change the platform ID
2255  if (old_platform_id != platform_id)
2256  {
2257  PBOOT_HEADER prev_boot_header = boot_header;
2258 
2259  boot_header = calloc(1, sizeof(*boot_header));
2260  if (boot_header == NULL)
2261  error_exit("Insufficient memory");
2262 
2263  boot_header->header_id = 0x91; // So far this is the last boot header
2264  boot_header->platform_id = platform_id;
2265  // boot_header->next_header = NULL;
2266  // boot_header->num_entries = 0;
2267  // boot_header->entry_list = NULL;
2268 
2269  old_boot_entry = NULL;
2270  old_platform_id = platform_id;
2271 
2272  // Link into the header list
2273  prev_boot_header->header_id = 0x90; // The previous boot header was not the last one
2274  prev_boot_header->next_header = boot_header;
2275  }
2276  }
2277 
2278  // Add the entry into the header
2280  if (old_boot_entry == NULL)
2282  else
2283  old_boot_entry->next_entry = boot_entry;
2284  }
2285  }
2286 
2287  free(bootdata);
2288  }
2289  else if (strcmp(argv[i], "-q") == 0)
2291  // else if (strcmp(argv[i], "-x") == 0)
2292  // compute_crc = TRUE;
2293  else if (i + 2 < argc)
2294  {
2295  strcpy(source, argv[i++]);
2296  strncpy(volume_label, argv[i++], sizeof(volume_label) - 1);
2297  strcpy(cd.filespecs, argv[i]);
2298  }
2299  else
2300  error_exit("Missing command line argument");
2301  }
2302 
2303  if (source[0] == 0)
2304  error_exit("Missing source directory");
2305  if (volume_label[0] == 0)
2306  error_exit("Missing volume label");
2307  if (cd.filespecs[0] == 0)
2308  error_exit("Missing image file specifications");
2309 
2310  if (source[0] != '@')
2311  {
2312  /* set source[] and end_source to source directory,
2313  * with a terminating directory separator */
2315  if (end_source[-1] == ':')
2316  *end_source++ = '.';
2317  if (end_source[-1] != DIR_SEPARATOR_CHAR)
2319 
2320  /* scan all files and create directory structure in memory */
2322  }
2323  else
2324  {
2325  char *trimmedline, *targetname, *normdir, *srcname, *eq;
2326  char lineread[1024];
2327 
2328  FILE *f = fopen(source+1, "r");
2329  if (!f)
2330  {
2331  error_exit("Cannot open CD-ROM file description '%s'\n", source+1);
2332  }
2333  while (fgets(lineread, sizeof(lineread), f))
2334  {
2335  /* We treat these characters as line endings */
2336  trimmedline = strtok(lineread, "\t\r\n;");
2337  eq = strchr(trimmedline, '=');
2338  if (!eq)
2339  {
2340  /* Treat this as a directory name */
2341  targetname = trimmedline;
2342  normdir = strdup(targetname);
2343  normalize_dirname(normdir);
2344  dir_hash_create_dir(&specified_files, targetname, normdir);
2345  free(normdir);
2346  }
2347  else
2348  {
2349  targetname = strtok(lineread, "=");
2350  srcname = strtok(NULL, "");
2351 
2352 #ifdef _WIN32
2353  if (_access(srcname, R_OK) == 0)
2354 #else
2355  if (access(srcname, R_OK) == 0)
2356 #endif
2357  {
2358  if (!dir_hash_add_file(&specified_files, srcname, targetname))
2359  error_exit("Target '%s' (file '%s') is invalid\n", targetname, srcname);
2360  }
2361  else
2362  error_exit("Cannot access file '%s' (target '%s')\n", srcname, targetname);
2363  }
2364  }
2365  fclose(f);
2366 
2367  /* scan all files and create directory structure in memory */
2369  }
2370 
2371  /* sort path table entries */
2372  root.next_in_path_table = sort_linked_list(root.next_in_path_table,
2373  1,
2375 
2376  // initialize CD-ROM write buffer
2377 
2378  cd.file = NULL;
2379  cd.sector = 0;
2380  cd.offset = 0;
2381  cd.count = 0;
2382 
2383  // make non-writing pass over directory structure to obtain the proper
2384  // sector numbers and offsets and to determine the size of the image
2385 
2388  pass();
2389 
2390  if (verbosity >= NORMAL)
2391  {
2392  printf("%s bytes ", edit_with_commas(bytes_in_files, TRUE));
2393  printf("in %s files\n", edit_with_commas(number_of_files, FALSE));
2394  printf("%s unused bytes at ends of files\n",
2397  printf("in %s directories\n",
2399  printf("%s other bytes\n", edit_with_commas(root.sector * SECTOR_SIZE, TRUE));
2400  puts("-------------");
2401  printf("%s total bytes\n",
2403  puts("=============");
2404  }
2405 
2406  if (size_limit != 0 && total_sectors > size_limit)
2407  error_exit("Size limit exceeded");
2408 
2409  if (!scan_files_only)
2410  {
2411  // re-initialize CD-ROM write buffer
2412 
2413  cd.file = fopen(cd.filespecs, "w+b");
2414  if (cd.file == NULL)
2415  error_exit("Cannot open image file '%s'", cd.filespecs);
2416  cd.sector = 0;
2417  cd.offset = 0;
2418  cd.count = 0;
2419 
2420 
2421  // make writing pass over directory structure
2422 
2423  pass();
2424 
2425  if (cd.count > 0)
2426  flush_buffer();
2427  if (show_progress)
2428  printf("\r \n");
2429  if (fclose(cd.file) != 0)
2430  {
2431  cd.file = NULL;
2432  error_exit("File write error in image file '%s'", cd.filespecs);
2433  }
2434 
2435  if (verbosity >= NORMAL)
2436  puts("CD-ROM image made successfully");
2437  }
2438 
2440  release_memory();
2441  return 0;
2442 }
2443 
2444 /* EOF */
BYTE hour
Definition: cdmake.c:138
unsigned short WORD
Definition: cdmake.c:77
char * name
Definition: wpp.c:36
#define MAX_LEVEL
Definition: cdmake.c:83
DWORD little_endian_path_table_sector
Definition: cdmake.c:203
static void convert_date_and_time(PDATE_AND_TIME dt, time_t *time)
Definition: cdmake.c:618
static int argc
Definition: ServiceArgs.c:12
struct _boot_validation_header BOOT_VALIDATION_HEADER
DWORD number_of_directories
Definition: cdmake.c:213
unsigned level
Definition: cdmake.c:163
DWORD joliet_sector
Definition: cdmake.c:161
UINT32 strtoul(const char *String, char **Terminator, UINT32 Base)
Definition: utclib.c:696
int tm_min
Definition: time.h:78
#define CloseHandle
Definition: compat.h:398
#define DATA_PREP_ID
Definition: config.h:14
DATE_AND_TIME date_and_time
Definition: cdmake.c:158
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:49
struct boot_header BOOT_HEADER
#define FALSE
Definition: cdmake.c:68
BYTE header_id
Definition: cdmake.c:127
struct directory_record * first_record
Definition: cdmake.c:149
static void write_byte(BYTE x)
Definition: cdmake.c:352
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
#define strcasecmp
Definition: fake.h:9
time_t st_ctime
Definition: stat.h:66
static void write_string(char *s)
Definition: cdmake.c:429
#define BUFFER_SIZE
Definition: cdmake.c:89
WORD wMonth
Definition: winbase.h:871
static void write_both_endian_dword(DWORD x)
Definition: cdmake.c:406
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
char * strpbrk(const char *String, const char *Delimiters)
Definition: utclib.c:302
struct _boot_validation_header * PBOOT_VALIDATION_HEADER
DWORD path_table_size
Definition: cdmake.c:202
enum directory_record_type DIR_RECORD_TYPE
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
BOOL make_bridged_udf
Definition: cdmake.c:240
DWORD joliet_size
Definition: cdmake.c:162
enum directory_record_type * PDIR_RECORD_TYPE
static void get_file_specifications(PDIR_RECORD d)
Definition: cdmake.c:1343
static struct cd_image cd
Definition: cdmake.c:182
GLuint GLuint GLsizei count
Definition: gl.h:1545
char * strncpy(char *DstString, const char *SrcString, ACPI_SIZE Count)
Definition: utclib.c:427
#define SECTOR_SIZE
Definition: cdmake.c:88
#define free
Definition: debug_ros.c:5
WORD load_segment
Definition: cdmake.c:116
#define MAX_CDEXTENSION_LENGTH
Definition: cdmake.c:87
int tm_mday
Definition: time.h:80
char extension_on_cd[MAX_CDEXTENSION_LENGTH+1]
Definition: cdmake.c:155
DWORD unused_bytes_at_ends_of_files
Definition: cdmake.c:212
GLdouble n
Definition: glext.h:7729
GLdouble GLdouble t
Definition: gl.h:2047
PBOOT_ENTRY entry_list
Definition: cdmake.c:131
int count
Definition: cdmake.c:100
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
static char HELP[]
Definition: cdmake.c:1854
struct boot_entry * next_entry
Definition: cdmake.c:113
static void error_exit(const char *fmt,...)
Definition: cdmake.c:315
static BOOL cdname_exists(PDIR_RECORD d)
Definition: cdmake.c:654
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
DWORD total_sectors
Definition: cdmake.c:201
BYTE month
Definition: cdmake.c:140
char name_on_cd[MAX_CDNAME_LENGTH+1]
Definition: cdmake.c:153
void * arg
Definition: msvc.h:12
void dir_hash_destroy(struct target_dir_hash *dh)
Definition: dirhash.c:235
#define MANUFACTURER_ID
Definition: config.h:12
int tm_year
Definition: time.h:82
int errno
BYTE system_type
Definition: cdmake.c:117
__u16 time
Definition: mkdosfs.c:366
WORD sector_count
Definition: cdmake.c:118
int BOOL
Definition: cdmake.c:79
static char DIRECTORY_TIMESTAMP[]
Definition: cdmake.c:180
_Check_return_ _CRTIMP int __cdecl isalnum(_In_ int _C)
_Check_return_opt_ _CRTIMP size_t __cdecl fwrite(_In_reads_bytes_(_Size *_Count) const void *_Str, _In_ size_t _Size, _In_ size_t _Count, _Inout_ FILE *_File)
#define argv
Definition: mplay32.c:18
#define R_OK
Definition: io.h:171
const char * filename
Definition: ioapi.h:135
static void pass(void)
Definition: cdmake.c:1410
const char * strerror(int err)
Definition: compat_str.c:23
#define eq(received, expected, label, type)
Definition: locale.c:144
static HWND child
Definition: cursoricon.c:298
char * strtok_s(char *str, const char *delim, char **ctx)
Definition: cdmake.c:1920
struct boot_header * PBOOT_HEADER
#define FILE_SHARE_READ
Definition: compat.h:125
unsigned char BYTE
Definition: cdmake.c:76
Definition: fatfs.h:198
Definition: dirhash.h:21
#define DT_DIR
Definition: fs.h:149
PDIR_RECORD sort_linked_list(PDIR_RECORD, unsigned, int(*)(PDIR_RECORD, PDIR_RECORD))
char * end_source
Definition: cdmake.c:187
static void write_word_block(unsigned count, WORD value)
Definition: cdmake.c:498
struct date_and_time DATE_AND_TIME
#define sprintf(buf, format,...)
Definition: sprintf.c:55
DIR *__cdecl opendir(const char *)
struct date_and_time * PDATE_AND_TIME
static void flush_buffer(void)
Definition: cdmake.c:334
WORD wYear
Definition: winbase.h:870
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
const char * orig_name
Definition: cdmake.c:157
#define DT_REG
Definition: fs.h:151
#define DIR_SEPARATOR_CHAR
Definition: config.h:5
_Check_return_opt_ _CRTIMP size_t __cdecl fread(_Out_writes_bytes_(_ElementSize *_Count) void *_DstBuf, _In_ size_t _ElementSize, _In_ size_t _Count, _Inout_ FILE *_File)
static void write_little_endian_word(WORD x)
Definition: cdmake.c:372
#define va_end(ap)
Definition: acmsvcex.h:90
static void write_little_endian_dword(DWORD x)
Definition: cdmake.c:390
static PDIR_RECORD new_empty_dirrecord(PDIR_RECORD d, BOOL directory)
Definition: cdmake.c:1183
unsigned int BOOL
Definition: ntddk_ex.h:94
_Check_return_ _CRTIMP char *__cdecl strdup(_In_opt_z_ const char *_Src)
BYTE platform_id
Definition: cdmake.c:128
Definition: dirent.h:39
char source[512]
Definition: cdmake.c:186
const WCHAR * str
WORD wMinute
Definition: winbase.h:875
DIR_RECORD root
Definition: cdmake.c:183
struct boot_entry * PBOOT_ENTRY
DWORD number_of_files
Definition: cdmake.c:210
smooth NULL
Definition: ftsmooth.c:416
_Check_return_opt_ _CRTIMP int __cdecl fseek(_Inout_ FILE *_File, _In_ long _Offset, _In_ int _Origin)
unsigned char
Definition: typeof.h:29
BOOL scan_files_only
Definition: cdmake.c:192
char * va_list
Definition: acmsvcex.h:78
static void parse_filename_into_dirrecord(const char *filename, PDIR_RECORD d, BOOL dir)
Definition: cdmake.c:668
int tm_mon
Definition: time.h:81
GLuint index
Definition: glext.h:6031
unsigned int dir
Definition: maze.c:112
BOOL eltorito
Definition: cdmake.c:222
FILE * file
Definition: cdmake.c:97
struct directory_record * next_in_path_table
Definition: cdmake.c:147
#define isdigit(c)
Definition: acclib.h:68
static void release_memory(void)
Definition: cdmake.c:275
#define OPEN_EXISTING
Definition: compat.h:426
struct boot_entry BOOT_ENTRY
static int check_for_punctuation(int c, const char *name)
Definition: cdmake.c:638
static void write_big_endian_dword(DWORD x)
Definition: cdmake.c:398
char bootimage[512]
Definition: cdmake.c:121
enum @1497 verbosity
_Check_return_opt_ _CRTIMP int __cdecl _findclose(_In_ intptr_t _FindHandle)
#define SEEK_SET
Definition: jmemansi.c:26
char filespecs[128]
Definition: cdmake.c:101
static void pad(Char *s)
Definition: bzip2.c:908
GLfloat f
Definition: glext.h:7540
BYTE second
Definition: cdmake.c:136
int toupper(int c)
Definition: utclib.c:881
BOOL WINAPI FileTimeToSystemTime(IN CONST FILETIME *lpFileTime, OUT LPSYSTEMTIME lpSystemTime)
Definition: time.c:178
unsigned int padding
Definition: isohybrid.c:50
#define HIDDEN_FLAG
Definition: cdmake.c:91
GLsizeiptr size
Definition: glext.h:5919
#define _A_SUBDIR
Definition: dos.h:34
_Check_return_opt_ _CRTIMP int __cdecl vprintf(_In_z_ _Printf_format_string_ const char *_Format, va_list _ArgList)
#define d
Definition: ke_i.h:81
r parent
Definition: btrfs.c:2897
_Check_return_ _CRTIMP int __cdecl _access(_In_z_ const char *_Filename, _In_ int _AccessMode)
DWORD sector
Definition: cdmake.c:98
_CRTIMP int __cdecl _findnext(intptr_t _FindHandle, struct _finddata_t *_FindData)
struct boot_header * next_header
Definition: cdmake.c:126
#define S_ISDIR(mode)
Definition: various.h:18
struct directory_record DIR_RECORD
DWORD big_endian_path_table_sector
Definition: cdmake.c:204
#define MAX_PATH
Definition: compat.h:26
const char file[]
Definition: icontest.c:11
const GLubyte * c
Definition: glext.h:8905
#define APP_ID
Definition: config.h:15
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
unsigned short WORD
Definition: ntddk_ex.h:93
unsigned long DWORD
Definition: ntddk_ex.h:95
BOOL accept_punctuation_marks
Definition: cdmake.c:199
static int compare_directory_order(PDIR_RECORD p, PDIR_RECORD q)
Definition: cdmake.c:834
PDIR_RECORD new_directory_record(struct dirent *entry, struct stat *stbuf, PDIR_RECORD parent)
Definition: cdmake.c:797
DWORD joliet_big_endian_path_table_sector
Definition: cdmake.c:235
GLdouble GLdouble GLdouble GLdouble q
Definition: gl.h:2063
struct directory_record * next_in_memory
Definition: cdmake.c:148
WORD wSecond
Definition: winbase.h:876
#define GetFileSizeEx
Definition: compat.h:414
static void init_boot_entry(PBOOT_ENTRY boot_entry, BYTE boot_emu_type, WORD load_segment, char *bootimage)
Definition: cdmake.c:1949
static void write_big_endian_word(WORD x)
Definition: cdmake.c:378
struct target_dir_hash specified_files
Definition: cdmake.c:216
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:126
#define index(s, c)
Definition: various.h:29
BOOL show_progress
Definition: cdmake.c:190
Definition: cdmake.c:189
unsigned short st_mode
Definition: stat.h:58
Definition: stat.h:55
uint32_t entry
Definition: isohybrid.c:63
DWORD joliet_path_table_size
Definition: cdmake.c:233
unsigned char BYTE
Definition: mem.h:68
GLdouble s
Definition: gl.h:2039
static void write_block(unsigned count, BYTE value)
Definition: cdmake.c:485
#define GENERIC_READ
Definition: compat.h:124
_Check_return_opt_ _CRTIMP int __cdecl fclose(_Inout_ FILE *_File)
_Check_return_ _CRTIMP FILE *__cdecl fopen(_In_z_ const char *_Filename, _In_z_ const char *_Mode)
Definition: time.h:76
BYTE boot_emu_type
Definition: cdmake.c:115
directory_record_type
Definition: cdmake.c:167
int __cdecl closedir(DIR *)
char * joliet_name
Definition: cdmake.c:156
Definition: cdmake.c:111
int puts(const char *string)
Definition: crtsupp.c:23
WORD year
Definition: cdmake.c:141
_Check_return_ _Ret_opt_z_ _CRTIMP char *__cdecl getcwd(_Out_writes_opt_(_SizeInBytes) char *_DstBuf, _In_ int _SizeInBytes)
struct target_dir_entry * dir_hash_create_dir(struct target_dir_hash *dh, const char *casename, const char *targetnorm)
Definition: dirhash.c:118
static void append_string_to_source(char *s)
Definition: cdmake.c:866
struct dirent *__cdecl readdir(DIR *)
#define MAX_NAME_LENGTH
Definition: cdmake.c:84
int offset
Definition: cdmake.c:99
DWORD bytes_in_files
Definition: cdmake.c:211
char volume_label[32]
Definition: cdmake.c:185
WORD wDay
Definition: winbase.h:873
WORD path_table_index
Definition: cdmake.c:164
_Check_return_opt_ _CRTIMP char *__cdecl fgets(_Out_writes_z_(_MaxCount) char *_Buf, _In_ int _MaxCount, _Inout_ FILE *_File)
_CRTIMP int __cdecl stat(const char *_Filename, struct stat *_Stat)
Definition: stat.h:345
static unsigned __int64 next
Definition: rand_nt.c:6
BYTE * buffer
Definition: cdmake.c:102
struct directory_record * next_in_directory
Definition: cdmake.c:146
__kernel_time_t time_t
Definition: linux.h:252
DWORD load_rba
Definition: cdmake.c:119
struct directory_record * PDIR_RECORD
static void write_bytecounted_string_as_big_endian_unicode(unsigned bytecount, char *s, char padding)
Definition: cdmake.c:462
static void write_both_endian_word(WORD x)
Definition: cdmake.c:384
static BOOL write_from_file(FILE *file, DWORD size)
Definition: cdmake.c:1377
GLuint GLint GLboolean GLint GLenum access
Definition: glext.h:7866
BOOL joliet
Definition: cdmake.c:232
#define PUBLISHER_ID
Definition: config.h:13
#define MAX_CDNAME_LENGTH
Definition: cdmake.c:85
_CRTIMP intptr_t __cdecl _findfirst(const char *_Filename, struct _finddata_t *_FindData)
WORD wHour
Definition: winbase.h:874
static void write_directory_record(PDIR_RECORD d, DIR_RECORD_TYPE DirType, BOOL joliet)
Definition: cdmake.c:512
static void fill_sector(void)
Definition: cdmake.c:418
#define va_start(ap, A)
Definition: acmsvcex.h:91
struct target_file * dir_hash_add_file(struct target_dir_hash *dh, const char *source, const char *target)
Definition: dirhash.c:178
void normalize_dirname(char *filename)
Definition: dirhash.c:63
PBOOT_HEADER boot_header_list
Definition: cdmake.c:227
static char * edit_with_commas(DWORD x, BOOL pad)
Definition: cdmake.c:255
DWORD size_limit
Definition: cdmake.c:198
char * strtok(char *String, const char *Delimiters)
Definition: utclib.c:338
char * strchr(const char *String, int ch)
Definition: utclib.c:501
int tm_sec
Definition: time.h:77
struct directory_record * parent
Definition: cdmake.c:150
Definition: name.c:36
#define calloc
Definition: rosglue.h:14
DWORD sector
Definition: cdmake.c:159
int main(int argc, char **argv)
Definition: cdmake.c:1962
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
#define c
Definition: ke_i.h:80
int tm_hour
Definition: time.h:79
_Check_return_ _CRTIMP long __cdecl ftell(_Inout_ FILE *_File)
#define TRUE
Definition: cdmake.c:67
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
#define SEEK_END
Definition: cabinet.c:27
#define malloc
Definition: debug_ros.c:4
static void scan_specified_files(PDIR_RECORD d, struct target_dir_entry *dir)
Definition: cdmake.c:1228
#define DIR_SEPARATOR_STRING
Definition: config.h:6
_CRTIMP struct tm *__cdecl gmtime(const time_t *_Time)
Definition: time.h:423
Definition: io.h:37
#define DIRECTORY_FLAG
Definition: cdmake.c:92
BOOT_ENTRY default_boot_entry
Definition: cdmake.c:226
#define CreateFileA(a, b, c, d, e, f, g)
Definition: compat.h:399
void exit(int exitcode)
Definition: _exit.c:33
GLfloat GLfloat p
Definition: glext.h:8902
DWORD boot_catalog_sector
Definition: cdmake.c:224
time_t st_mtime
Definition: stat.h:65
Definition: cdmake.c:189
unsigned long DWORD
Definition: cdmake.c:78
static void get_time_string(char *str)
Definition: cdmake.c:1366
DWORD joliet_little_endian_path_table_sector
Definition: cdmake.c:234
#define memset(x, y, z)
Definition: compat.h:39
BYTE day
Definition: cdmake.c:139
static void make_directory_records(PDIR_RECORD d)
Definition: cdmake.c:965
BOOT_VALIDATION_HEADER boot_validation_header
Definition: cdmake.c:225
#define _A_HIDDEN
Definition: dos.h:31
BYTE minute
Definition: cdmake.c:137
BOOL multi_boot
Definition: cdmake.c:223
#define S_ISREG(mode)
Definition: various.h:17
static int compare_path_table_order(PDIR_RECORD p, PDIR_RECORD q)
Definition: cdmake.c:848
BOOL WINAPI GetFileTime(IN HANDLE hFile, OUT LPFILETIME lpCreationTime OPTIONAL, OUT LPFILETIME lpLastAccessTime OPTIONAL, OUT LPFILETIME lpLastWriteTime OPTIONAL)
Definition: fileinfo.c:1046
Definition: dsound.c:943
char extension[MAX_EXTENSION_LENGTH+1]
Definition: cdmake.c:154
static void write_bytecounted_string(unsigned bytecount, char *s, char padding)
Definition: cdmake.c:435
HANDLE open_file(char *filename, BOOL bWrite)
Definition: mspatcha.c:163
#define MAX_EXTENSION_LENGTH
Definition: cdmake.c:86
struct CFHEADER header
Definition: fdi.c:109
BYTE boot_id
Definition: cdmake.c:114
#define file_size(inode)
Definition: reiserfs_fs.h:1869
static void write_string_as_big_endian_unicode(char *s)
Definition: cdmake.c:454
DWORD bytes_in_directories
Definition: cdmake.c:214
_off_t st_size
Definition: stat.h:63
#define printf
Definition: config.h:203
WORD num_entries
Definition: cdmake.c:129
Definition: fci.c:126