1b39c5158SmillertBEGIN { chdir 't' if -d 't' } 2b39c5158Smillert 3b39c5158Smillertuse Test::More 'no_plan'; 4b39c5158Smillertuse strict; 5b39c5158Smillertuse lib '../lib'; 6b39c5158Smillert 7b39c5158Smillertuse Cwd; 8b39c5158Smillertuse Config; 9b39c5158Smillertuse IO::File; 10b39c5158Smillertuse File::Copy; 11b39c5158Smillertuse File::Path; 12b39c5158Smillertuse File::Spec (); 13b39c5158Smillertuse File::Spec::Unix (); 14b39c5158Smillertuse File::Basename (); 15b39c5158Smillertuse Data::Dumper; 16b39c5158Smillert 17b39c5158Smillert### need the constants at compile time; 18b39c5158Smillertuse Archive::Tar::Constant; 19b39c5158Smillert 20b39c5158Smillertmy $Class = 'Archive::Tar'; 21b39c5158Smillertmy $FClass = $Class . '::File'; 22b39c5158Smillertuse_ok( $Class ); 23b39c5158Smillert 24b39c5158Smillert 25b39c5158Smillert 26b39c5158Smillert### XXX TODO: 27b39c5158Smillert### * change to fullname 28b39c5158Smillert### * add tests for global variables 29b39c5158Smillert 30b39c5158Smillert### set up the environment ### 31b39c5158Smillertmy @EXPECT_NORMAL = ( 32b39c5158Smillert ### dirs filename contents 33b39c5158Smillert [ [], 'c', qr/^iiiiiiiiiiii\s*$/ ], 34b39c5158Smillert [ [], 'd', qr/^uuuuuuuu\s*$/ ], 35b39c5158Smillert); 36b39c5158Smillert 37b39c5158Smillert### includes binary data 38b39c5158Smillertmy $ALL_CHARS = join '', "\r\n", map( chr, 1..255 ), "zzz\n\r"; 39b39c5158Smillert 40b39c5158Smillert### @EXPECTBIN is used to ensure that $tarbin is written in the right 41b39c5158Smillert### order and that the contents and order match exactly when extracted 42b39c5158Smillertmy @EXPECTBIN = ( 43b39c5158Smillert ### dirs filename contents ### 44b39c5158Smillert [ [], 'bIn11', $ALL_CHARS x 11 ], 45b39c5158Smillert [ [], 'bIn3', $ALL_CHARS x 3 ], 46b39c5158Smillert [ [], 'bIn4', $ALL_CHARS x 4 ], 47b39c5158Smillert [ [], 'bIn1', $ALL_CHARS ], 48b39c5158Smillert [ [], 'bIn2', $ALL_CHARS x 2 ], 49b39c5158Smillert); 50b39c5158Smillert 51b39c5158Smillert### @EXPECTX is used to ensure that $tarx is written in the right 52b39c5158Smillert### order and that the contents and order match exactly when extracted 53b39c5158Smillert### the 'x/x' extraction used to fail before A::T 1.08 54b39c5158Smillertmy @EXPECTX = ( 55b39c5158Smillert ### dirs filename contents 56b39c5158Smillert [ [ 'x' ], 'k', '', ], 57b39c5158Smillert [ [ 'x' ], 'x', 'j', ], # failed before A::T 1.08 58b39c5158Smillert); 59b39c5158Smillert 60b39c5158Smillertmy $LONG_FILE = qq[directory/really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-really-long-directory-name/myfile]; 61b39c5158Smillert 62b39c5158Smillert### wintendo can't deal with too long paths, so we might have to skip tests ### 63b39c5158Smillertmy $TOO_LONG = ($^O eq 'MSWin32' or $^O eq 'cygwin' or $^O eq 'VMS') 64b39c5158Smillert && length( cwd(). $LONG_FILE ) > 247; 65b39c5158Smillert 66898184e3Ssthenif(!$TOO_LONG) { 67898184e3Ssthen my $alt = File::Spec->catfile( cwd(), $LONG_FILE); 68898184e3Ssthen eval 'mkpath([$alt]);'; 69898184e3Ssthen if($@) 70898184e3Ssthen { 71898184e3Ssthen $TOO_LONG = 1; 72898184e3Ssthen } 73898184e3Ssthen else 74898184e3Ssthen { 75898184e3Ssthen $@ = ''; 76898184e3Ssthen my $base = File::Spec->catfile( cwd(), 'directory'); 77898184e3Ssthen rmtree $base; 78898184e3Ssthen } 79898184e3Ssthen} 80b39c5158Smillert### warn if we are going to skip long file names 81b39c5158Smillertif ($TOO_LONG) { 82b39c5158Smillert diag("No long filename support - long filename extraction disabled") if ! $ENV{PERL_CORE}; 83b39c5158Smillert} else { 84b39c5158Smillert push @EXPECT_NORMAL, [ [], $LONG_FILE, qr/^hello\s*$/]; 85b39c5158Smillert} 86b39c5158Smillert 87b39c5158Smillertmy @ROOT = grep { length } 'src', $TOO_LONG ? 'short' : 'long'; 88b39c5158Smillertmy $NO_UNLINK = $ARGV[0] ? 1 : 0; 89b39c5158Smillert 90b39c5158Smillert### enable debugging? 91b39c5158Smillert### pesky warnings 92b39c5158Smillert$Archive::Tar::DEBUG = $Archive::Tar::DEBUG = 1 if $ARGV[1]; 93b39c5158Smillert 94b39c5158Smillert### tests for binary and x/x files 95b39c5158Smillertmy $TARBIN = $Class->new; 96b39c5158Smillertmy $TARX = $Class->new; 97b39c5158Smillert 98b39c5158Smillert### paths to a .tar and .tgz file to use for tests 99b39c5158Smillertmy $TAR_FILE = File::Spec->catfile( @ROOT, 'bar.tar' ); 100b39c5158Smillertmy $TGZ_FILE = File::Spec->catfile( @ROOT, 'foo.tgz' ); 101b39c5158Smillertmy $TBZ_FILE = File::Spec->catfile( @ROOT, 'foo.tbz' ); 102de8cc8edSafresh1my $TXZ_FILE = File::Spec->catfile( @ROOT, 'foo.txz' ); 103b39c5158Smillertmy $OUT_TAR_FILE = File::Spec->catfile( @ROOT, 'out.tar' ); 104b39c5158Smillertmy $OUT_TGZ_FILE = File::Spec->catfile( @ROOT, 'out.tgz' ); 105b39c5158Smillertmy $OUT_TBZ_FILE = File::Spec->catfile( @ROOT, 'out.tbz' ); 106de8cc8edSafresh1my $OUT_TXZ_FILE = File::Spec->catfile( @ROOT, 'out.txz' ); 107b39c5158Smillert 108b39c5158Smillertmy $COMPRESS_FILE = 'copy'; 109b39c5158Smillert$^O eq 'VMS' and $COMPRESS_FILE .= '.'; 110b39c5158Smillertcopy( File::Basename::basename($0), $COMPRESS_FILE ); 111b39c5158Smillertchmod 0644, $COMPRESS_FILE; 112b39c5158Smillert 113b39c5158Smillert### done setting up environment ### 114b39c5158Smillert 115de8cc8edSafresh1### check for zlib/bzip2/xz support 116de8cc8edSafresh1{ for my $meth ( qw[has_zlib_support has_bzip2_support has_xz_support] ) { 117b39c5158Smillert can_ok( $Class, $meth ); 118b39c5158Smillert } 119b39c5158Smillert} 120b39c5158Smillert 121b39c5158Smillert 122b39c5158Smillert 123b39c5158Smillert### tar error tests 124b39c5158Smillert{ my $tar = $Class->new; 125b39c5158Smillert 126b39c5158Smillert ok( $tar, "Object created" ); 127b39c5158Smillert isa_ok( $tar, $Class ); 128b39c5158Smillert 129b39c5158Smillert local $Archive::Tar::WARN = 0; 130b39c5158Smillert 131b39c5158Smillert ### should be empty to begin with 132b39c5158Smillert is( $tar->error, '', "The error string is empty" ); 133b39c5158Smillert 134b39c5158Smillert ### try a read on nothing 135b39c5158Smillert my @list = $tar->read(); 136b39c5158Smillert 137b39c5158Smillert ok(!(scalar @list), "Function read returns 0 files on error" ); 138b39c5158Smillert ok( $tar->error, " error string is non empty" ); 139b39c5158Smillert like( $tar->error, qr/No file to read from/, 140b39c5158Smillert " error string from create()" ); 141b39c5158Smillert unlike( $tar->error, qr/add/, " error string does not contain add" ); 142b39c5158Smillert 143b39c5158Smillert ### now, add empty data 144b39c5158Smillert my $obj = $tar->add_data( '' ); 145b39c5158Smillert 146b39c5158Smillert ok( !$obj, "'add_data' returns undef on error" ); 147b39c5158Smillert ok( $tar->error, " error string is non empty" ); 148b39c5158Smillert like( $tar->error, qr/add/, " error string contains add" ); 149b39c5158Smillert unlike( $tar->error, qr/create/," error string does not contain create" ); 150b39c5158Smillert 151b39c5158Smillert ### check if ->error eq $error 152b39c5158Smillert is( $tar->error, $Archive::Tar::error, 153b39c5158Smillert "Error '$Archive::Tar::error' matches $Class->error method" ); 154b39c5158Smillert 155b39c5158Smillert ### check that 'contains_file' doesn't warn about missing files. 156b39c5158Smillert { ### turn on warnings in general! 157b39c5158Smillert local $Archive::Tar::WARN = 1; 158b39c5158Smillert 159b39c5158Smillert my $warnings = ''; 160b39c5158Smillert local $SIG{__WARN__} = sub { $warnings .= "@_" }; 161b39c5158Smillert 162b39c5158Smillert my $rv = $tar->contains_file( $$ ); 163b39c5158Smillert ok( !$rv, "Does not contain file '$$'" ); 164b39c5158Smillert is( $warnings, '', " No warnings issued during lookup" ); 165b39c5158Smillert } 166b39c5158Smillert} 167b39c5158Smillert 168256a93a4Safresh1my $ebcdic_skip_msg = "File contains an alien character set"; 169256a93a4Safresh1 170b39c5158Smillert### read tests ### 171256a93a4Safresh1SKIP: { 172256a93a4Safresh1 my @to_try; 173256a93a4Safresh1 174256a93a4Safresh1 if (ord 'A' == 65) { 175256a93a4Safresh1 push @to_try, $TAR_FILE; 176b39c5158Smillert push @to_try, $TGZ_FILE if $Class->has_zlib_support; 177b39c5158Smillert push @to_try, $TBZ_FILE if $Class->has_bzip2_support; 178de8cc8edSafresh1 push @to_try, $TXZ_FILE if $Class->has_xz_support; 179256a93a4Safresh1 } 180256a93a4Safresh1 else { 181256a93a4Safresh1 skip $ebcdic_skip_msg, 4; 182256a93a4Safresh1 } 183b39c5158Smillert 184b39c5158Smillert for my $type( @to_try ) { 185b39c5158Smillert 186b39c5158Smillert ### normal tar + gz compressed file 187b39c5158Smillert my $tar = $Class->new; 188b39c5158Smillert 189b39c5158Smillert ### check we got the object 190b39c5158Smillert ok( $tar, "Object created" ); 191b39c5158Smillert isa_ok( $tar, $Class ); 192b39c5158Smillert 193b39c5158Smillert ### ->read test 194b39c5158Smillert my @list = $tar->read( $type ); 195b39c5158Smillert my $cnt = scalar @list; 196b39c5158Smillert my $expect = scalar __PACKAGE__->get_expect(); 197b39c5158Smillert 198b39c5158Smillert ok( $cnt, "Reading '$type' using 'read()'" ); 199b39c5158Smillert is( $cnt, $expect, " All files accounted for" ); 200b39c5158Smillert 201b39c5158Smillert for my $file ( @list ) { 202b39c5158Smillert ok( $file, " Got File object" ); 203b39c5158Smillert isa_ok( $file, $FClass ); 204b39c5158Smillert 205b39c5158Smillert ### whitebox test -- make sure find_entry gets the 206b39c5158Smillert ### right files 207b39c5158Smillert for my $test ( $file->full_path, $file ) { 208b39c5158Smillert is( $tar->_find_entry( $test ), $file, 209b39c5158Smillert " Found proper object" ); 210b39c5158Smillert } 211b39c5158Smillert 212b39c5158Smillert next unless $file->is_file; 213b39c5158Smillert 214b39c5158Smillert my $name = $file->full_path; 215b39c5158Smillert my($expect_name, $expect_content) = 216b39c5158Smillert get_expect_name_and_contents( $name, \@EXPECT_NORMAL ); 217b39c5158Smillert 218b39c5158Smillert ### ->fullname! 219b39c5158Smillert ok($expect_name, " Found expected file '$name'" ); 220b39c5158Smillert 221b39c5158Smillert like($tar->get_content($name), $expect_content, 222b39c5158Smillert " Content OK" ); 223b39c5158Smillert } 224b39c5158Smillert 225b39c5158Smillert 226b39c5158Smillert ### list_archive test 227b39c5158Smillert { my @list = $Class->list_archive( $type ); 228b39c5158Smillert my $cnt = scalar @list; 229b39c5158Smillert my $expect = scalar __PACKAGE__->get_expect(); 230b39c5158Smillert 231b39c5158Smillert ok( $cnt, "Reading '$type' using 'list_archive'"); 232b39c5158Smillert is( $cnt, $expect, " All files accounted for" ); 233b39c5158Smillert 234b39c5158Smillert for my $file ( @list ) { 235b39c5158Smillert next if __PACKAGE__->is_dir( $file ); # directories 236b39c5158Smillert 237b39c5158Smillert my($expect_name, $expect_content) = 238b39c5158Smillert get_expect_name_and_contents( $file, \@EXPECT_NORMAL ); 239b39c5158Smillert 240b39c5158Smillert ok( $expect_name, 241b39c5158Smillert " Found expected file '$file'" ); 242b39c5158Smillert } 243b39c5158Smillert } 244b39c5158Smillert } 245b39c5158Smillert} 246b39c5158Smillert 247b39c5158Smillert### add files tests ### 248b39c5158Smillert{ my @add = map { File::Spec->catfile( @ROOT, @$_ ) } ['b']; 249b39c5158Smillert my @addunix = map { File::Spec::Unix->catfile( @ROOT, @$_ ) } ['b']; 250b39c5158Smillert my $tar = $Class->new; 251b39c5158Smillert 252b39c5158Smillert ### check we got the object 253b39c5158Smillert ok( $tar, "Object created" ); 254b39c5158Smillert isa_ok( $tar, $Class ); 255b39c5158Smillert 256b39c5158Smillert ### add the files 257b39c5158Smillert { my @files = $tar->add_files( @add ); 258b39c5158Smillert 259b39c5158Smillert is( scalar @files, scalar @add, 260b39c5158Smillert " Adding files"); 261b39c5158Smillert is( $files[0]->name,'b', " Proper name" ); 262b39c5158Smillert 263b39c5158Smillert SKIP: { 264b39c5158Smillert skip( "You are building perl using symlinks", 1) 265b39c5158Smillert if ($ENV{PERL_CORE} and $Config{config_args} =~/Dmksymlinks/); 266b39c5158Smillert 267b39c5158Smillert is( $files[0]->is_file, 1, 268b39c5158Smillert " Proper type" ); 269b39c5158Smillert } 270b39c5158Smillert 271b39c5158Smillert like( $files[0]->get_content, qr/^bbbbbbbbbbb\s*$/, 272b39c5158Smillert " Content OK" ); 273b39c5158Smillert 274b39c5158Smillert ### check if we have then in our tar object 275b39c5158Smillert for my $file ( @addunix ) { 276b39c5158Smillert ok( $tar->contains_file($file), 277b39c5158Smillert " File found in archive" ); 278b39c5158Smillert } 279b39c5158Smillert } 280b39c5158Smillert 281b39c5158Smillert ### check adding files doesn't conflict with a secondary archive 282b39c5158Smillert ### old A::T bug, we should keep testing for it 283b39c5158Smillert { my $tar2 = $Class->new; 284b39c5158Smillert my @added = $tar2->add_files( $COMPRESS_FILE ); 285b39c5158Smillert my @count = $tar2->list_files; 286b39c5158Smillert 287b39c5158Smillert is( scalar @added, 1, " Added files to secondary archive" ); 288b39c5158Smillert is( scalar @added, scalar @count, 289b39c5158Smillert " No conflict with first archive" ); 290b39c5158Smillert 291b39c5158Smillert ### check the adding of directories 292b39c5158Smillert my @add_dirs = File::Spec->catfile( @ROOT ); 293b39c5158Smillert my @dirs = $tar2->add_files( @add_dirs ); 294b39c5158Smillert is( scalar @dirs, scalar @add_dirs, 295b39c5158Smillert " Adding dirs"); 296b39c5158Smillert ok( $dirs[0]->is_dir, " Proper type" ); 297b39c5158Smillert } 298b39c5158Smillert 299b39c5158Smillert ### check if we can add a A::T::File object 300b39c5158Smillert { my $tar2 = $Class->new; 301b39c5158Smillert my($added) = $tar2->add_files( $add[0] ); 302b39c5158Smillert 303b39c5158Smillert ok( $added, " Added a file '$add[0]' to new object" ); 304b39c5158Smillert isa_ok( $added, $FClass, " Object" ); 305b39c5158Smillert 306b39c5158Smillert my($added2) = $tar2->add_files( $added ); 307b39c5158Smillert ok( $added2, " Added an $FClass object" ); 308b39c5158Smillert isa_ok( $added2, $FClass, " Object" ); 309b39c5158Smillert 310b39c5158Smillert is_deeply( [$added, $added2], [$tar2->get_files], 311b39c5158Smillert " All files accounted for" ); 312b39c5158Smillert isnt( $added, $added2, " Different memory allocations" ); 313b39c5158Smillert } 314b39c5158Smillert} 315b39c5158Smillert 316b39c5158Smillert### add data tests ### 317b39c5158Smillert{ 318b39c5158Smillert { ### standard data ### 319b39c5158Smillert my @to_add = ( 'a', 'aaaaa' ); 320b39c5158Smillert my $tar = $Class->new; 321b39c5158Smillert 322b39c5158Smillert ### check we got the object 323b39c5158Smillert ok( $tar, "Object created" ); 324b39c5158Smillert isa_ok( $tar, $Class ); 325b39c5158Smillert 326b39c5158Smillert ### add a new file item as data 327b39c5158Smillert my $obj = $tar->add_data( @to_add ); 328b39c5158Smillert 329b39c5158Smillert ok( $obj, " Adding data" ); 330b39c5158Smillert is( $obj->name, $to_add[0], " Proper name" ); 331b39c5158Smillert is( $obj->is_file, 1, " Proper type" ); 332b39c5158Smillert like( $obj->get_content, qr/^$to_add[1]\s*$/, 333b39c5158Smillert " Content OK" ); 334b39c5158Smillert } 335b39c5158Smillert 336b39c5158Smillert { ### binary data + 337b39c5158Smillert ### dir/file structure -- x/y always went ok, x/x used to extract 338b39c5158Smillert ### in the wrong way -- this test catches that 339b39c5158Smillert for my $list ( [$TARBIN, \@EXPECTBIN], 340b39c5158Smillert [$TARX, \@EXPECTX], 341b39c5158Smillert ) { 342b39c5158Smillert ### XXX GLOBAL! changes may affect other tests! 343b39c5158Smillert my($tar,$struct) = @$list; 344b39c5158Smillert 345b39c5158Smillert for my $aref ( @$struct ) { 346b39c5158Smillert my ($dirs,$file,$data) = @$aref; 347b39c5158Smillert 348b39c5158Smillert my $path = File::Spec::Unix->catfile( 349b39c5158Smillert grep { length } @$dirs, $file ); 350b39c5158Smillert 351b39c5158Smillert my $obj = $tar->add_data( $path, $data ); 352b39c5158Smillert 353b39c5158Smillert ok( $obj, " Adding data '$file'" ); 354b39c5158Smillert is( $obj->full_path, $path, 355b39c5158Smillert " Proper name" ); 356b39c5158Smillert ok( $obj->is_file, " Proper type" ); 357b39c5158Smillert is( $obj->get_content, $data, 358b39c5158Smillert " Content OK" ); 359b39c5158Smillert } 360b39c5158Smillert } 361b39c5158Smillert } 362b39c5158Smillert} 363b39c5158Smillert 364b39c5158Smillert### rename/replace_content tests ### 365256a93a4Safresh1 366256a93a4Safresh1SKIP: { 367256a93a4Safresh1 skip $ebcdic_skip_msg, 9 if ord "A" != 65; 368256a93a4Safresh1 369256a93a4Safresh1 my $tar = $Class->new; 370b39c5158Smillert my $from = 'c'; 371b39c5158Smillert my $to = 'e'; 372b39c5158Smillert 373b39c5158Smillert ### read in the file, check the proper files are there 374b39c5158Smillert ok( $tar->read( $TAR_FILE ), "Read in '$TAR_FILE'" ); 375b39c5158Smillert ok( $tar->get_files($from), " Found file '$from'" ); 376b39c5158Smillert { local $Archive::Tar::WARN = 0; 377b39c5158Smillert ok(!$tar->get_files($to), " File '$to' not yet found" ); 378b39c5158Smillert } 379b39c5158Smillert 380b39c5158Smillert ### rename an entry, check the rename has happened 381b39c5158Smillert ok( $tar->rename( $from, $to ), " Renamed '$from' to '$to'" ); 382b39c5158Smillert ok( $tar->get_files($to), " File '$to' now found" ); 383b39c5158Smillert { local $Archive::Tar::WARN = 0; 384b39c5158Smillert ok(!$tar->get_files($from), " File '$from' no longer found'"); 385b39c5158Smillert } 386b39c5158Smillert 387b39c5158Smillert ### now, replace the content 388b39c5158Smillert my($expect_name, $expect_content) = 389b39c5158Smillert get_expect_name_and_contents( $from, \@EXPECT_NORMAL ); 390b39c5158Smillert 391b39c5158Smillert like( $tar->get_content($to), $expect_content, 392b39c5158Smillert "Original content of '$from' in '$to'" ); 393b39c5158Smillert ok( $tar->replace_content( $to, $from ), 394b39c5158Smillert " Set content for '$to' to '$from'" ); 395b39c5158Smillert is( $tar->get_content($to), $from, 396b39c5158Smillert " Content for '$to' is indeed '$from'" ); 397b39c5158Smillert} 398b39c5158Smillert 399b39c5158Smillert### remove tests ### 400256a93a4Safresh1SKIP: { 401256a93a4Safresh1 skip $ebcdic_skip_msg, 3 if ord "A" != 65; 402256a93a4Safresh1 403256a93a4Safresh1 my $remove = 'c'; 404b39c5158Smillert my $tar = $Class->new; 405b39c5158Smillert 406b39c5158Smillert ok( $tar->read( $TAR_FILE ), "Read in '$TAR_FILE'" ); 407b39c5158Smillert 408b39c5158Smillert ### remove returns the files left, which should be equal to list_files 409b39c5158Smillert is( scalar($tar->remove($remove)), scalar($tar->list_files), 410b39c5158Smillert " Removing file '$remove'" ); 411b39c5158Smillert 412b39c5158Smillert ### so what's left should be all expected files minus 1 413b39c5158Smillert is( scalar($tar->list_files), scalar(__PACKAGE__->get_expect) - 1, 414b39c5158Smillert " Proper files remaining" ); 415b39c5158Smillert} 416b39c5158Smillert 417b39c5158Smillert### write + read + extract tests ### 418b39c5158SmillertSKIP: { ### pesky warnings 419256a93a4Safresh1 skip $ebcdic_skip_msg, 326 if ord "A" != 65; 420256a93a4Safresh1 421b39c5158Smillert skip('no IO::String', 326) if !$Archive::Tar::HAS_PERLIO && 422b39c5158Smillert !$Archive::Tar::HAS_PERLIO && 423b39c5158Smillert !$Archive::Tar::HAS_IO_STRING && 424b39c5158Smillert !$Archive::Tar::HAS_IO_STRING; 425b39c5158Smillert 426b39c5158Smillert my $tar = $Class->new; 427b39c5158Smillert my $new = $Class->new; 428b39c5158Smillert ok( $tar->read( $TAR_FILE ), "Read in '$TAR_FILE'" ); 429b39c5158Smillert 430b39c5158Smillert for my $aref ( [$tar, \@EXPECT_NORMAL], 431b39c5158Smillert [$TARBIN, \@EXPECTBIN], 432b39c5158Smillert [$TARX, \@EXPECTX] 433b39c5158Smillert ) { 434b39c5158Smillert my($obj,$struct) = @$aref; 435b39c5158Smillert 436b39c5158Smillert ### check if we stringify it ok 437b39c5158Smillert { my $string = $obj->write; 438b39c5158Smillert ok( $string, " Stringified tar file has size" ); 439b39c5158Smillert cmp_ok( length($string) % BLOCK, '==', 0, 440b39c5158Smillert " Tar archive stringified" ); 441b39c5158Smillert } 442b39c5158Smillert 443b39c5158Smillert ### write tar tests 444b39c5158Smillert { my $out = $OUT_TAR_FILE; 445b39c5158Smillert 446b39c5158Smillert ### bug #41798: 'Nonempty $\ when writing a TAR file produces a 447b39c5158Smillert ### corrupt TAR file' shows that setting $\ breaks writing tar files 448b39c5158Smillert ### set it here purposely so we can verify NOTHING breaks 449b39c5158Smillert local $\ = 'FOOBAR'; 450b39c5158Smillert 451b39c5158Smillert { ### write() 452b39c5158Smillert ok( $obj->write($out), 453b39c5158Smillert " Wrote tarfile using 'write'" ); 454b39c5158Smillert check_tar_file( $out ); 455b39c5158Smillert check_tar_object( $obj, $struct ); 456b39c5158Smillert 457b39c5158Smillert ### now read it in again 458b39c5158Smillert ok( $new->read( $out ), 459b39c5158Smillert " Read '$out' in again" ); 460b39c5158Smillert 461b39c5158Smillert check_tar_object( $new, $struct ); 462b39c5158Smillert 463b39c5158Smillert ### now extract it again 464b39c5158Smillert ok( $new->extract, " Extracted '$out' with 'extract'" ); 465b39c5158Smillert check_tar_extract( $new, $struct ); 466b39c5158Smillert 467b39c5158Smillert rm( $out ) unless $NO_UNLINK; 468b39c5158Smillert } 469b39c5158Smillert 470b39c5158Smillert 471b39c5158Smillert { ### create_archive() 472b39c5158Smillert ok( $Class->create_archive( $out, 0, $COMPRESS_FILE ), 473b39c5158Smillert " Wrote tarfile using 'create_archive'" ); 474b39c5158Smillert check_tar_file( $out ); 475b39c5158Smillert 476b39c5158Smillert ### now extract it again 477b39c5158Smillert ok( $Class->extract_archive( $out ), 478b39c5158Smillert " Extracted file using 'extract_archive'"); 479b39c5158Smillert rm( $out ) unless $NO_UNLINK; 480b39c5158Smillert } 481b39c5158Smillert } 482b39c5158Smillert 483b39c5158Smillert ## write tgz tests 484b39c5158Smillert { my @out; 485b39c5158Smillert push @out, [ $OUT_TGZ_FILE => 1 ] if $Class->has_zlib_support; 486b39c5158Smillert push @out, [ $OUT_TBZ_FILE => COMPRESS_BZIP ] if $Class->has_bzip2_support; 487de8cc8edSafresh1 push @out, [ $OUT_TXZ_FILE => COMPRESS_XZ ] if $Class->has_xz_support; 488b39c5158Smillert 489b39c5158Smillert for my $entry ( @out ) { 490b39c5158Smillert 491b39c5158Smillert my( $out, $compression ) = @$entry; 492b39c5158Smillert 493b39c5158Smillert { ### write() 494b39c5158Smillert ok($obj->write($out, $compression), 495b39c5158Smillert " Writing compressed file '$out' using 'write'" ); 496b39c5158Smillert check_compressed_file( $out ); 497b39c5158Smillert 498b39c5158Smillert check_tar_object( $obj, $struct ); 499b39c5158Smillert 500b39c5158Smillert ### now read it in again 501b39c5158Smillert ok( $new->read( $out ), 502b39c5158Smillert " Read '$out' in again" ); 503b39c5158Smillert check_tar_object( $new, $struct ); 504b39c5158Smillert 505b39c5158Smillert ### now extract it again 506b39c5158Smillert ok( $new->extract, 507b39c5158Smillert " Extracted '$out' again" ); 508b39c5158Smillert check_tar_extract( $new, $struct ); 509b39c5158Smillert 510b39c5158Smillert rm( $out ) unless $NO_UNLINK; 511b39c5158Smillert } 512b39c5158Smillert 513b39c5158Smillert { ### create_archive() 514b39c5158Smillert ok( $Class->create_archive( $out, $compression, $COMPRESS_FILE ), 515b39c5158Smillert " Wrote '$out' using 'create_archive'" ); 516b39c5158Smillert check_compressed_file( $out ); 517b39c5158Smillert 518b39c5158Smillert ### now extract it again 519b39c5158Smillert ok( $Class->extract_archive( $out, $compression ), 520b39c5158Smillert " Extracted file using 'extract_archive'"); 521b39c5158Smillert rm( $out ) unless $NO_UNLINK; 522b39c5158Smillert } 523b39c5158Smillert } 524b39c5158Smillert } 525b39c5158Smillert } 526b39c5158Smillert} 527b39c5158Smillert 528b39c5158Smillert 529b39c5158Smillert### limited read + extract tests ### 530256a93a4Safresh1SKIP: { ### pesky warnings 531256a93a4Safresh1 skip $ebcdic_skip_msg, 8 if ord "A" != 65; 532256a93a4Safresh1 533256a93a4Safresh1 my $tar = $Class->new; 534b39c5158Smillert my @files = $tar->read( $TAR_FILE, 0, { limit => 1 } ); 535b39c5158Smillert my $obj = $files[0]; 536b39c5158Smillert 537b39c5158Smillert is( scalar @files, 1, "Limited read" ); 538b39c5158Smillert 539b39c5158Smillert my ($name,$content) = get_expect_name_and_contents( 540b39c5158Smillert $obj->full_path, \@EXPECT_NORMAL ); 541b39c5158Smillert 542b39c5158Smillert is( $obj->name, $name, " Expected file found" ); 543b39c5158Smillert 544b39c5158Smillert 545b39c5158Smillert ### extract this single file to cwd() 546b39c5158Smillert for my $meth (qw[extract extract_file]) { 547b39c5158Smillert 548b39c5158Smillert ### extract it by full path and object 549b39c5158Smillert for my $arg ( $obj, $obj->full_path ) { 550b39c5158Smillert 551b39c5158Smillert ok( $tar->$meth( $arg ), 552b39c5158Smillert " Extract '$name' to cwd() with $meth" ); 553b39c5158Smillert ok( -e $obj->full_path, " Extracted file exists" ); 554b39c5158Smillert rm( $obj->full_path ) unless $NO_UNLINK; 555b39c5158Smillert } 556b39c5158Smillert } 557b39c5158Smillert 558b39c5158Smillert ### extract this file to @ROOT 559b39c5158Smillert ### can only do that with 'extract_file', not with 'extract' 560b39c5158Smillert for my $meth (qw[extract_file]) { 561b39c5158Smillert my $outpath = File::Spec->catdir( @ROOT ); 562b39c5158Smillert my $outfile = File::Spec->catfile( $outpath, $$ ); #$obj->full_path ); 563b39c5158Smillert 564b39c5158Smillert ok( $tar->$meth( $obj->full_path, $outfile ), 565b39c5158Smillert " Extract file '$name' to $outpath with $meth" ); 566b39c5158Smillert ok( -e $outfile, " Extracted file '$outfile' exists" ); 567b39c5158Smillert rm( $outfile ) unless $NO_UNLINK; 568b39c5158Smillert } 569b39c5158Smillert 570b39c5158Smillert} 571b39c5158Smillert 572b39c5158Smillert 573*5486feefSafresh1### extract tests with different $EXTRACT_BLOCK_SIZE values ### 574*5486feefSafresh1SKIP: { ### pesky warnings 575*5486feefSafresh1 skip $ebcdic_skip_msg, 431 if ord "A" != 65; 576*5486feefSafresh1 577*5486feefSafresh1 skip('no IO::String', 431) if !$Archive::Tar::HAS_PERLIO && 578*5486feefSafresh1 !$Archive::Tar::HAS_PERLIO && 579*5486feefSafresh1 !$Archive::Tar::HAS_IO_STRING && 580*5486feefSafresh1 !$Archive::Tar::HAS_IO_STRING; 581*5486feefSafresh1 582*5486feefSafresh1 my $tar = $Class->new; 583*5486feefSafresh1 ok( $tar->read( $TAR_FILE ), "Read in '$TAR_FILE'" ); 584*5486feefSafresh1 585*5486feefSafresh1 for my $aref ( [$tar, \@EXPECT_NORMAL], 586*5486feefSafresh1 [$TARBIN, \@EXPECTBIN], 587*5486feefSafresh1 [$TARX, \@EXPECTX] 588*5486feefSafresh1 ) { 589*5486feefSafresh1 my($obj, $struct) = @$aref; 590*5486feefSafresh1 591*5486feefSafresh1 for my $block_size ((1, BLOCK, 1024 * 1024, 2**31 - 4096, 2**31 - 1)) { 592*5486feefSafresh1 local $Archive::Tar::EXTRACT_BLOCK_SIZE = $block_size; 593*5486feefSafresh1 594*5486feefSafresh1 ok( $obj->extract, " Extracted with 'extract'" ); 595*5486feefSafresh1 check_tar_extract( $obj, $struct ); 596*5486feefSafresh1 } 597*5486feefSafresh1 } 598*5486feefSafresh1} 599*5486feefSafresh1 600*5486feefSafresh1 601b39c5158Smillert### clear tests ### 602256a93a4Safresh1SKIP: { ### pesky warnings 603256a93a4Safresh1 skip $ebcdic_skip_msg, 3 if ord "A" != 65; 604256a93a4Safresh1 605256a93a4Safresh1 my $tar = $Class->new; 606b39c5158Smillert my @files = $tar->read( $TAR_FILE ); 607b39c5158Smillert 608b39c5158Smillert my $cnt = $tar->list_files(); 609b39c5158Smillert ok( $cnt, "Found old data" ); 610b39c5158Smillert ok( $tar->clear, " Clearing old data" ); 611b39c5158Smillert 612b39c5158Smillert my $new_cnt = $tar->list_files; 613b39c5158Smillert ok( !$new_cnt, " Old data cleared" ); 614b39c5158Smillert} 615b39c5158Smillert 616b39c5158Smillert### $DO_NOT_USE_PREFIX tests 617b39c5158Smillert{ my $tar = $Class->new; 618b39c5158Smillert 619b39c5158Smillert 620b39c5158Smillert ### first write a tar file without prefix 621b39c5158Smillert { my ($obj) = $tar->add_files( $COMPRESS_FILE ); 622b39c5158Smillert my $dir = ''; # dir is empty! 623b39c5158Smillert my $file = File::Basename::basename( $COMPRESS_FILE ); 624b39c5158Smillert 625b39c5158Smillert ok( $obj, "File added" ); 626b39c5158Smillert isa_ok( $obj, $FClass ); 627b39c5158Smillert 628b39c5158Smillert ### internal storage ### 629b39c5158Smillert is( $obj->name, $file, " Name set to '$file'" ); 630b39c5158Smillert is( $obj->prefix, $dir, " Prefix set to '$dir'" ); 631b39c5158Smillert 632b39c5158Smillert ### write the tar file without a prefix in it 633b39c5158Smillert ### pesky warnings 634b39c5158Smillert local $Archive::Tar::DO_NOT_USE_PREFIX = 1; 635b39c5158Smillert local $Archive::Tar::DO_NOT_USE_PREFIX = 1; 636b39c5158Smillert 637b39c5158Smillert ok( $tar->write( $OUT_TAR_FILE ), 638b39c5158Smillert " Tar file written" ); 639b39c5158Smillert 640b39c5158Smillert ### and forget all about it... 641b39c5158Smillert $tar->clear; 642b39c5158Smillert } 643b39c5158Smillert 644b39c5158Smillert ### now read it back in, there should be no prefix 645b39c5158Smillert { ok( $tar->read( $OUT_TAR_FILE ), 646b39c5158Smillert " Tar file read in again" ); 647b39c5158Smillert 648b39c5158Smillert my ($obj) = $tar->get_files; 649b39c5158Smillert ok( $obj, " File retrieved" ); 650b39c5158Smillert isa_ok( $obj, $FClass, " Object" ); 651b39c5158Smillert 652b39c5158Smillert is( $obj->name, $COMPRESS_FILE, 653b39c5158Smillert " Name now set to '$COMPRESS_FILE'" ); 654b39c5158Smillert is( $obj->prefix, '', " Prefix now empty" ); 655b39c5158Smillert 656b39c5158Smillert my $re = quotemeta $COMPRESS_FILE; 657b39c5158Smillert like( $obj->raw, qr/^$re/, " Prefix + name in name slot of header" ); 658b39c5158Smillert } 659b39c5158Smillert 660b39c5158Smillert rm( $OUT_TAR_FILE ) unless $NO_UNLINK; 661b39c5158Smillert} 662b39c5158Smillert 663b39c5158Smillert### clean up stuff 664b39c5158SmillertEND { 665b39c5158Smillert for my $struct ( \@EXPECT_NORMAL, \@EXPECTBIN, \@EXPECTX ) { 666b39c5158Smillert for my $aref (@$struct) { 667b39c5158Smillert 668b39c5158Smillert my $dir = $aref->[0]->[0]; 669b39c5158Smillert rmtree $dir if $dir && -d $dir && not $NO_UNLINK; 670b39c5158Smillert } 671b39c5158Smillert } 672b39c5158Smillert 673b39c5158Smillert my ($dir) = File::Spec::Unix->splitdir( $LONG_FILE ); 674b39c5158Smillert rmtree $dir if $dir && -d $dir && not $NO_UNLINK; 675b39c5158Smillert 1 while unlink $COMPRESS_FILE; 676b39c5158Smillert} 677b39c5158Smillert 678b39c5158Smillert########################### 679b39c5158Smillert### helper subs ### 680b39c5158Smillert########################### 681b39c5158Smillertsub get_expect { 682b39c5158Smillert return map { 683b39c5158Smillert split '/', $_ 684b39c5158Smillert } map { 685b39c5158Smillert File::Spec::Unix->catfile( 686b39c5158Smillert grep { defined } @{$_->[0]}, $_->[1] 687b39c5158Smillert ) 688b39c5158Smillert } @EXPECT_NORMAL; 689b39c5158Smillert} 690b39c5158Smillert 691b39c5158Smillertsub is_dir { 692b39c5158Smillert my $file = pop(); 693b39c5158Smillert return $file =~ m|/$| ? 1 : 0; 694b39c5158Smillert} 695b39c5158Smillert 696b39c5158Smillertsub rm { 697b39c5158Smillert my $x = shift; 698b39c5158Smillert if ( is_dir($x) ) { 699b39c5158Smillert rmtree($x); 700b39c5158Smillert } else { 701b39c5158Smillert 1 while unlink $x; 702b39c5158Smillert } 703b39c5158Smillert} 704b39c5158Smillert 705b39c5158Smillertsub check_tar_file { 706b39c5158Smillert my $file = shift; 707b39c5158Smillert my $filesize = -s $file; 708b39c5158Smillert my $contents = slurp_binfile( $file ); 709b39c5158Smillert 710b39c5158Smillert ok( defined( $contents ), " File read" ); 711b39c5158Smillert ok( $filesize, " File written size=$filesize" ); 712b39c5158Smillert 713b39c5158Smillert cmp_ok( $filesize % BLOCK, '==', 0, 714b39c5158Smillert " File size is a multiple of 512" ); 715b39c5158Smillert 716b39c5158Smillert cmp_ok( length($contents), '==', $filesize, 717b39c5158Smillert " File contents match size" ); 718b39c5158Smillert 719b39c5158Smillert is( TAR_END x 2, substr( $contents, -(BLOCK*2) ), 720b39c5158Smillert " Ends with 1024 null bytes" ); 721b39c5158Smillert 722b39c5158Smillert return $contents; 723b39c5158Smillert} 724b39c5158Smillert 725b39c5158Smillertsub check_compressed_file { 726b39c5158Smillert my $file = shift; 727b39c5158Smillert my $filesize = -s $file; 728b39c5158Smillert my $contents = slurp_compressed_file( $file ); 729b39c5158Smillert my $uncompressedsize = length $contents; 730b39c5158Smillert 731b39c5158Smillert ok( defined( $contents ), " File read and uncompressed" ); 732b39c5158Smillert ok( $filesize, " File written size=$filesize uncompressed size=$uncompressedsize" ); 733b39c5158Smillert 734b39c5158Smillert cmp_ok( $uncompressedsize % BLOCK, '==', 0, 735b39c5158Smillert " Uncompressed size is a multiple of 512" ); 736b39c5158Smillert 737b39c5158Smillert is( TAR_END x 2, substr($contents, -(BLOCK*2)), 738b39c5158Smillert " Ends with 1024 null bytes" ); 739b39c5158Smillert 740b39c5158Smillert cmp_ok( $filesize, '<', $uncompressedsize, 741b39c5158Smillert " Compressed size < uncompressed size" ); 742b39c5158Smillert 743b39c5158Smillert return $contents; 744b39c5158Smillert} 745b39c5158Smillert 746b39c5158Smillertsub check_tar_object { 747b39c5158Smillert my $obj = shift; 748b39c5158Smillert my $struct = shift or return; 749b39c5158Smillert 750b39c5158Smillert ### amount of files (not dirs!) there should be in the object 751b39c5158Smillert my $expect = scalar @$struct; 752b39c5158Smillert my @files = grep { $_->is_file } $obj->get_files; 753b39c5158Smillert 754b39c5158Smillert ### count how many files there are in the object 755b39c5158Smillert ok( scalar @files, " Found some files in the archive" ); 756b39c5158Smillert is( scalar @files, $expect, " Found expected number of files" ); 757b39c5158Smillert 758b39c5158Smillert for my $file (@files) { 759b39c5158Smillert 760b39c5158Smillert ### XXX ->fullname 761b39c5158Smillert #my $path = File::Spec::Unix->catfile( 762b39c5158Smillert # grep { length } $file->prefix, $file->name ); 763b39c5158Smillert my($ename,$econtent) = 764b39c5158Smillert get_expect_name_and_contents( $file->full_path, $struct ); 765b39c5158Smillert 766b39c5158Smillert ok( $file->is_file, " It is a file" ); 767b39c5158Smillert is( $file->full_path, $ename, 768b39c5158Smillert " Name matches expected name" ); 769b39c5158Smillert like( $file->get_content, $econtent, 770b39c5158Smillert " Content as expected" ); 771b39c5158Smillert } 772b39c5158Smillert} 773b39c5158Smillert 774b39c5158Smillertsub check_tar_extract { 775b39c5158Smillert my $tar = shift; 776b39c5158Smillert my $struct = shift; 777b39c5158Smillert 778b39c5158Smillert my @dirs; 779b39c5158Smillert for my $file ($tar->get_files) { 780b39c5158Smillert push @dirs, $file && next if $file->is_dir; 781b39c5158Smillert 782b39c5158Smillert 783b39c5158Smillert my $path = $file->full_path; 784b39c5158Smillert my($ename,$econtent) = 785b39c5158Smillert get_expect_name_and_contents( $path, $struct ); 786b39c5158Smillert 787b39c5158Smillert 788b39c5158Smillert is( $ename, $path, " Expected file found" ); 789b39c5158Smillert ok( -e $path, " File '$path' exists" ); 790b39c5158Smillert 791b39c5158Smillert my $fh; 792b39c5158Smillert open $fh, "$path" or warn "Error opening file '$path': $!\n"; 793b39c5158Smillert binmode $fh; 794b39c5158Smillert 795b39c5158Smillert ok( $fh, " Opening file" ); 796b39c5158Smillert 797b39c5158Smillert my $content = do{local $/;<$fh>}; chomp $content; 798b39c5158Smillert like( $content, qr/$econtent/, 799b39c5158Smillert " Contents OK" ); 800b39c5158Smillert 801b39c5158Smillert close $fh; 802b39c5158Smillert $NO_UNLINK or 1 while unlink $path; 803b39c5158Smillert 804b39c5158Smillert ### alternate extract path tests 805b39c5158Smillert ### to abs and rel paths 806b39c5158Smillert { for my $outpath ( File::Spec->catdir( @ROOT ), 807b39c5158Smillert File::Spec->rel2abs( 808b39c5158Smillert File::Spec->catdir( @ROOT ) 809b39c5158Smillert ) 810b39c5158Smillert ) { 811b39c5158Smillert 812b39c5158Smillert my $outfile = File::Spec->catfile( $outpath, $$ ); 813b39c5158Smillert 814b39c5158Smillert ok( $tar->extract_file( $file->full_path, $outfile ), 815b39c5158Smillert " Extracted file '$path' to $outfile" ); 816b39c5158Smillert ok( -e $outfile," Extracted file '$outfile' exists" ); 817b39c5158Smillert 818b39c5158Smillert rm( $outfile ) unless $NO_UNLINK; 819b39c5158Smillert } 820b39c5158Smillert } 821b39c5158Smillert } 822b39c5158Smillert 823b39c5158Smillert ### now check if list_files is returning the same info as get_files 824b39c5158Smillert is_deeply( [$tar->list_files], [ map { $_->full_path } $tar->get_files], 825b39c5158Smillert " Verified via list_files as well" ); 826b39c5158Smillert 827b39c5158Smillert #do { rmtree $_->full_path if -d $_->full_path && not $NO_UNLINK } 828b39c5158Smillert # for @dirs; 829b39c5158Smillert} 830b39c5158Smillert 831b39c5158Smillertsub slurp_binfile { 832b39c5158Smillert my $file = shift; 833b39c5158Smillert my $fh = IO::File->new; 834b39c5158Smillert 835b39c5158Smillert $fh->open( $file ) or warn( "Error opening '$file': $!" ), return undef; 836b39c5158Smillert 837b39c5158Smillert binmode $fh; 838b39c5158Smillert local $/; 839b39c5158Smillert return <$fh>; 840b39c5158Smillert} 841b39c5158Smillert 842b39c5158Smillertsub slurp_compressed_file { 843b39c5158Smillert my $file = shift; 844b39c5158Smillert my $fh; 845b39c5158Smillert 846de8cc8edSafresh1 ### xz 847de8cc8edSafresh1 if( $file =~ /.txz$/ ) { 848de8cc8edSafresh1 require IO::Uncompress::UnXz; 849de8cc8edSafresh1 $fh = IO::Uncompress::UnXz->new( $file ) 850de8cc8edSafresh1 or warn( "Error opening '$file' with IO::Uncompress::UnXz" ), return 851de8cc8edSafresh1 852b39c5158Smillert ### bzip2 853de8cc8edSafresh1 } elsif( $file =~ /.tbz$/ ) { 854b39c5158Smillert require IO::Uncompress::Bunzip2; 855b39c5158Smillert $fh = IO::Uncompress::Bunzip2->new( $file ) 856b39c5158Smillert or warn( "Error opening '$file' with IO::Uncompress::Bunzip2" ), return 857b39c5158Smillert 858b39c5158Smillert ### gzip 859b39c5158Smillert } else { 860b39c5158Smillert require IO::Zlib; 861256a93a4Safresh1 $fh = IO::Zlib->new(); 862b39c5158Smillert $fh->open( $file, READ_ONLY->(1) ) 863b39c5158Smillert or warn( "Error opening '$file' with IO::Zlib" ), return 864b39c5158Smillert } 865b39c5158Smillert 866b39c5158Smillert my $str; 867b39c5158Smillert my $buff; 868b39c5158Smillert $str .= $buff while $fh->read( $buff, 4096 ) > 0; 869b39c5158Smillert $fh->close(); 870b39c5158Smillert 871b39c5158Smillert return $str; 872b39c5158Smillert} 873b39c5158Smillert 874b39c5158Smillertsub get_expect_name_and_contents { 875b39c5158Smillert my $find = shift; 876b39c5158Smillert my $struct = shift or return; 877b39c5158Smillert 878b39c5158Smillert ### find the proper name + contents for this file from 879b39c5158Smillert ### the expect structure 880b39c5158Smillert my ($name, $content) = 881b39c5158Smillert map { 882b39c5158Smillert @$_; 883b39c5158Smillert } grep { 884b39c5158Smillert $_->[0] eq $find 885b39c5158Smillert } map { 886b39c5158Smillert [ ### full path ### 887b39c5158Smillert File::Spec::Unix->catfile( 888b39c5158Smillert grep { length } @{$_->[0]}, $_->[1] 889b39c5158Smillert ), 890b39c5158Smillert ### regex 891b39c5158Smillert $_->[2], 892b39c5158Smillert ] 893b39c5158Smillert } @$struct; 894b39c5158Smillert 895b39c5158Smillert ### not a qr// yet? 896b39c5158Smillert unless( ref $content ) { 897b39c5158Smillert my $x = quotemeta ($content || ''); 898b39c5158Smillert $content = qr/$x/; 899b39c5158Smillert } 900b39c5158Smillert 901b39c5158Smillert unless( $name ) { 902b39c5158Smillert warn "Could not find '$find' in " . Dumper $struct; 903b39c5158Smillert } 904b39c5158Smillert 905b39c5158Smillert return ($name, $content); 906b39c5158Smillert} 907b39c5158Smillert 908b39c5158Smillert__END__ 909