diff options
| author | jdennis <jdennis@c9f7a03b-bd48-0410-a16d-cbbf54688b0b> | 2010-11-19 20:36:54 +0000 |
|---|---|---|
| committer | jdennis <jdennis@c9f7a03b-bd48-0410-a16d-cbbf54688b0b> | 2010-11-19 20:36:54 +0000 |
| commit | 391e47d2b0006d49395b1906a1f6f469e874dfa2 (patch) | |
| tree | 59a089453c70709b2bc354cf45818b96e97c43da | |
| parent | 3295970b2f978951e235bb237912f0f7497b687d (diff) | |
| download | pki-391e47d2b0006d49395b1906a1f6f469e874dfa2.tar.gz pki-391e47d2b0006d49395b1906a1f6f469e874dfa2.tar.xz pki-391e47d2b0006d49395b1906a1f6f469e874dfa2.zip | |
Reimplement copy_directory, remove_directory
The copy_directory function was losing critical information. It called
out to the shell to recursively copy the contents of one directory to
another. But this meant we lost track of the files and directories
actually being copied, we couldn't log them nor add them to the
installation manifest. Now the copy_directory function builds a list
of files in the src directory and iteratively copies each file calling
into our copy_file function which records the operation and checks for
errors.
The remove_directory function was an unapologetic sledge hammer, it
simply nuked entire trees. Now the function is more sensible, by
default it removed one empty directory, or optionally recursively
removes all directory contents.
Both functions previously had serious implementation mistakes. Both
were implemented by calling out to a UNIX shell and invoking a shell
command via the Perl backtick operator. The fundamental problems with
this were:
* UNIX shell commands only work on UNIX
* Not all UNIX shell commands are identical
* The error detection stragegy was completly broken. It executed the
shell command via the backtick operator which returns the stdout of
the command and discards stderr. The function would then test to see
if the length of stdout was zero to determine if there was an
error. If there was no stdout it assumed no errors occurred. This is
completely wrong. To test if an error occurs with a shell command
one needs to examine the exit status of the command which is
impossible to do with the Perl backtick operator. If one wants to
test the exit status of a shell command in Perl you must utilize the
subprocess features of Perl.
The reimplementation eschews the non-portable use of UNIX shell
commands in favor of the portable Perl extensions for operating on
filesystem directories.
git-svn-id: svn+ssh://svn.fedorahosted.org/svn/pki/trunk@1538 c9f7a03b-bd48-0410-a16d-cbbf54688b0b
| -rwxr-xr-x | pki/base/setup/pkicommon | 132 |
1 files changed, 87 insertions, 45 deletions
diff --git a/pki/base/setup/pkicommon b/pki/base/setup/pkicommon index 127720cb..dc197fa1 100755 --- a/pki/base/setup/pkicommon +++ b/pki/base/setup/pkicommon @@ -2878,82 +2878,110 @@ sub move_directory return 0; } - -# arg0 source directory -# arg1 destination path +# arg0 src directory +# arg1 dst path # return 1 - successfully copied directory, or # return 0 - failed copying directory sub copy_directory { - my $source_dir_path = $_[0]; - my $dest_dir_path = $_[1]; + my($src_dir_path, $dst_dir_path, $uninstall_action) = @_; + my($result); + my($paths, $path, $src_path, $dst_path); + my(%dst_dirs, $dst_dir); - my $result = 0; + $uninstall_action = 'remove' unless defined($uninstall_action); + $result = 1; + + $src_dir_path = normalize_path($src_dir_path); + $dst_dir_path = normalize_path($dst_dir_path); - emit("copy_directory(): source=> $source_dir_path dest=> $dest_dir_path \n","debug"); - if (!is_path_valid($source_dir_path)) { - emit("copy_directory(): illegal source path => $source_dir_path.\n", + if ($verbose > 1) { + emit(sprintf("%s(%s)\n", (caller(0))[3], join(', ', @_))); + } + + emit("copy_directory(): $src_dir_path => $dst_dir_path\n", "debug"); + if (!is_path_valid($src_dir_path)) { + emit("copy_directory(): illegal src path => $src_dir_path.\n", "error"); return 0; } - if (!is_path_valid($dest_dir_path)) { - emit("copy_directory(): illegal destination path => " - . "$dest_dir_path.\n", - "error"); + if (!is_path_valid($dst_dir_path)) { + emit("copy_directory(): illegal dst path ($dst_dir_path)\n", "error"); return 0; } - if (!directory_exists($source_dir_path)) { + if (!directory_exists($src_dir_path)) { # Take the case where this directory does not exist # Just return true + emit("copy_directory(): non-existent src path ($src_dir_path)\n", "error"); return 1; } - if (!directory_exists($dest_dir_path)) { - $result = create_directory($dest_dir_path); - if (!$result) { - return 0; - } + # Get list of files under the src dir + $paths = get_directory_files($src_dir_path, {'strip_dir' => 1}); + + + # Assure each destination directory exists + $dst_dirs{$dst_dir_path}++; + for $path (@$paths) { + $dst_path = "${dst_dir_path}/${path}"; + $dst_dir = dirname($dst_path); + $dst_dirs{$dst_dir}++; } - if (!is_directory_empty($source_dir_path)) { - $result = `cp -fr $source_dir_path/* $dest_dir_path`; - } else { - $result = 0; + for $dst_dir (keys %dst_dirs) { + return 0 if !create_directory($dst_dir); } - # System call returns 0 on success. - if ($result == 0) { - return 1; + # Copy each file + for $path (@$paths) { + $src_path = "${src_dir_path}/${path}"; + $dst_path = "${dst_dir_path}/${path}"; + if (!copy_file($src_path, $dst_path)) { + $result = 0; + } } - emit("copy_directory(): failed copying directory from $source_dir_path " - . "to $dest_dir_path.\n", - "error"); + if (!$result) { + emit("copy_directory(): failed $src_dir_path => $dst_dir_path.\n", + "error"); + } - return 0; + return $result; } -# arg0 directory -# return 1 - successfully removed directory, or -# return 0 - failed removing directory +# Removes given directory. By default only the directory is removed and +# only if it is empty. To remove the directory and all of it's contents +# you must provide the $remove_contents parameter and set it to true, +# it defaults to false. +# +# Return 1 if success, 0 if failure sub remove_directory { - my ($dir) = $_[0]; + my($dir, $remove_contents) = @_; + my($errors, $result); - emit("remove_directory(): " . $dir . "\n","debug"); - my $result = 0; + $remove_contents = 0 unless defined($remove_contents); + $result = 1; + + emit("remove_directory(): \"$dir\"\n", "debug"); + add_install_info($dir, 'dir', 'remove', 'remove'); + + if ($dry_run || $verbose > 1) { + emit(sprintf("%s(%s)\n", (caller(0))[3], join(', ', @_))); + return 1 if ($dry_run); + } if (!is_path_valid($dir)) { - emit("remove_directory(): specified invalid directory $dir.\n", + emit("remove_directory(): specified invalid directory $dir.\n", "error"); return 0; } if ($dir eq "/") { - emit("remove_directory(): don't even think about removing root!.\n", + emit("remove_directory(): don't even think about removing root!.\n", "error"); return 0; } @@ -2962,15 +2990,29 @@ sub remove_directory return 1; } - $result = `rm -rf $dir`; - if ($result == 0) { - return 1; + if ($remove_contents) { + remove_tree($dir, {error => \$errors}); + if (@$errors) { + my($error, $path, $errstr); + $result = 0; + for $error (@$errors) { + $path, $errstr = %$error; + if ($path eq '') { + emit("remove_directory(): tree=\"$dir\" ($errstr)\n", "error"); + } + else { + emit("remove_directory(): tree=\"$dir\" path=\"$path\" ($errstr)\n", "error"); + } + } + } + } else { + if (!rmdir($dir)) { + $result = 0; + emit("remove_directory(): dir=\"$dir\" ($!) \n", "error"); + } } - emit("remove_directory(): failed to remove directory $dir.\n", - "error"); - - return 0; + return $result; } |
