diff --git a/common/flatpak-utils.c b/common/flatpak-utils.c index cf36685c1..cd944e1e6 100644 --- a/common/flatpak-utils.c +++ b/common/flatpak-utils.c @@ -1460,6 +1460,60 @@ out: return ret; } +gboolean +flatpak_zero_mtime (int parent_dfd, + const char *rel_path, + GCancellable *cancellable, + GError **error) +{ + struct stat stbuf; + + if (TEMP_FAILURE_RETRY (fstatat (parent_dfd, rel_path, &stbuf, AT_SYMLINK_NOFOLLOW)) != 0) + { + glnx_set_error_from_errno (error); + return FALSE; + } + + if (S_ISDIR (stbuf.st_mode)) + { + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + + glnx_dirfd_iterator_init_at (parent_dfd, rel_path, FALSE, &dfd_iter, NULL); + + while (TRUE) + { + struct dirent *dent; + + if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, NULL, NULL) || dent == NULL) + break; + + if (!flatpak_zero_mtime (dfd_iter.fd, dent->d_name, + cancellable, error)) + return FALSE; + } + + /* Update stbuf */ + if (TEMP_FAILURE_RETRY (fstat (dfd_iter.fd, &stbuf)) != 0) + { + glnx_set_error_from_errno (error); + return FALSE; + } + } + + if (stbuf.st_mtime != 0) + { + const struct timespec times[2] = { { 0, UTIME_OMIT }, { 0, } }; + + if (TEMP_FAILURE_RETRY (utimensat (parent_dfd, rel_path, times, AT_SYMLINK_NOFOLLOW)) != 0) + { + glnx_set_error_from_errno (error); + return FALSE; + } + } + + return TRUE; +} + gboolean flatpak_variant_save (GFile *dest, GVariant *variant, diff --git a/common/flatpak-utils.h b/common/flatpak-utils.h index 24dfc750b..b5e1d7043 100644 --- a/common/flatpak-utils.h +++ b/common/flatpak-utils.h @@ -257,6 +257,10 @@ gboolean flatpak_cp_a (GFile *src, GCancellable *cancellable, GError **error); +gboolean flatpak_zero_mtime (int parent_dfd, + const char *rel_path, + GCancellable *cancellable, + GError **error); #define flatpak_autorm_rf _GLIB_CLEANUP (g_autoptr_cleanup_generic_gfree)