File-Cache
view release on metacpan or search on metacpan
@EXPORT_OK = qw($sSUCCESS $sFAILURE $sTRUE $sFALSE $sEXPIRES_NOW
$sEXPIRES_NEVER $sNO_MAX_SIZE );
# -----------------------------------------------------------------------------
# Code notes:
# Internal subroutines (helper routines not supposed to be called by
# external clients) are preceded with an underscore ("_"). Subroutines
# (both internal and external) that are called as functions, as
# opposed to methods, are in ALL CAPS. The PURGE and CLEAR routines
# are object-independent, which means that any subroutines they call
# must also be object-independent.
# -----------------------------------------------------------------------------
# Constants
$sSUCCESS = 1;
$sFAILURE = 0;
$sTRUE = 1;
$sFALSE = 0;
$sEXPIRES_NOW = 0;
$sEXPIRES_NEVER = -1;
$sNO_MAX_SIZE = -1;
$sGET_STALE_ONLY = 1;
$sGET_FRESH_ONLY = 0;
# The default cache key is used inside the tmp filesystem (as defined
# by File::Spec)
my $sDEFAULT_CACHE_KEY;
$sDEFAULT_CACHE_KEY = ($^O eq 'dos' || $^O eq 'MSWin32') ?
'FileCache' : 'File::Cache';
# if a namespace is not specified, use this as a default
my $sDEFAULT_NAMESPACE = "_default";
# by default, remove objects that have expired when then are requested
my $sDEFAULT_AUTO_REMOVE_STALE = $sTRUE;
# by default, the filemode is world read/writable
my $sDEFAULT_FILEMODE = 0777;
# by default, there is no max size to the cache
my $sDEFAULT_MAX_SIZE = $sNO_MAX_SIZE;
# if the OS does not support getpwuid, use this as a default username
my $sDEFAULT_USERNAME = 'nobody';
# by default, the objects in the cache never expire
my $sDEFAULT_GLOBAL_EXPIRES_IN = $sEXPIRES_NEVER;
# default cache depth
my $sDEFAULT_CACHE_DEPTH = 0;
# File::Cache supports either Storable or Data::Dumper as the
# persistence mechanism. The default persistence mechanism uses Storable
my $sDEFAULT_PERSISTENCE_MECHANISM = 'Storable';
# cache description filename
my $sCACHE_DESCRIPTION_FILENAME = '.description';
# Always use a global friendly umask for the .description files
my $sCACHE_DESCRIPTION_UMASK = 022;
# valid filepath characters for tainting. Be sure to accept DOS/Windows style
# path specifiers (C:\path) also
my $sUNTAINTED_FILE_PATH_REGEX = qr{^([-\@\w\\\\~./:]+|[\w]:[-\@\w\\\\~./]+)$};
# -----------------------------------------------------------------------------
# create a new Cache object that can be used to persist
# data across processes
sub new
{
my ($proto, $options) = @_;
my $class = ref($proto) || $proto;
my $self = {};
bless ($self, $class);
# remove objects from the cache that have expired on retrieval
# when this is set
my $auto_remove_stale = defined $options->{auto_remove_stale} ?
$options->{auto_remove_stale} : $sDEFAULT_AUTO_REMOVE_STALE;
$self->set_auto_remove_stale($auto_remove_stale);
return 0 unless -e $cache_key;
return _RECURSIVE_DIRECTORY_SIZE($cache_key);
}
# -----------------------------------------------------------------------------
# walk down a directory structure and total the size of the files
# contained therein. Doesn't count the size of the cache description
# file
sub _RECURSIVE_DIRECTORY_SIZE
{
my ($directory) = @_;
defined($directory) or
croak("directory required");
my $size = 0;
$directory = _UNTAINT_FILE_PATH($directory);
opendir(DIR, $directory) or
croak("Couldn't open directory $directory: $!");
my @dirents = readdir(DIR);
foreach my $dirent (@dirents) {
next if $dirent eq '.' or $dirent eq '..';
my $path = _BUILD_PATH($directory, $dirent);
if (-d $path) {
$size += _RECURSIVE_DIRECTORY_SIZE($path);
} else {
# Don't count the cache description file
$size += -s $path if $dirent ne $sCACHE_DESCRIPTION_FILENAME;
}
}
closedir(DIR);
return $size;
}
# -----------------------------------------------------------------------------
# Find the username of the person running the process in an OS
# independent way
sub _FIND_USERNAME
{
my ($self) = @_;
my $username;
my $success = eval {
my $effective_uid = $>;
$username = getpwuid($effective_uid);
};
if ($success and $username) {
return $username;
} else {
return $sDEFAULT_USERNAME;
}
}
# -----------------------------------------------------------------------------
# Untaint a path to a file
sub _UNTAINT_FILE_PATH
{
my ($file_path) = @_;
return _UNTAINT_STRING($file_path, $sUNTAINTED_FILE_PATH_REGEX);
}
# Untaint a string
sub _UNTAINT_STRING
{
my ($string, $untainted_regex) = @_;
defined($untainted_regex) or
croak("untainted regex required");
defined($string) or
croak("string required");
my ($untainted_string) = $string =~ /$untainted_regex/;
if (!defined $untainted_string || $untainted_string ne $string) {
warn("String $string contains possible taint");
}
return $untainted_string;
}
# -----------------------------------------------------------------------------
# Returns the default root of the cache under the OS dependent temp dir
sub _BUILD_DEFAULT_CACHE_KEY
{
my $tmpdir = tmpdir() or
croak("No tmpdir on this system. Bugs to the authors of File::Spec");
my $default_cache_key = _BUILD_PATH($tmpdir, $sDEFAULT_CACHE_KEY);
return $default_cache_key;
}
( run in 0.516 second using v1.01-cache-2.11-cpan-df04353d9ac )