CfgTie::filever - a simple module for substituting newer versions into a file system.


CfgTie documentation Contained in the CfgTie distribution.

Index


Code Index:

NAME

Top

CfgTie::filever -- a simple module for substituting newer versions into a file system.

SYNOPSIS

Top

This module allows a newer version of file to be safely placed into the file system.

DESCRIPTION

Top

This is a set of utilities for manipulating files.

File's_Rotate ($Old, $New)

This is the file space equivalent to the variable exchange or swap. The old file will be renamed (with a .old extension) and the new file will be renamed to old. This is extremely useful for many semi-critical functions, where modifying the file directly will cause unpredictable results. Instead, the preferred method is to modify old sending the results to new in the background and then doing a very quick switcheroo.

It preserves the permissions and ownership of the original file.

If this routine fails, it will make an attempt to restore things to their original state and return.

Return Value: 0 on success, -1 on error;

Roll(path,depth,sep)

This convert the specified files into a backup file (the original file is renamed, so you had better have something to put there).

Depth

(optional) Controlls the number of backup copies

Sep

(optional) Controlls the seperator between the main name and the backup number

The defaults for depth and sep are controlled by following two variables in the package:

RollDepth

Controlls the number of of older versions that are kept around as backup copies. [Default: 4]

RollSep

Controls the separator between the file name and the backup number. [Default: ~]

RCS_path (RCSObj,path)

For the given RCS object, this sets the working directory and the file.

find_by_user

This function attempts to locate all of the files in the system that are owned by the specified users. It takes the following parameters:

Base

Base can be a string to the base path or a reference to a list of base paths to search.

Return Value:

undef if there was an error
otherwise the list of file that matched

Author

Top

Randall Maas (randym@acm.org, http://www.hamline.edu/~rcmaas/)


CfgTie documentation Contained in the CfgTie distribution.

#Copyright 1998-2001, Randall Maas.  All rights reserved.  This program is free
#software; you can redistribute it and/or modify it under the same terms as
#PERL itself.

package CfgTie::filever;

my $RollDepth = 4;
my $RollSep = '~';

sub Rotate
{
   my($Old, $New) =  @_;
   if (!defined $Old) {die "Rotate: old not defined, but $New is!\n";}
   if ($Old eq $New) {return;}

   my @S =stat $Old;
   #If the old file does exist we need to do a bit of work (we use stat
   #since the other bits of information are relevant too)
   if (scalar @S)
     {
        #Migrate us to some backup copies, use one more than default so we
        #can unroll
        &Roll($Old,$RollDepth+1);

        # Modify the permissions of the new file to match that of the old one.
        if (!chmod($S[2], $New) ||

        # Modify the ownership of the new file to match that of the old one.
            !chown($S[4], $S[5], $New)||

            !rename($New, $Old))
          {
             die "bad things happened: $New doesn't exist? $!\n";
             &Unroll($Old,$RollDepth+1);
             return -1;
          }
     }
    else
     {
        rename ($New,$Old) || return -1;
     }
    0;
}


sub Roll
{
   my ($File,$Num,$Sep) =@_;
   if (!defined $File) {die "File not defined!\n";}
   if (!defined $Sep) {$Sep = $RollSep;}
   if (!defined $Num) {$Num = $RollDepth;}

   if ($Num < 1) {return;}

   my $Base = $File.$Sep;
   for (my $I=$Num-1; $I; $I--)
    {rename $Base.$I,$Base.($I+1);}

   link $File, $Base."1";
   #rename $File, $Base."1";
}

sub Unroll
{
  my ($File,$Num,$Sep) =@_;
  if (!defined $Sep) {$Sep = $RollSep;}
  if (!defined $Num) {$Num = $RollDepth;}

  if ($Num < 1) {return;}

  my $Base = $File.$Sep;
  rename $Base.'1',$File;
  for (my $I=1; $I < $RollDepth; $I++)
   {rename $Base.($I+1),$Base.$I;}
}

sub RCS_path($$)
{
   my ($RCSObj, $Path) = @_;
   if ($Path =~ /^(.+)\/([^\/]+)$/)
     {
        $RCSObj->workdir($1);
        $RCSObj->file($2);

        #Make the working directory and archive directory make sense
        my $t = $RCSObj->rcsdir;
        if (!defined $t || (substr($t,0,1) ne '/' && substr($1,0,1) ne '.'))
          {$RCSObj->rcsdir($1.'/'.$t);}

     }
    else
     {
        $RCSObj->file($Path);
     }
}

use FileHandle;

sub open($)
{
   local($name)=@_;
   #Save the environment so we can restore it
   my $E=\%ENV;

   #Erase the path, and other environment information
   %ENV=();
   $ENV{'PATH'}='/bin:/sbin';
   my $F=eval ('new FileHandle $name');

   #Restore the environment
   %ENV=%{$E};
   $F;
}

sub system($)
{
   my $F= &filever::open($_[0]."|");
   $F->close;
}


my @UID_paths; # Holder of file paths that match 

sub UID_worker
{
   # A worker to check to see if the specified files owner matches any in our
   # set
   my @S = stat $_;
   if (exists $UIDs_to_watch{$S[4]}) {push @UID_paths, $File::Find::name;}
}

sub find_by_user
{
   my $Base = shift;

   if (!scalar @_) {return ();}

   use File::Find;
   my %User;
   tie %User, 'user';

   #Convert all of the user names and such to ids
   %UIDs_to_watch=();
   foreach my $I (@_)
    {
       if (exists $User{$I})
         {$UIDs_to_watch{$User{$I}->{Id}}=1;}
        else
         {$UIDs_to_watch{$I} = 1;}
    }

   #Call find to executie it
   @UID_paths=();
   if (not ref $Base)
     {find(\&UID_worker, $Base);}
    else
     {find(\&UID_worker, @{$Base});}
   return @UID_paths;
}

1;