File Coverage

blib/lib/File/Cache.pm
Criterion Covered Total %
statement 520 584 89.0
branch 196 342 57.3
condition 37 72 51.3
subroutine 80 83 96.3
pod 30 32 93.7
total 863 1113 77.5


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2              
3             package File::Cache;
4              
5 3     3   3000 use strict;
  3         3  
  3         102  
6 3     3   12 use Carp;
  3         6  
  3         336  
7 3     3   18 use Digest::MD5 qw(md5_hex);
  3         15  
  3         180  
8 3     3   15 use File::Path;
  3         6  
  3         183  
9 3     3   36 use File::Find;
  3         6  
  3         216  
10 3     3   21 use File::Spec;
  3         6  
  3         99  
11 3     3   2841 use File::Spec::Functions qw(tmpdir splitdir splitpath catdir);
  3         3009  
  3         219  
12 3     3   18 use Exporter;
  3         6  
  3         153  
13              
14 3         25779 use vars qw(@ISA @EXPORT_OK $VERSION $sSUCCESS $sFAILURE $sTRUE $sFALSE
15             $sEXPIRES_NOW $sEXPIRES_NEVER $sNO_MAX_SIZE $sGET_STALE_ONLY
16 3     3   15 $sGET_FRESH_ONLY $CACHE_OBJECT_VERSION);
  3         3  
17              
18             $VERSION = '0.16';
19              
20             # Describes the caches created by this version of File::Cache. (Should
21             # be incremented any time the cache file format changes in a way that
22             # breaks backward compatibility.)
23              
24             $CACHE_OBJECT_VERSION = '0.01';
25              
26             @ISA = qw(Exporter);
27              
28             @EXPORT_OK = qw($sSUCCESS $sFAILURE $sTRUE $sFALSE $sEXPIRES_NOW
29             $sEXPIRES_NEVER $sNO_MAX_SIZE );
30              
31             # -----------------------------------------------------------------------------
32              
33             # Code notes:
34             # Internal subroutines (helper routines not supposed to be called by
35             # external clients) are preceded with an underscore ("_"). Subroutines
36             # (both internal and external) that are called as functions, as
37             # opposed to methods, are in ALL CAPS. The PURGE and CLEAR routines
38             # are object-independent, which means that any subroutines they call
39             # must also be object-independent.
40              
41             # -----------------------------------------------------------------------------
42              
43             # Constants
44              
45             $sSUCCESS = 1;
46             $sFAILURE = 0;
47              
48             $sTRUE = 1;
49             $sFALSE = 0;
50              
51             $sEXPIRES_NOW = 0;
52             $sEXPIRES_NEVER = -1;
53              
54             $sNO_MAX_SIZE = -1;
55              
56             $sGET_STALE_ONLY = 1;
57             $sGET_FRESH_ONLY = 0;
58              
59             # The default cache key is used inside the tmp filesystem (as defined
60             # by File::Spec)
61              
62             my $sDEFAULT_CACHE_KEY;
63              
64             $sDEFAULT_CACHE_KEY = ($^O eq 'dos' || $^O eq 'MSWin32') ?
65             'FileCache' : 'File::Cache';
66              
67              
68             # if a namespace is not specified, use this as a default
69              
70             my $sDEFAULT_NAMESPACE = "_default";
71              
72              
73             # by default, remove objects that have expired when then are requested
74              
75             my $sDEFAULT_AUTO_REMOVE_STALE = $sTRUE;
76              
77              
78             # by default, the filemode is world read/writable
79              
80             my $sDEFAULT_FILEMODE = 0777;
81              
82              
83             # by default, there is no max size to the cache
84              
85             my $sDEFAULT_MAX_SIZE = $sNO_MAX_SIZE;
86              
87              
88             # if the OS does not support getpwuid, use this as a default username
89              
90             my $sDEFAULT_USERNAME = 'nobody';
91              
92              
93             # by default, the objects in the cache never expire
94              
95             my $sDEFAULT_GLOBAL_EXPIRES_IN = $sEXPIRES_NEVER;
96              
97              
98             # default cache depth
99              
100             my $sDEFAULT_CACHE_DEPTH = 0;
101              
102              
103             # File::Cache supports either Storable or Data::Dumper as the
104             # persistence mechanism. The default persistence mechanism uses Storable
105              
106             my $sDEFAULT_PERSISTENCE_MECHANISM = 'Storable';
107              
108              
109              
110             # cache description filename
111              
112             my $sCACHE_DESCRIPTION_FILENAME = '.description';
113              
114              
115             # Always use a global friendly umask for the .description files
116              
117             my $sCACHE_DESCRIPTION_UMASK = 022;
118              
119              
120             # valid filepath characters for tainting. Be sure to accept DOS/Windows style
121             # path specifiers (C:\path) also
122              
123             my $sUNTAINTED_FILE_PATH_REGEX = qr{^([-\@\w\\\\~./:]+|[\w]:[-\@\w\\\\~./]+)$};
124              
125              
126              
127             # -----------------------------------------------------------------------------
128              
129             # create a new Cache object that can be used to persist
130             # data across processes
131              
132             sub new
133             {
134 13     13 1 8840516 my ($proto, $options) = @_;
135 13   33     228 my $class = ref($proto) || $proto;
136 13         26 my $self = {};
137 13         105 bless ($self, $class);
138              
139              
140             # remove objects from the cache that have expired on retrieval
141             # when this is set
142              
143 13 100       77 my $auto_remove_stale = defined $options->{auto_remove_stale} ?
144             $options->{auto_remove_stale} : $sDEFAULT_AUTO_REMOVE_STALE;
145              
146 13         140 $self->set_auto_remove_stale($auto_remove_stale);
147              
148              
149             # username is either specified or searched for in an OS
150             # independent way
151              
152 13 100       63 my $username = defined $options->{username} ?
153             $options->{username} : _FIND_USERNAME();
154              
155 13         74 $self->set_username($username);
156              
157              
158             # the user can specify the filemode
159              
160 13 100       76 my $filemode = defined $options->{filemode} ?
161             $options->{filemode} : $sDEFAULT_FILEMODE;
162              
163 13         142 $self->set_filemode($filemode);
164              
165              
166             # remember the expiration delta to be used for all objects if
167             # specified
168              
169 13 50       35 my $global_expires_in = defined $options->{expires_in} ?
170             $options->{expires_in} : $sDEFAULT_GLOBAL_EXPIRES_IN;
171              
172 13         76 $self->set_global_expires_in($global_expires_in);
173              
174              
175             # set the cache key to either the user's value or the default
176              
177 13 50       42 my $cache_key = defined $options->{cache_key} ?
178             $options->{cache_key} : _BUILD_DEFAULT_CACHE_KEY();
179              
180 13         47 $self->set_cache_key($cache_key);
181              
182              
183             # this instance will use the namespace specified or the default
184              
185 13 50       56 my $namespace = defined $options->{namespace} ?
186             $options->{namespace} : $sDEFAULT_NAMESPACE;
187              
188 13         49 $self->set_namespace($namespace);
189              
190              
191             # the cache will automatically create subdirectories to this depth
192              
193 13 100       91 my $cache_depth = defined $options->{cache_depth} ?
194             $options->{cache_depth} : $sDEFAULT_CACHE_DEPTH;
195              
196 13         58 $self->set_cache_depth($cache_depth);
197              
198              
199             # the max cache size is either specified by the user or by the
200             # default cache size. Be sure to do this after the cache key,
201             # user, and namespace are set up, because it invokes reduce_size.
202              
203 13 100       53 my $max_size = defined $options->{max_size} ?
204             $options->{max_size} : $sDEFAULT_MAX_SIZE;
205              
206 13         48 $self->set_max_size($max_size);
207              
208              
209             # verify that we can create the cache when necessary later
210              
211 13 50       54 _VERIFY_DIRECTORY( $self->_get_namespace_path() ) == $sSUCCESS or
212             croak("Can not build cache at " . $self->_get_namespace_path() .
213             ". Check directory permissions.");
214              
215             # set the persistence mechanism to the user specified one (or the
216             # default), then load the necessary modules that correspond to
217             # that persistence mechanism choice
218              
219 13 50       72 my $persistence_mechanism = defined $options->{persistence_mechanism} ?
220             $options->{persistence_mechanism} : $sDEFAULT_PERSISTENCE_MECHANISM;
221              
222 13         93 $self->set_persistence_mechanism($persistence_mechanism);
223 13         72 $self->_load_persistence_mechanism();
224              
225              
226             # could update a legacy cache here
227              
228              
229             # check that any existing cache is compatible
230              
231 13         94 $self->_check_cache_compatibility();
232              
233              
234             # write the cache description, in case there isn't already one
235              
236 13         61 my $cache_description = $self->_get_cache_description();
237              
238 13         87 _WRITE_CACHE_DESCRIPTION( $cache_key, $cache_description, $filemode );
239              
240              
241 13         143 return $self;
242             }
243              
244             # -----------------------------------------------------------------------------
245              
246             # Reads the cache description from the file system. Returns a reference to a
247             # hash, or undef if no cache appears to be in location specified by the cache
248             # key, or the cache has problems. A cache description is automatically
249             # generated for older style caches that do not have cache description files.
250             # (The presence of any directories in the cache key directory are taken to
251             # mean that such a legacy cache exists.)
252              
253             sub _READ_CACHE_DESCRIPTION
254             {
255 326     326   658 my ($cache_key) = @_;
256              
257 326 50       10249 defined($cache_key) or
258             croak("cache key required");
259              
260 326         602 my $cache_description_path =
261             _BUILD_PATH($cache_key, $sCACHE_DESCRIPTION_FILENAME);
262              
263             # This is the name of the variable stored using Data::Dumper in
264             # the cache description file.
265              
266 326         629 my $cache_description = {};
267              
268 326 100       6659 if (-f $cache_description_path) {
    50          
269              
270 315         662 my $serialized_cache_description_ref =
271             _READ_FILE($cache_description_path);
272              
273 315 50 33     1897 unless (defined $serialized_cache_description_ref and
274             defined $$serialized_cache_description_ref)
275             {
276              
277 0         0 warn "Could not read cache description file $cache_description_path";
278 0         0 return undef;
279              
280             }
281              
282 315         783 _UNSERIALIZE_HASH($$serialized_cache_description_ref,
283             $cache_description);
284              
285             } elsif (_SUBDIRECTORIES_PRESENT($cache_key) eq $sTRUE) {
286              
287             # Older caches used Storable as the persistence mechanism
288 0         0 $cache_description =
289             {
290             'File::Cache Version' => undef,
291             'Cache Object Version' => 0.01,
292             'Persistence Mechanism' => 'Storable',
293             };
294              
295             } else {
296              
297 11         43 return undef;
298              
299             }
300              
301 315         725 return $cache_description;
302             }
303              
304             # -----------------------------------------------------------------------------
305              
306             # Determines if there are subdirectories in a given directory
307              
308             sub _SUBDIRECTORIES_PRESENT
309             {
310 11     11   28 my ($directory) = @_;
311              
312 11 50       36 defined($directory) or
313             croak("directory required");
314              
315 11         28 $directory = _UNTAINT_FILE_PATH($directory);
316              
317 11 50       239 return $sFALSE unless -d $directory;
318              
319 0 0       0 opendir(DIR, $directory) or
320             croak("Couldn't open directory $directory: $!");
321              
322 0         0 my @dirents = readdir(DIR);
323              
324 0         0 closedir DIR;
325              
326 0         0 foreach my $dirent (@dirents)
327             {
328 0 0       0 return $sTRUE if -d $dirent;
329             }
330              
331 0         0 return $sFALSE;
332             }
333              
334             # -----------------------------------------------------------------------------
335              
336             # Writes a cache description to the file system. Takes a cache key, a
337             # reference to a hash, and a file mode
338              
339             sub _WRITE_CACHE_DESCRIPTION
340             {
341 13     13   42 my ($cache_key, $cache_description, $filemode) = @_;
342              
343 13 50       44 defined($cache_key) or
344             croak("cache_key required");
345              
346 13 50       45 defined($cache_description) or
347             croak("cache description required");
348              
349 13 50       41 defined($filemode) or
350             croak("filemode required");
351              
352 13         29 my $cache_description_path =
353             _BUILD_PATH($cache_key, $sCACHE_DESCRIPTION_FILENAME);
354              
355 13         61 my $serialized_cache_description = _SERIALIZE_HASH($cache_description);
356              
357 13         209 _CREATE_DIRECTORY($cache_key,0);
358              
359             # mike@blakeley.com: specifying the filemode is bad for .description,
360             # since it's global for the whole cache.
361              
362 13         95 _WRITE_FILE($cache_description_path,
363             \$serialized_cache_description,
364             $filemode,
365             $sCACHE_DESCRIPTION_UMASK);
366              
367              
368             }
369              
370              
371             sub _SERIALIZE_HASH
372             {
373 13     13   28 my ($hash_ref) = @_;
374              
375 13         23 my $serialized_hash;
376              
377 13         23 foreach my $key (keys %{$hash_ref}) {
  13         81  
378              
379 39         129 $serialized_hash .= "$key => $hash_ref->{$key}\n";
380              
381             }
382              
383 13         36 return $serialized_hash;
384             }
385              
386              
387             sub _UNSERIALIZE_HASH
388             {
389 315     315   484 my ($string, $hash_ref) = @_;
390              
391 315         1366 my @key_value_pair_list = split(/\n/, $string);
392              
393 315         2377 foreach my $key_value_pair (@key_value_pair_list) {
394              
395 945         4961 my ($key, $value) = $key_value_pair =~ m|(.*?) => (.*)|;
396              
397 945 50 33     5021 next unless $key and $value;
398              
399 945         4921 $hash_ref->{$key} = $value;
400              
401             }
402             }
403              
404             # -----------------------------------------------------------------------------
405              
406             # Check that any existing cache is compatible. For example, a cache
407             # created using a later version of File::Cache with a new cached
408             # object format is incompatible.
409              
410             sub _check_cache_compatibility
411             {
412 13     13   27 my ($self) = @_;
413              
414 13         42 my $existing_cache_description =
415             _READ_CACHE_DESCRIPTION( $self->get_cache_key() );
416              
417             # Not defined means that there is no existing cache, or there is a problem
418             # with the cache.
419 13 100       49 return unless defined $existing_cache_description;
420              
421             # Compare cache object versions.
422 2 50       13258669 if ( ($existing_cache_description->{'Cache Object Version'} >
423             $CACHE_OBJECT_VERSION) )
424             {
425 0         0 warn "Incompatible cache object versions detected. " .
426             "The cache will be cleared";
427 0         0 CLEAR( $self->get_cache_key() );
428 0         0 return;
429             }
430              
431             # Check that the persistence mechanisms match.
432 2 50       43 if ( $existing_cache_description->{'Persistence Mechanism'} ne
433             $self->get_persistence_mechanism() )
434             {
435 0         0 warn "Incompatible cache object persistence mechanisms detected. " .
436             "The cache will be cleared";
437 0         0 CLEAR( $self->get_cache_key() );
438 0         0 return;
439             }
440             }
441              
442             # -----------------------------------------------------------------------------
443              
444             # Gets the cache description for the cache, returning a reference to a
445             # hash. The keys are:
446             # - File::Cache Version: The version of File::Cache used to create the
447             # cache. (May be undef for cache descriptions that are auto-generated
448             # by _READ_CACHE_DESCRIPTION based on a legacy cache.)
449             # - Cache Object Version: The version number of the format used to store
450             # objects in the cache.
451             # - Persistence Mechanism: The persistence mechanism used to store
452             # objects in the cache.
453              
454             sub _get_cache_description
455             {
456 13     13   30 my ($self) = @_;
457              
458 13         48 my $cache_description =
459             {
460             'File::Cache Version' => $VERSION,
461             'Cache Object Version' => $CACHE_OBJECT_VERSION,
462             'Persistence Mechanism' => $self->get_persistence_mechanism(),
463             };
464              
465 13         32 return $cache_description;
466             }
467              
468             # -----------------------------------------------------------------------------
469              
470             # store an object in the cache associated with the identifier
471              
472             sub set
473             {
474 73     73 1 3266 my ($self, $identifier, $object, $expires_in) = @_;
475              
476 73 50       306 defined($identifier) or
477             croak("identifier required");
478              
479 73         548 my $unique_key = _BUILD_UNIQUE_KEY($identifier);
480              
481             # expiration time is based on a delta from the current time if
482             # expires_in is defined, the object will expire in that number of
483             # seconds from now else if expires_in is undefined, it will expire
484             # based on the global_expires_in
485              
486 73         345 my $global_expires_in = $self->get_global_expires_in();
487              
488 73         85 my $expires_at;
489              
490 73         129 my $created_at = time();
491              
492 73 100       294 if (defined $expires_in) {
    50          
493 9 50       40 $expires_at = ($expires_in eq $sEXPIRES_NEVER) ?
494             $expires_in : ($created_at + $expires_in);
495             } elsif ($global_expires_in ne $sEXPIRES_NEVER) {
496 0         0 $expires_at = $created_at + $global_expires_in;
497             } else {
498 64         144 $expires_at = $sEXPIRES_NEVER;
499             }
500              
501              
502             # add the new object to the cache in this instance's namespace
503              
504 73         538 my %object_data = ( object => $object, expires_at => $expires_at,
505             created_at => $created_at );
506              
507 73         354 my $frozen_object_data =
508             _SERIALIZE( \%object_data, $self->get_persistence_mechanism() );
509              
510             # Figure out what the new size of the cache should be in order to
511             # accomodate the new data and still be below the max_size. Then
512             # reduce the size.
513              
514 73         6401 my $max_size = $self->get_max_size();
515              
516 73 100       213 if ($max_size != $sNO_MAX_SIZE) {
517 70         168 my $new_size = $max_size - length $frozen_object_data;
518 70 50       263 $new_size = 0 if $new_size < 0;
519 70         252 $self->reduce_size($new_size);
520             }
521              
522 73         420 my $filemode = $self->get_filemode();
523              
524 73         630 my $cached_file_path = $self->_build_cached_file_path($unique_key);
525              
526 73         2475 _WRITE_FILE($cached_file_path, \$frozen_object_data, $filemode);
527              
528 73         552 return $sSUCCESS;
529             }
530              
531             # -----------------------------------------------------------------------------
532              
533             # loads the module for serializing data
534              
535             sub _load_persistence_mechanism
536             {
537 13     13   20 my ($self) = @_;
538              
539 13 50       45 if ($self->get_persistence_mechanism() eq 'Storable')
    0          
540             {
541 13         3417 require Storable;
542 13         13227 Storable->import( qw(nfreeze thaw dclone));
543             }
544             # Should be already loaded. No harm done in doing it again
545             elsif ($self->get_persistence_mechanism() eq 'Data::Dumper')
546             {
547 0         0 require Data::Dumper;
548 0         0 Data::Dumper->import();
549             }
550             # An invalid persistence mechanism choice by the user has already been
551             # checked. If we see an invalid choice here it must be a bug in
552             # the module. (die in this case instead of croaking)
553             else
554             {
555 0         0 croak("Argument must be either \"Storable\" or \"Data::Dumper\"");
556             }
557             }
558              
559             # ------------------------------------------------------------------------------
560              
561             # turns a hash reference into a serialized string using a method which
562             # depends on the persistence mechanism choice
563              
564             sub _SERIALIZE
565             {
566 73     73   170 my ($data_reference, $persistence_mechanism) = @_;
567              
568 73 50       177 defined($data_reference) or
569             croak("object reference required");
570              
571 73 50       224 defined($persistence_mechanism) or
572             croak("persistence mechanism required");
573              
574 73 50       184 if ($persistence_mechanism eq 'Storable')
575             {
576 73         359 return nfreeze($data_reference);
577             }
578             else
579             {
580 0         0 return Data::Dumper->Dump([$data_reference], ['cache_object']);
581             }
582             }
583              
584             # ------------------------------------------------------------------------------
585              
586             # turns a reference to a serialized string into a reference to data using
587             # a method which depends on the persistence mechanism choice. Deletes the
588             # cache key if the unserialization fails.
589              
590             sub _UNSERIALIZE
591             {
592 313     313   501 my ($data_reference, $persistence_mechanism, $cache_key) = @_;
593              
594 313 50       624 defined($data_reference) or
595             croak("object reference required");
596              
597 313 50       560 defined($persistence_mechanism) or
598             croak("persistence mechanism required");
599              
600 313 50       683 if ($persistence_mechanism eq 'Storable')
601             {
602 313         1145 return thaw($$data_reference);
603             }
604             else
605             {
606             # This is what the serialize routine calls the cached object
607 0         0 my $cache_object;
608              
609             my $errors;
610             {
611 0     0   0 local $SIG{__WARN__} = sub { $errors .= $_[0] };
  0         0  
  0         0  
612              
613 0         0 eval $$data_reference;
614             }
615              
616 0 0 0     0 if ($errors || $@)
617             {
618 0         0 warn "Cache object is corrupted and will be deleted";
619 0         0 unlink $cache_key;
620 0         0 return undef;
621             }
622              
623 0         0 return $cache_object;
624             }
625             }
626              
627             # ------------------------------------------------------------------------------
628              
629             # return a copy of a serialized string (reference or non-reference)
630             # using a method which depends on the persistence mechanism choice
631              
632             sub _CLONE
633             {
634 28     28   51 my ($data_reference, $persistence_mechanism) = @_;
635              
636 28 50       53 defined($data_reference) or
637             croak("object reference required");
638              
639 28 50       59 defined($persistence_mechanism) or
640             croak("persistence mechanism required");
641              
642 28         97 my $cloned_data;
643              
644 28 50       91 if ($persistence_mechanism eq 'Storable')
645             {
646 28 100       406 $cloned_data =
647             (ref $data_reference) ? dclone($data_reference) : $data_reference;
648             }
649             else
650             {
651 0 0       0 if (ref $data_reference)
652             {
653 0         0 my $data = $$data_reference;
654 0         0 $cloned_data = \$data;
655             }
656             else
657             {
658 0         0 $cloned_data = $data_reference;
659             }
660             }
661              
662 28         88 return $cloned_data;
663             }
664              
665             # ------------------------------------------------------------------------------
666              
667             # retrieve an object from the cache associated with the identifier,
668             # and remove it from the cache if its expiration has elapsed and
669             # auto_remove_stale is 1.
670              
671             sub get
672             {
673 38     38 1 9001752 my ($self, $identifier) = @_;
674              
675 38 50       142 defined($identifier) or
676             croak("identifier required");
677              
678 38         167 my $object = $self->_get($identifier, $sGET_FRESH_ONLY);
679              
680 38         336 return $object;
681             }
682              
683             # ------------------------------------------------------------------------------
684              
685             # retrieve an object from the cache associated with the identifier,
686             # but only if it's stale
687              
688             sub get_stale
689             {
690 3     3 1 125 my ($self, $identifier) = @_;
691              
692 3 50       14 defined($identifier) or
693             croak("identifier required");
694              
695 3         10 my $object = $self->_get($identifier, $sGET_STALE_ONLY);
696              
697 3         10 return $object;
698             }
699              
700             # ------------------------------------------------------------------------------
701              
702             # Gets the stale or non-stale data from the cache, depending on the
703             # second parameter ($sGET_STALE_ONLY or $sGET_FRESH_ONLY)
704              
705             sub _get
706             {
707 41     41   81 my ($self, $identifier, $freshness) = @_;
708              
709 41 50       287 defined($identifier) or
710             croak("identifier required");
711              
712 41 50       94 defined($freshness) or
713             croak("freshness required");
714              
715 41         110 my $unique_key = _BUILD_UNIQUE_KEY($identifier);
716              
717 41         563 my $cached_file_path = $self->_get_cached_file_path($unique_key);
718              
719             # check the cache for the specified object
720              
721 41         86 my $cloned_object = undef;
722              
723 41         48 my $object_data;
724              
725 41         119 $object_data =
726             _READ_OBJECT_DATA($cached_file_path);
727              
728 41 100       132 if ($object_data) {
729              
730 34         63 my $object = $object_data->{object};
731              
732 34         53 my $expires_at = $object_data->{expires_at};
733            
734             # If we want non-stale data...
735              
736 34 100       85 if ($freshness eq $sGET_FRESH_ONLY) {
737              
738             # Check if the cache item has expired
739              
740 31 100       98 if (_S_SHOULD_EXPIRE($expires_at)) {
741              
742             # Remove the item from the cache if auto_remove_stale
743             # is $sTRUE
744              
745 6         34 my $auto_remove_stale = $self->get_auto_remove_stale();
746            
747 6 50       24 if ($auto_remove_stale eq $sTRUE) {
748 0 0       0 _REMOVE_CACHED_FILE($cached_file_path) or
749             croak("Couldn't remove cached file $cached_file_path");
750             }
751              
752             # otherwise fetch the object and return a copy
753              
754             } else {
755 25         108 $cloned_object =
756             _CLONE( $object, $self->get_persistence_mechanism() );
757             }
758              
759             # If we want stale data...
760              
761             } else {
762            
763             # and the cache item is indeed stale...
764              
765 3 50       8 if (_S_SHOULD_EXPIRE($expires_at)) {
766            
767             # fetch the object and return a copy
768 3         14 $cloned_object =
769             _CLONE( $object, $self->get_persistence_mechanism() );
770              
771             }
772             }
773             }
774              
775 41         211 return $cloned_object;
776             }
777              
778             # ------------------------------------------------------------------------------
779              
780             # removes a key and value from the cache, it always succeeds, even if
781             # the key or value doesn't exist
782              
783             sub remove
784             {
785 3     3 1 25 my ($self, $identifier) = @_;
786              
787 3 50       27 defined($identifier) or
788             croak("identifier required");
789              
790 3         8 my $unique_key = _BUILD_UNIQUE_KEY($identifier);
791              
792 3         11 my $cached_file_path = $self->_get_cached_file_path($unique_key);
793              
794 3 50       17 _REMOVE_CACHED_FILE($cached_file_path) or
795             croak("couldn't remove cached file $cached_file_path");
796              
797 3         13 return $sSUCCESS;
798             }
799              
800             # ------------------------------------------------------------------------------
801              
802             # take an human readable identifier, and create a unique key from it
803              
804             sub _BUILD_UNIQUE_KEY
805             {
806 126     126   447 my ($identifier) = @_;
807              
808 126 50       368 defined($identifier) or
809             croak("identifier required");
810              
811 126 50       1076 my $unique_key = md5_hex($identifier) or
812             croak("couldn't build unique key for identifier $identifier");
813              
814 126         473 return $unique_key;
815             }
816              
817             # ------------------------------------------------------------------------------
818              
819             # Check to see if a directory exists and is writable, or if a prefix
820             # directory exists and we can write to it in order to create
821             # subdirectories. _VERIFY_DIRECTORY( $self->_get_namespace_path() )
822             # == $sSUCCESS should be checked every time the cache key, username,
823             # or namespace is changed.
824              
825             sub _VERIFY_DIRECTORY
826             {
827 13     13   54 my ($directory) = @_;
828              
829 13 50       34 defined($directory) or
830             croak("directory required");
831              
832             # If the directory doesn't exist, crawl upwards until we find a file or
833             # directory that exists
834 13   66     435 while (defined $directory && !-e $directory)
835             {
836 33         72 $directory = _GET_PARENT_DIRECTORY($directory);
837             }
838              
839 13 50       35 return $sFAILURE unless defined $directory;
840              
841 13 50 33     509 return $sSUCCESS if -d $directory && -w $directory;
842              
843 0         0 return $sFAILURE;
844             }
845              
846             # ------------------------------------------------------------------------------
847              
848             # find the parent directory of a directory. Returns undef if there is no
849             # parent
850              
851             sub _GET_PARENT_DIRECTORY
852             {
853 1975     1975   2677 my ($directory) = @_;
854              
855 1975 50       3644 defined($directory) or
856             croak("directory required");
857              
858 1975         8380 my @directories = splitdir($directory);
859 1975         35477 pop @directories;
860              
861 1975 50       4432 return undef unless @directories;
862              
863 1975         11429 return catdir(@directories);
864             }
865              
866             # -----------------------------------------------------------------------------
867              
868             # create a directory with optional mask, building subdirectories as needed. be
869             # sure to call _VERIFY_DIRECTORY before calling this function
870              
871             sub _CREATE_DIRECTORY
872             {
873 86     86   240 my ($directory, $mask) = @_;
874              
875 86 50       198 defined($directory) or
876             croak("directory required");
877              
878 86         128 my $old_mask;
879              
880 86 50       239 if (defined $mask)
881             {
882 86         370 $old_mask = umask;
883 86         271 umask($mask);
884             }
885              
886 86         560 $directory = _UNTAINT_FILE_PATH($directory);
887              
888 86         8653716 mkpath ($directory, 0, 0777);
889              
890 86 50       2464 croak("Couldn't create directory: $directory: $!")
891             unless -d $directory;
892              
893 86 50       368 umask($old_mask) if defined $mask;
894              
895 86         223 return $sSUCCESS;
896             }
897              
898             # -----------------------------------------------------------------------------
899              
900             # read in the object frozen in the specified file (absolute path).
901             # returns a reference to the object, or undef if the object can not be
902             # found or can not be unserialized
903              
904             sub _READ_OBJECT_DATA
905             {
906 320     320   482 my ($cached_file_path) = @_;
907              
908 320 50       1370 defined($cached_file_path) or
909             croak("cached file path required");
910              
911 320         412 my $frozen_object_data = undef;
912              
913 320 100       55309 if (-f $cached_file_path) {
914 313         792 $frozen_object_data = _READ_FILE($cached_file_path);
915             } else {
916 7         38 return;
917             }
918              
919 313 50       864 if (!$frozen_object_data) {
920 0         0 return;
921             }
922              
923              
924             # Get the cache persistence mechanism. Searching upwards for the cache
925             # description file is a bit of a hack, but it's much better than
926             # passing the persistence mechanism value through the call chain.
927              
928 313         716 my $cache_key = _SEARCH_FOR_CACHE_KEY($cached_file_path);
929              
930 313 50       717 die "Couldn't find cache key directory"
931             unless defined $cache_key;
932              
933 313         641 my $cache_description = _READ_CACHE_DESCRIPTION( $cache_key );
934              
935 313 50       784 return undef unless defined $cache_description;
936              
937             # if the $frozed_object_data is corrupted, thaw will return undef
938 313         1020 my $thawed_data = _UNSERIALIZE( $frozen_object_data,
939             $cache_description->{'Persistence Mechanism'}, $cache_key );
940              
941              
942 313         7445 return $thawed_data;
943             }
944              
945             # -----------------------------------------------------------------------------
946              
947             # Look up the directory hierarchy for the cache description file,
948             # which is in the cache key directory.
949              
950             sub _SEARCH_FOR_CACHE_KEY
951             {
952 313     313   446 my ($directory) = @_;
953              
954 313 50       728 defined($directory) or
955             croak("directory required");
956              
957 313         577 my $file = _BUILD_PATH($directory,$sCACHE_DESCRIPTION_FILENAME);
958              
959             # If the cache description file isn't in the current directory,
960             # crawl upwards
961 313   66     9229 while (defined $directory && !-e $file)
962             {
963 1869         3575 $directory = _GET_PARENT_DIRECTORY($directory);
964 1869 50       5637 $file = _BUILD_PATH($directory,$sCACHE_DESCRIPTION_FILENAME)
965             if defined $directory;
966             }
967              
968 313         683 return $directory;
969             }
970              
971             # -----------------------------------------------------------------------------
972              
973             # remove an object from the cache
974              
975             sub _REMOVE_CACHED_FILE
976             {
977 18     18   33 my ($cached_file_path) = @_;
978              
979 18 50       54 defined($cached_file_path) or
980             croak("cached file path required");
981              
982              
983             # cached_file_path may be tainted
984              
985 18         67 $cached_file_path = _UNTAINT_FILE_PATH($cached_file_path);
986              
987              
988             # Is there any way to do this atomically?
989              
990 18 50       516 if (-f $cached_file_path) {
991              
992             # We don't catch the error, because this may fail if two
993             # processes are in a race and try to remove the object
994              
995 18         309351 unlink($cached_file_path);
996              
997             }
998              
999 18         161 return $sSUCCESS;
1000             }
1001              
1002             # -----------------------------------------------------------------------------
1003              
1004             # clear all objects in this instance's namespace
1005              
1006             sub clear
1007             {
1008 3     3 1 307 my ($self) = @_;
1009              
1010 3         65 my $namespace_path = $self->_get_namespace_path();
1011              
1012 3         32 $namespace_path = _UNTAINT_FILE_PATH($namespace_path);
1013              
1014 3 50       261 return $sSUCCESS unless -e $namespace_path;
1015              
1016 3 50       28 _RECURSIVELY_REMOVE_DIRECTORY($namespace_path) or
1017             croak("Couldn't clear namespace: $!");
1018              
1019 3         38 return $sSUCCESS;
1020             }
1021              
1022              
1023             # -----------------------------------------------------------------------------
1024              
1025             # iterate over all the objects in this instance's namespace and delete
1026             # those that have expired
1027              
1028             sub purge
1029             {
1030 3     3 1 177 my ($self) = @_;
1031              
1032 3         15 my $namespace_path = $self->_get_namespace_path();
1033              
1034 3         2288 finddepth(\&_PURGE_FILE_WRAPPER, $namespace_path);
1035              
1036 3         16 return $sSUCCESS;
1037             }
1038              
1039             # -----------------------------------------------------------------------------
1040              
1041             # used with the Find::Find::find routine, this calls _PURGE_FILE on
1042             # each file found
1043              
1044             sub _PURGE_FILE_WRAPPER
1045             {
1046 390     390   880 my $file_path = $File::Find::name;
1047              
1048 390         746 $file_path = _UNTAINT_FILE_PATH($file_path);
1049              
1050 390         1323 my $file = (splitpath($file_path))[2];
1051              
1052             # Don't purge the cache description file
1053 390 100 100     12244 if (-f $file && $file ne $sCACHE_DESCRIPTION_FILENAME) {
1054 90         183 _PURGE_FILE($file_path);
1055             } else {
1056 300         31675 return;
1057             }
1058             }
1059              
1060             # -----------------------------------------------------------------------------
1061              
1062             # if the file specified has expired, remove it from the cache. (path
1063             # is absolute)
1064              
1065             sub _PURGE_FILE
1066             {
1067 90     90   124 my ($cached_file_path) = @_;
1068              
1069 90 50       194 defined($cached_file_path) or
1070             croak("cached file path required");
1071              
1072 90         187 my $object_data = _READ_OBJECT_DATA($cached_file_path);
1073              
1074 90 50       230 if ($object_data) {
1075            
1076 90         182 my $expires_at = $object_data->{expires_at};
1077              
1078 90 100       424 if (_S_SHOULD_EXPIRE($expires_at)) {
1079 3 50       10 _REMOVE_CACHED_FILE($cached_file_path) or
1080             croak("Couldn't remove cached file $cached_file_path");
1081             }
1082            
1083             }
1084              
1085 90         3465 return $sSUCCESS;
1086             }
1087              
1088             # -----------------------------------------------------------------------------
1089              
1090             # determine whether an object should expire
1091              
1092             sub _S_SHOULD_EXPIRE
1093             {
1094 124     124   274 my ($expires_at, $time) = @_;
1095              
1096 124 50       274 defined($expires_at) or
1097             croak("expires_at required");
1098              
1099             # time is optional
1100              
1101 124   33     600 $time = $time || time();
1102              
1103 124 50       481 if ($expires_at == $sEXPIRES_NOW) {
    100          
    100          
1104 0         0 return $sTRUE;
1105             } elsif ($expires_at == $sEXPIRES_NEVER) {
1106 106         302 return $sFALSE;
1107             } elsif ($time >= $expires_at) {
1108 12         55 return $sTRUE;
1109             } else {
1110 6         4343 return $sFALSE;
1111             }
1112             }
1113              
1114             # -----------------------------------------------------------------------------
1115              
1116             # reduce this namespace to a given size. (the size does not count the
1117             # space occupied by the cache description file.)
1118              
1119              
1120             sub reduce_size
1121             {
1122 75     75 1 122 my ($self, $new_size) = @_;
1123              
1124 75 50       359 $new_size >= 0 or
1125             croak("size >= 0 required");
1126              
1127 75         226 my $namespace_path = $self->_get_namespace_path();
1128              
1129 75         329 while ($self->size() > $new_size) {
1130              
1131 12         52 my $victim_file = _CHOOSE_VICTIM_FILE($namespace_path);
1132              
1133 12 50       48 if (!$victim_file) {
1134 0         0 warn("Couldn't reduce size to $new_size\n");
1135 0         0 return $sFAILURE;
1136             }
1137              
1138 12 50       46 _REMOVE_CACHED_FILE($victim_file) or
1139             croak("Couldn't remove cached file $victim_file");
1140             }
1141              
1142 75         202 return $sSUCCESS;
1143             }
1144              
1145             # -----------------------------------------------------------------------------
1146              
1147             # reduce the entire cache size to a given size. (the size does not
1148             # count the space occupied by the cache description files.)
1149              
1150             sub REDUCE_SIZE
1151             {
1152 0     0 1 0 my ($new_size, $cache_key) = @_;
1153              
1154 0 0       0 $new_size >= 0 or
1155             croak("size >= 0 required");
1156              
1157 0   0     0 $cache_key = $cache_key || _BUILD_DEFAULT_CACHE_KEY();
1158              
1159 0         0 while (SIZE() > $new_size) {
1160            
1161 0         0 my $victim_file = _CHOOSE_VICTIM_FILE($cache_key);
1162            
1163 0 0       0 if (!defined($victim_file)) {
1164 0         0 warn("Couldn't reduce size to $new_size\n");
1165 0         0 return $sFAILURE;
1166             }
1167              
1168 0 0       0 _REMOVE_CACHED_FILE($victim_file) or
1169             croak("Couldn't remove cached file $victim_file");
1170             }
1171              
1172 0         0 return $sSUCCESS;
1173             }
1174              
1175             # -----------------------------------------------------------------------------
1176              
1177             # Choose a "victim" cache object to remove starting from the argument
1178             # directory. (This directory should be either the cache key path or
1179             # some subdirectory of it.) The returned file is determined in this
1180             # order: (1) the one with the closest expiration, (2) the least recently
1181             # accessed one, (3) undef if there are no cache files.
1182              
1183             sub _CHOOSE_VICTIM_FILE
1184             {
1185 12     12   23 my ($root_directory) = @_;
1186              
1187 12 50       55 defined($root_directory) or
1188             croak("root directory required");
1189              
1190             # Look for the file to delete with the nearest expiration
1191              
1192 12         40 my ($nearest_expiration_path, $nearest_expiration_time) =
1193             _RECURSIVE_FIND_NEAREST_EXPIRATION($root_directory);
1194              
1195 12 100       50 return $nearest_expiration_path if defined $nearest_expiration_path;
1196              
1197             # If there are no files with expirations, get the least recently
1198             # accessed one
1199              
1200 6         23 my ($latest_accessed_path, $latest_accessed_time) =
1201             _RECURSIVE_FIND_LATEST_ACCESSED($root_directory);
1202              
1203 6 50       35 return $latest_accessed_path if defined $latest_accessed_path;
1204              
1205 0         0 return undef;
1206             }
1207              
1208             # -----------------------------------------------------------------------------
1209              
1210             # Recursively searches a cache namespace for the cache object with the
1211             # nearest expiration. Returns undef if no cache object with an
1212             # expiration time could be found.
1213              
1214             sub _RECURSIVE_FIND_NEAREST_EXPIRATION
1215             {
1216 552     552   791 my ($directory) = @_;
1217              
1218 552 50       1039 defined($directory) or
1219             croak("directory required");
1220              
1221 552         638 my $best_nearest_expiration_path = undef;
1222              
1223 552         622 my $best_nearest_expiration_time = undef;
1224              
1225 552         868 $directory = _UNTAINT_FILE_PATH($directory);
1226              
1227 552 50       20026 opendir(DIR, $directory) or
1228             croak("Couldn't open directory $directory: $!");
1229              
1230 552         8345 my @dirents = readdir(DIR);
1231              
1232 552         1033 foreach my $dirent (@dirents) {
1233              
1234 1824 100 100     8512 next if $dirent eq '.' or $dirent eq '..';
1235              
1236 720         804 my $nearest_expiration_path_candidate = undef;
1237              
1238 720         883 my $nearest_expiration_time_candidate = undef;
1239              
1240 720         1286 my $path = _BUILD_PATH($directory, $dirent);
1241              
1242 720 100       19703 if (-d $path) {
1243              
1244 540         1093 ($nearest_expiration_path_candidate,
1245             $nearest_expiration_time_candidate) =
1246             _RECURSIVE_FIND_NEAREST_EXPIRATION($path);
1247              
1248             } else {
1249              
1250 180         208 my $object_data;
1251              
1252 180         331 $object_data = _READ_OBJECT_DATA_WITHOUT_MODIFICATION($path);
1253            
1254 180         358 my $expires_at = $object_data->{expires_at};
1255              
1256 180         505 $nearest_expiration_path_candidate = $path;
1257              
1258 180         469 $nearest_expiration_time_candidate = $expires_at;
1259              
1260             }
1261              
1262            
1263 720 100       2234 next unless defined $nearest_expiration_path_candidate;
1264              
1265 198 50       625 next unless defined $nearest_expiration_time_candidate;
1266              
1267             # Skip this file if it doesn't have an expiration time.
1268              
1269 198 100       681 next if $nearest_expiration_time_candidate == $sEXPIRES_NEVER;
1270              
1271             # if this is the first candidate, they're automatically the
1272             # best, otherwise they have to beat the best
1273              
1274 24 50 33     71 if ((!defined $best_nearest_expiration_time) or
1275             ($best_nearest_expiration_time >
1276             $nearest_expiration_time_candidate)) {
1277              
1278 24         33 $best_nearest_expiration_path =
1279             $nearest_expiration_path_candidate;
1280              
1281 24         46 $best_nearest_expiration_time =
1282             $nearest_expiration_time_candidate;
1283             }
1284              
1285             }
1286              
1287 552         17467 closedir(DIR);
1288              
1289 552         2768 return ($best_nearest_expiration_path, $best_nearest_expiration_time);
1290             }
1291              
1292             # -----------------------------------------------------------------------------
1293              
1294             # read in object data without modifying the access time. returns a
1295             # reference to the object, or undef if the object could not be read
1296              
1297             sub _READ_OBJECT_DATA_WITHOUT_MODIFICATION
1298             {
1299 180     180   445 my ($path) = @_;
1300              
1301 180 50       459 defined($path) or
1302             croak("path required");
1303              
1304 180         305 $path = _UNTAINT_FILE_PATH($path);
1305              
1306 180         5088 my ($file_access_time, $file_modified_time) = (stat($path))[8,9];
1307              
1308 180         481 my $object_data_ref = _READ_OBJECT_DATA($path);
1309            
1310 180         279994 utime($file_access_time, $file_modified_time, $path);
1311              
1312 180         441 return $object_data_ref;
1313             }
1314              
1315             # -----------------------------------------------------------------------------
1316              
1317             # Recursively searches a cache namespace for the cache object with the
1318             # latest access time. Recursively searches for the file with the
1319             # latest access time, starting at the directory supplied as an
1320             # argument. Returns the path to the last accessed file and the last
1321             # accessed time. Returns (undef,undef) if there is not at least one
1322             # file in the directory hierarchy below and including the argument
1323             # directory.
1324              
1325             sub _RECURSIVE_FIND_LATEST_ACCESSED
1326             {
1327 261     261   350 my ($directory) = @_;
1328              
1329 261 50       526 defined($directory) or
1330             croak("directory required");
1331              
1332 261         271 my $best_latest_accessed_path = undef;
1333              
1334 261         235 my $best_latest_accessed_time = undef;
1335              
1336 261         410 $directory = _UNTAINT_FILE_PATH($directory);
1337              
1338 261 50       7857 opendir(DIR, $directory) or
1339             croak("Couldn't open directory $directory: $!");
1340              
1341 261         2589 my @dirents = readdir(DIR);
1342              
1343 261         449 foreach my $dirent (@dirents) {
1344              
1345 867 100 100     3419 next if $dirent eq '.' or $dirent eq '..';
1346 345 50       587 next if $dirent eq $sCACHE_DESCRIPTION_FILENAME;
1347              
1348 345         418 my $latest_accessed_path_candidate = undef;
1349              
1350 345         303 my $latest_accessed_time_candidate = undef;
1351              
1352 345         1068 my $path = _BUILD_PATH($directory, $dirent);
1353              
1354 345 100       8198 if (-d $path) {
1355              
1356 255         488 ($latest_accessed_path_candidate,
1357             $latest_accessed_time_candidate) =
1358             _RECURSIVE_FIND_LATEST_ACCESSED($path);
1359              
1360             } else {
1361              
1362 90         2059 my $last_accessed_time = (stat($path))[8];
1363              
1364 90         145 $latest_accessed_path_candidate = $path;
1365              
1366 90         113 $latest_accessed_time_candidate = $last_accessed_time;
1367              
1368             }
1369              
1370 345 100       954 next unless defined $latest_accessed_path_candidate;
1371              
1372 339 50       545 next unless defined $latest_accessed_time_candidate;
1373              
1374             # if this is the first candidate, they're automatically the
1375             # best, otherwise they have to beat the best
1376              
1377 339 100 100     918 if ((!defined $best_latest_accessed_time) or
1378             ($best_latest_accessed_time >
1379             $latest_accessed_time_candidate)) {
1380              
1381 258         255 $best_latest_accessed_path =
1382             $latest_accessed_path_candidate;
1383              
1384 258         406 $best_latest_accessed_time =
1385             $latest_accessed_time_candidate;
1386              
1387             }
1388             }
1389              
1390 261         5987 closedir(DIR);
1391              
1392 261         1023 return ($best_latest_accessed_path, $best_latest_accessed_time);
1393             }
1394              
1395             # -----------------------------------------------------------------------------
1396              
1397             # recursively descend to get an estimate of the memory consumption for
1398             # this namespace, ignoring space occupied by the cache description
1399             # file. returns 0 if the cache doesn't appear to exist
1400              
1401             sub size
1402             {
1403 141     141 1 845 my ($self) = @_;
1404              
1405 141         379 my $namespace_path = $self->_get_namespace_path();
1406              
1407 141 100       3850 return 0 unless -e $namespace_path;
1408              
1409 125         346 return _RECURSIVE_DIRECTORY_SIZE($namespace_path);
1410             }
1411              
1412             # -----------------------------------------------------------------------------
1413              
1414             # find the path to the cached file, taking into account the identifier and
1415             # namespace.
1416              
1417             sub _get_cached_file_path
1418             {
1419 126     126   233 my ($self,$unique_key) = @_;
1420              
1421 126 50       424 defined($unique_key) or
1422             croak("unique key required");
1423              
1424 126         385 my $namespace_path = $self->_get_namespace_path();
1425              
1426 126         419 my $cache_depth = $self->get_cache_depth();
1427              
1428 126         326 my (@path_prefix) = _EXTRACT_PATH_PREFIX($unique_key, $cache_depth);
1429              
1430 126         297 my $cached_file_path = _BUILD_PATH($namespace_path);
1431              
1432 126         276 foreach my $path_element (@path_prefix) {
1433              
1434 360         623 $cached_file_path = _BUILD_PATH($cached_file_path, $path_element);
1435              
1436             }
1437              
1438 126         440 $cached_file_path = _BUILD_PATH($cached_file_path, $unique_key);
1439              
1440 126         371 return $cached_file_path;
1441             }
1442              
1443             # -----------------------------------------------------------------------------
1444              
1445             # build the path to the cached file in the file system, taking into account
1446             # the identifier, namespace, and cache depth.
1447              
1448             sub _build_cached_file_path
1449             {
1450 73     73   114 my ($self,$unique_key) = @_;
1451              
1452 73 50       193 defined($unique_key) or
1453             croak("unique key required");
1454              
1455 73         224 my $cached_file_path = $self->_get_cached_file_path($unique_key);
1456              
1457             # $cached_file_path has the directory & file. remove the file.
1458 73         241 my $cached_file_directory = _GET_PARENT_DIRECTORY($cached_file_path);
1459              
1460 73         314 _CREATE_DIRECTORY($cached_file_directory,0);
1461              
1462 73         230 return $cached_file_path;
1463             }
1464              
1465             # -----------------------------------------------------------------------------
1466              
1467             # return a list of the first $cache_depth letters in the $identifier
1468              
1469             sub _EXTRACT_PATH_PREFIX
1470             {
1471 126     126   185 my ($unique_key, $cache_depth) = @_;
1472              
1473 126 50       333 defined($unique_key) or
1474             croak("unique key required");
1475              
1476 126 50       220 defined($cache_depth) or
1477             croak("cache depth required");
1478              
1479 126         151 my @path_prefix;
1480              
1481 126         356 for (my $i = 0; $i < $cache_depth; $i++) {
1482 360         1064 push (@path_prefix, substr($unique_key, $i, 1));
1483             }
1484              
1485 126         13257 return @path_prefix;
1486             }
1487              
1488             # -----------------------------------------------------------------------------
1489              
1490             # represent a path in canonical form, and check for illegal characters
1491              
1492             sub _BUILD_PATH
1493             {
1494 9302     9302   21283 my (@elements) = @_;
1495              
1496 9302 50       35099 if (grep (/\.\./, @elements)) {
1497 0         0 croak("Illegal path characters ..");
1498             }
1499              
1500 9302         87282 my $path = File::Spec->catfile(@elements);
1501              
1502 9302         91622 return $path;
1503             }
1504              
1505             # -----------------------------------------------------------------------------
1506              
1507             # read in a file. returns a reference to the data read
1508              
1509             sub _READ_FILE
1510             {
1511 628     628   1026 my ($filename) = @_;
1512              
1513 628         1058 my $data_ref;
1514              
1515 628 50       1189 defined($filename) or
1516             croak("filename required");
1517              
1518 628         1172 $filename = _UNTAINT_FILE_PATH($filename);
1519              
1520 628 50       44276 open(FILE, $filename) or
1521             croak("Couldn't open $filename for reading: $!");
1522              
1523             # In case the user stores binary data
1524 628         1465 binmode FILE;
1525              
1526 628         2332 local $/ = undef;
1527              
1528 628         3841230 $$data_ref = ;
1529              
1530 628         8172 close(FILE);
1531              
1532 628         2573 return $data_ref;
1533             }
1534              
1535             # -----------------------------------------------------------------------------
1536              
1537             # write a file atomically
1538              
1539             sub _WRITE_FILE
1540             {
1541 86     86   253 my ($filename, $data_ref, $mode, $new_umask) = @_;
1542              
1543 86 50       478 defined($filename) or
1544             croak("filename required");
1545              
1546 86 50       205 defined($data_ref) or
1547             croak("data reference required");
1548              
1549 86 50       210 defined($mode) or
1550             croak("mode required");
1551              
1552             # Prepare the name for taint checking
1553              
1554 86         185 $filename = _UNTAINT_FILE_PATH($filename);
1555              
1556             # Change the umask if necessary
1557              
1558 86 100       259 my $old_umask = umask if $new_umask;
1559              
1560 86 100       297 umask($new_umask) if $new_umask;
1561              
1562             # Create a temp filename
1563              
1564 86         996 my $temp_filename = "$filename.tmp$$";
1565              
1566 86 50       9064 open(FILE, ">$temp_filename") or
1567             croak("Couldn't open $temp_filename for writing: $!\n");
1568              
1569             # Use binmode in case the user stores binary data
1570              
1571 86         641 binmode(FILE);
1572              
1573 86         2562 chmod($mode, $filename);
1574              
1575 86         948 print FILE $$data_ref;
1576              
1577 86         23514493 close(FILE);
1578              
1579 86 50       6750 rename ($temp_filename, $filename) or
1580             croak("Couldn't rename $temp_filename to $filename");
1581              
1582 86 100       427 umask($old_umask) if $old_umask;
1583              
1584 86         640 return $sSUCCESS;
1585             }
1586              
1587             # -----------------------------------------------------------------------------
1588              
1589             # clear all objects in all namespaces
1590              
1591             sub CLEAR
1592             {
1593 12     12   1057 my ($cache_key) = @_;
1594              
1595 12   33     42 $cache_key = $cache_key || _BUILD_DEFAULT_CACHE_KEY();
1596              
1597 12 100       275 if (!-d $cache_key) {
1598 3         12 return $sSUCCESS;
1599             }
1600              
1601             # [Should this use the _UNTAINT_FILE_PATH routine?]
1602 9         25 $cache_key = _UNTAINT_FILE_PATH($cache_key);
1603              
1604 9 50       32 _RECURSIVELY_REMOVE_DIRECTORY($cache_key) or
1605             croak("Couldn't clear cache");
1606              
1607 9         179 return $sSUCCESS;
1608             }
1609              
1610             # -----------------------------------------------------------------------------
1611              
1612             # purge all objects in all namespaces that have expired
1613              
1614             sub PURGE
1615             {
1616 3     3 1 172 my ($cache_key) = @_;
1617              
1618             # [Should this use the _UNTAINT_FILE_PATH routine?]
1619 3         10 $cache_key = _UNTAINT_FILE_PATH($cache_key);
1620              
1621 3   33     10 $cache_key = $cache_key || _BUILD_DEFAULT_CACHE_KEY();
1622              
1623 3 50       65 if (!-d $cache_key) {
1624 0         0 return $sSUCCESS;
1625             }
1626              
1627 3         976 finddepth(\&_PURGE_FILE_WRAPPER, $cache_key);
1628              
1629 3         20 return $sSUCCESS;
1630             }
1631              
1632             # -----------------------------------------------------------------------------
1633              
1634             # get an estimate of the total memory consumption of the cache,
1635             # ignoring space occupied by cache description files. returns 0 if the
1636             # cache doesn't appear to exist
1637              
1638             sub SIZE
1639             {
1640 3     3 1 17705384 my ($cache_key) = @_;
1641              
1642 3 50       358 return 0 unless -e $cache_key;
1643              
1644 3         89 return _RECURSIVE_DIRECTORY_SIZE($cache_key);
1645             }
1646              
1647             # -----------------------------------------------------------------------------
1648              
1649             # walk down a directory structure and total the size of the files
1650             # contained therein. Doesn't count the size of the cache description
1651             # file
1652              
1653             sub _RECURSIVE_DIRECTORY_SIZE
1654             {
1655 3383     3383   5607 my ($directory) = @_;
1656              
1657 3383 50       6739 defined($directory) or
1658             croak("directory required");
1659              
1660 3383         3566 my $size = 0;
1661              
1662 3383         5179 $directory = _UNTAINT_FILE_PATH($directory);
1663              
1664 3383 50       122119 opendir(DIR, $directory) or
1665             croak("Couldn't open directory $directory: $!");
1666              
1667 3383         44242 my @dirents = readdir(DIR);
1668              
1669 3383         6522 foreach my $dirent (@dirents) {
1670              
1671 11148 100 100     55596 next if $dirent eq '.' or $dirent eq '..';
1672              
1673 4382         10562 my $path = _BUILD_PATH($directory, $dirent);
1674              
1675 4382 100       116774 if (-d $path) {
1676 3255         7464 $size += _RECURSIVE_DIRECTORY_SIZE($path);
1677             } else {
1678             # Don't count the cache description file
1679 1127 100       29940 $size += -s $path if $dirent ne $sCACHE_DESCRIPTION_FILENAME;
1680             }
1681              
1682             }
1683              
1684 3383         114571 closedir(DIR);
1685              
1686 3383         28757 return $size;
1687             }
1688              
1689             # -----------------------------------------------------------------------------
1690              
1691             # Find the username of the person running the process in an OS
1692             # independent way
1693              
1694             sub _FIND_USERNAME
1695             {
1696 6     6   11 my ($self) = @_;
1697              
1698 6         11 my $username;
1699              
1700 6         11 my $success = eval {
1701 6         37 my $effective_uid = $>;
1702 6         2365 $username = getpwuid($effective_uid);
1703             };
1704              
1705 6 50 33     58 if ($success and $username) {
1706 6         19 return $username;
1707             } else {
1708 0         0 return $sDEFAULT_USERNAME;
1709             }
1710             }
1711              
1712             # -----------------------------------------------------------------------------
1713              
1714              
1715             # Untaint a path to a file
1716              
1717             sub _UNTAINT_FILE_PATH
1718             {
1719 5853     5853   12844 my ($file_path) = @_;
1720              
1721 5853         12631 return _UNTAINT_STRING($file_path, $sUNTAINTED_FILE_PATH_REGEX);
1722             }
1723              
1724              
1725              
1726             # Untaint a string
1727              
1728             sub _UNTAINT_STRING
1729             {
1730 5853     5853   11372 my ($string, $untainted_regex) = @_;
1731              
1732 5853 50       11694 defined($untainted_regex) or
1733             croak("untainted regex required");
1734              
1735 5853 50       9385 defined($string) or
1736             croak("string required");
1737              
1738 5853         40427 my ($untainted_string) = $string =~ /$untainted_regex/;
1739              
1740 5853 50 33     36925 if (!defined $untainted_string || $untainted_string ne $string) {
1741 0         0 warn("String $string contains possible taint");
1742             }
1743              
1744 5853         13156 return $untainted_string;
1745             }
1746              
1747              
1748             # -----------------------------------------------------------------------------
1749              
1750             # Returns the default root of the cache under the OS dependent temp dir
1751              
1752             sub _BUILD_DEFAULT_CACHE_KEY
1753             {
1754 0 0   0   0 my $tmpdir = tmpdir() or
1755             croak("No tmpdir on this system. Bugs to the authors of File::Spec");
1756              
1757 0         0 my $default_cache_key = _BUILD_PATH($tmpdir, $sDEFAULT_CACHE_KEY);
1758              
1759 0         0 return $default_cache_key;
1760             }
1761              
1762              
1763             # -----------------------------------------------------------------------------
1764              
1765             # Remove a directory starting at the root
1766              
1767              
1768             sub _RECURSIVELY_REMOVE_DIRECTORY
1769             {
1770 195     195   305 my ($root) = @_;
1771              
1772 195 50       4525 -d $root or
1773             croak("$root is not a directory");
1774              
1775 195 50       5676 opendir(DIR, $root) or
1776             croak("Couldn't open directory $root: $!");
1777              
1778 195         2585 my @dirents = readdir(DIR);
1779              
1780 195 50       2646 closedir(DIR) or
1781             croak("Couldn't close directory $root: $!");
1782              
1783 195         349 foreach my $dirent (@dirents) {
1784              
1785 633 100 100     3984 next if $dirent eq '.' or $dirent eq '..';
1786              
1787 243         515 my $path_to_dirent = "$root/$dirent";
1788              
1789 243         457 $path_to_dirent = _UNTAINT_FILE_PATH($path_to_dirent);
1790              
1791 243 100       6224 if (-d $path_to_dirent) {
1792 183         840 _RECURSIVELY_REMOVE_DIRECTORY($path_to_dirent);
1793             } else {
1794 60 50       1064224 unlink($path_to_dirent) or
1795             croak("Couldn't unlink($path_to_dirent): $!\n");
1796             }
1797              
1798             }
1799              
1800 195 50       23513 rmdir($root) or
1801             croak("Couldn't rmdir $root: $!");
1802             }
1803              
1804              
1805             # -----------------------------------------------------------------------------
1806              
1807             # Get whether or not we automatically remove stale data from the cache
1808             # on retrieval
1809              
1810             sub get_auto_remove_stale
1811             {
1812 6     6 1 14 my ($self) = @_;
1813              
1814 6         27 return $self->{_auto_remove_stale};
1815             }
1816              
1817             # -----------------------------------------------------------------------------
1818              
1819             # Set whether or not we automatically remove stale data from the cache
1820             # on retrieval
1821              
1822             sub set_auto_remove_stale
1823             {
1824 13     13 1 30 my ($self, $auto_remove_stale) = @_;
1825              
1826 13 50       40 defined($auto_remove_stale) or
1827             croak("\$File::Cache::sTRUE (i.e. 1) or " .
1828             "\$File::Cache::sFALSE (i.e. 0) required");
1829              
1830 13         127 $self->{_auto_remove_stale} = $auto_remove_stale;
1831             }
1832              
1833             # -----------------------------------------------------------------------------
1834              
1835             # Get the root of this cache on the filesystem
1836              
1837             sub get_cache_key
1838             {
1839 374     374 0 508 my ($self) = @_;
1840              
1841 374         741 my $cache_key = $self->{_cache_key};
1842              
1843 374         974 return $cache_key;
1844             }
1845              
1846             # -----------------------------------------------------------------------------
1847              
1848             # Set the root of this cache on the filesystem
1849              
1850             sub set_cache_key
1851             {
1852 13     13 0 28 my ($self, $cache_key) = @_;
1853              
1854 13 50       1911 defined($cache_key) or
1855             croak("cache key required");
1856              
1857 13         33 $self->{_cache_key} = $cache_key;
1858              
1859             # We don't verify the new directory if this function is called
1860             # during cache creation
1861 13 50       123 if ( (caller(1))[3] ne 'File::Cache::new')
1862             {
1863 0 0       0 _VERIFY_DIRECTORY( $self->_get_namespace_path() ) == $sSUCCESS or
1864             croak("Can not build cache at " . $self->_get_namespace_path() .
1865             ". Check directory permissions.");
1866             }
1867             }
1868              
1869             # -----------------------------------------------------------------------------
1870              
1871             # Get the root of this user's path
1872              
1873             sub _get_user_path
1874             {
1875 361     361   471 my ($self) = @_;
1876              
1877 361         881 my $cache_key = $self->get_cache_key();
1878 361         1061 my $username = $self->get_username();
1879              
1880 361         803 my $user_path = _BUILD_PATH($cache_key, $username);
1881              
1882 361         959 return $user_path;
1883             }
1884              
1885             # -----------------------------------------------------------------------------
1886              
1887             # Get the root of this namespace's path
1888              
1889             sub _get_namespace_path
1890             {
1891 361     361   571 my ($self) = @_;
1892              
1893 361         1071 my $user_path = $self->_get_user_path();
1894 361         1104 my $namespace = $self->get_namespace();
1895              
1896 361         732 my $namespace_path = _BUILD_PATH($user_path, $namespace);
1897              
1898 361         919 return $namespace_path;
1899             }
1900              
1901             # -----------------------------------------------------------------------------
1902              
1903             # Get the namespace for this cache instance (within the entire cache)
1904              
1905             sub get_namespace
1906             {
1907 361     361 1 650 my ($self) = @_;
1908              
1909 361         863 return $self->{_namespace};
1910             }
1911              
1912             # -----------------------------------------------------------------------------
1913              
1914             # Set the namespace for this cache instance (within the entire cache)
1915              
1916             sub set_namespace
1917             {
1918 13     13 1 58 my ($self, $namespace) = @_;
1919              
1920 13 50       38 defined($namespace) or
1921             croak("namespace required");
1922              
1923 13         62 $self->{_namespace} = $namespace;
1924              
1925             # We don't verify the new directory if this function is called
1926             # during cache creation
1927 13 50       92 if ( (caller(1))[3] ne 'File::Cache::new')
1928             {
1929 0 0       0 _VERIFY_DIRECTORY( $self->_get_namespace_path() ) == $sSUCCESS or
1930             croak("Can not build cache at " . $self->_get_namespace_path() .
1931             ". Check directory permissions.");
1932             }
1933             }
1934              
1935             # -----------------------------------------------------------------------------
1936              
1937             # Get the global expiration value for the cache
1938              
1939             sub get_global_expires_in
1940             {
1941 73     73 1 178 my ($self) = @_;
1942              
1943 73         215 return $self->{_global_expires_in};
1944             }
1945              
1946             # -----------------------------------------------------------------------------
1947              
1948             # Set the global expiration value for the cache
1949              
1950             sub set_global_expires_in
1951             {
1952 13     13 1 26 my ($self, $global_expires_in) = @_;
1953              
1954 13 50 33     181 ($global_expires_in > 0) ||
      33        
1955             ($global_expires_in == $sEXPIRES_NEVER) ||
1956             ($global_expires_in == $sEXPIRES_NOW) or
1957             croak("\$global_expires_in must be > 0," .
1958             "\$sEXPIRES_NOW, or \$sEXPIRES_NEVER");
1959              
1960 13         70 $self->{_global_expires_in} = $global_expires_in;
1961             }
1962              
1963             # -----------------------------------------------------------------------------
1964              
1965             # Get the creation time for a cache object. Returns undef if the value
1966             # is not in the cache
1967              
1968             sub get_creation_time
1969             {
1970 6     6 1 6047797 my ($self, $identifier) = @_;
1971              
1972 6         34 my $unique_key = _BUILD_UNIQUE_KEY($identifier);
1973              
1974 6         39 my $cached_file_path = $self->_get_cached_file_path($unique_key);
1975              
1976 6         16 my $object_data;
1977              
1978 6         26 $object_data =
1979             _READ_OBJECT_DATA($cached_file_path);
1980              
1981 6 50       28 if ($object_data) {
1982              
1983 6         42 return $object_data->{created_at};
1984            
1985             } else {
1986            
1987 0         0 return undef;
1988            
1989             }
1990             }
1991              
1992             # -----------------------------------------------------------------------------
1993              
1994             # Get the expiration time for a cache object. Returns undef if the
1995             # value is not in the cache
1996              
1997             sub get_expiration_time
1998             {
1999 3     3 1 18 my ($self, $identifier) = @_;
2000              
2001 3         9 my $unique_key = _BUILD_UNIQUE_KEY($identifier);
2002              
2003 3         12 my $cached_file_path = $self->_get_cached_file_path($unique_key);
2004              
2005 3         8 my $object_data;
2006              
2007 3         10 $object_data =
2008             _READ_OBJECT_DATA($cached_file_path);
2009              
2010 3 50       15 if ($object_data) {
2011            
2012 3         15 return $object_data->{expires_at};
2013            
2014             } else {
2015            
2016 0         0 return undef;
2017            
2018             }
2019             }
2020              
2021             # -----------------------------------------------------------------------------
2022              
2023             # Get the username associated with this cache
2024              
2025             sub get_username
2026             {
2027 361     361 1 570 my ($self) = @_;
2028              
2029 361         892 return $self->{_username};
2030             }
2031              
2032             # -----------------------------------------------------------------------------
2033              
2034             # Set the username associated with this cache
2035              
2036             sub set_username
2037             {
2038 13     13 1 26 my ($self, $username) = @_;
2039              
2040 13 50       43 defined($username) or
2041             croak("username required");
2042              
2043 13         77 $self->{_username} = $username;
2044              
2045             # We don't verify the new directory if this function is called
2046             # during cache creation
2047 13 50       413 if ( (caller(1))[3] ne 'File::Cache::new')
2048             {
2049 0 0       0 _VERIFY_DIRECTORY( $self->_get_namespace_path() ) == $sSUCCESS or
2050             croak("Can not build cache at " . $self->_get_namespace_path() .
2051             ". Check directory permissions.");
2052             }
2053             }
2054              
2055             # -----------------------------------------------------------------------------
2056              
2057             # Gets the filemode for files created within the cache
2058              
2059             sub get_filemode
2060             {
2061 73     73 1 137 my ($self) = @_;
2062              
2063 73         231 return $self->{_filemode};
2064             }
2065              
2066             # -----------------------------------------------------------------------------
2067              
2068             # Sets the filemode for files created within the cache
2069              
2070             sub set_filemode
2071             {
2072 13     13 1 40 my ($self, $filemode) = @_;
2073              
2074 13 50       54 defined ($filemode) or
2075             croak("filemode required");
2076              
2077 13         55 $self->{_filemode} = $filemode;
2078             }
2079              
2080             # -----------------------------------------------------------------------------
2081              
2082             # Gets the max cache size.
2083              
2084             sub get_max_size
2085             {
2086 73     73 1 120 my ($self) = @_;
2087              
2088 73         203 return $self->{_max_size};
2089             }
2090              
2091             # -----------------------------------------------------------------------------
2092              
2093             # Sets the max cache size.
2094              
2095             sub set_max_size
2096             {
2097 13     13 1 15 my ($self, $max_size) = @_;
2098              
2099 13 50 66     133 ($max_size > 0) || ($max_size == $sNO_MAX_SIZE) or
2100             croak("Invalid cache size. " .
2101             "Must be either \$sNO_MAX_SIZE or greater than zero");
2102              
2103 13         51 $self->{_max_size} = $max_size;
2104              
2105             # Reduce the size if necessary.
2106 13 100       37 if ($max_size != $sNO_MAX_SIZE) {
2107 5         23 $self->reduce_size($max_size);
2108             }
2109             }
2110              
2111             # -----------------------------------------------------------------------------
2112              
2113             # Gets the cache depth
2114              
2115             sub get_cache_depth
2116             {
2117 126     126 1 248 my ($self) = @_;
2118              
2119 126         338 return $self->{_cache_depth};
2120             }
2121              
2122             # -----------------------------------------------------------------------------
2123              
2124             # Sets the cache depth
2125              
2126             sub set_cache_depth
2127             {
2128 13     13 1 19 my ($self, $cache_depth) = @_;
2129              
2130 13 50       37 ($cache_depth >= 0) or
2131             croak("Invalid cache depth. Must be greater than zero");
2132              
2133 13         52 $self->{_cache_depth} = $cache_depth;
2134             }
2135              
2136             # -----------------------------------------------------------------------------
2137              
2138             # Gets the persistence mechanism
2139              
2140             sub get_persistence_mechanism
2141             {
2142 129     129 1 247 my ($self) = @_;
2143              
2144 129         1005 return $self->{_persistence_mechanism};
2145             }
2146              
2147             # -----------------------------------------------------------------------------
2148              
2149             # Sets the persistence mechanism.
2150              
2151             sub set_persistence_mechanism
2152             {
2153 13     13 1 27 my ($self, $persistence_mechanism) = @_;
2154              
2155 13 50       50 defined ($persistence_mechanism) or
2156             croak("persistence mechanism required");
2157              
2158             # We don't clear the cache if this function is called during cache
2159             # creation
2160 13 50       100 if ( (caller(1))[3] ne 'File::Cache::new')
2161             {
2162 0         0 $self->clear();
2163             }
2164              
2165 13 50 33     48 ($persistence_mechanism eq 'Storable') ||
2166             ($persistence_mechanism eq 'Data::Dumper') or
2167             croak("Peristence mechanism must be either " .
2168             \"Storable\" or \"Data::Dumper\"");
2169              
2170 13         57 $self->{_persistence_mechanism} = $persistence_mechanism;
2171             }
2172              
2173              
2174             1;
2175              
2176              
2177             __END__