home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2604 < prev    next >
Encoding:
Internet Message Format  |  1991-01-24  |  5.5 KB

  1. From: ronald@robobar.co.uk (Ronald S H Khoo)
  2. Newsgroups: alt.sources,comp.lang.perl
  3. Subject: simple tarfilter in perl (WAS Re: mtf, part 1 of 2)
  4. Message-ID: <1991Jan23.175822.24238@robobar.co.uk>
  5. Date: 23 Jan 91 17:58:22 GMT
  6.  
  7. Archive-Name: perl-sources/mtf.pl
  8.  
  9. goer@quads.uchicago.edu (Richard L. Goerwitz) writes:
  10.  
  11. > X#  PURPOSE: Maps 15+ char. filenames in a tar archive to 14 chars.
  12. > X#  to facilitate installation of tar'd archives on systems subject to
  13. > X#  the System V 14-character filename limit.
  14.  
  15. [ introduces his Icon program "mtf" ]
  16. I can't comment on that program because I don't speak Icon....
  17.  
  18. > X#  Final word of caution:  Try not to use mtf on binaries.  It cannot
  19. > X#  possibly preserve the correct format and alignment of strings in an
  20. > X#  executable.
  21.  
  22. Things written in perl tend to be binary friendly.  Here's a less fully
  23. featured mtf in perl.  Mine's a simple filter, no arguments.  Report
  24. goes to stderr, redirect with your shell to taste.
  25.  
  26. Actually, there's no reason it shouldn't have been written as a complete
  27. tar replacement program, it wouldn't have been much bigger.   Has anyone
  28. thought of re-implementing most of /bin in perl ?  It would make for
  29. a much smaller system distribution kit :-)
  30.  
  31. ObPerlQuestion:  If I want to be able to map both forwards and backwards
  32.          key->value and value->key, is there a less memory intensive
  33.          way of doing it other than having two separate assoc
  34.          arrays (as in %map and %revmap below), which can get expensive
  35.          if the values are large ?
  36.  
  37. #! /usr/bin/perl
  38. # filter a tar stream converting file path components to <= 14 chars for SysV
  39. # bugs: doesn't preserve null padding at end, use dd if you need it :-)
  40. # Ronald Khoo <ronald@robobar.co.uk> hacked this together because
  41. # Richard Goerwitz <goer@sophist.uchicago.edu> posted a nice one in Icon.
  42. # His has more features but this one is binary clean and I Can Understand It:-)
  43. # normal usage: zcat < dist.tar.Z | this_script 2>transcript | tar xf -
  44. # leaves the filename mapping on "transcript".
  45. eval 'exec /usr/bin/perl -S $0 ${1+"$@"}' # OK, so I don't use the args yet...
  46.     if 0;
  47.  
  48. die "Get a newer Perl\n" if $] < 3.044; # is this when checksums first made it?
  49. # open(STDERR, ">/dev/null");    # uncomment this line for silent operation.
  50. $output = 1;            # set to zero for no output
  51. $stop_at_null = 1;         # set to zero when hacking at broken tarfiles.
  52. $maxlen = 14;            # 14 is max length of Sys V R < 4 files
  53.  
  54. # people stuff all kindsa junk in $tar_the_rest, but these are enuff...
  55. $tar_hdr = "a100a8a8a8a12a12a8a1a100a*";
  56. $tar_name        =  0;    $tar_mode        =  1;
  57. $tar_uid        =  2;    $tar_gid        =  3;
  58. $tar_size        =  4;    $tar_mtime        =  5;
  59. $tar_chksum        =  6;    $tar_linkflag        =  7;
  60. $tar_linkname        =  8;    $tar_the_rest        =  9;
  61.  
  62. $nullblock = "\0" x 512;
  63. $bad = $null = 0;
  64.  
  65. while (($nread = read(STDIN, $hdr, 512)) == 512) {
  66.     @H[0..9] = unpack($tar_hdr, $hdr);
  67.     $nhdr = pack($tar_hdr, @H[0..5], " " x 8, @H[7..9]);
  68.     $c = sprintf( "% 6o\0 ", unpack("%16C*", $nhdr));
  69.     ($name = $H[$tar_name]) =~ s/\0.*//;
  70.     ($linkname = $H[$tar_linkname]) =~ s/\0.*//;
  71. #    ($omode = $H[$tar_mode]) =~ s/^\s+//;
  72. #    $mode = oct($omode);
  73.     ($osize = $H[$tar_size]) =~ s/^\s+//;
  74.     $size = oct($osize);
  75.     if (length($name) && 0+$c == 0+$H[6]) {
  76.         if ($bad || $null) {
  77.             $bad && print STDERR "$bad bad + ";
  78.             print STDERR "$null null blocks skipped.\n";
  79.         }
  80.         $skipping = $bad = $null = 0;
  81.         $blocks = int($size / 512) + (($size % 512) ? 1 : 0);
  82.         if (($newnm = &munge($name)) ne $name) {
  83.             print STDERR "(renamed to $newnm) ";
  84.             $nhdr = pack($tar_hdr,$newnm,@H[1..5]," " x 8,@H[7..9]);
  85.             $c = sprintf( "% 6o\0 ", unpack("%16C*", $nhdr));
  86.             print pack($tar_hdr, $newnm, @H[1..5], $c, @H[7..9]);
  87.         } else
  88.             { print $hdr; }
  89.         if ($blocks == 0 && $name =~ m|/$|) {
  90.             print STDERR "$name: is a directory\n";
  91.         } elsif (0+$H[$tar_linkflag]) {
  92.             print STDERR "$name: linked to $linkname\n";
  93.         } else {
  94.             print STDERR "$name: $size bytes ($blocks tar blocks)\n";
  95.         }
  96. # try to gain a little efficiency by doing large reads....
  97. # 16 blks is supposedly good for BSD files, I don't have BSD but so what :-)
  98.         while ($blocks > 16) {
  99.             $blocks -= 16;
  100.             read(STDIN, $hdr, 8192)==8192 || die "Premature EOF\n";
  101.             print $hdr if $output;
  102.         }
  103.         for (1..$blocks) {
  104.             read(STDIN, $hdr, 512) == 512 || die "Premature EOF\n";
  105.             print $hdr if $output;
  106.         }
  107.     } else {
  108.         $isnull = ($hdr eq $nullblock);
  109.         print STDERR "Skipping ... " if (! $isnull && $skipping++ == 0);
  110.         $isnull ? ($stop_at_null? &quit: $null++): $bad++;
  111.         print $hdr if $output;
  112.     }
  113. }
  114. $bad && print STDERR "$bad bad + ";
  115. ($bad || $null) && print STDERR "$null null blocks skipped at the end.\n";
  116. $nread && print STDERR "Partial block ($nread) bytes ignored at the end.\n";
  117. exit 1;
  118.  
  119. sub quit { print $nullblock x 2 if $output; exit 0; }
  120.  
  121. sub munge { # munge a whole path
  122.     local($", $orig, $head, $tail, @out) = ("/", @_);
  123.     $head = (substr($orig, 0, 1) eq "/")? "/": "";
  124.     $tail = (substr($orig, -1) eq "/")? "/": "";
  125.     @in = split('/', $orig);
  126.     while (defined($next = shift @in)) {
  127.         next unless length($next);
  128.         push(@out, (length($next) > $maxlen) ? &cmunge($next) : $next);
  129.     }
  130.     return $head . "@out" . $tail;
  131. }
  132.  
  133. sub cmunge { # munge one component of a path
  134.     local($aa, $name, $trunc, $suff) = ("00", @_);
  135.     return $map{$name} if $map{$name};
  136.     if (substr($name, -2, 1) eq ".") {
  137.         $trunc = substr($name, 0, $maxlen - 4);
  138.         $suff =  substr($name, -2);
  139.     } else {
  140.         $trunc = substr($name, 0, $maxlen - 2);
  141.         $suff = "";
  142.     }
  143.     $aa++ while ($revmap{"$trunc$aa$suff"});
  144.     $revmap{"$trunc$aa$suff"} = $name;
  145.     $map{$name} = "$trunc$aa$suff";
  146. }
  147. __END__
  148. Just another Perl Wannabe,
  149. -- 
  150. Ronald Khoo <ronald@robobar.co.uk> +44 81 991 1142 (O) +44 71 229 7741 (H)
  151.