1995-02-12 08:00:42 +00:00
/*
* 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 0213 9 , USA . */
# include "mkisofs.h"
1995-02-12 08:16:50 +00:00
# include <assert.h>
1995-02-12 08:00:42 +00:00
# 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.03 " ;
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 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 */
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
void FDECL1 ( read_rcfile , char * , appname )
{
FILE * rcfile ;
struct rcopts * rco ;
char * pnt , * pnt1 ;
char linebuffer [ 256 ] ;
rcfile = fopen ( " .mkisofsrc " , " r " ) ;
if ( ! rcfile ) {
if ( strlen ( appname ) + sizeof ( " .mkisofsrc " ) > sizeof ( linebuffer ) ) return ;
strcpy ( linebuffer , appname ) ;
pnt = strrchr ( linebuffer , ' / ' ) ;
if ( ! pnt ) return ;
pnt + + ;
strcpy ( pnt , " .mkisofsrc " ) ;
rcfile = fopen ( linebuffer , " r " ) ;
fprintf ( stderr , " Using %s. \n " , linebuffer ) ;
} else {
fprintf ( stderr , " Using ./.mkisofsrc. \n " ) ;
}
if ( ! rcfile ) return ;
/* OK, we got it. Now read in the lines and parse them */
while ( ! feof ( rcfile ) )
{
fgets ( linebuffer , sizeof ( linebuffer ) , rcfile ) ;
pnt = linebuffer ;
while ( 1 = = 1 ) {
if ( * pnt = = ' ' | | * pnt = = ' \t ' | | * pnt = = ' \n ' | | * pnt = = 0 ) break ;
if ( islower ( * pnt ) ) * pnt = toupper ( * pnt ) ;
pnt + + ;
}
/* OK, now find the '=' sign */
while ( * pnt & & * pnt ! = ' = ' & & * pnt ! = ' # ' ) pnt + + ;
if ( * pnt = = ' # ' ) continue ; /* SKip comment */
if ( * pnt ! = ' = ' ) continue ; /* Skip to next line */
pnt + + ; /* Skip past '=' sign */
while ( * pnt = = ' ' | | * pnt = = ' \t ' ) pnt + + ; /* And skip past whitespace */
/* Now get rid of trailing newline */
pnt1 = pnt ;
while ( * pnt1 ) {
if ( * pnt1 = = ' \n ' ) * pnt1 = 0 ;
else
pnt1 + + ;
} ;
pnt1 = linebuffer ;
while ( * pnt1 = = ' ' | | * pnt1 = = ' \t ' ) pnt1 + + ;
/* OK, now figure out which option we have */
for ( rco = rcopt ; rco - > tag ; rco + + ) {
if ( strncmp ( rco - > tag , pnt1 , 4 ) = = 0 )
{
* rco - > variable = strdup ( pnt ) ;
break ;
} ;
}
}
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 ] [ - 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 ( 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 ;
1995-02-12 08:16:50 +00:00
# if 1 /* WALNUT CREEK HACKS -- rab 950126 */
{
int i , c , len ;
char * r ;
assert ( result ) ;
assert ( omit_version_number ) ;
assert ( omit_period ) ;
assert ( extra = = 0 ) ;
r = sresult - > isorec . name ;
len = strlen ( r ) ;
if ( r [ len - 1 ] = = ' . ' ) {
assert ( seen_dot & & chars_after_dot = = 0 ) ;
r [ - - len ] = ' \0 ' ;
seen_dot = 0 ;
}
for ( i = 0 ; i < len ; + + i ) {
c = r [ i ] ;
if ( c = = ' . ' ) {
if ( dirflag ) {
fprintf ( stderr , " changing DIR %s to " , r ) ;
r [ i ] = ' \0 ' ;
fprintf ( stderr , " %s \n " , r ) ;
chars_after_dot = 0 ;
seen_dot = 0 ;
extra = 0 ;
break ;
}
} else if ( ! isalnum ( c ) & & c ! = ' _ ' ) {
fprintf ( stderr , " changing %s to " , r ) ;
r [ i ] = ' _ ' ;
fprintf ( stderr , " %s \n " , r ) ;
}
}
}
# endif
1995-02-12 08:00:42 +00:00
sresult - > priority = priority ;
return chars_before_dot + chars_after_dot + seen_dot + extra ;
}
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 ;
if ( argc < 2 )
usage ( ) ;
/* Get the defaults from the .mkisofsrc file */
read_rcfile ( argv [ 0 ] ) ;
outfile = NULL ;
while ( ( c = getopt ( argc , argv , " o:V:RfvaTp:P:x:dDlNzA: " ) ) ! = 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 ' N ' :
omit_version_number + + ;
break ;
case ' o ' :
outfile = optarg ;
break ;
case ' f ' :
follow_links + + ;
break ;
case ' R ' :
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 ;
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 ] ;
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 ( 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 ( ) ;
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 ;
}