Secure temporary file: Difference between revisions

From Rosetta Code
Content added Content deleted
m (omit TI-BASIC)
m (Fixed lang tags.)
Line 6: Line 6:
This example creates a temporary file, writes to the file, then reads from the file.
This example creates a temporary file, writes to the file, then reads from the file.


<lang ada> with Ada.Text_Io; use Ada.Text_Io;
<lang ada>with Ada.Text_Io; use Ada.Text_Io;

procedure Temp_File is
procedure Temp_File is
Temp : File_Type;
Temp : File_Type;
Contents : String(1..80);
Contents : String(1..80);
Length : Natural;
Length : Natural;
begin
begin
-- Create a temporary file
-- Create a temporary file
Create(File => Temp);
Create(File => Temp);
Put_Line(File => Temp, Item => "Hello World");
Put_Line(File => Temp, Item => "Hello World");
Reset(File => Temp, Mode => In_File);
Reset(File => Temp, Mode => In_File);
Get_Line(File => Temp, Item => Contents, Last => Length);
Get_Line(File => Temp, Item => Contents, Last => Length);
Put_Line(Contents(1..Length));
Put_Line(Contents(1..Length));
end Temp_File;</lang>
end Temp_File;</lang>


=={{header|C}}==
=={{header|C}}==
Line 79: Line 79:


=={{header|Haskell}}==
=={{header|Haskell}}==
<lang haskell>import System.IO
<pre>
import System.IO


main = do (pathOfTempFile, h) <- openTempFile "." "prefix.suffix" -- first argument is path to directory where you want to put it
main = do (pathOfTempFile, h) <- openTempFile "." "prefix.suffix" -- first argument is path to directory where you want to put it
-- do stuff with it here; "h" is the Handle to the opened file
-- do stuff with it here; "h" is the Handle to the opened file
return ()
return ()</lang>
</pre>


=={{header|Java}}==
=={{header|Java}}==
Line 104: Line 102:
=={{header|OCaml}}==
=={{header|OCaml}}==
From the module Filename, one can use the functions [http://caml.inria.fr/pub/docs/manual-ocaml/libref/Filename.html#VALtemp_file temp_file] or [http://caml.inria.fr/pub/docs/manual-ocaml/libref/Filename.html#VALopen_temp_file open_temp_file]
From the module Filename, one can use the functions [http://caml.inria.fr/pub/docs/manual-ocaml/libref/Filename.html#VALtemp_file temp_file] or [http://caml.inria.fr/pub/docs/manual-ocaml/libref/Filename.html#VALopen_temp_file open_temp_file]
<lang ocaml>
<lang ocaml># Filename.temp_file "prefix." ".suffix" ;;
# Filename.temp_file "prefix." ".suffix" ;;
- : string = "/home/blue_prawn/tmp/prefix.301f82.suffix"</lang>
- : string = "/home/blue_prawn/tmp/prefix.301f82.suffix"
</lang>


=={{header|Perl}}==
=={{header|Perl}}==
Line 140: Line 136:




>>> import tempfile
<lang python>>>> import tempfile
>>> invisible = tempfile.TemporaryFile()
>>> invisible = tempfile.TemporaryFile()
>>> invisible.name
>>> invisible.name
'<fdopen>'
'<fdopen>'
>>> visible = tempfile.NamedTemporaryFile()
>>> visible = tempfile.NamedTemporaryFile()
>>> visible.name
>>> visible.name
'/tmp/tmpZNfc_s'
'/tmp/tmpZNfc_s'
>>> visible.close()
>>> visible.close()
>>> invisible.close()
>>> invisible.close()</lang>




Line 154: Line 150:




fd, path = tempfile.mkstemp()
<lang python>fd, path = tempfile.mkstemp()
try:
try:
# use the path or the file descriptor
# use the path or the file descriptor
finally:
finally:
os.close(fd)
os.close(fd)</lang>


=={{header|Ruby}}==
=={{header|Ruby}}==
irb(main):001:0> require 'tempfile'
<lang ruby>irb(main):001:0> require 'tempfile'
=> true
=> true
irb(main):002:0> f = Tempfile.new('foo')
irb(main):002:0> f = Tempfile.new('foo')
=> #<File:/tmp/foo20081226-307-10p746n-0>
=> #<File:/tmp/foo20081226-307-10p746n-0>
irb(main):003:0> f.path
irb(main):003:0> f.path
=> "/tmp/foo20081226-307-10p746n-0"
=> "/tmp/foo20081226-307-10p746n-0"
irb(main):004:0> f.close
irb(main):004:0> f.close
=> nil
=> nil</lang>


=={{header|Standard ML}}==
=={{header|Standard ML}}==
Line 186: Line 182:
thereunder.
thereunder.


RESTOREUMASK=$(umask)
<lang bash>RESTOREUMASK=$(umask)
TRY=0
TRY=0
while :; do
while :; do
let TRY+=1 ## No spaces around += operator in let statement!
let TRY+=1 ## No spaces around += operator in let statement!
umask 0077
umask 0077
MYTMP=${TMPDIR:-/tmp}/$(basename $0).$$.$(date +%s).$TRY
MYTMP=${TMPDIR:-/tmp}/$(basename $0).$$.$(date +%s).$TRY
trap "rm -fr $MYTMP" EXIT
trap "rm -fr $MYTMP" EXIT
mkdir "$MYTMP" 2>/dev/null && break
mkdir "$MYTMP" 2>/dev/null && break
done
done
umask "$RESTOREUMASK"
umask "$RESTOREUMASK"
cd ""$MYTMP" || {
cd ""$MYTMP" || {
echo "Temporary directory failure on $MYTMP" >&2
echo "Temporary directory failure on $MYTMP" >&2
exit 1; }
exit 1; }</lang>


Note that the shell special variable $$ (the PID of the currently ''exec()''-ed shell) is unique at any given
Note that the shell special variable $$ (the PID of the currently ''exec()''-ed shell) is unique at any given

Revision as of 20:47, 19 November 2009

Task
Secure temporary file
You are encouraged to solve this task according to the task description, using any language you may know.

Create a temporary file, securely and exclusively (opening it such that there are no possible race conditions). It's fine assuming local filesystem semantics (NFS or other networking filesystems can have signficantly more complicated semantics for satisfying the "no race conditions" criteria). The function should automatically resolve name collisions and should only fail in cases where permission is denied, the filesystem is read-only or full, or similar conditions exist (returning an error or raising an exception as appropriate to the language/environment).

Ada

Ada creates a temporary file whenever the create procedure is called without file name. That temporary file is automatically deleted at the end of the program creating the file.

This example creates a temporary file, writes to the file, then reads from the file.

<lang ada>with Ada.Text_Io; use Ada.Text_Io;

procedure Temp_File is

  Temp : File_Type;
  Contents : String(1..80);
  Length : Natural;

begin

  -- Create a temporary file
  Create(File => Temp);
  Put_Line(File => Temp, Item => "Hello World");
  Reset(File => Temp, Mode => In_File);
  Get_Line(File => Temp, Item => Contents, Last => Length);
  Put_Line(Contents(1..Length));  

end Temp_File;</lang>

C

<lang c>#include <stdio.h>

int main() {

 FILE *fh = tmpfile(); /* file is automatically deleted when program exits */
 /* do stuff with stream "fh" */
 fclose(fh);
 
 /* The C standard library also has a tmpnam() function to create a file
    for you to open later. But you should not use it because someone else might
    be able to open the file from the time it is created by this function to the
    time you open it. */
 
 return 0;

}</lang>

The following

Works with: POSIX

<lang c>#include <stdlib.h>

  1. include <stdio.h>

int main() {

 char filename[] = "/tmp/prefixXXXXXX";
 int fd = mkstemp(filename);
 puts(filename);
 /* do stuff with file descriptor "fd" */
 close(fd);
 
 return 0;

}</lang>

D

Works with: Tango

<lang d>module tempfile ; import tango.io.TempFile, tango.io.Stdout ;

void main(char[][] args) {

 // create a temporary file that will be deleted automatically when out of scope
 auto tempTransient = new TempFile(TempFile.Transient) ;
 Stdout(tempTransient.path()).newline ;
 // create a temporary file, still persist after the TempFile object has been destroyed
 auto tempPermanent = new TempFile(TempFile.Permanent) ;
 Stdout(tempPermanent.path()).newline ;  
 // both can only be accessed by the current user (the program?). 

}</lang>

Groovy

Follows technique of Java example <lang groovy>def file = File.createTempFile( "xxx", ".txt" ) file.deleteOnExit() println file</lang>

Output:

C:\DOCUME~1\ROGER~1.GLO\LOCALS~1\Temp\xxx8918700806071036530.txt

Haskell

<lang haskell>import System.IO

main = do (pathOfTempFile, h) <- openTempFile "." "prefix.suffix" -- first argument is path to directory where you want to put it

         -- do stuff with it here; "h" is the Handle to the opened file
         return ()</lang>

Java

<lang java>import java.io.File;

try {

   // Create temp file
   File filename = File.createTempFile("prefix", ".suffix");
   // Delete temp file when program exits
   filename.deleteOnExit();
   System.out.println(filename);

} catch (IOException e) { }</lang>

OCaml

From the module Filename, one can use the functions temp_file or open_temp_file <lang ocaml># Filename.temp_file "prefix." ".suffix" ;; - : string = "/home/blue_prawn/tmp/prefix.301f82.suffix"</lang>

Perl

function interface: <lang perl>use File::Temp qw(tempfile); $fh = tempfile(); ($fh2, $filename) = tempfile(); # this file stays around by default print "$filename\n"; close $fh; close $fh2;</lang>

object-oriented interface: <lang perl>use File::Temp; $fh = new File::Temp; print $fh->filename, "\n"; close $fh;</lang>

PHP

<lang php>$fh = tmpfile(); // do stuff with $fh fclose($fh); // file removed when closed

// or: $filename = tempnam('/tmp', 'prefix'); echo "$filename\n"; // open $filename and do stuff with it</lang>

Python

Works with: Python version 2.3+

In both cases, the temporary file will be deleted automatically when the file is closed. The invisible file will not be accessible on UNIX-like systems. You can use os.link to preserve the visible temporary file contents.


<lang python>>>> import tempfile >>> invisible = tempfile.TemporaryFile() >>> invisible.name '<fdopen>' >>> visible = tempfile.NamedTemporaryFile() >>> visible.name '/tmp/tmpZNfc_s' >>> visible.close() >>> invisible.close()</lang>


More low level way, if you have special needs. This was the only option before Python 2.3:


<lang python>fd, path = tempfile.mkstemp() try:

   # use the path or the file descriptor

finally:

   os.close(fd)</lang>

Ruby

<lang ruby>irb(main):001:0> require 'tempfile' => true irb(main):002:0> f = Tempfile.new('foo') => #<File:/tmp/foo20081226-307-10p746n-0> irb(main):003:0> f.path => "/tmp/foo20081226-307-10p746n-0" irb(main):004:0> f.close => nil</lang>

Standard ML

<lang sml>val filename = OS.FileSys.tmpName ();</lang>

Tcl

Works with: Tcl version 8.6


Will store the name of the file in the variable filenameVar and an open read-write channel on the file in the variable chan. <lang Tcl>set chan [file tempfile filenameVar]</lang> Note that because we're asking for the filename in the script, Tcl does not automatically clean the file. (There are cases where auto-cleaning would be really unwanted.) If we hadn't asked for it, the file would be automatically deleted (at a time that depends on platform constraints).

UNIX Shell

UNIX shell scripts cannot guarantee secure, race-free, exclusive access to an open file descriptor. The best approach to working around this limitation is to create a directory (the mkdir command is a wrapper around the atomic mkdir() system call) and then perform all temporary file operations thereunder.

<lang bash>RESTOREUMASK=$(umask) TRY=0 while :; do

  let TRY+=1  ## No spaces around += operator in let statement!
  umask 0077
  MYTMP=${TMPDIR:-/tmp}/$(basename $0).$$.$(date +%s).$TRY
  trap "rm -fr $MYTMP" EXIT
  mkdir "$MYTMP" 2>/dev/null && break
  done

umask "$RESTOREUMASK" cd ""$MYTMP" || {

  echo "Temporary directory failure on $MYTMP" >&2
  exit 1; }</lang>

Note that the shell special variable $$ (the PID of the currently exec()-ed shell) is unique at any given moment on a UNIX system, and $(date +%s) gives the time represented as a number of seconds since the UNIX epoch (GNU date or any other with the %s extension). So any name collision here is most likely "enemy action." This code will loop, picking new names and resetting the trap (clean-up command) until it succeeds in making a directory. (Simple changes to the code could limit the number of attempts or implement a timeout).