/home/uherbst/Daten/Projekte/ServDoc/servdoc/tools/separ.pl
#!/usr/bin/perl
# This script is a lightly modified version of the script on
# http://www.perlmonks.org/index.pl?node_id=101426
#
# Changes:
# - symlinks will be copied as symlinks, not as flat files.
# - execute-rights will be preserved.
#
# Usage:
# perl separ.pl [-l] [-s autostartscript] <fileOrDir> [...] > archive
#
# -l: Don't copy symlinks as flat files but as symlinks (this is
# useless for links outside your archive dir!)
#
# -s autostartscript:
# Without that option, your selfextracting perl archive will create
# your original files or directories and then stop.
# With that option, your selfextracting perl archive will create a
# temporary dir, cd to that tempdir, create there your archives,
# start there your autstartscript, and after that it will remove
# that tempdir.
#
#--------------------------------------------------------------------
#
# Creates self-extracting archives that use Perl to extract.
# Will make directories on extraction, but parents of top-level
# directories must exist and be writable.
#
# Outputs self-extracting archive to stdout.
# Arguments that are directories will be recursed into.
#
# To make an archive:
# perl separ.pl <fileOrDir> [...] > archive
#
# To unpack an archive:
# perl archive
#
# Uses no external modules for decompression.
# File format is: extractor program (Perl) at top,
# __DATA__ tag,
# multiple files, uuencoded.
# There may be "mkdir" lines before files.
#
# By Ned Konz, perl@bike-nomad.com
# encode() derived from Tom Christensen's PPT version of uuencode
# decoder based on code by Nick Ing-Simmons and Tom Christiansen
#
#--------------------------------------------------------------------
#
use strict;
use File::Find;
use Getopt::Std;
sub encode {
my ( $source, $destination, $mode ) = @_;
if ( $source eq '-' && -t STDIN ) {
warn "$0: WARNING: reading from standard input\n";
}
printf "begin %03o $destination\012", $mode || 0644;
local *INPUT;
open( INPUT, "< $source" ) || die "can't open $source: $!";
binmode(INPUT);
my $block;
print pack( "u", $block ) while read( INPUT, $block, 45 );
print "`\012";
print "end\012";
close(INPUT) || die "can't close $source: $!";
}
getopts('ls:');
my $AUTOSTART = "";
if ($Getopt::Std::opt_s) {
$AUTOSTART = "my \$AUTOSTART = \"$Getopt::Std::opt_s\";";
}
# copy the extractor
while (<DATA>) {
s/\# AUTOSTART/$AUTOSTART/o;
print $_;
}
# now encode the files with relative path names
$File::Find::dont_use_nlink = 1;
for my $arg (@ARGV) {
my $ignoreLength = length($arg) + 1;
File::Find::find(
{
no_chdir => 1,
wanted => sub {
my $name = $File::Find::name;
return if ( $name =~ /CVS/ );
my $mode = $name eq '-' ? 0777 : ( stat($name) )[2];
if ( -d _ ) {
$mode &= 0777;
printf( "mkdir %03o %s\012", $mode || 0777, $name );
return;
}
if ( -l "$name" && $Getopt::Std::opt_l ) {
printf( "symlink %s %s\012", readlink($name), $name );
return;
}
# encode( $name, $name, $mode & 0666 );
encode( $name, $name, $mode );
},
},
$arg
);
}
__DATA__
#!/usr/bin/perl
use strict;
# This is a self-extracting archive that requires Perl to extract.
BEGIN { $/ = "\012" }
# AUTOSTART
my $debug=0;
my $TEMPDIR="separ.$$";
if ($AUTOSTART) {
mkdir $TEMPDIR,0777 or die "Can't make directory $TEMPDIR: $!\n";
chdir $TEMPDIR
}
while (<DATA>) {
# attempt to be robust if someone edits this file in a different OS
$_ =~ s/[\r\n]+$//s;
next
unless my ( $op, $mode, $file ) = /^(begin|mkdir|symlink)\s+(\S+)\s+(.*)/s;
if ( $op eq 'mkdir' ) {
if ( !-d $file ) {
print STDERR "making directory $file\n" if ( $debug);
mkdir $file, 0777 or die "Can't make directory $file: $!\n";
}
next;
}
if ( $op eq 'symlink' ) {
print STDERR "making symlink $mode -> $file\n" if ( $debug);
symlink $mode,$file or die "Can't make symlink $file: $!\n";
next;
}
my $foundEnd = 0;
print STDERR "extracting file $file\n" if ( $debug);
open( OUT, ">$file" ) or die "Can't create $file: $!\n";
binmode(OUT);
while (<DATA>) {
$_ =~ s/[\r\n]+$//s;
if (/^end/) { $foundEnd++; last }
next if /[a-z]/;
next
unless int( ( ( ( ord() - 32 ) & 077 ) + 2 ) / 3 ) == int( length() / 4 );
print OUT unpack( "u", $_ ) or die "can't write $file: $!";
}
close(OUT) or die "can't close $file: $!";
chmod oct($mode), $file or die "can't chmod $file to $mode: $!\n";
$foundEnd or die "Missing end: $file may be truncated.\n";
}
if ($AUTOSTART) {
print STDERR "running $AUTOSTART @ARGV" if ( $debug);
system "$AUTOSTART @ARGV";
chdir "..";
system "rm -rf $TEMPDIR";
}
__DATA__