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", ©right}, {"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.