line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# mt-aws-glacier - Amazon Glacier sync client |
2
|
|
|
|
|
|
|
# Copyright (C) 2012-2014 Victor Efimov |
3
|
|
|
|
|
|
|
# http://mt-aws.com (also http://vs-dev.com) vs@vs-dev.com |
4
|
|
|
|
|
|
|
# License: GPLv3 |
5
|
|
|
|
|
|
|
# |
6
|
|
|
|
|
|
|
# This file is part of "mt-aws-glacier" |
7
|
|
|
|
|
|
|
# |
8
|
|
|
|
|
|
|
# mt-aws-glacier is free software: you can redistribute it and/or modify |
9
|
|
|
|
|
|
|
# it under the terms of the GNU General Public License as published by |
10
|
|
|
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or |
11
|
|
|
|
|
|
|
# (at your option) any later version. |
12
|
|
|
|
|
|
|
# |
13
|
|
|
|
|
|
|
# mt-aws-glacier is distributed in the hope that it will be useful, |
14
|
|
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
15
|
|
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16
|
|
|
|
|
|
|
# GNU General Public License for more details. |
17
|
|
|
|
|
|
|
# |
18
|
|
|
|
|
|
|
# You should have received a copy of the GNU General Public License |
19
|
|
|
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
package App::MtAws::ChildWorker; |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
our $VERSION = '1.114_2'; |
24
|
|
|
|
|
|
|
|
25
|
18
|
|
|
18
|
|
8023
|
use App::MtAws::LineProtocol; |
|
18
|
|
|
|
|
35
|
|
|
18
|
|
|
|
|
1183
|
|
26
|
18
|
|
|
18
|
|
8030
|
use App::MtAws::GlacierRequest; |
|
18
|
|
|
|
|
47
|
|
|
18
|
|
|
|
|
708
|
|
27
|
18
|
|
|
18
|
|
120
|
use App::MtAws::Utils; |
|
18
|
|
|
|
|
32
|
|
|
18
|
|
|
|
|
2617
|
|
28
|
18
|
|
|
18
|
|
120
|
use App::MtAws::Exceptions; |
|
18
|
|
|
|
|
19
|
|
|
18
|
|
|
|
|
1187
|
|
29
|
18
|
|
|
18
|
|
94
|
use strict; |
|
18
|
|
|
|
|
28
|
|
|
18
|
|
|
|
|
420
|
|
30
|
18
|
|
|
18
|
|
77
|
use warnings; |
|
18
|
|
|
|
|
27
|
|
|
18
|
|
|
|
|
432
|
|
31
|
18
|
|
|
18
|
|
78
|
use utf8; |
|
18
|
|
|
|
|
27
|
|
|
18
|
|
|
|
|
101
|
|
32
|
18
|
|
|
18
|
|
370
|
use Carp; |
|
18
|
|
|
|
|
21
|
|
|
18
|
|
|
|
|
1662
|
|
33
|
18
|
|
|
18
|
|
2436
|
use IO::Select; |
|
18
|
|
|
|
|
6123
|
|
|
18
|
|
|
|
|
583
|
|
34
|
18
|
|
|
18
|
|
65
|
use POSIX; |
|
18
|
|
|
|
|
19
|
|
|
18
|
|
|
|
|
128
|
|
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
sub new |
37
|
|
|
|
|
|
|
{ |
38
|
0
|
|
|
0
|
0
|
0
|
my ($class, %args) = @_; |
39
|
0
|
|
|
|
|
0
|
my $self = \%args; |
40
|
0
|
0
|
|
|
|
0
|
$self->{fromchild}||die; |
41
|
0
|
0
|
|
|
|
0
|
$self->{tochild}||die; |
42
|
0
|
0
|
|
|
|
0
|
$self->{options}||die; |
43
|
0
|
|
|
|
|
0
|
bless $self, $class; |
44
|
0
|
|
|
|
|
0
|
return $self; |
45
|
|
|
|
|
|
|
} |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
sub process |
48
|
|
|
|
|
|
|
{ |
49
|
0
|
|
|
0
|
0
|
0
|
my ($self) = @_; |
50
|
|
|
|
|
|
|
|
51
|
0
|
|
|
|
|
0
|
my $tochild = $self->{tochild}; |
52
|
0
|
|
|
|
|
0
|
my $fromchild = $self->{fromchild}; |
53
|
0
|
|
|
|
|
0
|
while (1) { |
54
|
0
|
|
|
|
|
0
|
my ($remote_pid, $action, $taskid, $data, $attachmentref) = get_data($tochild); |
55
|
0
|
0
|
|
|
|
0
|
$remote_pid or comm_error(); # we exit() if eof or socket error. we don't distinct |
56
|
0
|
|
|
|
|
0
|
my ($result, $result_attachmentref, $console_out) = $self->process_task($action, $data, $attachmentref); |
57
|
0
|
|
|
|
|
0
|
$result->{console_out}=$console_out; |
58
|
0
|
0
|
|
|
|
0
|
send_data($fromchild, 'response', $taskid, $result, $result_attachmentref) or comm_error(); |
59
|
|
|
|
|
|
|
}; |
60
|
|
|
|
|
|
|
# unreachable |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
sub process_task |
64
|
|
|
|
|
|
|
{ |
65
|
1
|
|
|
1
|
0
|
827
|
my ($self, $action, $data, $attachmentref) = @_; |
66
|
1
|
|
|
|
|
2
|
my ($result, $result_attachmentref) = (undef, undef); |
67
|
|
|
|
|
|
|
|
68
|
1
|
|
|
|
|
1
|
my $console_out = undef; |
69
|
1
|
50
|
|
|
|
11
|
if ($action eq 'create_upload') { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
70
|
|
|
|
|
|
|
# TODO: partsize confusing, need use another name for option partsize. partsize Amazon Upload partsize vs Download 'Range' partsize |
71
|
0
|
|
|
|
|
0
|
my $req = App::MtAws::GlacierRequest->new($self->{options}); |
72
|
0
|
|
|
|
|
0
|
my $uploadid = $req->create_multipart_upload($data->{partsize}, $data->{relfilename}, $data->{mtime}); |
73
|
0
|
0
|
|
|
|
0
|
confess unless $uploadid; |
74
|
0
|
|
|
|
|
0
|
$result = { upload_id => $uploadid }; |
75
|
0
|
|
|
|
|
0
|
$console_out = "Created an upload_id $uploadid"; |
76
|
|
|
|
|
|
|
} elsif ($action eq "upload_part") { |
77
|
0
|
|
|
|
|
0
|
my $req = App::MtAws::GlacierRequest->new($self->{options}); |
78
|
0
|
|
|
|
|
0
|
my $r = $req->upload_part($data->{upload_id}, $attachmentref, $data->{start}, $data->{part_final_hash}); |
79
|
0
|
0
|
|
|
|
0
|
confess "upload_part failed" unless $r; |
80
|
0
|
|
|
|
|
0
|
$result = { uploaded => $data->{start} } ; |
81
|
0
|
|
|
|
|
0
|
$console_out = "Uploaded part for $data->{relfilename} at offset [$data->{start}]"; |
82
|
|
|
|
|
|
|
} elsif ($action eq 'finish_upload') { |
83
|
|
|
|
|
|
|
# TODO: move vault to task, not to options! |
84
|
0
|
|
|
|
|
0
|
my $req = App::MtAws::GlacierRequest->new($self->{options}); |
85
|
0
|
|
|
|
|
0
|
my $archive_id = $req->finish_multipart_upload($data->{upload_id}, $data->{filesize}, $data->{final_hash}); |
86
|
0
|
0
|
|
|
|
0
|
confess "finish_upload failed" unless $archive_id; |
87
|
|
|
|
|
|
|
$result = { |
88
|
|
|
|
|
|
|
final_hash => $data->{final_hash}, |
89
|
|
|
|
|
|
|
archive_id => $archive_id, |
90
|
|
|
|
|
|
|
journal_entry => { |
91
|
|
|
|
|
|
|
type=> 'CREATED', |
92
|
|
|
|
|
|
|
'time' => $req->{last_request_time}, |
93
|
|
|
|
|
|
|
archive_id => $archive_id, |
94
|
|
|
|
|
|
|
size => $data->{filesize}, |
95
|
|
|
|
|
|
|
mtime => $data->{mtime}, |
96
|
|
|
|
|
|
|
treehash => $data->{final_hash}, |
97
|
|
|
|
|
|
|
relfilename => $data->{relfilename} |
98
|
|
|
|
|
|
|
}, |
99
|
0
|
|
|
|
|
0
|
}; |
100
|
0
|
|
|
|
|
0
|
$console_out = "Finished $data->{relfilename} hash [$data->{final_hash}] archive_id [$archive_id]"; |
101
|
|
|
|
|
|
|
} elsif ($action eq 'delete_archive') { |
102
|
0
|
|
|
|
|
0
|
my $req = App::MtAws::GlacierRequest->new($self->{options}); |
103
|
0
|
|
|
|
|
0
|
my $r = $req->delete_archive($data->{archive_id}); |
104
|
0
|
0
|
|
|
|
0
|
confess "delete_archive failed" unless $r; |
105
|
|
|
|
|
|
|
$result = { |
106
|
|
|
|
|
|
|
journal_entry => { |
107
|
|
|
|
|
|
|
type=> 'DELETED', |
108
|
|
|
|
|
|
|
'time' => $req->{last_request_time}, |
109
|
|
|
|
|
|
|
archive_id => $data->{archive_id}, |
110
|
|
|
|
|
|
|
relfilename => $data->{relfilename} |
111
|
|
|
|
|
|
|
} |
112
|
0
|
|
|
|
|
0
|
}; |
113
|
0
|
|
|
|
|
0
|
$console_out = "Deleted $data->{relfilename} archive_id [$data->{archive_id}]"; |
114
|
|
|
|
|
|
|
} elsif ($action eq 'retrieval_download_job') { |
115
|
1
|
|
|
|
|
9
|
my $req = App::MtAws::GlacierRequest->new($self->{options}); |
116
|
|
|
|
|
|
|
|
117
|
1
|
|
|
|
|
9
|
my $i_tmp = App::MtAws::IntermediateFile->new(target_file => $data->{filename}, mtime => $data->{mtime}); |
118
|
1
|
|
|
|
|
4
|
my $tempfile = $i_tmp->tempfilename; |
119
|
|
|
|
|
|
|
|
120
|
1
|
|
|
|
|
7
|
my $r = $req->retrieval_download_job($data->{jobid}, $data->{relfilename}, $tempfile, $data->{size}, $data->{treehash}); |
121
|
|
|
|
|
|
|
|
122
|
1
|
50
|
|
|
|
3
|
confess "retrieval_download_job failed" unless $r; |
123
|
|
|
|
|
|
|
|
124
|
1
|
|
|
|
|
3
|
$i_tmp->make_permanent; |
125
|
|
|
|
|
|
|
|
126
|
1
|
|
|
|
|
3
|
$result = { response => $r }; |
127
|
1
|
|
|
|
|
6
|
$console_out = "Downloaded archive $data->{filename}"; |
128
|
|
|
|
|
|
|
} elsif ($action eq 'segment_download_job') { |
129
|
0
|
|
|
|
|
0
|
my $req = App::MtAws::GlacierRequest->new($self->{options}); |
130
|
0
|
|
|
|
|
0
|
my $r = $req->segment_download_job($data->{jobid}, $data->{tempfile}, $data->{filename}, $data->{position}, $data->{download_size}); |
131
|
0
|
0
|
|
|
|
0
|
confess "segment_download_job failed" unless $r; |
132
|
0
|
|
|
|
|
0
|
$result = { response => $r }; |
133
|
0
|
|
|
|
|
0
|
$console_out = "Downloaded part of archive $data->{filename} at offset $data->{position}, size $data->{download_size}"; |
134
|
|
|
|
|
|
|
} elsif ($action eq 'inventory_download_job') { |
135
|
0
|
|
|
|
|
0
|
my $req = App::MtAws::GlacierRequest->new($self->{options}); |
136
|
0
|
|
|
|
|
0
|
my ($r, $inventory_type) = $req->retrieval_download_to_memory($data->{job_id}); |
137
|
0
|
0
|
|
|
|
0
|
confess "inventory_download_job failed" unless $r; |
138
|
0
|
|
|
|
|
0
|
$result = { response => !! $r, inventory_type => $inventory_type }; |
139
|
0
|
|
|
|
|
0
|
$result_attachmentref = \$r; |
140
|
0
|
0
|
|
|
|
0
|
$console_out = "Downloaded inventory in ".($inventory_type eq INVENTORY_TYPE_JSON ? "JSON" : "CSV")." format"; |
141
|
|
|
|
|
|
|
} elsif ($action eq 'retrieve_archive') { |
142
|
0
|
|
|
|
|
0
|
my $req = App::MtAws::GlacierRequest->new($self->{options}); |
143
|
0
|
|
|
|
|
0
|
my $r = $req->retrieve_archive( $data->{archive_id}); |
144
|
0
|
0
|
|
|
|
0
|
return "retrieve_archive failed" unless $r; |
145
|
|
|
|
|
|
|
$result = { |
146
|
|
|
|
|
|
|
journal_entry => { |
147
|
|
|
|
|
|
|
type=> 'RETRIEVE_JOB', |
148
|
|
|
|
|
|
|
'time' => $req->{last_request_time}, |
149
|
|
|
|
|
|
|
archive_id => $data->{archive_id}, |
150
|
0
|
|
|
|
|
0
|
job_id => $r, |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
}; |
153
|
0
|
|
|
|
|
0
|
$console_out = "Retrieved Archive $data->{archive_id}"; |
154
|
|
|
|
|
|
|
} elsif ($action eq 'retrieval_fetch_job') { |
155
|
0
|
|
|
|
|
0
|
my $req = App::MtAws::GlacierRequest->new($self->{options}); |
156
|
0
|
|
|
|
|
0
|
my $r = $req->retrieval_fetch_job($data->{marker}); |
157
|
0
|
0
|
|
|
|
0
|
confess unless $r; |
158
|
0
|
|
|
|
|
0
|
$result = { response => $r }; |
159
|
0
|
|
|
|
|
0
|
$console_out = "Retrieved Job List"; |
160
|
|
|
|
|
|
|
} elsif ($action eq 'inventory_fetch_job') { |
161
|
0
|
|
|
|
|
0
|
my $req = App::MtAws::GlacierRequest->new($self->{options}); |
162
|
0
|
|
|
|
|
0
|
my $r = $req->retrieval_fetch_job($data->{marker}); |
163
|
0
|
0
|
|
|
|
0
|
confess unless $r; |
164
|
0
|
|
|
|
|
0
|
$result = { response => $r }; |
165
|
0
|
|
|
|
|
0
|
$console_out = "Fetched job list for inventory retrieval"; |
166
|
|
|
|
|
|
|
} elsif ($action eq 'retrieve_inventory_job') { |
167
|
0
|
|
|
|
|
0
|
my $req = App::MtAws::GlacierRequest->new($self->{options}); |
168
|
0
|
|
|
|
|
0
|
my $r = $req->retrieve_inventory($data->{format}); |
169
|
0
|
0
|
|
|
|
0
|
confess unless $r; |
170
|
0
|
|
|
|
|
0
|
$result = { job_id => $r }; |
171
|
0
|
|
|
|
|
0
|
$console_out = "Retrieved Inventory, job id $r"; |
172
|
|
|
|
|
|
|
} elsif ($action eq 'create_vault_job') { |
173
|
0
|
|
|
|
|
0
|
my $req = App::MtAws::GlacierRequest->new($self->{options}); |
174
|
0
|
|
|
|
|
0
|
my $r = $req->create_vault($data->{name}); |
175
|
0
|
0
|
|
|
|
0
|
confess unless $r; |
176
|
0
|
|
|
|
|
0
|
$result = { }; |
177
|
0
|
|
|
|
|
0
|
$console_out = "Created vault $data->{name}"; |
178
|
|
|
|
|
|
|
} elsif ($action eq 'delete_vault_job') { |
179
|
0
|
|
|
|
|
0
|
my $req = App::MtAws::GlacierRequest->new($self->{options}); |
180
|
0
|
|
|
|
|
0
|
my $r = $req->delete_vault($data->{name}); |
181
|
0
|
0
|
|
|
|
0
|
confess unless $r; |
182
|
0
|
|
|
|
|
0
|
$result = { }; |
183
|
0
|
|
|
|
|
0
|
$console_out = "Deleted vault $data->{name}"; |
184
|
|
|
|
|
|
|
} elsif ($action eq 'verify_file') { |
185
|
0
|
|
|
|
|
0
|
my $th = App::MtAws::TreeHash->new(); |
186
|
0
|
|
|
|
|
0
|
my $binaryfilename = binaryfilename $data->{filename}; |
187
|
|
|
|
|
|
|
die exception file_is_zero => "File size is zero (and it was not when we read directory listing). Filename: %string filename%", |
188
|
|
|
|
|
|
|
filename => $data->{filename} |
189
|
0
|
0
|
|
|
|
0
|
unless -s $binaryfilename; |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
open_file(my $F, $data->{filename}, mode => '<', binary => 1) or |
192
|
|
|
|
|
|
|
die exception upload_file_open_error => "Unable to open task file %string filename% for reading, errno=%errno%", |
193
|
0
|
0
|
|
|
|
0
|
filename => $data->{filename}, 'ERRNO'; # TODO: test |
194
|
|
|
|
|
|
|
|
195
|
0
|
|
|
|
|
0
|
$th->eat_file($F); |
196
|
0
|
0
|
|
|
|
0
|
close $F or confess; |
197
|
0
|
|
|
|
|
0
|
$th->calc_tree(); |
198
|
0
|
|
|
|
|
0
|
my $treehash = $th->get_final_hash(); |
199
|
|
|
|
|
|
|
|
200
|
0
|
0
|
|
|
|
0
|
if ($treehash eq $data->{treehash}) { |
201
|
0
|
|
|
|
|
0
|
$result = { match => 1 }; |
202
|
0
|
|
|
|
|
0
|
$console_out = "Checked treehash for $data->{filename} - MATCH"; |
203
|
|
|
|
|
|
|
} else { |
204
|
0
|
|
|
|
|
0
|
$result = { match => 0 }; |
205
|
0
|
|
|
|
|
0
|
$console_out = "Checked treehash for $data->{filename} - DOES NOT MATCH"; |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
} else { |
208
|
0
|
|
|
|
|
0
|
die $action; |
209
|
|
|
|
|
|
|
} |
210
|
1
|
|
|
|
|
3
|
return ($result, $result_attachmentref, $console_out); |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
sub comm_error |
214
|
|
|
|
|
|
|
{ |
215
|
|
|
|
|
|
|
# error message useless here |
216
|
0
|
|
|
0
|
0
|
|
exit(1); |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
1; |