Skip to content
Snippets Groups Projects
Commit 013417ea authored by Alexander Larsson's avatar Alexander Larsson
Browse files

Add GLNX_FILE_REPLACE_INCREASING_MTIME

This make replaced files have a strictly increasing st_mtime. The main
usecase I have for this is to ensure the summary file mtime increases
because the flatpak tests are failing due to the python httpd used
in the tests rely on st_mtime for the http If-Modified-Since header.

For the tests this breaks all the time since we're just doing a lot of
summary updates. However, I can see this accidentally happening in the
wild too, so i think its proper to always ensure the new summary is
"newer", even though it means it will be timestamped slightly in the
future. In practice this will not happen regularly, and the times it
*does* happen we really do need it.
parent 1dd01d5e
No related branches found
No related tags found
No related merge requests found
...@@ -1105,6 +1105,11 @@ glnx_file_replace_contents_with_perms_at (int dfd, ...@@ -1105,6 +1105,11 @@ glnx_file_replace_contents_with_perms_at (int dfd,
{ {
char *dnbuf = strdupa (subpath); char *dnbuf = strdupa (subpath);
const char *dn = dirname (dnbuf); const char *dn = dirname (dnbuf);
gboolean increasing_mtime = (flags & GLNX_FILE_REPLACE_INCREASING_MTIME) != 0;
gboolean nodatasync = (flags & GLNX_FILE_REPLACE_NODATASYNC) != 0;
gboolean datasync_new = (flags & GLNX_FILE_REPLACE_DATASYNC_NEW) != 0;
struct stat stbuf;
gboolean has_stbuf = FALSE;
dfd = glnx_dirfd_canonicalize (dfd); dfd = glnx_dirfd_canonicalize (dfd);
...@@ -1128,34 +1133,55 @@ glnx_file_replace_contents_with_perms_at (int dfd, ...@@ -1128,34 +1133,55 @@ glnx_file_replace_contents_with_perms_at (int dfd,
if (glnx_loop_write (tmpf.fd, buf, len) < 0) if (glnx_loop_write (tmpf.fd, buf, len) < 0)
return glnx_throw_errno_prefix (error, "write"); return glnx_throw_errno_prefix (error, "write");
if (!(flags & GLNX_FILE_REPLACE_NODATASYNC)) if (!nodatasync || increasing_mtime)
{ {
struct stat stbuf;
gboolean do_sync;
if (!glnx_fstatat_allow_noent (dfd, subpath, &stbuf, AT_SYMLINK_NOFOLLOW, error)) if (!glnx_fstatat_allow_noent (dfd, subpath, &stbuf, AT_SYMLINK_NOFOLLOW, error))
return FALSE; return FALSE;
if (errno == ENOENT) has_stbuf = errno != ENOENT;
do_sync = (flags & GLNX_FILE_REPLACE_DATASYNC_NEW) > 0; }
if (!nodatasync)
{
gboolean do_sync;
if (!has_stbuf)
do_sync = datasync_new;
else else
do_sync = TRUE; do_sync = TRUE;
if (do_sync) if (do_sync)
{ {
if (fdatasync (tmpf.fd) != 0) if (TEMP_FAILURE_RETRY (fdatasync (tmpf.fd)) != 0)
return glnx_throw_errno_prefix (error, "fdatasync"); return glnx_throw_errno_prefix (error, "fdatasync");
} }
} }
if (uid != (uid_t) -1) if (uid != (uid_t) -1)
{ {
if (fchown (tmpf.fd, uid, gid) != 0) if (TEMP_FAILURE_RETRY (fchown (tmpf.fd, uid, gid)) != 0)
return glnx_throw_errno_prefix (error, "fchown"); return glnx_throw_errno_prefix (error, "fchown");
} }
if (fchmod (tmpf.fd, mode) != 0) if (TEMP_FAILURE_RETRY (fchmod (tmpf.fd, mode)) != 0)
return glnx_throw_errno_prefix (error, "fchmod"); return glnx_throw_errno_prefix (error, "fchmod");
if (increasing_mtime && has_stbuf)
{
struct stat fd_stbuf;
if (fstat (tmpf.fd, &fd_stbuf) != 0)
return glnx_throw_errno_prefix (error, "fstat");
/* We want to ensure that the new file has a st_mtime (i.e. the second precision)
* is incrementing to avoid mtime check issues when files change often.
*/
if (fd_stbuf.st_mtime <= stbuf.st_mtime)
{
struct timespec ts[2] = { {0, UTIME_OMIT}, {stbuf.st_mtime + 1, 0} };
if (TEMP_FAILURE_RETRY (futimens (tmpf.fd, ts)) != 0)
return glnx_throw_errno_prefix (error, "futimens");
}
}
if (!glnx_link_tmpfile_at (&tmpf, GLNX_LINK_TMPFILE_REPLACE, if (!glnx_link_tmpfile_at (&tmpf, GLNX_LINK_TMPFILE_REPLACE,
dfd, subpath, error)) dfd, subpath, error))
return FALSE; return FALSE;
......
...@@ -143,12 +143,14 @@ glnx_file_get_contents_utf8_at (int dfd, ...@@ -143,12 +143,14 @@ glnx_file_get_contents_utf8_at (int dfd,
* GLnxFileReplaceFlags: * GLnxFileReplaceFlags:
* @GLNX_FILE_REPLACE_DATASYNC_NEW: Call fdatasync() even if the file did not exist * @GLNX_FILE_REPLACE_DATASYNC_NEW: Call fdatasync() even if the file did not exist
* @GLNX_FILE_REPLACE_NODATASYNC: Never call fdatasync() * @GLNX_FILE_REPLACE_NODATASYNC: Never call fdatasync()
* @GLNX_FILE_REPLACE_INCREASING_MTIME: Ensure that st_mtime increases (in second precision)
* *
* Flags controlling file replacement. * Flags controlling file replacement.
*/ */
typedef enum { typedef enum {
GLNX_FILE_REPLACE_DATASYNC_NEW = (1 << 0), GLNX_FILE_REPLACE_DATASYNC_NEW = (1 << 0),
GLNX_FILE_REPLACE_NODATASYNC = (1 << 1), GLNX_FILE_REPLACE_NODATASYNC = (1 << 1),
GLNX_FILE_REPLACE_INCREASING_MTIME = (1 << 2),
} GLnxFileReplaceFlags; } GLnxFileReplaceFlags;
gboolean gboolean
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment