blob: 74922405a1b2900655a11ff56b6a6ecf2b5e8458 [file] [log] [blame]
Guido van Rossume7b146f2000-02-04 15:28:42 +00001"""Temporary files and filenames."""
2
Guido van Rossum41f95031992-03-31 19:02:01 +00003# XXX This tries to be not UNIX specific, but I don't know beans about
4# how to choose a temp directory or filename on MS-DOS or other
5# systems so it may have to be changed...
Guido van Rossumeee94981991-11-12 15:38:08 +00006
Guido van Rossum41f95031992-03-31 19:02:01 +00007import os
Guido van Rossumeee94981991-11-12 15:38:08 +00008
Skip Montanaro40fc1602001-03-01 04:27:19 +00009__all__ = ["mktemp", "TemporaryFile", "tempdir", "gettempprefix"]
10
Guido van Rossum41f95031992-03-31 19:02:01 +000011# Parameters that the caller may set to override the defaults
Guido van Rossum41f95031992-03-31 19:02:01 +000012tempdir = None
13template = None
14
Guido van Rossum41f95031992-03-31 19:02:01 +000015def gettempdir():
Guido van Rossume7b146f2000-02-04 15:28:42 +000016 """Function to calculate the directory to use."""
Guido van Rossumf4aaf861996-05-28 23:31:34 +000017 global tempdir
Guido van Rossum4033ad71996-08-08 18:33:56 +000018 if tempdir is not None:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000019 return tempdir
Tim Peters4fd5a062002-01-28 23:11:23 +000020
21 # _gettempdir_inner deduces whether a candidate temp dir is usable by
22 # trying to create a file in it, and write to it. If that succeeds,
23 # great, it closes the file and unlinks it. There's a race, though:
24 # the *name* of the test file it tries is the same across all threads
25 # under most OSes (Linux is an exception), and letting multiple threads
26 # all try to open, write to, close, and unlink a single file can cause
27 # a variety of bogus errors (e.g., you cannot unlink a file under
28 # Windows if anyone has it open, and two threads cannot create the
29 # same file in O_EXCL mode under Unix). The simplest cure is to serialize
30 # calls to _gettempdir_inner. This isn't a real expense, because the
31 # first thread to succeed sets the global tempdir, and all subsequent
32 # calls to gettempdir() reuse that without trying _gettempdir_inner.
33 _tempdir_lock.acquire()
34 try:
35 return _gettempdir_inner()
36 finally:
37 _tempdir_lock.release()
38
39def _gettempdir_inner():
40 """Function to calculate the directory to use."""
41 global tempdir
42 if tempdir is not None:
43 return tempdir
Guido van Rossum29e5f5d1998-04-09 14:27:57 +000044 try:
45 pwd = os.getcwd()
46 except (AttributeError, os.error):
47 pwd = os.curdir
Guido van Rossum7dcf84f2001-03-02 05:51:16 +000048 attempdirs = ['/tmp', '/var/tmp', '/usr/tmp', pwd]
Guido van Rossum3e065ad1996-08-20 20:38:59 +000049 if os.name == 'nt':
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000050 attempdirs.insert(0, 'C:\\TEMP')
51 attempdirs.insert(0, '\\TEMP')
Guido van Rossumf4f756c1997-04-11 19:00:53 +000052 elif os.name == 'mac':
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000053 import macfs, MACFS
54 try:
Tim Petersb90f89a2001-01-15 03:26:36 +000055 refnum, dirid = macfs.FindFolder(MACFS.kOnSystemDisk,
56 MACFS.kTemporaryFolderType, 1)
57 dirname = macfs.FSSpec((refnum, dirid, '')).as_pathname()
58 attempdirs.insert(0, dirname)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000059 except macfs.error:
60 pass
Guido van Rossume2ae77b2001-10-24 20:42:55 +000061 elif os.name == 'riscos':
62 scrapdir = os.getenv('Wimp$ScrapDir')
63 if scrapdir:
64 attempdirs.insert(0, scrapdir)
Guido van Rossumca549821997-08-12 18:00:12 +000065 for envname in 'TMPDIR', 'TEMP', 'TMP':
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000066 if os.environ.has_key(envname):
67 attempdirs.insert(0, os.environ[envname])
Guido van Rossum3e065ad1996-08-20 20:38:59 +000068 testfile = gettempprefix() + 'test'
Guido van Rossumf4aaf861996-05-28 23:31:34 +000069 for dir in attempdirs:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000070 try:
Tim Petersb90f89a2001-01-15 03:26:36 +000071 filename = os.path.join(dir, testfile)
72 if os.name == 'posix':
73 try:
Jeremy Hyltonc348cd72001-02-19 15:34:10 +000074 fd = os.open(filename,
75 os.O_RDWR | os.O_CREAT | os.O_EXCL, 0700)
Tim Petersb90f89a2001-01-15 03:26:36 +000076 except OSError:
77 pass
78 else:
79 fp = os.fdopen(fd, 'w')
80 fp.write('blat')
81 fp.close()
82 os.unlink(filename)
83 del fp, fd
84 tempdir = dir
85 break
86 else:
87 fp = open(filename, 'w')
88 fp.write('blat')
89 fp.close()
90 os.unlink(filename)
91 tempdir = dir
92 break
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000093 except IOError:
94 pass
Guido van Rossumf4aaf861996-05-28 23:31:34 +000095 if tempdir is None:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000096 msg = "Can't find a usable temporary directory amongst " + `attempdirs`
97 raise IOError, msg
Guido van Rossumf4aaf861996-05-28 23:31:34 +000098 return tempdir
Guido van Rossum41f95031992-03-31 19:02:01 +000099
100
Tim Peters9fadfb02001-01-13 03:04:02 +0000101# template caches the result of gettempprefix, for speed, when possible.
102# XXX unclear why this isn't "_template"; left it "template" for backward
103# compatibility.
104if os.name == "posix":
105 # We don't try to cache the template on posix: the pid may change on us
106 # between calls due to a fork, and on Linux the pid changes even for
107 # another thread in the same process. Since any attempt to keep the
108 # cache in synch would have to call os.getpid() anyway in order to make
109 # sure the pid hasn't changed between calls, a cache wouldn't save any
110 # time. In addition, a cache is difficult to keep correct with the pid
111 # changing willy-nilly, and earlier attempts proved buggy (races).
112 template = None
113
114# Else the pid never changes, so gettempprefix always returns the same
115# string.
116elif os.name == "nt":
117 template = '~' + `os.getpid()` + '-'
Guido van Rossume2ae77b2001-10-24 20:42:55 +0000118elif os.name in ('mac', 'riscos'):
Tim Peters9fadfb02001-01-13 03:04:02 +0000119 template = 'Python-Tmp-'
120else:
121 template = 'tmp' # XXX might choose a better one
Guido van Rossumb0e57181998-10-14 20:27:05 +0000122
Guido van Rossum41f95031992-03-31 19:02:01 +0000123def gettempprefix():
Tim Peters9fadfb02001-01-13 03:04:02 +0000124 """Function to calculate a prefix of the filename to use.
125
126 This incorporates the current process id on systems that support such a
127 notion, so that concurrent processes don't generate the same prefix.
128 """
129
Tim Peters83732182001-01-14 05:12:40 +0000130 global template
Guido van Rossumb0e57181998-10-14 20:27:05 +0000131 if template is None:
Tim Peters83732182001-01-14 05:12:40 +0000132 return '@' + `os.getpid()` + '.'
Tim Peters9fadfb02001-01-13 03:04:02 +0000133 else:
134 return template
Guido van Rossumcff34541992-01-14 18:31:56 +0000135
Guido van Rossumeee94981991-11-12 15:38:08 +0000136
Guido van Rossumb8c42c91997-12-19 04:29:50 +0000137def mktemp(suffix=""):
Guido van Rossume7b146f2000-02-04 15:28:42 +0000138 """User-callable function to return a unique temporary file name."""
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000139 dir = gettempdir()
140 pre = gettempprefix()
141 while 1:
Tim Peters1baa22a2001-01-12 10:02:46 +0000142 i = _counter.get_next()
143 file = os.path.join(dir, pre + str(i) + suffix)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000144 if not os.path.exists(file):
145 return file
Guido van Rossumca549821997-08-12 18:00:12 +0000146
147
148class TemporaryFileWrapper:
149 """Temporary file wrapper
150
151 This class provides a wrapper around files opened for temporary use.
152 In particular, it seeks to automatically remove the file when it is
153 no longer needed.
154 """
Tim Petersa255a722001-12-18 22:32:40 +0000155
156 # Cache the unlinker so we don't get spurious errors at shutdown
Tim Peters81b61bd2001-12-18 23:22:01 +0000157 # when the module-level "os" is None'd out. Note that this must
Tim Petersa255a722001-12-18 22:32:40 +0000158 # be referenced as self.unlink, because the name TemporaryFileWrapper
159 # may also get None'd out before __del__ is called.
160 unlink = os.unlink
161
Guido van Rossumca549821997-08-12 18:00:12 +0000162 def __init__(self, file, path):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000163 self.file = file
164 self.path = path
Tim Petersc57a2852001-10-29 21:46:08 +0000165 self.close_called = 0
Guido van Rossumca549821997-08-12 18:00:12 +0000166
167 def close(self):
Tim Petersc57a2852001-10-29 21:46:08 +0000168 if not self.close_called:
169 self.close_called = 1
170 self.file.close()
Tim Petersa255a722001-12-18 22:32:40 +0000171 self.unlink(self.path)
Guido van Rossumca549821997-08-12 18:00:12 +0000172
173 def __del__(self):
Tim Petersc57a2852001-10-29 21:46:08 +0000174 self.close()
Guido van Rossumca549821997-08-12 18:00:12 +0000175
176 def __getattr__(self, name):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000177 file = self.__dict__['file']
178 a = getattr(file, name)
Guido van Rossum6b708d51999-06-01 18:55:36 +0000179 if type(a) != type(0):
180 setattr(self, name, a)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000181 return a
Guido van Rossumca549821997-08-12 18:00:12 +0000182
Neil Schemenauer153cc0f2002-03-24 22:21:48 +0000183try:
184 import fcntl as _fcntl
185 def _set_cloexec(fd, flag=_fcntl.FD_CLOEXEC):
186 flags = _fcntl.fcntl(fd, _fcntl.F_GETFD, 0)
187 if flags >= 0:
188 # flags read successfully, modify
189 flags |= flag
190 _fcntl.fcntl(fd, _fcntl.F_SETFD, flags)
191except (ImportError, AttributeError):
192 def _set_cloexec(fd):
193 pass
Guido van Rossumca549821997-08-12 18:00:12 +0000194
Guido van Rossumb8c42c91997-12-19 04:29:50 +0000195def TemporaryFile(mode='w+b', bufsize=-1, suffix=""):
Guido van Rossume7b146f2000-02-04 15:28:42 +0000196 """Create and return a temporary file (opened read-write by default)."""
Guido van Rossumb8c42c91997-12-19 04:29:50 +0000197 name = mktemp(suffix)
Guido van Rossumdce3d551998-10-24 01:34:45 +0000198 if os.name == 'posix':
199 # Unix -- be very careful
200 fd = os.open(name, os.O_RDWR|os.O_CREAT|os.O_EXCL, 0700)
Neil Schemenauer153cc0f2002-03-24 22:21:48 +0000201 _set_cloexec(fd)
Guido van Rossum2457fc21998-10-24 15:02:59 +0000202 try:
203 os.unlink(name)
204 return os.fdopen(fd, mode, bufsize)
205 except:
206 os.close(fd)
207 raise
Tim Petersc7349ee2002-01-30 07:47:51 +0000208 elif os.name == 'nt':
209 # Windows -- can't unlink an open file, but O_TEMPORARY creates a
210 # file that "deletes itself" when the last handle is closed.
211 # O_NOINHERIT ensures processes created via spawn() don't get a
212 # handle to this too. That would be a security hole, and, on my
213 # Win98SE box, when an O_TEMPORARY file is inherited by a spawned
214 # process, the fd in the spawned process seems to lack the
215 # O_TEMPORARY flag, so the file doesn't go away by magic then if the
216 # spawning process closes it first.
217 flags = (os.O_RDWR | os.O_CREAT | os.O_EXCL |
218 os.O_TEMPORARY | os.O_NOINHERIT)
219 if 'b' in mode:
220 flags |= os.O_BINARY
221 fd = os.open(name, flags, 0700)
222 return os.fdopen(fd, mode, bufsize)
Guido van Rossumca549821997-08-12 18:00:12 +0000223 else:
Tim Petersc7349ee2002-01-30 07:47:51 +0000224 # Assume we can't unlink a file that's still open, or arrange for
225 # an automagically self-deleting file -- use wrapper.
Guido van Rossumdce3d551998-10-24 01:34:45 +0000226 file = open(name, mode, bufsize)
227 return TemporaryFileWrapper(file, name)
Tim Peters1baa22a2001-01-12 10:02:46 +0000228
229# In order to generate unique names, mktemp() uses _counter.get_next().
230# This returns a unique integer on each call, in a threadsafe way (i.e.,
231# multiple threads will never see the same integer). The integer will
232# usually be a Python int, but if _counter.get_next() is called often
233# enough, it will become a Python long.
Tim Peters4fd5a062002-01-28 23:11:23 +0000234# Note that the only names that survive this next block of code
235# are "_counter" and "_tempdir_lock".
Tim Peters1baa22a2001-01-12 10:02:46 +0000236
237class _ThreadSafeCounter:
238 def __init__(self, mutex, initialvalue=0):
239 self.mutex = mutex
240 self.i = initialvalue
241
242 def get_next(self):
243 self.mutex.acquire()
244 result = self.i
245 try:
246 newi = result + 1
247 except OverflowError:
248 newi = long(result) + 1
249 self.i = newi
250 self.mutex.release()
251 return result
252
253try:
254 import thread
255
256except ImportError:
257 class _DummyMutex:
258 def acquire(self):
259 pass
260
261 release = acquire
262
263 _counter = _ThreadSafeCounter(_DummyMutex())
Tim Peters40915bf2002-01-30 09:11:42 +0000264 _tempdir_lock = _DummyMutex()
Tim Peters1baa22a2001-01-12 10:02:46 +0000265 del _DummyMutex
266
267else:
268 _counter = _ThreadSafeCounter(thread.allocate_lock())
Tim Peters4fd5a062002-01-28 23:11:23 +0000269 _tempdir_lock = thread.allocate_lock()
Tim Peters1baa22a2001-01-12 10:02:46 +0000270 del thread
271
272del _ThreadSafeCounter