# HG changeset patch # User zas_ # Date 1263133409 0 # Node ID b8d37cc79410a76a89d2fd43e77e1e44205d4c7a # Parent 10f9803aca45cebaf92a1d37d618c95711a54934 copy_file(): remove incomplete file on error (bug 2890715) The behavior changed, data is first written to a temporary file, which is unlinked in case of error, then the tempfile is renamed to the final name. Size of buffer was increased from 4k to 16k. diff -r 10f9803aca45 -r b8d37cc79410 src/ui_fileops.c --- a/src/ui_fileops.c Sat Jan 09 11:44:27 2010 +0000 +++ b/src/ui_fileops.c Sun Jan 10 14:23:29 2010 +0000 @@ -520,52 +520,66 @@ { FILE *fi = NULL; FILE *fo = NULL; - gchar *sl, *tl; - gchar buf[4096]; + gchar *sl = NULL; + gchar *tl = NULL; + gchar *randname = NULL; + gchar buf[16384]; size_t b; + gint ret = FALSE; + gint fd = -1; sl = path_from_utf8(s); tl = path_from_utf8(t); if (hard_linked(sl, tl)) { - g_free(sl); - g_free(tl); - return TRUE; + ret = TRUE; + goto end; } fi = fopen(sl, "rb"); - if (fi) - { - fo = fopen(tl, "wb"); - if (!fo) - { - fclose(fi); - fi = NULL; - } - } - - g_free(sl); - g_free(tl); - - if (!fi || !fo) return FALSE; + if (!fi) goto end; + + /* First we write to a temporary file, then we rename it on success, + and attributes from original file are copied */ + randname = g_strconcat(tl, ".tmp_XXXXXX", NULL); + if (!randname) goto end; + + fd = g_mkstemp(randname); + if (fd == -1) goto end; + + fo = fdopen(fd, "wb"); + if (!fo) { + close(fd); + goto end; + } while ((b = fread(buf, sizeof(gchar), sizeof(buf), fi)) && b != 0) { if (fwrite(buf, sizeof(gchar), b, fo) != b) { - fclose(fi); - fclose(fo); - return FALSE; + unlink(randname); + goto end; } } - fclose(fi); - fclose(fo); + fclose(fi); fi = NULL; + fclose(fo); fo = NULL; + + if (rename(randname, tl) < 0) { + unlink(randname); + goto end; + } - copy_file_attributes(s, t, TRUE, TRUE); + ret = copy_file_attributes(s, t, TRUE, TRUE); - return TRUE; +end: + if (fi) fclose(fi); + if (fo) fclose(fo); + if (sl) g_free(sl); + if (tl) g_free(tl); + if (randname) g_free(randname); + return ret; } gboolean move_file(const gchar *s, const gchar *t)