--- ./src/cairo-png.c.orig 2012-03-29 13:05:32.000000000 +0300 +++ ./src/cairo-png.c 2012-07-14 18:08:06.163286064 +0300 @@ -44,6 +44,10 @@ #include #include +#include +#include +#include +#include #include /** @@ -359,6 +363,9 @@ { FILE *fp; cairo_status_t status; + char *tmpfn; + size_t len; + int fd; if (surface->status) return surface->status; @@ -366,9 +373,28 @@ if (surface->finished) return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); - fp = fopen (filename, "wb"); + 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: @@ -377,9 +403,21 @@ } 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; }