summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2020-11-02 14:37:26 +0100
committerAlexander Larsson <alexl@redhat.com>2020-11-03 11:44:52 +0100
commit013417ea72aa767aec15259271ef04846070be64 (patch)
treead382749a15a56d34bc1c5e8152faaa695f4b2a3
parent1dd01d5ef172fbe7cb385c91ee2a3740962e8074 (diff)
downloadlibglnx-replace-increasing-mtime.tar.gz
Add GLNX_FILE_REPLACE_INCREASING_MTIMEreplace-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.
-rw-r--r--glnx-fdio.c44
-rw-r--r--glnx-fdio.h2
2 files changed, 37 insertions, 9 deletions
diff --git a/glnx-fdio.c b/glnx-fdio.c
index 422bc2d..d4eeb24 100644
--- a/glnx-fdio.c
+++ b/glnx-fdio.c
@@ -1105,6 +1105,11 @@ glnx_file_replace_contents_with_perms_at (int dfd,
{
char *dnbuf = strdupa (subpath);
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);
@@ -1128,34 +1133,55 @@ glnx_file_replace_contents_with_perms_at (int dfd,
if (glnx_loop_write (tmpf.fd, buf, len) < 0)
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))
return FALSE;
- if (errno == ENOENT)
- do_sync = (flags & GLNX_FILE_REPLACE_DATASYNC_NEW) > 0;
+ has_stbuf = errno != ENOENT;
+ }
+
+ if (!nodatasync)
+ {
+ gboolean do_sync;
+ if (!has_stbuf)
+ do_sync = datasync_new;
else
do_sync = TRUE;
if (do_sync)
{
- if (fdatasync (tmpf.fd) != 0)
+ if (TEMP_FAILURE_RETRY (fdatasync (tmpf.fd)) != 0)
return glnx_throw_errno_prefix (error, "fdatasync");
}
}
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");
}
- if (fchmod (tmpf.fd, mode) != 0)
+ if (TEMP_FAILURE_RETRY (fchmod (tmpf.fd, mode)) != 0)
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,
dfd, subpath, error))
return FALSE;
diff --git a/glnx-fdio.h b/glnx-fdio.h
index f95e473..cc1ed4b 100644
--- a/glnx-fdio.h
+++ b/glnx-fdio.h
@@ -143,12 +143,14 @@ glnx_file_get_contents_utf8_at (int dfd,
* GLnxFileReplaceFlags:
* @GLNX_FILE_REPLACE_DATASYNC_NEW: Call fdatasync() even if the file did not exist
* @GLNX_FILE_REPLACE_NODATASYNC: Never call fdatasync()
+ * @GLNX_FILE_REPLACE_INCREASING_MTIME: Ensure that st_mtime increases (in second precision)
*
* Flags controlling file replacement.
*/
typedef enum {
GLNX_FILE_REPLACE_DATASYNC_NEW = (1 << 0),
GLNX_FILE_REPLACE_NODATASYNC = (1 << 1),
+ GLNX_FILE_REPLACE_INCREASING_MTIME = (1 << 2),
} GLnxFileReplaceFlags;
gboolean