File Coverage

blib/lib/CGI/Builder/Auth/AdminBase.pm
Criterion Covered Total %
statement 112 175 64.0
branch 28 74 37.8
condition 6 30 20.0
subroutine 21 33 63.6
pod 0 17 0.0
total 167 329 50.7


line stmt bran cond sub pod time code
1             # $Id: AdminBase.pm,v 1.1.1.1 2004/06/28 19:24:26 veselosky Exp $
2             package CGI::Builder::Auth::AdminBase;
3 5     5   26 use strict;
  5         9  
  5         199  
4              
5 5     5   25 use Carp ();
  5         7  
  5         66  
6 5     5   23 use Fcntl ();
  5         22  
  5         109  
7 5     5   4271 use Symbol qw(gensym);
  5         4988  
  5         417  
8 5     5   34 use File::Basename;
  5         10  
  5         600  
9 5     5   27 use Fcntl qw(:DEFAULT :flock);
  5         11  
  5         2721  
10 5     5   45 use vars qw($VERSION);
  5         10  
  5         2985  
11             $VERSION = (qw$Revision: 1.1.1.1 $)[1];
12              
13             #generic contructor stuff
14              
15             my $Debug = 0;
16             my %Default = (DBTYPE => "DBM",
17             SERVER => "_generic",
18             DEBUG => $Debug,
19             LOCKING => 1,
20             READONLY => 0,
21             );
22              
23             my %ImplementedBy = ();
24              
25             sub new {
26 43     43 0 1087 my($class) = shift;
27 43         344 my $attrib = { %Default, @_ };
28 43         191 for (keys %$attrib) { $attrib->{"\U$_"} = delete $attrib->{$_}; }
  390         975  
29 43 50       207 $Debug = $attrib->{DEBUG} if defined $attrib->{DEBUG};
30              
31             #who's gonna do all the work?
32 43         69 my $impclass = $class->implementor(@{$attrib}{qw(DBTYPE SERVER)});
  43         224  
33 43 50       123 unless ($impclass) {
34 0         0 Carp::croak(sprintf "%s not implemented for Server '%s' and DBType '%s'",
35 0         0 $class, @{$attrib}{qw(SERVER DBTYPE)});
36             }
37             #the final product
38 43         48 return new $impclass ( %{$attrib} );
  43         474  
39             }
40              
41 4     4 0 12 sub close { $_[0] = undef }
42              
43             sub dbtype {
44 0     0 0 0 my($self,$dbtype) = @_;
45 0         0 my $old = $self->{DBTYPE};
46 0 0       0 return $old unless $dbtype;
47 0         0 Carp::croak("Can't modify DBType attribute");
48             #I think it makes more sense
49             #just to create a new instance in your script
50 0         0 my $base = $self->baseclass(3); #snag CGI::Builder::Auth::(UserAdmin|GroupAdmin)::(DBM|Text|SQL)
51 0         0 $self->close;
52 0         0 $self = $base->new( %{$self}, DBType => $dbtype );
  0         0  
53 0         0 return $old;
54             }
55              
56             #implementor code derived from URI::URL
57             sub implementor {
58 43     43 0 93 my($self,$dbtype,$server,$impclass) = @_;
59 43   33     207 my $class = ref $self || $self;
60 43         51 my $ic;
61 43 50       98 if(ref $self) {
62 0         0 ($server,$dbtype) = @{$self}{qw(SERVER DBTYPE)};
  0         0  
63             }
64              
65 43 50       137 $server = (defined $server) ? lc($server) : '_generic';
66 43 50       89 $dbtype = (defined $dbtype) ? $dbtype : 'DBM';
67             # print STDERR join('::', $class,$dbtype,$server), "\n";
68 43         136 my $modclass = join('::', $class,$dbtype,$server);
69 43 50       86 if ($impclass) {
70 0         0 $ImplementedBy{$modclass} = $impclass;
71             }
72              
73 43 100       177 return $ic if $ic = $ImplementedBy{$modclass};
74              
75             #first load the database class
76 9         67 $ic = $self->load($class, $dbtype);
77              
78             # now look for a server subclass
79 9         47 $ic = $self->load($ic, $server);
80              
81 9 50       34 if ($ic) {
82 9         24 $ImplementedBy{$ic} = $ic;
83             }
84 9         23 $ic;
85             }
86              
87             sub load {
88 61     61 0 107 my($self) = shift;
89 61         67 my($ic,$module);
90 61 100       134 if(@_ > 1) { $ic = join('::', @_) }
  18         48  
91 43         71 else { $ic = $_[0] }
92 5     5   31 no strict 'refs';
  5         81  
  5         3161  
93 61 100       78 unless (defined @{"${ic}::ISA"}) {
  61         371  
94             # Try to load it
95 18         111 ($module = $ic) =~ s,::,/,g;
96 18         83 $module =~ /^[^<>|;]+$/; $module = $&; #untaint
  18         58  
97 18         28 eval { require "$module.pm"; };
  18         12996  
98 18 50       74 print STDERR "loading $ic $@\n" if $Debug;
99 18 50       27 $ic = '' unless defined @{"${ic}::ISA"};
  18         90  
100             }
101 61         179 $ic;
102             }
103              
104             sub support {
105 9     9 0 29 my($self,%support) = @_;
106 9   33     71 my $class = ref $self || $self;
107 9         17 my($code,$db,$srv);
108 9         26 foreach $srv (keys %support) {
109 5     5   32 no strict 'refs';
  5         9  
  5         15812  
110 22         30 foreach $db (@{$support{$srv}}) {
  22         44  
111 45         94 @{"$class\:\:$db\:\:$srv\:\:ISA"} = qq($class\:\:$db\:\:_generic);
  45         968  
112             }
113             }
114             }
115              
116             sub _check {
117 0     0   0 my($self) = shift;
118 0         0 foreach (@_) {
119 0 0       0 next if defined $self->{$_};
120 0   0     0 Carp::croak(sprintf "cannot construct new %s object without '%s'", ref $self || $self, $_);
121             }
122             }
123              
124             sub _elem {
125 43     43   79 my($self, $element, $val) = @_;
126 43         75 my $old = $self->{$element};
127 43 50       4676 return $old unless $val;
128 0         0 $self->{$element} = $val;
129 0         0 return $old;
130             }
131              
132             #DBM stuff
133             sub _tie {
134 0     0   0 my($self, $key, $file) = @_;
135 0 0 0     0 printf STDERR "%s->_tie($file)\n", ref $self || $self if $Debug;
136 0 0 0     0 Carp::confess
137             qq{Invalid CGI::Builder::Auth::AdminBase call: self="$self" key="$key" file="$file" \$self->{$key}="$self->{$key}"}
138             unless defined $key and defined $file;
139 0   0     0 $self->{$key} ||= {};
140 0         0 my($d,$f,$fl,$m) = ($self->{'_DBMPACK'}, $file, @{$self}{qw(_FLAGS MODE)});
  0         0  
141              
142 0 0       0 tie %{$self->{$key}}, $d, $f, $fl, $m
  0         0  
143             or Carp::croak("tie failed (args[$d,$f,$fl,$m]): $!");
144             }
145              
146             sub _untie {
147 0     0   0 my($self, $key) = @_;
148 0         0 untie %{$self->{$key}};
  0         0  
149             }
150              
151             my(%DBMFiles) = ();
152             my(%DBMFlags) = (
153             GDBM => {
154             rwc => sub { GDBM_File::GDBM_WRCREAT() },
155             rw => sub { GDBM_File::GDBM_READER()|GDBM_File::GDBM_WRITER() },
156             w => sub { GDBM_File::GDBM_WRITER() },
157             r => sub { GDBM_File::GDBM_READER() },
158             },
159             DEFAULT => {
160             rwc => sub { O_RDWR|O_CREAT },
161             rw => sub { O_RDWR },
162             w => sub { O_WRONLY },
163             r => sub { O_RDONLY },
164             },
165             );
166              
167             sub _dbm_init {
168 0     0   0 my($self,$dbmf) = @_;
169 0 0       0 $self->{DBMF} = $dbmf if defined $dbmf;
170 0         0 my($flags, $dbmpack);
171 0 0       0 unless($dbmpack = $DBMFiles{$self->{DBMF}}) {
172 0         0 $DBMFiles{$dbmpack} = $dbmpack = "$self->{DBMF}_File";
173 0 0       0 $self->load($dbmpack) or Carp::croak("can't load '$dbmpack'");
174             }
175              
176 0         0 @{$self}{qw(_DBMPACK _FLAGS)} = ($dbmpack, $self->flags);
  0         0  
177 0         0 1;
178             }
179              
180             sub lock {
181 43     43 0 77 my($self,$timeout,$file) = @_;
182 43         219 my($FH) = $self->{'_LOCKFH'} = $self->gensym;
183 43 100       672 return 1 unless $self->{LOCKING};
184 39   50     162 $timeout = $timeout || 10;
185              
186 39 50 33     192 unless($file = $file || "$self->{DB}.lock") {
187 0         0 Carp::croak("can't set lock, no file specified!");
188             }
189 39 50       2275 unless ( -w dirname($self->{'_LOCKFILE'} = $file)) {
190 0 0       0 print STDERR "lock: can't write to '$file' " if $Debug;
191             #for writing lock files under CGI and such
192 0         0 $self->{'_LOCKFILE'} = $file =
193             sprintf "%s/%s-%s", $self->tmpdir(), "HTTPD", basename($file);
194 0 0       0 print STDERR "trying '$file' instead\n" if $Debug;
195             }
196              
197 39 50       202 $file =~ /^([^<>;|]+)$/ or Carp::croak("Bad file name '$file'"); $file = $1; #untaint
  39         90  
198              
199 39 50       3216 open($FH, ">$file") || Carp::croak("can't open '$file' $!");
200              
201 39         422 while(! flock($FH, LOCK_EX|LOCK_NB) ) {
202 0         0 sleep 1;
203 0 0       0 if(--$timeout < 0) {
204 0         0 print STDERR "lock: timeout, can't lock $file \n";
205 0         0 return 0;
206             }
207             }
208 39 50       92 print STDERR "lock-> $file\n" if $Debug;
209 39         163 1;
210             }
211              
212             sub unlock {
213 38     38 0 76 my($self) = @_;
214 38 100       114 return 1 unless $self->{LOCKING};
215 36         66 my $FH = $self->{'_LOCKFH'};
216 36         232 flock($FH, LOCK_UN);
217 36         328 CORE::close($FH);
218 36         1774 unlink $self->{'_LOCKFILE'};
219 36 50       97 print STDERR "unlock-> $self->{'_LOCKFILE'}\n" if $Debug;
220 36         478 1;
221             }
222              
223             #hmm, this doesn't seem right
224             sub tmpdir {
225 0     0 0 0 my($self) = @_;
226 0 0       0 return $self->{TMPDIR} if defined $self->{TMPDIR};
227 0         0 my $dir;
228 0         0 foreach ( qw(/tmp /usr/tmp /var/tmp) ) {
229 0 0       0 last if -d ($dir = $_);
230             }
231 0         0 $self->{TMPDIR} = $dir;
232             }
233              
234 13     13   659 sub import {}
235 0     0   0 sub DESTROY { warn "in AdminBase::DESTROY" }
236 0 0   0 0 0 sub class { ref $_[0] || $_[0] }
237 57     57 0 173 sub readonly { shift->flags == Fcntl::O_RDONLY() }
238 43     43 0 196 sub debug { shift->_elem('DEBUG', @_) }
239 0     0 0 0 sub path { shift->_elem('PATH', @_) }
240 0     0 0 0 sub locking { shift->_elem('LOCKING', @_) }
241             sub flags {
242 57     57 0 77 my($self, $mode) = @_;
243 57         58 my $flags;
244 57   50     238 my $key = $self->{DBMF} || "DEFAULT";
245 57   33     194 $mode ||= $self->{FLAGS};
246 57         80 $self->{FLAGS} = $mode;
247 57 50       195 $key = "DEFAULT" unless defined $DBMFlags{$key};
248 57 50       149 if(defined $DBMFlags{$key}->{$mode}) {
249 57         71 $flags = &{$DBMFlags{$key}->{$mode}};
  57         163  
250             }
251 57         255 return $flags;
252             }
253             #fallback, only implemented with DBType => Text
254 0     0 0   sub commit { (1,''); }
255              
256             sub baseclass {
257 0     0 0   my($self, $n) = @_;
258 0   0       my $class = join '::', (split(/::/, (ref $self || $self)))[0 .. $n - 1];
259 0           print STDERR "baseclass got '$class' from '$self'\n";
260 0           $class;
261             }
262              
263             1;
264