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