File Coverage

blib/lib/HTML/WebMake/SiteCache.pm
Criterion Covered Total %
statement 22 116 18.9
branch 0 32 0.0
condition 0 12 0.0
subroutine 8 20 40.0
pod 0 12 0.0
total 30 192 15.6


line stmt bran cond sub pod time code
1             #
2              
3             package HTML::WebMake::SiteCache;
4              
5             ###########################################################################
6              
7              
8 1     1   4 use Carp;
  1         3  
  1         64  
9              
10 1     1   34 BEGIN { @AnyDBM_File::ISA = qw(DB_File GDBM_File NDBM_File SDBM_File); }
11 1     1   793 use AnyDBM_File;
  1         3554  
  1         58  
12              
13 1     1   8 use Fcntl;
  1         2  
  1         318  
14 1     1   7 use File::Spec;
  1         2  
  1         40  
15 1     1   5 use strict;
  1         2  
  1         27  
16              
17 1     1   4 use HTML::WebMake::Main;
  1         2  
  1         39  
18              
19 1         5513 use vars qw{
20             @ISA $DB_MODULE $UNDEF_SYMBOL
21 1     1   8 };
  1         2  
22              
23             @ISA = qw();
24              
25             $DB_MODULE = undef;
26              
27             $UNDEF_SYMBOL = '!!UnDeF';
28              
29             ###########################################################################
30              
31             sub new ($$$) {
32 0     0 0   my $class = shift;
33 0   0       $class = ref($class) || $class;
34 0           my ($main, $fname) = @_;
35              
36 0 0         die ("no cache filename") unless defined($fname);
37              
38 0           my $self = {
39             'main' => $main,
40             'filename' => $fname,
41              
42             'front_metadata_cache' => { }
43             };
44              
45 0           bless ($self, $class);
46              
47 0           $self;
48             }
49              
50 0     0 0   sub dbg { HTML::WebMake::Main::dbg (@_); }
51              
52             # -------------------------------------------------------------------------
53              
54             sub tie {
55 0     0 0   my ($self) = @_;
56              
57 0           my $try = 0;
58 0           my %db;
59 0           for ($try = 0; $try < 4; $try++)
60             {
61 0 0         my $dbobj = tie (%db, 'AnyDBM_File', $self->{filename},
62             O_CREAT|O_RDWR, 0600)
63             or die "Cannot open/create site cache: $self->{filename}\n";
64              
65 0 0         if ($AnyDBM_File::ISA[0] ne 'DB_File') {
66 0           dbg ("cannot do db ownership security check on this platform");
67 0           goto all_ok;
68             }
69              
70             # check the open db file for ownership, to make sure it really
71             # is owned by us and we're not the victim of a race exploit.
72 0           my $fd = $dbobj->fd(); undef $dbobj;
  0            
73             # dbg ("checking ownership of site cache: $self->{filename} fd=$fd");
74 0 0         open (DB_FH, "+<&=$fd") || die "dup $!";
75 0 0         if (-o DB_FH) { goto all_ok; }
  0            
76              
77 0           warn "Site cache file is not owned by us. Deleting and retrying.\n";
78 0           system ("ls -l '".$self->{filename}."' 1>&2");
79 0           untie ($self->{db});
80 0           unlink ($self->{filename});
81             }
82              
83 0           die "Site cache file is not owned by us. Giving up.\n";
84              
85 0           all_ok:
86             # all's well, no funny tricks are underway
87             dbg ("opened site cache: $self->{filename}");
88 0           $self->{db} = \%db;
89 0           return;
90             }
91              
92             # -------------------------------------------------------------------------
93              
94             sub untie {
95 0     0 0   my ($self) = @_;
96              
97 0 0         untie ($self->{db}) or die "untie failed";
98 0           dbg ("closed site cache: $self->{filename}");
99             }
100              
101             # -------------------------------------------------------------------------
102              
103             sub get_modtime {
104 0     0 0   my ($self, $file) = @_;
105 0           return $self->{db}{'m#'.$file};
106             }
107              
108             sub set_modtime {
109 0     0 0   my ($self, $fname, $mod) = @_;
110 0           $self->{db}{'m#'.$fname} = $mod;
111             }
112              
113             # -------------------------------------------------------------------------
114              
115             sub set_content_deps {
116 0     0 0   my ($self, $file, %deps) = @_;
117 0           my ($fname, $mod);
118              
119 0           my $depstr = '';
120 0           while (($fname, $mod) = each %deps) {
121 0           $self->{db}{'m#'.$fname} = $mod;
122 0           $depstr .= "\0".$fname;
123             }
124 0           $self->{db}{'d#'.$file} = $depstr;
125             }
126              
127             sub get_content_deps {
128 0     0 0   my ($self, $file) = @_;
129 0           my $str = $self->{db}{'d#'.$file};
130              
131 0 0         if (defined $str) {
132 0           return split (/\0/, $self->{db}{'d#'.$file});
133             } else {
134 0           return (); # an empty list
135             }
136             }
137              
138             # -------------------------------------------------------------------------
139              
140             sub get_metadata {
141 0     0 0   my ($self, $key) = @_;
142 0           my $val = $self->{db}{'M#'.$key};
143              
144             # we use an additional, in-memory cache to avoid writing metadata
145             # that matches what was already there
146 0           $self->{front_metadata_cache}->{$key} = $val;
147              
148 0 0 0       if (defined $val && $val eq $UNDEF_SYMBOL) { return undef; }
  0            
149 0           return $val;
150             }
151              
152             sub put_metadata {
153 0     0 0   my ($self, $key, $val) = @_;
154 0 0         if (!defined $key) { return; }
  0            
155 0 0         if (!defined $val) { $val = $UNDEF_SYMBOL; }
  0            
156              
157             # we use an additional, in-memory cache to avoid writing metadata
158             # that matches what was already there
159 0           my $front = $self->{front_metadata_cache}->{$key};
160 0 0 0       if (defined $front && $front eq $val) { return; }
  0            
161              
162 0           dbg ("caching metadata '$key' = '$val'");
163 0           $self->{db}{'M#'.$key} = $val;
164             }
165              
166             # -------------------------------------------------------------------------
167              
168             sub get_format_conversion {
169 0     0 0   my ($self, $contobj, $fmts, $pretext) = @_;
170              
171 0           my $cachename = $self->{db}{'F#'.$fmts.'#'.$contobj->{name}};
172 0 0         if (!defined $cachename) { return; }
  0            
173              
174 0           my $thenmtime = $self->{main}->cached_get_modtime ($cachename);
175 0 0         if (!defined $thenmtime) { return; }
  0            
176              
177 0           my $nowmtime = $contobj->get_modtime ();
178              
179 0 0 0       if ($thenmtime < $nowmtime || !open (IN, "<$cachename")) {
180 0           return;
181             }
182              
183 0           dbg ("using cached format conversion for ".$contobj->as_string());
184 0           my $txt = join ('', );
185 0           close IN;
186 0           return $txt;
187             }
188              
189             sub store_format_conversion {
190 0     0 0   my ($self, $contobj, $fmts, $posttext) = @_;
191              
192             # convert the content object's name and formats to a checksum
193             # value, to avoid filename clashes whereever possible.
194 0           my $fname = $fmts.'#'.$contobj->{name};
195 0           $fname = $contobj->{name}.'.'.unpack("%32C*", $fname);
196 0           $fname =~ s/[^A-Za-z0-9]/_/g;
197              
198 0           my $cachename = File::Spec->catfile ($self->{main}->cachedir(), $fname);
199              
200 0 0         if (!open (OUT, ">$cachename")) { goto giveup; }
  0            
201 0           print OUT $posttext;
202 0 0         if (!close OUT) { goto giveup; }
  0            
203              
204 0           $self->{db}{'F#'.$fmts.'#'.$contobj->{name}} = $cachename;
205 0           dbg ("cached format conversion for ".$contobj->as_string().": $cachename");
206 0           return;
207              
208 0           giveup:
209             warn "cannot write to $cachename\n";
210 0           unlink ($cachename);
211 0           return;
212             }
213              
214             # -------------------------------------------------------------------------
215              
216             1;