File Coverage

blib/lib/Net/uFTP/SFTP.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package Net::uFTP::SFTP;
2              
3 1     1   765 use vars qw($VERSION);
  1         3  
  1         53  
4              
5             $VERSION = 0.16;
6             #--------------
7              
8 1     1   5 use warnings;
  1         2  
  1         26  
9 1     1   5 use strict;
  1         1  
  1         37  
10 1     1   5 use Carp;
  1         1  
  1         84  
11 1     1   1478 use Net::SSH2;
  0            
  0            
12             use File::Spec;
13             use File::Basename qw(basename dirname);
14             use File::Stat::ModeString;
15             use File::Find;
16             use File::Path qw(mkpath);
17             use Cwd qw(getcwd);
18             #======================================================================
19             use base qw(Class::Accessor::Fast::XS);
20             #----------------------------------------------------------------------
21             __PACKAGE__->mk_accessors(qw(ssh sftp host user password debug root _cwd port));
22             #======================================================================
23             sub new {
24             my ($self, $host, %params) = (shift, shift, @_);
25            
26             $self = bless \%params, $self;
27             $self->host($host);
28             $self->ssh(Net::SSH2->new());
29             $self->ssh()->blocking( 1 );
30             $self->ssh()->debug($self->debug() ? 1 : 0);
31             #$self->ssh()->connect($host . q/:/ . $params{port});
32             $self->ssh()->connect($host, $self->port) or return;
33             $self->ssh()->auth_password($self->user(), $self->password()) or return;
34             #$self->ssh()->auth(username => $self->user(), password => $self->password());
35             $self->sftp($self->ssh()->sftp());
36             $self->root($self->sftp()->realpath('.'));
37             $self->cwd($self->root());
38             $self->_cwd('/');
39              
40             return $self;
41             }
42             #======================================================================
43             sub change_root {
44             my ($self, $root) = @_;
45             $self->root($root);
46             $self->cwd($root);
47             $self->_cwd('/');
48             return $root;
49             }
50             #======================================================================
51             sub cwd {
52             # ustawiamy sciezke na poczatkowa jesli nie zostal podany argument
53             return $_[0]->_cwd($_[0]->root()) unless defined $_[1];
54             my $realpath = $_[0]->sftp()->realpath(File::Spec->catfile($_[0]->_cwd(), $_[1]));
55             return $realpath ? $_[0]->_cwd($realpath) : undef;
56             }
57             #======================================================================
58             sub pwd {
59             my ($self) = @_;
60             my $root = $self->root();
61             (my $cwd = $self->_cwd()) =~ s/^$root//;
62             return ($cwd and $cwd ne 0) ? $cwd : '/';
63             }
64             #======================================================================
65             sub ls {
66             my ($self, $path) = @_;
67            
68             my $_path = defined $path ? $path : $self->pwd();
69             my $root = ($_path =~ /^\//o) ? $self->root() : $self->_cwd();
70             $root = File::Spec->catfile($root,$_path);
71             my $r = $self->root();
72             (my $remote = $root) =~ s/^$r//;
73            
74             if(my $dir = $self->sftp()->opendir($root)){
75             my @files;
76             while(my $file = $dir->read){
77             next if $file->{name} =~ /^\./;
78             push @files, $file->{name};
79             }
80             return @files unless defined $path;
81             return map { File::Spec->catfile($path,$_) } @files;
82             }else{
83             return $remote if $self->sftp()->open($root);
84             }
85             }
86             #======================================================================
87             sub dir {
88             my ($self, $path) = @_;
89            
90             my @abbr = qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec );
91             $path = $self->pwd() unless defined $path;
92             my $root = ($path =~ /^\//o) ? $self->root() : $self->_cwd();
93             $root = File::Spec->catfile($root,$path);
94            
95             if(my $dir = $self->sftp()->opendir($root)){
96             my @files;
97             while(my $file = $dir->read){
98             next if $file->{name} =~ /^\./;
99             my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($file->{mtime});
100             push @files, mode_to_string($file->{mode}).qq/\tx $file->{uid}\t\t$file->{gid}\t\t$file->{size}\t$abbr[$mon] $mday $hour:$min\t$file->{name}/;
101             }
102             return @files;
103             }else{
104             return unless my $dir = $self->sftp()->opendir(dirname($root));
105             my $basename = basename($root);
106             while(my $file = $dir->read()){
107             my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($file->{mtime});
108             return mode_to_string($file->{mode}).qq/\tx $file->{uid}\t\t$file->{gid}\t\t$file->{size}\t$abbr[$mon] $mday $hour:$min\t$file->{name}/
109             if $file->{name} eq $basename;
110             }
111             }
112             }
113             #======================================================================
114             sub rename {
115             my ($self, $remote, $nremote) = @_;
116             return unless defined $remote and defined $nremote;
117              
118             my $root = ($remote =~ /^\//o) ? $self->root() : $self->_cwd();
119             my $nroot = ($nremote =~ /^\//o) ? $self->root() : $self->_cwd();
120            
121             return $self->sftp()->rename(File::Spec->catfile($root,$remote), File::Spec->catfile($nroot,$nremote));
122             }
123             #======================================================================
124             sub size {
125             my ($self, $remote) = @_;
126             return unless defined $remote;
127             my $root = ($remote =~ /^\//o) ? $self->root() : $self->_cwd();
128             $remote = File::Spec->catfile($root,$remote);
129             return unless $self->sftp()->open($remote);
130             return ($self->sftp()->stat($remote))->{size};
131             }
132             #======================================================================
133             sub mdtm {
134             my ($self, $remote) = @_;
135             return unless defined $remote;
136             my $root = ($remote =~ /^\//o) ? $self->root() : $self->_cwd();
137             $remote = File::Spec->catfile($root,$remote);
138             return unless $self->sftp()->open($remote);
139             return ($self->sftp()->stat($remote))->{mtime};
140             }
141             #======================================================================
142             sub put {
143             my ($self, $local, $remote, $recurse) = @_;
144             return if not defined $local or not -e $local;
145              
146             $remote = $self->pwd() unless defined $remote;
147             my $root = ($remote =~ /^\//o) ? $self->root() : $self->_cwd();
148             $root = File::Spec->catfile($root,$remote);
149             $root = File::Spec->catfile($root, basename($local)) if $self->sftp()->opendir($root);
150             $root = File::Spec->canonpath($root);
151            
152             if(not $recurse and -d $local){
153             $self->mkdir($root);
154             }elsif(-d $local){
155             my (@dirs, @files);
156             find(sub {
157             return if /^\./o;
158             if(-d $File::Find::name){ push @dirs, $File::Find::name; }
159             elsif(-f $File::Find::name){ push @files, $File::Find::name; }
160             }, $local);
161            
162             @dirs = map { s/^$local//o; $_} @dirs;
163             $self->mkdir($root, 1);
164             $self->mkdir(File::Spec->catfile($root,$_),1) for @dirs;
165            
166             for(@files){
167             (my $r = $_) =~ s/^$local//o;
168             $self->ssh()->scp_put($_, quotemeta(File::Spec->canonpath(File::Spec->catfile($root,$r))));
169             }
170             }elsif(-f $local){
171             $self->mkdir(dirname($remote));
172             $self->ssh()->scp_put($local, quotemeta($root));
173             }
174             }
175             #======================================================================
176             sub is_dir {
177             my ($self, $path) = @_;
178             return 1 if defined $path and $self->sftp()->opendir($path);
179             return;
180             }
181             #======================================================================
182             sub get {
183             my ($self, $remote, $local, $recurse) = @_;
184             return unless defined $remote and $self->mdtm($remote);
185            
186             $local = getcwd() unless defined $local;
187             if(-d $local){ $local = File::Spec->catfile($local, basename($remote)); }
188             else{ mkpath dirname($local); }
189            
190             my $root = $remote =~ /^\//o ? $self->root() : $self->_cwd();
191             (my $src = $remote) =~ s/^$root//o;
192             $src = File::Spec->catfile($root, $src);
193            
194             if(my $dir = $self->sftp()->opendir($src)){
195             mkpath $local;
196             return unless $recurse;
197             while(my $file = $dir->read()){
198             next if $file->{name} =~ /^\./o;
199             my $this = File::Spec->catfile($src, $file->{name});
200             my $dst = File::Spec->catfile($local, $file->{name});
201             if($self->is_dir($this)){
202             $self->get(File::Spec->catfile($remote, $file->{name}), $dst, 1);
203             }else{
204             $self->ssh()->scp_get(quotemeta($this), $dst);
205             }
206             }
207             }else {
208             $self->ssh()->scp_get(quotemeta($src), $local);
209             }
210             }
211             #======================================================================
212             sub delete {
213             my ($self, $remote) = @_;
214             return unless defined $remote;
215             my $root = $remote =~ /^\//o ? $self->root() : $self->_cwd();
216             $remote =~ s/^$root//o;
217             return $self->sftp()->unlink(File::Spec->catfile($root, $remote));
218             }
219             #======================================================================
220             sub mkdir {
221             my ($self, $path, $recurse) = @_;
222             return unless defined $path;
223             my $root = $path =~ /^\//o ? $self->root() : $self->_cwd();
224             (my $tmp = $path) =~ s/^$root//o;
225            
226             # powrot jest taki katalog juz istnieje
227             return File::Spec->catfile($self->pwd(),$path) if $self->sftp()->opendir(File::Spec->catfile($root, $tmp));
228            
229             my @path = $recurse ? split(/\//o, $tmp) : ($tmp);
230            
231             for my $dir(@path){
232             $root = File::Spec->catfile($root, $dir);
233             $self->sftp()->mkdir($root);
234             }
235            
236             return File::Spec->catfile($self->pwd(),$path);
237             }
238             #======================================================================
239             sub rmdir {
240             my ($self, $path, $recurse) = @_;
241             return unless defined $path;
242             my $root = $self->_cwd();
243             $path =~ s/^$root//o;
244             $path = File::Spec->catfile($root, $path);
245            
246             if($recurse){
247             my $dir = $self->sftp()->opendir($path);
248             return unless $dir;
249             while(my $file = $dir->read()){
250             next if $file->{name} eq q/./ or $file->{name} eq q/../;
251             my $p = File::Spec->catfile($path, $file->{name});
252             if($self->sftp()->opendir($p)){ $self->rmdir($p, 1); }
253             else { $self->sftp()->unlink($p); }
254             }
255             }
256            
257             $self->sftp()->rmdir($path);
258            
259             return;
260             }
261             #======================================================================
262             sub message { return $_[0]->ssh()->error(); }
263             #======================================================================
264             sub cdup {
265             my ($self) = @_;
266             # powrot, jesli wyzej sie nie da
267             return 1 if $self->root() eq $self->_cwd();
268             $self->cwd(dirname($self->_cwd()));
269             return 1;
270             }
271             #======================================================================
272             sub binary { }
273             #======================================================================
274             sub ascii { }
275             #======================================================================
276             sub pasv { }
277             #======================================================================
278             sub quit { return $_[0]->ssh()->disconnect(); }
279             #======================================================================
280             #======================================================================
281             1;