From: ara.t.howard@... Date: 2006-05-06T22:24:54+09:00 Subject: Re: Generate unique filenames On Sat, 6 May 2006, Robert Klemme wrote: > - tempfile ships with every ruby install > - tempfiles are guaranteed to be removed on process termination > - if you are going to need it anyway, you can as well create it > directly, remember, you can control the point in time when the > tempfile instance is created and thus when the file will be created > - tempfile is for "free" while you'll have to maintain every homegrown > solution mostly i agree with all of this. however, i've had serious issues with tempfile because this is not __quite__ true. in particular a process that dies under 'sig 9' or 'exit!' sig -9: harp:~/.mp3/kcrw > ruby -r tempfile -e' puts Tempfile.new($$.to_s){|f| f.puts $$}.path; Process.kill -9, $$ ' /tmp/2901929019.0 Killed harp:~/.mp3/kcrw > ls /tmp/2901929019.0 /tmp/2901929019.0 exit!: harp:~ > ruby -r tempfile -e' puts Tempfile.new($$.to_s){|f| f.puts $$}.path; exit! ' /tmp/2916129161.0 harp:~ > ls /tmp/2916129161.0 /tmp/2916129161.0 so you can fill up /tmp with a sick process. i now use this code as part if a method which generates a tmpdir that i use to get a clean workspace, tmpdirs are also removed after program exit, and it has a very important feature: is knows it's naming scheme and can 'clean-up' after itself. in otherwords each time i generate a tmpdir old dead ones are looked for and blown away: it impiments it's own tmpwatch. so, for most code tempfile is ok, be people should be aware that it is not 'guaranteed' to clean up after itself and it's mkdir based atomic creation is not nfs safe at all - eg. you can end up with two tempfiles with the same name on nfs. anyhow, here's a bit of the code i now use, snipped out of my personal lib (alib - on rubyforge): # # generate a temporary filename for the directory dir using seed as a basename # def tmpnam(*argv) #--{{{ args, opts = argv_split argv dirname = argv.shift || getopt(%w(dir base prefix), opts, '.') seed = getopt 'seed', opts, prognam reap = getopt 'reap', opts, true dirname = File.expand_path dirname seed = seed.gsub(%r/[^0-9a-zA-Z]/,'_').gsub(%r/\s+/, '') host = hostname.gsub(%r/\./, '_') if reap begin baseglob = "%s__*__*__*__%s" % [ host, seed ] glob = File.join(dirname, baseglob) host_re = %r/^#{ host }$/ candidates = Dir[glob] candidates.each do |candidate| basename = File.basename candidate parts = basename.split %r/__/, 5 if parts[0] =~ host_re pid = Integer parts[1] unless alive? pid FileUtils.rm_rf candidate end end end rescue => e warn(errmsg(e)) rescue nil end end basename = "%s__%s__%s__%s__%s" % [ host, Process::pid, timestamp('nospace' => true), rand, seed, ] File.join(dirname, basename) #--}}} end export 'tmpnam' this name is then combined with my lockfile lib which atomically creates files - even on nfs - to make tempfiles or tempdirs. the key is that it looks for old tempfiles and 'reaps' them iff the name indicates the file was created on this host (otherwise we cannot signal the other process to see if it's still alive). the reason i'm pointing all this out is that one could easily wrap such behaviour on top of the built-in tmpfile and it's a valid concern in 24x7 production systems which must not fill disk. regards. -a -- be kind whenever possible... it is always possible. - h.h. the 14th dali lama