ftp.nice.ch/pub/next/unix/cdrom/mkisof.1.0.5.s.tar.gz#/mkisofs-1.05/mkisofs.c

This is mkisofs.c in view mode; [Download] [Up]

/*
 * Program mkisofs.c - generate iso9660 filesystem  based upon directory
 * tree on hard disk.

   Written by Eric Youngdale (1993).

   Copyright 1993 Yggdrasil Computing, Incorporated

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */

/* ADD_FILES changes made by Ross Biro biro@yggdrasil.com 2/23/95 */

#include <errno.h>
#include "mkisofs.h"

#ifdef linux
#include <getopt.h>
#endif

#include "iso9660.h"
#include <ctype.h>

#ifndef VMS
#include <time.h>
#else
#include <sys/time.h>
#include "vms.h"
#endif

#include <stdlib.h>
#include <sys/stat.h>

#ifndef VMS
#include <unistd.h>
#endif

#include "exclude.h"

#ifdef __NetBSD__
#include <sys/time.h>
#include <sys/resource.h>
#endif

struct directory * root = NULL;

static char version_string[] = "mkisofs v1.05";

FILE * discimage;
unsigned int next_extent = 0;
unsigned int last_extent = 0;
unsigned int path_table_size = 0;
unsigned int path_table[4] = {0,};
unsigned int path_blocks = 0;
struct iso_directory_record root_record;
static int timezone_offset;
char * extension_record = NULL;
int extension_record_extent = 0;
static  int extension_record_size = 0;

/* These variables are associated with command line options */
int use_RockRidge = 0;
int verbose = 0;
int all_files  = 0;
int follow_links = 0;
int rationalize = 0;
int generate_tables = 0;
char * preparer = PREPARER_DEFAULT;
char * publisher = PUBLISHER_DEFAULT;
char * appid = APPID_DEFAULT;
char * copyright = COPYRIGHT_DEFAULT;
char * biblio = BIBLIO_DEFAULT;
char * abstract = ABSTRACT_DEFAULT;
char * volset_id = VOLSET_ID_DEFAULT;
char * volume_id = VOLUME_ID_DEFAULT;
char * system_id = SYSTEM_ID_DEFAULT;

int omit_period = 0;             /* Violates iso9660, but these are a pain */
int transparent_compression = 0; /* So far only works with linux */
int omit_version_number = 0;     /* May violate iso9660, but noone uses vers*/
int RR_relocation_depth = 6;     /* Violates iso9660, but most systems work */
int full_iso9660_filenames = 0;  /* Used with Amiga.  Disc will not work with
				  DOS */
int allow_leading_dots = 0;	 /* DOS cannot read names with leading dots */

struct rcopts{
  char * tag;
  char ** variable;
};

struct rcopts rcopt[] = {
  {"PREP", &preparer},
  {"PUBL", &publisher},
  {"APPI", &appid},
  {"COPY", &copyright},
  {"BIBL", &biblio},
  {"ABST", &abstract},
  {"VOLS", &volset_id},
  {"VOLI", &volume_id},
  {"SYSI", &system_id},
  {NULL, NULL}
};

#ifdef ultrix
char *strdup(s)
char *s;{char *c;if(c=(char *)malloc(strlen(s)+1))strcpy(c,s);return c;}
#endif

#ifdef __NeXT__ 
char *strdup(s)
char *s;{char *c;if(c=(char *)malloc(strlen(s)+1))strcpy(c,s);return c;}
#endif

void FDECL1(read_rcfile, char *, appname)
{
  FILE * rcfile;
  struct rcopts * rco;
  char * pnt, *pnt1;
  char linebuffer[256];
  static char rcfn[] = ".mkisofsrc";
  char filename[1000];
  int linum;

  strcpy(filename, rcfn);
  rcfile = fopen(filename, "r");
  if (!rcfile && errno != ENOENT)
    perror(filename);

  if (!rcfile)
    {
      pnt = getenv("HOME");
      if (pnt && strlen(pnt) + strlen(rcfn) + 2 <= sizeof(filename))
	{
	  strcpy(filename, pnt);
	  strcat(filename, "/");
	  strcat(filename, rcfn);
	  rcfile = fopen(filename, "r");
	  if (!rcfile && errno != ENOENT)
	    perror(filename);
	}
    }
  if (!rcfile && strlen(appname)+sizeof(rcfn)+2 <= sizeof(filename))
    {
      strcpy(filename, appname);
      pnt = strrchr(filename, '/');
      if (pnt)
	{
	  strcpy(pnt + 1, rcfn);
	  rcfile = fopen(filename, "r");
	  if (!rcfile && errno != ENOENT)
	    perror(filename);
	}
    }
  if (!rcfile)
    return;
  fprintf(stderr, "Using \"%s\"\n", filename);
  /* OK, we got it.  Now read in the lines and parse them */
  linum = 0;
  while (fgets(linebuffer, sizeof(linebuffer), rcfile))
    {
      char *name;
      char *name_end;
      ++linum;
      /* skip any leading white space */
	pnt = linebuffer;
      while (*pnt == ' ' || *pnt == '\t')
	++pnt;
      /* If we are looking at a # character, this line is a comment. */
	if (*pnt == '#')
	  continue;
      /* The name should begin in the left margin.  Make sure it is in
	 upper case.  Stop when we see white space or a comment. */
	name = pnt;
      while (*pnt && isalpha(*pnt))
	{
	  if(islower(*pnt))
	    *pnt = toupper(*pnt);
	  pnt++;
	}
      if (name == pnt)
	{
	  fprintf(stderr, "%s:%d: name required\n", filename, linum);
	  continue;
	}
      name_end = pnt;
      /* Skip past white space after the name */
      while (*pnt == ' ' || *pnt == '\t')
	pnt++;
      /* silently ignore errors in the rc file. */
      if (*pnt != '=')
	{
	  fprintf(stderr, "%s:%d: equals sign required\n", filename, linum);
	  continue;
	}
      /* Skip pas the = sign, and any white space following it */
      pnt++; /* Skip past '=' sign */
      while (*pnt == ' ' || *pnt == '\t')
	pnt++;
      +       /* now it is safe to NUL terminate the name */
	*name_end = 0;
      /* Now get rid of trailing newline */
      pnt1 = pnt;
      while (*pnt1)
	{
	  if (*pnt1 == '\n')
	    {
	      *pnt1 = 0;
	      break;
	    }
	  pnt1++;
	};
      /* OK, now figure out which option we have */
      for(rco = rcopt; rco->tag; rco++) {
	if(strcmp(rco->tag, name) == 0)
	  {
	    *rco->variable = strdup(pnt);
	    break;
	  };
      }
      if (rco->tag == NULL)
	{
	  fprintf(stderr, "%s:%d: field name \"%s\" unknown\n", filename, linum,
		  name);
	}
     }
  if (ferror(rcfile))
    perror(filename);
  fclose(rcfile);
}

char * path_table_l = NULL;
char * path_table_m = NULL;
int goof = 0;

void usage(){
	fprintf(stderr,"Usage:\n");
	fprintf(stderr,
"mkisofs [-o outfile] [-R] [-V volid] [-v] [-a] \
[-T]\n [-l] [-d] [-V] [-D] [-L] [-p preparer] \
[-P publisher] [ -A app_id ] [-z] \
[-x path -x path ...] path\n");
	exit(1);
}

int get_iso9660_timezone_offset(){
  struct tm gm;
  struct tm * pt;
  time_t ctime;
  int local_min, gmt_min;

  time(&ctime);
  pt = gmtime(&ctime);
  gm = *pt;
  pt = localtime(&ctime);

  if(gm.tm_year < pt->tm_year)
    gm.tm_yday = -1;

  if(gm.tm_year > pt->tm_year)
    pt->tm_yday = -1;

  gmt_min = gm.tm_min + 60*(gm.tm_hour + 24*gm.tm_yday);
  local_min = pt->tm_min + 60*(pt->tm_hour + 24*pt->tm_yday);
  return (gmt_min - local_min)/15;
}


/* Fill in date in the iso9660 format */
int FDECL2(iso9660_date,char *, result, time_t, ctime){
  struct tm *local;
  local = localtime(&ctime);
  result[0] = local->tm_year;
  result[1] = local->tm_mon + 1;
  result[2] = local->tm_mday;
  result[3] = local->tm_hour;
  result[4] = local->tm_min;
  result[5] = local->tm_sec;
  result[6] = timezone_offset;
  return 0;
}

int FDECL3(iso9660_file_length,const char*, name, struct directory_entry *, sresult, 
			int, dirflag){
  int seen_dot = 0;
  int seen_semic = 0;
  char * result;
  int priority = 32767;
  int tildes = 0;
  int ignore = 0;
  int extra = 0;
  int current_length = 0;
  int chars_after_dot = 0;
  int chars_before_dot = 0;
  const char * pnt;
  result = sresult->isorec.name;

  if(strcmp(name,".") == 0){
    if(result) *result = 0;
    return 1;
  };

  if(strcmp(name,"..") == 0){
    if(result) {
	    *result++ = 1;
	    *result++ = 0;
    }
    return 1;
  };

  pnt = name;
  while(*pnt){
#ifdef VMS
    if(strcmp(pnt,".DIR;1") == 0) break;
#endif
    if(*pnt == '#') {priority = 1; pnt++; continue; };
    if(*pnt == '~') {priority = 1; tildes++; pnt++; continue;};
    if(*pnt == ';') {seen_semic = 1; *result++ = *pnt++; continue; };
    if(ignore) {pnt++; continue;};
    if(seen_semic){
      if(*pnt >= '0' && *pnt <= '9') *result++ = *pnt;
      extra++;
      pnt++;
      continue;
    };
    if(full_iso9660_filenames) {
      /* Here we allow a more relaxed syntax. */
      if(*pnt == '.') {
	if (seen_dot) {ignore++; continue;}
	seen_dot++;
      }
      if(current_length < 30) *result++ = (islower(*pnt) ? toupper(*pnt) : *pnt);
    } else { /* Dos style filenames */
      if(*pnt == '.') {
        if (!chars_before_dot && !allow_leading_dots) {
	  /* DOS can't read files with dot first */
          chars_before_dot++;
          if (result) *result++ = '_'; /* Substitute underscore */
        } else {
          if (seen_dot) {ignore++; continue;}
	  if(result) *result++ = '.';
	  seen_dot++;
        }
      } else if (seen_dot) {
	if(chars_after_dot < 3) {
	  chars_after_dot++;
	  if(result) *result++ = (islower(*pnt) ? toupper(*pnt) : *pnt);
	}
      } else {
	if(chars_before_dot < 8) {
	  chars_before_dot++;
	  if(result) *result++ = (islower(*pnt) ? toupper(*pnt) : *pnt);
	};
      };
    };
    current_length++;
    pnt++;
  };
  
  if(tildes == 2){
    int prio1 = 0;
    pnt = name;
    while (*pnt && *pnt != '~') pnt++;
    if (*pnt) pnt++;
    while(*pnt && *pnt != '~'){
      prio1 = 10*prio1 + *pnt - '0';
      pnt++;
    };
    priority = prio1;
  };
    
  if (!dirflag){
    if (!seen_dot && !omit_period) {
      if (result) *result++ = '.'; 
      extra++;
    };
    if(!omit_version_number && !seen_semic) {
      if(result){
	*result++ = ';';
	*result++ = '1';
      };
      extra += 2;
    }
  };
		    
  if(result) *result++ = 0;
  sresult->priority = priority;
  return chars_before_dot + chars_after_dot + seen_dot + extra;
}

#ifdef ADD_FILES

struct file_adds *root_file_adds = NULL;

void
FDECL2(add_one_file, char *, addpath, char *, path )
{
  char *cp;
  char *name;
  struct file_adds *f;
  struct file_adds *tmp;

  f = root_file_adds;
  tmp = NULL;

  name = rindex (addpath, PATH_SEPARATOR);
  if (name == NULL) {
    name = addpath;
  } else {
    name++;
  }

  cp = strtok (addpath, SPATH_SEPARATOR);

  while (cp != NULL && strcmp (name, cp)) {
     if (f == NULL) {
        root_file_adds = e_malloc (sizeof *root_file_adds);
        f=root_file_adds;
        f->name = NULL;
        f->child = NULL;
        f->next = NULL;
        f->add_count = 0;
        f->adds = NULL;
	f->used = 0;
     }
    if (f->child) {
      for (tmp = f->child; tmp->next != NULL; tmp =tmp->next) {
         if (strcmp (tmp->name, cp) == 0) {
           f = tmp;
           goto next;
         }
      }
      if (strcmp (tmp->name, cp) == 0) {
          f=tmp;
          goto next;
      }
      /* add a new node. */
      tmp->next = e_malloc (sizeof (*tmp->next));
      f=tmp->next;
      f->name = strdup (cp);
      f->child = NULL;
      f->next = NULL;
      f->add_count = 0;
      f->adds = NULL;
      f->used = 0;
    } else {
      /* no children. */
      f->child = e_malloc (sizeof (*f->child));
      f = f->child;
      f->name = strdup (cp);
      f->child = NULL;
      f->next = NULL;
      f->add_count = 0;
      f->adds = NULL;
      f->used = 0;

    }
   next:
     cp = strtok (NULL, SPATH_SEPARATOR);
   }
  /* Now f if non-null points to where we should add things */
  if (f == NULL) {
     root_file_adds = e_malloc (sizeof *root_file_adds);
     f=root_file_adds;
     f->name = NULL;
     f->child = NULL;
     f->next = NULL;
     f->add_count = 0;
     f->adds = NULL;
   }

  /* Now f really points to where we should add this name. */
  f->add_count++;
  f->adds = realloc (f->adds, sizeof (*f->adds)*f->add_count);
  f->adds[f->add_count-1].path = strdup (path);
  f->adds[f->add_count-1].name = strdup (name);
}

void
FDECL3(add_file_list, int, argc, char **,argv, int, ind)
{
  char *ptr;
  char *dup_arg;

  while (ind < argc) {
     dup_arg = strdup (argv[ind]);
     ptr = index (dup_arg,'=');
     if (ptr == NULL) {
        free (dup_arg);
        return;
     }
     *ptr = 0;
     ptr++;
     add_one_file (dup_arg, ptr);
     free (dup_arg);
     ind++;
  }
}
void
FDECL1(add_file, char *, filename)
{
  char buff[1024];
  FILE *f;
  char *ptr;
  char *p2;
  int count=0;

  if (strcmp (filename, "-") == 0) {
    f = stdin;
  } else {
    f = fopen (filename, "r");
    if (f == NULL) {
      perror ("fopen");
      exit (1);
    }
  }
  while (fgets (buff, 1024, f)) {
    count++;
    ptr = buff;
    while (isspace (*ptr)) ptr++;
    if (*ptr==0) continue;
    if (*ptr=='#') continue;

    if (ptr[strlen(ptr)-1]== '\n') ptr[strlen(ptr)-1]=0;
    p2 = index (ptr, '=');
    if (p2 == NULL) {
      fprintf (stderr, "Error in line %d: %s\n", count, buff);
      exit (1);
    }
    *p2 = 0;
    p2++;
    add_one_file (ptr, p2);
  }
  if (f != stdin) fclose (f);
}

#endif

int FDECL2(main, int, argc, char **, argv){
  char * outfile;
  struct directory_entry de;
  unsigned int mem_start;
  struct stat statbuf;
  char * scan_tree;
  int c;
#ifdef ADD_FILES
  char *add_file_file = NULL;
#endif

  if (argc < 2)
    usage();

  /* Get the defaults from the .mkisofsrc file */
  read_rcfile(argv[0]);

  outfile = NULL;
  while ((c = getopt(argc, argv, "i:o:V:RrfvaTp:P:x:dDlLNzA:")) != EOF)
    switch (c)
      {
      case 'p':
	preparer = optarg;
	if(strlen(preparer) > 128) {
		fprintf(stderr,"Preparer string too long\n");
		exit(1);
	};
	break;
      case 'P':
	publisher = optarg;
	if(strlen(publisher) > 128) {
		fprintf(stderr,"Publisher string too long\n");
		exit(1);
	};
	break;
      case 'A':
	appid = optarg;
	if(strlen(appid) > 128) {
		fprintf(stderr,"Application-id string too long\n");
		exit(1);
	};
	break;
      case 'd':
	omit_period++;
	break;
      case 'D':
	RR_relocation_depth = 32767;
	break;
      case 'l':
	full_iso9660_filenames++;
	break;
      case 'L':
        allow_leading_dots++;
        break;
      case 'N':
	omit_version_number++;
	break;
      case 'o':
	outfile = optarg;
	break;
      case 'f':
	follow_links++;
	break;
      case 'R':
	use_RockRidge++;
	break;
      case 'r':
	rationalize++;
	use_RockRidge++;
	break;
      case 'V':
	volume_id = optarg;
	break;
      case 'v':
	verbose++;
	break;
      case 'a':
	all_files++;
	break;
      case 'T':
	generate_tables++;
	break;
      case 'z':
#ifdef VMS
	fprintf(stderr,"Transparent compression not supported with VMS\n");
	exit(1);
#else
	transparent_compression++;
#endif
	break;
      case 'x':
        exclude(optarg);
	break;
      case 'i':
#ifdef ADD_FILES
	add_file_file = optarg;
	break;
#endif
      default:
	usage();
	exit(1);
      }
#ifdef __NetBSD__
    {
	int resource;
    struct rlimit rlp;
	if (getrlimit(RLIMIT_DATA,&rlp) == -1) 
		perror("Warning: getrlimit");
	else {
		rlp.rlim_cur=33554432;
		if (setrlimit(RLIMIT_DATA,&rlp) == -1)
			perror("Warning: setrlimit");
		}
	}
#endif
  mem_start = (unsigned int) sbrk(0);

  if(verbose) fprintf(stderr,"%s\n", version_string);
  /* Now find the timezone offset */

  timezone_offset = get_iso9660_timezone_offset();

  /*  The first step is to scan the directory tree, and take some notes */

  scan_tree = argv[optind];

#ifdef ADD_FILES
  if (add_file_file) {
    add_file(add_file_file);
  }
  add_file_list (argc, argv, optind+1);
#endif

  if(!scan_tree){
	  usage();
	  exit(1);
  };

#ifndef VMS
  if(scan_tree[strlen(scan_tree)-1] != '/') {
    scan_tree = (char *) e_malloc(strlen(argv[optind])+2);
    strcpy(scan_tree, argv[optind]);
    strcat(scan_tree, "/");
  };
#endif

  if(use_RockRidge){
#if 1
	extension_record = generate_rr_extension_record("RRIP_1991A",
				       "THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS",
				       "PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE.  SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR CONTACT INFORMATION.", &extension_record_size);
#else
	extension_record = generate_rr_extension_record("IEEE_P1282",
				       "THE IEEE P1282 PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS",
				       "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, PISCATAWAY, NJ, USA FOR THE P1282 SPECIFICATION.", &extension_record_size);
#endif
  };

  stat_filter(argv[optind], &statbuf);
  add_directory_hash(statbuf.st_dev, STAT_INODE(statbuf));

  de.filedir = root;  /* We need this to bootstrap */
  scan_directory_tree(argv[optind], &de);
  root->self = root->contents;  /* Fix this up so that the path tables get done right */

  if(reloc_dir) sort_n_finish(reloc_dir);

  if (goof) exit(1);
  
  if (outfile){
	  discimage = fopen(outfile, "w");
	  if (!discimage){
		  fprintf(stderr,"Unable to open disc image file\n");
		  exit(1);

	  };
  } else
	  discimage =  stdout;

  /* Now assign addresses on the disc for the path table. */

  path_blocks = (path_table_size + (SECTOR_SIZE - 1)) >> 11;
  if (path_blocks & 1) path_blocks++;
  path_table[0] = 0x14;
  path_table[1] = path_table[0] + path_blocks;
  path_table[2] = path_table[1] + path_blocks;
  path_table[3] = path_table[2] + path_blocks;

  last_extent = path_table[3] + path_blocks;  /* The next free block */

  /* The next step is to go through the directory tree and assign extent
     numbers for all of the directories */

  assign_directory_addresses(root);

  if(extension_record) {
	  struct directory_entry * s_entry;
	  extension_record_extent = last_extent++;
	  s_entry = root->contents;
	  set_733(s_entry->rr_attributes + s_entry->rr_attr_size - 24,
		  extension_record_extent);
	  set_733(s_entry->rr_attributes + s_entry->rr_attr_size - 8,
		  extension_record_size);
  };

  if (use_RockRidge && reloc_dir)
	  finish_cl_pl_entries();

  /* Now we generate the path tables that are used by DOS to improve directory
     access times. */
  generate_path_tables();

  /* Generate root record for volume descriptor. */
  generate_root_record();

  if (verbose)
    dump_tree(root);

  iso_write(discimage);

  fprintf(stderr,"Max brk space used %x\n", 
	  ((unsigned int)sbrk(0)) - mem_start);
  fprintf(stderr,"%d extents written (%d Mb)\n", last_extent, last_extent >> 9);
#ifdef VMS
  return 1;
#else
  return 0;
#endif
}

void *e_malloc(size_t size)
{
void* pt;
	if((pt=malloc(size))==NULL) {
		printf("Not enougth memory\n");
		exit (1);
		}
return pt;
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.