blob: ef6a1c55d0f6ce4d9978aa17dbf213df07de7db7 [file] [log] [blame]
Guido van Rossum0e548712002-08-09 16:14:33 +00001"""Temporary files.
Guido van Rossume7b146f2000-02-04 15:28:42 +00002
Guido van Rossum0e548712002-08-09 16:14:33 +00003This module provides generic, low- and high-level interfaces for
4creating temporary files and directories. The interfaces listed
5as "safe" just below can be used without fear of race conditions.
6Those listed as "unsafe" cannot, and are provided for backward
7compatibility only.
Guido van Rossumeee94981991-11-12 15:38:08 +00008
Guido van Rossum0e548712002-08-09 16:14:33 +00009This module also provides some data items to the user:
Guido van Rossumeee94981991-11-12 15:38:08 +000010
Guido van Rossum0e548712002-08-09 16:14:33 +000011 TMP_MAX - maximum number of names that will be tried before
12 giving up.
13 template - the default prefix for all temporary names.
14 You may change this to control the default prefix.
15 tempdir - If this is set to a string before the first use of
16 any routine from this module, it will be considered as
17 another candidate location to store temporary files.
18"""
Skip Montanaro40fc1602001-03-01 04:27:19 +000019
Guido van Rossum0e548712002-08-09 16:14:33 +000020__all__ = [
21 "NamedTemporaryFile", "TemporaryFile", # high level safe interfaces
22 "mkstemp", "mkdtemp", # low level safe interfaces
23 "mktemp", # deprecated unsafe interface
24 "TMP_MAX", "gettempprefix", # constants
25 "tempdir", "gettempdir"
26 ]
Guido van Rossum41f95031992-03-31 19:02:01 +000027
Tim Peters4fd5a062002-01-28 23:11:23 +000028
Guido van Rossum0e548712002-08-09 16:14:33 +000029# Imports.
Tim Peters4fd5a062002-01-28 23:11:23 +000030
Guido van Rossum0e548712002-08-09 16:14:33 +000031import os as _os
32import errno as _errno
33from random import Random as _Random
34
35if _os.name == 'mac':
Jack Jansenbb829b72003-03-21 12:55:38 +000036 import Carbon.Folder as _Folder
37 import Carbon.Folders as _Folders
Guido van Rossum0e548712002-08-09 16:14:33 +000038
39try:
40 import fcntl as _fcntl
Tim Peters291f14e2003-07-22 02:50:01 +000041 # If PYTHONCASEOK is set on Windows, stinking FCNTL.py gets
42 # imported, and we don't get an ImportError then. Provoke
43 # an AttributeError instead in that case.
44 _fcntl.fcntl
45except (ImportError, AttributeError):
46 def _set_cloexec(fd):
47 pass
48else:
Guido van Rossum0e548712002-08-09 16:14:33 +000049 def _set_cloexec(fd):
Alex Martellif09994e2003-11-09 16:44:09 +000050 try: flags = _fcntl.fcntl(fd, _fcntl.F_GETFD, 0)
51 except IOError: pass
52 else:
Guido van Rossum0e548712002-08-09 16:14:33 +000053 # flags read successfully, modify
54 flags |= _fcntl.FD_CLOEXEC
55 _fcntl.fcntl(fd, _fcntl.F_SETFD, flags)
Tim Peters291f14e2003-07-22 02:50:01 +000056
Guido van Rossum0e548712002-08-09 16:14:33 +000057
58try:
59 import thread as _thread
Guido van Rossuma0934242002-12-30 22:36:09 +000060except ImportError:
61 import dummy_thread as _thread
62_allocate_lock = _thread.allocate_lock
Guido van Rossum0e548712002-08-09 16:14:33 +000063
64_text_openflags = _os.O_RDWR | _os.O_CREAT | _os.O_EXCL
Tim Petersa0d55de2002-08-09 18:01:01 +000065if hasattr(_os, 'O_NOINHERIT'):
66 _text_openflags |= _os.O_NOINHERIT
67if hasattr(_os, 'O_NOFOLLOW'):
68 _text_openflags |= _os.O_NOFOLLOW
Guido van Rossum0e548712002-08-09 16:14:33 +000069
70_bin_openflags = _text_openflags
Tim Petersa0d55de2002-08-09 18:01:01 +000071if hasattr(_os, 'O_BINARY'):
72 _bin_openflags |= _os.O_BINARY
Guido van Rossum0e548712002-08-09 16:14:33 +000073
74if hasattr(_os, 'TMP_MAX'):
75 TMP_MAX = _os.TMP_MAX
76else:
77 TMP_MAX = 10000
78
Tim Petersbd7b4c72002-08-13 23:33:56 +000079template = "tmp"
Guido van Rossum0e548712002-08-09 16:14:33 +000080
81tempdir = None
82
83# Internal routines.
84
85_once_lock = _allocate_lock()
86
Guido van Rossumb256159392003-11-10 02:16:36 +000087if hasattr(_os, "lstat"):
88 _stat = _os.lstat
89elif hasattr(_os, "stat"):
90 _stat = _os.stat
91else:
92 # Fallback. All we need is something that raises os.error if the
93 # file doesn't exist.
94 def _stat(fn):
95 try:
96 f = open(fn)
97 except IOError:
98 raise _os.error
99 f.close()
100
101def _exists(fn):
102 try:
103 _stat(fn)
104 except _os.error:
105 return False
106 else:
107 return True
108
Guido van Rossum0e548712002-08-09 16:14:33 +0000109class _RandomNameSequence:
110 """An instance of _RandomNameSequence generates an endless
111 sequence of unpredictable strings which can safely be incorporated
112 into file names. Each string is six characters long. Multiple
113 threads can safely use the same instance at the same time.
114
115 _RandomNameSequence is an iterator."""
116
Tim Peters97701b52002-11-21 15:59:59 +0000117 characters = ("abcdefghijklmnopqrstuvwxyz" +
118 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
119 "0123456789-_")
Guido van Rossum0e548712002-08-09 16:14:33 +0000120
121 def __init__(self):
122 self.mutex = _allocate_lock()
123 self.rng = _Random()
124 self.normcase = _os.path.normcase
Tim Peters97701b52002-11-21 15:59:59 +0000125
Guido van Rossum0e548712002-08-09 16:14:33 +0000126 def __iter__(self):
127 return self
128
129 def next(self):
130 m = self.mutex
131 c = self.characters
Tim Peters97701b52002-11-21 15:59:59 +0000132 choose = self.rng.choice
Guido van Rossum0e548712002-08-09 16:14:33 +0000133
Tim Peters97701b52002-11-21 15:59:59 +0000134 m.acquire()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000135 try:
Tim Peters97701b52002-11-21 15:59:59 +0000136 letters = [choose(c) for dummy in "123456"]
Guido van Rossum0e548712002-08-09 16:14:33 +0000137 finally:
138 m.release()
139
Tim Peters97701b52002-11-21 15:59:59 +0000140 return self.normcase(''.join(letters))
Guido van Rossum0e548712002-08-09 16:14:33 +0000141
142def _candidate_tempdir_list():
143 """Generate a list of candidate temporary directories which
144 _get_default_tempdir will try."""
145
146 dirlist = []
147
148 # First, try the environment.
149 for envname in 'TMPDIR', 'TEMP', 'TMP':
150 dirname = _os.getenv(envname)
151 if dirname: dirlist.append(dirname)
152
153 # Failing that, try OS-specific locations.
154 if _os.name == 'mac':
155 try:
Jack Jansenbb829b72003-03-21 12:55:38 +0000156 fsr = _Folder.FSFindFolder(_Folders.kOnSystemDisk,
157 _Folders.kTemporaryFolderType, 1)
158 dirname = fsr.as_pathname()
Guido van Rossum0e548712002-08-09 16:14:33 +0000159 dirlist.append(dirname)
Jack Jansenbb829b72003-03-21 12:55:38 +0000160 except _Folder.error:
Guido van Rossum0e548712002-08-09 16:14:33 +0000161 pass
162 elif _os.name == 'riscos':
163 dirname = _os.getenv('Wimp$ScrapDir')
164 if dirname: dirlist.append(dirname)
165 elif _os.name == 'nt':
166 dirlist.extend([ r'c:\temp', r'c:\tmp', r'\temp', r'\tmp' ])
167 else:
168 dirlist.extend([ '/tmp', '/var/tmp', '/usr/tmp' ])
169
170 # As a last resort, the current directory.
171 try:
172 dirlist.append(_os.getcwd())
173 except (AttributeError, _os.error):
174 dirlist.append(_os.curdir)
175
176 return dirlist
Tim Petersa0d55de2002-08-09 18:01:01 +0000177
Guido van Rossum0e548712002-08-09 16:14:33 +0000178def _get_default_tempdir():
179 """Calculate the default directory to use for temporary files.
Guido van Rossume888cdc2002-08-17 14:50:24 +0000180 This routine should be called exactly once.
Guido van Rossum0e548712002-08-09 16:14:33 +0000181
182 We determine whether or not a candidate temp dir is usable by
183 trying to create and write to a file in that directory. If this
184 is successful, the test file is deleted. To prevent denial of
185 service, the name of the test file must be randomized."""
186
187 namer = _RandomNameSequence()
188 dirlist = _candidate_tempdir_list()
189 flags = _text_openflags
190
191 for dir in dirlist:
192 if dir != _os.curdir:
193 dir = _os.path.normcase(_os.path.abspath(dir))
194 # Try only a few names per directory.
195 for seq in xrange(100):
196 name = namer.next()
197 filename = _os.path.join(dir, name)
198 try:
199 fd = _os.open(filename, flags, 0600)
200 fp = _os.fdopen(fd, 'w')
Tim Petersb90f89a2001-01-15 03:26:36 +0000201 fp.write('blat')
202 fp.close()
Guido van Rossum0e548712002-08-09 16:14:33 +0000203 _os.unlink(filename)
204 del fp, fd
205 return dir
206 except (OSError, IOError), e:
207 if e[0] != _errno.EEXIST:
208 break # no point trying more names in this directory
209 pass
210 raise IOError, (_errno.ENOENT,
211 ("No usable temporary directory found in %s" % dirlist))
212
Guido van Rossume888cdc2002-08-17 14:50:24 +0000213_name_sequence = None
214
Guido van Rossum0e548712002-08-09 16:14:33 +0000215def _get_candidate_names():
216 """Common setup sequence for all user-callable interfaces."""
217
Guido van Rossume888cdc2002-08-17 14:50:24 +0000218 global _name_sequence
219 if _name_sequence is None:
220 _once_lock.acquire()
221 try:
222 if _name_sequence is None:
223 _name_sequence = _RandomNameSequence()
224 finally:
225 _once_lock.release()
Guido van Rossum0e548712002-08-09 16:14:33 +0000226 return _name_sequence
Guido van Rossum41f95031992-03-31 19:02:01 +0000227
228
Guido van Rossum0e548712002-08-09 16:14:33 +0000229def _mkstemp_inner(dir, pre, suf, flags):
230 """Code common to mkstemp, TemporaryFile, and NamedTemporaryFile."""
Tim Peters9fadfb02001-01-13 03:04:02 +0000231
Guido van Rossum0e548712002-08-09 16:14:33 +0000232 names = _get_candidate_names()
233
234 for seq in xrange(TMP_MAX):
235 name = names.next()
236 file = _os.path.join(dir, pre + name + suf)
237 try:
238 fd = _os.open(file, flags, 0600)
239 _set_cloexec(fd)
Martin v. Löwisd6625482003-10-12 17:37:01 +0000240 return (fd, _os.path.abspath(file))
Guido van Rossum0e548712002-08-09 16:14:33 +0000241 except OSError, e:
242 if e.errno == _errno.EEXIST:
243 continue # try again
244 raise
245
246 raise IOError, (_errno.EEXIST, "No usable temporary file name found")
Tim Petersa0d55de2002-08-09 18:01:01 +0000247
Guido van Rossum0e548712002-08-09 16:14:33 +0000248
249# User visible interfaces.
Guido van Rossumb0e57181998-10-14 20:27:05 +0000250
Guido van Rossum41f95031992-03-31 19:02:01 +0000251def gettempprefix():
Guido van Rossum0e548712002-08-09 16:14:33 +0000252 """Accessor for tempdir.template."""
253 return template
Tim Peters9fadfb02001-01-13 03:04:02 +0000254
Guido van Rossume888cdc2002-08-17 14:50:24 +0000255tempdir = None
256
Guido van Rossum0e548712002-08-09 16:14:33 +0000257def gettempdir():
258 """Accessor for tempdir.tempdir."""
Guido van Rossume888cdc2002-08-17 14:50:24 +0000259 global tempdir
260 if tempdir is None:
261 _once_lock.acquire()
262 try:
263 if tempdir is None:
264 tempdir = _get_default_tempdir()
265 finally:
266 _once_lock.release()
Guido van Rossum0e548712002-08-09 16:14:33 +0000267 return tempdir
268
Guido van Rossume888cdc2002-08-17 14:50:24 +0000269def mkstemp(suffix="", prefix=template, dir=None, text=False):
Tim Peters04490bf2002-08-14 15:41:26 +0000270 """mkstemp([suffix, [prefix, [dir, [text]]]])
Guido van Rossum0e548712002-08-09 16:14:33 +0000271 User-callable function to create and return a unique temporary
272 file. The return value is a pair (fd, name) where fd is the
273 file descriptor returned by os.open, and name is the filename.
274
275 If 'suffix' is specified, the file name will end with that suffix,
276 otherwise there will be no suffix.
277
278 If 'prefix' is specified, the file name will begin with that prefix,
279 otherwise a default prefix is used.
280
281 If 'dir' is specified, the file will be created in that directory,
282 otherwise a default directory is used.
283
Tim Peters04490bf2002-08-14 15:41:26 +0000284 If 'text' is specified and true, the file is opened in text
285 mode. Else (the default) the file is opened in binary mode. On
286 some operating systems, this makes no difference.
Guido van Rossum0e548712002-08-09 16:14:33 +0000287
288 The file is readable and writable only by the creating user ID.
289 If the operating system uses permission bits to indicate whether a
290 file is executable, the file is executable by no one. The file
291 descriptor is not inherited by children of this process.
292
293 Caller is responsible for deleting the file when done with it.
Tim Peters9fadfb02001-01-13 03:04:02 +0000294 """
295
Guido van Rossume888cdc2002-08-17 14:50:24 +0000296 if dir is None:
297 dir = gettempdir()
298
Tim Peters04490bf2002-08-14 15:41:26 +0000299 if text:
Guido van Rossum0e548712002-08-09 16:14:33 +0000300 flags = _text_openflags
Tim Peters04490bf2002-08-14 15:41:26 +0000301 else:
302 flags = _bin_openflags
Guido van Rossum0e548712002-08-09 16:14:33 +0000303
304 return _mkstemp_inner(dir, prefix, suffix, flags)
Guido van Rossumcff34541992-01-14 18:31:56 +0000305
Guido van Rossumeee94981991-11-12 15:38:08 +0000306
Guido van Rossume888cdc2002-08-17 14:50:24 +0000307def mkdtemp(suffix="", prefix=template, dir=None):
Guido van Rossum0e548712002-08-09 16:14:33 +0000308 """mkdtemp([suffix, [prefix, [dir]]])
309 User-callable function to create and return a unique temporary
310 directory. The return value is the pathname of the directory.
311
Tim Peters04490bf2002-08-14 15:41:26 +0000312 Arguments are as for mkstemp, except that the 'text' argument is
Guido van Rossum0e548712002-08-09 16:14:33 +0000313 not accepted.
314
315 The directory is readable, writable, and searchable only by the
316 creating user.
317
318 Caller is responsible for deleting the directory when done with it.
319 """
320
Guido van Rossume888cdc2002-08-17 14:50:24 +0000321 if dir is None:
322 dir = gettempdir()
323
Guido van Rossum0e548712002-08-09 16:14:33 +0000324 names = _get_candidate_names()
Tim Petersa0d55de2002-08-09 18:01:01 +0000325
Guido van Rossum0e548712002-08-09 16:14:33 +0000326 for seq in xrange(TMP_MAX):
327 name = names.next()
328 file = _os.path.join(dir, prefix + name + suffix)
329 try:
330 _os.mkdir(file, 0700)
331 return file
332 except OSError, e:
333 if e.errno == _errno.EEXIST:
334 continue # try again
335 raise
336
337 raise IOError, (_errno.EEXIST, "No usable temporary directory name found")
338
Guido van Rossume888cdc2002-08-17 14:50:24 +0000339def mktemp(suffix="", prefix=template, dir=None):
Guido van Rossum0e548712002-08-09 16:14:33 +0000340 """mktemp([suffix, [prefix, [dir]]])
341 User-callable function to return a unique temporary file name. The
342 file is not created.
343
Tim Peters04490bf2002-08-14 15:41:26 +0000344 Arguments are as for mkstemp, except that the 'text' argument is
Guido van Rossum0e548712002-08-09 16:14:33 +0000345 not accepted.
346
347 This function is unsafe and should not be used. The file name
348 refers to a file that did not exist at some point, but by the time
349 you get around to creating it, someone else may have beaten you to
350 the punch.
351 """
352
Guido van Rossum44f602d2002-11-22 15:56:29 +0000353## from warnings import warn as _warn
354## _warn("mktemp is a potential security risk to your program",
355## RuntimeWarning, stacklevel=2)
Guido van Rossum0e548712002-08-09 16:14:33 +0000356
Guido van Rossume888cdc2002-08-17 14:50:24 +0000357 if dir is None:
358 dir = gettempdir()
359
Guido van Rossum0e548712002-08-09 16:14:33 +0000360 names = _get_candidate_names()
361 for seq in xrange(TMP_MAX):
362 name = names.next()
363 file = _os.path.join(dir, prefix + name + suffix)
Guido van Rossumb256159392003-11-10 02:16:36 +0000364 if not _exists(file):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000365 return file
Guido van Rossumca549821997-08-12 18:00:12 +0000366
Guido van Rossum0e548712002-08-09 16:14:33 +0000367 raise IOError, (_errno.EEXIST, "No usable temporary filename found")
Guido van Rossumca549821997-08-12 18:00:12 +0000368
Guido van Rossum0e548712002-08-09 16:14:33 +0000369class _TemporaryFileWrapper:
Guido van Rossumca549821997-08-12 18:00:12 +0000370 """Temporary file wrapper
371
Guido van Rossum0e548712002-08-09 16:14:33 +0000372 This class provides a wrapper around files opened for
373 temporary use. In particular, it seeks to automatically
374 remove the file when it is no longer needed.
Guido van Rossumca549821997-08-12 18:00:12 +0000375 """
Tim Petersa255a722001-12-18 22:32:40 +0000376
Guido van Rossum0e548712002-08-09 16:14:33 +0000377 def __init__(self, file, name):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000378 self.file = file
Guido van Rossum0e548712002-08-09 16:14:33 +0000379 self.name = name
Tim Peters6ef966e2002-11-21 15:48:33 +0000380 self.close_called = False
Guido van Rossumca549821997-08-12 18:00:12 +0000381
Guido van Rossumca549821997-08-12 18:00:12 +0000382 def __getattr__(self, name):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000383 file = self.__dict__['file']
384 a = getattr(file, name)
Guido van Rossum6b708d51999-06-01 18:55:36 +0000385 if type(a) != type(0):
386 setattr(self, name, a)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000387 return a
Guido van Rossumca549821997-08-12 18:00:12 +0000388
Guido van Rossum0e548712002-08-09 16:14:33 +0000389 # NT provides delete-on-close as a primitive, so we don't need
390 # the wrapper to do anything special. We still use it so that
391 # file.name is useful (i.e. not "(fdopen)") with NamedTemporaryFile.
392 if _os.name != 'nt':
Guido van Rossumca549821997-08-12 18:00:12 +0000393
Guido van Rossum0e548712002-08-09 16:14:33 +0000394 # Cache the unlinker so we don't get spurious errors at
395 # shutdown when the module-level "os" is None'd out. Note
396 # that this must be referenced as self.unlink, because the
397 # name TemporaryFileWrapper may also get None'd out before
398 # __del__ is called.
399 unlink = _os.unlink
Tim Peters1baa22a2001-01-12 10:02:46 +0000400
Guido van Rossum0e548712002-08-09 16:14:33 +0000401 def close(self):
402 if not self.close_called:
Tim Peters6ef966e2002-11-21 15:48:33 +0000403 self.close_called = True
Guido van Rossum0e548712002-08-09 16:14:33 +0000404 self.file.close()
405 self.unlink(self.name)
Tim Peters1baa22a2001-01-12 10:02:46 +0000406
Guido van Rossum0e548712002-08-09 16:14:33 +0000407 def __del__(self):
408 self.close()
Tim Peters1baa22a2001-01-12 10:02:46 +0000409
Guido van Rossum0e548712002-08-09 16:14:33 +0000410def NamedTemporaryFile(mode='w+b', bufsize=-1, suffix="",
Guido van Rossume888cdc2002-08-17 14:50:24 +0000411 prefix=template, dir=None):
Guido van Rossum0e548712002-08-09 16:14:33 +0000412 """Create and return a temporary file.
413 Arguments:
414 'prefix', 'suffix', 'dir' -- as for mkstemp.
415 'mode' -- the mode argument to os.fdopen (default "w+b").
416 'bufsize' -- the buffer size argument to os.fdopen (default -1).
417 The file is created as mkstemp() would do it.
Tim Peters1baa22a2001-01-12 10:02:46 +0000418
Guido van Rossum0e548712002-08-09 16:14:33 +0000419 Returns a file object; the name of the file is accessible as
420 file.name. The file will be automatically deleted when it is
421 closed.
422 """
Tim Peters1baa22a2001-01-12 10:02:46 +0000423
Guido van Rossume888cdc2002-08-17 14:50:24 +0000424 if dir is None:
425 dir = gettempdir()
426
Tim Petersc21ea742002-08-13 23:36:01 +0000427 if 'b' in mode:
428 flags = _bin_openflags
429 else:
430 flags = _text_openflags
Tim Peters1baa22a2001-01-12 10:02:46 +0000431
Guido van Rossum0e548712002-08-09 16:14:33 +0000432 # Setting O_TEMPORARY in the flags causes the OS to delete
433 # the file when it is closed. This is only supported by Windows.
434 if _os.name == 'nt':
435 flags |= _os.O_TEMPORARY
Tim Peters1baa22a2001-01-12 10:02:46 +0000436
Guido van Rossum0e548712002-08-09 16:14:33 +0000437 (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags)
438 file = _os.fdopen(fd, mode, bufsize)
439 return _TemporaryFileWrapper(file, name)
440
Jason Tishler80c02af2002-08-14 15:10:09 +0000441if _os.name != 'posix' or _os.sys.platform == 'cygwin':
442 # On non-POSIX and Cygwin systems, assume that we cannot unlink a file
443 # while it is open.
Guido van Rossum0e548712002-08-09 16:14:33 +0000444 TemporaryFile = NamedTemporaryFile
Tim Peters1baa22a2001-01-12 10:02:46 +0000445
446else:
Guido van Rossum0e548712002-08-09 16:14:33 +0000447 def TemporaryFile(mode='w+b', bufsize=-1, suffix="",
Guido van Rossume888cdc2002-08-17 14:50:24 +0000448 prefix=template, dir=None):
Guido van Rossum0e548712002-08-09 16:14:33 +0000449 """Create and return a temporary file.
450 Arguments:
451 'prefix', 'suffix', 'directory' -- as for mkstemp.
452 'mode' -- the mode argument to os.fdopen (default "w+b").
453 'bufsize' -- the buffer size argument to os.fdopen (default -1).
454 The file is created as mkstemp() would do it.
Tim Peters1baa22a2001-01-12 10:02:46 +0000455
Guido van Rossum0e548712002-08-09 16:14:33 +0000456 Returns a file object. The file has no name, and will cease to
457 exist when it is closed.
458 """
459
Guido van Rossume888cdc2002-08-17 14:50:24 +0000460 if dir is None:
461 dir = gettempdir()
462
Tim Petersc21ea742002-08-13 23:36:01 +0000463 if 'b' in mode:
464 flags = _bin_openflags
465 else:
466 flags = _text_openflags
Guido van Rossum0e548712002-08-09 16:14:33 +0000467
468 (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags)
469 try:
470 _os.unlink(name)
471 return _os.fdopen(fd, mode, bufsize)
472 except:
473 _os.close(fd)
474 raise