summaryrefslogtreecommitdiff
path: root/Python/import.c
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2011-11-15 19:15:19 +0100
committerAntoine Pitrou <solipsis@pitrou.net>2011-11-15 19:15:19 +0100
commit1a238237f0304a03e73e464b069a2a4aec4beb3c (patch)
tree0c201d34accbad136e07ca4a6966102d0f385243 /Python/import.c
parent388d73e715566576ff9021e9be17c04197592b5d (diff)
downloadcpython-1a238237f0304a03e73e464b069a2a4aec4beb3c.tar.gz
Issue #13392: Writing a pyc file should now be atomic under Windows as well.
Diffstat (limited to 'Python/import.c')
-rw-r--r--Python/import.c48
1 files changed, 38 insertions, 10 deletions
diff --git a/Python/import.c b/Python/import.c
index ae1101e4ec..3c3e504e28 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -1197,6 +1197,8 @@ write_compiled_module(PyCodeObject *co, PyObject *cpathname,
time_t mtime = srcstat->st_mtime;
#ifdef MS_WINDOWS /* since Windows uses different permissions */
mode_t mode = srcstat->st_mode & ~S_IEXEC;
+ PyObject *cpathname_tmp;
+ Py_ssize_t cpathname_len;
#else
mode_t dirmode = (srcstat->st_mode |
S_IXUSR | S_IXGRP | S_IXOTH |
@@ -1255,18 +1257,29 @@ write_compiled_module(PyCodeObject *co, PyObject *cpathname,
}
Py_DECREF(dirname);
+ /* We first write to a tmp file and then take advantage
+ of atomic renaming (which *should* be true even under Windows). */
#ifdef MS_WINDOWS
- (void)DeleteFileW(PyUnicode_AS_UNICODE(cpathname));
- fd = _wopen(PyUnicode_AS_UNICODE(cpathname),
- O_EXCL | O_CREAT | O_WRONLY | O_TRUNC | O_BINARY,
- mode);
+ cpathname_len = PyUnicode_GET_LENGTH(cpathname);
+ cpathname_tmp = PyUnicode_New(cpathname_len + 4,
+ PyUnicode_MAX_CHAR_VALUE(cpathname));
+ if (cpathname_tmp == NULL) {
+ PyErr_Clear();
+ return;
+ }
+ PyUnicode_WriteChar(cpathname_tmp, cpathname_len + 0, '.');
+ PyUnicode_WriteChar(cpathname_tmp, cpathname_len + 1, 't');
+ PyUnicode_WriteChar(cpathname_tmp, cpathname_len + 2, 'm');
+ PyUnicode_WriteChar(cpathname_tmp, cpathname_len + 3, 'p');
+ (void)DeleteFileW(PyUnicode_AS_UNICODE(cpathname_tmp));
+ fd = _wopen(PyUnicode_AS_UNICODE(cpathname_tmp),
+ O_EXCL | O_CREAT | O_WRONLY | O_BINARY,
+ mode);
if (0 <= fd)
fp = fdopen(fd, "wb");
else
fp = NULL;
#else
- /* Under POSIX, we first write to a tmp file and then take advantage
- of atomic renaming. */
cpathbytes = PyUnicode_EncodeFSDefault(cpathname);
if (cpathbytes == NULL) {
PyErr_Clear();
@@ -1294,7 +1307,9 @@ write_compiled_module(PyCodeObject *co, PyObject *cpathname,
if (Py_VerboseFlag)
PySys_FormatStderr(
"# can't create %R\n", cpathname);
-#ifndef MS_WINDOWS
+#ifdef MS_WINDOWS
+ Py_DECREF(cpathname_tmp);
+#else
Py_DECREF(cpathbytes);
Py_DECREF(cpathbytes_tmp);
#endif
@@ -1315,7 +1330,8 @@ write_compiled_module(PyCodeObject *co, PyObject *cpathname,
/* Don't keep partial file */
fclose(fp);
#ifdef MS_WINDOWS
- (void)DeleteFileW(PyUnicode_AS_UNICODE(cpathname));
+ (void)DeleteFileW(PyUnicode_AS_UNICODE(cpathname_tmp));
+ Py_DECREF(cpathname_tmp);
#else
(void) unlink(PyBytes_AS_STRING(cpathbytes_tmp));
Py_DECREF(cpathbytes);
@@ -1324,8 +1340,20 @@ write_compiled_module(PyCodeObject *co, PyObject *cpathname,
return;
}
fclose(fp);
- /* Under POSIX, do an atomic rename */
-#ifndef MS_WINDOWS
+ /* Do a (hopefully) atomic rename */
+#ifdef MS_WINDOWS
+ if (!MoveFileExW(PyUnicode_AS_UNICODE(cpathname_tmp),
+ PyUnicode_AS_UNICODE(cpathname),
+ MOVEFILE_REPLACE_EXISTING)) {
+ if (Py_VerboseFlag)
+ PySys_FormatStderr("# can't write %R\n", cpathname);
+ /* Don't keep tmp file */
+ (void) DeleteFileW(PyUnicode_AS_UNICODE(cpathname_tmp));
+ Py_DECREF(cpathname_tmp);
+ return;
+ }
+ Py_DECREF(cpathname_tmp);
+#else
if (rename(PyBytes_AS_STRING(cpathbytes_tmp),
PyBytes_AS_STRING(cpathbytes))) {
if (Py_VerboseFlag)