Mailinglist Archive: opensuse-factory (757 mails)

< Previous Next >
sudo, makeSUSEdvd, and iso images
If it helps with avoiding root any, attached you will find the "isox"
perl script which uses the isoinfo program (the same one that
file-roller uses) to extract all the files from an iso image.

Doesn't need to be root, just needs read permissions on the iso
and write permissions where it creates the copy of all the files.

I hereby declare this script to be public domain (because I sure
don't want to maintain it :-). Do what you will with it.

It does have some restrictions. For one thing the isoinfo program
won't report anything more than the day for timestamps, so it can't
reproduce the timestamp info very accurately (but it does what
it can). It assumes the iso image has the "Rock Ridge" extensions
so that the permission strings will be sensible in the isoinfo
output (probably get all files with 000 mode if the iso doesn't
have the extension).

But it does seem to work. I've extracted some isos and compared them
to the mounted image and the contents of the files certainly seem
to match.

: # feed this into perl -w
eval 'exec perl -w -S $0 ${1+"$@"}'
if 0;
#
# TODO:
# Keep track of "inode" number to reconstruct hard links.
#
use strict;
use Getopt::Long;
use File::Copy;
use Time::Local;

my %months;
$months{'Jan'} = 0;
$months{'Feb'} = 1;
$months{'Mar'} = 2;
$months{'Apr'} = 3;
$months{'May'} = 4;
$months{'Jun'} = 5;
$months{'Jul'} = 6;
$months{'Aug'} = 7;
$months{'Sep'} = 8;
$months{'Oct'} = 9;
$months{'Nov'} = 10;
$months{'Dec'} = 11;

my $help = 0;

if (! GetOptions("help|H|?" => \$help)) {
die "See isox --help for usage info.\n";
}
if ($help) {
print "isox - extract files from iso image to a directory

usage: isox [--help] isofile directory

--help Print this message and exit.

Uses the isoinfo utility to extract the directory structure and files
from an iso image, creating directory and storing all the files in it.\n";
exit(0);
}

if (scalar(@ARGV) != 2) {
die "Must have exactly two arguments, run with --help for usage.\n";
}

if (! -r $ARGV[0]) {
die "Cannot read iso file: $!\n";
}

if (-e $ARGV[1]) {
die "$ARGV[1] already exists, will not overwrite.\n";
}

# The dirlist array will contain all the directory names and permission
# strings and timestamp for each directory.

my @dirlist;

# Much like dirlist, the filelist array will contain all the file names
# and permission strings, and timestamp.

my @filelist;

# translate ls -l style permission string into a mode value
#
sub permval {
my $perms = shift;
$perms=~s/[d-]/0/g;
$perms=~s/[^0]/1/g;
return oct("0b$perms");
}

# Run isoinfo to read the list of directories and files and build up
# the dirlist and filelist arrays...

my $fh;
my $lastdirname;
my $perms;
my $file;
my $month;
my $day;
my $year;
my $stamp;
open($fh, '-|', "isoinfo -l -R -i '$ARGV[0]'") ||
die "Cannot run command isoinfo -l -R -i '$ARGV[0]' : $!\n";
while (<$fh>) {
chomp;
if (/^Directory listing of (.+)$/) {
$lastdirname = $1;
} elsif (/^(\S+)\s+\d+\s+\d+\s+\d+\s+\d+\s+(\S+)\s+(\d+)\s+(\d+)\s+\[\s*\d+\s+\d+\] (.+)$/) {
$perms = $1;
$month = $2;
$day = $3;
$year = $4;
$file = $5;

# Sigh.. The isoinfo program apparently adds 1 space to the end of
# all the file names, so chop it off if there is a space there.

if ($file=~/\s+$/) {
chop($file);
}

# Unfortunately isoinfo won't tell us more than the day, so
# midnight is as close as we can get to the time.

$stamp = timelocal(0,0,0,$day+0,$months{$month},$year+0);

if ($perms=~/^d/) {
if ($file eq ".") {
push(@dirlist, [ $lastdirname, $perms, $stamp ]);
}
} else {
push(@filelist, [ "${lastdirname}$file", $perms, $stamp ]);
}
}
}
close($fh);

# Now run through the dirlist, creating all the directories writable
# by me (so I have permission to write the files).

my $root=$ARGV[1];
foreach $_ (@dirlist) {
$file = ${$_}[0];
$file = "${root}$file";
if (! mkdir($file, 0700)) {
die "Unable to create directory $file : $!\n";
}
}

# Once the directories are there, we can write the files by extracting
# each one using isoinfo and File::Copy to write stdout from isoinfo
# to disk.

foreach $_ (@filelist) {
$file = ${$_}[0];
$perms = ${$_}[1];
$stamp = ${$_}[2];
print "Extracting: $file ...\n";
my $origmask = umask(077);
open($fh, '-|', "isoinfo -R -i '$ARGV[0]' -x '$file'") ||
die "Cannot run isoinfo -R -i '$ARGV[0]' -x '$file' : $!\n";
copy($fh, "${root}$file");
close($fh);
umask($origmask);
utime($stamp, $stamp, "${root}$file");
chmod(permval($perms), "${root}$file");
}

# Now that we have extracted all the file, it is safe to utime and chmod the
# directories (in reverse order so we will do the deep ones first).

while (scalar(@dirlist) > 0) {
$_ = pop(@dirlist);
$file = ${$_}[0];
$file = "${root}$file";
$perms = ${$_}[1];
$stamp = ${$_}[2];
utime($stamp, $stamp, $file);
chmod(permval($perms), $file);
}
< Previous Next >
List Navigation
Follow Ups