1#************************************************************** 2# 3# Licensed to the Apache Software Foundation (ASF) under one 4# or more contributor license agreements. See the NOTICE file 5# distributed with this work for additional information 6# regarding copyright ownership. The ASF licenses this file 7# to you under the Apache License, Version 2.0 (the 8# "License"); you may not use this file except in compliance 9# with the License. You may obtain a copy of the License at 10# 11# http://www.apache.org/licenses/LICENSE-2.0 12# 13# Unless required by applicable law or agreed to in writing, 14# software distributed under the License is distributed on an 15# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16# KIND, either express or implied. See the License for the 17# specific language governing permissions and limitations 18# under the License. 19# 20#************************************************************** 21 22package installer::patch::FileOperations; 23 24use File::Basename; 25use File::Copy; 26use IO::Compress::Bzip2; 27use IO::Uncompress::Bunzip2; 28 29my $CompressionMethod = "bzip2"; 30 31 32=head1 NAME 33 34 package installer::patch::FileOperations - Class for collecting, checking and executing file operations. 35 36=cut 37 38 39sub new ($) 40{ 41 my ($class) = (@_); 42 43 my $self = { 44 'operations' => [] 45 }; 46 bless($self, $class); 47 48 return $self; 49} 50 51 52 53 54sub AddCopyOperation ($$$) 55{ 56 my ($self, $source_name, $target_name) = @_; 57 58 push 59 @{$self->{'operations'}}, 60 [ 61 'copy', 62 $source_name, 63 $target_name 64 ]; 65} 66 67 68 69 70sub AddMakeDirectoryOperation ($$) 71{ 72 my ($self, $path) = @_; 73 74 push 75 @{$self->{'operations'}}, 76 [ 77 'mkdir', 78 $path 79 ]; 80} 81 82 83 84 85sub AddCompressOperation ($$) 86{ 87 my ($self, $filename) = @_; 88 89 push 90 @{$self->{'operations'}}, 91 [ 92 'compress', 93 $filename 94 ]; 95} 96 97 98 99 100sub AddUncompressOperation ($$$) 101{ 102 my ($self, $source_name, $target_name) = @_; 103 104 push 105 @{$self->{'operations'}}, 106 [ 107 'uncompress', 108 $source_name, 109 $target_name 110 ]; 111} 112 113 114 115 116sub Check ($) 117{ 118 my ($self) = @_; 119 120 # Keep track of which directories or files would be created to check if 121 # operations that depend on these files will succeed. 122 my %files = (); 123 my %directories = (); 124 125 my @error_messages = (); 126 foreach my $operation (@{$self->{'operations'}}) 127 { 128 my $command = $operation->[0]; 129 130 if ($command eq "copy") 131 { 132 my ($source_name, $destination_name) = ($operation->[1], $operation->[2]); 133 if ( ! -f $source_name) 134 { 135 push @error_messages, sprintf("%s is not a regular file and can not be copied", $source_name); 136 } 137 my $destination_path = dirname($destination_name); 138 if ( ! -d $destination_path && ! defined $directories{$destination_path}) 139 { 140 push @error_messages, sprintf("destination path %s does not exist", $destination_path); 141 } 142 if ( -f $destination_name) 143 { 144 # The destination file already exists. We have to overwrite it. 145 if ( ! -w $destination_name) 146 { 147 push @error_messges, sprintf("destination file %s exists but can not be overwritten", $destination_name); 148 } 149 } 150 $files{$destination_name} = 1; 151 } 152 elsif ($command eq "mkdir") 153 { 154 my $path = $operation->[1]; 155 if ( -d $path) 156 { 157 # Directory already exists. That is OK, the mkdir command will be silently ignored. 158 } 159 else 160 { 161 $directories{$path} = 1; 162 } 163 } 164 elsif ($command eq "compress") 165 { 166 my $filename = $operation->[1]; 167 if ( ! -f $filename && ! defined $files{$filename}) 168 { 169 # File does not exist and will not be created by an earlier operation. 170 push @error_messages, sprintf("file %s does not exist and can not be compressed", $filename); 171 } 172 } 173 elsif ($command eq "uncompress") 174 { 175 my ($source_filename, $destination_filename) = ($operation->[1], $operation->[2]); 176 if ($CompressionMethod eq "bzip2") 177 { 178 $source_filename .= ".bz2"; 179 } 180 if ( ! -f $source_filename && ! defined $files{$source_filename}) 181 { 182 # File does not exist and will not be created by an earlier operation. 183 push @error_messages, sprintf("file %s does not exist and can not be decompressed", $source_filename); 184 } 185 if ( -f $destination_filename && ! -w $destination_filename) 186 { 187 # Destination file already exists but can not be replaced. 188 push @error_messages, sprintf("compress destination file %s exists but can not be replaced", $destination_filename); 189 } 190 } 191 else 192 { 193 push @error_messages, sprintf("unknown operation %s", $command); 194 } 195 } 196 197 return @error_messages; 198} 199 200 201 202 203sub CheckAndExecute ($) 204{ 205 my ($self) = @_; 206 207 my @error_messages = $self->Check(); 208 if (scalar @error_messages > 0) 209 { 210 $installer::logger::Lang->printf("can not execute all operations:\n"); 211 for my $message (@error_messages) 212 { 213 $installer::logger::Lang->printf("ERROR: %s\n", $message); 214 } 215 return 0; 216 } 217 else 218 { 219 return $self->Execute(); 220 } 221} 222 223 224 225 226sub Execute ($) 227{ 228 my ($self) = @_; 229 230 foreach my $operation (@{$self->{'operations'}}) 231 { 232 my $command = $operation->[0]; 233 234 if ($command eq "copy") 235 { 236 my ($source_name, $destination_name) = ($operation->[1], $operation->[2]); 237 $installer::logger::Lang->printf("copy from %s\n to %s\n", $source_name, $destination_name); 238 if ( ! $DryRun) 239 { 240 my $result = copy($source_name, $destination_name); 241 if ( ! $result) 242 { 243 $installer::logger::Lang->printf("ERROR: copying from %s to %s failed", 244 $source_name, $destination_name); 245 } 246 } 247 } 248 elsif ($command eq "mkdir") 249 { 250 my $path = $operation->[1]; 251 if ( -d $path) 252 { 253 # Path exists already. Do nothing. 254 } 255 else 256 { 257 $installer::logger::Lang->printf("creating directory %s\n", $path); 258 if ( ! $DryRun) 259 { 260 if (File::Path::make_path($path, {'mode' => 0775}) == 0) 261 { 262 $installer::logger::Lang->printf("could not create directory %s\n", $path); 263 } 264 } 265 } 266 } 267 elsif ($command eq "compress") 268 { 269 my $filename = $operation->[1]; 270 $installer::logger::Lang->printf("compressing %s\n", $filename); 271 if ( ! $DryRun) 272 { 273 my $result = 0; 274 if ($CompressionMethod eq "bzip2") 275 { 276 $result = IO::Compress::Bzip2::bzip2($filename => $filename.".bz2"); 277 } 278 if ($result == 0) 279 { 280 $installer::logger::Lang->printf("ERROR: could not compress %s\n", $filename); 281 } 282 else 283 { 284 unlink($filename); 285 } 286 } 287 } 288 elsif ($command eq "uncompress") 289 { 290 my ($source_name, $destination_name) = ($operation->[1], $operation->[2]); 291 if ($CompressionMethod eq "bzip2") 292 { 293 $source_name .= ".bz2"; 294 } 295 $installer::logger::Lang->printf("uncompressing %s to %s\n", $source_name, $destination_name); 296 297 my $destination_base_name = basename($destination_name); 298 299 if ( ! $DryRun) 300 { 301 my $result = 0; 302 if ($CompressionMethod eq "bzip2") 303 { 304 $result = IO::Uncompress::Bunzip2::bunzip2($source_name => $destination_name); 305 } 306 if ($result == 0) 307 { 308 $installer::logger::Lang->printf("ERROR: failed to extract content of '%s' from '%s'\n", 309 $destination_name, $source_name); 310 return 0; 311 } 312 } 313 } 314 315 else 316 { 317 die "unknown operation $command\n"; 318 } 319 } 320 321 return 1; 322} 323 324 325 326sub GetOperationCount ($) 327{ 328 my ($self) = @_; 329 return scalar @{$self->{'operations'}}; 330} 331 332 3331; 334