From 0f1c723ad2fe48a0f22e32619985f93ebb2e02ef Mon Sep 17 00:00:00 2001 From: Christian Persch Date: Sun, 25 Oct 2009 15:04:20 +0000 Subject: libdocument: Clean up temp file handling t push origin HEAD:master Make sure we can cope with not being able to create our temp directory. Bug #595372. --- diff --git a/backend/comics/comics-document.c b/backend/comics/comics-document.c index fbe6ba0..b53d513 100644 --- a/backend/comics/comics-document.c +++ b/backend/comics/comics-document.c @@ -205,32 +205,20 @@ comics_generate_command_lines (ComicsDocument *comics_document, comics_document->regex_arg = command_usage_def[type].regex_arg; comics_document->offset = command_usage_def[type].offset; if (command_usage_def[type].decompress_tmp) { - comics_document->dir = ev_tmp_directory (NULL); - comics_document->decompress_tmp = + comics_document->dir = ev_mkdtemp ("comics.XXXXXX", error); + if (comics_document->dir == NULL) + return FALSE; + + /* unrar-free can't create directories, but ev_mkdtemp already created the dir */ + + comics_document->decompress_tmp = g_strdup_printf (command_usage_def[type].decompress_tmp, comics_document->selected_command, quoted_file, comics_document->dir); g_free (quoted_file); - /* unrar-free can't create directories so we do it on its - * behalf */ - if (type == GNAUNRAR) { - if (g_mkdir_with_parents (comics_document->dir, 0700) != - 0) { - int errsv = errno; - g_set_error (error, - EV_DOCUMENT_ERROR, - EV_DOCUMENT_ERROR_INVALID, - _("Failed to create a temporary " - "directory.")); - g_warning ("Failed to create directory %s: %s", - comics_document->dir, - g_strerror (errsv)); - - return FALSE; - } - } - if (!comics_decompress_temp_dir (comics_document->decompress_tmp, + + if (!comics_decompress_temp_dir (comics_document->decompress_tmp, comics_document->selected_command, error)) return FALSE; else @@ -713,7 +701,6 @@ comics_document_finalize (GObject *object) g_warning (_("There was an error deleting “%s”."), comics_document->dir); g_free (comics_document->dir); - g_remove (ev_tmp_dir ()); } if (comics_document->page_names) { diff --git a/libdocument/ev-attachment.c b/libdocument/ev-attachment.c index c1d1333..c4dd38d 100644 --- a/libdocument/ev-attachment.c +++ b/libdocument/ev-attachment.c @@ -101,7 +101,7 @@ ev_attachment_finalize (GObject *object) attachment->priv->tmp_file = NULL; } - (* G_OBJECT_CLASS (ev_attachment_parent_class)->finalize) (object); + G_OBJECT_CLASS (ev_attachment_parent_class)->finalize (object); } static void @@ -411,18 +411,19 @@ ev_attachment_open (EvAttachment *attachment, return FALSE; } - if (attachment->priv->tmp_file && - g_file_query_exists (attachment->priv->tmp_file, NULL)) { + if (attachment->priv->tmp_file) { retval = ev_attachment_launch_app (attachment, screen, timestamp, error); } else { - GFile *tmpdir; + char *template; GFile *file; - - tmpdir = g_file_new_for_path (ev_tmp_dir ()); - file = g_file_get_child (tmpdir, attachment->priv->name); - if (ev_attachment_save (attachment, file, error)) { + /* FIXMEchpe: convert to filename encoding first! */ + template = g_strdup_printf ("%s.XXXXXX", ev_attachment_get_name (attachment)); + file = ev_mkstemp_file (template, error); + g_free (template); + + if (file != NULL && ev_attachment_save (attachment, file, error)) { if (attachment->priv->tmp_file) g_object_unref (attachment->priv->tmp_file); attachment->priv->tmp_file = g_object_ref (file); @@ -432,7 +433,6 @@ ev_attachment_open (EvAttachment *attachment, } g_object_unref (file); - g_object_unref (tmpdir); } return retval; diff --git a/libdocument/ev-file-helpers.c b/libdocument/ev-file-helpers.c index 3da4a59..4816db0 100644 --- a/libdocument/ev-file-helpers.c +++ b/libdocument/ev-file-helpers.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2002 Jorn Baayen + * Copyright © 2009 Christian Persch * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,58 +15,85 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Id$ */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif +#include #include #include #include #include +#include + #include #include -#include +#include #include "ev-file-helpers.h" static gchar *tmp_dir = NULL; -static gint count = 0; +/** + * ev_dir_ensure_exists: + * @dir: the directory name + * @mode: permissions to use when creating the directory + * @error: a location to store a #GError + * + * Create @dir recursively with permissions @mode. + * + * Returns: %TRUE on success, or %FALSE on error with @error filled in + */ gboolean ev_dir_ensure_exists (const gchar *dir, - int mode) + int mode, + GError **error) { + int errsv; + char *display_name; + + g_return_val_if_fail (dir != NULL, FALSE); + + errno = 0; if (g_mkdir_with_parents (dir, mode) == 0) return TRUE; - if (errno == EEXIST) - return g_file_test (dir, G_FILE_TEST_IS_DIR); - - g_warning ("Failed to create directory %s: %s", dir, g_strerror (errno)); + errsv = errno; + if (errsv == EEXIST && g_file_test (dir, G_FILE_TEST_IS_DIR)) + return TRUE; + + display_name = g_filename_display_name (dir); + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv), + "Failed to create directory '%s': %s", + display_name, g_strerror (errsv)); + g_free (display_name); + return FALSE; } -const gchar * -ev_tmp_dir (void) +/* + * _ev_tmp_dir: + * @error: a location to store a #GError + * + * Returns the tmp directory. + * + * Returns: the tmp directory, or %NULL with @error filled in if the + * directory could not be created + */ +const char * +_ev_tmp_dir (GError **error) { - if (tmp_dir == NULL) { - gboolean exists; - gchar *dirname, *prgname; + + if (tmp_dir == NULL) { + gchar *dirname, *prgname; prgname = g_get_prgname (); - dirname = g_strdup_printf ("%s-%u", prgname ? prgname : "unknown", getpid ()); - tmp_dir = g_build_filename (g_get_tmp_dir (), - dirname, - NULL); - g_free (dirname); - - exists = ev_dir_ensure_exists (tmp_dir, 0700); - g_assert (exists); - } + dirname = g_strdup_printf ("%s-%u", prgname ? prgname : "unknown", getpid ()); + tmp_dir = g_build_filename (g_get_tmp_dir (), dirname, NULL); + g_free (dirname); + } + + if (!ev_dir_ensure_exists (tmp_dir, 0700, error)) + return NULL; return tmp_dir; } @@ -85,47 +113,121 @@ _ev_file_helpers_shutdown (void) tmp_dir = NULL; } -GFile * -ev_tmp_file_get (const gchar *prefix) +/** + * ev_mkstemp: + * @template: a template string; must contain 'XXXXXX', but not necessarily as a suffix + * @file_name: a location to store the filename of the temp file + * @error: a location to store a #GError + * + * Creates a temp file in the evince temp directory. + * + * Returns: a file descriptor to the newly created temp file name, or %-1 + * on error with @error filled in + */ +int +ev_mkstemp (const char *template, + char **file_name, + GError **error) { - gchar *path; - GFile *file; + const char *tmp; + char *name; + int fd; - path = ev_tmp_filename (prefix); - file = g_file_new_for_path (path); - - g_free (path); - - return file; + if ((tmp = _ev_tmp_dir (error)) == NULL) + return -1; + + name = g_build_filename (tmp, template, NULL); + fd = g_mkstemp (name); + + if (fd == -1) { + int errsv = errno; + + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv), + _("Failed to create a temporary file: %s"), + g_strerror (errsv)); + + g_free (name); + return -1; + } + + if (file_name) + *file_name = name; + + return fd; } -gchar * -ev_tmp_filename (const gchar *prefix) +static void +close_fd_cb (gpointer fdptr) { - gchar *basename; - gchar *filename = NULL; - - do { - if (filename != NULL) - g_free (filename); - - basename = g_strdup_printf ("%s-%d", - prefix ? prefix : "document", - count ++); - - filename = g_build_filename (ev_tmp_dir (), - basename, NULL); - - g_free (basename); - } while (g_file_test (filename, G_FILE_TEST_EXISTS)); - - return filename; + int fd = GPOINTER_TO_INT (fdptr); + + close (fd); +} + +/** + * ev_mkstemp_file: + * @template: a template string; must contain 'XXXXXX', but not necessarily as a suffix + * @error: a location to store a #GError + * + * Creates a temp #GFile in the evince temp directory. See ev_mkstemp() for more information. + * + * Returns: a newly allocated #GFile for the newly created temp file name, or %NULL + * on error with @error filled in + */ +GFile * +ev_mkstemp_file (const char *template, + GError **error) +{ + char *file_name; + int fd; + GFile *file; + + fd = ev_mkstemp (template, &file_name, error); + if (fd == -1) + return NULL; + + file = g_file_new_for_path (file_name); + g_free (file_name); + + g_object_set_data_full (G_OBJECT (file), "ev-mkstemp-fd", + GINT_TO_POINTER (fd), (GDestroyNotify) close_fd_cb); + + return file; } -gchar * -ev_tmp_directory (const gchar *prefix) +/** + * ev_mkdtemp: + * @template: a template string; must end in 'XXXXXX' + * @error: a location to store a #GError + * + * Creates a temp directory in the evince temp directory. + * + * Returns: a newly allocated string with the temp directory name, or %NULL + * on error with @error filled in + */ +gchar * +ev_mkdtemp (const char *template, + GError **error) { - return ev_tmp_filename (prefix ? prefix : "directory"); + const char *tmp; + char *name; + + if ((tmp = _ev_tmp_dir (error)) == NULL) + return NULL; + + name = g_build_filename (tmp, template, NULL); + if (mkdtemp (name) == NULL) { + int errsv = errno; + + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv), + _("Failed to create a temporary directory: %s"), + g_strerror (errsv)); + + g_free (name); + return NULL; + } + + return name; } /* Remove a local temp file created by evince */ @@ -138,7 +240,7 @@ ev_tmp_filename_unlink (const gchar *filename) return; tempdir = g_get_tmp_dir (); - if (g_ascii_strncasecmp (filename, tempdir, strlen (tempdir)) == 0) { + if (g_str_has_prefix (filename, tempdir) == 0) { g_unlink (filename); } } @@ -326,7 +428,7 @@ compression_run (const gchar *uri, { gchar *argv[N_ARGS]; gchar *uri_dst = NULL; - gchar *filename, *filename_dst; + gchar *filename, *filename_dst = NULL; gchar *cmd; gint fd, pout; GError *err = NULL; @@ -349,20 +451,12 @@ compression_run (const gchar *uri, g_free (cmd); return NULL; } - - filename_dst = g_build_filename (ev_tmp_dir (), "evinceXXXXXX", NULL); - fd = g_mkstemp (filename_dst); - if (fd < 0) { - int errsv = errno; + fd = ev_mkstemp ("comp.XXXXXX", &filename_dst, error); + if (fd == -1) { g_free (cmd); g_free (filename); - g_free (filename_dst); - g_set_error (error, G_IO_ERROR, - g_io_error_from_errno (errsv), - "Error creating a temporary file: %s", - g_strerror (errsv)); return NULL; } diff --git a/libdocument/ev-file-helpers.h b/libdocument/ev-file-helpers.h index 47a5417..99df4ed 100644 --- a/libdocument/ev-file-helpers.h +++ b/libdocument/ev-file-helpers.h @@ -36,18 +36,23 @@ typedef enum { EV_COMPRESSION_GZIP } EvCompressionType; -const gchar *ev_tmp_dir (void); +const char *_ev_tmp_dir (GError **error); void _ev_file_helpers_init (void); void _ev_file_helpers_shutdown (void); gboolean ev_dir_ensure_exists (const gchar *dir, - int mode); - -GFile *ev_tmp_file_get (const gchar *prefix); -gchar *ev_tmp_filename (const char *prefix); -gchar *ev_tmp_directory (const char *prefix); + int mode, + GError **error); + +int ev_mkstemp (const char *template, + char **file_name, + GError **error); +GFile *ev_mkstemp_file (const char *template, + GError **error); +gchar *ev_mkdtemp (const char *template, + GError **error); void ev_tmp_filename_unlink (const gchar *filename); void ev_tmp_file_unlink (GFile *file); void ev_tmp_uri_unlink (const gchar *uri); diff --git a/libdocument/ev-image.c b/libdocument/ev-image.c index 4fa2225..572b119 100644 --- a/libdocument/ev-image.c +++ b/libdocument/ev-image.c @@ -18,7 +18,10 @@ */ #include + #include +#include + #include "ev-document-misc.h" #include "ev-file-helpers.h" #include "ev-image.h" @@ -132,7 +135,8 @@ ev_image_save_tmp (EvImage *image, GdkPixbuf *pixbuf) { GError *error = NULL; - gchar *filename; + gchar *filename = NULL; + int fd; g_return_val_if_fail (EV_IS_IMAGE (image), NULL); g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL); @@ -140,19 +144,28 @@ ev_image_save_tmp (EvImage *image, if (image->priv->tmp_uri) return image->priv->tmp_uri; - filename = ev_tmp_filename ("image"); + if ((fd = ev_mkstemp ("image.XXXXXX", &filename, &error)) == -1) + goto had_error; + gdk_pixbuf_save (pixbuf, filename, "png", &error, "compression", "3", NULL); + close (fd); + if (!error) { - image->priv->tmp_uri = g_filename_to_uri (filename, NULL, NULL); + image->priv->tmp_uri = g_filename_to_uri (filename, NULL, &error); + if (image->priv->tmp_uri == NULL) + goto had_error; + g_free (filename); return image->priv->tmp_uri; } + had_error: + /* Erro saving image */ - g_warning ("%s", error->message); + g_warning ("Error saving image: %s", error->message); g_error_free (error); g_free (filename); @@ -166,6 +179,3 @@ ev_image_get_tmp_uri (EvImage *image) return image->priv->tmp_uri; } - - - diff --git a/libview/ev-jobs.c b/libview/ev-jobs.c index c0aa0b4..a0866d5 100644 --- a/libview/ev-jobs.c +++ b/libview/ev-jobs.c @@ -936,31 +936,17 @@ ev_job_save_run (EvJob *job) { EvJobSave *job_save = EV_JOB_SAVE (job); gint fd; - gchar *filename; - gchar *tmp_filename; + gchar *tmp_filename = NULL; gchar *local_uri; GError *error = NULL; ev_debug_message (DEBUG_JOBS, "uri: %s, document_uri: %s", job_save->uri, job_save->document_uri); ev_profiler_start (EV_PROFILE_JOBS, "%s (%p)", EV_GET_TYPE_NAME (job), job); - - filename = ev_tmp_filename ("saveacopy"); - tmp_filename = g_strdup_printf ("%s.XXXXXX", filename); - g_free (filename); - - fd = g_mkstemp (tmp_filename); - if (fd == -1) { - gchar *display_name; - gint save_errno = errno; - display_name = g_filename_display_name (tmp_filename); - ev_job_failed (job, - G_FILE_ERROR, - g_file_error_from_errno (save_errno), - _("Failed to create file “%s”: %s"), - display_name, g_strerror (save_errno)); - g_free (display_name); - g_free (tmp_filename); + fd = ev_mkstemp ("saveacopy.XXXXXX", &tmp_filename, &error); + if (fd == -1) { + ev_job_failed_from_error (job, error); + g_error_free (error); return FALSE; } @@ -968,8 +954,11 @@ ev_job_save_run (EvJob *job) ev_document_doc_mutex_lock (); /* Save document to temp filename */ - local_uri = g_filename_to_uri (tmp_filename, NULL, NULL); - ev_document_save (job->document, local_uri, &error); + local_uri = g_filename_to_uri (tmp_filename, NULL, &error); + if (local_uri != NULL) { + ev_document_save (job->document, local_uri, &error); + } + close (fd); ev_document_doc_mutex_unlock (); @@ -1000,7 +989,7 @@ ev_job_save_run (EvJob *job) uri_comp = ev_file_compress (local_uri, ctype, &error); g_free (local_uri); - ev_tmp_filename_unlink (tmp_filename); + g_unlink (tmp_filename); if (!uri_comp || error) { local_uri = NULL; @@ -1010,7 +999,7 @@ ev_job_save_run (EvJob *job) } g_free (tmp_filename); - + if (error) { g_free (local_uri); ev_job_failed_from_error (job, error); diff --git a/shell/ev-application.c b/shell/ev-application.c index bbd5ec6..2c6b509 100644 --- a/shell/ev-application.c +++ b/shell/ev-application.c @@ -885,7 +885,7 @@ ev_application_init (EvApplication *ev_application) NULL); /* FIXME: why make this fatal? */ - if (!ev_dir_ensure_exists (ev_application->dot_dir, 0700)) + if (!ev_dir_ensure_exists (ev_application->dot_dir, 0700, NULL)) exit (1); #ifdef G_OS_WIN32 diff --git a/shell/ev-sidebar-attachments.c b/shell/ev-sidebar-attachments.c index d89617b..74e89c4 100644 --- a/shell/ev-sidebar-attachments.c +++ b/shell/ev-sidebar-attachments.c @@ -410,7 +410,7 @@ ev_sidebar_attachments_drag_data_get (GtkWidget *widget, GtkTreePath *path; GtkTreeIter iter; GFile *file; - gchar *filename; + gchar *filename, *template, *name; GError *error = NULL; path = (GtkTreePath *) l->data; @@ -421,13 +421,12 @@ ev_sidebar_attachments_drag_data_get (GtkWidget *widget, COLUMN_ATTACHMENT, &attachment, -1); - filename = g_build_filename (ev_tmp_dir (), - ev_attachment_get_name (attachment), - NULL); - file = g_file_new_for_path (filename); - g_free (filename); + /* FIXMEchpe: convert to filename encoding first! */ + template = g_strdup_printf ("%s.XXXXXX", ev_attachment_get_name (attachment)); + file = ev_mkstemp_file (template, &error); + g_free (template); - if (ev_attachment_save (attachment, file, &error)) { + if (file != NULL && ev_attachment_save (attachment, file, &error)) { gchar *uri; uri = g_file_get_uri (file); diff --git a/shell/ev-window.c b/shell/ev-window.c index c55c9f8..042b4f9 100644 --- a/shell/ev-window.c +++ b/shell/ev-window.c @@ -1708,19 +1708,30 @@ ev_window_load_file_remote (EvWindow *ev_window, GFile *target_file; if (!ev_window->priv->local_uri) { - gchar *tmp_name; - gchar *base_name; + char *base_name, *template; + GFile *tmp_file; + GError *err = NULL; /* We'd like to keep extension of source uri since - * it helps to resolve some mime types, say cbz */ - tmp_name = ev_tmp_filename (NULL); + * it helps to resolve some mime types, say cbz. + */ base_name = g_file_get_basename (source_file); - ev_window->priv->local_uri = g_strconcat ("file:", tmp_name, "-", - base_name, NULL); + template = g_build_filename ("document.XXXXXX-%s", base_name, NULL); + g_free (base_name); + + tmp_file = ev_mkstemp_file (template, &err); + if (tmp_file == NULL) { + ev_window_error_message (ev_window, err, + "%s", _("Failed to load remote file.")); + g_error_free (err); + return; + } + + ev_window->priv->local_uri = g_file_get_uri (tmp_file); + g_object_unref (tmp_file); + ev_job_load_set_uri (EV_JOB_LOAD (ev_window->priv->load_job), ev_window->priv->local_uri); - g_free (base_name); - g_free (tmp_name); } ev_window_reset_progress_cancellable (ev_window); @@ -4648,13 +4659,13 @@ ev_window_drag_data_received (GtkWidget *widget, static void ev_window_finalize (GObject *object) { + G_OBJECT_CLASS (ev_window_parent_class)->finalize (object); + if (ev_window_n_copies == 0) { ev_application_shutdown (EV_APP); } else { ev_window_n_copies--; } - - G_OBJECT_CLASS (ev_window_parent_class)->finalize (object); } static void @@ -5629,7 +5640,9 @@ image_save_dialog_response_cb (GtkWidget *fc, if (is_native) { filename = g_file_get_path (target_file); } else { - filename = ev_tmp_filename ("saveimage"); + /* Create a temporary local file to save to */ + if (ev_mkstemp ("saveimage.XXXXXX", &filename, &error) == -1) + goto has_error; } ev_document_doc_mutex_lock (); @@ -5642,6 +5655,7 @@ image_save_dialog_response_cb (GtkWidget *fc, g_free (file_format); g_object_unref (pixbuf); + has_error: if (error) { ev_window_error_message (ev_window, error, "%s", _("The image could not be saved.")); @@ -5774,7 +5788,7 @@ attachment_save_dialog_response_cb (GtkWidget *fc, for (l = ev_window->priv->attach_list; l && l->data; l = g_list_next (l)) { EvAttachment *attachment; - GFile *save_to; + GFile *save_to = NULL; GError *error = NULL; attachment = (EvAttachment *) l->data; @@ -5782,15 +5796,17 @@ attachment_save_dialog_response_cb (GtkWidget *fc, if (is_native) { if (is_dir) { save_to = g_file_get_child (target_file, + /* FIXMEchpe: file name encoding! */ ev_attachment_get_name (attachment)); } else { save_to = g_object_ref (target_file); } } else { - save_to = ev_tmp_file_get ("saveattachment"); + save_to = ev_mkstemp_file ("saveattachment.XXXXXX", &error); } - ev_attachment_save (attachment, save_to, &error); + if (save_to) + ev_attachment_save (attachment, save_to, &error); if (error) { ev_window_error_message (ev_window, error, -- cgit v0.9.1