Correctly handle .pyc mtimes for .py files changing multiple times

If a .py file changes multiple times we can end up in a situation
where there is an .py file with corresponding .pyc file that we
rewrote, so both are now mtime==1. Then a new version of the .py file
is added, but the corresponding .pyc file is not updated. This means
that the .pyc file is stale, and python would not normally use it.
However, we will later change the mtime on the .py file to 1, causing
the old .pyo file to look up-to-date even though its stale.

We fix this by detecting the case where the is a new mtime on a .py file
where the .pyc file doesn't match, and remove the stale .pyc file.
tingping/wmclass
Alexander Larsson 2016-08-10 16:19:29 +02:00
parent 7fe93224f4
commit 006d9a1927
1 changed files with 42 additions and 12 deletions

View File

@ -1016,9 +1016,10 @@ fixup_python_timestamp (int dfd,
glnx_fd_close int fd = -1;
guint8 buffer[8];
ssize_t res;
guint32 mtime;
g_autofree char *new_path = NULL;
guint32 pyc_mtime;
g_autofree char *py_path = NULL;
struct stat stbuf;
gboolean remove_pyc = FALSE;
fd = openat (dfd_iter.fd, dent->d_name, O_RDWR | O_CLOEXEC | O_NOFOLLOW);
if (fd == -1)
@ -1040,15 +1041,12 @@ fixup_python_timestamp (int dfd,
continue;
}
mtime =
pyc_mtime =
(buffer[4] << 8*0) |
(buffer[5] << 8*1) |
(buffer[6] << 8*2) |
(buffer[7] << 8*3);
if (mtime == 1)
continue; /* Already 1 (which is what ostree checkout uses), ignore */
if (strcmp (rel_path, "__pycache__") == 0)
{
/* Python3 */
@ -1065,19 +1063,51 @@ fixup_python_timestamp (int dfd,
continue;
*dot = 0;
new_path = g_strconcat ("../", base, ".py", NULL);
py_path = g_strconcat ("../", base, ".py", NULL);
}
else
{
/* Python2 */
new_path = g_strndup (dent->d_name, strlen (dent->d_name) - 1);
py_path = g_strndup (dent->d_name, strlen (dent->d_name) - 1);
}
if (fstatat (dfd_iter.fd, new_path, &stbuf, AT_SYMLINK_NOFOLLOW) != 0)
continue;
/* Here we found a .pyc (or .pyo) file an a possible .py file that apply for it.
* There are several possible cases wrt their mtimes:
*
* py not existing: pyc is stale, remove it
* pyc mtime == 1: (.pyc is from an old commited module)
* py mtime == 1: Do nothing, already correct
* py mtime != 1: The py changed in this module, remove pyc
* pyc mtime != 1: (.pyc changed this module)
* py == 1: Shouldn't really happen, but for safety, remove pyc
* py mtime != pyc mtime: new pyc doesn't match last py written in this module, remove it
* py mtime == pyc mtime: These match, but the py will be set to mtime 1 by ostree, so update timestamp in pyc.
*/
if (stbuf.st_mtime != mtime)
continue;
if (fstatat (dfd_iter.fd, py_path, &stbuf, AT_SYMLINK_NOFOLLOW) != 0)
{
remove_pyc = TRUE;
}
else if (pyc_mtime == 1)
{
if (stbuf.st_mtime == 1)
continue; /* Previously handled pyc */
remove_pyc = TRUE;
}
else /* pyc_mtime != 1 */
{
if (pyc_mtime == stbuf.st_mtime || stbuf.st_mtime == 1)
remove_pyc = TRUE;
/* else change mtime */
}
if (remove_pyc)
{
if (unlinkat(dfd_iter.fd, dent->d_name, 0) != 0)
g_warning ("Unable to delete %s", dent->d_name);
continue;
}
/* Change to mtime 1 which is what ostree uses for checkouts */
buffer[4] = 1;