Version 8 of Creating Temporary Files

Updated 2003-09-21 22:41:25

Purpose: Show how to create a temp file.

DL


Tcl doesn't have a built-in command to create a temporary file and there are no built-in variables for temp directories, so you have to do a little work.

Best is to figure out the temp directory separately. Then you can create multiple files in it.

 switch $tcl_platform(platform) {
    unix {
        set tmpdir /tmp   # or even $::env(TMPDIR), at times.
    } macintosh {
        set tmpdir $::env(TRASH_FOLDER)  ;# a better place?
    } default {
        set tmpdir [pwd]
        catch {set tmpdir $::env(TMP)}
        catch {set tmpdir $::env(TEMP)}
    }
 }

Ingemar Hansson - Added double colons to "env" since it isn't global declared

If you just want one temp file:

 set filename [file join $tmpdir [pid]]

If you want multiple tmpfiles, consider appending things like the application name, counter, time stamp, etc. For example:

 set file [file join $tmpdir $appname.[pid].[incr ::globalCounter]]

DKF - Or create in a subdirectory/subfolder

 if {![file exists [file join $tmpdir [pid]]]} {
    file mkdir [file join $tmpdir [pid]]
 }
 set file [file join $tmpdir [pid] [incr ::globalCounter]]

Michael Schlenker - Be aware of potential race conditions while opening temp files. The linux secure programming howto has some nice examples for the linux platform: http://www.linuxdoc.org/HOWTO/Secure-Programs-HOWTO/avoid-race.html

To be sure to get a new tempfile (and not some evil symlink) try something like:

 set access [list RDWR CREAT EXCL TRUNC]
 set perm 0600
 if {[catch {open $file $access $perm} fid ]} {
     # something went wrong 
     error "Could not open tempfile."
 } 
 # ok everything went well

I had some luck with the following procedure on a UNIX box. Maybe, somebody can check if it works for windows.

 proc tempfile {prefix suffix} {
     set chars "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
     set nrand_chars 10
     set maxtries 10
     set access [list RDWR CREAT EXCL TRUNC]
     set permission 0600
     set channel ""
     set checked_dir_writable 0
     set mypid [pid]
     for {set i 0} {$i < $maxtries} {incr i} {
         set newname $prefix
         for {set j 0} {$j < $nrand_chars} {incr j} {
             append newname [string index $chars \
                     [expr ([clock clicks] ^ $mypid) % 62]]
         }
         append newname $suffix
         if {[file exists $newname]} {
             after 1
         } else {
             if {[catch {open $newname $access $permission} channel]} {
                 if {!$checked_dir_writable} {
                     set dirname [file dirname $newname]
                     if {![file writable $dirname]} {
                         error "Directory $dirname is not writable"
                     }
                     set checked_dir_writable 1
                 }
             } else {
                 # Success
                 return [list $newname $channel]
             }
         }
     }
     if {[string compare $channel ""]} {
         error "Failed to open a temporary file: $chanel"
     } else {
         error "Failed to find an unused temporary file name"
     }
 }

Igor Volobouev


Category Security | Category Tutorial