#!/usr/bin/env perl #-*- Mode: perl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- # Functions for file manipulation. Find, open, read, write, backup, etc. # # Copyright (C) 2000-2001 Ximian, Inc. # # Authors: Hans Petter Jansson # Arturo Espinosa # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Library General Public License as published # by the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Library General Public License for more details. # # You should have received a copy of the GNU Library General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. require "___scriptsdir___/general.pl"; require "___scriptsdir___/report.pl"; # --- File operations --- # sub xst_file_get_base_path { return "/var/cache/ximian-setup-tools"; } sub xst_file_get_tmp_path { return (&xst_file_get_base_path () . "/tmp"); } sub xst_file_get_backup_path { return (&xst_file_get_base_path () . "/backup"); } sub xst_file_get_debug_path { return (&xst_file_get_base_path (). "/debug"); } sub xst_file_get_data_path { return (&xst_file_get_base_path (). "/data"); } sub xst_file_create_path { my $path = $_[0]; my @pelem; $path =~ tr/\///s; @pelem = split(/\//, $path); # 'a/b/c/d/' -> 'a', 'b', 'c', 'd', '' for ($path = ""; @pelem; shift @pelem) { $path = "$path$pelem[0]"; mkdir($path, 0770); $path = "$path/"; } &xst_report_enter (); &xst_report ("file_create_path", $_[0]); &xst_report_leave (); } sub xst_file_create_path_for_file { my $path = $_[0]; my @pelem; $path =~ tr/\///s; @pelem = split(/\//, $path); # 'a/b/c/d/' -> 'a', 'b', 'c', 'd', '' for ($path = ""; @pelem; shift @pelem) { if ($pelem[1] ne "") { $path = "$path$pelem[0]"; mkdir($path, 0770); $path = "$path/"; } } &xst_report_enter (); &xst_report ("file_create_path", $_[0]); &xst_report_leave (); } $xst_file_backup_dir_rotation_was_made = 0; # If this is the first backup created by this tool on this invocation, # rotate the backup directories and create a new, empty one. sub xst_file_backup_rotate_dirs { my $backup_tool_dir = $_[0]; &xst_report_enter (); if (!$xst_file_backup_dir_rotation_was_made) { my $i; $xst_file_backup_dir_rotation_was_made = 1; &xst_file_run ("rm -Rf $backup_tool_dir/9"); for ($i = 8; $i; $i--) { if (stat ("$backup_tool_dir/$i")) { &xst_file_run ("mv $backup_tool_dir/$i $backup_tool_dir/" . ($i+1)); } } if (!stat ("$backup_tool_dir/First")) { &xst_file_create_path ("$backup_tool_dir/First"); &xst_file_run ("ln -s First $backup_tool_dir/1"); } else { &xst_file_create_path_for_file ("$backup_tool_dir/1/"); } &xst_report ("file_backup_rotate", $backup_tool_dir); } &xst_report_enter (); } sub xst_file_backup { my $backup_file = $_[0]; my $backup_tool_dir; &xst_report_enter (); $backup_tool_dir = &xst_file_get_backup_path () . "/$xst_name/"; &xst_file_backup_rotate_dirs ($backup_tool_dir); # If the file hasn't already been backed up on this invocation, copy the # file to the backup directory. if (!stat ("$backup_tool_dir/1/$backup_file")) { &xst_file_create_path_for_file ("$backup_tool_dir/1/$backup_file"); &xst_file_run ("cp $backup_file $backup_tool_dir/1/$backup_file"); &xst_report ("file_backup_success", $backup_tool_dir); } &xst_report_leave (); } sub xst_file_open_read_from_names { local *FILE; my $fname = ""; &xst_report_enter (); foreach $name (@_) { if (open (FILE, "$xst_prefix/$name")) { $fname = $name; last; } } (my $fullname = "$xst_prefix/$fname") =~ tr/\//\//s; # '//' -> '/' if ($fname eq "") { &xst_report ("file_open_read_failed", "@_"); return; } &xst_report ("file_open_read_success", $fullname); &xst_report_leave (); return *FILE; } sub xst_file_open_write_from_names { local *FILE; my $name; my $fullname; &xst_report_enter (); # Find out where it lives. foreach $elem (@_) { if (stat($elem) ne "") { $name = $elem; last; } } if ($name eq "") { $name = $_[0]; (my $fullname = "$xst_prefix/$name") =~ tr/\//\//s; &xst_report ("file_open_write_create", "@_", $fullname); } else { (my $fullname = "$xst_prefix/$name") =~ tr/\//\//s; &xst_report ("file_open_write_success", $fullname); } ($name = "$xst_prefix/$name") =~ tr/\//\//s; # '//' -> '/' &xst_file_create_path_for_file ($name); # Make a backup if the file already exists - if the user specified a prefix, # it might not. if (stat ($name)) { &xst_file_backup ($name); } &xst_report_leave (); # Truncate and return filehandle. if (!open (FILE, ">$name")) { &xst_report ("file_open_write_failed", "Failed to write to \[$name\]"); return; } return *FILE; } sub xst_file_open_filter_write_from_names { local *INFILE; local *OUTFILE; my ($filename, $name, $elem); &xst_report_enter (); # Find out where it lives. foreach $coin (@_) { if (-e $coin) { $name = $coin; last; } } if (! -e $name) { # If we couldn't locate the file, and have no prefix, give up. # If we have a prefix, but couldn't locate the file relative to '/', # take the first name in the array and let that be created in $prefix. if ($prefix eq "") { &xst_report ("file_open_filter_failed", "@_"); return(0, 0); } else { $name = $_[0]; (my $fullname = "$xst_prefix/$name") =~ tr/\//\//s; &xst_report ("file_open_filter_create", "@_", $fullname); } } else { (my $fullname = "$xst_prefix/$name") =~ tr/\//\//s; &xst_report ("file_open_filter_success", $name, $fullname); } ($filename) = $name =~ /.*\/(.+)$/; ($name = "$xst_prefix/$name") =~ tr/\//\//s; # '//' -> '/' &xst_file_create_path_for_file ($name); # Make a backup if the file already exists - if the user specified a prefix, # it might not. if (-e $name) { &xst_file_backup ($name); } # Return filehandles. Make a copy to use as filter input. It might be # invalid (no source file), in which case the caller should just write to # OUTFILE without bothering with INFILE filtering. my $tmp_path = &xst_file_get_tmp_path (); &xst_file_create_path ("$tmp_path"); unlink ("$tmp_path/$xst_name-$filename"); &xst_file_run ("cp $name $tmp_path/$xst_name-$filename"); open (INFILE, "$tmp_path/$xst_name-$filename"); if (!open (OUTFILE, ">$name")) { &xst_report ("file_open_filter_failed", $name); return; } &xst_report_leave (); return (*INFILE, *OUTFILE); } sub xst_file_remove { my ($name) = @_; &xst_report_enter (); &xst_report ("file_remove", $name); if (stat ($name)) { &xst_file_backup ($name); } unlink $name; &xst_report_leave (); } # --- Buffer operations --- # # Open $file and put it into @buffer, for in-line editting. # \%buffer on success, undef on error. sub xst_file_buffer_load { my $file = $_[0]; my @buffer; my $fd; &xst_report_enter (); &xst_report ("file_buffer_load", $file); $fd = &xst_file_open_read_from_names ($file); return [] if !$fd; @buffer = (<$fd>); &xst_report_leave (); return \@buffer; } # Take a $buffer and save it in $file. -1 is error, 0 success. sub xst_file_buffer_save { my ($buffer, $file) = @_; my ($fd, $i); &xst_report_enter (); &xst_report ("file_buffer_save", $file); foreach $i (@$buffer) { &xst_debug_print_string ("|" . $i); } $fd = &xst_file_open_write_from_names ($file); return -1 if !$fd; if (@$buffer < 1) { # We want to write single line. # Print only if $buffer is NOT a reference (it'll print ARRAY(0x412493) for example). print $fd $buffer if (!ref ($buffer)); } else { # Let's print array foreach $i (@$buffer) { print $fd $i; } } close $fd; &xst_report_leave (); return 0; } # Erase all empty string elements from the $buffer. sub xst_file_buffer_clean { my $buffer = $_[0]; my $i; for ($i = 0; $i <= $#$buffer; $i++) { splice (@$buffer, $i, 1) if $$buffer[$i] eq ""; } } sub xst_file_buffer_join_lines { my $buffer = $_[0]; my $i; for ($i = 0; $i <= $#$buffer; $i++) { while ($$buffer[$i] =~ /\\$/) { chomp $$buffer[$i]; chop $$buffer[$i]; $$buffer[$i] .= $$buffer[$i + 1]; splice (@$buffer, $i + 1, 1); } } } # --- Command-line utilities --- # # &xst_file_run () # # Assumes the first word on the command line is the command-line utility # to run, and tries to locate it, replacing it with its full path. The path # is cached in a hash, to avoid searching for it repeatedly. Output # redirection is appended, to make the utility perfectly silent. The # preprocessed command line is run, and its exit value is returned. # # Example: "mkswap /dev/hda3" -> '/bin/sh -c "/sbin/mkswap /dev/hda3" >/dev/null 2>/dev/null'. sub xst_file_run { my ($cmd) = @_; my ($command, $tool_name, $tool_path, @argline); &xst_report_enter (); ($tool_name, @argline) = split("[ \t]+", $cmd); $tool_path = &xst_file_locate_tool ($tool_name); if ($tool_path eq "") { # Not found at all. return -1; } $command = "$tool_path @argline"; $command =~ s/\"/\\\"/g; &xst_report ("file_run", "$command > /dev/null 2> /dev/null"); &xst_report_leave (); # As documented in perlfunc, divide by 256. return (system ("$command > /dev/null 2> /dev/null") / 256); } # &xst_file_locate_tool # # Tries to locate a command-line utility from a set of built-in paths # and a set of user paths (found in the environment). The path (or a negative # entry) is cached in a hash, to avoid searching for it repeatedly. @xst_builtin_paths = ( "/sbin", "/usr/sbin", "/usr/local/sbin", "/bin", "/usr/bin", "/usr/local/bin" ); %xst_tool_paths = {}; sub xst_file_locate_tool { my $found = ""; my @user_paths; # We don't search absolute paths. Arturo. return $_[0] if $_[0] =~ /^\//; &xst_report_enter (); $found = %xst_tool_paths->{$_[0]}; if ($found eq "0") { # Negative cache hit. At this point, the failure has already been reported # once. return ""; } if ($found eq "") { # Nothing found in cache. Look for real. # Extract user paths to try. @user_paths = ($ENV{PATH} =~ /([^:]+):/mg); # Try user paths. for $path (@user_paths) { if (-x "$path/$_[0]") { $found = "$path/$_[0]"; last; } } # Try builtin paths. for $path (@xst_builtin_paths) { if (-x "$path/$_[0]") { $found = "$path/$_[0]"; last; } } # Report success/failure and update cache. if ($found) { %xst_tool_paths->{$_[0]} = $found; &xst_report ("file_locate_tool_success", $_[0]); } else { %xst_tool_paths->{$_[0]} = "0"; &xst_report ("file_locate_tool_failed", $_[0]); } } &xst_report_leave (); return ($found); } sub xst_file_tool_installed { my ($tool) = @_; $tool = &xst_file_locate_tool ($tool); return 0 if $tool eq ""; return 1; } 1;