The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.
ChangeLog 0113
MANIFEST 02
META.yml 1322
Makefile.PL 02
README 758
Temp.pm 217394
t/fork.t 090
t/lock.t 060
t/object.t 217
t/seekable.t 314
10 files changed (This is a version diff) 242772
@@ -1,3 +1,114 @@
+2008-11-12  Tim Jenness  <timj@poma.jach.hawaii.edu>
+
+	---- Release V0.21 CPAN ----
+
+	* Temp.pm: Clean out $FILES_CREATED_BY_OBJECT when the destructor
+	runs. Otherwise memory does not get returned. Really bad idea for 
+	daemons. (Thanks to Maxime Therreault RT #37621)
+	
+	* Temp.pm: Integrate patches from bleadperl for cygwin. (thanks to 
+	Jari Aalto RT #36376)
+
+	* t/seekable.t: seekable test was failing on perl 5.6.0 so we now
+	skip the specific test. (thanks to Zefram)
+
+	* Temp.pm: Remove the test on the parent directory to see if a file
+	can be written. This will be found out anyway as soon as the file open
+	is attempted. AFS systems may fail a -w test but still allow a file to
+	be created. (thanks to Christopher Ellison)
+
+	* Temp.pm: Put an eval around rmtree. Some versions of rmtree croak
+	if you attempt to remove a directory that you are inside. (debian bug
+	479317 and RT #35779).
+	
+2008-03-15 Tim Jenness <tjenness@cpan.org>
+
+	* Temp.pm: Localize special variables in END blocks and destructors.
+	
+2007-12-20  Tim Jenness  <tjenness@cpan.org>
+
+	---- Release V0.20 CPAN ----
+	
+	* t/lock.t: Fix logic problem with BEGIN block that was causing grief on some
+	systems (thanks to Steve Peters for patch).
+
+2007-11-19  Tim Jenness  <tjenness@cpan.org>
+
+	----- Release V0.19 CPAN -----
+	
+	* Temp.pm (tempfile): Add EXLOCK option which can be used to disable O_EXLOCK
+
+	* t/lock.t: Test ability to disable O_EXLOCK
+	
+2007-11-16  Tim Jenness  <tjenness@cpan.org>
+
+	* Temp.pm (newdir): Add object oriented interface to "tempdir". Use
+	File::Temp->newdir()
+
+2007-11-15  Tim Jenness  <tjenness@cpan.org>
+
+	* Temp.pm (tempdir): Add a note to the tempdir documentation to
+	clarify that the default is for the directory not to be temporary
+	and that use of an OO approach may be required (thanks to David
+	Golden's annotation on CPAN).
+	
+	* Temp.pm (_randchar): Remove _randchar function (no longer used) 
+
+	* Temp.pm: Add note  about File::Tempdir module
+	
+2007-11-14  Tim Jenness  <tjenness@cpan.org>
+
+	* Temp.pm (new): Track pid used when file created and make sure
+	object destructor deletes the file only when the current pid
+	matches the original pid (RT#11067 again - thanks to Grousse)
+	Added new test (fork.t) to test this behaviour.
+
+	* t/seekable.t: Add tests to verify fix for RT#22052
+	
+2007-11-01  Tim Jenness  <tjenness@cpan.org>
+
+	* Temp.pm (_is_safe): Correct cluck message to match uid check
+	(thanks to Alexey Tourbin RT #14218)
+
+	* Temp.pm: Add note on use of binmode to modify encoding. (prompted
+	by Wolfgang Husmann)
+	
+2007-10-31  Tim Jenness  <tjenness@cpan.org>
+
+	* Temp.pm (tempfile): Add TMPDIR flag to simplify 
+	    tempdir(template, DIR => File::Spec->tmpdir) and to remove confusion
+	for tempdir interface. (thanks to Brendan O'Dea - debian bug #351373)
+
+	* META.yml: Update to v1.0 spec YAML spec. (thanks to Alexandr Ciornii RT# 23524)
+
+	* Temp.pm: Localize $@ when using eval to prevent leakage (prompted by Zefram)
+	
+	* Makefile.PL: Support LICENSE in newer ExtUtils::MakeMaker implementations
+	(thanks to Alexandr Ciornii RT #23524)
+
+2007-10-31  Tim Jenness  <tjenness@cpan.org>
+
+	* t/seekable.t: Skip seek test on older IO::Seekable versions.
+	(thanks to Sebastien Aperghis-Tramoni RT #23524)
+	
+	* Temp.pm: Allow XXX replacement to run on perl 5.005 and 5.004.
+	(thanks to Sebastien Aperghis-Tramoni RT #23524)
+
+2007-10-29  Tim Jenness  <tjenness@cpan.org>
+
+	* Temp.pm: Fix range of random character determination such that the last character
+	in the list (_) will appear occassionally. (Thanks to Peter Dintelmann perl RT# 41345)
+
+	* Temp.pm: Clarify error message when parent directory does not exist (thanks to
+	Peter Dintelmann perl RT # 41346)
+
+	* Temp.pm: Carp::Heavy does not exist on older perls (eg 5.005) so wrap the require
+	in an eval (Thanks to Sebastien Aperghis-Tramoni, Jesse Vincent, Slaven Rezic
+	and Robin Barker RT #26841)
+
+	* Temp.pm: Replace "new File::Temp" with "File::Temp->new" at the behest of H. Merijn 
+	Brand
+	
 2007-01-21 Tim Jenness <tjenness@cpan.org>
 
 	--- RELEASE 0.18 CPAN ---
@@ -9,6 +120,8 @@
 	(thanks to Peter Dintelmann, Gisle Aas)
 
 	* t/cmp.t: New test file
+
+	* Temp.pm: Export SEEK_* constants (Matt Lawrence RT #22052)
 	
 2006-08-18  Tim Jenness  <tjenness@cpan.org>
 
@@ -9,6 +9,8 @@ t/security.t
 t/object.t
 t/seekable.t
 t/cmp.t
+t/fork.t
+t/lock.t
 ChangeLog
 misc/benchmark.pl
 misc/results.txt
@@ -1,14 +1,23 @@
-# http://module-build.sourceforge.net/META-spec.html
-#XXXXXXX This is a prototype!!!  It will change in the future!!! XXXXX#
-name:         File-Temp
-version:      0.18
-version_from: Temp.pm
-installdirs:  perl
+--- #YAML:1.0
+name:               File-Temp
+version:            0.21
+abstract:           return name and handle of a temporary file safely
+author:
+    - Tim Jenness <tjenness@cpan.org>
+license:            perl
+distribution_type:  module
+configure_requires:
+    ExtUtils::MakeMaker:  0
 requires:
-    Fcntl:                         1.03
-    File::Path:                    0
-    File::Spec:                    0.8
-    Test::More:                    0
-
-distribution_type: module
-generated_by: ExtUtils::MakeMaker version 6.30
+    Fcntl:       1.03
+    File::Path:  0
+    File::Spec:  0.8
+    Test::More:  0
+no_index:
+    directory:
+        - t
+        - inc
+generated_by:       ExtUtils::MakeMaker version 6.48
+meta-spec:
+    url:      http://module-build.sourceforge.net/META-spec-v1.4.html
+    version:  1.4
@@ -18,4 +18,6 @@ WriteMakefile(
   ($] >= 5.005 ?    ## Add these new keywords supported since 5.005
         (ABSTRACT_FROM => 'Temp.pm',
          AUTHOR     => 'Tim Jenness <tjenness@cpan.org>') : ()),
+	      ($ExtUtils::MakeMaker::VERSION gt '6.30'?
+	       ('LICENSE'                => 'perl', ) : ()),
 );
@@ -1,6 +1,6 @@
 File::Temp - provides functions for generating temporary files
 
-This is release V0.18 of File::Temp. This module can be used to
+This is release V0.21 of File::Temp. This module can be used to
 generate temporary files (providing a filename and filehandle) or directories.
 Possible race conditions are avoided and some security checks are performed
 (eg making sure the sticky bit is set on world writeable temp directories).
@@ -12,8 +12,8 @@ the program exits (via an END block), this differs from the Unix
 implementation where files can be deleted when the file is closed.
 
 The object-oriented implementation can get around this problem by
-making use of the object destructor to delete the file and is the
-recommended interface.
+making use of the object destructor to delete the file or directory
+and is the recommended interface.
 
 Please let me know if it fails on other operating systems.
 
@@ -73,7 +73,7 @@ about the various security aspects.
 
 REQUIREMENTS
 
-Requires perl 5.004 or newer.
+Requires perl 5.6.0 or newer.
 Perl 5.6.0 will give access to extra security checks.
 
 Written completely in Perl. XS is not required.
@@ -86,8 +86,8 @@ PLATFORMS
 
 Tested on the following platforms:
 
- MacOSX 10.4.9, perl 5.8.7
- Linux WBEL 4, perl 5.8.7
+ MacOSX 10.5.5, perl 5.10.0
+ Linux CentOS 5.2, perl 5.8.9
 
 Earlier versions were tested on:
 
@@ -123,13 +123,64 @@ AUTHOR
 
 Tim Jenness <tjenness@cpan.org>
 
-Copyright (C) 1999 - 2007 Tim Jenness and the UK Particle Physics and
+Copyright (C) 1999 - 2008 Tim Jenness and the UK Particle Physics and
 Astronomy Research Council. All Rights Reserved.  This program is free
 software; you can redistribute it and/or modify it under the same
 terms as Perl itself.
 
 CHANGES IN THIS RELEASE
 
+V0.21
+      + Clean out $FILES_CREATED_BY_OBJECT when the destructor runs. Otherwise
+        memory does not get returned. Really bad idea for daemons.
+        (Thanks to Maxime Therreault RT #37621)
+
+      + Remove the test on the parent directory to see if a file can
+        be written. This will be found out anyway as soon as the file open
+       	is attempted. AFS systems may fail a -w test but still allow a file
+	      to be created. (thanks to Christopher Ellison)
+
+      + Put an eval around rmtree. Some versions of rmtree croak if
+        you attempt to remove a directory that you are inside. (debian bug
+	      479317 and RT #35779).
+
+      + seekable test was failing on perl 5.6.0 so we now skip the specific
+        test. (thanks to Zefram)
+
+      + Integrate patches from bleadperl for cygwin. (thanks to Jari Aalto
+        RT #36376)
+
+V0.20
+      + Fix lock.t test that was failing on some systems due to dodgy BEGIN
+         block usage (Thanks to Steve Peters and JDHEDDEN - RT #31129)
+
+V0.19
+      + Add "newdir" constructor to create a temporary directory
+        that will be deleted automatically when the object goes out
+        of scope. (RT #15733)
+
+      + tempdir now accepts a TEMPDIR flag for symmetry with tempfile
+        (debian bug #351373)
+
+      + Use of exclusive lock can now be disabled by using EXLOCK => 0
+        in constructor or tempfile() call. (RT #22702 and #28397)
+
+      + Hopefully really fixed problems with forked processes removing
+        temp files and directories created by parent (V0.18 was still broken
+        in OO interface) (RT #11067)
+
+      + "_" should now be available as a character from the random character
+	generator (RT #41345)
+
+      + Now works again with perl 5.004 (RT#26841 RT#23524)
+
+      + Error message clarified when parent directory does not exist (RT#41346)
+
+      + Fix error message in uid check (RT #14218)
+
+      + Add note concerning binmode to modify encoding of handle returned by tempfile
+        (Wolfgang Husmann)
+
 V0.18
       + overload extended to allow compare of object filename directly
         (Rafael Garcia-Suarez)
@@ -52,7 +52,9 @@ The C<_can_do_level> method should be modified accordingly.
 
   ($fh, $filename) = tempfile( $template, DIR => $dir);
   ($fh, $filename) = tempfile( $template, SUFFIX => '.dat');
+  ($fh, $filename) = tempfile( $template, TMPDIR => 1 );
 
+  binmode( $fh, ":utf8" );
 
   $dir = tempdir( CLEANUP => 1 );
   ($fh, $filename) = tempfile( DIR => $dir );
@@ -63,13 +65,13 @@ Object interface:
   use File::Temp ();
   use File::Temp qw/ :seekable /;
 
-  $fh = new File::Temp();
+  $fh = File::Temp->new();
   $fname = $fh->filename;
 
-  $fh = new File::Temp(TEMPLATE => $template);
+  $fh = File::Temp->new(TEMPLATE => $template);
   $fname = $fh->filename;
 
-  $tmp = new File::Temp( UNLINK => 0, SUFFIX => '.dat' );
+  $tmp = File::Temp->new( UNLINK => 0, SUFFIX => '.dat' );
   print $tmp "Some data\n";
   print "Filename is $tmp\n";
   $tmp->seek( 0, SEEK_END );
@@ -130,6 +132,8 @@ but should be used with caution since they return only a filename
 that was valid when function was called, so cannot guarantee
 that the file will not exist by the time the caller opens the filename.
 
+Filehandles returned by these functions support the seekable methods.
+
 =cut
 
 # 5.6.0 gives us S_IWOTH, S_IWGRP, our and auto-vivifying filehandls
@@ -140,7 +144,7 @@ use Carp;
 use File::Spec 0.8;
 use File::Path qw/ rmtree /;
 use Fcntl 1.03;
-use IO::Seekable; # For SEEK_*
+use IO::Seekable;               # For SEEK_*
 use Errno;
 require VMS::Stdio if $^O eq 'VMS';
 
@@ -149,7 +153,7 @@ require VMS::Stdio if $^O eq 'VMS';
 # us that Carp::Heavy won't load rather than an error telling us we
 # have run out of file handles. We either preload croak() or we
 # switch the calls to croak from _gettemp() to use die.
-require Carp::Heavy;
+eval { require Carp::Heavy; };
 
 # Need the Symbol package if we are running older perl
 require Symbol if $] < 5.006;
@@ -171,42 +175,42 @@ use base qw/Exporter/;
 # Export list - to allow fine tuning of export table
 
 @EXPORT_OK = qw{
-	      tempfile
-	      tempdir
-	      tmpnam
-	      tmpfile
-	      mktemp
-	      mkstemp
-	      mkstemps
-	      mkdtemp
-	      unlink0
-	      cleanup
-	      SEEK_SET
-              SEEK_CUR
-              SEEK_END
-		};
+                 tempfile
+                 tempdir
+                 tmpnam
+                 tmpfile
+                 mktemp
+                 mkstemp
+                 mkstemps
+                 mkdtemp
+                 unlink0
+                 cleanup
+                 SEEK_SET
+                 SEEK_CUR
+                 SEEK_END
+             };
 
 # Groups of functions for export
 
 %EXPORT_TAGS = (
-		'POSIX' => [qw/ tmpnam tmpfile /],
-		'mktemp' => [qw/ mktemp mkstemp mkstemps mkdtemp/],
-		'seekable' => [qw/ SEEK_SET SEEK_CUR SEEK_END /],
-	       );
+                'POSIX' => [qw/ tmpnam tmpfile /],
+                'mktemp' => [qw/ mktemp mkstemp mkstemps mkdtemp/],
+                'seekable' => [qw/ SEEK_SET SEEK_CUR SEEK_END /],
+               );
 
 # add contents of these tags to @EXPORT
 Exporter::export_tags('POSIX','mktemp','seekable');
 
 # Version number
 
-$VERSION = '0.18';
+$VERSION = '0.21';
 
 # This is a list of characters that can be used in random filenames
 
 my @CHARS = (qw/ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
-	         a b c d e f g h i j k l m n o p q r s t u v w x y z
-	         0 1 2 3 4 5 6 7 8 9 _
-	     /);
+                 a b c d e f g h i j k l m n o p q r s t u v w x y z
+                 0 1 2 3 4 5 6 7 8 9 _
+               /);
 
 # Maximum number of tries to make a temp file before failing
 
@@ -229,9 +233,10 @@ use constant HIGH     => 2;
 # us an optimisation when many temporary files are requested
 
 my $OPENFLAGS = O_CREAT | O_EXCL | O_RDWR;
+my $LOCKFLAG;
 
 unless ($^O eq 'MacOS') {
-  for my $oflag (qw/ NOFOLLOW BINARY LARGEFILE EXLOCK NOINHERIT /) {
+  for my $oflag (qw/ NOFOLLOW BINARY LARGEFILE NOINHERIT /) {
     my ($bit, $func) = (0, "Fcntl::O_" . $oflag);
     no strict 'refs';
     $OPENFLAGS |= $bit if eval {
@@ -243,6 +248,12 @@ unless ($^O eq 'MacOS') {
       1;
     };
   }
+  # Special case O_EXLOCK
+  $LOCKFLAG = eval {
+    local $SIG{__DIE__} = sub {};
+    local $SIG{__WARN__} = sub {};
+    &Fcntl::O_EXLOCK();
+  };
 }
 
 # On some systems the O_TEMPORARY flag can be used to tell the OS
@@ -256,6 +267,7 @@ my $OPENTEMPFLAGS = $OPENFLAGS;
 unless ($^O eq 'MacOS') {
   for my $oflag (qw/ TEMPORARY /) {
     my ($bit, $func) = (0, "Fcntl::O_" . $oflag);
+    local($@);
     no strict 'refs';
     $OPENTEMPFLAGS |= $bit if eval {
       # Make sure that redefined die handlers do not cause problems
@@ -268,6 +280,9 @@ unless ($^O eq 'MacOS') {
   }
 }
 
+# Private hash tracking which files have been created by each process id via the OO interface
+my %FILES_CREATED_BY_OBJECT;
+
 # INTERNAL ROUTINES - not to be used outside of package
 
 # Generic routine for getting a temporary filename
@@ -292,6 +307,7 @@ unless ($^O eq 'MacOS') {
 #                        the file as soon as it is closed. Usually indicates
 #                        use of the O_TEMPORARY flag to sysopen.
 #                        Usually irrelevant on unix
+#   "use_exlock" => Indicates that O_EXLOCK should be used. Default is true.
 
 # Optionally a reference to a scalar can be passed into the function
 # On error this will be used to store the reason for the error
@@ -324,12 +340,13 @@ sub _gettemp {
 
   # Default options
   my %options = (
-		 "open" => 0,
-		 "mkdir" => 0,
-		 "suffixlen" => 0,
-		 "unlink_on_close" => 0,
-		 "ErrStr" => \$tempErrStr,
-		);
+                 "open" => 0,
+                 "mkdir" => 0,
+                 "suffixlen" => 0,
+                 "unlink_on_close" => 0,
+                 "use_exlock" => 1,
+                 "ErrStr" => \$tempErrStr,
+                );
 
   # Read the template
   my $template = shift;
@@ -389,7 +406,7 @@ sub _gettemp {
   # or a tempfile
 
   my ($volume, $directories, $file);
-  my $parent; # parent directory
+  my $parent;                   # parent directory
   if ($options{"mkdir"}) {
     # There is no filename at the end
     ($volume, $directories, $file) = File::Spec->splitpath( $path, 1);
@@ -404,16 +421,16 @@ sub _gettemp {
       $parent = File::Spec->curdir;
     } else {
 
-      if ($^O eq 'VMS') {  # need volume to avoid relative dir spec
+      if ($^O eq 'VMS') {     # need volume to avoid relative dir spec
         $parent = File::Spec->catdir($volume, @dirs[0..$#dirs-1]);
         $parent = 'sys$disk:[]' if $parent eq '';
       } else {
 
-	# Put it back together without the last one
-	$parent = File::Spec->catdir(@dirs[0..$#dirs-1]);
+        # Put it back together without the last one
+        $parent = File::Spec->catdir(@dirs[0..$#dirs-1]);
 
-	# ...and attach the volume (no filename)
-	$parent = File::Spec->catpath($volume, $parent, '');
+        # ...and attach the volume (no filename)
+        $parent = File::Spec->catpath($volume, $parent, '');
       }
 
     }
@@ -437,15 +454,14 @@ sub _gettemp {
   # not a file -- no point returning a name that includes a directory
   # that does not exist or is not writable
 
+  unless (-e $parent) {
+    ${$options{ErrStr}} = "Parent directory ($parent) does not exist";
+    return ();
+  }
   unless (-d $parent) {
     ${$options{ErrStr}} = "Parent directory ($parent) is not a directory";
     return ();
   }
-  unless (-w $parent) {
-    ${$options{ErrStr}} = "Parent directory ($parent) is not writable\n";
-      return ();
-  }
-
 
   # Check the stickiness of the directory and chown giveaway if required
   # If the directory is world writable the sticky bit
@@ -475,7 +491,7 @@ sub _gettemp {
 
       # If we are running before perl5.6.0 we can not auto-vivify
       if ($] < 5.006) {
-	$fh = &Symbol::gensym;
+        $fh = &Symbol::gensym;
       }
 
       # Try to make sure this will be marked close-on-exec
@@ -487,52 +503,53 @@ sub _gettemp {
       my $open_success = undef;
       if ( $^O eq 'VMS' and $options{"unlink_on_close"} && !$KEEP_ALL) {
         # make it auto delete on close by setting FAB$V_DLT bit
-	$fh = VMS::Stdio::vmssysopen($path, $OPENFLAGS, 0600, 'fop=dlt');
-	$open_success = $fh;
+        $fh = VMS::Stdio::vmssysopen($path, $OPENFLAGS, 0600, 'fop=dlt');
+        $open_success = $fh;
       } else {
-	my $flags = ( ($options{"unlink_on_close"} && !$KEEP_ALL) ?
-		      $OPENTEMPFLAGS :
-		      $OPENFLAGS );
-	$open_success = sysopen($fh, $path, $flags, 0600);
+        my $flags = ( ($options{"unlink_on_close"} && !$KEEP_ALL) ?
+                      $OPENTEMPFLAGS :
+                      $OPENFLAGS );
+        $flags |= $LOCKFLAG if (defined $LOCKFLAG && $options{use_exlock});
+        $open_success = sysopen($fh, $path, $flags, 0600);
       }
       if ( $open_success ) {
 
-	# in case of odd umask force rw
-	chmod(0600, $path);
+        # in case of odd umask force rw
+        chmod(0600, $path);
 
-	# Opened successfully - return file handle and name
-	return ($fh, $path);
+        # Opened successfully - return file handle and name
+        return ($fh, $path);
 
       } else {
 
-	# Error opening file - abort with error
-	# if the reason was anything but EEXIST
-	unless ($!{EEXIST}) {
-	  ${$options{ErrStr}} = "Could not create temp file $path: $!";
-	  return ();
-	}
+        # Error opening file - abort with error
+        # if the reason was anything but EEXIST
+        unless ($!{EEXIST}) {
+          ${$options{ErrStr}} = "Could not create temp file $path: $!";
+          return ();
+        }
 
-	# Loop round for another try
+        # Loop round for another try
 
       }
     } elsif ($options{"mkdir"}) {
 
       # Open the temp directory
       if (mkdir( $path, 0700)) {
-	# in case of odd umask
-	chmod(0700, $path);
+        # in case of odd umask
+        chmod(0700, $path);
 
-	return undef, $path;
+        return undef, $path;
       } else {
 
-	# Abort with error if the reason for failure was anything
-	# except EEXIST
-	unless ($!{EEXIST}) {
-	  ${$options{ErrStr}} = "Could not create directory $path: $!";
-	  return ();
-	}
+        # Abort with error if the reason for failure was anything
+        # except EEXIST
+        unless ($!{EEXIST}) {
+          ${$options{ErrStr}} = "Could not create directory $path: $!";
+          return ();
+        }
 
-	# Loop round for another try
+        # Loop round for another try
 
       }
 
@@ -559,7 +576,7 @@ sub _gettemp {
     # attempt and make sure that none are repeated
 
     my $original = $path;
-    my $counter = 0;  # Stop infinite loop
+    my $counter = 0;            # Stop infinite loop
     my $MAX_GUESS = 50;
 
     do {
@@ -587,22 +604,6 @@ sub _gettemp {
 
 }
 
-# Internal routine to return a random character from the
-# character list. Does not do an srand() since rand()
-# will do one automatically
-
-# No arguments. Return value is the random character
-
-# No longer called since _replace_XX runs a few percent faster if
-# I inline the code. This is important if we are creating thousands of
-# temporary files.
-
-sub _randchar {
-
-  $CHARS[ int( rand( $#CHARS ) ) ];
-
-}
-
 # Internal routine to replace the XXXX... with random characters
 # This has to be done by _gettemp() every time it fails to
 # open a temp file/dir
@@ -623,11 +624,12 @@ sub _replace_XX {
   # and suffixlen=0 returns nothing if used in the substr directly
   # Alternatively, could simply set $ignore to length($path)-1
   # Don't want to always use substr when not required though.
+  my $end = ( $] >= 5.006 ? "\\z" : "\\Z" );
 
   if ($ignore) {
-    substr($path, 0, - $ignore) =~ s/X(?=X*\z)/$CHARS[ int( rand( $#CHARS ) ) ]/ge;
+    substr($path, 0, - $ignore) =~ s/X(?=X*$end)/$CHARS[ int( rand( @CHARS ) ) ]/ge;
   } else {
-    $path =~ s/X(?=X*\z)/$CHARS[ int( rand( $#CHARS ) ) ]/ge;
+    $path =~ s/X(?=X*$end)/$CHARS[ int( rand( @CHARS ) ) ]/ge;
   }
   return $path;
 }
@@ -670,16 +672,17 @@ sub _is_safe {
   unless (scalar(@info)) {
     $$err_ref = "stat(path) returned no values";
     return 0;
-  };
-  return 1 if $^O eq 'VMS';  # owner delete control at file level
+  }
+  ;
+  return 1 if $^O eq 'VMS';     # owner delete control at file level
 
   # Check to see whether owner is neither superuser (or a system uid) nor me
   # Use the effective uid from the $> variable
   # UID is in [4]
   if ($info[4] > File::Temp->top_system_uid() && $info[4] != $>) {
 
-    Carp::cluck(sprintf "uid=$info[4] topuid=%s euid=$< path='$path'",
-		File::Temp->top_system_uid());
+    Carp::cluck(sprintf "uid=$info[4] topuid=%s euid=$> path='$path'",
+                File::Temp->top_system_uid());
 
     $$err_ref = "Directory owned neither by root nor the current user"
       if ref($err_ref);
@@ -691,18 +694,18 @@ sub _is_safe {
   # use 022 to check writability
   # Do it with S_IWOTH and S_IWGRP for portability (maybe)
   # mode is in info[2]
-  if (($info[2] & &Fcntl::S_IWGRP) ||   # Is group writable?
-      ($info[2] & &Fcntl::S_IWOTH) ) {  # Is world writable?
+  if (($info[2] & &Fcntl::S_IWGRP) ||  # Is group writable?
+      ($info[2] & &Fcntl::S_IWOTH) ) { # Is world writable?
     # Must be a directory
     unless (-d $path) {
       $$err_ref = "Path ($path) is not a directory"
-      if ref($err_ref);
+        if ref($err_ref);
       return 0;
     }
     # Must have sticky bit set
     unless (-k $path) {
       $$err_ref = "Sticky bit not set on $path when dir is group|world writable"
-	if ref($err_ref);
+        if ref($err_ref);
       return 0;
     }
   }
@@ -727,12 +730,13 @@ sub _is_verysafe {
 
   my $path = shift;
   print "_is_verysafe testing $path\n" if $DEBUG;
-  return 1 if $^O eq 'VMS';  # owner delete control at file level
+  return 1 if $^O eq 'VMS';     # owner delete control at file level
 
   my $err_ref = shift;
 
   # Should Get the value of _PC_CHOWN_RESTRICTED if it is defined
   # and If it is not there do the extensive test
+  local($@);
   my $chown_restricted;
   $chown_restricted = &POSIX::_PC_CHOWN_RESTRICTED()
     if eval { &POSIX::_PC_CHOWN_RESTRICTED(); 1};
@@ -769,9 +773,9 @@ sub _is_verysafe {
   foreach my $pos (0.. $#dirs) {
     # Get a directory name
     my $dir = File::Spec->catpath($volume,
-				  File::Spec->catdir(@dirs[0.. $#dirs - $pos]),
-				  ''
-				  );
+                                  File::Spec->catdir(@dirs[0.. $#dirs - $pos]),
+                                  ''
+                                 );
 
     print "TESTING DIR $dir\n" if $DEBUG;
 
@@ -863,6 +867,7 @@ sub _can_do_level {
 
   # Set up an end block to use these arrays
   END {
+    local($., $@, $!, $^E, $?);
     cleanup();
   }
 
@@ -872,33 +877,38 @@ sub _can_do_level {
     if (!$KEEP_ALL) {
       # Files
       my @files = (exists $files_to_unlink{$$} ?
-		   @{ $files_to_unlink{$$} } : () );
+                   @{ $files_to_unlink{$$} } : () );
       foreach my $file (@files) {
-	# close the filehandle without checking its state
-	# in order to make real sure that this is closed
-	# if its already closed then I dont care about the answer
-	# probably a better way to do this
-	close($file->[0]);  # file handle is [0]
-
-	if (-f $file->[1]) {  # file name is [1]
-	  _force_writable( $file->[1] ); # for windows
-	  unlink $file->[1] or warn "Error removing ".$file->[1];
-	}
+        # close the filehandle without checking its state
+        # in order to make real sure that this is closed
+        # if its already closed then I dont care about the answer
+        # probably a better way to do this
+        close($file->[0]);      # file handle is [0]
+
+        if (-f $file->[1]) {       # file name is [1]
+          _force_writable( $file->[1] ); # for windows
+          unlink $file->[1] or warn "Error removing ".$file->[1];
+        }
       }
       # Dirs
       my @dirs = (exists $dirs_to_unlink{$$} ?
-		  @{ $dirs_to_unlink{$$} } : () );
+                  @{ $dirs_to_unlink{$$} } : () );
       foreach my $dir (@dirs) {
-	if (-d $dir) {
-	  rmtree($dir, $DEBUG, 0);
-	}
+        if (-d $dir) {
+          # Some versions of rmtree will abort if you attempt to remove
+          # the directory you are sitting in. We protect that and turn it
+          # into a warning. We do this because this occurs during
+          # cleanup and so can not be caught by the user.
+          eval { rmtree($dir, $DEBUG, 0); };
+          warn $@ if ($@ && $^W);
+        }
       }
 
       # clear the arrays
       @{ $files_to_unlink{$$} } = ()
-	if exists $files_to_unlink{$$};
+        if exists $files_to_unlink{$$};
       @{ $dirs_to_unlink{$$} } = ()
-	if exists $dirs_to_unlink{$$};
+        if exists $dirs_to_unlink{$$};
     }
   }
 
@@ -923,28 +933,28 @@ sub _can_do_level {
 
       if (-d $fname) {
 
-	# Directory exists so store it
-	# first on VMS turn []foo into [.foo] for rmtree
-	$fname = VMS::Filespec::vmspath($fname) if $^O eq 'VMS';
-	$dirs_to_unlink{$$} = [] 
-	  unless exists $dirs_to_unlink{$$};
-	push (@{ $dirs_to_unlink{$$} }, $fname);
+        # Directory exists so store it
+        # first on VMS turn []foo into [.foo] for rmtree
+        $fname = VMS::Filespec::vmspath($fname) if $^O eq 'VMS';
+        $dirs_to_unlink{$$} = [] 
+          unless exists $dirs_to_unlink{$$};
+        push (@{ $dirs_to_unlink{$$} }, $fname);
 
       } else {
-	carp "Request to remove directory $fname could not be completed since it does not exist!\n" if $^W;
+        carp "Request to remove directory $fname could not be completed since it does not exist!\n" if $^W;
       }
 
     } else {
 
       if (-f $fname) {
 
-	# file exists so store handle and name for later removal
-	$files_to_unlink{$$} = []
-	  unless exists $files_to_unlink{$$};
-	push(@{ $files_to_unlink{$$} }, [$fh, $fname]);
+        # file exists so store handle and name for later removal
+        $files_to_unlink{$$} = []
+          unless exists $files_to_unlink{$$};
+        push(@{ $files_to_unlink{$$} }, [$fh, $fname]);
 
       } else {
-	carp "Request to remove file $fname could not be completed since it is not there!\n" if $^W;
+        carp "Request to remove file $fname could not be completed since it is not there!\n" if $^W;
       }
 
     }
@@ -974,7 +984,7 @@ available.
 
 Create a temporary file object.
 
-  my $tmp = new File::Temp();
+  my $tmp = File::Temp->new();
 
 by default the object is constructed as if C<tempfile>
 was called without options, but with the additional behaviour
@@ -982,11 +992,11 @@ that the temporary file is removed by the object destructor
 if UNLINK is set to true (the default).
 
 Supported arguments are the same as for C<tempfile>: UNLINK
-(defaulting to true), DIR and SUFFIX. Additionally, the filename
+(defaulting to true), DIR, EXLOCK and SUFFIX. Additionally, the filename
 template is specified using the TEMPLATE option. The OPEN option
 is not supported (the file is always opened).
 
- $tmp = new File::Temp( TEMPLATE => 'tempXXXXX',
+ $tmp = File::Temp->new( TEMPLATE => 'tempXXXXX',
                         DIR => 'mydir',
                         SUFFIX => '.dat');
 
@@ -1008,8 +1018,8 @@ sub new {
   my $unlink = (exists $args{UNLINK} ? $args{UNLINK} : 1 );
   delete $args{UNLINK};
 
-  # template (store it in an error so that it will
-  # disappear from the arg list of tempfile
+  # template (store it in an array so that it will
+  # disappear from the arg list of tempfile)
   my @template = ( exists $args{TEMPLATE} ? $args{TEMPLATE} : () );
   delete $args{TEMPLATE};
 
@@ -1024,6 +1034,9 @@ sub new {
   # Store the filename in the scalar slot
   ${*$fh} = $path;
 
+  # Cache the filename by pid so that the destructor can decide whether to remove it
+  $FILES_CREATED_BY_OBJECT{$$}{$path} = 1;
+
   # Store unlink information in hash slot (plus other constructor info)
   %{*$fh} = %args;
 
@@ -1036,9 +1049,48 @@ sub new {
   return $fh;
 }
 
+=item B<newdir>
+
+Create a temporary directory using an object oriented interface.
+
+  $dir = File::Temp->newdir();
+
+By default the directory is deleted when the object goes out of scope.
+
+Supports the same options as the C<tempdir> function. Note that directories
+created with this method default to CLEANUP => 1.
+
+  $dir = File::Temp->newdir( $template, %options );
+
+=cut
+
+sub newdir {
+  my $self = shift;
+
+  # need to handle args as in tempdir because we have to force CLEANUP
+  # default without passing CLEANUP to tempdir
+  my $template = (scalar(@_) % 2 == 1 ? shift(@_) : undef );
+  my %options = @_;
+  my $cleanup = (exists $options{CLEANUP} ? $options{CLEANUP} : 1 );
+
+  delete $options{CLEANUP};
+
+  my $tempdir;
+  if (defined $template) {
+    $tempdir = tempdir( $template, %options );
+  } else {
+    $tempdir = tempdir( %options );
+  }
+  return bless { DIRNAME => $tempdir,
+                 CLEANUP => $cleanup,
+                 LAUNCHPID => $$,
+               }, "File::Temp::Dir";
+}
+
 =item B<filename>
 
-Return the name of the temporary file associated with this object.
+Return the name of the temporary file associated with this object
+(if the object was created using the "new" constructor).
 
   $filename = $tmp->filename;
 
@@ -1057,6 +1109,15 @@ sub STRINGIFY {
   return $self->filename;
 }
 
+=item B<dirname>
+
+Return the name of the temporary directory associated with this
+object (if the object was created using the "newdir" constructor).
+
+  $dirname = $tmpdir->dirname;
+
+This method is called automatically when the object is used in string context.
+
 =item B<unlink_on_destroy>
 
 Control whether the file is unlinked when the object goes out of scope.
@@ -1085,24 +1146,47 @@ if UNLINK is not specified).
 
 No error is given if the unlink fails.
 
-If the global variable $KEEP_ALL is true, the file will not be removed.
+If the object has been passed to a child process during a fork, the
+file will be deleted when the object goes out of scope in the parent.
+
+For a temporary directory object the directory will be removed
+unless the CLEANUP argument was used in the constructor (and set to
+false) or C<unlink_on_destroy> was modified after creation.
+
+If the global variable $KEEP_ALL is true, the file or directory
+will not be removed.
 
 =cut
 
 sub DESTROY {
+  local($., $@, $!, $^E, $?);
   my $self = shift;
+
+  # Make sure we always remove the file from the global hash
+  # on destruction. This prevents the hash from growing uncontrollably
+  # and post-destruction there is no reason to know about the file.
+  my $file = $self->filename;
+  my $was_created_by_proc;
+  if (exists $FILES_CREATED_BY_OBJECT{$$}{$file}) {
+    $was_created_by_proc = 1;
+    delete $FILES_CREATED_BY_OBJECT{$$}{$file};
+  }
+
   if (${*$self}{UNLINK} && !$KEEP_ALL) {
     print "# --------->   Unlinking $self\n" if $DEBUG;
 
+    # only delete if this process created it
+    return unless $was_created_by_proc;
+
     # The unlink1 may fail if the file has been closed
     # by the caller. This leaves us with the decision
     # of whether to refuse to remove the file or simply
     # do an unlink without test. Seems to be silly
     # to do this when we are trying to be careful
     # about security
-    _force_writable( $self->filename ); # for windows
-    unlink1( $self, $self->filename )
-      or unlink($self->filename);
+    _force_writable( $file ); # for windows
+    unlink1( $self, $file )
+      or unlink($file);
   }
 }
 
@@ -1145,6 +1229,12 @@ But see the WARNING at the end.
 Translates the template as before except that a directory name
 is specified.
 
+  ($fh, $filename) = tempfile($template, TMPDIR => 1);
+
+Equivalent to specifying a DIR of "File::Spec->tmpdir", writing the file
+into the same temporary directory as would be used if no template was
+specified at all.
+
   ($fh, $filename) = tempfile($template, UNLINK => 1);
 
 Return the filename and filehandle as before except that the file is
@@ -1163,7 +1253,7 @@ automatically generated. This temporary file is placed in tmpdir()
 (L<File::Spec>) unless a directory is specified explicitly with the
 DIR option.
 
-  $fh = tempfile( $template, DIR => $dir );
+  $fh = tempfile( DIR => $dir );
 
 If called in scalar context, only the filehandle is returned and the
 file will automatically be deleted when closed on operating systems
@@ -1186,6 +1276,16 @@ if warnings are turned on. Consider using the tmpnam()
 and mktemp() functions described elsewhere in this document
 if opening the file is not required.
 
+If the operating system supports it (for example BSD derived systems), the 
+filehandle will be opened with O_EXLOCK (open with exclusive file lock). 
+This can sometimes cause problems if the intention is to pass the filename 
+to another system that expects to take an exclusive lock itself (such as 
+DBD::SQLite) whilst ensuring that the tempfile is not reused. In this 
+situation the "EXLOCK" option can be passed to tempfile. By default EXLOCK 
+will be true (this retains compatibility with earlier releases).
+
+  ($fh, $filename) = tempfile($template, EXLOCK => 0);
+
 Options can be combined as required.
 
 Will croak() if there is an error.
@@ -1199,11 +1299,13 @@ sub tempfile {
 
   # Default options
   my %options = (
-		 "DIR"    => undef,  # Directory prefix
-                "SUFFIX" => '',     # Template suffix
-                "UNLINK" => 0,      # Do not unlink file on exit
-                "OPEN"   => 1,      # Open file
-		);
+                 "DIR"    => undef, # Directory prefix
+                 "SUFFIX" => '',    # Template suffix
+                 "UNLINK" => 0,     # Do not unlink file on exit
+                 "OPEN"   => 1,     # Open file
+                 "TMPDIR" => 0, # Place tempfile in tempdir if template specified
+                 "EXLOCK" => 1, # Open file with O_EXLOCK
+                );
 
   # Check to see whether we have an odd or even number of arguments
   my $template = (scalar(@_) % 2 == 1 ? shift(@_) : undef);
@@ -1221,8 +1323,8 @@ sub tempfile {
 
   if ($options{"DIR"} and $^O eq 'VMS') {
 
-      # on VMS turn []foo into [.foo] for concatenation
-      $options{"DIR"} = VMS::Filespec::vmspath($options{"DIR"});
+    # on VMS turn []foo into [.foo] for concatenation
+    $options{"DIR"} = VMS::Filespec::vmspath($options{"DIR"});
   }
 
   # Construct the template
@@ -1234,10 +1336,15 @@ sub tempfile {
   # First generate a template if not defined and prefix the directory
   # If no template must prefix the temp directory
   if (defined $template) {
+    # End up with current directory if neither DIR not TMPDIR are set
     if ($options{"DIR"}) {
 
       $template = File::Spec->catfile($options{"DIR"}, $template);
 
+    } elsif ($options{TMPDIR}) {
+
+      $template = File::Spec->catfile(File::Spec->tmpdir, $template );
+
     }
 
   } else {
@@ -1273,12 +1380,13 @@ sub tempfile {
   my ($fh, $path, $errstr);
   croak "Error in tempfile() using $template: $errstr"
     unless (($fh, $path) = _gettemp($template,
-				    "open" => $options{'OPEN'},
-				    "mkdir"=> 0 ,
+                                    "open" => $options{'OPEN'},
+                                    "mkdir"=> 0 ,
                                     "unlink_on_close" => $unlink_on_close,
-				    "suffixlen" => length($options{'SUFFIX'}),
-				    "ErrStr" => \$errstr,
-				   ) );
+                                    "suffixlen" => length($options{'SUFFIX'}),
+                                    "ErrStr" => \$errstr,
+                                    "use_exlock" => $options{EXLOCK},
+                                   ) );
 
   # Set up an exit handler that can do whatever is right for the
   # system. This removes files at exit when requested explicitly or when
@@ -1312,7 +1420,15 @@ sub tempfile {
 
 =item B<tempdir>
 
-This is the recommended interface for creation of temporary directories.
+This is the recommended interface for creation of temporary
+directories.  By default the directory will not be removed on exit
+(that is, it won't be temporary; this behaviour can not be changed
+because of issues with backwards compatibility). To enable removal
+either use the CLEANUP option which will trigger removal on program
+exit, or consider using the "newdir" method in the object interface which
+will allow the directory to be cleaned up when the object goes out of
+scope.
+
 The behaviour of the function depends on the arguments:
 
   $tempdir = tempdir();
@@ -1374,10 +1490,10 @@ sub tempdir  {
 
   # Default options
   my %options = (
-		 "CLEANUP"    => 0,  # Remove directory on exit
-		 "DIR"        => '', # Root directory
-		 "TMPDIR"     => 0,  # Use tempdir with template
-		);
+                 "CLEANUP"    => 0, # Remove directory on exit
+                 "DIR"        => '', # Root directory
+                 "TMPDIR"     => 0,  # Use tempdir with template
+                );
 
   # Check to see whether we have an odd or even number of arguments
   my $template = (scalar(@_) % 2 == 1 ? shift(@_) : undef );
@@ -1409,8 +1525,8 @@ sub tempdir  {
 
       } elsif ($options{TMPDIR}) {
 
-	# Prepend tmpdir
-	$template = File::Spec->catdir(File::Spec->tmpdir, $template);
+        # Prepend tmpdir
+        $template = File::Spec->catdir(File::Spec->tmpdir, $template);
 
       }
 
@@ -1433,7 +1549,7 @@ sub tempdir  {
   # Create the directory
   my $tempdir;
   my $suffixlen = 0;
-  if ($^O eq 'VMS') {  # dir names can end in delimiters
+  if ($^O eq 'VMS') {           # dir names can end in delimiters
     $template =~ m/([\.\]:>]+)$/;
     $suffixlen = length($1);
   }
@@ -1445,11 +1561,11 @@ sub tempdir  {
   my $errstr;
   croak "Error in tempdir() using $template: $errstr"
     unless ((undef, $tempdir) = _gettemp($template,
-				    "open" => 0,
-				    "mkdir"=> 1 ,
-				    "suffixlen" => $suffixlen,
-				    "ErrStr" => \$errstr,
-				   ) );
+                                         "open" => 0,
+                                         "mkdir"=> 1 ,
+                                         "suffixlen" => $suffixlen,
+                                         "ErrStr" => \$errstr,
+                                        ) );
 
   # Install exit handler; must be dynamic to get lexical
   if ( $options{'CLEANUP'} && -d $tempdir) {
@@ -1499,11 +1615,11 @@ sub mkstemp {
   my ($fh, $path, $errstr);
   croak "Error in mkstemp using $template: $errstr"
     unless (($fh, $path) = _gettemp($template,
-				    "open" => 1,
-				    "mkdir"=> 0 ,
-				    "suffixlen" => 0,
-				    "ErrStr" => \$errstr,
-				   ) );
+                                    "open" => 1,
+                                    "mkdir"=> 0 ,
+                                    "suffixlen" => 0,
+                                    "ErrStr" => \$errstr,
+                                   ) );
 
   if (wantarray()) {
     return ($fh, $path);
@@ -1544,11 +1660,11 @@ sub mkstemps {
   my ($fh, $path, $errstr);
   croak "Error in mkstemps using $template: $errstr"
     unless (($fh, $path) = _gettemp($template,
-				    "open" => 1,
-				    "mkdir"=> 0 ,
-				    "suffixlen" => length($suffix),
-				    "ErrStr" => \$errstr,
-				   ) );
+                                    "open" => 1,
+                                    "mkdir"=> 0 ,
+                                    "suffixlen" => length($suffix),
+                                    "ErrStr" => \$errstr,
+                                   ) );
 
   if (wantarray()) {
     return ($fh, $path);
@@ -1582,7 +1698,7 @@ sub mkdtemp {
 
   my $template = shift;
   my $suffixlen = 0;
-  if ($^O eq 'VMS') {  # dir names can end in delimiters
+  if ($^O eq 'VMS') {           # dir names can end in delimiters
     $template =~ m/([\.\]:>]+)$/;
     $suffixlen = length($1);
   }
@@ -1593,11 +1709,11 @@ sub mkdtemp {
   my ($junk, $tmpdir, $errstr);
   croak "Error creating temp directory from template $template\: $errstr"
     unless (($junk, $tmpdir) = _gettemp($template,
-					"open" => 0,
-					"mkdir"=> 1 ,
-					"suffixlen" => $suffixlen,
-					"ErrStr" => \$errstr,
-				       ) );
+                                        "open" => 0,
+                                        "mkdir"=> 1 ,
+                                        "suffixlen" => $suffixlen,
+                                        "ErrStr" => \$errstr,
+                                       ) );
 
   return $tmpdir;
 
@@ -1626,11 +1742,11 @@ sub mktemp {
   my ($tmpname, $junk, $errstr);
   croak "Error getting name to temp file from template $template: $errstr"
     unless (($junk, $tmpname) = _gettemp($template,
-					 "open" => 0,
-					 "mkdir"=> 0 ,
-					 "suffixlen" => 0,
-					 "ErrStr" => \$errstr,
-					 ) );
+                                         "open" => 0,
+                                         "mkdir"=> 0 ,
+                                         "suffixlen" => 0,
+                                         "ErrStr" => \$errstr,
+                                        ) );
 
   return $tmpname;
 }
@@ -1680,20 +1796,20 @@ Will croak() if there is an error.
 
 sub tmpnam {
 
-   # Retrieve the temporary directory name
-   my $tmpdir = File::Spec->tmpdir;
+  # Retrieve the temporary directory name
+  my $tmpdir = File::Spec->tmpdir;
 
-   croak "Error temporary directory is not writable"
-     if $tmpdir eq '';
+  croak "Error temporary directory is not writable"
+    if $tmpdir eq '';
 
-   # Use a ten character template and append to tmpdir
-   my $template = File::Spec->catfile($tmpdir, TEMPXXX);
+  # Use a ten character template and append to tmpdir
+  my $template = File::Spec->catfile($tmpdir, TEMPXXX);
 
-   if (wantarray() ) {
-       return mkstemp($template);
-   } else {
-       return mktemp($template);
-   }
+  if (wantarray() ) {
+    return mkstemp($template);
+  } else {
+    return mktemp($template);
+  }
 
 }
 
@@ -1939,12 +2055,12 @@ sub cmpstat {
   # depending on whether it is a file or a handle.
   # Cannot simply compare all members of the stat return
   # Select the ones we can use
-  my @okstat = (0..$#fh);  # Use all by default
+  my @okstat = (0..$#fh);       # Use all by default
   if ($^O eq 'MSWin32') {
     @okstat = (1,2,3,4,5,7,8,9,10);
   } elsif ($^O eq 'os2') {
     @okstat = (0, 2..$#fh);
-  } elsif ($^O eq 'VMS') { # device and file ID are sufficient
+  } elsif ($^O eq 'VMS') {      # device and file ID are sufficient
     @okstat = (0, 1);
   } elsif ($^O eq 'dos') {
     @okstat = (0,2..7,11..$#fh);
@@ -2045,11 +2161,10 @@ Options are:
 
 =item STANDARD
 
-Do the basic security measures to ensure the directory exists and
-is writable, that the umask() is fixed before opening of the file,
-that temporary files are opened only if they do not already exist, and
-that possible race conditions are avoided.  Finally the L<unlink0|"unlink0">
-function is used to remove files safely.
+Do the basic security measures to ensure the directory exists and is
+writable, that temporary files are opened only if they do not already
+exist, and that possible race conditions are avoided.  Finally the
+L<unlink0|"unlink0"> function is used to remove files safely.
 
 =item MEDIUM
 
@@ -2113,15 +2228,15 @@ simply examine the return value of C<safe_level>.
     if (@_) {
       my $level = shift;
       if (($level != STANDARD) && ($level != MEDIUM) && ($level != HIGH)) {
-	carp "safe_level: Specified level ($level) not STANDARD, MEDIUM or HIGH - ignoring\n" if $^W;
+        carp "safe_level: Specified level ($level) not STANDARD, MEDIUM or HIGH - ignoring\n" if $^W;
       } else {
-	# Dont allow this on perl 5.005 or earlier
-	if ($] < 5.006 && $level != STANDARD) {
-	  # Cant do MEDIUM or HIGH checks
-	  croak "Currently requires perl 5.006 or newer to do the safe checks";
-	}
-	# Check that we are allowed to change level
-	# Silently ignore if we can not.
+        # Dont allow this on perl 5.005 or earlier
+        if ($] < 5.006 && $level != STANDARD) {
+          # Cant do MEDIUM or HIGH checks
+          croak "Currently requires perl 5.006 or newer to do the safe checks";
+        }
+        # Check that we are allowed to change level
+        # Silently ignore if we can not.
         $LEVEL = $level if _can_do_level($level);
       }
     }
@@ -2234,12 +2349,21 @@ srand(EXPR) in each child else all the children will attempt to walk
 through the same set of random file names and may well cause
 themselves to give up if they exceed the number of retry attempts.
 
+=head2 Directory removal
+
+Note that if you have chdir'ed into the temporary directory and it is
+subsequently cleaned up (either in the END block or as part of object
+destruction), then you will get a warning from File::Path::rmtree().
+
 =head2 BINMODE
 
 The file returned by File::Temp will have been opened in binary mode
-if such a mode is available. If that is not correct, use the binmode()
+if such a mode is available. If that is not correct, use the C<binmode()>
 function to change the mode of the filehandle.
 
+Note that you can modify the encoding of a file opened by File::Temp
+also by using C<binmode()>.
+
 =head1 HISTORY
 
 Originally began life in May 1999 as an XS interface to the system
@@ -2256,10 +2380,14 @@ L<POSIX/tmpnam>, L<POSIX/tmpfile>, L<File::Spec>, L<File::Path>
 See L<IO::File> and L<File::MkTemp>, L<Apache::TempFile> for
 different implementations of temporary file handling.
 
+See L<File::Tempdir> for an alternative object-oriented wrapper for
+the C<tempdir> function.
+
 =head1 AUTHOR
 
 Tim Jenness E<lt>tjenness@cpan.orgE<gt>
 
+Copyright (C) 2007-2008 Tim Jenness.
 Copyright (C) 1999-2007 Tim Jenness and the UK Particle Physics and
 Astronomy Research Council. All Rights Reserved.  This program is free
 software; you can redistribute it and/or modify it under the same
@@ -2272,4 +2400,53 @@ security enhancements.
 
 =cut
 
+package File::Temp::Dir;
+
+use File::Path qw/ rmtree /;
+use strict;
+use overload '""' => "STRINGIFY", fallback => 1;
+
+# private class specifically to support tempdir objects
+# created by File::Temp->newdir
+
+# ostensibly the same method interface as File::Temp but without
+# inheriting all the IO::Seekable methods and other cruft
+
+# Read-only - returns the name of the temp directory
+
+sub dirname {
+  my $self = shift;
+  return $self->{DIRNAME};
+}
+
+sub STRINGIFY {
+  my $self = shift;
+  return $self->dirname;
+}
+
+sub unlink_on_destroy {
+  my $self = shift;
+  if (@_) {
+    $self->{CLEANUP} = shift;
+  }
+  return $self->{CLEANUP};
+}
+
+sub DESTROY {
+  my $self = shift;
+  local($., $@, $!, $^E, $?);
+  if ($self->unlink_on_destroy && 
+      $$ == $self->{LAUNCHPID} && !$File::Temp::KEEP_ALL) {
+    if (-d $self->{DIRNAME}) {
+      # Some versions of rmtree will abort if you attempt to remove
+      # the directory you are sitting in. We protect that and turn it
+      # into a warning. We do this because this occurs during object
+      # destruction and so can not be caught by the user.
+      eval { rmtree($self->{DIRNAME}, $File::Temp::DEBUG, 0); };
+      warn $@ if ($@ && $^W);
+    }
+  }
+}
+
+
 1;
@@ -0,0 +1,90 @@
+#!/usr/bin/perl
+$| = 1;
+
+# Note that because fork loses test count we do not use Test::More
+
+use strict;
+
+BEGIN { print "1..8\n"; }
+
+use File::Temp;
+
+# OO interface
+
+my $file = File::Temp->new(CLEANUP=>1);
+
+myok( 1, -f $file->filename, "OO File exists" );
+
+my $children = 2;
+for my $i (1 .. $children) {
+  my $pid = fork;
+  die "Can't fork: $!" unless defined $pid;
+  if ($pid) {
+    # parent process
+    next;
+  } else {
+    # in a child we can't keep the count properly so we do it manually
+    # make sure that child 1 dies first
+    srand();
+    my $time = (($i-1) * 5) +int(rand(5));
+    print "# child $i sleeping for $time seconds\n";
+    sleep($time);
+    my $count = $i + 1;
+    myok( $count, -f $file->filename(), "OO file present in child $i" );
+    print "# child $i exiting\n";
+    exit;
+  }
+}
+
+while ($children) {
+    wait;
+    $children--;
+}
+
+
+
+myok( 4, -f $file->filename(), "OO File exists in parent" );
+
+# non-OO interface
+
+my ($fh, $filename) = File::Temp::tempfile( CLEANUP => 1 );
+
+myok( 5, -f $filename, "non-OO File exists" );
+
+$children = 2;
+for my $i (1 .. $children) {
+  my $pid = fork;
+  die "Can't fork: $!" unless defined $pid;
+  if ($pid) {
+    # parent process
+    next;
+  } else {
+    srand();
+    my $time = (($i-1) * 5) +int(rand(5));
+    print "# child $i sleeping for $time seconds\n";
+    sleep($time);
+    my $count = 5 + $i;
+    myok( $count, -f $filename, "non-OO File present in child $i" );
+    print "# child $i exiting\n";
+    exit;
+  }
+}
+
+while ($children) {
+    wait;
+    $children--;
+}
+myok(8, -f $filename, "non-OO File exists in parent" );
+
+
+# Local ok sub handles explicit number
+sub myok {
+  my ($count, $test, $msg) = @_;
+
+  if ($test) {
+    print "ok $count - $msg\n";
+  } else {
+    print "not ok $count - $msg\n";
+  }
+  return $test;
+}
@@ -0,0 +1,60 @@
+#!perl -w
+# Test O_EXLOCK
+
+use Test::More;
+use strict;
+use Fcntl;
+
+BEGIN {
+# see if we have O_EXLOCK
+  eval { &Fcntl::O_EXLOCK; };
+  if ($@) {
+    plan skip_all => 'Do not seem to have O_EXLOCK';
+  } else {
+    plan tests => 4;
+    use_ok( "File::Temp" );
+  }
+}
+
+# Need Symbol package for lexical filehandle on older perls
+require Symbol if $] < 5.006;
+
+# Get a tempfile with O_EXLOCK
+my $fh = new File::Temp();
+ok( -e "$fh", "temp file is present" );
+
+# try to open it with a lock
+my $flags = O_CREAT | O_RDWR | O_EXLOCK;
+
+my $timeout = 5;
+my $status;
+eval {
+   local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n required
+   alarm $timeout;
+   my $newfh;
+   $newfh = &Symbol::gensym if $] < 5.006;
+   $status = sysopen($newfh, "$fh", $flags, 0600);
+   alarm 0;
+};
+if ($@) {
+   die unless $@ eq "alarm\n";   # propagate unexpected errors
+   # timed out
+}
+ok( !$status, "File $fh is locked" );
+
+# Now get a tempfile with locking disabled
+$fh = new File::Temp( EXLOCK => 0 );
+
+eval {
+   local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n required
+   alarm $timeout;
+   my $newfh;
+   $newfh = &Symbol::gensym if $] < 5.006;
+   $status = sysopen($newfh, "$fh", $flags, 0600);
+   alarm 0;
+};
+if ($@) {
+   die unless $@ eq "alarm\n";   # propagate unexpected errors
+   # timed out
+}
+ok( $status, "File $fh is not locked");
@@ -2,7 +2,7 @@
 # Test for File::Temp - OO interface
 
 use strict;
-use Test::More tests => 26;
+use Test::More tests => 30;
 use File::Spec;
 
 # Will need to check that all files were unlinked correctly
@@ -44,7 +44,22 @@ ok( (-f "$fh"), "File $fh still exists after close" );
 # Check again at exit
 push(@files, "$fh");
 
-# TEMPDIR test
+# OO tempdir
+my $tdir = File::Temp->newdir();
+my $dirname = "$tdir"; # Stringify overload
+ok( -d $dirname, "Directory $tdir exists");
+undef $tdir;
+ok( !-d $dirname, "Directory should now be gone");
+
+# Quick basic tempfile test
+my $qfh = File::Temp->new();
+my $qfname = "$qfh";
+ok (-f $qfname, "temp file exists");
+undef $qfh;
+ok( !-f $qfname, "temp file now gone");
+
+
+# TEMPDIR test as somewhere to put the temp files
 # Create temp directory in current dir
 my $template = 'tmpdirXXXXXX';
 print "# Template: $template\n";
@@ -6,7 +6,7 @@
 
 # change 'tests => 1' to 'tests => last_test_to_print';
 
-use Test::More tests => 7;
+use Test::More tests => 10;
 BEGIN { use_ok('File::Temp') };
 
 #########################
@@ -18,10 +18,17 @@ BEGIN { use_ok('File::Temp') };
 $tmp = File::Temp->new;
 isa_ok( $tmp, 'File::Temp' );
 isa_ok( $tmp, 'IO::Handle' );
-isa_ok( $tmp, 'IO::Seekable' );
+SKIP: {
+  skip "->isa is broken on 5.6.0", 1 if $] == 5.006000;
+  isa_ok( $tmp, 'IO::Seekable' );
+}
 
 # make sure the seek method is available...
-ok( File::Temp->can('seek'), 'tmp can seek' );
+# Note that we need a reasonably modern IO::Seekable
+SKIP: {
+  skip "IO::Seekable is too old", 1 if IO::Seekable->VERSION <= 1.06;
+  ok( File::Temp->can('seek'), 'tmp can seek' );
+}
 
 # make sure IO::Handle methods are still there...
 ok( File::Temp->can('print'), 'tmp can print' );
@@ -30,3 +37,7 @@ ok( File::Temp->can('print'), 'tmp can print' );
 $c = scalar @File::Temp::EXPORT;
 $l = join ' ', @File::Temp::EXPORT;
 ok( $c == 9, "really exporting $c: $l" );
+
+ok(defined eval { SEEK_SET() }, 'SEEK_SET defined by File::Temp') or diag $@;
+ok(defined eval { SEEK_END() }, 'SEEK_END defined by File::Temp') or diag $@;
+ok(defined eval { SEEK_CUR() }, 'SEEK_CUR defined by File::Temp') or diag $@;