line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Evo::Fs; |
2
|
8
|
|
|
8
|
|
3988
|
use Evo '-Export *; -Class; ::Stat; -Path; Carp croak; -Path'; |
|
8
|
|
|
|
|
19
|
|
|
8
|
|
|
|
|
53
|
|
3
|
|
|
|
|
|
|
die "Win isn't supported yet. Pull requests are welcome!" if $^O eq 'MSWin32'; |
4
|
|
|
|
|
|
|
|
5
|
8
|
|
|
8
|
|
57
|
use Fcntl qw(:seek O_RDWR O_RDONLY O_WRONLY O_RDWR O_CREAT O_TRUNC O_APPEND O_EXCL :flock); |
|
8
|
|
|
|
|
16
|
|
|
8
|
|
|
|
|
1318
|
|
6
|
8
|
|
|
8
|
|
47
|
use Evo 'File::Spec; File::Path; Cwd() abs_path; File::Basename fileparse; Symbol()'; |
|
8
|
|
|
|
|
15
|
|
|
8
|
|
|
|
|
29
|
|
7
|
8
|
|
|
8
|
|
3005
|
use Time::HiRes (); |
|
8
|
|
|
|
|
7501
|
|
|
8
|
|
|
|
|
234
|
|
8
|
8
|
|
|
8
|
|
48
|
use Evo 'List::Util first; File::Copy ()'; |
|
8
|
|
|
|
|
17
|
|
|
8
|
|
|
|
|
121
|
|
9
|
8
|
|
|
8
|
|
50
|
use Errno qw(EAGAIN EWOULDBLOCK); |
|
8
|
|
|
|
|
15
|
|
|
8
|
|
|
|
|
983
|
|
10
|
8
|
|
|
8
|
|
284
|
use Scalar::Util; |
|
8
|
|
|
|
|
19
|
|
|
8
|
|
|
|
|
1086
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
sub SKIP_HIDDEN : Export : prototype() { |
13
|
7
|
50
|
|
7
|
|
70
|
sub($dir) { |
|
7
|
50
|
|
|
|
18
|
|
|
7
|
|
|
|
|
11
|
|
|
7
|
|
|
|
|
11
|
|
14
|
7
|
|
|
|
|
41
|
my @dirs = File::Spec->splitdir($dir); |
15
|
7
|
|
|
|
|
39
|
$dirs[-1] !~ /^\./; |
16
|
5
|
|
|
5
|
1
|
37
|
}; |
17
|
8
|
|
|
8
|
|
121
|
} |
|
8
|
|
|
|
|
16
|
|
|
8
|
|
|
|
|
60
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
# ========= CLASS ========= |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
has root => |
24
|
|
|
|
|
|
|
check sub($v) { File::Spec->file_name_is_absolute($v) ? 1 : (0, "root should be absolute") }; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
|
27
|
2
|
50
|
|
2
|
1
|
14
|
sub cd ($self, $rel) { |
|
2
|
50
|
|
|
|
9
|
|
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
4
|
|
28
|
2
|
|
|
|
|
14
|
my $root = Evo::Path->from_string('', $self->root . '')->append_unsafe($rel)->to_string; |
29
|
2
|
|
|
|
|
23
|
ref($self)->new(root => $root); |
30
|
|
|
|
|
|
|
} |
31
|
|
|
|
|
|
|
|
32
|
568
|
50
|
|
568
|
1
|
1188
|
sub path2real ($self, $rel) { |
|
568
|
50
|
|
|
|
1095
|
|
|
568
|
|
|
|
|
793
|
|
|
568
|
|
|
|
|
831
|
|
|
568
|
|
|
|
|
718
|
|
33
|
568
|
|
|
|
|
2474
|
Evo::Path->from_string($rel, $self->root . '')->to_string; |
34
|
|
|
|
|
|
|
} |
35
|
|
|
|
|
|
|
|
36
|
78
|
50
|
|
78
|
0
|
588
|
sub exists ($self, $path) { |
|
78
|
50
|
|
|
|
172
|
|
|
78
|
|
|
|
|
109
|
|
|
78
|
|
|
|
|
111
|
|
|
78
|
|
|
|
|
112
|
|
37
|
78
|
|
|
|
|
140
|
-e $self->path2real($path); |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
|
41
|
14
|
50
|
|
14
|
0
|
94
|
sub mkdir ($self, $path, $perm = undef) { |
|
14
|
50
|
|
|
|
44
|
|
|
14
|
|
|
|
|
26
|
|
|
14
|
|
|
|
|
26
|
|
|
14
|
|
|
|
|
27
|
|
|
14
|
|
|
|
|
23
|
|
42
|
14
|
|
|
|
|
32
|
my $real = $self->path2real($path); |
43
|
14
|
100
|
|
|
|
904
|
&CORE::mkdir($real, defined $perm ? $perm : ()) or croak "$real: $!"; |
|
|
100
|
|
|
|
|
|
44
|
|
|
|
|
|
|
} |
45
|
|
|
|
|
|
|
|
46
|
72
|
50
|
|
72
|
0
|
196
|
sub make_tree ($self, $path, $perms = undef) { |
|
72
|
50
|
|
|
|
158
|
|
|
72
|
|
|
|
|
106
|
|
|
72
|
|
|
|
|
119
|
|
|
72
|
|
|
|
|
102
|
|
|
72
|
|
|
|
|
86
|
|
47
|
72
|
|
|
|
|
151
|
my $real = $self->path2real($path); |
48
|
72
|
|
|
|
|
277
|
my %opts = (error => \my $err); |
49
|
72
|
50
|
|
|
|
175
|
$opts{chmod} = $perms if defined $perms; |
50
|
72
|
|
|
|
|
6363
|
File::Path::make_path($real, \%opts); |
51
|
72
|
100
|
|
|
|
362
|
croak join('; ', map { $_->%* } @$err) if @$err; # TODO: test |
|
1
|
|
|
|
|
86
|
|
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
|
54
|
7
|
50
|
|
7
|
0
|
51
|
sub symlink ($self, $to_path, $link_path) { |
|
7
|
50
|
|
|
|
21
|
|
|
7
|
|
|
|
|
12
|
|
|
7
|
|
|
|
|
17
|
|
|
7
|
|
|
|
|
13
|
|
|
7
|
|
|
|
|
12
|
|
55
|
7
|
100
|
|
|
|
16
|
CORE::symlink($self->path2real($to_path), $self->path2real($link_path)) |
56
|
|
|
|
|
|
|
or croak "symlink $to_path $link_path: $!"; |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
|
59
|
3
|
50
|
|
3
|
0
|
30
|
sub link ($self, $to_path, $link_path) { |
|
3
|
50
|
|
|
|
13
|
|
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
9
|
|
60
|
3
|
50
|
|
|
|
8
|
CORE::link($self->path2real($to_path), $self->path2real($link_path)) |
61
|
|
|
|
|
|
|
or croak "hardlink $to_path $link_path: $!"; |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
|
64
|
4
|
50
|
|
4
|
0
|
16
|
sub is_symlink ($self, $path) { |
|
4
|
50
|
|
|
|
10
|
|
|
4
|
|
|
|
|
6
|
|
|
4
|
|
|
|
|
9
|
|
|
4
|
|
|
|
|
5
|
|
65
|
4
|
|
|
|
|
10
|
-l $self->path2real($path); |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
|
69
|
2
|
50
|
|
2
|
0
|
19
|
sub utimes ($self, $path, $atime = undef, $mtime = undef) { |
|
2
|
50
|
|
|
|
36
|
|
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
5
|
|
70
|
2
|
|
|
|
|
6
|
my $real = $self->path2real($path); |
71
|
2
|
100
|
100
|
|
|
150
|
utime($atime // undef, $mtime // undef, $real) or croak "utimes $path: $!"; |
|
|
|
100
|
|
|
|
|
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
|
74
|
55
|
50
|
|
55
|
0
|
1471
|
sub close ($self, $fh) { |
|
55
|
50
|
|
|
|
122
|
|
|
55
|
|
|
|
|
107
|
|
|
55
|
|
|
|
|
82
|
|
|
55
|
|
|
|
|
76
|
|
75
|
55
|
|
|
|
|
364
|
close $fh; |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
|
78
|
143
|
50
|
|
143
|
1
|
325
|
sub stat ($self, $path) { |
|
143
|
50
|
|
|
|
291
|
|
|
143
|
|
|
|
|
199
|
|
|
143
|
|
|
|
|
205
|
|
|
143
|
|
|
|
|
178
|
|
79
|
143
|
|
|
|
|
190
|
my %opts; |
80
|
143
|
100
|
|
|
|
278
|
my @stat = Time::HiRes::stat $self->path2real($path) or croak "stat $path: $!"; |
81
|
141
|
|
|
|
|
822
|
@opts{qw(dev ino mode nlink uid gid rdev size atime mtime ctime blksize blocks)} = @stat; |
82
|
141
|
|
|
|
|
2272
|
Evo::Fs::Stat->new(%opts, _data => \@stat); |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
1
|
50
|
|
1
|
1
|
10
|
sub rename ($self, $old, $new) { |
|
1
|
50
|
|
|
|
4
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
2
|
|
86
|
1
|
50
|
|
|
|
2
|
rename $self->path2real($old), $self->path2real($new) or croak "rename $!"; |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
my %seek_map = (start => SEEK_SET, cur => SEEK_CUR, end => SEEK_END,); |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
my %open_map = ( |
93
|
|
|
|
|
|
|
r => O_RDONLY, |
94
|
|
|
|
|
|
|
'r+' => O_RDWR, |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
w => O_WRONLY | O_CREAT | O_TRUNC, |
97
|
|
|
|
|
|
|
wx => O_WRONLY | O_CREAT | O_EXCL, |
98
|
|
|
|
|
|
|
'w+' => O_RDWR | O_CREAT | O_TRUNC, |
99
|
|
|
|
|
|
|
'wx+' => O_RDWR | O_CREAT | O_EXCL, |
100
|
|
|
|
|
|
|
a => O_WRONLY | O_CREAT | O_APPEND, |
101
|
|
|
|
|
|
|
ax => O_WRONLY | O_CREAT | O_APPEND | O_EXCL, |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
'a+' => O_RDWR | O_CREAT | O_APPEND, |
104
|
|
|
|
|
|
|
'ax+' => O_RDWR | O_CREAT | O_APPEND | O_EXCL, |
105
|
|
|
|
|
|
|
); |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
# self, fh, path, mode, perm? |
108
|
129
|
50
|
|
129
|
1
|
2970
|
sub sysopen ($, $, $, $, @) { |
|
129
|
|
|
|
|
193
|
|
109
|
129
|
100
|
|
|
|
466
|
croak "Bad mode $_[3]" unless exists $open_map{$_[3]}; |
110
|
128
|
100
|
|
|
|
309
|
&CORE::sysopen($_[1], $_[0]->path2real($_[2]), $open_map{$_[3]}, (defined($_[4]) ? $_[4] : ())) |
|
|
100
|
|
|
|
|
|
111
|
|
|
|
|
|
|
or croak "sysopen: $!"; |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
|
115
|
13
|
50
|
|
13
|
1
|
903
|
sub sysseek ($self, $fh, $pos, $whence = 'start') { |
|
13
|
50
|
|
|
|
43
|
|
|
13
|
100
|
|
|
|
24
|
|
|
13
|
|
|
|
|
19
|
|
|
13
|
|
|
|
|
20
|
|
|
13
|
|
|
|
|
35
|
|
|
13
|
|
|
|
|
19
|
|
116
|
13
|
100
|
|
|
|
188
|
croak "Bad whence $whence" unless exists $seek_map{$whence}; |
117
|
12
|
|
33
|
|
|
76
|
&CORE::sysseek($fh, $pos, $seek_map{$whence}) // croak "Can't sysseek $!"; |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
|
120
|
73
|
50
|
|
73
|
1
|
252
|
sub syswrite ($, $, $, @) { # other lengh, scalar offset |
|
73
|
|
|
|
|
107
|
|
121
|
73
|
|
|
|
|
109
|
shift; |
122
|
73
|
|
66
|
|
|
1768
|
&CORE::syswrite(@_) // croak "Can't write: $!"; |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
|
125
|
49
|
50
|
|
49
|
1
|
674
|
sub sysread ($, $, $, $, @) { # @other = string offset |
|
49
|
|
|
|
|
74
|
|
126
|
49
|
|
|
|
|
71
|
shift; |
127
|
49
|
|
66
|
|
|
409
|
&CORE::sysread(@_) // croak "Can't read: $!"; |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
|
130
|
31
|
50
|
|
31
|
0
|
545
|
sub unlink ($self, $path) { |
|
31
|
50
|
|
|
|
77
|
|
|
31
|
|
|
|
|
50
|
|
|
31
|
|
|
|
|
51
|
|
|
31
|
|
|
|
|
53
|
|
131
|
31
|
100
|
|
|
|
74
|
unlink $self->path2real($path) or croak "$path $!"; |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
|
134
|
7
|
50
|
|
7
|
0
|
29
|
sub remove_tree ($self, $path, $opts = {}) { |
|
7
|
50
|
|
|
|
23
|
|
|
7
|
100
|
|
|
|
12
|
|
|
7
|
|
|
|
|
13
|
|
|
7
|
|
|
|
|
24
|
|
|
7
|
|
|
|
|
13
|
|
135
|
7
|
|
|
|
|
18
|
my $real = $self->path2real($path); |
136
|
7
|
50
|
|
|
|
27
|
croak "remove_tree $real: Not a directory" unless $self->stat($path)->is_dir; |
137
|
6
|
|
|
|
|
1893
|
File::Path::remove_tree($real, {%$opts, error => \my $err}); |
138
|
6
|
50
|
|
|
|
52
|
croak join('; ', map { $_->%* } @$err) if @$err; # TODO: test |
|
0
|
|
|
|
|
0
|
|
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
|
141
|
43
|
50
|
|
43
|
0
|
114
|
sub ls ($self, $path) { |
|
43
|
50
|
|
|
|
88
|
|
|
43
|
|
|
|
|
64
|
|
|
43
|
|
|
|
|
59
|
|
|
43
|
|
|
|
|
56
|
|
142
|
43
|
|
|
|
|
86
|
my $real = $self->path2real($path); |
143
|
43
|
100
|
|
|
|
1001
|
opendir(my $dh, $real) || croak "Can't opendir $real: $!"; |
144
|
42
|
100
|
|
|
|
552
|
my @result = grep { $_ ne '.' && $_ ne '..' } readdir($dh); |
|
149
|
|
|
|
|
557
|
|
145
|
42
|
|
|
|
|
227
|
closedir $dh; |
146
|
42
|
|
|
|
|
218
|
@result; |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
my %flock_map = ( |
150
|
|
|
|
|
|
|
ex => LOCK_EX, |
151
|
|
|
|
|
|
|
ex_nb => LOCK_EX | LOCK_NB, |
152
|
|
|
|
|
|
|
sh => LOCK_SH, |
153
|
|
|
|
|
|
|
sh_nb => LOCK_SH | LOCK_NB, |
154
|
|
|
|
|
|
|
un => LOCK_UN |
155
|
|
|
|
|
|
|
); |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
|
158
|
112
|
50
|
|
112
|
0
|
279
|
sub flock ($self, $fh, $flag) { |
|
112
|
50
|
|
|
|
230
|
|
|
112
|
|
|
|
|
212
|
|
|
112
|
|
|
|
|
142
|
|
|
112
|
|
|
|
|
163
|
|
|
112
|
|
|
|
|
153
|
|
159
|
112
|
100
|
|
|
|
420
|
croak "Bad flag $flag" unless exists $flock_map{$flag}; |
160
|
111
|
|
|
|
|
446
|
my $res = flock($fh, $flock_map{$flag}); |
161
|
111
|
100
|
100
|
|
|
373
|
croak "$!" unless $res || $! == EAGAIN || $! == EWOULDBLOCK; |
|
|
|
66
|
|
|
|
|
162
|
110
|
|
|
|
|
182
|
$res; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
62
|
50
|
|
62
|
0
|
239
|
sub open ($self, $path, $mode, @rest) { |
|
62
|
|
|
|
|
98
|
|
|
62
|
|
|
|
|
96
|
|
|
62
|
|
|
|
|
135
|
|
|
62
|
|
|
|
|
167
|
|
|
62
|
|
|
|
|
100
|
|
166
|
62
|
50
|
66
|
|
|
1176
|
$self->make_tree((fileparse($path))[1]) unless ($mode eq 'r' && $mode eq 'r+'); |
167
|
62
|
|
|
|
|
215
|
$self->sysopen(my $fh, $path, $mode, @rest); |
168
|
60
|
|
|
|
|
279
|
$fh; |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
|
172
|
2
|
50
|
|
2
|
1
|
12
|
sub append ($self, $path, $) { |
|
2
|
50
|
|
|
|
5
|
|
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
3
|
|
173
|
2
|
|
|
|
|
9
|
my $fh = $self->open($path, 'a'); |
174
|
2
|
|
|
|
|
11
|
$self->flock($fh, 'ex'); |
175
|
2
|
|
|
|
|
10
|
$self->syswrite($fh, $_[2]); |
176
|
2
|
|
|
|
|
9
|
$self->flock($fh, 'un'); |
177
|
2
|
|
|
|
|
18
|
CORE::close $fh; |
178
|
2
|
|
|
|
|
8
|
return; |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
# don't copy 3rd arg |
182
|
39
|
50
|
|
39
|
1
|
211
|
sub write ($self, $path, $) { |
|
39
|
50
|
|
|
|
91
|
|
|
39
|
|
|
|
|
60
|
|
|
39
|
|
|
|
|
63
|
|
|
39
|
|
|
|
|
58
|
|
183
|
39
|
|
|
|
|
92
|
my $fh = $self->open($path, 'w'); |
184
|
39
|
|
|
|
|
120
|
$self->flock($fh, 'ex'); |
185
|
39
|
|
|
|
|
105
|
$self->syswrite($fh, $_[2]); |
186
|
39
|
|
|
|
|
119
|
$self->flock($fh, 'un'); |
187
|
39
|
|
|
|
|
223
|
CORE::close $fh; |
188
|
39
|
|
|
|
|
115
|
return; |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
|
191
|
18
|
50
|
|
18
|
1
|
44
|
sub read_ref ($self, $path) { |
|
18
|
50
|
|
|
|
46
|
|
|
18
|
|
|
|
|
26
|
|
|
18
|
|
|
|
|
27
|
|
|
18
|
|
|
|
|
30
|
|
192
|
18
|
|
|
|
|
41
|
my $fh = $self->open($path, 'r'); |
193
|
18
|
|
|
|
|
53
|
$self->flock($fh, 'sh'); |
194
|
18
|
|
|
|
|
54
|
$self->sysread($fh, \my $buf, $self->stat($path)->size); |
195
|
18
|
|
|
|
|
87
|
$self->flock($fh, 'un'); |
196
|
18
|
|
|
|
|
102
|
CORE::close $fh; |
197
|
18
|
|
|
|
|
102
|
\$buf; |
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
|
200
|
17
|
50
|
|
17
|
1
|
364
|
sub read ($self, $path) { |
|
17
|
50
|
|
|
|
49
|
|
|
17
|
|
|
|
|
30
|
|
|
17
|
|
|
|
|
29
|
|
|
17
|
|
|
|
|
23
|
|
201
|
17
|
|
|
|
|
40
|
$self->read_ref($path)->$*; |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
|
204
|
10
|
50
|
|
10
|
1
|
170
|
sub write_many ($self, %map) { |
|
10
|
50
|
|
|
|
35
|
|
|
10
|
|
|
|
|
19
|
|
|
10
|
|
|
|
|
52
|
|
|
10
|
|
|
|
|
18
|
|
205
|
10
|
|
|
|
|
48
|
$self->write($_, $map{$_}) for keys %map; |
206
|
10
|
|
|
|
|
40
|
$self; |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
|
209
|
3
|
50
|
|
3
|
1
|
36
|
sub find_files ($self, $start, $fhs_fn, $pick = undef) { |
|
3
|
50
|
|
|
|
8
|
|
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
4
|
|
|
3
|
|
|
|
|
5
|
|
210
|
3
|
|
|
|
|
5
|
my %seen; |
211
|
15
|
50
|
|
15
|
|
91
|
my $fn = sub ($path) { |
|
15
|
50
|
|
|
|
31
|
|
|
15
|
|
|
|
|
24
|
|
|
15
|
|
|
|
|
17
|
|
212
|
15
|
|
|
|
|
32
|
my $stat = $self->stat($path); |
213
|
15
|
100
|
|
|
|
50
|
return unless $stat->is_file; |
214
|
6
|
|
|
|
|
19
|
$fhs_fn->($path); |
215
|
3
|
|
|
|
|
11
|
}; |
216
|
3
|
|
|
|
|
10
|
$self->traverse($start, $fn, $pick); |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
# make faster? |
220
|
12
|
50
|
|
12
|
1
|
88
|
sub traverse ($self, $start, $fn, $pick_d = undef) { |
|
12
|
50
|
|
|
|
31
|
|
|
12
|
|
|
|
|
21
|
|
|
12
|
|
|
|
|
16
|
|
|
12
|
|
|
|
|
26
|
|
|
12
|
|
|
|
|
19
|
|
|
12
|
|
|
|
|
18
|
|
221
|
|
|
|
|
|
|
|
222
|
12
|
100
|
|
|
|
96
|
$start = [$start] unless ref $start eq 'ARRAY'; |
223
|
12
|
|
|
|
|
23
|
my %seen_dirs; # don't go into the same dir twice |
224
|
|
|
|
|
|
|
my %seen_children; # don't fire the same file twice |
225
|
|
|
|
|
|
|
|
226
|
14
|
|
|
|
|
80
|
my @stack = map { Evo::Path->new(base => $_); } map { |
227
|
12
|
|
|
|
|
36
|
my $path = $_; |
|
15
|
|
|
|
|
27
|
|
228
|
15
|
|
|
|
|
33
|
my $stat = $self->stat($path); |
229
|
15
|
100
|
|
|
|
161
|
$seen_dirs{($stat->dev, '-', $stat->ino)}++ ? () : ($path); |
230
|
|
|
|
|
|
|
} reverse $start->@*; |
231
|
|
|
|
|
|
|
|
232
|
12
|
|
|
|
|
42
|
while (@stack) { |
233
|
41
|
|
|
|
|
73
|
my $cur_dir = pop @stack; |
234
|
|
|
|
|
|
|
|
235
|
41
|
|
|
|
|
59
|
my (@dirs, @children); |
236
|
41
|
|
|
|
|
105
|
foreach my $cur_child (sort $self->ls($cur_dir)) { |
237
|
|
|
|
|
|
|
|
238
|
63
|
|
|
|
|
188
|
my $path = $cur_dir->append($cur_child); |
239
|
63
|
100
|
|
|
|
166
|
next unless $self->exists($path); # broken link |
240
|
62
|
|
|
|
|
158
|
my $stat = $self->stat($path); |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
my $bool |
244
|
|
|
|
|
|
|
= $stat->is_dir |
245
|
|
|
|
|
|
|
&& $stat->can_exec |
246
|
|
|
|
|
|
|
&& $stat->can_read |
247
|
62
|
|
66
|
|
|
203
|
&& !$seen_dirs{$stat->dev, '-', $stat->ino}++ |
248
|
|
|
|
|
|
|
&& (!$pick_d || $pick_d->($path)); |
249
|
|
|
|
|
|
|
|
250
|
62
|
100
|
|
|
|
480
|
unshift @dirs, $path if $bool; |
251
|
62
|
100
|
|
|
|
435
|
push @children, $path if !$seen_children{$stat->dev, '-', $stat->ino}++; |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
} |
254
|
41
|
|
|
|
|
140
|
$fn->($_) for @children; |
255
|
41
|
|
|
|
|
2099
|
push @stack, @dirs; |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
|
259
|
8
|
50
|
|
8
|
|
23
|
my sub _copy_file ($self, $from, $to) { |
|
8
|
50
|
|
|
|
18
|
|
|
8
|
|
|
|
|
13
|
|
|
8
|
|
|
|
|
11
|
|
|
8
|
|
|
|
|
11
|
|
|
8
|
|
|
|
|
11
|
|
260
|
8
|
50
|
|
|
|
18
|
File::Copy::cp $self->path2real($from), $self->path2real($to) or die "Copy failed: $!"; |
261
|
|
|
|
|
|
|
} |
262
|
|
|
|
|
|
|
|
263
|
4
|
50
|
|
4
|
1
|
24
|
sub copy_dir ($self, $from, $to) { |
|
4
|
50
|
|
|
|
11
|
|
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
5
|
|
264
|
4
|
|
|
|
|
29
|
$to = Evo::Path->new(base => $to); |
265
|
4
|
|
|
|
|
12
|
$self->make_tree($to); |
266
|
4
|
|
|
|
|
11
|
my @stack = ($from); |
267
|
4
|
|
|
|
|
12
|
while (@stack) { |
268
|
4
|
|
|
|
|
9
|
my $cur_dir = shift @stack; |
269
|
12
|
|
|
|
|
18
|
$self->traverse( |
270
|
|
|
|
|
|
|
$cur_dir, |
271
|
12
|
50
|
|
12
|
|
273
|
sub($path) { |
|
12
|
50
|
|
|
|
24
|
|
|
12
|
|
|
|
|
19
|
|
272
|
12
|
|
|
|
|
22
|
my $stat = $self->stat($path); |
273
|
12
|
|
|
|
|
53
|
my $dest = $to->append(join '/', $path->children->@*); |
274
|
12
|
100
|
|
|
|
37
|
if ($stat->is_dir) { |
|
|
50
|
|
|
|
|
|
275
|
5
|
100
|
|
|
|
13
|
$self->mkdir($dest) unless $self->exists($dest); |
276
|
|
|
|
|
|
|
} |
277
|
|
|
|
|
|
|
elsif ($stat->is_file) { |
278
|
7
|
|
|
|
|
19
|
_copy_file($self, $path, $dest); |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
#else { croak "Can't copy $path, not a dir neither a file"; } |
282
|
|
|
|
|
|
|
} |
283
|
4
|
|
|
|
|
28
|
); |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
} |
286
|
|
|
|
|
|
|
|
287
|
1
|
50
|
|
1
|
1
|
5
|
sub copy_file ($self, $from, $to) { |
|
1
|
50
|
|
|
|
4
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
1
|
|
288
|
1
|
|
|
|
|
16
|
$self->make_tree((fileparse($to))[1]); |
289
|
1
|
|
|
|
|
4
|
_copy_file($self, $from, $to); |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
# ========= MODULE ========= |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
my $FSROOT = __PACKAGE__->new(root => '/'); |
295
|
8
|
|
|
8
|
1
|
22309
|
sub FSROOT : Export {$FSROOT} |
|
8
|
|
|
1
|
|
17
|
|
|
8
|
|
|
|
|
37
|
|
|
1
|
|
|
|
|
12
|
|
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
1; |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
__END__ |