Monday, January 02, 2006

ISO files with Linux

In the Linux world, people usually just mount their ISO images by typing as root :

$ mkdir /mnt/isotmp
$ mount isofile.iso /mnt/isotmp -o loop

And once they're done, unmount the virtual disk :

$ umount /mnt/isotmp

This can be very annoying.


UNISO

Here's another solution. This is a script in Perl that I found somewhere.
It uses isofile from the cdrecord-isotools package to extract the ISO file and you don't need to be root to execute it.


#!/usr/bin/perl
# Copyright (C) 2003 Tiago Cogumbreiro
#
# This file 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 of the License, or
# (at your option) any later version.
# This file 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 file; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA 02111-1307 USA

use strict;
use warnings;
our $VERSION = "0.1b";
our $ISOINFO = "isoinfo";
our $EXTRACT_COMPRESSED_FS = "extract_compressed_fs";
our $dest_dir = "";
our $iso = "";
our $do_chmod = 1;
our $do_cloop = 0;
our $tmp_iso = "/tmp/$$.iso";

sub usage {
print "Usage: $0 [-d ] \n";
print "\t-d \tthe destination directory\n";
print "\t-m\t\t\tdon't chmod files, usefull when extracting non Rockridge isos\n";
print "\t-c\t\t\textract from a cloop file instead of an iso\n";
print "\t-t \t\twhen extracting from a cloop we'll need to create a temporary file, define the temporary file with this argument\n";
}
# converts a string mode to a number mode
sub cvt_mode {
my ($str) = @_;
my $ret = 0;
if (substr($str, 0, 1) eq "r") {
$ret += 4;
}
if (substr($str, 1, 1) eq "w") {
$ret += 2;
}
if (substr($str, 2, 1) eq "x") {
$ret += 1;
}
return $ret;
}
# extracts a file from an iso
sub extract_file {
my ($curr_dir, $dest_dir, $line) = @_;
print "$line\n";
my $mode = substr($line, 0, 10);
my $file = substr($line, 67);
my $target = $dest_dir.$curr_dir.$file;
if((not $file =~ /\. */ or not $file =~ /\.\. */) and substr($mode, 0, 1) ne "d" ) {
print "$target\n";
if(substr($mode, 0, 1) eq "l") {
# create a link
my($src, $dst) = split(" -> ", $file);
print "ln -s $dst $dest_dir$curr_dir$src\n";
system "ln -s $dst $dest_dir$curr_dir$src";
unless($? == 0) {
print "Error while extracting symbolic link\n";
exit 1;
}
print "$file\n";
} else {
# Extract a regular file
system "$ISOINFO -i $iso -x /$curr_dir$file > $target";
# Correct mode
# Convert string to numeral mode
my $real_mod = cvt_mode(substr($mode, 1));
$real_mod .= cvt_mode(substr($mode, 4));
$real_mod .= cvt_mode(substr($mode, 7));
# apply conversion
# TODO add the SUI, SGI, sticky
# TODO chown
# TODO use perl's chmod
if ($do_chmod) {
system "chmod 0$real_mod $target";
}
}
}
}



# Parse arguments
while ((scalar @ARGV) gt 0) {
my $arg = shift(@ARGV);
# user don't want to chmod
if ($arg eq "-m") {
$do_chmod = 0;
# we'll be extracting from a cloop file instead
} elsif ($arg eq "-c") {
$do_cloop = 1;
# get the temporary file
} elsif ($arg eq "-t") {
$arg = shift(@ARGV);

unless($arg) {
usage();
exit 1;
}
$tmp_iso = $arg;
# user wants to set a destination dir
} elsif ($arg eq "-d") {

$arg = shift(@ARGV);

unless($arg) {
usage();
exit 1;
}
$dest_dir = $arg;
} else {
$iso = $arg;
}
}

unless($iso) {
usage();
exit 1;
}


# If we are extracting from a cloop file we'll need to extract
# a temp iso to extract the data from it, unfornatly isoinfo has
# no input redirection arg
if($do_cloop) {
system "$EXTRACT_COMPRESSED_FS $iso > $tmp_iso";
if($? != 0) {
print "Error converting cloop file to iso!\n";
exit 1;
}
$iso = $tmp_iso;
}

# Get the file list
my @file_list = split("\n", `$ISOINFO -R -l -i $iso`);

my $curr_dir = "";
foreach(@file_list) {
# ignore empty lines

# Get the current directory
if(/Directory listing of /) {
$curr_dir = substr($_, 22);
if($curr_dir) {
print("$dest_dir$curr_dir\n");
mkdir $dest_dir.$curr_dir;
}
} elsif ($_) {
extract_file($curr_dir, $dest_dir, $_);
}
}




One day though, it didn't work on one particular ISO file. So I stopped using it and made a script that would work everytime using the mount command.

This new script must be executed as root ( so link it to /usr/bin might be a good idea with ln uniso /usr/bin/uniso) and it will give 777 permissions to the extracted files ( read, write, exe for all users/groups ). Pass the name of the ISO file as argument and it will extract it a new directory.

A directory /mnt/isotmp will also be created.


#!/usr/bin/python
import sys, os

isofile = sys.argv[1] # command line argument

# check iso extension
if isofile.find('.iso') == -1: sys.exit('no iso file')

# check if /mnt/isotmp exists and create it
if os.path.exists( "/mnt/isotmp" ) == False : os.system('mkdir /mnt/isotmp')

# remove the extension '.iso'
folder = isofile[0:isofile.find('.iso')]

isofile = '\'' + isofile + '\'' # add ' '
folder = '\'' + folder + '\'' # add ' '

# mount the iso file to /mnt/isotmp/
os.system('mount ' + isofile+ ' /mnt/isotmp -o loop')

# creates a new folder in the current folder
os.system( 'mkdir ' + folder )

# copies th mounted directory into the new folder
os.system( 'cp -R /mnt/isotmp/* ' + folder )

# changes owner, group, and permissions
# username = os.environ['USER']
# os.system( 'chown -fhR username ' + folder )
# os.system( 'chgrp -fhR username ' + folder )
# os.system( 'chmod -R u+w,go-w ' + folder )

os.system( 'chmod -R 777 ' + folder )

# unmount the iso file
os.system( 'umount ' + ' /mnt/isotmp' )



To transform this new uniso script into an iso2tar command-line just add at the end of the program :

os.system( "tar cvf " + folder + ".tar" + folder )
os.system( 'chmod -R 777 ' + folder + '.tar' )


To transform it into an iso2tar.gz command-line :

os.system( 'tar cvfz ' + folder + '.tar.gz' + folder )
os.system( 'chmod -R 777 ' + folder + '.tar.gz' )


To transform it into an iso2tar.bz2 command-line :

os.system( 'tar cvfj ' + folder + '.tar.bz2' + folder )
os.system( 'chmod -R 777 ' + folder + '.tar.bz2' )


To transform it into an iso2zip command-line :

os.system( 'zip -r' + folder + '.zip' + folder )
os.system( 'chmod -R 777 ' + folder + '.zip' )


To transform it into an iso2rar command-line :

Wait, you don't really want to do that, do you !!


If you know a better way to handle ISO files, please drop a comment ! ( no registration required )



EDIT 1 :
Check out this program : Kiso
Strangely you need to run it as root ( ??? ).











EDIT 2 :
The archiver "File-roller" can extract ISO file. Well, sometimes.


EDIT 3 :
http://www.acetoneteam.org/


Last updated : July 2007

8 comments :

Anonymous said...

Thanks for this helpful post:)

Anonymous said...

Why so much perl? It takes just one line to make an ISO:

cp /dev/cdrom file.iso

Note that if the CD is copy-protected, this won't work (the subchannel Q data isn't copied). You'll need cdrdao or the like.

Anonymous said...

Wow! Imprssive.

I am tring to move to Linux and thinking about Ubuntu
http://www.ubuntulinux.jp/

Since I am stil using WinXP, how can I make a ISO Image burn to CD under Windows?

Also can you give me Linmodem info too? I have HSP56MR modem made by PcTel. I would like to know this soft modem/winmodem can be use as Linmodem or not?

And last, but not the least, how can I listen to your Podcast ne0-san
is mentioning? Thank you.

Anonymous said...

to shamelessly pimp my app :) take a look at ISO Master: http://littlesvr.ca/isomaster/

Anonymous said...

hi!
file-roller is quite useless because if the iso has a lot of files and nested directories it just hangs.

Poor Yorick said...

Also shamelessly pimping my own software:

http://sourceforge.net/projects/uniso/

Same principle as the above script, but also faithfully reproduces hard links, times, and permissions

Anonymous said...

super ton site lache pas
belle photo

viens voir !!!!!!!!!!!!!!!!
http://www.e-monsite.com/pleinsdegains

Anonymous said...

To be honest, i don't really see why you are using a Python script. You could replace it with Bash, since you are actually just calling os.system() where you could use Builtin functions from Python. None of these scripts are system-independent.