#************************************************************** # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # #************************************************************** package installer::patch::FileOperations; use File::Basename; use File::Copy; use IO::Compress::Bzip2; use IO::Uncompress::Bunzip2; my $CompressionMethod = "bzip2"; =head1 NAME package installer::patch::FileOperations - Class for collecting, checking and executing file operations. =cut sub new ($) { my ($class) = (@_); my $self = { 'operations' => [] }; bless($self, $class); return $self; } sub AddCopyOperation ($$$) { my ($self, $source_name, $target_name) = @_; push @{$self->{'operations'}}, [ 'copy', $source_name, $target_name ]; } sub AddMakeDirectoryOperation ($$) { my ($self, $path) = @_; push @{$self->{'operations'}}, [ 'mkdir', $path ]; } sub AddCompressOperation ($$) { my ($self, $filename) = @_; push @{$self->{'operations'}}, [ 'compress', $filename ]; } sub AddUncompressOperation ($$$) { my ($self, $source_name, $target_name) = @_; push @{$self->{'operations'}}, [ 'uncompress', $source_name, $target_name ]; } sub Check ($) { my ($self) = @_; # Keep track of which directories or files would be created to check if # operations that depend on these files will succeed. my %files = (); my %directories = (); my @error_messages = (); foreach my $operation (@{$self->{'operations'}}) { my $command = $operation->[0]; if ($command eq "copy") { my ($source_name, $destination_name) = ($operation->[1], $operation->[2]); if ( ! -f $source_name) { push @error_messages, sprintf("%s is not a regular file and can not be copied", $source_name); } my $destination_path = dirname($destination_name); if ( ! -d $destination_path && ! defined $directories{$destination_path}) { push @error_messages, sprintf("destination path %s does not exist", $destination_path); } if ( -f $destination_name) { # The destination file already exists. We have to overwrite it. if ( ! -w $destination_name) { push @error_messges, sprintf("destination file %s exists but can not be overwritten", $destination_name); } } $files{$destination_name} = 1; } elsif ($command eq "mkdir") { my $path = $operation->[1]; if ( -d $path) { # Directory already exists. That is OK, the mkdir command will be silently ignored. } else { $directories{$path} = 1; } } elsif ($command eq "compress") { my $filename = $operation->[1]; if ( ! -f $filename && ! defined $files{$filename}) { # File does not exist and will not be created by an earlier operation. push @error_messages, sprintf("file %s does not exist and can not be compressed", $filename); } } elsif ($command eq "uncompress") { my ($source_filename, $destination_filename) = ($operation->[1], $operation->[2]); if ($CompressionMethod eq "bzip2") { $source_filename .= ".bz2"; } if ( ! -f $source_filename && ! defined $files{$source_filename}) { # File does not exist and will not be created by an earlier operation. push @error_messages, sprintf("file %s does not exist and can not be decompressed", $source_filename); } if ( -f $destination_filename && ! -w $destination_filename) { # Destination file already exists but can not be replaced. push @error_messages, sprintf("compress destination file %s exists but can not be replaced", $destination_filename); } } else { push @error_messages, sprintf("unknown operation %s", $command); } } return @error_messages; } sub CheckAndExecute ($) { my ($self) = @_; my @error_messages = $self->Check(); if (scalar @error_messages > 0) { $installer::logger::Lang->printf("can not execute all operations:\n"); for my $message (@error_messages) { $installer::logger::Lang->printf("ERROR: %s\n", $message); } return 0; } else { return $self->Execute(); } } sub Execute ($) { my ($self) = @_; foreach my $operation (@{$self->{'operations'}}) { my $command = $operation->[0]; if ($command eq "copy") { my ($source_name, $destination_name) = ($operation->[1], $operation->[2]); $installer::logger::Lang->printf("copy from %s\n to %s\n", $source_name, $destination_name); if ( ! $DryRun) { my $result = copy($source_name, $destination_name); if ( ! $result) { $installer::logger::Lang->printf("ERROR: copying from %s to %s failed", $source_name, $destination_name); } } } elsif ($command eq "mkdir") { my $path = $operation->[1]; if ( -d $path) { # Path exists already. Do nothing. } else { $installer::logger::Lang->printf("creating directory %s\n", $path); if ( ! $DryRun) { if (File::Path::make_path($path, {'mode' => 0775}) == 0) { $installer::logger::Lang->printf("could not create directory %s\n", $path); } } } } elsif ($command eq "compress") { my $filename = $operation->[1]; $installer::logger::Lang->printf("compressing %s\n", $filename); if ( ! $DryRun) { my $result = 0; if ($CompressionMethod eq "bzip2") { $result = IO::Compress::Bzip2::bzip2($filename => $filename.".bz2"); } if ($result == 0) { $installer::logger::Lang->printf("ERROR: could not compress %s\n", $filename); } else { unlink($filename); } } } elsif ($command eq "uncompress") { my ($source_name, $destination_name) = ($operation->[1], $operation->[2]); if ($CompressionMethod eq "bzip2") { $source_name .= ".bz2"; } $installer::logger::Lang->printf("uncompressing %s to %s\n", $source_name, $destination_name); my $destination_base_name = basename($destination_name); if ( ! $DryRun) { my $result = 0; if ($CompressionMethod eq "bzip2") { $result = IO::Uncompress::Bunzip2::bunzip2($source_name => $destination_name); } if ($result == 0) { $installer::logger::Lang->printf("ERROR: failed to extract content of '%s' from '%s'\n", $destination_name, $source_name); return 0; } } } else { die "unknown operation $command\n"; } } return 1; } sub GetOperationCount ($) { my ($self) = @_; return scalar @{$self->{'operations'}}; } 1;