ReactOS  0.4.15-dev-483-ga77a65a
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 
255 static char *edit_with_commas(DWORD x, BOOL pad)
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
317 void error_exit(const char* fmt, ...)
318 {
319  va_list arg;
320 
321  va_start(arg, fmt);
322  vprintf(fmt, arg);
323  va_end(arg);
324  printf("\n");
325  if (cd.file != NULL)
326  fclose(cd.file);
327  release_memory();
328  exit(1);
329 }
330 
331 /*-----------------------------------------------------------------------------
332 This function, which is called only on the second pass, and only when the
333 buffer is not empty, flushes the buffer to the CD-ROM image.
334 -----------------------------------------------------------------------------*/
335 
336 static void flush_buffer(void)
337 {
338  if (fwrite(cd.buffer, cd.count, 1, cd.file) < 1)
339  error_exit("File write error");
340  cd.count = 0;
341  if (show_progress)
342  {
343  printf("\r%s ",
345  }
346 }
347 
348 /*-----------------------------------------------------------------------------
349 This function writes a single byte to the CD-ROM image. On the first pass (in
350 which cd.handle < 0), it does not actually write anything but merely updates
351 the file pointer as though the byte had been written.
352 -----------------------------------------------------------------------------*/
353 
354 static void write_byte(BYTE x)
355 {
356  if (cd.file != NULL)
357  {
358  cd.buffer[cd.count] = x;
359  if (++cd.count == BUFFER_SIZE)
360  flush_buffer();
361  }
362  if (++cd.offset == SECTOR_SIZE)
363  {
364  cd.sector++;
365  cd.offset = 0;
366  }
367 }
368 
369 /*-----------------------------------------------------------------------------
370 These functions write a word or double word to the CD-ROM image with the
371 specified endianity.
372 -----------------------------------------------------------------------------*/
373 
375 {
376  write_byte((BYTE)x);
377  write_byte((BYTE)(x >> 8));
378 }
379 
381 {
382  write_byte((BYTE)(x >> 8));
383  write_byte((BYTE)x);
384 }
385 
387 {
390 }
391 
393 {
394  write_byte((BYTE)x);
395  write_byte((BYTE)(x >> 8));
396  write_byte((BYTE)(x >> 16));
397  write_byte((BYTE)(x >> 24));
398 }
399 
401 {
402  write_byte((BYTE)(x >> 24));
403  write_byte((BYTE)(x >> 16));
404  write_byte((BYTE)(x >> 8));
405  write_byte((BYTE)x);
406 }
407 
409 {
412 }
413 
414 /*-----------------------------------------------------------------------------
415 This function writes enough zeros to fill out the end of a sector, and leaves
416 the file pointer at the beginning of the next sector. If the file pointer is
417 already at the beginning of a sector, it writes nothing.
418 -----------------------------------------------------------------------------*/
419 
420 static void fill_sector(void)
421 {
422  while (cd.offset != 0)
423  write_byte(0);
424 }
425 
426 /*-----------------------------------------------------------------------------
427 This function writes a string to the CD-ROM image. The terminating \0 is not
428 written.
429 -----------------------------------------------------------------------------*/
430 
431 static void write_string(char *s)
432 {
433  while (*s != 0)
434  write_byte(*s++);
435 }
436 
437 static void write_bytecounted_string(unsigned bytecount, char *s, char padding)
438 {
439  while (*s != 0 && bytecount != 0)
440  {
441  write_byte(*s++);
442  bytecount--;
443  }
444  while (bytecount != 0)
445  {
447  bytecount--;
448  }
449 }
450 
451 /*-----------------------------------------------------------------------------
452 This function writes a ansi string as a big endian unicode string to the CD-ROM
453 image. The terminating \0 is not written.
454 -----------------------------------------------------------------------------*/
455 
457 {
458  while (*s != 0)
459  {
461  }
462 }
463 
464 static void write_bytecounted_string_as_big_endian_unicode(unsigned bytecount, char *s, char padding)
465 {
466  unsigned wordcount = bytecount / 2;
467 
468  while (*s != 0 && wordcount != 0)
469  {
471  wordcount--;
472  }
473  while (wordcount != 0)
474  {
476  wordcount--;
477  }
478 
479  if (bytecount % 2 != 0)
481 }
482 
483 /*-----------------------------------------------------------------------------
484 This function writes a block of identical bytes to the CD-ROM image.
485 -----------------------------------------------------------------------------*/
486 
487 static void write_block(unsigned count, BYTE value)
488 {
489  while (count != 0)
490  {
491  write_byte(value);
492  count--;
493  }
494 }
495 
496 /*-----------------------------------------------------------------------------
497 This function writes a block of identical big endian words to the CD-ROM image.
498 -----------------------------------------------------------------------------*/
499 
500 static void write_word_block(unsigned count, WORD value)
501 {
502  while (count != 0)
503  {
505  count--;
506  }
507 }
508 
509 /*-----------------------------------------------------------------------------
510 This function writes a directory record to the CD_ROM image.
511 -----------------------------------------------------------------------------*/
512 
513 static void
515  DIR_RECORD_TYPE DirType,
516  BOOL joliet)
517 {
518  unsigned identifier_size;
519  unsigned record_size;
520 
521  if (joliet)
522  {
523  if (DirType == DOT_RECORD || DirType == DOT_DOT_RECORD)
524  identifier_size = 1;
525  else
526  identifier_size = strlen(d->joliet_name) * 2;
527  }
528  else
529  {
530  switch (DirType)
531  {
532  case DOT_RECORD:
533  case DOT_DOT_RECORD:
534  identifier_size = 1;
535  break;
536  case SUBDIRECTORY_RECORD:
537  /*printf("Subdir: %s\n", d->name_on_cd);*/
538  identifier_size = strlen(d->name_on_cd);
539  break;
540  case FILE_RECORD:
541  /*printf("File: %s.%s -> %s.%s\n", d->name, d->extension, d->name_on_cd, d->extension_on_cd);*/
542  identifier_size = strlen(d->name_on_cd) + 2;
543  if (d->extension_on_cd[0] != 0)
544  identifier_size += 1 + strlen(d->extension_on_cd);
545  break;
546  default:
547  identifier_size = 1;
548  break;
549  }
550  }
551  record_size = 33 + identifier_size;
552  if ((identifier_size & 1) == 0)
553  record_size++;
554  if (cd.offset + record_size > SECTOR_SIZE)
555  fill_sector();
556  write_byte((BYTE)record_size);
557  write_byte(0); // number of sectors in extended attribute record
558  if (joliet)
559  {
560  write_both_endian_dword(d->joliet_sector);
561  write_both_endian_dword(d->joliet_size);
562  }
563  else
564  {
565  write_both_endian_dword(d->sector);
566  write_both_endian_dword(d->size);
567  }
568  write_byte((BYTE)(d->date_and_time.year - 1900));
569  write_byte(d->date_and_time.month);
570  write_byte(d->date_and_time.day);
571  write_byte(d->date_and_time.hour);
572  write_byte(d->date_and_time.minute);
573  write_byte(d->date_and_time.second);
574  write_byte(0); // GMT offset
575  write_byte(d->flags);
576  write_byte(0); // file unit size for an interleaved file
577  write_byte(0); // interleave gap size for an interleaved file
578  write_both_endian_word(1); // volume sequence number
579  write_byte((BYTE)identifier_size);
580  switch (DirType)
581  {
582  case DOT_RECORD:
583  write_byte(0);
584  break;
585  case DOT_DOT_RECORD:
586  write_byte(1);
587  break;
588  case SUBDIRECTORY_RECORD:
589  if (joliet)
591  else
592  write_string(d->name_on_cd);
593  break;
594  case FILE_RECORD:
595  if (joliet)
596  {
598  }
599  else
600  {
601  write_string(d->name_on_cd);
602  if (d->extension_on_cd[0] != 0)
603  {
604  write_byte('.');
605  write_string(d->extension_on_cd);
606  }
607  write_string(";1");
608  }
609  break;
610  }
611  if ((identifier_size & 1) == 0)
612  write_byte(0);
613 }
614 
615 /*-----------------------------------------------------------------------------
616 This function converts the date and time words from an ffblk structure and
617 puts them into a date_and_time structure.
618 -----------------------------------------------------------------------------*/
619 
621 {
622  struct tm *timedef;
623  timedef = gmtime(time);
624 
625  dt->second = timedef->tm_sec;
626  dt->minute = timedef->tm_min;
627  dt->hour = timedef->tm_hour;
628  dt->day = timedef->tm_mday;
629  dt->month = timedef->tm_mon + 1;
630  dt->year = timedef->tm_year + 1900;
631 }
632 
633 /*-----------------------------------------------------------------------------
634 This function checks the specified character, if necessary, and
635 generates an error if it is a punctuation mark other than an underscore.
636 It also converts small letters to capital letters and returns the
637 result.
638 -----------------------------------------------------------------------------*/
639 
640 static int check_for_punctuation(int c, const char *name)
641 {
642  c = toupper(c & 0xFF);
643  if (!accept_punctuation_marks && !isalnum(c) && c != '_')
644  error_exit("Punctuation mark in %s", name);
645  return c;
646 }
647 
648 /*-----------------------------------------------------------------------------
649 This function checks to see if there's a cdname conflict.
650 -----------------------------------------------------------------------------*/
651 
652 #if defined(_WIN32) && !defined(strcasecmp)
653 #define strcasecmp stricmp
654 #endif // _WIN32
655 
657 {
658  PDIR_RECORD p = d->parent->first_record;
659  while (p)
660  {
661  if ( p != d
662  && !strcasecmp(p->name_on_cd, d->name_on_cd)
663  && !strcasecmp(p->extension_on_cd, d->extension_on_cd) )
664  return TRUE;
665  p = p->next_in_directory;
666  }
667  return FALSE;
668 }
669 
671 {
672  const char *s = filename;
673  char *t = d->name_on_cd;
674  char *n = d->name;
675  int joliet_length;
676  int filename_counter;
677  filename_counter = 1;
678  while (*s != 0)
679  {
680  if (*s == '.')
681  {
682  s++;
683  break;
684  }
685 
686  if ((size_t)(t-d->name_on_cd) < sizeof(d->name_on_cd)-1)
688  else if (!joliet)
689  error_exit("'%s' is not ISO-9660, aborting...", filename);
690 
691  if ((size_t)(n-d->name) < sizeof(d->name)-1)
692  *n++ = *s;
693  else if (!joliet)
694  error_exit("'%s' is not ISO-9660, aborting...", filename);
695  s++;
696  }
697  // Check for extension length
698  if (!joliet && strlen(s) > MAX_EXTENSION_LENGTH)
699  {
700  error_exit("'%s' has too long extension, aborting...", filename);
701  }
702  *t = 0;
703  strcpy(d->extension, s);
704  t = d->extension_on_cd;
705  while (*s != 0)
706  {
707  if ((size_t)(t-d->extension_on_cd) < sizeof(d->extension_on_cd)-1)
709  else if (!joliet)
710  error_exit("'%s' is not ISO-9660, aborting...", filename);
711  s++;
712  }
713  *t = 0;
714  *n = 0;
715 
716  if (dir)
717  {
718  if (d->extension[0] != 0)
719  {
720  if (!joliet)
721  error_exit("Directory with extension '%s'", filename);
722  }
723  d->flags = DIRECTORY_FLAG;
724  } else
725  {
726  d->flags = 0;
727  }
728 
729  filename_counter = 1;
730  while (cdname_exists(d))
731  {
732  // the file name must be at least 8 chars long
733  if (strlen(d->name_on_cd)<8)
734  error_exit("'%s' is a duplicate file name, aborting...", filename);
735 
736  if ((d->name_on_cd[8] == '.') && (strlen(d->name_on_cd) < 13))
737  error_exit("'%s' is a duplicate file name, aborting...", filename);
738 
739  // max 255 times for equal short filename
740  if (filename_counter>255)
741  error_exit("'%s' is a duplicate file name, aborting...", filename);
742 
743  d->name_on_cd[8] = '~';
744  memset(&d->name_on_cd[9],0,5);
745  sprintf(&d->name_on_cd[9],"%d",filename_counter);
746  filename_counter++;
747  }
748 
749  if (joliet)
750  {
751  joliet_length = strlen(filename);
752  if (joliet_length > 64)
753  error_exit("'%s' is not Joliet, aborting...", filename);
754  d->joliet_name = malloc(joliet_length + 1);
755  if (d->joliet_name == NULL)
756  error_exit("Insufficient memory");
757  strcpy(d->joliet_name, filename);
758  }
759 }
760 
761 /*-----------------------------------------------------------------------------
762 This function creates a new directory record with the information from the
763 specified ffblk. It links it into the beginning of the directory list
764 for the specified parent and returns a pointer to the new record.
765 -----------------------------------------------------------------------------*/
766 
767 #ifdef _WIN32
768 
769 /* Win32 version */
773 {
774  PDIR_RECORD d;
775 
776  d = calloc(1, sizeof(*d));
777  if (d == NULL)
778  error_exit("Insufficient memory");
779  d->next_in_memory = root.next_in_memory;
780  root.next_in_memory = d;
781 
782  /* I need the parent set before calling parse_filename_into_dirrecord(),
783  because that functions checks for duplicate file names*/
784  d->parent = parent;
785  parse_filename_into_dirrecord(f->name, d, f->attrib & _A_SUBDIR);
786 
787  convert_date_and_time(&d->date_and_time, &f->time_write);
788  d->flags |= f->attrib & _A_HIDDEN ? HIDDEN_FLAG : 0;
789  d->size = d->joliet_size = f->size;
790  d->next_in_directory = parent->first_record;
791  parent->first_record = d;
792  return d;
793 }
794 
795 #else
796 
797 /* Linux version */
800  struct stat *stbuf,
802 {
803  PDIR_RECORD d;
804 
805  d = calloc(1, sizeof(*d));
806  if (d == NULL)
807  error_exit("Insufficient memory");
808  d->next_in_memory = root.next_in_memory;
809  root.next_in_memory = d;
810 
811  /* I need the parent set before calling parse_filename_into_dirrecord(),
812  because that functions checks for duplicate file names*/
813  d->parent = parent;
814 #ifdef HAVE_D_TYPE
815  parse_filename_into_dirrecord(entry->d_name, d, entry->d_type == DT_DIR);
816 #else
818 #endif
819 
820  convert_date_and_time(&d->date_and_time, &stbuf->st_mtime);
821  d->flags |= entry->d_name[0] == '.' ? HIDDEN_FLAG : 0;
822  d->size = d->joliet_size = stbuf->st_size;
823  d->next_in_directory = parent->first_record;
824  parent->first_record = d;
825  return d;
826 }
827 
828 #endif
829 
830 /*-----------------------------------------------------------------------------
831 This function compares two directory records according to the ISO9660 rules
832 for directory sorting and returns a negative value if p is before q, or a
833 positive value if p is after q.
834 -----------------------------------------------------------------------------*/
835 
837 {
838  int n = strcmp(p->name_on_cd, q->name_on_cd);
839  if (n == 0)
840  n = strcmp(p->extension_on_cd, q->extension_on_cd);
841  return n;
842 }
843 
844 /*-----------------------------------------------------------------------------
845 This function compares two directory records (which must represent
846 directories) according to the ISO9660 rules for path table sorting and returns
847 a negative value if p is before q, or a positive vlaue if p is after q.
848 -----------------------------------------------------------------------------*/
849 
851 {
852  int n = p->level - q->level;
853  if (p == q)
854  return 0;
855  if (n == 0)
856  {
857  n = compare_path_table_order(p->parent, q->parent);
858  if (n == 0)
860  }
861  return n;
862 }
863 
864 /*-----------------------------------------------------------------------------
865 This function appends the specified string to the buffer source[].
866 -----------------------------------------------------------------------------*/
867 
868 static void append_string_to_source(char *s)
869 {
870  while (*s != 0)
871  *end_source++ = *s++;
872 }
873 
874 /*-----------------------------------------------------------------------------
875 This function scans all files from the current source[] (which must end in \,
876 and represents a directory already in the database as d),
877 and puts the appropriate directory records into the database in memory, with
878 the specified root. It calls itself recursively to scan all subdirectories.
879 -----------------------------------------------------------------------------*/
880 
881 #ifdef _WIN32
882 
883 static void
885 {
886  PDIR_RECORD new_d;
887  struct _finddata_t f;
888  char *old_end_source;
889  int findhandle;
890 
891  d->first_record = NULL;
892  strcpy(end_source, "*.*");
893 
894  findhandle = _findfirst(source, &f);
895  if (findhandle != 0)
896  {
897  do
898  {
899  if ((f.attrib & (_A_HIDDEN | _A_SUBDIR)) == 0 && f.name[0] != '.')
900  {
901  if (strcmp(f.name, DIRECTORY_TIMESTAMP) == 0)
902  {
903  convert_date_and_time(&d->date_and_time, &f.time_write);
904  }
905  else
906  {
907  if (verbosity == VERBOSE)
908  {
909  old_end_source = end_source;
910  strcpy(end_source, f.name);
911  printf("%d: file %s\n", d->level, source);
912  end_source = old_end_source;
913  }
915  }
916  }
917  }
918  while (_findnext(findhandle, &f) == 0);
919 
920  _findclose(findhandle);
921  }
922 
923  strcpy(end_source, "*.*");
924  findhandle = _findfirst(source, &f);
925  if (findhandle)
926  {
927  do
928  {
929  if (f.attrib & _A_SUBDIR && f.name[0] != '.')
930  {
931  old_end_source = end_source;
934  if (verbosity == VERBOSE)
935  {
936  *end_source = 0;
937  printf("%d: directory %s\n", d->level + 1, source);
938  }
939  if (d->level < MAX_LEVEL)
940  {
941  new_d = new_directory_record(&f, d);
942  new_d->next_in_path_table = root.next_in_path_table;
943  root.next_in_path_table = new_d;
944  new_d->level = d->level + 1;
945  make_directory_records(new_d);
946  }
947  else
948  {
949  error_exit("Directory is nested too deep");
950  }
951  end_source = old_end_source;
952  }
953  }
954  while (_findnext(findhandle, &f) == 0);
955 
956  _findclose(findhandle);
957  }
958 
959  // sort directory
960  d->first_record = sort_linked_list(d->first_record, 0, compare_directory_order);
961 }
962 
963 #else
964 
965 /* Linux version */
966 static void
968 {
969  PDIR_RECORD new_d;
970  DIR *dirp;
971  struct dirent *entry;
972  char *old_end_source;
973  struct stat stbuf;
974  char buf[MAX_PATH];
975 
976  d->first_record = NULL;
977 
978 #ifdef HAVE_D_TYPE
979  dirp = opendir(source);
980  if (dirp != NULL)
981  {
982  while ((entry = readdir(dirp)) != NULL)
983  {
984  if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
985  continue; // skip self and parent
986 
987  if (entry->d_type == DT_REG) // normal file
988  {
989  // Check for an absolute path
990  if (source[0] == DIR_SEPARATOR_CHAR)
991  {
992  strcpy(buf, source);
994  strcat(buf, entry->d_name);
995  }
996  else
997  {
998  if (!getcwd(buf, sizeof(buf)))
999  error_exit("Cannot get CWD: %s\n", strerror(errno));
1001  strcat(buf, source);
1002  strcat(buf, entry->d_name);
1003  }
1004 
1005  if (stat(buf, &stbuf) == -1)
1006  {
1007  error_exit("Cannot access '%s' (%s)\n", buf, strerror(errno));
1008  return;
1009  }
1010 
1011  if (strcmp(entry->d_name, DIRECTORY_TIMESTAMP) == 0)
1012  {
1013  convert_date_and_time(&d->date_and_time, &stbuf.st_ctime);
1014  }
1015  else
1016  {
1017  if (verbosity == VERBOSE)
1018  {
1019  printf("%d: file %s\n", d->level, buf);
1020  }
1021  (void) new_directory_record(entry, &stbuf, d);
1022  }
1023  }
1024  }
1025  closedir(dirp);
1026  }
1027  else
1028  {
1029  error_exit("Cannot open '%s'\n", source);
1030  return;
1031  }
1032 
1033  dirp = opendir(source);
1034  if (dirp != NULL)
1035  {
1036  while ((entry = readdir(dirp)) != NULL)
1037  {
1038  if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
1039  continue; // skip self and parent
1040 
1041  if (entry->d_type == DT_DIR) // directory
1042  {
1043  old_end_source = end_source;
1044  append_string_to_source(entry->d_name);
1046  *end_source = 0;
1047  if (verbosity == VERBOSE)
1048  {
1049  printf("%d: directory %s\n", d->level + 1, source);
1050  }
1051  if (d->level < MAX_LEVEL)
1052  {
1053  // Check for an absolute path
1054  if (source[0] == DIR_SEPARATOR_CHAR)
1055  {
1056  strcpy(buf, source);
1057  }
1058  else
1059  {
1060  if (!getcwd(buf, sizeof(buf)))
1061  error_exit("Cannot get CWD: %s\n", strerror(errno));
1063  strcat(buf, source);
1064  }
1065 
1066  if (stat(buf, &stbuf) == -1)
1067  {
1068  error_exit("Cannot access '%s' (%s)\n", buf, strerror(errno));
1069  return;
1070  }
1071  new_d = new_directory_record(entry, &stbuf, d);
1072  new_d->next_in_path_table = root.next_in_path_table;
1073  root.next_in_path_table = new_d;
1074  new_d->level = d->level + 1;
1075  make_directory_records(new_d);
1076  }
1077  else
1078  {
1079  error_exit("Directory is nested too deep");
1080  }
1081  end_source = old_end_source;
1082  *end_source = 0;
1083  }
1084  }
1085  closedir(dirp);
1086  }
1087  else
1088  {
1089  error_exit("Cannot open '%s'\n", source);
1090  return;
1091  }
1092 
1093 #else
1094 
1095  dirp = opendir(source);
1096  if (dirp != NULL)
1097  {
1098  while ((entry = readdir(dirp)) != NULL)
1099  {
1100  if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
1101  continue; // skip self and parent
1102 
1103  // Check for an absolute path
1104  if (source[0] == DIR_SEPARATOR_CHAR)
1105  {
1106  strcpy(buf, source);
1108  strcat(buf, entry->d_name);
1109  }
1110  else
1111  {
1112  if (!getcwd(buf, sizeof(buf)))
1113  error_exit("Cannot get CWD: %s\n", strerror(errno));
1115  strcat(buf, source);
1116  strcat(buf, entry->d_name);
1117  }
1118 
1119  if (stat(buf, &stbuf) == -1)
1120  {
1121  error_exit("Cannot access '%s' (%s)\n", buf, strerror(errno));
1122  return;
1123  }
1124 
1125  if (S_ISDIR(stbuf.st_mode))
1126  {
1127  old_end_source = end_source;
1128  append_string_to_source(entry->d_name);
1130  *end_source = 0;
1131  if (verbosity == VERBOSE)
1132  {
1133  printf("%d: directory %s\n", d->level + 1, source);
1134  }
1135 
1136  if (d->level < MAX_LEVEL)
1137  {
1138  new_d = new_directory_record(entry, &stbuf, d);
1139  new_d->next_in_path_table = root.next_in_path_table;
1140  root.next_in_path_table = new_d;
1141  new_d->level = d->level + 1;
1142  make_directory_records(new_d);
1143  }
1144  else
1145  {
1146  error_exit("Directory is nested too deep");
1147  }
1148 
1149  end_source = old_end_source;
1150  *end_source = 0;
1151  }
1152  else if (S_ISREG(stbuf.st_mode))
1153  {
1154  if (strcmp(entry->d_name, DIRECTORY_TIMESTAMP) == 0)
1155  {
1156  convert_date_and_time(&d->date_and_time, &stbuf.st_ctime);
1157  }
1158  else
1159  {
1160  if (verbosity == VERBOSE)
1161  {
1162  printf("%d: file %s\n", d->level, buf);
1163  }
1164  (void) new_directory_record(entry, &stbuf, d);
1165  }
1166  }
1167  }
1168  closedir(dirp);
1169  }
1170  else
1171  {
1172  error_exit("Cannot open '%s'\n", source);
1173  return;
1174  }
1175 
1176 #endif
1177 
1178  // sort directory
1179  d->first_record = sort_linked_list(d->first_record, 0, compare_directory_order);
1180 }
1181 
1182 #endif
1183 
1184 static PDIR_RECORD
1186 {
1187  PDIR_RECORD new_d;
1188  new_d = calloc(1, sizeof(*new_d));
1189  new_d->parent = d;
1190  new_d->level = d->level + 1;
1191  new_d->next_in_directory = d->first_record;
1192  d->first_record = new_d;
1193  new_d->next_in_memory = root.next_in_memory;
1194  root.next_in_memory = new_d;
1195  new_d->date_and_time = d->date_and_time;
1196  if (directory)
1197  {
1198  new_d->flags |= DIRECTORY_FLAG;
1199  new_d->next_in_path_table = root.next_in_path_table;
1200  root.next_in_path_table = new_d;
1201  }
1202  return new_d;
1203 }
1204 
1205 #ifdef _WIN32
1206 static BOOL
1207 get_cd_file_time(HANDLE handle, PDATE_AND_TIME cd_time_info)
1208 {
1209  FILETIME file_time;
1210  SYSTEMTIME sys_time;
1211 
1212  if (!GetFileTime(handle, NULL, NULL, &file_time))
1213  return FALSE;
1214 
1215  FileTimeToSystemTime(&file_time, &sys_time);
1216  memset(cd_time_info, 0, sizeof(*cd_time_info));
1217 
1218  cd_time_info->year = sys_time.wYear;
1219  cd_time_info->month = sys_time.wMonth;
1220  cd_time_info->day = sys_time.wDay;
1221  cd_time_info->hour = sys_time.wHour;
1222  cd_time_info->minute = sys_time.wMinute;
1223  cd_time_info->second = sys_time.wSecond;
1224 
1225  return TRUE;
1226 }
1227 #endif
1228 
1229 static void
1231 {
1232  PDIR_RECORD new_d;
1233 #ifdef _WIN32
1234  HANDLE open_file;
1236 #else
1237  struct stat stbuf;
1238 #endif
1239  struct target_file *file;
1240  struct target_dir_entry *child;
1241 
1242  d->first_record = NULL;
1243 
1244  for (file = dir->head; file; file = file->next)
1245  {
1246  if (strcmp(file->target_name, DIRECTORY_TIMESTAMP) == 0)
1247  {
1248 #ifdef _WIN32
1249  if ((open_file = CreateFileA(file->source_name,
1250  GENERIC_READ,
1252  NULL,
1253  OPEN_EXISTING,
1256  {
1257  error_exit("Cannot open timestamp file '%s'\n", file->source_name);
1258  }
1259 
1260  if (!get_cd_file_time(open_file, &d->date_and_time))
1261  {
1262  error_exit("Cannot stat timestamp file '%s'\n", file->source_name);
1263  }
1265 #else
1266  if (stat(file->target_name, &stbuf) == -1)
1267  {
1268  error_exit("Cannot stat timestamp file '%s'\n", file->source_name);
1269  }
1270  convert_date_and_time(&d->date_and_time, &stbuf.st_ctime);
1271 #endif
1272  }
1273  else
1274  {
1275  if (verbosity == VERBOSE)
1276  {
1277  printf("%d: file %s (from %s)\n",
1278  d->level,
1279  file->target_name,
1280  file->source_name);
1281  }
1282  new_d = new_empty_dirrecord(d, FALSE);
1283  parse_filename_into_dirrecord(file->target_name, new_d, FALSE);
1284 #ifdef _WIN32
1285  if ((open_file = CreateFileA(file->source_name,
1286  GENERIC_READ,
1288  NULL,
1289  OPEN_EXISTING,
1292  {
1293  error_exit("Cannot open file '%s'\n", file->source_name);
1294  }
1295  if (!get_cd_file_time(open_file, &new_d->date_and_time))
1296  {
1297  error_exit("Cannot stat file '%s'\n", file->source_name);
1298  }
1300  {
1301  error_exit("Cannot get file size of '%s'\n", file->source_name);
1302  }
1303  new_d->size = new_d->joliet_size = file_size.QuadPart;
1304  new_d->orig_name = file->source_name;
1306 #else
1307  if (stat(file->source_name, &stbuf) == -1)
1308  {
1309  error_exit("Cannot find '%s' (target '%s')\n",
1310  file->source_name,
1311  file->target_name);
1312  }
1313  convert_date_and_time(&new_d->date_and_time, &stbuf.st_mtime);
1314  new_d->size = new_d->joliet_size = stbuf.st_size;
1315  new_d->orig_name = file->source_name;
1316 #endif
1317  }
1318  }
1319 
1320  for (child = dir->child; child; child = child->next)
1321  {
1322  if (verbosity == VERBOSE)
1323  {
1324  printf("%d: directory %s\n", d->level, child->case_name);
1325  }
1326  new_d = new_empty_dirrecord(d, TRUE);
1327  parse_filename_into_dirrecord(child->case_name, new_d, TRUE);
1328  scan_specified_files(new_d, child);
1329  }
1330 
1331  /* sort directory */
1332  d->first_record = sort_linked_list(d->first_record,
1333  0,
1335  source[0] = 0;
1336  end_source = source;
1337 }
1338 
1339 /*-----------------------------------------------------------------------------
1340 This function loads the file specifications for the file or directory
1341 corresponding to the specified directory record into the source[] buffer. It
1342 is recursive.
1343 -----------------------------------------------------------------------------*/
1344 
1346 {
1347  if (d != &root)
1348  {
1349  get_file_specifications(d->parent);
1350  if (d->joliet_name == NULL)
1352  else
1353  append_string_to_source(d->joliet_name);
1354 
1355  if (((d->flags & DIRECTORY_FLAG) == 0 || joliet) && d->extension[0] != 0)
1356  {
1357  if (d->joliet_name == NULL)
1358  {
1359  *end_source++ = '.';
1360  append_string_to_source(d->extension);
1361  }
1362  }
1363  if (d->flags & DIRECTORY_FLAG)
1365  }
1366 }
1367 
1368 static void get_time_string(char *str)
1369 {
1370  sprintf(str, "%04d%02d%02d%02d%02d%02d00",
1371  root.date_and_time.year,
1372  root.date_and_time.month,
1373  root.date_and_time.day,
1374  root.date_and_time.hour,
1375  root.date_and_time.minute,
1376  root.date_and_time.second);
1377 }
1378 
1380 {
1381  if (cd.file != NULL)
1382  {
1383  int n;
1384 
1385  fseek(file, 0, SEEK_SET);
1386  while (size > 0)
1387  {
1388  n = BUFFER_SIZE - cd.count;
1389  if ((DWORD)n > size)
1390  n = size;
1391 
1392  if (fread(cd.buffer + cd.count, n, 1, file) < 1)
1393  return FALSE;
1394 
1395  cd.count += n;
1396  if (cd.count == BUFFER_SIZE)
1397  flush_buffer();
1398  cd.sector += n / SECTOR_SIZE;
1399  cd.offset += n % SECTOR_SIZE;
1400  size -= n;
1401  }
1402  }
1403  else
1404  {
1405  cd.sector += size / SECTOR_SIZE;
1406  cd.offset += size % SECTOR_SIZE;
1407  }
1408 
1409  return TRUE;
1410 }
1411 
1412 static void pass(void)
1413 {
1414  PDIR_RECORD d, q;
1415  unsigned int index;
1416  unsigned int name_length;
1417  DWORD size;
1418  DWORD number_of_sectors;
1419  char *old_end_source;
1420  FILE *file;
1421 
1424 
1425  char timestring[17];
1426 
1427  get_time_string(timestring);
1428 
1429  // first 16 sectors are zeros
1430  write_block(16 * SECTOR_SIZE, 0);
1431 
1432 
1433  // Primary Volume Descriptor
1434  if (make_bridged_udf)
1435  {
1436  write_string("\1CD001\1");
1437  write_byte(0);
1438  write_bytecounted_string(32, "", ' '); // system identifier
1439  write_bytecounted_string(32, volume_label, ' '); // volume label
1440 
1441  write_block(8, 0);
1443  write_block(32, 0);
1444  write_both_endian_word(1); // volume set size
1445  write_both_endian_word(1); // volume sequence number
1446  write_both_endian_word(2048); // sector size
1449  write_little_endian_dword(0); // second little endian path table
1451  write_big_endian_dword(0); // second big endian path table
1453 
1454  write_bytecounted_string(128, volume_label, ' '); // volume set identifier
1455  write_bytecounted_string(128, PUBLISHER_ID, ' '); // publisher identifier
1456  write_bytecounted_string(128, DATA_PREP_ID, ' '); // data preparer identifier
1457  write_bytecounted_string(128, APP_ID, ' '); // application identifier
1458 
1459  write_bytecounted_string(37, "", ' '); // copyright file identifier
1460  write_bytecounted_string(37, "", ' '); // abstract file identifier
1461  write_bytecounted_string(37, "", ' '); // bibliographic file identifier
1462 
1463  write_string(timestring); // volume creation
1464  write_byte(0);
1465  write_string(timestring); // most recent modification
1466  write_byte(0);
1467  write_string("0000000000000000"); // volume expires
1468  write_byte(0);
1469  write_string("0000000000000000"); // volume is effective
1470  write_byte(0);
1471  write_byte(1);
1472  write_byte(0);
1473  fill_sector();
1474  }
1475 
1476  // Boot Volume Descriptor
1477  if (eltorito)
1478  {
1479  write_byte(0); // Boot record ID
1480  write_string("CD001\1");
1481  write_bytecounted_string(32, "EL TORITO SPECIFICATION", 0); // El-Torito identifier
1482  write_block(32, 0); // unused
1483  write_little_endian_dword(boot_catalog_sector); // pointer to boot catalog
1484  fill_sector();
1485  }
1486 
1487  // Supplementary Volume Descriptor
1488  if (joliet)
1489  {
1490  write_string("\2CD001\1");
1491  write_byte(0);
1492  write_bytecounted_string_as_big_endian_unicode(32, "", ' '); // system identifier
1494 
1495  write_block(8, 0);
1497  write_string("%/E");
1498  write_block(29, 0);
1499  write_both_endian_word(1); // volume set size
1500  write_both_endian_word(1); // volume sequence number
1501  write_both_endian_word(2048); // sector size
1504  write_little_endian_dword(0); // second little endian path table
1506  write_big_endian_dword(0); // second big endian path table
1508 
1509  write_bytecounted_string_as_big_endian_unicode(128, volume_label, ' '); // volume set identifier
1510  write_bytecounted_string_as_big_endian_unicode(128, PUBLISHER_ID, ' '); // publisher identifier
1511  write_bytecounted_string_as_big_endian_unicode(128, DATA_PREP_ID, ' '); // data preparer identifier
1512  write_bytecounted_string_as_big_endian_unicode(128, APP_ID, ' '); // application identifier
1513 
1514  write_bytecounted_string_as_big_endian_unicode(37, "", ' '); // copyright file identifier
1515  write_bytecounted_string_as_big_endian_unicode(37, "", ' '); // abstract file identifier
1516  write_bytecounted_string_as_big_endian_unicode(37, "", ' '); // bibliographic file identifier
1517 
1518  write_string(timestring); // volume creation
1519  write_byte(0);
1520  write_string(timestring); // most recent modification
1521  write_byte(0);
1522  write_string("0000000000000000"); // volume expires
1523  write_byte(0);
1524  write_string("0000000000000000"); // volume is effective
1525  write_byte(0);
1526  write_byte(1);
1527  write_byte(0);
1528  fill_sector();
1529  }
1530 
1531  // Volume Descriptor Set Terminator
1532  if (make_bridged_udf)
1533  {
1534  write_string("\377CD001\1");
1535  fill_sector();
1536  }
1537 
1538  // TODO: Add UDF support!
1539 
1540  // Boot Catalog
1541  if (eltorito)
1542  {
1543  boot_catalog_sector = cd.sector;
1544 
1545  // Validation entry header
1548  write_little_endian_word(0); // reserved
1549  write_bytecounted_string(24, MANUFACTURER_ID, 0); // Manufacturer identifier
1550  write_little_endian_word(0x62E); // checksum // FIXME: This is hardcoded!!
1551  write_little_endian_word(0xAA55); // signature
1552 
1553  // Default entry
1557  write_byte(0); // partition type
1558  write_byte(0); // unused
1561  write_block(20, 0); // unused
1562 
1563  // Loop through each boot header
1565  while (header)
1566  {
1567  write_byte(header->header_id);
1568  write_byte(header->platform_id);
1569  write_little_endian_word(header->num_entries);
1570  write_block(28, 0); // Identifier string (unused)
1571 
1572  // Loop through each boot entry
1573  entry = header->entry_list;
1574  while (entry)
1575  {
1576  write_byte(entry->boot_id);
1577  write_byte(entry->boot_emu_type);
1578  write_little_endian_word(entry->load_segment);
1579  write_byte(0); // partition type
1580  write_byte(0); // unused
1581  write_little_endian_word(entry->sector_count);
1582  write_little_endian_dword(entry->load_rba);
1583  write_block(20, 0); // Selection criteria (unused)
1584 
1585  entry = entry->next_entry;
1586  }
1587 
1588  header = header->next_header;
1589  }
1590 
1591  fill_sector();
1592  }
1593 
1594 
1595  // Boot Images
1596  if (eltorito)
1597  {
1598  default_boot_entry.load_rba = cd.sector;
1599 
1601  if (file == NULL)
1602  error_exit("Cannot open '%s'\n", default_boot_entry.bootimage);
1603  fseek(file, 0, SEEK_END);
1604  size = ftell(file);
1605  if (size == 0 || (size % 2048))
1606  {
1607  fclose(file);
1608  error_exit("Invalid boot image size (%lu bytes)\n", size);
1609  }
1610  // Sector count in 512 byte sectors and rounded up
1611  default_boot_entry.sector_count = (size + 511) / 512;
1612  if (!write_from_file(file, size))
1613  {
1614  fclose(file);
1615  error_exit("Read error in file '%s'\n", default_boot_entry.bootimage);
1616  }
1617  fclose(file);
1618 
1619  // Loop through each boot header
1621  while (header)
1622  {
1623  // Loop through each boot entry
1624  entry = header->entry_list;
1625  while (entry)
1626  {
1627  entry->load_rba = cd.sector;
1628 
1629  file = fopen(entry->bootimage, "rb");
1630  if (file == NULL)
1631  error_exit("Cannot open '%s'\n", entry->bootimage);
1632  fseek(file, 0, SEEK_END);
1633  size = ftell(file);
1634  if (size == 0 || (size % 2048))
1635  {
1636  fclose(file);
1637  error_exit("Invalid boot image size (%lu bytes)\n", size);
1638  }
1639  // Sector count in 512 byte sectors and rounded up
1640  entry->sector_count = (size + 511) / 512;
1641  if (!write_from_file(file, size))
1642  {
1643  fclose(file);
1644  error_exit("Read error in file '%s'\n", entry->bootimage);
1645  }
1646  fclose(file);
1647 
1648  entry = entry->next_entry;
1649  }
1650 
1651  header = header->next_header;
1652  }
1653 
1654 // fill_sector();
1655  }
1656 
1657 
1658  // Little Endian Path Table
1659 
1661  write_byte(1);
1662  write_byte(0); // number of sectors in extended attribute record
1665  write_byte(0);
1666  write_byte(0);
1667 
1668  index = 1;
1669  root.path_table_index = 1;
1670  for (d = root.next_in_path_table; d != NULL; d = d->next_in_path_table)
1671  {
1672  name_length = strlen(d->name_on_cd);
1673  write_byte((BYTE)name_length);
1674  write_byte(0); // number of sectors in extended attribute record
1675  write_little_endian_dword(d->sector);
1676  write_little_endian_word(d->parent->path_table_index);
1677  write_string(d->name_on_cd);
1678  if (name_length & 1)
1679  write_byte(0);
1680  d->path_table_index = ++index;
1681  }
1682 
1684  SECTOR_SIZE + cd.offset;
1685  fill_sector();
1686 
1687 
1688  // Big Endian Path Table
1689 
1691  write_byte(1);
1692  write_byte(0); // number of sectors in extended attribute record
1693  write_big_endian_dword(root.sector);
1695  write_byte(0);
1696  write_byte(0);
1697 
1698  for (d = root.next_in_path_table; d != NULL; d = d->next_in_path_table)
1699  {
1700  name_length = strlen(d->name_on_cd);
1701  write_byte((BYTE)name_length);
1702  write_byte(0); // number of sectors in extended attribute record
1703  write_big_endian_dword(d->sector);
1704  write_big_endian_word(d->parent->path_table_index);
1705  write_string(d->name_on_cd);
1706  if (name_length & 1)
1707  write_byte(0);
1708  }
1709  fill_sector();
1710 
1711  if (joliet)
1712  {
1713  // Little Endian Path Table
1714 
1716  write_byte(1);
1717  write_byte(0); // number of sectors in extended attribute record
1718  write_little_endian_dword(root.joliet_sector);
1720  write_byte(0);
1721  write_byte(0);
1722 
1723  for (d = root.next_in_path_table; d != NULL; d = d->next_in_path_table)
1724  {
1725  name_length = strlen(d->joliet_name) * 2;
1726  write_byte((BYTE)name_length);
1727  write_byte(0); // number of sectors in extended attribute record
1728  write_little_endian_dword(d->joliet_sector);
1729  write_little_endian_word(d->parent->path_table_index);
1730  write_string_as_big_endian_unicode(d->joliet_name);
1731  }
1732 
1734  SECTOR_SIZE + cd.offset;
1735  fill_sector();
1736 
1737  // Big Endian Path Table
1738 
1740  write_byte(1);
1741  write_byte(0); // number of sectors in extended attribute record
1742  write_big_endian_dword(root.joliet_sector);
1744  write_byte(0);
1745  write_byte(0);
1746 
1747  for (d = root.next_in_path_table; d != NULL; d = d->next_in_path_table)
1748  {
1749  name_length = strlen(d->joliet_name) * 2;
1750  write_byte((BYTE)name_length);
1751  write_byte(0); // number of sectors in extended attribute record
1752  write_big_endian_dword(d->joliet_sector);
1753  write_big_endian_word(d->parent->path_table_index);
1754  write_string_as_big_endian_unicode(d->joliet_name);
1755  }
1756  fill_sector();
1757  }
1758 
1759  // TODO: Add UDF support!
1760 
1761 #if 0
1762  // Boot Images ??
1763 #endif
1764 
1765  // TODO: Add CRC block for header!
1766 
1767  // Directories and files
1768  for (d = &root; d != NULL; d = d->next_in_path_table)
1769  {
1770  // write directory
1771  d->sector = cd.sector;
1773  write_directory_record(d == &root ? d : d->parent, DOT_DOT_RECORD, FALSE);
1774  for (q = d->first_record; q != NULL; q = q->next_in_directory)
1775  {
1778  FALSE);
1779  }
1780  fill_sector();
1781  d->size = (cd.sector - d->sector) * SECTOR_SIZE;
1782 
1783  // write directory for joliet
1784  if (joliet)
1785  {
1786  d->joliet_sector = cd.sector;
1788  write_directory_record(d == &root ? d : d->parent, DOT_DOT_RECORD, TRUE);
1789  for (q = d->first_record; q != NULL; q = q->next_in_directory)
1790  {
1793  TRUE);
1794  }
1795  fill_sector();
1796  d->joliet_size = (cd.sector - d->joliet_sector) * SECTOR_SIZE;
1797  bytes_in_directories += d->joliet_size;
1798  }
1799 
1801  bytes_in_directories += d->size;
1802 
1803  // write file data
1804  for (q = d->first_record; q != NULL; q = q->next_in_directory)
1805  {
1806  if ((q->flags & DIRECTORY_FLAG) == 0)
1807  {
1808  q->sector = q->joliet_sector = cd.sector;
1809  size = q->size;
1810  if (cd.file == NULL)
1811  {
1812  number_of_sectors = (size + SECTOR_SIZE - 1) / SECTOR_SIZE;
1813  cd.sector += number_of_sectors;
1814  number_of_files++;
1815  bytes_in_files += size;
1817  number_of_sectors * SECTOR_SIZE - size;
1818  }
1819  else
1820  {
1821  const char *file_source;
1822  old_end_source = end_source;
1823  if (!q->orig_name)
1824  {
1826  *end_source = 0;
1827  file_source = source;
1828  }
1829  else
1830  {
1831  file_source = q->orig_name;
1832  }
1833  if (verbosity == VERBOSE)
1834  printf("Writing contents of %s\n", file_source);
1835  file = fopen(file_source, "rb");
1836  if (file == NULL)
1837  error_exit("Cannot open '%s'\n", file_source);
1838  if (!write_from_file(file, size))
1839  {
1840  fclose(file);
1841  error_exit("Read error in file '%s'\n", file_source);
1842  }
1843  fclose(file);
1844  end_source = old_end_source;
1845  fill_sector();
1846  }
1847  }
1848  }
1849  }
1850 
1851  // TODO: Add final CRC block!
1852 
1853  total_sectors = (DWORD)cd.sector;
1854 }
1855 
1856 static char HELP[] =
1857  "\n"
1858  "CDMAKE CD-ROM Premastering Utility\n"
1859  "Copyright (C) 1997 Philip J. Erdelsky\n"
1860  "Copyright (C) 2003-2016 ReactOS Team\n"
1861  "\n\n"
1862  "CDMAKE [-vN] [-p] [-s N] [-m] [-j] [-q] "
1863  // "[-x] "
1864  "[-pN] [-eN] [-b bootimage]\n"
1865  " [-bootdata:N#<defaultBootEntry>#<bootEntry1>#...#<bootEntryN>]\n"
1866  " source volume image\n"
1867  "\n"
1868  "Mandatory options:\n"
1869  " source Specifications of base directory containing all files to be\n"
1870  " written to CD-ROM image. Can be a directory, or a path to a\n"
1871  " file list (in which case the path must start with a '@').\n"
1872  " volume Volume label.\n"
1873  " image Image file or device.\n"
1874  "\n"
1875  "General options:\n"
1876  " -vN Verbosity level. Valid values for 'N' are:\n"
1877  " 0: Quiet mode - display nothing but error messages.\n"
1878  " 1: Normal mode (default).\n"
1879  " 2: Verbose mode - display file information as files are\n"
1880  " scanned and written. Overrides the -p option.\n"
1881  " -p Show progress while writing.\n"
1882  " -s N Abort operation before beginning write if image will be larger\n"
1883  " than N megabytes (i.e. 1024*1024*N bytes).\n"
1884  " -q Only scan the source files; do not create an image.\n"
1885  // " -x Compute and encode the AutoCRC value in the image.\n"
1886  "\n"
1887  "ISO 9660 and Joliet options:\n"
1888  " -m Accept punctuation marks other than underscores in names and\n"
1889  " extensions.\n"
1890  " -j Generate Joliet filename records.\n"
1891  "\n"
1892  // "UDF options:\n"
1893  // " Not implemented yet!\n"
1894  // "\n"
1895  "El-Torito boot options:\n"
1896  " -pN Boot platform ID in hex format (default: 00 for a BIOS system).\n"
1897  " -eN Boot media emulation. Valid values for 'N' are:\n"
1898  " 0 (or nothing): No emulation.\n"
1899  " 1: 1.2 MB diskette.\n"
1900  " 2: 1.44MB diskette.\n"
1901  " 3: 2.88MB diskette.\n"
1902  " 4: Hard disk.\n"
1903  " -b bootimage Create a single-boot El-Torito image.\n"
1904  " -bootdata: Create a multi-boot El-Torito image. This option cannot be\n"
1905  " combined with the -b option.\n"
1906  " Syntax:\n"
1907  " -bootdata:N#<defaultBootEntry>#<bootEntry2>#...#<bootEntryN>\n"
1908  " 'N': number of boot entries following.\n"
1909  " defaultBootEntry: The default boot entry, needed in all cases.\n"
1910  " Used by BIOSes which do not support additional boot entries.\n"
1911  " bootEntryX: Additional boot entries.\n"
1912  " - Do not use spaces.\n"
1913  " - Each multi-boot entry must be delimited with a hash symbol (#).\n"
1914  " - Each option for a boot entry must be delimited with a comma (,).\n"
1915  " - Each boot entry must specify the platform ID.\n";
1916 
1917 /*-----------------------------------------------------------------------------
1918 Program execution starts here.
1919 -----------------------------------------------------------------------------*/
1920 
1921 #if (defined(__GNUC__) || (_MSC_VER < 1900))
1922 char* strtok_s(char *str, const char *delim, char **ctx)
1923 {
1924  if (delim == NULL || ctx == NULL || (str == NULL && *ctx == NULL))
1925  {
1926  return NULL;
1927  }
1928 
1929  if (!str)
1930  str = *ctx;
1931 
1932  while (*str && strchr(delim, *str))
1933  str++;
1934  if (!*str)
1935  {
1936  *ctx = str;
1937  return NULL;
1938  }
1939 
1940  *ctx = str + 1;
1941  while (**ctx && !strchr(delim, **ctx))
1942  (*ctx)++;
1943  if (**ctx)
1944  *(*ctx)++ = '\0';
1945 
1946  return str;
1947 }
1948 #endif
1949 
1950 static void
1952  BYTE boot_emu_type, WORD load_segment,
1953  char* bootimage)
1954 {
1955  boot_entry->boot_id = 0x88; // Bootable entry
1956  boot_entry->boot_emu_type = boot_emu_type; // 0: No emulation, etc...
1957  boot_entry->load_segment = load_segment; // If 0 then use default 0x07C0
1958 
1959  boot_entry->bootimage[0] = '\0';
1960  strncpy(boot_entry->bootimage, bootimage, sizeof(boot_entry->bootimage));
1961  boot_entry->bootimage[sizeof(boot_entry->bootimage)-1] = '\0';
1962 }
1963 
1964 int main(int argc, char **argv)
1965 {
1967  int i;
1968  char *t;
1969 
1970  if (argc < 2)
1971  {
1972  puts(HELP);
1973  return 1;
1974  }
1975 
1976  // Initialize CD-ROM write buffer
1977 
1978  cd.file = NULL;
1979  cd.filespecs[0] = 0;
1980 
1981  cd.buffer = malloc(BUFFER_SIZE);
1982  if (cd.buffer == NULL)
1983  error_exit("Insufficient memory");
1984 
1985  // Initialize root directory
1986 
1987  memset(&root, 0, sizeof(root));
1988  root.level = 1;
1989  root.flags = DIRECTORY_FLAG;
1990  convert_date_and_time(&root.date_and_time, &timestamp);
1991 
1992  // Initialize parameters
1993 
1996  // compute_crc = FALSE;
1997 
1998  verbosity = NORMAL;
1999  show_progress = FALSE;
2000  size_limit = 0;
2002  source[0] = 0;
2003  volume_label[0] = 0;
2004 
2005  // Initialize boot information
2006  eltorito = FALSE;
2007  multi_boot = FALSE;
2008  boot_validation_header.header_id = 1; // Validation header ID
2009  boot_validation_header.platform_id = 0; // x86/64 BIOS system
2011  0, // No emulation
2012  0, // Use default 0x07C0
2013  "");
2017 
2018  // Scan command line arguments
2019 
2020  for (i = 1; i < argc; i++)
2021  {
2022  if (strncmp(argv[i], "-v", 2) == 0)
2023  {
2024  t = argv[i] + 2;
2025  if (*t == 0) // Normal verbosity level.
2026  verbosity = NORMAL;
2027  else // Verbosity level in decimal
2028  verbosity = strtoul(t, NULL, 10);
2029 
2030  // Check for validity
2031  if (verbosity > VERBOSE)
2032  verbosity = NORMAL;
2033 
2034  // Disable by default, unless we are in normal verbosity level.
2035  // If progress is still wanted, use '-p'.
2036  if (verbosity == QUIET || verbosity == VERBOSE)
2037  show_progress = FALSE;
2038  }
2039  else if (strcmp(argv[i], "-p") == 0)
2040  show_progress = TRUE;
2041  else if (strncmp(argv[i], "-s", 2) == 0)
2042  {
2043  t = argv[i] + 2;
2044  if (*t == 0)
2045  {
2046  if (++i < argc)
2047  t = argv[i];
2048  else
2049  error_exit("Missing size limit parameter");
2050  }
2051  // size_limit = strtoul(t, NULL, 10);
2052  while (isdigit(*t))
2053  size_limit = size_limit * 10 + *t++ - '0';
2054  if (size_limit < 1 || size_limit > 800)
2055  error_exit("Invalid size limit");
2056  size_limit <<= 9; // convert megabyte to sector count
2057  }
2058  else if (strcmp(argv[i], "-m") == 0)
2060  else if (strcmp(argv[i], "-j") == 0)
2061  joliet = TRUE;
2062  else if (strncmp(argv[i], "-e", 2) == 0)
2063  {
2064  // Check whether the multi-boot option '-bootdata:' was already set.
2065  // If so, print an error and bail out.
2066  if (eltorito && multi_boot)
2067  error_exit("Single-boot and multi-boot entries cannot be combined");
2068 
2069  eltorito = TRUE;
2070  multi_boot = FALSE;
2071 
2072  t = argv[i] + 2;
2073  if (*t == 0) // No emulation
2075  else // ID in decimal
2077  }
2078  else if (strncmp(argv[i], "-p", 2) == 0)
2079  {
2080  // Check whether the multi-boot option '-bootdata:' was already set.
2081  // If so, print an error and bail out.
2082  if (eltorito && multi_boot)
2083  error_exit("Single-boot and multi-boot entries cannot be combined");
2084 
2085  eltorito = TRUE;
2086  multi_boot = FALSE;
2087 
2088  // Platform ID in hexadecimal
2090  }
2091  else if (strcmp(argv[i], "-b") == 0)
2092  {
2093  // Check whether the multi-boot option '-bootdata:' was already set.
2094  // If so, print an error and bail out.
2095  if (eltorito && multi_boot)
2096  error_exit("Single-boot and multi-boot entries cannot be combined");
2097 
2098  eltorito = TRUE;
2099  multi_boot = FALSE;
2100 
2103  }
2104  else if (strncmp(argv[i], "-bootdata:", sizeof("-bootdata:") - 1) == 0)
2105  {
2106  char *bootdata, *entry_ctx, *option_ctx;
2107  DWORD num_boot_entries = 0;
2108 
2109  BOOL default_entry = TRUE; // Start by setting the default boot entry
2110  PBOOT_HEADER boot_header = NULL; // Current boot header
2111  PBOOT_ENTRY boot_entry = NULL; // The last boot entry in the current boot header
2112  BYTE platform_id, old_platform_id = 0;
2113  BYTE boot_emu_type;
2114  WORD load_segment;
2115  char bootimage[512];
2116 
2117  // Check whether the single-boot option '-b' was already set.
2118  // If so, print an error and bail out.
2119  if (eltorito && !multi_boot)
2120  error_exit("Single-boot and multi-boot entries cannot be combined");
2121 
2122  t = argv[i] + (sizeof("-bootdata:") - 1);
2123  bootdata = strdup(t);
2124  if (bootdata == NULL)
2125  error_exit("Insufficient memory");
2126 
2127  eltorito = TRUE;
2128  multi_boot = TRUE;
2129 
2130  // FIXME: Paths containing '#' or ',' or ' ' are not yet supported!!
2131 
2132  // Start parsing...
2133  t = strtok_s(bootdata, "#", &entry_ctx);
2134  if (t == NULL)
2135  {
2136  free(bootdata);
2137  error_exit("Malformed bootdata command");
2138  }
2139 
2140  num_boot_entries = strtoul(t, NULL, 10);
2141 
2142  while (num_boot_entries--)
2143  {
2144  // Reset to default values
2145  platform_id = 0; // x86/64 BIOS system
2146  boot_emu_type = 0; // No emulation
2147  load_segment = 0; // Use default 0x07C0
2148  bootimage[0] = '\0';
2149 
2150  t = strtok_s(NULL, "#", &entry_ctx);
2151  if (t == NULL)
2152  {
2153  free(bootdata);
2154  error_exit("Malformed bootdata command");
2155  }
2156 
2157  t = strtok_s(t, ",", &option_ctx);
2158  while (t != NULL)
2159  {
2160  switch (*t++)
2161  {
2162  case 'b': // Boot sector file
2163  {
2164  char *q;
2165 
2166  // Searches for any of the valid separators:
2167  // '#' starts a new boot entry;
2168  // ',' starts a new boot option;
2169  // ' ' finishes the bootdata command.
2170  q = strpbrk(t, "#, ");
2171  if (!q) q = t + strlen(t);
2172  strncpy(bootimage, t, q - t + 1);
2173  break;
2174  }
2175 
2176  case 'p': // Platform ID
2177  {
2178  // Platform ID in hexadecimal
2179  platform_id = (BYTE)strtoul(t, NULL, 16);
2180  break;
2181  }
2182 
2183  case 'e': // No floppy-disk emulation
2184  {
2185  if (*t == 0) // No emulation
2186  boot_emu_type = 0;
2187  else // ID in decimal
2188  boot_emu_type = (BYTE)strtoul(t, NULL, 10);
2189 
2190  break;
2191  }
2192 
2193  case 't': // Loading segment
2194  {
2195  if (*t == 0) // Not specified: use default 0x07C0
2196  load_segment = 0;
2197  else // Segment in hexadecimal
2198  load_segment = (BYTE)strtoul(t, NULL, 16);
2199 
2200  break;
2201  }
2202 
2203  default:
2204  free(bootdata);
2205  error_exit("Malformed bootdata command");
2206  }
2207 
2208  t = strtok_s(NULL, ",", &option_ctx);
2209  }
2210 
2211  // Create a new entry and possibly a boot header
2212  if (default_entry)
2213  {
2214  // Initialize the default boot entry and header
2215 
2216  boot_validation_header.header_id = 1; // Validation header ID
2217  boot_validation_header.platform_id = platform_id;
2218 
2219  init_boot_entry(&default_boot_entry, boot_emu_type, load_segment, bootimage);
2220 
2221  // Default entry is now initialized.
2222  default_entry = FALSE;
2223  }
2224  else
2225  {
2226  // Initialize a new boot entry
2227  PBOOT_ENTRY old_boot_entry = boot_entry;
2228 
2229  boot_entry = calloc(1, sizeof(*boot_entry));
2230  if (boot_entry == NULL)
2231  error_exit("Insufficient memory");
2232  // boot_entry->next_entry = NULL;
2233 
2234  init_boot_entry(boot_entry, boot_emu_type, load_segment, bootimage);
2235 
2236  // Create a new boot header if we don't have one yet
2237  if (boot_header == NULL)
2238  {
2239  boot_header = calloc(1, sizeof(*boot_header));
2240  if (boot_header == NULL)
2241  error_exit("Insufficient memory");
2242 
2243  boot_header->header_id = 0x91; // So far this is the last boot header
2244  boot_header->platform_id = platform_id;
2245  // boot_header->next_header = NULL;
2246  // boot_header->num_entries = 0;
2247  // boot_header->entry_list = NULL;
2248 
2249  old_boot_entry = NULL;
2250  old_platform_id = platform_id;
2251 
2253  }
2254  else
2255  {
2256  // Create a new boot header if we change the platform ID
2257  if (old_platform_id != platform_id)
2258  {
2259  PBOOT_HEADER prev_boot_header = boot_header;
2260 
2261  boot_header = calloc(1, sizeof(*boot_header));
2262  if (boot_header == NULL)
2263  error_exit("Insufficient memory");
2264 
2265  boot_header->header_id = 0x91; // So far this is the last boot header
2266  boot_header->platform_id = platform_id;
2267  // boot_header->next_header = NULL;
2268  // boot_header->num_entries = 0;
2269  // boot_header->entry_list = NULL;
2270 
2271  old_boot_entry = NULL;
2272  old_platform_id = platform_id;
2273 
2274  // Link into the header list
2275  prev_boot_header->header_id = 0x90; // The previous boot header was not the last one
2276  prev_boot_header->next_header = boot_header;
2277  }
2278  }
2279 
2280  // Add the entry into the header
2282  if (old_boot_entry == NULL)
2284  else
2285  old_boot_entry->next_entry = boot_entry;
2286  }
2287  }
2288 
2289  free(bootdata);
2290  }
2291  else if (strcmp(argv[i], "-q") == 0)
2293  // else if (strcmp(argv[i], "-x") == 0)
2294  // compute_crc = TRUE;
2295  else if (i + 2 < argc)
2296  {
2297  strcpy(source, argv[i++]);
2298  strncpy(volume_label, argv[i++], sizeof(volume_label) - 1);
2299  strcpy(cd.filespecs, argv[i]);
2300  }
2301  else
2302  error_exit("Missing command line argument");
2303  }
2304 
2305  if (source[0] == 0)
2306  error_exit("Missing source directory");
2307  if (volume_label[0] == 0)
2308  error_exit("Missing volume label");
2309  if (cd.filespecs[0] == 0)
2310  error_exit("Missing image file specifications");
2311 
2312  if (source[0] != '@')
2313  {
2314  /* set source[] and end_source to source directory,
2315  * with a terminating directory separator */
2317  if (end_source[-1] == ':')
2318  *end_source++ = '.';
2319  if (end_source[-1] != DIR_SEPARATOR_CHAR)
2321 
2322  /* scan all files and create directory structure in memory */
2324  }
2325  else
2326  {
2327  char *trimmedline, *targetname, *normdir, *srcname, *eq;
2328  char lineread[1024];
2329 
2330  FILE *f = fopen(source+1, "r");
2331  if (!f)
2332  {
2333  error_exit("Cannot open CD-ROM file description '%s'\n", source+1);
2334  }
2335  while (fgets(lineread, sizeof(lineread), f))
2336  {
2337  /* We treat these characters as line endings */
2338  trimmedline = strtok(lineread, "\t\r\n;");
2339  eq = strchr(trimmedline, '=');
2340  if (!eq)
2341  {
2342  /* Treat this as a directory name */
2343  targetname = trimmedline;
2344  normdir = strdup(targetname);
2345  normalize_dirname(normdir);
2346  dir_hash_create_dir(&specified_files, targetname, normdir);
2347  free(normdir);
2348  }
2349  else
2350  {
2351  targetname = strtok(lineread, "=");
2352  srcname = strtok(NULL, "");
2353 
2354 #ifdef _WIN32
2355  if (_access(srcname, R_OK) == 0)
2356 #else
2357  if (access(srcname, R_OK) == 0)
2358 #endif
2359  {
2360  if (!dir_hash_add_file(&specified_files, srcname, targetname))
2361  error_exit("Target '%s' (file '%s') is invalid\n", targetname, srcname);
2362  }
2363  else
2364  error_exit("Cannot access file '%s' (target '%s')\n", srcname, targetname);
2365  }
2366  }
2367  fclose(f);
2368 
2369  /* scan all files and create directory structure in memory */
2371  }
2372 
2373  /* sort path table entries */
2374  root.next_in_path_table = sort_linked_list(root.next_in_path_table,
2375  1,
2377 
2378  // initialize CD-ROM write buffer
2379 
2380  cd.file = NULL;
2381  cd.sector = 0;
2382  cd.offset = 0;
2383  cd.count = 0;
2384 
2385  // make non-writing pass over directory structure to obtain the proper
2386  // sector numbers and offsets and to determine the size of the image
2387 
2390  pass();
2391 
2392  if (verbosity >= NORMAL)
2393  {
2394  printf("%s bytes ", edit_with_commas(bytes_in_files, TRUE));
2395  printf("in %s files\n", edit_with_commas(number_of_files, FALSE));
2396  printf("%s unused bytes at ends of files\n",
2399  printf("in %s directories\n",
2401  printf("%s other bytes\n", edit_with_commas(root.sector * SECTOR_SIZE, TRUE));
2402  puts("-------------");
2403  printf("%s total bytes\n",
2405  puts("=============");
2406  }
2407 
2408  if (size_limit != 0 && total_sectors > size_limit)
2409  error_exit("Size limit exceeded");
2410 
2411  if (!scan_files_only)
2412  {
2413  // re-initialize CD-ROM write buffer
2414 
2415  cd.file = fopen(cd.filespecs, "w+b");
2416  if (cd.file == NULL)
2417  error_exit("Cannot open image file '%s'", cd.filespecs);
2418  cd.sector = 0;
2419  cd.offset = 0;
2420  cd.count = 0;
2421 
2422 
2423  // make writing pass over directory structure
2424 
2425  pass();
2426 
2427  if (cd.count > 0)
2428  flush_buffer();
2429  if (show_progress)
2430  printf("\r \n");
2431  if (fclose(cd.file) != 0)
2432  {
2433  cd.file = NULL;
2434  error_exit("File write error in image file '%s'", cd.filespecs);
2435  }
2436 
2437  if (verbosity >= NORMAL)
2438  puts("CD-ROM image made successfully");
2439  }
2440 
2442  release_memory();
2443  return 0;
2444 }
2445 
2446 /* EOF */
BYTE hour
Definition: cdmake.c:138
unsigned short WORD
Definition: cdmake.c:77
#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:620
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:407
#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:354
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:431
#define BUFFER_SIZE
Definition: cdmake.c:89
WORD wMonth
Definition: winbase.h:884
static void write_both_endian_dword(DWORD x)
Definition: cdmake.c:408
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:1345
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:400
static char HELP[]
Definition: cdmake.c:1856
struct boot_entry * next_entry
Definition: cdmake.c:113
static BOOL cdname_exists(PDIR_RECORD d)
Definition: cdmake.c:656
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:10
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:1412
const char * strerror(int err)
Definition: compat_str.c:23
#define eq(received, expected, label, type)
Definition: locale.c:144
enum @1516 verbosity
static HWND child
Definition: cursoricon.c:298
#define DECLSPEC_NORETURN
Definition: ntbasedef.h:176
char * strtok_s(char *str, const char *delim, char **ctx)
Definition: cdmake.c:1922
struct boot_header * PBOOT_HEADER
#define FILE_SHARE_READ
Definition: compat.h:125
unsigned char BYTE
Definition: cdmake.c:76
Definition: cdmake.c:189
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:500
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:336
WORD wYear
Definition: winbase.h:883
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:374
#define va_end(ap)
Definition: acmsvcex.h:90
static void write_little_endian_dword(DWORD x)
Definition: cdmake.c:392
static PDIR_RECORD new_empty_dirrecord(PDIR_RECORD d, BOOL directory)
Definition: cdmake.c:1185
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:888
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:670
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:435
struct boot_entry BOOT_ENTRY
static int check_for_punctuation(int c, const char *name)
Definition: cdmake.c:640
static void write_big_endian_dword(DWORD x)
Definition: cdmake.c:400
char bootimage[512]
Definition: cdmake.c:121
_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
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:188
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
static DECLSPEC_NORETURN void error_exit(const char *fmt,...)
Definition: cdmake.c:317
_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:2944
_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
char * name
Definition: compiler.c:66
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:836
PDIR_RECORD new_directory_record(struct dirent *entry, struct stat *stbuf, PDIR_RECORD parent)
Definition: cdmake.c:799
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:889
#define GetFileSizeEx
Definition: compat.h:423
static void init_boot_entry(PBOOT_ENTRY boot_entry, BYTE boot_emu_type, WORD load_segment, char *bootimage)
Definition: cdmake.c:1951
static void write_big_endian_word(WORD x)
Definition: cdmake.c:380
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
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
GLdouble s
Definition: gl.h:2039
static void write_block(unsigned count, BYTE value)
Definition: cdmake.c:487
#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
unsigned char BYTE
Definition: xxhash.c:193
_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:868
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:886
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)
Definition: cdmake.c:189
_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:464
static void write_both_endian_word(WORD x)
Definition: cdmake.c:386
static BOOL write_from_file(FILE *file, DWORD size)
Definition: cdmake.c:1379
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:887
static void write_directory_record(PDIR_RECORD d, DIR_RECORD_TYPE DirType, BOOL joliet)
Definition: cdmake.c:514
static void fill_sector(void)
Definition: cdmake.c:420
#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:38
#define calloc
Definition: rosglue.h:14
DWORD sector
Definition: cdmake.c:159
int main(int argc, char **argv)
Definition: cdmake.c:1964
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:1230
#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:408
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
unsigned long DWORD
Definition: cdmake.c:78
static void get_time_string(char *str)
Definition: cdmake.c:1368
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:967
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:850
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:437
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:101
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:456
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