diff --git a/subprojects/libglnx/glnx-fdio.c b/subprojects/libglnx/glnx-fdio.c index 6ae6ec7e327f3cced32466d9513341bfd3600218..3fa73b5d2c18af1d2bfcc88936ca30f75bc4bb4f 100644 --- a/subprojects/libglnx/glnx-fdio.c +++ b/subprojects/libglnx/glnx-fdio.c @@ -303,8 +303,8 @@ glnx_open_anonymous_tmpfile_full (int flags, } /* A variant of `glnx_open_tmpfile_linkable_at()` which doesn't support linking. - * Useful for true temporary storage. The fd will be allocated in /var/tmp to - * ensure maximum storage space. + * Useful for true temporary storage. The fd will be allocated in `$TMPDIR` if + * set or `/var/tmp` otherwise. * * If you need the file on a specific filesystem use glnx_open_anonymous_tmpfile_full() * which lets you pass a directory. @@ -314,7 +314,10 @@ glnx_open_anonymous_tmpfile (int flags, GLnxTmpfile *out_tmpf, GError **error) { - return glnx_open_anonymous_tmpfile_full (flags, "/var/tmp", out_tmpf, error); + return glnx_open_anonymous_tmpfile_full (flags, + getenv("TMPDIR") ?: "/var/tmp", + out_tmpf, + error); } /* Use this after calling glnx_open_tmpfile_linkable_at() to give @@ -826,7 +829,7 @@ glnx_regfile_copy_bytes (int fdf, int fdt, off_t max_bytes) have_cfr = 0; try_cfr = false; } - else if (errno == EXDEV) + else if (G_IN_SET (errno, EXDEV, EOPNOTSUPP)) /* We won't try cfr again for this run, but let's be * conservative and not mark it as available/unavailable until * we know for sure. @@ -997,8 +1000,11 @@ glnx_file_copy_at (int src_dfd, if (glnx_regfile_copy_bytes (src_fd, tmp_dest.fd, (off_t) -1) < 0) return glnx_throw_errno_prefix (error, "regfile copy"); - if (fchown (tmp_dest.fd, src_stbuf->st_uid, src_stbuf->st_gid) != 0) - return glnx_throw_errno_prefix (error, "fchown"); + if (!(copyflags & GLNX_FILE_COPY_NOCHOWN)) + { + if (fchown (tmp_dest.fd, src_stbuf->st_uid, src_stbuf->st_gid) != 0) + return glnx_throw_errno_prefix (error, "fchown"); + } if (!(copyflags & GLNX_FILE_COPY_NOXATTRS)) { @@ -1102,6 +1108,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); @@ -1125,34 +1136,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/subprojects/libglnx/glnx-fdio.h b/subprojects/libglnx/glnx-fdio.h index f95e473f8cfdc65e37a1262e3d69761095597725..3d1f024cc744b55ecab9fa6edba0fa497c4e6bcf 100644 --- a/subprojects/libglnx/glnx-fdio.h +++ b/subprojects/libglnx/glnx-fdio.h @@ -43,7 +43,7 @@ G_BEGIN_DECLS static inline const char *glnx_basename (const char *path) { - gchar *base = strrchr (path, G_DIR_SEPARATOR); + const gchar *base = strrchr (path, G_DIR_SEPARATOR); if (base) return base + 1; @@ -55,7 +55,7 @@ const char *glnx_basename (const char *path) static inline void glnx_stdio_file_cleanup (void *filep) { - FILE *f = filep; + FILE *f = (FILE*)filep; if (f) fclose (f); } @@ -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 @@ -187,7 +189,8 @@ glnx_regfile_copy_bytes (int fdf, int fdt, off_t max_bytes); typedef enum { GLNX_FILE_COPY_OVERWRITE = (1 << 0), GLNX_FILE_COPY_NOXATTRS = (1 << 1), - GLNX_FILE_COPY_DATASYNC = (1 << 2) + GLNX_FILE_COPY_DATASYNC = (1 << 2), + GLNX_FILE_COPY_NOCHOWN = (1 << 3) } GLnxFileCopyFlags; gboolean diff --git a/subprojects/libglnx/glnx-macros.h b/subprojects/libglnx/glnx-macros.h index 700fc75ceed0ab1248a95e4fe03abb8b8bc6c6e9..3177bb6658dad6559b0e48950d85d677430ca19d 100644 --- a/subprojects/libglnx/glnx-macros.h +++ b/subprojects/libglnx/glnx-macros.h @@ -52,7 +52,7 @@ G_BEGIN_DECLS unsigned _i_; \ for (_i_ = 0; _i_ < G_N_ELEMENTS(_appendees_) && _appendees_[_i_]; _i_++) \ _len_ += strlen(_appendees_[_i_]); \ - _p_ = _d_ = alloca(_len_ + 1); \ + _p_ = _d_ = (char*) alloca(_len_ + 1); \ for (_i_ = 0; _i_ < G_N_ELEMENTS(_appendees_) && _appendees_[_i_]; _i_++) \ _p_ = stpcpy(_p_, _appendees_[_i_]); \ *_p_ = 0; \ @@ -136,7 +136,7 @@ G_BEGIN_DECLS guard && ({ g_hash_table_iter_init (&it, ht), TRUE; }); \ guard = FALSE) \ for (kt k; guard; guard = FALSE) \ - for (vt v; g_hash_table_iter_next (&it, (gpointer)&k, (gpointer)&v);) + for (vt v; g_hash_table_iter_next (&it, (void**)&k, (void**)&v);) /* Cleaner method to iterate over a GHashTable. I.e. rather than diff --git a/subprojects/libglnx/glnx-xattrs.c b/subprojects/libglnx/glnx-xattrs.c index 79a14cd372e29b79644abc773baf8234711d1b62..892d5343e882fee166aa7fab84626f5a079f5c03 100644 --- a/subprojects/libglnx/glnx-xattrs.c +++ b/subprojects/libglnx/glnx-xattrs.c @@ -283,7 +283,7 @@ set_all_xattrs_for_path (const char *path, const guint8* value_data = g_variant_get_fixed_array (value, &value_len, 1); if (lsetxattr (path, (char*)name, (char*)value_data, value_len, 0) < 0) - return glnx_throw_errno_prefix (error, "lsetxattr"); + return glnx_throw_errno_prefix (error, "lsetxattr(%s)", name); } return TRUE; @@ -351,7 +351,7 @@ glnx_fd_set_all_xattrs (int fd, const guint8* value_data = g_variant_get_fixed_array (value, &value_len, 1); if (TEMP_FAILURE_RETRY (fsetxattr (fd, (char*)name, (char*)value_data, value_len, 0)) < 0) - return glnx_throw_errno_prefix (error, "fsetxattr"); + return glnx_throw_errno_prefix (error, "Setting xattrs: fsetxattr(%s)", name); } return TRUE; @@ -378,11 +378,11 @@ glnx_lgetxattrat (int dfd, ssize_t bytes_read, real_size; if (TEMP_FAILURE_RETRY (bytes_read = lgetxattr (pathbuf, attribute, NULL, 0)) < 0) - return glnx_null_throw_errno_prefix (error, "lgetxattr"); + return glnx_null_throw_errno_prefix (error, "lgetxattr(%s)", attribute); g_autofree guint8 *buf = g_malloc (bytes_read); if (TEMP_FAILURE_RETRY (real_size = lgetxattr (pathbuf, attribute, buf, bytes_read)) < 0) - return glnx_null_throw_errno_prefix (error, "lgetxattr"); + return glnx_null_throw_errno_prefix (error, "lgetxattr(%s)", attribute); return g_bytes_new_take (g_steal_pointer (&buf), real_size); } @@ -403,11 +403,11 @@ glnx_fgetxattr_bytes (int fd, ssize_t bytes_read, real_size; if (TEMP_FAILURE_RETRY (bytes_read = fgetxattr (fd, attribute, NULL, 0)) < 0) - return glnx_null_throw_errno_prefix (error, "fgetxattr"); + return glnx_null_throw_errno_prefix (error, "fgetxattr(%s)", attribute); g_autofree guint8 *buf = g_malloc (bytes_read); if (TEMP_FAILURE_RETRY (real_size = fgetxattr (fd, attribute, buf, bytes_read)) < 0) - return glnx_null_throw_errno_prefix (error, "fgetxattr"); + return glnx_null_throw_errno_prefix (error, "fgetxattr(%s)", attribute); return g_bytes_new_take (g_steal_pointer (&buf), real_size); } @@ -437,7 +437,7 @@ glnx_lsetxattrat (int dfd, snprintf (pathbuf, sizeof (pathbuf), "/proc/self/fd/%d/%s", dfd, subpath); if (TEMP_FAILURE_RETRY (lsetxattr (subpath, attribute, value, len, flags)) < 0) - return glnx_throw_errno_prefix (error, "lsetxattr"); + return glnx_throw_errno_prefix (error, "lsetxattr(%s)", attribute); return TRUE; } diff --git a/subprojects/libglnx/libglnx.m4 b/subprojects/libglnx/libglnx.m4 index 5922805bc7a014812d3da44c8d5b9f3b76a5eb59..5a72e98bd077b7255c62e2a7a9ffd16744d17e6b 100644 --- a/subprojects/libglnx/libglnx.m4 +++ b/subprojects/libglnx/libglnx.m4 @@ -25,10 +25,10 @@ AS_IF([test $enable_otmpfile = yes], [], [ AC_ARG_ENABLE(wrpseudo-compat, [AS_HELP_STRING([--enable-wrpseudo-compat], - [Disable use syscall() and filesystem calls to for compatibility with wrpseudo [default=no]])],, + [Disable use of syscall() in some cases for compatibility with pseudo [default=no]])],, [enable_wrpseudo_compat=no]) AS_IF([test $enable_wrpseudo_compat = no], [], [ - AC_DEFINE([ENABLE_WRPSEUDO_COMPAT], 1, [Define if we should be compatible with wrpseudo])]) + AC_DEFINE([ENABLE_WRPSEUDO_COMPAT], 1, [Define if we should be compatible with pseudo])]) dnl end LIBGLNX_CONFIGURE ])