home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 5 / FreshFish_July-August1994.bin / bbs / disk / mkisofs-1.00.5.lha / mkisofs / mkisofs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-23  |  11.7 KB  |  524 lines

  1. /*
  2.  * Program mkisofs.c - generate iso9660 filesystem  based upon directory
  3.  * tree on hard disk.
  4.  
  5.    Written by Eric Youngdale (1993).
  6.  
  7.    Copyright 1993 Yggdrasil Computing, Incorporated
  8.  
  9.    This program is free software; you can redistribute it and/or modify
  10.    it under the terms of the GNU General Public License as published by
  11.    the Free Software Foundation; either version 2, or (at your option)
  12.    any later version.
  13.  
  14.    This program is distributed in the hope that it will be useful,
  15.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.    GNU General Public License for more details.
  18.  
  19.    You should have received a copy of the GNU General Public License
  20.    along with this program; if not, write to the Free Software
  21.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  22.  
  23. #include "mkisofs.h"
  24.  
  25. #ifdef linux
  26. #include <getopt.h>
  27. #endif
  28.  
  29. #include "iso9660.h"
  30. #include <ctype.h>
  31. #include <time.h>
  32. #include <stdlib.h>
  33. #ifndef AMIGA
  34. #include <sys/stat.h>
  35. #endif
  36.  
  37. #ifndef VMS
  38. #ifndef AMIGA
  39. #include <unistd.h>
  40. #endif
  41. #endif
  42.  
  43. #ifdef AMIGA
  44. #ifdef LATTICE
  45. #include <proto/exec.h>
  46. #include <proto/utility.h>
  47. #endif
  48. #if defined(__GNUC__) || defined(AZTEC_C)
  49. #include <clib/exec_protos.h>
  50. #include <clib/utility_protos.h>
  51. #endif
  52. #endif
  53.  
  54. struct Library *UtilityBase = NULL;
  55.  
  56. #include "exclude.h"
  57.  
  58. struct directory * root = NULL;
  59.  
  60. static char version_string[] = "$VER: mkisofs-1.00-Amiga 1.5 (23.06.94)";
  61.  
  62. FILE * discimage;
  63. unsigned int next_extent = 0;
  64. unsigned int last_extent = 0;
  65. unsigned int path_table_size = 0;
  66. unsigned int path_table[4] = {0,};
  67. unsigned int path_blocks = 0;
  68. struct iso_directory_record root_record;
  69. int use_RockRidge = 0;
  70. int verbose = 0;
  71. int all_files  = 0;
  72. int follow_links = 0;
  73. int generate_tables = 0;
  74. static int timezone_offset;
  75. char * extension_record = NULL;
  76. int extension_record_extent = 0;
  77. static  int extension_record_size = 0;
  78. int cdtv_trademark_file = 0;
  79.  
  80. int convert_filenames = 1;
  81. int inhibit_relocation = 0;
  82. int sort_extents = 0;
  83. int progress_indicator = 1;
  84. int short_filenames = 1;
  85. int map_filenames = 1;
  86. int preallocate = 0;
  87.  
  88. char * preparer = NULL;
  89. char * publisher = NULL;
  90. char * system_identifier = NULL;
  91.  
  92.  
  93. char * path_table_l = NULL;
  94. char * path_table_m = NULL;
  95. int goof = 0;
  96.  
  97. void usage(void){
  98.   fprintf(stderr,
  99.     "Usage:\n"
  100.     "mkisofs [-RvaTcres12AB] [-o outfile] [-V volid] [-p preparer]\n"
  101.     "        [-P publisher] [-S systemid] [-D path -D path ...]\n"
  102.     "        [-x path -x path ...] [--cdtv] path\n"
  103.     );
  104.   exit(1);
  105. }
  106.  
  107. int get_iso9660_timezone_offset(void){
  108. #ifdef AMIGA
  109.   return 0;
  110. #else
  111.   struct tm gm;
  112.   struct tm * pt;
  113.   time_t ctime;
  114.   int local_min, gmt_min;
  115.  
  116.   time(&ctime);
  117.   pt = gmtime(&ctime);
  118.   gm = *pt;
  119.   pt = localtime(&ctime);
  120.  
  121.   if(gm.tm_year < pt->tm_year)
  122.     gm.tm_yday = -1;
  123.  
  124.   if(gm.tm_year > pt->tm_year)
  125.     pt->tm_yday = -1;
  126.  
  127.   gmt_min = gm.tm_min + 60*(gm.tm_hour + 24*gm.tm_yday);
  128.   local_min = pt->tm_min + 60*(pt->tm_hour + 24*pt->tm_yday);
  129.   return (gmt_min - local_min)/15;
  130. #endif
  131. }
  132.  
  133.  
  134. /* Fill in date in the iso9660 format */
  135. int FDECL2(iso9660_date,char *, result, time_t, ctime){
  136.   struct tm *local;
  137. #ifdef AMIGA
  138.   local = gmtime(&ctime);
  139. #else
  140.   local = localtime(&ctime);
  141. #endif
  142.   result[0] = local->tm_year;
  143.   result[1] = local->tm_mon + 1;
  144.   result[2] = local->tm_mday;
  145.   result[3] = local->tm_hour;
  146.   result[4] = local->tm_min;
  147.   result[5] = local->tm_sec;
  148.   result[6] = timezone_offset;
  149.   return 0;
  150. }
  151.  
  152. int FDECL3(iso9660_file_length,const char*, name, struct directory_entry *, sresult, 
  153.             int, dirflag){
  154.   char buf[33];
  155.   char *result = buf;
  156.   const char * pnt;
  157. #if 0
  158.   int seen_dot = 0;
  159.   int priority = 32767;
  160.   int tildes = 0;
  161.   int ignore = 0;
  162.   int extra = 0;
  163.   int chars_after_dot = 0;
  164.   int chars_before_dot = 0;
  165. #endif
  166.  
  167.   if(strcmp(name,".") == 0){
  168.     sresult->isorec.iso_name = "";
  169.     return 1;
  170.   };
  171.  
  172.   if(strcmp(name,"..") == 0){
  173.     sresult->isorec.iso_name = "\1";
  174.     return 1;
  175.   };
  176.  
  177.   if (!convert_filenames) {
  178.     int i;
  179.     for (pnt=name, i=0; *pnt && i < 30; i++)
  180.       *result++ = *pnt++;
  181.     if (!dirflag) {
  182.       *result++ = ';';
  183.       *result++ = '1';
  184.     }
  185.     *result++ = 0;
  186.     sresult->isorec.iso_name = strdup_forever (buf);
  187.     return i+(dirflag?0:2);
  188.   }
  189.  
  190.   sresult->isorec.iso_name =
  191.     strdup_forever (dirflag ? convert_dirname (name) :
  192.                     convert_filename (name));
  193.   sresult->priority = 32767;
  194.   return (int) strlen (sresult->isorec.iso_name);
  195.  
  196. #if 0
  197.  
  198.   pnt = name;
  199.   while(*pnt){
  200.     if(*pnt == '#') {priority = 1; pnt++; continue; };
  201.     if(*pnt == '~') {priority = 1; tildes++; pnt++; continue;};
  202.     if(ignore) {pnt++; continue;};
  203.     if(*pnt == '.') {
  204.       if (seen_dot) {ignore++; continue;}
  205.       *result++ = '.';
  206.       seen_dot++;
  207.     } else if (seen_dot) {
  208.       if(chars_after_dot < 3) {
  209.     chars_after_dot++;
  210.     *result++ = toupper(*pnt);
  211.       }
  212.     } else {
  213.       if(chars_before_dot < 8) {
  214.     chars_before_dot++;
  215.     *result++ = toupper(*pnt);
  216.       };
  217.     };
  218.     pnt++;
  219.   };
  220.   
  221.   if(tildes == 2){
  222.     int prio1 = 0;
  223.     pnt = name;
  224.     while (*pnt && *pnt != '~') pnt++;
  225.     if (*pnt) pnt++;
  226.     while(*pnt && *pnt != '~'){
  227.       prio1 = 10*prio1 + *pnt - '0';
  228.       pnt++;
  229.     };
  230.     priority = prio1;
  231.   };
  232.     
  233.   if (!dirflag){
  234.     if (!seen_dot) {
  235.       *result++ = '.'; 
  236.       extra++;
  237.     };
  238.     *result++ = ';';
  239.     *result++ = '1';
  240.     extra += 2;
  241.   };
  242.             
  243.   *result++ = 0;
  244.   sresult->priority = priority;
  245.   sresult->isorec.iso_name = strdup_forever (buf);
  246.   return chars_before_dot + chars_after_dot + seen_dot + extra;
  247. #endif
  248. }
  249.  
  250. #ifdef AMIGA
  251. static void Cleanup (void)
  252. {
  253.   if (UtilityBase)
  254.     CloseLibrary (UtilityBase);
  255. }
  256. #endif
  257.  
  258. int FDECL2(main, int, argc, char **, argv){
  259.   char * outfile, *volid;
  260.   struct directory_entry de;
  261. #ifndef AMIGA
  262.   unsigned int mem_start;
  263.   struct stat statbuf;
  264. #endif
  265.   char * scan_tree;
  266.   int c;
  267.   char * trademark_filename;
  268.  
  269.   if (argc < 2)
  270.     usage();
  271.  
  272. #ifdef AMIGA
  273.   UtilityBase = OpenLibrary ((UBYTE*) "utility.library", 0);
  274.   if (!UtilityBase) {
  275.     fprintf (stderr, "cannot open utility.library!\n");
  276.     exit (10);
  277.   }
  278.   atexit (Cleanup);
  279. #endif
  280.  
  281.   outfile = NULL;
  282.   volid = "CDROM";
  283.   while ((c = getopt(argc, argv, "acefo:p:rsvx:ABCD:P:RS:TV:-:12")) != EOF)
  284.                                  
  285.     switch (c)
  286.       {
  287.       case '-':
  288.         if (strcmp (optarg, "cdtv") == 0) {
  289.       convert_filenames = 0;
  290.       cdtv_trademark_file = 1;
  291.       inhibit_relocation = 1;
  292.       system_identifier = "CDTV";
  293.       all_files++;
  294.     } else {
  295.       fprintf (stderr, "unknown option --%s\n", optarg);
  296.       exit (1);
  297.     }
  298.     break;
  299.       case 'c':
  300.         convert_filenames = 0;
  301.         break;
  302.       case 'C':
  303.         cdtv_trademark_file = 1;
  304.         break;
  305.       case 'D':
  306.         convert_filenames = 0;
  307.     include_conv (optarg);
  308.         break;
  309.       case 'r':
  310.         inhibit_relocation = 1;
  311.     break;
  312.       case 'e':
  313.         sort_extents = 1;
  314.         break;
  315.       case 's':
  316.         preallocate = 1;
  317.         break;
  318.       case 'p':
  319.     preparer = optarg;
  320.     if(strlen(preparer) > 128) {
  321.         fprintf(stderr,"Preparer string too long\n");
  322.         exit(1);
  323.     };
  324.     break;
  325.       case 'P':
  326.     publisher = optarg;
  327.     if(strlen(publisher) > 128) {
  328.         fprintf(stderr,"Publisher string too long\n");
  329.         exit(1);
  330.     };
  331.     break;
  332.       case 'S':
  333.         system_identifier = optarg;
  334.     if(strlen(system_identifier) > 32) {
  335.         fprintf(stderr,"System identifier string too long\n");
  336.         exit (1);
  337.     }
  338.     break;
  339.       case 'o':
  340.     outfile = optarg;
  341.     break;
  342.       case 'f':
  343.     follow_links++;
  344.     break;
  345.       case 'R':
  346.     use_RockRidge++;
  347.     break;
  348.       case 'V':
  349. #ifdef AMIGA
  350.     if (strlen (optarg) > 30) {
  351.       fprintf (stderr, "volume name too long (max. 30 characters)\n");
  352.       exit (1);
  353.     }
  354. #endif
  355.     volid = optarg;
  356.     break;
  357.       case 'v':
  358.     verbose++;
  359.     progress_indicator=0;
  360.     break;
  361.       case 'a':
  362.     all_files++;
  363.     break;
  364.       case 'T':
  365.     generate_tables++;
  366.     break;
  367.       case 'x':
  368.         exclude(optarg);
  369.     break;
  370.       case '1':
  371.         short_filenames = 1;
  372.     break;
  373.       case '2':
  374.         short_filenames = 0;
  375.     break;
  376.       case 'A':
  377.         map_filenames = 1;
  378.     break;
  379.       case 'B':
  380.         map_filenames = 0;
  381.     break;
  382.       default:
  383.     usage();
  384.     exit(1);
  385.       }
  386.  
  387. #ifndef AMIGA
  388.   mem_start = (unsigned int) sbrk(0);
  389. #endif
  390.  
  391.   if (volid && convert_filenames && map_filenames &&
  392.       strspn (volid, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_") !=
  393.       strlen (volid))
  394.     fprintf (stderr, "WARNING: volume id contains illegal characters!\n");
  395.  
  396.   if(verbose) fprintf(stderr,"%s\n", version_string + 6);
  397.   /* Now find the timezone offset */
  398.  
  399.   timezone_offset = get_iso9660_timezone_offset();
  400.  
  401.   /*  The first step is to scan the directory tree, and take some notes */
  402.  
  403.   scan_tree = argv[optind];
  404.  
  405.   if(!scan_tree){
  406.       usage();
  407.       exit(1);
  408.   }
  409.  
  410.   if(scan_tree[strlen(scan_tree)-1] != '/'
  411. #ifdef AMIGA
  412.      && scan_tree[strlen(scan_tree)-1] != ':'
  413. #endif
  414.     ) {
  415.     scan_tree = (char *) malloc(strlen(argv[optind])+2);
  416.     strcpy(scan_tree, argv[optind]);
  417.     strcat(scan_tree, "/");
  418.   }
  419.  
  420.   /* Test if trademark file is present: */
  421.   if (cdtv_trademark_file) {
  422.     struct stat sbuf;
  423.     trademark_filename = (char *) malloc (strlen (scan_tree) + 10);
  424.     strcpy (trademark_filename, scan_tree);
  425.     strcat (trademark_filename, "cdtv.tm");
  426.     if (stat (trademark_filename, &sbuf) == -1) {
  427.       fprintf (stderr, "ERROR: file %s missing\n", trademark_filename);
  428.       exit (1);
  429.     }
  430.     free (trademark_filename);
  431.   }
  432.  
  433.   if(use_RockRidge){
  434.     extension_record = generate_rr_extension_record("RRIP_1991A",
  435.                        "THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS",
  436.                        "PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE.  SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR CONTACT INFORMATION.", &extension_record_size);
  437.   }
  438.  
  439. #ifndef AMIGA
  440.   stat(argv[optind], &statbuf);
  441.   add_directory_hash(statbuf.st_dev, statbuf.st_ino);
  442. #endif
  443.  
  444.   de.filedir = root;  /* We need this to bootstrap */
  445.   if (!scan_directory_tree(argv[optind], &de))
  446.     exit (1);
  447.   if (progress_indicator)
  448.     putchar ('\n');
  449.   root->self = root->contents;  /* Fix this up so that the path tables get done right */
  450.  
  451.   if(reloc_dir) sort_n_finish(reloc_dir);
  452.  
  453.   if (goof) exit(1);
  454.   
  455.   if (outfile){
  456.       discimage = fopen(outfile, "w");
  457.       if (!discimage){
  458.           fprintf(stderr,"Unable to open disc image file\n");
  459.           exit(1);
  460.  
  461.       }
  462.   } else
  463.       discimage =  stdout;
  464.  
  465.   /* Now assign addresses on the disc for the path table. */
  466.  
  467.   path_blocks = (path_table_size + (SECTOR_SIZE - 1)) >> 11;
  468.   if (path_blocks & 1) path_blocks++;
  469.   path_table[0] = 0x14;
  470.   path_table[1] = path_table[0] + path_blocks;
  471.   path_table[2] = path_table[1] + path_blocks;
  472.   path_table[3] = path_table[2] + path_blocks;
  473.  
  474.   last_extent = path_table[3] + path_blocks;  /* The next free block */
  475.  
  476.   /* The next step is to go through the directory tree and assign extent
  477.      numbers for all of the directories */
  478.  
  479.   if (verbose)
  480.     printf ("assigning directory addresses\n");
  481.  
  482.   assign_directory_addresses(root);
  483.  
  484.   if (progress_indicator)
  485.     putchar ('\n');
  486.  
  487.   if(extension_record) {
  488.       struct directory_entry * s_entry;
  489.       extension_record_extent = last_extent++;
  490.       s_entry = root->contents;
  491.       set_733(s_entry->rr_attributes + s_entry->rr_attr_size - 24,
  492.           extension_record_extent);
  493.       set_733(s_entry->rr_attributes + s_entry->rr_attr_size - 8,
  494.           extension_record_size);
  495.   };
  496.  
  497.   if (use_RockRidge && reloc_dir)
  498.       finish_cl_pl_entries();
  499.  
  500.   if (verbose)
  501.     printf ("generating path tables\n");
  502.  
  503.   /* Now we generate the path tables that are used by DOS to improve directory
  504.      access times. */
  505.   generate_path_tables();
  506.  
  507.   /* Generate root record for volume descriptor. */
  508.   generate_root_record();
  509.  
  510.   if (verbose)
  511.     dump_tree(root);
  512.  
  513.   iso_write(discimage, volid);
  514.  
  515. #ifndef AMIGA
  516.   fprintf(stderr,"Max brk space used %x\n", 
  517.       ((unsigned int)sbrk(0)) - mem_start);
  518. #endif
  519.   fprintf(stderr,"%d extents written (%d Mb)\n", last_extent, last_extent >> 9);
  520.  
  521.   return 0;
  522. }
  523.  
  524.