--- cairo-1.15.10/src/cairo-png.c.orig 2017-12-07 04:14:36.000000000 +0200 +++ cairo-1.15.10/src/cairo-png.c 2017-12-13 11:48:00.345602738 +0200 @@ -44,6 +44,10 @@ #include #include +#include +#include +#include +#include #include /** @@ -367,6 +371,9 @@ cairo_surface_write_to_png (cairo_surfac { FILE *fp; cairo_status_t status; + char *tmpfn; + size_t len; + int fd; if (surface->status) return surface->status; @@ -374,13 +381,28 @@ cairo_surface_write_to_png (cairo_surfac if (surface->finished) return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); - status = _cairo_fopen (filename, "wb", &fp); - - if (status != CAIRO_STATUS_SUCCESS) - return _cairo_error (status); + len = strlen(filename) + 13; + tmpfn = malloc(len); + if (!tmpfn) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + if (snprintf(tmpfn, len, "%s.tmp.XXXXXX", filename) >= len) { + free(tmpfn); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + fd = mkostemp(tmpfn, O_CLOEXEC); + if (fd == -1) { + free(tmpfn); + return _cairo_error (CAIRO_STATUS_WRITE_ERROR); + } + fp = fdopen (fd, "wb"); if (fp == NULL) { - switch (errno) { + int saved = errno; + + unlink(tmpfn); + free(tmpfn); + switch (saved) { case ENOMEM: return _cairo_error (CAIRO_STATUS_NO_MEMORY); default: @@ -389,9 +411,21 @@ cairo_surface_write_to_png (cairo_surfac } status = write_png (surface, stdio_write_func, fp); - - if (fclose (fp) && status == CAIRO_STATUS_SUCCESS) + if (fflush (fp) && status == CAIRO_STATUS_SUCCESS) { + unlink(tmpfn); status = _cairo_error (CAIRO_STATUS_WRITE_ERROR); + } + fchmod(fileno(fp), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fclose (fp) && status == CAIRO_STATUS_SUCCESS) { + unlink(tmpfn); + status = _cairo_error (CAIRO_STATUS_WRITE_ERROR); + } else { + if (rename (tmpfn, filename) == -1) { + unlink(tmpfn); + status = _cairo_error (CAIRO_STATUS_WRITE_ERROR); + } + } + free(tmpfn); return status; }