200 lines
5.5 KiB
Perl
200 lines
5.5 KiB
Perl
# ==================================================================
|
|
# Gossamer Threads Module Library - http://gossamer-threads.com/
|
|
#
|
|
# GT::TempFile
|
|
# Author : Scott Beck
|
|
# CVS Info :
|
|
# $Id: TempFile.pm,v 1.36 2005/03/23 04:27:26 jagerman Exp $
|
|
#
|
|
# Copyright (c) 2004 Gossamer Threads Inc. All Rights Reserved.
|
|
# ==================================================================
|
|
#
|
|
# Description:
|
|
# Implements a tempfile.
|
|
#
|
|
|
|
package GT::TempFile;
|
|
# ===================================================================
|
|
|
|
# Pragmas
|
|
use strict;
|
|
use vars qw/$VERSION $TMP_DIR %OBJECTS/;
|
|
use bases 'GT::Base' => ':all';
|
|
use overload '""' => \&as_string;
|
|
|
|
$VERSION = sprintf "%d.%03d", q$Revision: 1.36 $ =~ /(\d+)\.(\d+)/;
|
|
|
|
sub find_tmpdir {
|
|
# -------------------------------------------------------------------
|
|
# Sets the tmpdir.
|
|
#
|
|
return $TMP_DIR if $TMP_DIR;
|
|
my @tmp_dirs;
|
|
for (qw/GT_TMPDIR TEMP TMP TMPDIR/) {
|
|
push @tmp_dirs, $ENV{$_} if exists $ENV{$_};
|
|
}
|
|
push @tmp_dirs, $ENV{windir} . '/temp' if exists $ENV{windir};
|
|
eval { push @tmp_dirs, (getpwuid $>)[7] . '/tmp' };
|
|
push @tmp_dirs, '/usr/tmp', '/var/tmp', 'c:/temp', '/tmp', '/temp', '/sys$scratch', '/WWW_ROOT', 'c:/windows/temp', 'c:/winnt/temp';
|
|
|
|
for my $dir (@tmp_dirs) {
|
|
return $TMP_DIR = $dir if $dir and -d $dir and -w _ and -x _;
|
|
}
|
|
$TMP_DIR = '.';
|
|
}
|
|
|
|
sub new {
|
|
# -----------------------------------------------------------------------------
|
|
# Create a new tempfile.
|
|
#
|
|
$TMP_DIR ||= find_tmpdir();
|
|
my $self = bless {}, 'GT::TempFile::Tmp';
|
|
$self->reset;
|
|
|
|
# Backwards compatibility
|
|
if ( @_ == 2 and not ref( $_[1] ) ) {
|
|
( $self->{tmp_dir} ) = $_[1];
|
|
}
|
|
elsif ( @_ > 1 ) {
|
|
$self->set( @_[1 .. $#_] );
|
|
}
|
|
|
|
my $dir = $self->{tmp_dir} || $TMP_DIR;
|
|
my $count = substr(time, -4) . int(rand(10000));
|
|
my $filename = '';
|
|
|
|
# Directory for locking
|
|
my $lock_dir = "$dir/$self->{prefix}GT_TempFile_lock";
|
|
|
|
# W need to create the directory
|
|
my $safety = 0;
|
|
until ( mkdir( $lock_dir, 0777 ) ) {
|
|
|
|
# If we wait 10 seconds and still no lock we assume the lockfile is stale
|
|
if ( $safety++ > 10 ) {
|
|
rmdir $lock_dir or $self->fatal( 'RMDIR', $lock_dir, "$!" );
|
|
}
|
|
sleep 1;
|
|
}
|
|
|
|
# Now lets get our temp file
|
|
for (1 .. 20) {
|
|
$filename = "$dir/$self->{prefix}GTTemp$count";
|
|
last if (! -f $filename);
|
|
$count++;
|
|
}
|
|
|
|
# If the open fails we need to remove the lockdir
|
|
if ( !open( FH, ">$filename" ) ) {
|
|
rmdir $lock_dir or $self->fatal( 'RMDIR', $lock_dir, "$!" );
|
|
$self->fatal( 'WRITEOPEN', $filename, "$!" );
|
|
}
|
|
close FH;
|
|
|
|
# All done searching for a temp file, now release the directory lock
|
|
rmdir $lock_dir or $self->fatal( 'RMDIR', $lock_dir, "$!" );
|
|
($filename =~ /^(.+)$/) and ($filename = $1); # Detaint.
|
|
|
|
$self->{filename} = $filename;
|
|
my $object = bless \$filename, 'GT::TempFile';
|
|
$OBJECTS{overload::StrVal $object} = $self;
|
|
$self->debug("New tmpfile created ($filename).") if ($self->{_debug});
|
|
$object;
|
|
}
|
|
|
|
sub as_string {
|
|
# -------------------------------------------------------------------
|
|
# Backwards compatibility
|
|
my ( $self ) = @_;
|
|
return $$self;
|
|
}
|
|
|
|
sub DESTROY {
|
|
# -------------------------------------------------------------------
|
|
my $obj = shift;
|
|
my $self = $OBJECTS{$obj};
|
|
$self->debug("Deleteing $self->{filename}") if $self->{_debug};
|
|
|
|
# unlink the file if they wanted it deleted
|
|
if ($self->{destroy}) {
|
|
unless (unlink $self->{filename}) {
|
|
$self->debug("Unable to remove temp file: $self->{filename} ($!)") if $self->{_debug};
|
|
}
|
|
}
|
|
delete $OBJECTS{$obj};
|
|
}
|
|
|
|
package GT::TempFile::Tmp;
|
|
use bases 'GT::Base' => '';
|
|
use vars qw/$ATTRIBS $ERRORS/;
|
|
$ATTRIBS = {
|
|
prefix => '',
|
|
destroy => 1,
|
|
tmp_dir => undef,
|
|
};
|
|
$ERRORS = { SAFETY => "Safety reached while trying to create lock directory %s, (%s)" };
|
|
|
|
1;
|
|
|
|
__END__
|
|
|
|
=head1 NAME
|
|
|
|
GT::TempFile - implements a very simple temp file.
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
my $file = new GT::TempFile;
|
|
open (FILE, "> $file");
|
|
print FILE "somedata";
|
|
close FILE;
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
GT::TempFile implements a very simple temp file system that will remove
|
|
itself once the variable goes out of scope.
|
|
|
|
When you call new, it creates a random file name and looks for a
|
|
tmp directory. What you get back is an object that when dereferenced
|
|
is the file name. You can also pass in a temp dir to use:
|
|
|
|
my $file = new GT::Tempfile '/path/to/tmpfiles';
|
|
|
|
Other option you may use are:
|
|
my $file = new GT::TempFile(
|
|
destroy => 1,
|
|
prefix => '',
|
|
tmp_dir => '/tmp'
|
|
);
|
|
|
|
|
|
When the object is destroyed, it automatically unlinks the temp file
|
|
unless you specify I<destroy> => 0.
|
|
|
|
I<prefix> will be prepended to the start of all temp files created
|
|
and the lock directory that is created. It is used to keep programs
|
|
using the tempfile module that do not have the temp files destroyed
|
|
from clashing.
|
|
|
|
I<tmp_dir> is the same as calling new with just one argument, it is
|
|
the directory where files will be stored.
|
|
|
|
TempFile picks a temp directory based on the following:
|
|
|
|
1. ENV{GT_TMPDIR}
|
|
2. ~/tmp
|
|
3. ENV{TMPDIR}, ENV{TEMP}, ENV{TMP}
|
|
4. /usr/tmp, /var/tmp, c:/temp, /tmp, /temp,
|
|
/WWW_ROOT, c:/windows/temp, c:/winnt/temp
|
|
|
|
=head1 COPYRIGHT
|
|
|
|
Copyright (c) 2004 Gossamer Threads Inc. All Rights Reserved.
|
|
http://www.gossamer-threads.com/
|
|
|
|
=head1 VERSION
|
|
|
|
Revision: $Id: TempFile.pm,v 1.36 2005/03/23 04:27:26 jagerman Exp $
|
|
|
|
=cut
|