home *** CD-ROM | disk | FTP | other *** search
/ Dream 49 / Amiga_Dream_49.iso / beos / utils / mkisofs-1.000 / mkisofs-1.11-beos / mkisofs.c < prev    next >
C/C++ Source or Header  |  1997-04-09  |  16KB  |  661 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. static char rcsid[] ="$Id: mkisofs.c,v 1.9 1997/04/10 02:45:09 eric Rel $";
  24.  
  25. /* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */
  26.  
  27. #include <errno.h>
  28. #include "mkisofs.h"
  29. #include "config.h"
  30.  
  31. #ifdef linux
  32. #include <getopt.h>
  33. #endif
  34.  
  35. #include "iso9660.h"
  36. #include <ctype.h>
  37.  
  38. #ifndef VMS
  39. #include <time.h>
  40. #else
  41. #include <sys/time.h>
  42. #include "vms.h"
  43. #endif
  44.  
  45. #include <stdlib.h>
  46. #include <sys/stat.h>
  47.  
  48. #ifndef VMS
  49. #ifdef HAVE_UNISTD_H
  50. #include <unistd.h>
  51. #endif
  52. #endif
  53.  
  54. #include "exclude.h"
  55.  
  56. #ifdef __NetBSD__
  57. #include <sys/time.h>
  58. #include <sys/resource.h>
  59. #endif
  60.  
  61. struct directory * root = NULL;
  62.  
  63. static char version_string[] = "mkisofs v1.11";
  64.  
  65. FILE * discimage;
  66. unsigned int next_extent = 0;
  67. unsigned int last_extent = 0;
  68. unsigned int session_start = 0;
  69. unsigned int path_table_size = 0;
  70. unsigned int path_table[4] = {0,};
  71. unsigned int path_blocks = 0;
  72. struct iso_directory_record root_record;
  73. char * extension_record = NULL;
  74. int extension_record_extent = 0;
  75. static  int extension_record_size = 0;
  76.  
  77. /* These variables are associated with command line options */
  78. int use_eltorito = 0;
  79. int use_RockRidge = 0;
  80. int verbose = 0;
  81. int all_files  = 0;
  82. int follow_links = 0;
  83. int rationalize = 0;
  84. int generate_tables = 0;
  85. char * preparer = PREPARER_DEFAULT;
  86. char * publisher = PUBLISHER_DEFAULT;
  87. char * appid = APPID_DEFAULT;
  88. char * copyright = COPYRIGHT_DEFAULT;
  89. char * biblio = BIBLIO_DEFAULT;
  90. char * abstract = ABSTRACT_DEFAULT;
  91. char * volset_id = VOLSET_ID_DEFAULT;
  92. char * volume_id = VOLUME_ID_DEFAULT;
  93. char * system_id = SYSTEM_ID_DEFAULT;
  94. char * boot_catalog = BOOT_CATALOG_DEFAULT;
  95. char * boot_image = BOOT_IMAGE_DEFAULT;
  96.  
  97. int omit_period = 0;             /* Violates iso9660, but these are a pain */
  98. int transparent_compression = 0; /* So far only works with linux */
  99. int omit_version_number = 0;     /* May violate iso9660, but noone uses vers*/
  100. int RR_relocation_depth = 6;     /* Violates iso9660, but most systems work */
  101. int full_iso9660_filenames = 0;  /* Used with Amiga.  Disc will not work with
  102.                   DOS */
  103. int allow_leading_dots = 0;     /* DOS cannot read names with leading dots */
  104.  
  105. struct rcopts{
  106.   char * tag;
  107.   char ** variable;
  108. };
  109.  
  110. struct rcopts rcopt[] = {
  111.   {"PREP", &preparer},
  112.   {"PUBL", &publisher},
  113.   {"APPI", &appid},
  114.   {"COPY", ©right},
  115.   {"BIBL", &biblio},
  116.   {"ABST", &abstract},
  117.   {"VOLS", &volset_id},
  118.   {"VOLI", &volume_id},
  119.   {"SYSI", &system_id},
  120.   {NULL, NULL}
  121. };
  122.  
  123. #if defined(ultrix) || defined(_AUX_SOURCE)
  124. char *strdup(s)
  125. char *s;{char *c;if(c=(char *)malloc(strlen(s)+1))strcpy(c,s);return c;}
  126. #endif
  127.  
  128. void FDECL1(read_rcfile, char *, appname)
  129. {
  130.   FILE * rcfile;
  131.   struct rcopts * rco;
  132.   char * pnt, *pnt1;
  133.   char linebuffer[256];
  134.   static char rcfn[] = ".mkisofsrc";
  135.   char filename[1000];
  136.   int linum;
  137.  
  138.   strcpy(filename, rcfn);
  139.   rcfile = fopen(filename, "r");
  140.   if (!rcfile && errno != ENOENT)
  141.     perror(filename);
  142.  
  143.   if (!rcfile)
  144.     {
  145.       pnt = getenv("MKISOFSRC");
  146.       if (pnt && strlen(pnt) <= sizeof(filename))
  147.     {
  148.       strcpy(filename, pnt);
  149.       rcfile = fopen(filename, "r");
  150.       if (!rcfile && errno != ENOENT)
  151.         perror(filename);
  152.     }
  153.     }
  154.  
  155.   if (!rcfile)
  156.     {
  157.       pnt = getenv("HOME");
  158.       if (pnt && strlen(pnt) + strlen(rcfn) + 2 <= sizeof(filename))
  159.     {
  160.       strcpy(filename, pnt);
  161.       strcat(filename, "/");
  162.       strcat(filename, rcfn);
  163.       rcfile = fopen(filename, "r");
  164.       if (!rcfile && errno != ENOENT)
  165.         perror(filename);
  166.     }
  167.     }
  168.   if (!rcfile && strlen(appname)+sizeof(rcfn)+2 <= sizeof(filename))
  169.     {
  170.       strcpy(filename, appname);
  171.       pnt = strrchr(filename, '/');
  172.       if (pnt)
  173.     {
  174.       strcpy(pnt + 1, rcfn);
  175.       rcfile = fopen(filename, "r");
  176.       if (!rcfile && errno != ENOENT)
  177.         perror(filename);
  178.     }
  179.     }
  180.   if (!rcfile)
  181.     return;
  182.   fprintf(stderr, "Using \"%s\"\n", filename);
  183.   /* OK, we got it.  Now read in the lines and parse them */
  184.   linum = 0;
  185.   while (fgets(linebuffer, sizeof(linebuffer), rcfile))
  186.     {
  187.       char *name;
  188.       char *name_end;
  189.       ++linum;
  190.       /* skip any leading white space */
  191.     pnt = linebuffer;
  192.       while (*pnt == ' ' || *pnt == '\t')
  193.     ++pnt;
  194.       /* If we are looking at a # character, this line is a comment. */
  195.     if (*pnt == '#')
  196.       continue;
  197.       /* The name should begin in the left margin.  Make sure it is in
  198.      upper case.  Stop when we see white space or a comment. */
  199.     name = pnt;
  200.       while (*pnt && isalpha(*pnt))
  201.     {
  202.       if(islower(*pnt))
  203.         *pnt = toupper(*pnt);
  204.       pnt++;
  205.     }
  206.       if (name == pnt)
  207.     {
  208.       fprintf(stderr, "%s:%d: name required\n", filename, linum);
  209.       continue;
  210.     }
  211.       name_end = pnt;
  212.       /* Skip past white space after the name */
  213.       while (*pnt == ' ' || *pnt == '\t')
  214.     pnt++;
  215.       /* silently ignore errors in the rc file. */
  216.       if (*pnt != '=')
  217.     {
  218.       fprintf(stderr, "%s:%d: equals sign required\n", filename, linum);
  219.       continue;
  220.     }
  221.       /* Skip pas the = sign, and any white space following it */
  222.       pnt++; /* Skip past '=' sign */
  223.       while (*pnt == ' ' || *pnt == '\t')
  224.     pnt++;
  225.  
  226.       /* now it is safe to NUL terminate the name */
  227.  
  228.     *name_end = 0;
  229.  
  230.       /* Now get rid of trailing newline */
  231.  
  232.       pnt1 = pnt;
  233.       while (*pnt1)
  234.     {
  235.       if (*pnt1 == '\n')
  236.         {
  237.           *pnt1 = 0;
  238.           break;
  239.         }
  240.       pnt1++;
  241.     };
  242.       /* OK, now figure out which option we have */
  243.       for(rco = rcopt; rco->tag; rco++) {
  244.     if(strcmp(rco->tag, name) == 0)
  245.       {
  246.         *rco->variable = strdup(pnt);
  247.         break;
  248.       };
  249.       }
  250.       if (rco->tag == NULL)
  251.     {
  252.       fprintf(stderr, "%s:%d: field name \"%s\" unknown\n", filename, linum,
  253.           name);
  254.     }
  255.      }
  256.   if (ferror(rcfile))
  257.     perror(filename);
  258.   fclose(rcfile);
  259. }
  260.  
  261. char * path_table_l = NULL;
  262. char * path_table_m = NULL;
  263. int goof = 0;
  264.  
  265. void usage(){
  266.     fprintf(stderr,"Usage:\n");
  267.     fprintf(stderr,
  268. "mkisofs [-o outfile] [-R] [-V volid] [-v] [-a] \
  269. [-T]\n [-l] [-d] [-V] [-D] [-L] [-p preparer]"
  270. #ifdef ADD_FILES
  271. "[-i file] \n"
  272. #endif
  273. "[-P publisher] [ -A app_id ] [-z] \n \
  274. [-b boot_image_name] [-c boot_catalog-name] \
  275. [-x path -x path ...] path\n");
  276.     exit(1);
  277. }
  278.  
  279.  
  280. /* 
  281.  * Fill in date in the iso9660 format 
  282.  *
  283.  * The standards  state that the timezone offset is in multiples of 15
  284.  * minutes, and is what you add to GMT to get the localtime.  The U.S.
  285.  * is always at a negative offset, from -5h to -8h (can vary a little
  286.  * with DST,  I guess).  The Linux iso9660 filesystem has had the sign
  287.  * of this wrong for ages (mkisofs had it wrong too for the longest time).
  288.  */
  289. int FDECL2(iso9660_date,char *, result, time_t, ctime){
  290.   struct tm *local;
  291.   local = localtime(&ctime);
  292.   result[0] = local->tm_year;
  293.   result[1] = local->tm_mon + 1;
  294.   result[2] = local->tm_mday;
  295.   result[3] = local->tm_hour;
  296.   result[4] = local->tm_min;
  297.   result[5] = local->tm_sec;
  298.  
  299.   /* 
  300.    * Must recalculate proper timezone offset each time,
  301.    * as some files use daylight savings time and some don't... 
  302.    */
  303.   result[6] = local->tm_yday;    /* save yday 'cause gmtime zaps it */
  304.   local = gmtime(&ctime);
  305.   local->tm_year -= result[0];
  306.   local->tm_yday -= result[6];
  307.   local->tm_hour -= result[3];
  308.   local->tm_min -= result[4];
  309.   if (local->tm_year < 0) 
  310.     {
  311.       local->tm_yday = -1;
  312.     }
  313.   else 
  314.     {
  315.       if (local->tm_year > 0) local->tm_yday = 1;
  316.     }
  317.  
  318.   result[6] = -(local->tm_min + 60*(local->tm_hour + 24*local->tm_yday)) / 15;
  319.  
  320.   return 0;
  321. }
  322.  
  323.  
  324. extern char * cdwrite_data;
  325.  
  326. int FDECL2(main, int, argc, char **, argv){
  327.   char * outfile;
  328.   struct directory_entry de;
  329.   unsigned long mem_start;
  330.   struct stat statbuf;
  331.   char * scan_tree;
  332.   char * merge_image = NULL;
  333.   struct iso_directory_record * mrootp = NULL;
  334.   int c;
  335. #ifdef ADD_FILES
  336.   char *add_file_file = NULL;
  337. #endif
  338.  
  339.   if (argc < 2)
  340.     usage();
  341.  
  342.   /* Get the defaults from the .mkisofsrc file */
  343.   read_rcfile(argv[0]);
  344.  
  345.   outfile = NULL;
  346.   while ((c = getopt(argc, argv, "i:o:V:RrfvaTp:P:b:c:x:dDlLNzA:M:m:C:")) != EOF)
  347.     switch (c)
  348.       {
  349.       case 'C':
  350.     /*
  351.      * This is a temporary hack until cdwrite gets the proper hooks in
  352.      * it.
  353.      */
  354.     cdwrite_data = optarg;
  355.     break;
  356.       case 'a':
  357.     all_files++;
  358.     break;
  359.       case 'b':
  360.     use_eltorito++;
  361.     boot_image = optarg;  /* pathname of the boot image on cd */
  362.     if (boot_image == NULL) {
  363.             fprintf(stderr,"Required boot image pathname missing\n");
  364.         exit(1);
  365.     }
  366.     break;
  367.       case 'c':
  368.     use_eltorito++;
  369.     boot_catalog = optarg;  /* pathname of the boot image on cd */
  370.     if (boot_catalog == NULL) {
  371.             fprintf(stderr,"Required boot catalog pathname missing\n");
  372.         exit(1);
  373.     }
  374.     break;
  375.       case 'A':
  376.     appid = optarg;
  377.     if(strlen(appid) > 128) {
  378.         fprintf(stderr,"Application-id string too long\n");
  379.         exit(1);
  380.     };
  381.     break;
  382.       case 'd':
  383.     omit_period++;
  384.     break;
  385.       case 'D':
  386.     RR_relocation_depth = 32767;
  387.     break;
  388.       case 'f':
  389.     follow_links++;
  390.     break;
  391.       case 'i':
  392. #ifdef ADD_FILES
  393.     add_file_file = optarg;
  394.     break;
  395. #else
  396.     usage();
  397.     exit(1);
  398. #endif
  399.       case 'l':
  400.     full_iso9660_filenames++;
  401.     break;
  402.       case 'L':
  403.         allow_leading_dots++;
  404.         break;
  405.       case 'M':
  406.     merge_image = optarg;
  407.     break;
  408.       case 'N':
  409.     omit_version_number++;
  410.     break;
  411.       case 'o':
  412.     outfile = optarg;
  413.     break;
  414.       case 'p':
  415.     preparer = optarg;
  416.     if(strlen(preparer) > 128) {
  417.         fprintf(stderr,"Preparer string too long\n");
  418.         exit(1);
  419.     };
  420.     break;
  421.       case 'P':
  422.     publisher = optarg;
  423.     if(strlen(publisher) > 128) {
  424.         fprintf(stderr,"Publisher string too long\n");
  425.         exit(1);
  426.     };
  427.     break;
  428.       case 'R':
  429.     use_RockRidge++;
  430.     break;
  431.       case 'r':
  432.     rationalize++;
  433.     use_RockRidge++;
  434.     break;
  435.       case 'T':
  436.     generate_tables++;
  437.     break;
  438.       case 'V':
  439.     volume_id = optarg;
  440.     break;
  441.       case 'v':
  442.     verbose++;
  443.     break;
  444.       case 'z':
  445. #ifdef VMS
  446.     fprintf(stderr,"Transparent compression not supported with VMS\n");
  447.     exit(1);
  448. #else
  449.     transparent_compression++;
  450. #endif
  451.     break;
  452.       case 'm':
  453.         add_match(optarg);
  454.     break;
  455.       case 'x':
  456.         exclude(optarg);
  457.     break;
  458.       default:
  459.     usage();
  460.     exit(1);
  461.       }
  462. #ifdef __NetBSD__
  463.     {
  464.     int resource;
  465.     struct rlimit rlp;
  466.     if (getrlimit(RLIMIT_DATA,&rlp) == -1) 
  467.         perror("Warning: getrlimit");
  468.     else {
  469.         rlp.rlim_cur=33554432;
  470.         if (setrlimit(RLIMIT_DATA,&rlp) == -1)
  471.             perror("Warning: setrlimit");
  472.         }
  473.     }
  474. #endif
  475. #ifdef HAVE_SBRK
  476.   mem_start = (unsigned long) sbrk(0);
  477. #endif
  478.  
  479.   if(verbose) fprintf(stderr,"%s\n", version_string);
  480.  
  481.   if(     (cdwrite_data != NULL && merge_image == NULL)
  482.        || (cdwrite_data == NULL && merge_image != NULL) )
  483.     {
  484.       fprintf(stderr,"Multisession usage bug - both -C and -M must be specified.\n");
  485.       exit(0);
  486.     }
  487.  
  488.   /*  The first step is to scan the directory tree, and take some notes */
  489.  
  490.   scan_tree = argv[optind];
  491.  
  492. #ifdef ADD_FILES
  493.   if (add_file_file) {
  494.     add_file(add_file_file);
  495.   }
  496.   add_file_list (argc, argv, optind+1);
  497. #endif
  498.  
  499.   if(!scan_tree){
  500.       usage();
  501.       exit(1);
  502.   };
  503.  
  504. #ifndef VMS
  505.   if(scan_tree[strlen(scan_tree)-1] != '/') {
  506.     scan_tree = (char *) e_malloc(strlen(argv[optind])+2);
  507.     strcpy(scan_tree, argv[optind]);
  508.     strcat(scan_tree, "/");
  509.   };
  510. #endif
  511.  
  512.   if(use_RockRidge){
  513. #if 1
  514.     extension_record = generate_rr_extension_record("RRIP_1991A",
  515.                        "THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS",
  516.                        "PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE.  SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR CONTACT INFORMATION.", &extension_record_size);
  517. #else
  518.     extension_record = generate_rr_extension_record("IEEE_P1282",
  519.                        "THE IEEE P1282 PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS",
  520.                        "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, PISCATAWAY, NJ, USA FOR THE P1282 SPECIFICATION.", &extension_record_size);
  521. #endif
  522.   }
  523.  
  524.   /*
  525.    * See if boot catalog file exists in root directory, if not
  526.    * we will create it.
  527.    */
  528.   if (use_eltorito)
  529.     init_boot_catalog(argv[optind]);
  530.  
  531.   /*
  532.    * Find the device and inode number of the root directory.
  533.    * Record this in the hash table so we don't scan it more than
  534.    * once.
  535.    */
  536.   stat_filter(argv[optind], &statbuf);
  537.   add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));
  538.  
  539.   memset(&de, 0, sizeof(de));
  540.  
  541.   de.filedir = root;  /* We need this to bootstrap */
  542.  
  543.   if( merge_image != NULL )
  544.     {
  545.       mrootp = merge_isofs(merge_image);
  546.       if( mrootp == NULL )
  547.     {
  548.       /*
  549.        * Complain and die.
  550.        */
  551.       fprintf(stderr,"Unable to open previous session image %s\n",
  552.           merge_image);
  553.       exit(1);
  554.     }
  555.  
  556.       memcpy(&de.isorec.extent, mrootp->extent, 8);      
  557.     }
  558.  
  559.   /*
  560.    * Scan the actual directory (and any we find below it)
  561.    * for files to write out to the output image.
  562.    */
  563.   if (!scan_directory_tree(argv[optind], &de, mrootp))
  564.     {
  565.       exit(1);
  566.     }
  567.  
  568.   /*
  569.    * Fix a couple of things in the root directory so that everything
  570.    * is self consistent.
  571.    */
  572.   root->self = root->contents;  /* Fix this up so that the path tables get done right */
  573.  
  574.   if(reloc_dir) sort_n_finish(reloc_dir);
  575.  
  576.   if (goof) exit(1);
  577.   
  578.   /*
  579.    * OK, ready to write the file.  Open it up, and generate the thing.
  580.    */
  581.   if (outfile){
  582.       discimage = fopen(outfile, "w");
  583.       if (!discimage){
  584.           fprintf(stderr,"Unable to open disc image file\n");
  585.           exit(1);
  586.  
  587.       };
  588.   } else
  589.       discimage =  stdout;
  590.  
  591.   /* Now assign addresses on the disc for the path table. */
  592.  
  593.   path_blocks = (path_table_size + (SECTOR_SIZE - 1)) >> 11;
  594.   if (path_blocks & 1) path_blocks++;
  595.  
  596.   path_table[0] = session_start + 0x14;
  597.   path_table[1] = 0;
  598.   path_table[2] = path_table[0] + path_blocks;
  599.   path_table[3] = 0;
  600.  
  601.   last_extent += path_table[2] - session_start + path_blocks;  
  602.         /* The next free block */
  603.  
  604.   /* The next step is to go through the directory tree and assign extent
  605.      numbers for all of the directories */
  606.  
  607.   assign_directory_addresses(root);
  608.  
  609.   if(extension_record) {
  610.       struct directory_entry * s_entry;
  611.       extension_record_extent = last_extent++;
  612.       s_entry = root->contents;
  613.       set_733((char *) s_entry->rr_attributes + s_entry->rr_attr_size - 24,
  614.           extension_record_extent);
  615.       set_733((char *) s_entry->rr_attributes + s_entry->rr_attr_size - 8,
  616.           extension_record_size);
  617.   };
  618.  
  619.   if (use_RockRidge && reloc_dir)
  620.       finish_cl_pl_entries();
  621.  
  622.   /* Now we generate the path tables that are used by DOS to improve directory
  623.      access times. */
  624.   generate_path_tables();
  625.  
  626.   /* Generate root record for volume descriptor. */
  627.   generate_root_record();
  628.  
  629.   if (verbose)
  630.     dump_tree(root);
  631.  
  632.   if( in_image != NULL )
  633.     {
  634.       fclose(in_image);
  635.     }
  636.  
  637.   iso_write(discimage);
  638.  
  639. #ifdef HAVE_SBRK
  640.   fprintf(stderr,"Max brk space used %x\n", 
  641.       (unsigned int)(((unsigned long)sbrk(0)) - mem_start));
  642. #endif
  643.   fprintf(stderr,"%d extents written (%d Mb)\n", last_extent, last_extent >> 9);
  644. #ifdef VMS
  645.   return 1;
  646. #else
  647.   return 0;
  648. #endif
  649. }
  650.  
  651. void *
  652. FDECL1(e_malloc, size_t, size)
  653. {
  654. void* pt = 0;
  655.     if( (size > 0) && ((pt=malloc(size))==NULL) ) {
  656.         fprintf(stderr, "Not enough memory\n");
  657.         exit (1);
  658.         }
  659. return pt;
  660. }
  661.