There are two preferred, modern ways to make temporary files:
1. Tcl offered [file tempfile] for creating temporary files.
1. [Tcllib] provides commands for tempdir and tempfile: <
> http://tcllib.sourceforge.net/doc/fileutil.html
However this page is dedicated to ways to create temporary files by adding a bit of Tcl code, for people who target distributions older than Tcl 8.6 (not having [file tempfile]) and do not wish to depend on tcllib.
----
The temp directory is put in to different environment variables on different systems. Examples are:
Mac OS X: TMPDIR (tested on 10.8.5)
Windows 2000: TMP and TEMP (tested on Windows 2000 SP3)
CygWin: TMP and TEMP (tested on Cygwin 1.7.9)
A scriptlet to do this:
======
set tmpdir [pwd]
if {[file exists "/tmp"]} {set tmpdir "/tmp"}
catch {set tmpdir $::env(TRASH_FOLDER)} ;# very old Macintosh. Mac OS X doesn't have this.
catch {set tmpdir $::env(TMP)}
catch {set tmpdir $::env(TEMP)}
======
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://en.tldp.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
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 {int(rand() * 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: $channel"
} else {
error "Failed to find an unused temporary file name"
}
}
======
Igor Volobouev
----
[Stu] - My version of mkstemp(3)
======
proc randazAZchar {} {
return [format %c [expr {int(rand() * 26) + [expr {int(rand() * 10) > 5 ? 97 : 65}]}]]
}
proc randazAZstring {length} {
set s {}
for {set i $length} {$i > 0} {incr i -1} {append s [randazAZchar]}
return $s
}
proc makeTempFile {template} {
if {[set xi [string first "X" $template]] == -1} {
set n $template
set p {}
set rl 0
} else {
set n [string range $template 0 [expr {$xi - 1}]]
set p [pid]
set rl [expr {[string length $template] - $xi - [string length $p]}]
if {$rl < 0} {
set p [string range $p 0 end-[expr {$rl * -1}]]
set rl 0
}
}
for {set i [expr {int(pow(26, ($rl <= 6 ? $rl : 6)))}]} {$i > 0} {incr i -1} {
set fn $n[randazAZstring $rl]$p
if {![catch {open $fn {CREAT EXCL RDWR} 0600} fd]} {
file delete $fn
return $fd
}
if {[lindex $::errorCode 1] ne "EEXIST" || [lindex $::errorCode 0] ne "POSIX"} {
break
}
}
return -code error -errorcode $::errorCode $fd
}
======
----
wld
Have a look at [GUID and UUID] for generating unique filenames for temp-files.
<> Security | Tutorial | File