2 commits - src/cairoint.h src/cairo-misc.c src/cairo-ps-surface.c

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Sat Jun 8 22:20:21 UTC 2024


 src/cairo-misc.c       |   96 +++++++++++++++++++++++++++++++++++++++++++------
 src/cairo-ps-surface.c |    2 -
 src/cairoint.h         |    9 +---
 3 files changed, 90 insertions(+), 17 deletions(-)

New commits:
commit a308881018136ba8cd48cd2b051400dd047fafaf
Merge: 1193515f5 b0b5562b9
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sat Jun 8 22:20:17 2024 +0000

    Merge branch 'cloexec' into 'master'
    
    Set CLOEXEC when opening files
    
    Closes #213
    
    See merge request cairo/cairo!563

commit b0b5562b9e676a2b172df4a9d5dee78f8dec748a
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Fri Jun 7 21:09:54 2024 +0930

    Set CLOEXEC when opening files
    
    Based on the patch by Christian Persch in #213.
    
    Closes #213

diff --git a/src/cairo-misc.c b/src/cairo-misc.c
index 23e3eaf0b..59cf76fc9 100644
--- a/src/cairo-misc.c
+++ b/src/cairo-misc.c
@@ -48,6 +48,9 @@
 #ifdef HAVE_XLOCALE_H
 #include <xlocale.h>
 #endif
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
 
 COMPILE_TIME_ASSERT ((int)CAIRO_STATUS_LAST_STATUS < (int)CAIRO_INT_STATUS_UNSUPPORTED);
 COMPILE_TIME_ASSERT (CAIRO_INT_STATUS_LAST_STATUS <= 127);
@@ -956,14 +959,40 @@ _cairo_fopen (const char *filename, const char *mode, FILE **file_out)
 	return status;
     }
 
-    result = _wfopen(filename_w, mode_w);
+    result = _wfopen (filename_w, mode_w);
 
     free (filename_w);
     free (mode_w);
 
 #else /* Use fopen directly */
+
+#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 7)
+    /* Glibc 2.7 supports the "e" mode flag that opens the file with O_CLOEXEC.
+     * this avoid the race condition in the fcntl fallback below. */
+
+    char new_mode[20];
+    snprintf (new_mode, sizeof (new_mode), "%s%s", mode, "e");
+    result = fopen (filename, new_mode);
+
+#else /* fopen "e" not available */
+
     result = fopen (filename, mode);
-#endif
+
+#if defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC)
+    /* Manually set CLOEXEC */
+    if (result != NULL) {
+	int fd = fileno (result);
+	if (fd != -1) {
+	    int flags = fcntl (fd, F_GETFD);
+	    if (flags >= 0)
+		flags = fcntl (fd, F_SETFD, flags | FD_CLOEXEC);
+	}
+    }
+#endif /* defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) */
+
+#endif /* fopen "e" not available */
+
+#endif /* !_WIN32 */
 
     *file_out = result;
 
@@ -971,18 +1000,15 @@ _cairo_fopen (const char *filename, const char *mode, FILE **file_out)
 }
 
 #ifdef _WIN32
-
 #include <windows.h>
 #include <io.h>
 
-#if !_WIN32_WCE
 /* tmpfile() replacement for Windows.
  *
  * On Windows tmpfile() creates the file in the root directory. This
- * may fail due to insufficient privileges. However, this isn't a
- * problem on Windows CE so we don't use it there.
+ * may fail due to insufficient privileges.
  */
-FILE *
+static FILE *
 _cairo_win32_tmpfile (void)
 {
     DWORD path_len;
@@ -996,7 +1022,7 @@ _cairo_win32_tmpfile (void)
     if (path_len <= 0 || path_len >= MAX_PATH)
 	return NULL;
 
-    if (GetTempFileNameW (path_name, L"ps_", 0, file_name) == 0)
+    if (GetTempFileNameW (path_name, L"cairo_", 0, file_name) == 0)
 	return NULL;
 
     handle = CreateFileW (file_name,
@@ -1025,10 +1051,60 @@ _cairo_win32_tmpfile (void)
 
     return fp;
 }
-#endif /* !_WIN32_WCE */
-
 #endif /* _WIN32 */
 
+/**
+ * _cairo_tmpfile:
+ *
+ * Exactly like the C library function. On platforms that support
+ * O_CLOEXEC, the file will be opened with this flag. On Windows, the
+ * file is opened in the temp directory instead of the root directory.
+ *
+ * Return value: a file handle or NULL on error.
+ **/
+FILE *
+_cairo_tmpfile (void)
+{
+#ifdef _WIN32
+    return _cairo_win32_tmpfile ();
+#else /* !_WIN32 */
+    int fd;
+    FILE *file;
+    int flags;
+
+#ifdef O_TMPFILE
+    fd = open(P_tmpdir,
+	      O_TMPFILE | O_EXCL | O_RDWR | O_NOATIME | O_CLOEXEC,
+	      0600);
+    if (fd == -1 && errno == ENOENT) {
+	fd = open("/tmp",
+		  O_TMPFILE | O_EXCL | O_RDWR | O_NOATIME | O_CLOEXEC,
+		  0600);
+    }
+    if (fd != -1)
+	return fdopen (fd, "wb+");
+
+    /* Fallback */
+#endif /* O_TMPFILE */
+
+    file = tmpfile();
+
+#if defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC)
+    /* Manually set CLOEXEC */
+    if (file != NULL) {
+	fd = fileno(file);
+	if (fd != -1) {
+	    flags = fcntl(fd, F_GETFD);
+	    if (flags >= 0 && !(flags & FD_CLOEXEC))
+		fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
+	}
+    }
+#endif /* defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) */
+
+    return file;
+#endif /* !_WIN32 */
+}
+
 typedef struct _cairo_intern_string {
     cairo_hash_entry_t hash_entry;
     int len;
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index cdf06344d..b08955092 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -1115,7 +1115,7 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
 
     surface->final_stream = stream;
 
-    surface->tmpfile = tmpfile ();
+    surface->tmpfile = _cairo_tmpfile ();
     if (surface->tmpfile == NULL) {
 	switch (errno) {
 	case ENOMEM:
diff --git a/src/cairoint.h b/src/cairoint.h
index cac7f56d4..be1a4ba2a 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -89,12 +89,6 @@
 
 CAIRO_BEGIN_DECLS
 
-#if _WIN32 && !_WIN32_WCE /* Permissions on WinCE? No worries! */
-cairo_private FILE *
-_cairo_win32_tmpfile (void);
-#define tmpfile() _cairo_win32_tmpfile()
-#endif
-
 #undef MIN
 #define MIN(a, b) ((a) < (b) ? (a) : (b))
 
@@ -1962,6 +1956,9 @@ _cairo_observers_notify (cairo_list_t *observers, void *arg);
 cairo_private cairo_status_t
 _cairo_fopen (const char *filename, const char *mode, FILE **file_out);
 
+cairo_private FILE *
+_cairo_tmpfile (void);
+
 #include "cairo-mutex-private.h"
 #include "cairo-fixed-private.h"
 #include "cairo-wideint-private.h"


More information about the cairo-commit mailing list