File Coverage

blib/lib/Persistence/Object/Simple.pm
Criterion Covered Total %
statement 15 126 11.9
branch 0 62 0.0
condition 0 32 0.0
subroutine 5 15 33.3
pod 8 10 80.0
total 28 245 11.4


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -s
2             ##
3             ## Persistence::Object::Simple -- Persistence For Perl5 Objects.
4             ##
5             ## $Date: 1999/10/13 23:08:43 $
6             ## $Revision: 0.47 $
7             ## $State: Exp $
8             ## $Author: root $
9             ##
10             ## Copyright (c) 1998, Vipul Ved Prakash. All rights reserved.
11             ## This code is free software; you can redistribute it and/or modify
12             ## it under the same terms as Perl itself.
13              
14             package Persistence::Object::Simple;
15 1     1   753 use Digest::MD5;
  1         2  
  1         38  
16 1     1   1273 use Data::Dumper;
  1         10350  
  1         71  
17 1     1   9 use Carp;
  1         5  
  1         48  
18 1     1   4 use Fcntl;
  1         1  
  1         273  
19 1     1   5 use vars qw( $VERSION );
  1         1  
  1         1517  
20              
21             ( $VERSION ) = '$Revision: 0.92 $' =~ /\s+(\d+\.\d+)\s+/; #-- Module Version
22              
23             my $DOPE = "/tmp"; #-- The default Directory Of Persistent Entities
24             my $MAXTRIES = 250; #-- TTL counter for generating a unique file
25              
26             sub dope { #-- Default DOPE access method
27              
28 0     0 0   my ( $self, $dope ) = @_;
29 0 0         ${ $self->{ __DOPE } } = $dope if $dope;
  0            
30 0           ${ $self->{ __DOPE } };
  0            
31              
32             }
33            
34             sub new { #-- Constructor. Creates and inits a P::O::S
35             #-- object instance. Binds class data.
36              
37 0     0 1   my ( $class, %args ) = @_;
38 0           my $self = {};
39 0           my $fn = $args{ __Fn };
40 0           my $exists;
41 0   0       $args{ __Create } ||= "";
42 0 0 0       if ($args{ __Create } and lc($args{ __Create }) eq "no") {
43 0           $exists = 1;
44             }
45              
46 0 0 0       return undef if !(-e $fn) && $exists;
47 0 0         unless ( $fn ) {
48 0   0       $fn = $class->uniqfile ( $args{ __Dope } || $DOPE, $args{ __Random } );
49 0 0         return undef unless $fn;
50             }
51              
52 0           $self->{ __Fn } = $fn;
53 0           $self->{ __DOPE } = \$DOPE;
54              
55            
56 0           my $existing = $class->load ( __Fn => $fn );
57 0 0         $self = $existing if $existing;
58 0           for ( keys %args ) { $self->{ $_ } = $args{ $_ } }
  0            
59              
60 0           bless $self, $class;
61              
62             }
63              
64             sub dumper { #-- Returns the Data::Dumper object associated
65             #-- with the instance
66 0     0 1   my $self = shift;
67              
68 0           $self->{ __Dumper } = new Data::Dumper ( [ $self ] );
69 0           return $self->{ __Dumper };
70              
71             }
72              
73             sub commit { #-- Commits the object to disk. Works as a class
74             #-- method as well.
75 0     0 1   my ( $self, %args ) = @_;
76 0   0       my $class = ref $self || $self;
77 0           my ( $d, $fn );
78 0   0       $fn = $args{ __Fn } || $self->{ __Fn };
79              
80 0 0         if ( ref $self ) {
81 0   0       $d = $self->{ __Dumper } || $self->dumper () ;
82             } else { # -- Whoa! It's a class method!
83 0           $d = new Data::Dumper ( [ $args{ Data } ] );
84             }
85              
86 0 0 0       if ( $args{ __Dope } && $fn ) { # -- change to a new dope
87 0           $fn =~ s:.*/::;
88 0           $args{ __Dope } =~ s:/$::;
89 0           $fn = $args{ __Dope } . "/$fn";
90 0 0         croak "$fn exists. Can't overwrite." if -e $fn;
91             }
92            
93 0 0         unless ( $fn ) { # -- generate a uniq filename in the
94 0 0         $args{ __Dope } = $DOPE unless $args{ __Dope }; # -- new dope
95 0           $fn = $class->uniqfile ( $args{ __Dope } );
96             }
97              
98            
99 0           my $locked_fh = $self->{ __Lock };
100 0 0         seek $locked_fh, 0, 0 if $locked_fh;
101 0           my $fh;
102              
103             # -- delete extra object data and class data-refs if this looks like
104             # -- an object.
105 0 0         if ( ref $self ) {
106 0 0         for ( keys %$self ) { delete $self->{ $_ }
  0            
107             if /^__(?:Dumper|DOPE|Fn|Lock|Create)/ };
108             }
109              
110 0 0         unless ( $locked_fh ) {
111             # guard against disallowed characters in filename (basically those
112             # which might mess up the open() call)
113 0 0         if (($fn) = ($fn =~ /^([^<>|+]+)$/)) {
114 0   0       open C, ">$fn" || croak "Can't open $fn for writing.";
115 0           eval { flock C, 2 }; undef $@;
  0            
  0            
116 0           $fh = *C{ IO };
117             } else {
118 0           die "Filename '$fn' contains inappropriate characters";
119             }
120             }
121              
122 0 0         print { $locked_fh ? $locked_fh : $fh }
  0 0          
123             defined &Data::Dumper::Dumpxs ? $d->Dumpxs() : $d->Dump();
124 0 0         close $fh if $fh;
125              
126 0 0         if ( ref $self ) {
127 0           $self->{ __Fn } = $fn;
128 0 0         $self->{ __Lock } = $locked_fh if $locked_fh;
129             }
130              
131 0           return $fn;
132              
133             }
134              
135             sub load {
136              
137 0     0 1   my ( $class, %args ) = @_;
138              
139 0 0         return undef unless -e $args{ __Fn };
140            
141 0   0       open C, $args{ __Fn } || croak "Couldn't open $args{ __Fn }.";
142 0           eval { flock C, 2 }; undef $@;
  0            
  0            
143              
144 0           local $/ = undef; # slurp mode
145 0           my $objectfile = ;
146 0           close C;
147              
148             # untaint the input meaningfully
149 0 0         if ($objectfile =~ /^(\$VAR1 = bless[^;]+;)$/s) {
    0          
150 0           my $object = eval "$1";
151 0 0         croak "$args{ __Fn } is corrupt. Object loading aborted." if $@;
152              
153 0 0         $object->{ __Fn } = $args{ __Fn } if ref $object eq 'HASH';
154 0           return $object;
155             } elsif ($objectfile =~ /^$/) {
156 0           return undef;
157             } else {
158 0           croak "Tainted data from $args{__Fn} looks unsafe. Object loading aborted.";
159             }
160             }
161              
162             sub expire {
163              
164 0     0 1   my ( $self ) = @_;
165 0           my $fn = $self->{ __Fn };
166 0 0         return 1 if unlink $fn;
167              
168             }
169              
170             sub move {
171              
172 0     0 1   my ( $self, %args ) = @_;
173 0           my $class = ref $self;
174              
175 0           $self->expire ();
176 0 0         $self->{ __Fn } = undef if $args{ __Fnalter };
177 0           my $fn = $self->commit ( %args );
178              
179 0           my $moved = $class->new ( __Fn => $fn );
180 0           $self = $moved;
181              
182             }
183              
184             sub lock {
185              
186 0     0 1   my ( $self ) = @_;
187              
188 0           my $fn = $self->{ __Fn };
189 0 0         $self->commit unless -e $fn;
190 0 0         open ( F, "+<$fn" ) || croak "Couldn't open $fn for locking. Commit first!";
191 0           eval { flock F, 2 }; undef $@;
  0            
  0            
192 0           $self->{ __Lock } = *F{ IO };
193              
194             }
195              
196             sub unlock {
197              
198 0     0 1   my ( $self ) = @_;
199 0           my $F = $self->{ __Lock }; close $F;
  0            
200 0           undef $self->{ __Lock };
201            
202             }
203              
204             sub uniqfile {
205              
206 0     0 0   my ( $class, $dir, $random ) = @_;
207 0           my $fn; my $counter;
208              
209 0   0       do {
210 0           $fn = Digest::MD5::md5_hex( "@{[time]}.@{[int rand 2**8]}.$random" );
  0            
  0            
211 0           ($fn) = ($fn =~ m!([^/<>|;]+)!);
212 0           $counter++ ;
213             }
214             until sysopen ( C, "$dir/$fn" , O_RDWR|O_EXCL|O_CREAT )
215             or $counter > $MAXTRIES;
216              
217 0           close C;
218 0 0         return undef if $counter > $MAXTRIES;
219 0           return "$dir/$fn";
220             }
221              
222             'True Value';
223              
224             __END__