2013-06-26 22:41:22 +04:00
#!/usr/bin/perl
2013-07-16 01:41:15 +04:00
# Unix SMB/CIFS implementation.
# Test suite for the tar backup mode of smbclient.
# Copyright (C) Aurélien Aptel 2013
# This program 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 3 of the License, or
# (at your option) any later version.
# This program 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 program. If not, see <http://www.gnu.org/licenses/>.
2013-06-27 17:00:24 +04:00
= head1 NAME
2013-07-04 19:54:43 +04:00
C <test_smbclient_tarmode.pl> - Test for smbclient tar backup feature
2013-06-27 17:00:24 +04:00
= cut
2013-06-26 22:41:22 +04:00
2013-08-12 18:29:41 +04:00
use v5 .10 ;
2013-06-26 22:41:22 +04:00
use strict ;
use warnings ;
use Archive::Tar ;
use Data::Dumper ;
2013-07-16 02:34:41 +04:00
use Digest::MD5 qw/md5_hex/ ;
2013-06-26 22:41:22 +04:00
use File::Path qw/make_path remove_tree/ ;
2013-07-22 20:49:51 +04:00
use File::Spec ;
2013-07-16 02:34:41 +04:00
use File::Temp ;
2013-06-27 17:00:24 +04:00
use Getopt::Long ;
use Pod::Usage ;
2013-06-26 22:41:22 +04:00
use Term::ANSIColor ;
2013-07-16 02:34:41 +04:00
2013-06-26 22:41:22 +04:00
sub d { print Dumper @ _ ; }
2013-06-27 17:00:24 +04:00
# DEFAULTS
2013-07-04 19:54:43 +04:00
# 'our' to make them available in the File package
2013-06-28 05:16:29 +04:00
our $ USER = '' ;
our $ PW = '' ;
2013-10-29 15:08:57 +04:00
our $ HOST = '' ;
2013-06-28 05:16:29 +04:00
our $ IP = '' ;
2013-10-29 15:08:57 +04:00
our $ SHARE = '' ;
2013-07-03 18:09:03 +04:00
our $ DIR = 'tar_test_dir' ;
2013-10-29 15:08:57 +04:00
our $ LOCALPATH = '' ;
2013-07-16 02:34:41 +04:00
our $ TMP = File::Temp - > newdir ( ) ;
2013-06-28 05:16:29 +04:00
our $ BIN = 'smbclient' ;
2013-08-05 20:55:25 +04:00
our $ SUBUNIT = 0 ;
2013-06-28 05:16:29 +04:00
2013-07-16 16:46:02 +04:00
my $ SELECTED_TEST = '' ;
2013-07-04 19:54:43 +04:00
my $ LIST_TEST = 0 ;
2013-06-28 20:36:22 +04:00
2013-07-04 19:54:43 +04:00
my @ SMBARGS = ( ) ;
2013-06-28 05:16:29 +04:00
our $ DEBUG = 0 ;
2013-07-22 20:49:51 +04:00
our $ VERBOSE = 0 ;
2013-07-04 19:54:43 +04:00
my $ MAN = 0 ;
my $ HELP = 0 ;
my $ CLEAN = 0 ;
# all tests
my @ TESTS = (
2013-10-25 17:12:27 +04:00
# ['test helper', \&test_helper],
2013-07-04 19:54:43 +04:00
[ 'create, normal files (no attributes)' , \ & test_creation_normal , 'normal' ] ,
[ 'create, normal nested files (no attributes)' , \ & test_creation_normal , 'nested' ] ,
2013-07-17 18:27:01 +04:00
[ 'create, normal files (interactive)' , \ & test_creation_normal , 'inter' ] ,
2013-07-17 20:54:07 +04:00
[ 'create, large file' , \ & test_creation_large_file ] ,
[ 'create, long path' , \ & test_creation_long_path ] ,
2013-07-04 19:54:43 +04:00
[ 'create, incremental with -g' , \ & test_creation_incremental , '-g' ] ,
[ 'create, incremental with tarmode' , \ & test_creation_incremental , 'tarmode inc' ] ,
[ 'create, reset archived files with -a' , \ & test_creation_reset , '-a' ] ,
[ 'create, reset archived files with tarmode' , \ & test_creation_reset , 'tarmode reset' ] ,
[ 'create, files newer than a file' , \ & test_creation_newer ] ,
[ 'create, combination of tarmode filter' , \ & test_creation_attr ] ,
[ 'create, explicit include' , \ & test_creation_include ] ,
2013-10-28 21:07:25 +04:00
[ 'create, explicit exclude' , \ & test_creation_exclude ] ,
2013-07-04 19:54:43 +04:00
[ 'create, include w/ filelist (F)' , \ & test_creation_list ] ,
2013-07-17 18:27:01 +04:00
[ 'create, wildcard simple' , \ & test_creation_wildcard_simple ] ,
2013-10-25 17:12:27 +04:00
[ 'create, regex' , \ & test_creation_regex ] ,
2013-07-24 18:49:06 +04:00
[ 'create, multiple backup in session' , \ & test_creation_multiple ] ,
2013-07-04 19:54:43 +04:00
[ 'extract, normal files' , \ & test_extraction_normal ] ,
[ 'extract, explicit include' , \ & test_extraction_include ] ,
[ 'extract, explicit exclude' , \ & test_extraction_exclude ] ,
[ 'extract, include w/ filelist (F)' , \ & test_extraction_list ] ,
2013-07-22 20:49:51 +04:00
[ 'extract, regex' , \ & test_extraction_regex ] ,
2013-07-04 19:54:43 +04:00
) ;
2013-06-27 17:00:24 +04:00
= head1 SYNOPSIS
2013-07-04 19:54:43 +04:00
test_smbclient_tarmode . pl [ options ] - - [ smbclient options ]
2013-06-27 17:00:24 +04:00
Options:
- h , - - help brief help message
- - man full documentation
2013-06-28 20:36:22 +04:00
Environment:
2013-06-27 17:00:24 +04:00
- u , - - user USER
- p , - - password PW
2013-10-29 15:08:57 +04:00
- n , - - name HOST ( required )
2013-06-27 17:00:24 +04:00
- i , - - ip IP
2013-10-29 15:08:57 +04:00
- s , - - share SHARE ( required )
2013-06-27 17:00:24 +04:00
- d , - - dir PATH
sub - path to use on the share
2013-10-29 15:08:57 +04:00
- l , - - local - path PATH ( required )
2013-06-27 17:00:24 +04:00
path to the root of the samba share on the machine .
- b , - - bin BIN
path to the smbclient binary to use
2013-06-28 20:36:22 +04:00
Test:
2013-07-04 19:54:43 +04:00
- - list
list tests
2013-06-28 20:36:22 +04:00
- - test N
2013-07-16 16:46:02 +04:00
- - test A - B
- - test A , B , D - F
only run certain tests ( accept list and intervals of numbers )
2013-06-28 20:36:22 +04:00
2013-07-22 20:49:51 +04:00
- v , - - verbose
be more verbose
- - debug
2013-08-05 20:56:04 +04:00
print command and their output ( also set - v )
- - subunit
print output in subunit format
2013-07-22 20:49:51 +04:00
2013-06-27 17:00:24 +04:00
= cut
GetOptions ( 'u|user=s' = > \ $ USER ,
'p|password=s' = > \ $ PW ,
2013-08-05 20:56:04 +04:00
'n|name=s' = > \ $ HOST ,
2013-06-27 17:00:24 +04:00
'i|ip=s' = > \ $ IP ,
's|share=s' = > \ $ SHARE ,
'd|dir=s' = > \ $ DIR ,
'l|local-path=s' = > \ $ LOCALPATH ,
'b|bin=s' = > \ $ BIN ,
2013-07-16 16:46:02 +04:00
'test=s' = > \ $ SELECTED_TEST ,
2013-07-04 19:54:43 +04:00
'list' = > \ $ LIST_TEST ,
2013-06-28 20:36:22 +04:00
2013-07-03 01:20:53 +04:00
'clean' = > \ $ CLEAN ,
2013-08-05 20:55:25 +04:00
'subunit' = > \ $ SUBUNIT ,
2013-06-27 17:00:24 +04:00
'debug' = > \ $ DEBUG ,
2013-07-22 20:49:51 +04:00
'v|verbose' = > \ $ VERBOSE ,
2013-06-27 17:00:24 +04:00
'h|help' = > \ $ HELP ,
'man' = > \ $ MAN ) or pod2usage ( 2 ) ;
pod2usage ( 0 ) if $ HELP ;
pod2usage ( - exitval = > 0 , - verbose = > 2 ) if $ MAN ;
2013-07-04 19:54:43 +04:00
list_test ( ) , exit 0 if $ LIST_TEST ;
2013-10-29 15:08:57 +04:00
pod2usage ( 1 ) unless $ HOST ;
pod2usage ( 1 ) unless $ SHARE ;
pod2usage ( 1 ) unless $ LOCALPATH ;
2013-06-27 17:00:24 +04:00
2013-07-16 02:10:09 +04:00
if ( $ USER xor $ PW ) {
2013-06-27 17:00:24 +04:00
die "Need both user and password when one is provided\n" ;
2013-07-16 02:10:09 +04:00
}
elsif ( $ USER and $ PW ) {
2013-06-27 17:00:24 +04:00
push @ SMBARGS , '-U' . $ USER . '%' . $ PW ;
2013-07-16 02:10:09 +04:00
}
else {
2013-06-27 17:00:24 +04:00
push @ SMBARGS , '-N' ;
}
2013-06-26 22:41:22 +04:00
2013-07-16 02:10:09 +04:00
if ( $ IP ) {
2013-06-27 17:00:24 +04:00
push @ SMBARGS , '-I' , $ IP ;
}
2013-06-26 22:41:22 +04:00
2013-06-27 17:00:24 +04:00
# remaining arguments are passed to smbclient
push @ SMBARGS , @ ARGV ;
2013-06-26 22:41:22 +04:00
2013-06-27 17:00:24 +04:00
# path to store the downloaded tarball
2013-06-26 22:41:22 +04:00
my $ TAR = "$TMP/tarmode.tar" ;
2013-07-16 02:34:41 +04:00
#####
# SANITIZATION
# remove all final slashes from input paths
$ LOCALPATH =~ s{[/\\]+$} {}g ;
$ SHARE =~ s{[/\\]+$} {}g ;
$ HOST =~ s{[/\\]+$} {}g ;
2013-08-05 20:57:54 +04:00
$ DIR =~ s{^\.[/\\]+$} {}g ;
2013-07-16 02:34:41 +04:00
$ DIR =~ s{[/\\]+$} {}g ;
if ( ! - d $ LOCALPATH ) {
die "Local path '$LOCALPATH' is not a directory.\n" ;
}
2013-07-16 02:10:09 +04:00
if ( $ CLEAN ) {
2013-07-03 01:20:53 +04:00
# clean the whole root first
remove_tree ( $ LOCALPATH , { keep_root = > 1 } ) ;
}
2013-07-22 20:49:51 +04:00
if ( $ DEBUG ) {
$ VERBOSE = 1 ;
}
2013-06-26 22:41:22 +04:00
#####
# RUN TESTS
2013-07-16 16:46:02 +04:00
my @ selection = parse_test_string ( $ SELECTED_TEST ) ;
if ( $ SELECTED_TEST eq '' ) {
2013-07-04 19:54:43 +04:00
run_test ( @ TESTS ) ;
2013-07-16 16:46:02 +04:00
} elsif ( @ selection > 0 ) {
run_test ( @ selection ) ;
2013-07-16 02:10:09 +04:00
} else {
2013-07-16 16:46:02 +04:00
die "Test selection '$SELECTED_TEST' is invalid\n" ;
2013-06-28 20:36:22 +04:00
}
2013-07-04 19:54:43 +04:00
#################################
2013-06-26 22:41:22 +04:00
2013-07-04 19:54:43 +04:00
= head1 DOCUMENTATION
2013-06-26 22:41:22 +04:00
2013-07-04 19:54:43 +04:00
= head2 Defining a test
= over
= item * Create a function C <test_yourtest>
2013-07-14 17:22:36 +04:00
= item * Use the File module , documented below
2013-07-04 19:54:43 +04:00
= item * Use C <smb_tar> , C <smb_client> , C <check_tar> or C <check_remote>
= item * Return number of error
2013-06-27 22:30:44 +04:00
2013-07-04 19:54:43 +04:00
= item * Add function to C <@TESTS>
2013-06-27 22:30:44 +04:00
2013-07-04 19:54:43 +04:00
= back
The function must be placed in the C <@TESTS> list along with a short
description and optional arguments .
= cut
sub test_creation_newer {
2013-06-28 05:16:29 +04:00
my @ files ;
2013-06-27 22:30:44 +04:00
my $ dt = 3000 ;
# create oldest file at - DT
2013-06-28 05:16:29 +04:00
my $ oldest = File - > new_remote ( 'oldest' ) ;
$ oldest - > set_time ( time - $ dt ) ;
2013-06-27 22:30:44 +04:00
# create limit file
2013-06-28 05:16:29 +04:00
my $ limit = File - > new_local ( "$TMP/limit" ) ;
2013-06-27 22:30:44 +04:00
# create newA file at + DT
2013-06-28 05:16:29 +04:00
my $ newA = File - > new_remote ( 'newA' ) ;
$ newA - > set_time ( time + $ dt ) ;
2013-06-27 22:30:44 +04:00
# create newB file at + DT
2013-06-28 05:16:29 +04:00
my $ newB = File - > new_remote ( 'newB' ) ;
$ newB - > set_time ( time + $ dt ) ;
2013-06-27 22:30:44 +04:00
# get files newer than limit_file
2013-06-28 05:16:29 +04:00
push @ files , $ newA , $ newB ;
2013-06-27 22:30:44 +04:00
2013-06-28 05:16:29 +04:00
smb_tar ( '' , '-TcN' , $ limit - > localpath , $ TAR , $ DIR ) ;
return check_tar ( $ TAR , \ @ files ) ;
2013-06-27 22:30:44 +04:00
}
2013-07-03 18:09:03 +04:00
sub test_creation_attr {
my @ attr = qw/r h s a/ ;
my @ all ;
my @ inc ;
my $ err = 0 ;
# one normal file
my $ f = File - > new_remote ( "file-n.txt" ) ;
push @ all , $ f ;
2013-07-14 17:22:36 +04:00
# combinations of attributes
2013-07-03 18:09:03 +04:00
for my $ n ( 1 .. @ attr ) {
2013-07-16 02:10:09 +04:00
for ( combine ( \ @ attr , $ n ) ) {
2013-07-03 18:09:03 +04:00
my @ t = @$ _ ;
my $ fn = "file-" . join ( '+' , @ t ) . ".txt" ;
my $ f = File - > new_remote ( $ fn ) ;
$ f - > set_attr ( @ t ) ;
push @ all , $ f ;
}
}
2013-07-04 19:54:43 +04:00
@ inc = grep { ! $ _ - > attr ( 's' ) } @ all ;
2013-07-03 18:09:03 +04:00
smb_tar ( 'tarmode nosystem' , '-Tc' , $ TAR , $ DIR ) ;
$ err += check_tar ( $ TAR , \ @ inc ) ;
2013-07-04 19:54:43 +04:00
@ inc = grep { ! $ _ - > attr ( 'h' ) } @ all ;
2013-07-03 18:09:03 +04:00
smb_tar ( 'tarmode nohidden' , '-Tc' , $ TAR , $ DIR ) ;
$ err += check_tar ( $ TAR , \ @ inc ) ;
2013-07-04 19:54:43 +04:00
@ inc = grep { ! $ _ - > attr_any ( 'h' , 's' ) } @ all ;
2013-07-03 18:09:03 +04:00
smb_tar ( 'tarmode nohidden nosystem' , '-Tc' , $ TAR , $ DIR ) ;
$ err += check_tar ( $ TAR , \ @ inc ) ;
2013-07-04 19:54:43 +04:00
@ inc = grep { $ _ - > attr ( 'a' ) && ! $ _ - > attr_any ( 'h' , 's' ) } @ all ;
2013-07-03 18:09:03 +04:00
smb_tar ( 'tarmode inc nohidden nosystem' , '-Tc' , $ TAR , $ DIR ) ;
$ err += check_tar ( $ TAR , \ @ inc ) ;
2020-11-30 13:41:57 +03:00
# adjust attr so remote files can be deleted with deltree
File:: walk ( sub { $ _ - > set_attr ( qw/n r s h/ ) } , File:: tree ( $ DIR ) ) ;
2013-07-03 18:09:03 +04:00
$ err ;
}
2013-06-27 20:53:34 +04:00
sub test_creation_reset {
my ( $ mode ) = @ _ ;
2013-06-28 05:16:29 +04:00
my @ files ;
2013-06-27 20:53:34 +04:00
my $ n = 3 ;
2013-07-16 02:10:09 +04:00
for ( 1 .. $ n ) {
2013-06-28 05:16:29 +04:00
my $ f = File - > new_remote ( "file-$_" ) ;
$ f - > set_attr ( 'a' ) ;
push @ files , $ f ;
2013-06-27 20:53:34 +04:00
}
2013-07-16 02:10:09 +04:00
if ( $ mode =~ /reset/ ) {
2013-06-27 20:53:34 +04:00
smb_tar ( 'tarmode full reset' , '-Tc' , $ TAR , $ DIR ) ;
} else {
smb_tar ( '' , '-Tca' , $ TAR , $ DIR ) ;
}
2013-06-28 05:16:29 +04:00
my $ err = check_tar ( $ TAR , \ @ files ) ;
2013-07-16 02:10:09 +04:00
return $ err if ( $ err > 0 ) ;
2013-06-27 20:53:34 +04:00
2013-07-04 19:54:43 +04:00
for my $ f ( File:: list ( $ DIR ) ) {
2013-07-16 02:10:09 +04:00
if ( $ f - > { attr } { a } ) {
2013-06-28 05:16:29 +04:00
printf " ! %s %s\n" , $ f - > attr_str , $ f - > remotepath ;
2013-06-27 20:53:34 +04:00
$ err + + ;
}
}
return $ err ;
}
2013-07-17 20:54:07 +04:00
sub test_creation_large_file {
my $ size = int ( 15e6 ) ; # 15MB
my $ f = File - > new_remote ( "fat.jpg" , 0 , $ size ) ;
smb_tar ( '' , '-Tc' , $ TAR , $ DIR ) ;
return check_tar ( $ TAR , [ $ f ] ) ;
}
sub test_creation_long_path {
my $ d = "a" x130 ;
my @ all ;
2013-08-05 20:57:54 +04:00
for ( qw( foo/a bar/b ) ) {
2013-07-17 20:54:07 +04:00
push @ all , File - > new_remote ( "$d/$_" ) ;
}
smb_tar ( '' , '-Tc' , $ TAR , $ DIR ) ;
return check_tar ( $ TAR , \ @ all ) ;
}
2013-06-26 22:41:22 +04:00
sub test_creation_normal {
2013-06-28 05:30:06 +04:00
my ( $ mode ) = @ _ ;
2013-06-26 22:41:22 +04:00
2013-06-28 05:30:06 +04:00
my $ prefix = ( $ mode =~ /nest/ ) ? "/foo/bar/bar/" : '' ;
2013-06-28 05:16:29 +04:00
my @ files ;
2013-06-26 22:41:22 +04:00
my $ n = 5 ;
2013-07-16 02:10:09 +04:00
for ( 1 .. $ n ) {
2013-06-28 05:30:06 +04:00
my $ f = File - > new_remote ( $ prefix . "file-$_" ) ;
2013-06-28 05:16:29 +04:00
push @ files , $ f ;
2013-06-26 22:41:22 +04:00
}
2013-10-25 16:55:47 +04:00
if ( $ mode =~ /inter/ ) {
smb_tar ( "tar c $TAR $DIR" , '' ) ;
} else {
smb_tar ( 'tarmode full' , '-Tc' , $ TAR , $ DIR ) ;
}
2013-06-28 05:16:29 +04:00
return check_tar ( $ TAR , \ @ files ) ;
2013-06-26 22:41:22 +04:00
}
sub test_creation_incremental {
my ( $ mode ) = @ _ ;
2013-06-28 05:16:29 +04:00
my @ files ;
2013-06-27 17:07:42 +04:00
my $ n = 10 ;
2013-07-16 02:10:09 +04:00
for ( 1 .. $ n ) {
2013-06-28 05:16:29 +04:00
my $ f = File - > new_remote ( "file-$_" ) ;
2013-06-26 22:41:22 +04:00
2013-07-14 17:22:36 +04:00
# set archive bit on ~half of them
2013-07-16 02:10:09 +04:00
if ( $ _ < $ n / 2 ) {
2013-06-28 05:16:29 +04:00
$ f - > set_attr ( 'a' ) ;
push @ files , $ f ;
2013-06-26 22:41:22 +04:00
}
2013-06-27 17:07:42 +04:00
else {
2013-06-28 05:16:29 +04:00
$ f - > set_attr ( ( qw/n r s h/ ) [ $ _ % 4 ] ) ;
2013-06-27 17:07:42 +04:00
}
2013-06-26 22:41:22 +04:00
}
2013-07-16 02:10:09 +04:00
if ( $ mode =~ /inc/ ) {
2013-06-26 22:41:22 +04:00
smb_tar ( 'tarmode inc' , '-Tc' , $ TAR , $ DIR ) ;
} else {
smb_tar ( '' , '-Tcg' , $ TAR , $ DIR ) ;
}
2020-11-30 13:41:57 +03:00
my $ res = check_tar ( $ TAR , \ @ files ) ;
# adjust attr so remote files can be deleted with deltree
File:: walk ( sub { $ _ - > set_attr ( qw/n r s h/ ) } , File:: tree ( $ DIR ) ) ;
return $ res
2013-06-26 22:41:22 +04:00
}
2013-06-28 20:10:56 +04:00
sub test_extraction_normal {
2013-07-01 19:44:54 +04:00
my @ files ;
2013-06-28 20:10:56 +04:00
my $ n = 5 ;
2013-07-16 02:10:09 +04:00
for ( 1 .. $ n ) {
2013-06-28 20:10:56 +04:00
my $ f = File - > new_remote ( "file-$_" ) ;
2013-07-01 19:44:54 +04:00
push @ files , $ f ;
2013-06-28 20:10:56 +04:00
}
# store
smb_tar ( '' , '-Tc' , $ TAR , $ DIR ) ;
2013-07-01 19:44:54 +04:00
my $ err = check_tar ( $ TAR , \ @ files ) ;
2013-06-28 20:10:56 +04:00
return $ err if $ err > 0 ;
reset_remote ( ) ;
smb_tar ( '' , '-Tx' , $ TAR ) ;
2013-07-03 01:22:24 +04:00
check_remote ( $ DIR , \ @ files ) ;
2013-06-28 20:10:56 +04:00
}
2013-07-01 19:44:54 +04:00
sub test_extraction_include {
my @ all_files ;
my @ inc_files ;
2013-07-16 02:10:09 +04:00
for ( qw( file_inc inc/b inc/c inc/dir/foo dir_ex/d zob ) ) {
2013-07-01 19:44:54 +04:00
my $ f = File - > new_remote ( $ _ ) ;
push @ all_files , $ f ;
push @ inc_files , $ f if /inc/ ;
}
# store
smb_tar ( '' , '-Tc' , $ TAR , $ DIR ) ;
my $ err = check_tar ( $ TAR , \ @ all_files ) ;
return $ err if $ err > 0 ;
reset_remote ( ) ;
smb_tar ( '' , '-TxI' , $ TAR , "$DIR/file_inc" , "$DIR/inc" ) ;
2013-07-03 01:22:24 +04:00
check_remote ( $ DIR , \ @ inc_files ) ;
2013-07-01 19:44:54 +04:00
}
sub test_extraction_exclude {
my @ all_files ;
my @ inc_files ;
2013-07-16 02:10:09 +04:00
for ( qw( file_exc exc/b exc/c exc/dir/foo dir_ex/d zob ) ) {
2013-07-01 19:44:54 +04:00
my $ f = File - > new_remote ( $ _ ) ;
push @ all_files , $ f ;
push @ inc_files , $ f if ! /exc/ ;
}
# store
smb_tar ( '' , '-Tc' , $ TAR , $ DIR ) ;
my $ err = check_tar ( $ TAR , \ @ all_files ) ;
return $ err if $ err > 0 ;
reset_remote ( ) ;
smb_tar ( '' , '-TxX' , $ TAR , "$DIR/file_exc" , "$DIR/exc" ) ;
2013-07-03 01:22:24 +04:00
check_remote ( $ DIR , \ @ inc_files ) ;
2013-07-01 19:44:54 +04:00
}
2013-07-01 19:25:29 +04:00
sub test_creation_include {
my @ files ;
2013-07-16 02:10:09 +04:00
for ( qw( file_inc inc/b inc/c inc/dir/foo dir_ex/d zob ) ) {
2013-07-01 19:25:29 +04:00
my $ f = File - > new_remote ( $ _ ) ;
push @ files , $ f if /inc/ ;
}
smb_tar ( '' , '-TcI' , $ TAR , "$DIR/file_inc" , "$DIR/inc" ) ;
return check_tar ( $ TAR , \ @ files ) ;
}
sub test_creation_exclude {
my @ files ;
2013-07-16 02:10:09 +04:00
for ( qw( file_ex ex/b ex/c ex/dir/foo foo/bar zob ) ) {
2013-07-01 19:25:29 +04:00
my $ f = File - > new_remote ( $ _ ) ;
push @ files , $ f if ! /ex/ ;
}
smb_tar ( '' , '-TcX' , $ TAR , "$DIR/file_ex" , "$DIR/ex" ) ;
return check_tar ( $ TAR , \ @ files ) ;
}
2013-07-01 20:01:50 +04:00
sub test_creation_list {
my @ inc_files ;
2013-07-16 02:10:09 +04:00
for ( qw( file_inc inc/b inc/c inc/dir/foo foo/bar zob ) ) {
2013-07-01 20:01:50 +04:00
my $ f = File - > new_remote ( $ _ ) ;
push @ inc_files , $ f if /inc/ ;
}
my $ flist = File - > new_local ( "$TMP/list" , file_list ( @ inc_files ) ) ;
smb_tar ( '' , '-TcF' , $ TAR , $ flist - > localpath ) ;
return check_tar ( $ TAR , \ @ inc_files ) ;
}
2013-10-25 17:12:27 +04:00
sub test_creation_regex {
my @ exts = qw( jpg exe ) ;
my @ dirs = ( '' , "$DIR/" ) ;
my @ all = make_env ( \ @ exts , \ @ dirs ) ;
my $ nb ;
my @ inc ;
my $ err = 0 ;
# EXCLUSION
# skip *.exe
@ inc = grep { $ _ - > remotepath !~ m {exe$} } @ all ;
smb_tar ( '' , '-TcrX' , $ TAR , '*.exe' ) ;
$ err += check_tar ( $ TAR , \ @ inc ) ;
# if the pattern is a path, it doesn't skip anything
smb_tar ( '' , '-TcrX' , $ TAR , "$DIR/*.exe" ) ;
$ err += check_tar ( $ TAR , \ @ all ) ;
smb_tar ( '' , '-TcrX' , $ TAR , "$DIR/*" ) ;
$ err += check_tar ( $ TAR , \ @ all ) ;
smb_tar ( '' , '-TcrX' , $ TAR , "$DIR" ) ;
$ err += check_tar ( $ TAR , \ @ all ) ;
# no paths => include everything
smb_tar ( '' , '-TcrX' , $ TAR ) ;
$ err += check_tar ( $ TAR , \ @ all ) ;
# skip everything
smb_tar ( '' , '-TcrX' , $ TAR , "*.*" ) ;
$ err += check_tar ( $ TAR , [] ) ;
smb_tar ( '' , '-TcrX' , $ TAR , "*" ) ;
$ err += check_tar ( $ TAR , [] ) ;
# INCLUSION
# no paths => include everything
smb_tar ( '' , '-Tcr' , $ TAR ) ;
$ err += check_tar ( $ TAR , \ @ all ) ;
# include everything
smb_tar ( '' , '-Tcr' , $ TAR , '*' ) ;
$ err += check_tar ( $ TAR , \ @ all ) ;
# include only .exe at root
@ inc = grep { $ _ - > remotepath =~ m {^[^/]+exe$} } @ all ;
smb_tar ( '' , '-Tcr' , $ TAR , '*.exe' ) ;
$ err += check_tar ( $ TAR , \ @ inc ) ;
# smb_tar('', '-Tcr', $TAR, "$DIR/*");
## in old version (bug?)
# $err += check_tar($TAR, []);
## in rewrite
# @inc = grep { $_->remotepath =~ /^$DIR/ } @all;
# $err += check_tar($TAR, \@inc);
$ err ;
}
2013-07-17 18:27:01 +04:00
sub test_creation_wildcard_simple {
my @ exts = qw( jpg exe ) ;
my @ dirs = ( '' , "$DIR/" ) ;
my @ all = make_env ( \ @ exts , \ @ dirs ) ;
my $ nb ;
my @ inc ;
my $ err = 0 ;
@ inc = grep { $ _ - > remotepath =~ m {^[^/]+exe$} } @ all ;
smb_tar ( '' , '-Tc' , $ TAR , "*.exe" ) ;
$ err += check_tar ( $ TAR , \ @ inc ) ;
@ inc = grep { $ _ - > remotepath =~ m {$DIR/.+exe$} } @ all ;
smb_tar ( '' , '-Tc' , $ TAR , "$DIR/*.exe" ) ;
$ err += check_tar ( $ TAR , \ @ inc ) ;
$ err ;
}
# NOT USED
2013-10-25 17:12:27 +04:00
# helper to test tests
sub test_helper {
2013-07-03 01:22:24 +04:00
my @ exts = qw( txt jpg exe ) ;
my @ dirs = ( '' , "$DIR/" , "$DIR/dir/" ) ;
2013-10-25 17:12:27 +04:00
my @ all = make_env ( \ @ exts , \ @ dirs ) ;
2013-07-03 18:09:03 +04:00
my $ nb ;
my $ err = 0 ;
2013-07-22 20:49:51 +04:00
my @ inc ;
smb_tar ( '' , '-Tc' , $ TAR ) ;
return 1 if check_tar ( $ TAR , \ @ all ) ;
reset_remote ( ) ;
my @ exc = grep { $ _ - > remotepath =~ m !/dir/.+exe! } @ all ;
@ inc = grep { $ _ - > remotepath !~ m !/dir/.+exe! } @ all ;
smb_tar ( '' , '-TxXr' , $ TAR , "/$DIR/dir/*.exe" ) ;
$ err += check_remote ( '/' , \ @ all ) ; # BUG: should be \@inc
reset_remote ( ) ;
2013-07-03 01:22:24 +04:00
2013-07-17 18:27:01 +04:00
return 0 ;
2013-07-03 18:09:03 +04:00
}
2013-07-24 18:49:06 +04:00
sub test_creation_multiple {
my @ exts = qw( jpg exe ) ;
my @ dirs = ( '' , "$DIR/" ) ;
my @ all = make_env ( \ @ exts , \ @ dirs ) ;
my $ nb ;
my @ inc ;
my $ err = 0 ;
my ( $ tarA , $ tarB ) = ( "$TMP/a.tar" , "$TMP/b.tar" ) ;
my @ incA = grep { $ _ - > remotepath =~ m {^[^/]+exe$} } @ all ;
my @ incB = grep { $ _ - > remotepath =~ m {^[^/]+jpg$} } @ all ;
my $ flistA = File - > new_local ( "$TMP/listA" , file_list ( @ incA ) ) - > localpath ;
my $ flistB = File - > new_local ( "$TMP/listB" , file_list ( @ incB ) ) - > localpath ;
smb_tar ( "tar cF $tarA $flistA ; tar cF $tarB $flistB ; quit" ) ;
$ err += check_tar ( $ tarA , \ @ incA ) ;
$ err += check_tar ( $ tarB , \ @ incB ) ;
$ err ;
}
2013-07-22 20:49:51 +04:00
sub test_extraction_regex {
my @ exts = qw( txt jpg exe ) ;
my @ dirs = ( '' , "$DIR/" , "$DIR/dir/" ) ;
my @ all = make_env ( \ @ exts , \ @ dirs ) ;
my $ nb ;
my $ err = 0 ;
my ( @ inc , @ exc ) ;
smb_tar ( '' , '-Tc' , $ TAR ) ;
return 1 if check_tar ( $ TAR , \ @ all ) ;
reset_remote ( ) ;
# INCLUDE
# only include file at root
@ inc = grep { $ _ - > remotepath =~ m !exe! } @ all ;
smb_tar ( '' , '-Txr' , $ TAR , "*.exe" ) ;
$ err += check_remote ( '/' , \ @ inc ) ;
reset_remote ( ) ;
@ inc = grep { $ _ - > remotepath =~ m !/dir/.+exe! } @ all ;
smb_tar ( '' , '-Txr' , $ TAR , "/$DIR/dir/*.exe" ) ;
$ err += check_remote ( '/' , [] ) ; # BUG: should be \@inc
reset_remote ( ) ;
# EXCLUDE
# exclude file not directly at root
@ inc = grep { $ _ - > remotepath =~ m !^[^/]+$! } @ all ;
@ exc = grep { $ _ - > remotepath !~ m !^[^/]+$! } @ all ;
smb_tar ( '' , '-TxrX' , $ TAR , map { $ _ - > remotepath } @ exc ) ;
$ err += check_remote ( '/' , \ @ all ) ; # BUG: should be @inc...
reset_remote ( ) ;
# exclude only $DIR/dir/*exe
@ exc = grep { $ _ - > remotepath =~ m !/dir/.+exe! } @ all ;
@ inc = grep { $ _ - > remotepath !~ m !/dir/.+exe! } @ all ;
smb_tar ( '' , '-TxXr' , $ TAR , "/$DIR/dir/*.exe" ) ;
$ err += check_remote ( '/' , \ @ all ) ; # BUG: should be \@inc
reset_remote ( ) ;
$ err ;
}
2013-07-03 18:09:03 +04:00
sub test_extraction_wildcard {
my @ exts = qw( txt jpg exe ) ;
my @ dirs = ( '' , "$DIR/" , "$DIR/dir/" ) ;
my $ nb ;
my $ err = 0 ;
for my $ dir ( @ dirs ) {
my @ all ;
$ nb = 0 ;
for my $ dir ( @ dirs ) {
2013-07-16 02:10:09 +04:00
for ( @ exts ) {
2013-07-03 18:09:03 +04:00
my $ fn = $ dir . "file$nb." . $ _ ;
my $ f = File - > new_remote ( $ fn , 'ABSPATH' ) ;
$ f - > delete_on_destruction ( 1 ) ;
push @ all , $ f ;
$ nb + + ;
}
2013-07-03 01:22:24 +04:00
}
2013-07-03 18:09:03 +04:00
my @ inc ;
my $ ext = 'exe' ;
my $ fn = $ dir . "file$nb." . $ ext ;
my $ pattern = $ dir . '*.' . $ ext ;
my $ flist ;
# with F
$ flist = File - > new_local ( "$TMP/list" , "$pattern\n" ) ;
# store
my $ re = '^' . $ dir . '.*file' ;
@ inc = grep { $ dir eq '' or $ _ - > remotepath =~ m {$re} } @ all ;
smb_tar ( '' , '-Tc' , $ TAR , $ dir ) ;
$ err += check_tar ( $ TAR , \ @ inc ) ;
reset_remote ( ) ;
my $ re2 = '^' . $ dir . 'file.+exe' ;
@ inc = grep { $ _ - > remotepath =~ /$re2/ } @ all ;
smb_tar ( '' , '-TxrF' , $ TAR , $ flist - > localpath ) ;
$ err += check_remote ( $ dir , \ @ inc ) ;
reset_remote ( ) ;
2013-07-03 01:22:24 +04:00
}
$ err ;
}
2013-07-02 13:16:13 +04:00
sub test_extraction_list {
my @ inc_files ;
my @ all_files ;
2013-07-16 02:10:09 +04:00
for ( qw( file_inc inc/b inc/c inc/dir/foo foo/bar zob ) ) {
2013-07-02 13:16:13 +04:00
my $ f = File - > new_remote ( $ _ ) ;
push @ all_files , $ f ;
push @ inc_files , $ f if /inc/ ;
}
# store
smb_tar ( '' , '-Tc' , $ TAR , $ DIR ) ;
my $ err = check_tar ( $ TAR , \ @ all_files ) ;
return $ err if $ err > 0 ;
reset_remote ( ) ;
my $ flist = File - > new_local ( "$TMP/list" , file_list ( @ inc_files ) ) ;
smb_tar ( '' , '-TxF' , $ TAR , $ flist - > localpath ) ;
2013-07-03 01:22:24 +04:00
return check_remote ( $ DIR , \ @ inc_files ) ;
2013-07-02 13:16:13 +04:00
}
2013-07-04 19:54:43 +04:00
#################################
2013-06-26 22:41:22 +04:00
# IMPLEMENTATION
2013-07-04 19:54:43 +04:00
= head2 Useful functions
Here are a list of useful functions and helpers to define tests .
= cut
# list test number and description
sub list_test {
my $ i = 0 ;
2013-07-16 02:10:09 +04:00
for ( @ TESTS ) {
2013-07-04 19:54:43 +04:00
my ( $ desc , $ f , @ args ) = @$ _ ;
printf "%2d.\t%s\n" , $ i + + , $ desc ;
}
}
2013-06-26 22:41:22 +04:00
sub run_test {
2013-08-05 20:55:25 +04:00
if ( $ SUBUNIT ) {
run_test_subunit ( @ _ ) ;
} else {
run_test_normal ( @ _ ) ;
}
}
sub run_test_normal {
2013-07-16 02:10:09 +04:00
for ( @ _ ) {
2013-07-04 19:54:43 +04:00
my ( $ desc , $ f , @ args ) = @$ _ ;
2013-07-22 20:49:51 +04:00
my $ err ;
2013-06-26 22:41:22 +04:00
reset_env ( ) ;
2013-07-04 19:54:43 +04:00
say "TEST: $desc" ;
2013-07-22 20:49:51 +04:00
if ( $ VERBOSE ) {
$ err = $ f - > ( @ args ) ;
} else {
# turn off STDOUT
open my $ saveout , ">&STDOUT" ;
open STDOUT , '>' , File::Spec - > devnull ( ) ;
$ err = $ f - > ( @ args ) ;
open STDOUT , ">&" , $ saveout ;
}
2013-06-26 22:41:22 +04:00
print_res ( $ err ) ;
print "\n" ;
}
2013-06-27 20:53:34 +04:00
reset_env ( ) ;
2013-06-26 22:41:22 +04:00
}
2013-08-05 20:55:25 +04:00
sub run_test_subunit {
for ( @ _ ) {
my ( $ desc , $ f , @ args ) = @$ _ ;
my $ err ;
my $ str = '' ;
reset_env ( ) ;
say "test: $desc" ;
# capture output in $buf
my $ buf = '' ;
open my $ handle , '>' , \ $ buf ;
select $ handle ;
# check for die() calls
eval {
$ err = $ f - > ( @ args ) ;
} ;
if ( $@ ) {
$ str = $@ ;
$ err = 1 ;
}
close $ handle ;
# restore output
select STDOUT ;
# result string is output + eventual exception message
$ str = $ buf . $ str ;
printf "%s: %s [\n%s]\n" , ( $ err > 0 ? "failure" : "success" ) , $ desc , $ str ;
}
reset_env ( ) ;
}
2013-07-16 16:46:02 +04:00
sub parse_test_string {
my $ s = shift ;
my @ tests = ( ) ;
if ( ! length ( $ s ) ) {
return ( ) ;
}
for ( split /,/ , $ s ) {
2013-08-12 18:29:41 +04:00
if ( /^\d+$/ ) {
2013-07-16 16:46:02 +04:00
if ( $ _ >= @ TESTS ) {
return ( ) ;
}
push @ tests , $ TESTS [ $ _ ] ;
}
2013-08-12 18:29:41 +04:00
elsif ( /^(\d+)-(\d+)$/ ) {
2013-07-16 16:46:02 +04:00
my ( $ min , $ max ) = sort ( $ 1 , $ 2 ) ;
if ( $ max >= @ TESTS ) {
return ( ) ;
}
for ( $ min .. $ max ) {
push @ tests , $ TESTS [ $ _ ] ;
}
}
2013-08-12 18:29:41 +04:00
else {
2013-07-16 16:46:02 +04:00
return ( ) ;
}
}
return @ tests ;
}
2013-06-26 22:41:22 +04:00
sub print_res {
my $ err = shift ;
2013-07-16 02:10:09 +04:00
if ( $ err ) {
2013-06-26 22:41:22 +04:00
printf " RES: %s%d ERR%s\n" , color ( 'bold red' ) , $ err , color 'reset' ;
} else {
printf " RES: %sOK%s\n" , color ( 'bold green' ) , color 'reset' ;
}
}
2013-07-17 18:27:01 +04:00
sub make_env {
my ( $ exts , $ dirs ) = @ _ ;
my @ all ;
my $ nb = 0 ;
for my $ dir ( @$ dirs ) {
for ( @$ exts ) {
my $ fn = $ dir . "file$nb." . $ _ ;
my $ f = File - > new_remote ( $ fn , 'ABSPATH' ) ;
$ f - > delete_on_destruction ( 1 ) ;
push @ all , $ f ;
$ nb + + ;
}
}
@ all ;
}
2013-07-04 19:54:43 +04:00
= head3 C < combine ( \ @ set , $ n ) >
= head3 C < combine ( [ 'a' , 'b' , 'c' ] , 2 ) >
2013-07-14 17:22:36 +04:00
Return a list of all possible I <n> - uplet ( or combination of C <$n> element ) of C <@set> .
2013-07-04 19:54:43 +04:00
= cut
2013-07-03 18:09:03 +04:00
sub combine {
my ( $ list , $ n ) = @ _ ;
die "Insufficient list members" if $ n > @$ list ;
return map [ $ _ ] , @$ list if $ n <= 1 ;
my @ comb ;
for ( my $ i = 0 ; $ i + $ n <= @$ list ; $ i + + ) {
my $ val = $ list - > [ $ i ] ;
my @ rest = @$ list [ $ i + 1 .. $#$ list ] ;
push @ comb , [ $ val , @$ _ ] for combine ( \ @ rest , $ n - 1 ) ;
2013-07-03 01:22:24 +04:00
}
2013-07-03 18:09:03 +04:00
return @ comb ;
2013-07-03 01:22:24 +04:00
}
2013-07-04 19:54:43 +04:00
= head3 C < reset_remote ( ) >
Remove all files in the server C <$DIR> ( not root )
= cut
2013-06-28 20:10:56 +04:00
sub reset_remote {
2013-07-22 20:49:51 +04:00
# remove_tree($LOCALPATH . '/'. $DIR);
# make_path($LOCALPATH . '/'. $DIR);
2020-11-30 20:19:29 +03:00
my $ DIR ;
my @ names ;
my $ name ;
2020-11-30 13:41:57 +03:00
smb_client_cmd ( 0 , '-c' , "deltree ./*" ) ;
2020-11-30 20:19:29 +03:00
# Ensure all files are gone.
opendir ( DIR , $ LOCALPATH ) or die "Can't open $LOCALPATH\n" ;
@ names = readdir ( DIR ) or die "Unable to read $LOCALPATH\n" ;
closedir ( DIR ) ;
foreach $ name ( @ names ) {
next if ( $ name eq "." ) ; # skip the current directory entry
next if ( $ name eq ".." ) ; # skip the parent directory entry
die "$LOCALPATH not empty\n" ;
}
2013-06-28 20:10:56 +04:00
}
2013-07-04 19:54:43 +04:00
= head3 C < reset_tmp ( ) >
Remove all files in the temp directory C <$TMP>
= cut
2013-06-28 20:10:56 +04:00
sub reset_tmp {
2013-07-16 02:34:41 +04:00
remove_tree ( $ TMP , { keep_root = > 1 } ) ;
2013-06-28 20:10:56 +04:00
}
2013-06-26 22:41:22 +04:00
2013-07-04 19:54:43 +04:00
= head3 C < reset_env ( ) >
Remove both temp and remote ( C <$DIR> ) files
= cut
2013-06-28 20:10:56 +04:00
sub reset_env {
reset_tmp ( ) ;
reset_remote ( ) ;
}
2013-07-04 19:54:43 +04:00
= head3 C < file_list ( @ files ) >
Make a multiline string of all the files remote path , one path per line .
C <@files> must be a list of C <File> instance .
= cut
2013-07-01 20:01:50 +04:00
sub file_list {
my @ files = @ _ ;
my $ s = '' ;
2013-07-16 02:10:09 +04:00
for ( @ files ) {
2013-07-01 20:01:50 +04:00
$ s . = $ _ - > remotepath . "\n" ;
}
return $ s ;
}
2013-08-05 20:58:39 +04:00
# remove leading "./"
sub remove_dot {
my $ s = shift ;
$ s =~ s{^\./} {} ;
$ s ;
}
2013-07-04 19:54:43 +04:00
= head3 C < check_remote ( $ remotepath , \ @ files ) >
Check if C <$remotepath> has B <exactly> all the C <@files> .
Print a summary on STDOUT .
C <@files> must be a list of C <File> instance .
= cut
2013-06-28 20:10:56 +04:00
sub check_remote {
2013-07-03 01:22:24 +04:00
my ( $ subpath , $ files ) = @ _ ;
2013-06-28 20:10:56 +04:00
my ( % done , % expected ) ;
my ( @ less , @ more , @ diff ) ;
2013-07-16 02:10:09 +04:00
for ( @$ files ) {
2013-08-05 20:58:39 +04:00
my $ fn = remove_dot ( $ _ - > remotepath ) ;
$ expected { $ fn } = $ _ ;
$ done { $ fn } = 0 ;
2013-06-28 20:10:56 +04:00
}
my % remote ;
2013-08-05 20:58:39 +04:00
File:: walk ( sub { $ remote { remove_dot ( $ _ - > remotepath ) } = $ _ } , File:: tree ( $ subpath ) ) ;
2013-06-28 20:10:56 +04:00
2013-07-22 20:49:51 +04:00
for my $ rfile ( sort keys % remote ) {
2013-06-28 20:10:56 +04:00
# files that shouldn't be there
2013-07-16 02:10:09 +04:00
if ( ! exists $ expected { $ rfile } ) {
2013-07-01 19:44:54 +04:00
say " + $rfile" ;
2013-06-28 20:10:56 +04:00
push @ more , $ rfile ;
next ;
}
# same file multiple times
2013-07-16 02:10:09 +04:00
if ( $ done { $ rfile } > 0 ) {
2013-06-28 20:10:56 +04:00
$ done { $ rfile } + + ;
push @ more , $ rfile ;
printf " +%3d %s\n" , $ done { $ rfile } , $ rfile ;
next ;
}
$ done { $ rfile } + + ;
# different file
my $ rmd5 = $ remote { $ rfile } - > md5 ;
2013-07-16 02:10:09 +04:00
if ( $ expected { $ rfile } - > md5 ne $ rmd5 ) {
2013-06-28 20:10:56 +04:00
say " ! $rfile ($rmd5)" ;
push @ diff , $ rfile ;
2013-07-03 18:09:03 +04:00
next ;
}
2013-07-22 20:49:51 +04:00
say " $rfile" ;
2013-06-28 20:10:56 +04:00
}
# file that should have been in tar
2013-07-22 20:49:51 +04:00
@ less = grep { $ done { $ _ } == 0 } sort keys % done ;
2013-07-16 02:10:09 +04:00
for ( @ less ) {
2013-06-28 20:10:56 +04:00
say " - $_" ;
}
# summary
printf ( "\t%d files, +%d, -%d, !%d\n" ,
scalar keys % done ,
scalar @ more ,
scalar @ less ,
scalar @ diff ) ;
return ( @ more + @ less + @ diff ) ; # nb of errors
2013-06-26 22:41:22 +04:00
}
2013-07-04 19:54:43 +04:00
= head3 C < check_tar ( $ path_to_tar , \ @ files ) >
Check if the archive C <$path_to_tar> has B <exactly> all the C <@files> .
Print a summary on C <STDOUT> ;
C <@files> must be a list of C <File> instance .
= cut
2013-06-26 22:41:22 +04:00
sub check_tar {
2013-06-28 05:16:29 +04:00
my ( $ tar , $ files ) = @ _ ;
2013-06-26 22:41:22 +04:00
my % done ;
my ( @ less , @ more , @ diff ) ;
2013-06-28 05:16:29 +04:00
my % h ;
2013-07-24 18:49:06 +04:00
if ( ! - f $ tar ) {
say "no tar file $tar" ;
return 1 ;
}
2013-07-16 02:10:09 +04:00
for ( @$ files ) {
2013-06-28 05:16:29 +04:00
$ h { $ _ - > tarpath } = $ _ ;
$ done { $ _ - > tarpath } = 0 ;
2013-06-26 22:41:22 +04:00
}
2013-07-03 01:22:24 +04:00
my $ total = 0 ;
2013-06-28 05:16:29 +04:00
my $ i = Archive::Tar - > iter ( $ tar , 1 , { md5 = > 1 } ) ;
2013-07-16 02:10:09 +04:00
while ( my $ f = $ i - > ( ) ) {
if ( $ f - > has_content ) {
2013-08-12 18:29:41 +04:00
my $ p = $ f - > full_path ;
2015-12-03 12:23:09 +03:00
# we skip pseudo files of Pax format archives
next if ( $ p =~ m/\/PaxHeader/ ) ;
$ total + + ;
2013-08-12 18:29:41 +04:00
$ p =~ s{^\./+} {} ;
2013-06-26 22:41:22 +04:00
# file that shouldn't be there
2013-07-16 02:10:09 +04:00
if ( ! exists $ done { $ p } ) {
2013-06-26 22:41:22 +04:00
push @ more , $ p ;
say " + $p" ;
next ;
}
# same file multiple times
2013-07-16 02:10:09 +04:00
if ( $ done { $ p } > 0 ) {
2013-06-26 22:41:22 +04:00
$ done { $ p } + + ;
push @ more , $ p ;
printf " +%3d %s\n" , $ done { $ p } , $ p ;
next ;
}
$ done { $ p } + + ;
# different file
2013-07-15 21:01:58 +04:00
2013-06-26 22:41:22 +04:00
my $ md5 = $ f - > data ;
2013-07-16 02:10:09 +04:00
if ( $ ^ V lt v5 .16 ) {
2013-07-15 21:01:58 +04:00
$ md5 = md5_hex ( $ md5 ) ;
}
2013-07-16 02:10:09 +04:00
if ( $ md5 ne $ h { $ p } - > md5 ) {
2013-06-26 22:41:22 +04:00
say " ! $p ($md5)" ;
push @ diff , $ p ;
2013-07-03 01:22:24 +04:00
next ;
}
2013-07-22 20:49:51 +04:00
say " $p" ;
2013-06-26 22:41:22 +04:00
}
}
# file that should have been in tar
@ less = grep { $ done { $ _ } == 0 } keys % done ;
2013-07-17 18:27:01 +04:00
for ( sort @ less ) {
2013-06-26 22:41:22 +04:00
say " - $_" ;
}
# summary
printf ( "\t%d files, +%d, -%d, !%d\n" ,
2013-07-03 01:22:24 +04:00
$ total ,
2013-06-26 22:41:22 +04:00
scalar @ more ,
scalar @ less ,
scalar @ diff ) ;
return ( @ more + @ less + @ diff ) ; # nb of errors
}
2020-11-30 13:18:32 +03:00
= head3 C < smb_client_cmd ( $ will_die , @ args ) >
= head3 C < smb_client_cmd ( 0 , '-c' , 'deltree' , $ somedir ) >
2013-07-04 19:54:43 +04:00
Run smbclient with C <@args> passed as argument and return output .
Each element of C <@args> becomes one escaped argument of smbclient .
2023-07-17 16:03:58 +03:00
Host , share , user , password and the additional arguments provided on
2013-07-04 19:54:43 +04:00
the command - line are already inserted .
The output contains both the C <STDOUT> and C <STDERR> .
2020-11-30 13:18:32 +03:00
if C <$will_die> then Die if smbclient crashes or exits with an error code .
otherwise return output
2013-07-04 19:54:43 +04:00
= cut
2020-11-30 13:18:32 +03:00
sub smb_client_cmd {
my ( $ will_die , @ args ) = @ _ ;
2013-06-27 17:00:24 +04:00
my $ fullpath = "//$HOST/$SHARE" ;
2013-06-26 22:41:22 +04:00
my $ cmd = sprintf ( "%s %s %s" ,
quotemeta ( $ BIN ) ,
2013-06-27 17:00:24 +04:00
quotemeta ( $ fullpath ) ,
join ( ' ' , map { quotemeta } ( @ SMBARGS , @ args ) ) ) ;
2013-06-26 22:41:22 +04:00
2013-07-16 02:10:09 +04:00
if ( $ DEBUG ) {
2013-08-12 18:29:41 +04:00
my $ tmp = $ cmd ;
$ tmp =~ s{\\([./+-])} {$1}g ;
say color ( 'bold yellow' ) , $ tmp , color ( 'reset' ) ;
2013-07-03 01:22:24 +04:00
}
2013-06-26 22:41:22 +04:00
my $ out = `$cmd 2>&1` ;
my $ err = $? ;
2013-08-05 20:55:25 +04:00
my $ errstr = '' ;
2013-06-26 22:41:22 +04:00
# handle abnormal exit
if ( $ err == - 1 ) {
2013-08-05 20:55:25 +04:00
$ errstr = "failed to execute $cmd: $!\n" ;
2013-06-26 22:41:22 +04:00
}
elsif ( $ err & 127 ) {
2013-08-05 20:55:25 +04:00
$ errstr = sprintf "child died with signal %d (%s)\n" , ( $ err & 127 ) , $ cmd ;
2013-06-26 22:41:22 +04:00
}
elsif ( $ err >> 8 ) {
2013-08-05 20:55:25 +04:00
$ errstr = sprintf "child exited with value %d (%s)\n" , ( $ err >> 8 ) , $ cmd ;
2013-06-26 22:41:22 +04:00
}
2013-07-16 02:10:09 +04:00
if ( $ DEBUG ) {
2013-06-27 22:30:44 +04:00
say $ out ;
2013-06-27 17:00:24 +04:00
}
2013-07-16 02:10:09 +04:00
if ( $ err ) {
2020-11-30 13:18:32 +03:00
if ( $ will_die ) {
die "ERROR: $errstr" ;
} else {
say "ERROR: $errstr" ;
}
2013-06-26 22:41:22 +04:00
}
return $ out ;
}
2020-11-30 13:18:32 +03:00
= head3 C < smb_client ( @ args ) >
Run smbclient with C <@args> passed as argument and return output .
Each element of C <@args> becomes one escaped argument of smbclient .
2023-07-17 16:03:58 +03:00
Host , share , user , password and the additional arguments provided on
2020-11-30 13:18:32 +03:00
the command - line are already inserted .
The output contains both the C <STDOUT> and C <STDERR> .
Die if smbclient crashes or exits with an error code .
= cut
sub smb_client {
my ( @ args ) = @ _ ;
return smb_client_cmd ( 1 , @ args )
}
2013-06-26 22:41:22 +04:00
sub smb_cmd {
return smb_client ( '-c' , join ( ' ' , @ _ ) ) ;
}
2013-07-04 19:54:43 +04:00
= head3 C < smb_tar ( $ cmd , @ args ) >
= head3 C < smb_tar ( 'tarmode inc' , '-Tc' , $ TAR , $ DIR ) >
Run C <$cmd> command and use C <@args> as argument and return output .
Wrapper around C <smb_client> for tar calls .
= cut
2013-06-26 22:41:22 +04:00
sub smb_tar {
my ( $ cmd , @ rest ) = @ _ ;
printf " CMD: %s\n ARG: %s\n" , $ cmd , join ( ' ' , @ rest ) ;
smb_client ( ( length ( $ cmd ) ? ( '-c' , $ cmd ) : ( ) ) , @ rest ) ;
}
2013-07-04 19:54:43 +04:00
= head3 C < random ( $ min , $ max ) >
2013-07-14 17:22:36 +04:00
Return integer in C < [ $ min ; $ max ] >
2013-07-04 19:54:43 +04:00
= cut
2013-06-28 05:16:29 +04:00
sub random {
my ( $ min , $ max ) = @ _ ;
2013-07-16 02:10:09 +04:00
( $ min , $ max ) = ( $ max , $ min ) if ( $ min > $ max ) ;
2013-06-28 05:16:29 +04:00
$ min + int ( rand ( $ max - $ min ) ) ;
}
2013-07-04 19:54:43 +04:00
#################################
2013-06-28 05:16:29 +04:00
package File ;
2013-07-04 19:54:43 +04:00
= head2 The File module
All the test should use the C <File> class . It has nice functions and
methods to deal with paths , to create random files , to list the
content of the server , to change attributes , etc .
There are 2 kinds of C <File> : remote and local .
= over
= item * Remote files are accessible on the server .
= item * Local files are not .
= back
Thus , some methods only works on remote files . If they do not make
sense for local ones , they always return undef .
= cut
2013-06-28 05:16:29 +04:00
use File::Basename ;
use File::Path qw/make_path remove_tree/ ;
use Digest::MD5 qw/md5_hex/ ;
2013-07-03 01:22:24 +04:00
use Scalar::Util 'blessed' ;
2013-07-04 19:54:43 +04:00
= head3 Constructors
2013-07-17 20:54:07 +04:00
= head4 C << File - > new_remote ( $ path [ , $ abs , $ size ] ) >>
2013-07-04 19:54:43 +04:00
Creates a file accessible on the server at C <$DIR/$path> ie . not at the
2013-07-17 20:54:07 +04:00
root of the share and write C <$size> random bytes .
If no size is provided , a random size is chosen .
2013-07-04 19:54:43 +04:00
If you want to remove the automatic prefix C <$DIR> , set C <$abs> to 1 .
The file is created without any DOS attributes .
If C <$path> contains non - existent directories , they are automatically
created .
= cut
sub new_remote {
2013-07-17 20:54:07 +04:00
my ( $ class , $ path , $ abs , $ size ) = @ _ ;
2013-07-04 19:54:43 +04:00
my ( $ file , $ dir ) = fileparse ( $ path ) ;
$ dir = '' if $ dir eq './' ;
my $ loc ;
2013-07-16 02:10:09 +04:00
if ( $ abs ) {
2013-07-04 19:54:43 +04:00
$ loc = cleanpath ( $ main:: LOCALPATH . '/' . $ dir ) ;
} else {
$ dir = cleanpath ( $ main:: DIR . '/' . $ dir ) ;
$ loc = cleanpath ( $ main:: LOCALPATH . '/' . $ dir ) ;
}
make_path ( $ loc ) ;
my $ self = bless {
'attr' = > { qw/r 0 s 0 h 0 a 0 d 0 n 0/ } ,
'dir' = > $ dir ,
'name' = > $ file ,
2013-07-17 20:54:07 +04:00
'md5' = > create_file ( $ loc . '/' . $ file , $ size ) ,
2013-07-04 19:54:43 +04:00
'remote' = > 1 ,
} , $ class ;
$ self - > set_attr ( ) ;
$ self ;
2013-07-03 01:22:24 +04:00
}
2013-06-28 05:16:29 +04:00
2013-07-04 19:54:43 +04:00
= head4 C << File - > new_local ( $ abs_path [ , $ data ] ) >>
Creates a file at C <$abs_path> with $ data in it on the system .
If $ data is not provided , fill it with random bytes .
= cut
sub new_local {
my ( $ class , $ path , $ data ) = @ _ ;
my ( $ file , $ dir ) = fileparse ( $ path ) ;
make_path ( $ dir ) ;
my $ md5 ;
2013-07-16 02:10:09 +04:00
if ( defined $ data ) {
2013-07-04 19:54:43 +04:00
open my $ f , '>' , $ path or die "can't write in $path: $!" ;
print $ f $ data ;
close $ f ;
$ md5 = md5_hex ( $ data ) ;
} else {
$ md5 = create_file ( $ path ) ;
2013-06-26 22:41:22 +04:00
}
2013-07-04 19:54:43 +04:00
my $ self = {
'attr' = > { qw/r 0 s 0 h 0 a 0 d 0 n 0/ } ,
'dir' = > $ dir ,
'name' = > $ file ,
'md5' = > $ md5 ,
'remote' = > 0 ,
} ;
bless $ self , $ class ;
2013-06-26 22:41:22 +04:00
}
2013-07-04 19:54:43 +04:00
= head3 Methods
= head4 C << $ f - > localpath >>
Return path on the system eg . F </opt/samba/share/test_tar_mode/file>
= cut
2013-06-28 05:16:29 +04:00
sub localpath {
my $ s = shift ;
2013-07-16 02:10:09 +04:00
if ( $ s - > { remote } ) {
2013-07-03 01:22:24 +04:00
return cleanpath ( $ main:: LOCALPATH . '/' . $ s - > remotepath ) ;
}
else {
return cleanpath ( $ s - > { dir } . '/' . $ s - > { name } ) ;
}
2013-06-28 05:16:29 +04:00
}
2013-07-04 19:54:43 +04:00
= head4 C << $ f - > remotepath >>
Return path on the server share .
Return C <undef> if the file is local .
= cut
2013-06-28 05:16:29 +04:00
sub remotepath {
2013-07-03 01:22:24 +04:00
my ( $ s ) = @ _ ;
2013-06-28 05:16:29 +04:00
return undef if ! $ s - > { remote } ;
2013-08-12 18:29:41 +04:00
my $ r = $ s - > { dir } . '/' . $ s - > { name } ;
$ r =~ s{^/} {} ;
return cleanpath ( $ r ) ;
2013-06-28 05:16:29 +04:00
}
2013-07-04 19:54:43 +04:00
= head4 C << $ f - > remotedir >>
Return the directory path of the file on the server .
Like C << $ f - > remotepath >> but without the final file name .
= cut
2013-06-28 05:16:29 +04:00
sub remotedir {
my $ s = shift ;
return undef if ! $ s - > { remote } ;
2013-07-03 01:22:24 +04:00
cleanpath ( $ s - > { dir } ) ;
2013-06-28 05:16:29 +04:00
}
2013-07-04 19:54:43 +04:00
= head4 C << $ f - > tarpath >>
Return path as it would appear in a tar archive .
Like C << $ f - > remotepath >> but prefixed with F <./>
= cut
2013-06-28 05:16:29 +04:00
sub tarpath {
my $ s = shift ;
return undef if ! $ s - > { remote } ;
2013-08-12 18:29:41 +04:00
my $ r = $ s - > remotepath ;
$ r =~ s{^\./+} {} ;
return $ r ;
2013-07-03 01:22:24 +04:00
}
2013-07-04 19:54:43 +04:00
= head4 C << $ f - > delete_on_destruction ( 0 ) >>
= head4 C << $ f - > delete_on_destruction ( 1 ) >>
By default , a C <File> is not deleted on the filesystem when it is not
referenced anymore in Perl memory .
When set to 1 , the destructor unlink the file if it is not already removed .
If the C <File> created directories when constructed , it does not remove them .
= cut
2013-07-03 01:22:24 +04:00
sub delete_on_destruction {
my ( $ s , $ delete ) = @ _ ;
$ s - > { delete_on_destruction } = $ delete ;
2013-06-28 05:16:29 +04:00
}
2013-07-04 19:54:43 +04:00
= head4 C << $ f - > set_attr ( ) >>
= head4 C << $ f - > set_attr ( 'a' ) >>
= head4 C << $ f - > set_attr ( 'a' , 'r' , 's' , 'h' ) >>
Remove all DOS attributes and only set the one provided .
= cut
2013-06-26 22:41:22 +04:00
sub set_attr {
2013-06-28 05:16:29 +04:00
my ( $ s , @ flags ) = @ _ ;
return undef if ! $ s - > { remote } ;
2013-06-26 22:41:22 +04:00
2013-06-28 05:16:29 +04:00
$ s - > { attr } = { qw/r 0 s 0 h 0 a 0 d 0 n 0/ } ;
2013-07-16 02:10:09 +04:00
for ( @ flags ) {
2013-06-28 05:16:29 +04:00
$ s - > { attr } { lc ( $ _ ) } = 1 ;
}
my $ file = $ s - > { name } ;
2013-07-03 01:22:24 +04:00
my @ args ;
2013-07-16 02:10:09 +04:00
if ( $ s - > remotedir ) {
2013-07-03 01:22:24 +04:00
push @ args , '-D' , $ s - > remotedir ;
}
main:: smb_client ( @ args , '-c' , qq{ setmode "$file" -rsha } ) ;
2013-07-16 02:10:09 +04:00
if ( @ flags && $ flags [ 0 ] !~ /n/i ) {
2013-07-03 01:22:24 +04:00
main:: smb_client ( @ args , '-c' , qq{ setmode "$file" + } . join ( '' , @ flags ) ) ;
2013-06-26 22:41:22 +04:00
}
}
2013-07-04 19:54:43 +04:00
= head4 C << $ f - > attr_any ( 'a' ) >>
= head4 C << $ f - > attr_any ( 'a' , 's' , ... ) >>
Return 1 if the file has any of the DOS attributes provided .
= cut
sub attr_any {
my ( $ s , @ flags ) = @ _ ;
2013-07-16 02:10:09 +04:00
for ( @ flags ) {
2013-07-04 19:54:43 +04:00
return 1 if $ s - > { attr } { $ _ } ;
}
0 ;
}
= head4 C << $ f - > attr ( 'a' ) >>
= head4 C << $ f - > attr ( 'a' , 's' , ... ) >>
Return 1 if the file has all the DOS attributes provided .
= cut
sub attr {
my ( $ s , @ flags ) = @ _ ;
2013-07-16 02:10:09 +04:00
for ( @ flags ) {
2013-07-04 19:54:43 +04:00
return 0 if ! $ s - > { attr } { $ _ } ;
}
1 ;
}
= head4 C << $ f - > attr_str >>
Return DOS attributes as a compact string .
2023-07-17 16:03:58 +03:00
Read - only , hidden , system , archive = > "rhsa"
2013-07-04 19:54:43 +04:00
= cut
2013-06-28 05:16:29 +04:00
sub attr_str {
my $ s = shift ;
return undef if ! $ s - > { remote } ;
join ( '' , map { $ _ if $ s - > { attr } { $ _ } } qw/r h s a d n/ ) ;
}
2013-06-27 20:53:34 +04:00
2013-07-04 19:54:43 +04:00
= head4 C << $ f - > set_time ( $ t ) >>
2013-06-28 20:10:56 +04:00
2013-07-04 19:54:43 +04:00
Set modification and access time of the file to C <$t> .
C <$t> must be in Epoch time ( number of seconds since 1970 /1/ 1 ) .
= cut
2013-06-28 05:16:29 +04:00
sub set_time {
my ( $ s , $ t ) = @ _ ;
utime $ t , $ t , $ s - > localpath ;
2013-06-27 20:53:34 +04:00
}
2013-07-04 19:54:43 +04:00
= head4 C << $ f - > md5 >>
Return md5 sum of the file .
The result is cached .
= cut
2013-06-28 20:10:56 +04:00
sub md5 {
my $ s = shift ;
2013-07-16 02:10:09 +04:00
if ( ! $ s - > { md5 } ) {
2013-06-28 20:10:56 +04:00
open my $ h , '<' , $ s - > localpath ( ) or die "can't read " . $ s - > localpath . ": $!" ;
binmode $ h ;
$ s - > { md5 } = Digest::MD5 - > new - > addfile ( $ h ) - > hexdigest ;
close $ h ;
}
return $ s - > { md5 } ;
}
2013-07-04 19:54:43 +04:00
sub DESTROY {
my $ s = shift ;
2013-07-16 02:10:09 +04:00
if ( $ s - > { delete_on_destruction } && - f $ s - > localpath ) {
if ( $ main:: DEBUG ) {
2013-07-04 19:54:43 +04:00
say "DESTROY " . $ s - > localpath ;
}
unlink $ s - > localpath ;
}
}
= head3 Functions
= head4 C << File:: walk ( \ & function , @ files ) >>
= head4 C << File:: walk ( sub { ... } , @ files ) >>
2019-08-29 22:50:45 +03:00
Iterate on file hierarchy in C <@files> and return accumulated results .
2013-07-04 19:54:43 +04:00
2013-07-14 17:22:36 +04:00
Use C <$_> in the sub to access the current C < File > .
2013-07-04 19:54:43 +04:00
The C <@files> must come from a call to the C <File::tree> function .
= cut
2013-06-28 20:10:56 +04:00
sub walk {
my $ fun = \ & { shift @ _ } ;
my @ res ;
for ( @ _ ) {
2013-07-16 02:10:09 +04:00
if ( $ _ - > { attr } { d } ) {
2013-06-28 20:10:56 +04:00
push @ res , walk ( $ fun , @ { $ _ - > { content } } ) ;
} else {
push @ res , $ fun - > ( $ _ ) ;
}
}
return @ res ;
}
2013-07-04 19:54:43 +04:00
= head4 C << File:: list ( $ remotepath ) >>
2013-06-28 20:10:56 +04:00
2013-07-04 19:54:43 +04:00
Return list of file ( C <File> instance ) in C <$remotepath> .
2013-06-28 20:10:56 +04:00
2013-07-04 19:54:43 +04:00
C <$remotepath> must be a directory .
2013-06-28 20:10:56 +04:00
2013-07-04 19:54:43 +04:00
= cut
2013-06-28 05:16:29 +04:00
sub list {
2013-07-04 19:54:43 +04:00
my ( $ path ) = @ _ ;
2013-07-03 01:22:24 +04:00
$ path || = '/' ;
2013-06-28 05:16:29 +04:00
my @ files ;
2013-07-03 01:22:24 +04:00
my $ out = main:: smb_client ( '-D' , $ path , '-c' , 'ls' ) ;
2013-08-12 18:29:41 +04:00
$ path =~ s{^/} {} ;
2013-06-28 05:16:29 +04:00
2013-07-16 02:10:09 +04:00
for ( split /\n/ , $ out ) {
2013-07-15 21:04:43 +04:00
next if ! /^ (.+?)\s+([AHSRDN]*)\s+(\d+)\s+(.+)/o ;
2013-06-28 05:16:29 +04:00
my ( $ fn , $ attr , $ size , $ date ) = ( $ 1 , $ 2 , $ 3 , $ 4 ) ;
next if $ fn =~ /^\.{1,2}$/ ;
push @ files , bless {
'remote' = > 1 ,
2013-08-12 18:29:41 +04:00
'dir' = > $ path ,
2013-06-28 05:16:29 +04:00
'name' = > $ fn ,
'size' = > int ( $ size ) ,
'date' = > $ date ,
'attr' = > {
2013-07-14 17:22:36 +04:00
# list context returns something different than the
2013-06-28 05:16:29 +04:00
# boolean matching result => force scalar context
'a' = > scalar ( $ attr =~ /A/ ) ,
'h' = > scalar ( $ attr =~ /H/ ) ,
's' = > scalar ( $ attr =~ /S/ ) ,
'r' = > scalar ( $ attr =~ /R/ ) ,
'd' = > scalar ( $ attr =~ /D/ ) ,
'n' = > scalar ( $ attr =~ /N/ ) ,
} ,
2013-07-04 19:54:43 +04:00
} , 'File' ;
2013-06-28 05:16:29 +04:00
}
return @ files ;
2013-06-27 22:30:44 +04:00
}
2013-07-04 19:54:43 +04:00
= head4 C << File:: tree ( $ remotepath ) >>
2013-06-28 05:16:29 +04:00
2013-07-04 19:54:43 +04:00
Return recursive list of file in C <$remotepath> .
2013-07-03 01:22:24 +04:00
2013-07-04 19:54:43 +04:00
C <$remotepath> must be a directory .
Use C <File::walk()> to iterate over all the files .
= cut
sub tree {
my ( $ d ) = @ _ ;
my @ files ;
2013-07-16 02:10:09 +04:00
if ( ! defined $ d ) {
2013-07-04 19:54:43 +04:00
@ files = list ( ) ;
2013-07-16 02:10:09 +04:00
} elsif ( blessed $ d ) {
2013-07-04 19:54:43 +04:00
@ files = list ( $ d - > remotepath ) ;
2013-07-03 01:22:24 +04:00
} else {
2013-07-04 19:54:43 +04:00
@ files = list ( $ d ) ;
2013-07-03 01:22:24 +04:00
}
2013-06-28 05:16:29 +04:00
2013-07-04 19:54:43 +04:00
for my $ f ( @ files ) {
2013-07-16 02:10:09 +04:00
if ( $ f - > { attr } { d } ) {
2013-07-04 19:54:43 +04:00
$ f - > { content } = [ tree ( $ f ) ] ;
}
}
2013-06-28 05:16:29 +04:00
2013-07-04 19:54:43 +04:00
return @ files ;
}
2013-06-28 05:16:29 +04:00
2013-07-04 19:54:43 +04:00
# remove trailing or duplicated slash
sub cleanpath {
my $ p = shift ;
$ p =~ s{/+} {/}g ;
$ p =~ s{/$} {} ;
$ p ;
2013-06-26 22:41:22 +04:00
}
2013-06-28 05:16:29 +04:00
2013-07-04 19:54:43 +04:00
# create random file at path local path $fn
sub create_file {
2013-07-17 20:54:07 +04:00
my ( $ fn , $ size ) = @ _ ;
2013-07-04 19:54:43 +04:00
my $ buf = '' ;
unlink $ fn if - e $ fn ;
2013-07-17 20:54:07 +04:00
$ size || = main:: random ( 512 , 1024 ) ;
$ size = int ( $ size ) ;
my $ md5 ;
# try /dev/urandom, faster
if ( - e '/dev/urandom' ) {
my $ cmd = sprintf ( 'head -c %d /dev/urandom | tee %s | md5sum' ,
$ size , quotemeta ( $ fn ) ) ;
$ md5 = ( split / / , `$cmd` ) [ 0 ] ;
} else {
open my $ out , '>' , $ fn or die "can't open $fn: $!\n" ;
binmode $ out ;
for ( 1 .. $ size ) {
$ buf . = pack ( 'C' , main:: random ( 0 , 256 ) ) ;
}
print $ out $ buf ;
close $ out ;
$ md5 = md5_hex ( $ buf ) ;
2013-07-04 19:54:43 +04:00
}
2013-07-17 20:54:07 +04:00
return $ md5 ;
2013-07-04 19:54:43 +04:00
}
2013-06-28 05:16:29 +04:00
2013-07-04 19:54:43 +04:00
= head3 Examples
2013-07-01 20:01:50 +04:00
2013-07-04 19:54:43 +04:00
# create remote file in $DIR/foo/bar
my $ f = File - > new_remote ( "foo/bar/myfile" ) ;
say $ f - > localpath ; # /opt/share/$DIR/foo/bar/myfile
say $ f - > remotepath ; # $DIR/foo/bar/myfile
say $ f - > remotedir ; # $DIR/foo/bar
2013-07-01 20:01:50 +04:00
2013-06-28 05:16:29 +04:00
2013-07-04 19:54:43 +04:00
# same but in root dir
my $ f = File - > new_remote ( "myfile" , 1 ) ;
say $ f - > localpath ; # /opt/share/myfile
say $ f - > remotepath ; # myfile
say $ f - > remotedir ; #
2013-06-28 05:16:29 +04:00
2013-07-04 19:54:43 +04:00
# create local random temp file in $TMP
my $ f = File - > new_local ( "$TMP/temp" ) ;
say $ f - > remotepath ; # undef because it's not on the server
# same but file contains "hello"
my $ f = File - > new_local ( "$TMP/temp" , "hello" ) ;
# list of files in $DIR (1 level)
for ( File:: list ( $ DIR ) ) {
say $ _ - > remotepath ;
2013-07-03 01:22:24 +04:00
}
2013-07-04 19:54:43 +04:00
# list of all files in dir and subdir of $DIR
File:: walk ( sub { say $ _ - > remotepath } , File:: tree ( $ DIR ) ) ;
= cut
2013-07-03 01:22:24 +04:00
2013-06-28 05:16:29 +04:00
1 ;