X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=blobdiff_plain;f=libdocument%2Fev-file-helpers.c;h=edd4e4fd0adc2414e6918cab61dc7bceb4ce75e8;hb=68314b63836ebfd7878ba056d09290544f66750e;hp=6a3d2fa019e422943cb901cb26fe5c46e3c2fbf9;hpb=7b0368829c39a9c1d78a785164bfe1c5d1f9f6ff;p=evince.git diff --git a/libdocument/ev-file-helpers.c b/libdocument/ev-file-helpers.c index 6a3d2fa0..edd4e4fd 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 @@ -13,59 +14,86 @@ * * 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$ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#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; -gboolean -ev_dir_ensure_exists (const gchar *dir, - int mode) +/* + * 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 + */ +static gboolean +_ev_dir_ensure_exists (const gchar *dir, + 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 + */ +static 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,54 +113,219 @@ _ev_file_helpers_shutdown (void) tmp_dir = NULL; } +/** + * 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) +{ + const char *tmp; + char *name; + int fd; + + 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; +} + +static void +close_fd_cb (gpointer fdptr) +{ + 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_tmp_file_get (const gchar *prefix) +ev_mkstemp_file (const char *template, + GError **error) { - gchar *path; - GFile *file; + char *file_name; + int fd; + GFile *file; - path = ev_tmp_filename (prefix); - file = g_file_new_for_path (path); - - g_free (path); - - return 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; +} + +/** + * This function is copied from + * http://bugzilla.gnome.org/show_bug.cgi?id=524831 + * and renamed from g_mkdtemp to _ev_g_mkdtemp. + * + * If/when this function gets added to glib, it can be removed from + * evince' sources. + * + * + * g_mkdtemp: + * @tmpl: template directory name + * + * Creates a temporary directory. See the mkdtemp() documentation + * on most UNIX-like systems. + * + * The parameter is a string that should follow the rules for + * mkdtemp() templates, i.e. contain the string "XXXXXX". g_mkdtemp() + * is slightly more flexible than mkdtemp() in that the sequence does + * not have to occur at the very end of the template. The X string + * will be modified to form the name of a directory that didn't + * already exist. The string should be in the GLib file name + * encoding. Most importantly, on Windows it should be in UTF-8. + * + * Return value: If a temporary directory was successfully created, + * @tmpl will be returned with the XXXXXX string modified in such a + * way as to make the path unique. In case of errors, %NULL is + * returned. + */ +static gchar * +_ev_g_mkdtemp (gchar *tmpl) +{ + static const char letters[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + static const int NLETTERS = sizeof (letters) - 1; + static int counter = 0; + char *XXXXXX; + GTimeVal tv; + glong value; + int count; + + /* find the last occurrence of "XXXXXX" */ + XXXXXX = g_strrstr (tmpl, "XXXXXX"); + + if (!XXXXXX || strncmp (XXXXXX, "XXXXXX", 6)) + { + errno = EINVAL; + return NULL; + } + + /* Get some more or less random data. */ + g_get_current_time (&tv); + value = (tv.tv_usec ^ tv.tv_sec) + counter++; + + for (count = 0; count < 100; value += 7777, ++count) + { + glong v = value; + + /* Fill in the random bits. */ + XXXXXX[0] = letters[v % NLETTERS]; + v /= NLETTERS; + XXXXXX[1] = letters[v % NLETTERS]; + v /= NLETTERS; + XXXXXX[2] = letters[v % NLETTERS]; + v /= NLETTERS; + XXXXXX[3] = letters[v % NLETTERS]; + v /= NLETTERS; + XXXXXX[4] = letters[v % NLETTERS]; + v /= NLETTERS; + XXXXXX[5] = letters[v % NLETTERS]; + + /* tmpl is in UTF-8 on Windows, thus use g_mkdir() */ + if (g_mkdir (tmpl, 0700) == 0) + return tmpl; + + if (errno != EEXIST) + /* Any other error will apply also to other names we might + * try, and there are 2^32 or so of them, so give up now. + */ + return NULL; + } + + /* We got out of the loop because we ran out of combinations to try. */ + errno = EEXIST; + return NULL; } -gchar * -ev_tmp_filename (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) { - 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; + const char *tmp; + char *name; + + if ((tmp = _ev_tmp_dir (error)) == NULL) + return NULL; + + name = g_build_filename (tmp, template, NULL); + if (_ev_g_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 */ void ev_tmp_filename_unlink (const gchar *filename) { - const gchar *tempdir; - if (!filename) return; - tempdir = g_get_tmp_dir (); - if (g_ascii_strncasecmp (filename, tempdir, strlen (tempdir)) == 0) { + if (!tmp_dir) + return; + + if (g_str_has_prefix (filename, tmp_dir)) { g_unlink (filename); } } @@ -176,6 +369,35 @@ ev_tmp_uri_unlink (const gchar *uri) g_object_unref (file); } +gboolean +ev_file_is_temp (GFile *file) +{ + gchar *path; + gboolean retval; + + if (!g_file_is_native (file)) + return FALSE; + + path = g_file_get_path (file); + if (!path) + return FALSE; + + retval = g_str_has_prefix (path, g_get_tmp_dir ()); + g_free (path); + + return retval; +} + +/** + * ev_xfer_uri_simple: + * @from: the source URI + * @to: the target URI + * @error: a #GError location to store an error, or %NULL + * + * Performs a g_file_copy() from @from to @to. + * + * Returns: %TRUE on success, or %FALSE on error with @error filled in + */ gboolean ev_xfer_uri_simple (const char *from, const char *to, @@ -183,30 +405,25 @@ ev_xfer_uri_simple (const char *from, { GFile *source_file; GFile *target_file; - GError *ioerror = NULL; gboolean result; if (!from) - return FALSE; - + return TRUE; + + g_return_val_if_fail (to != NULL, TRUE); + source_file = g_file_new_for_uri (from); target_file = g_file_new_for_uri (to); result = g_file_copy (source_file, target_file, -#if GLIB_CHECK_VERSION(2,19,0) G_FILE_COPY_TARGET_DEFAULT_PERMS | -#endif G_FILE_COPY_OVERWRITE, - NULL, NULL, NULL, &ioerror); + NULL, NULL, NULL, error); g_object_unref (target_file); g_object_unref (source_file); - if (!result) { - g_propagate_error (error, ioerror); - } return result; - } static gchar * @@ -215,6 +432,7 @@ get_mime_type_from_uri (const gchar *uri, GError **error) GFile *file; GFileInfo *file_info; const gchar *content_type; + gchar *mime_type = NULL; file = g_file_new_for_uri (uri); file_info = g_file_query_info (file, @@ -226,17 +444,18 @@ get_mime_type_from_uri (const gchar *uri, GError **error) return NULL; content_type = g_file_info_get_content_type (file_info); - g_object_unref (file_info); + if (content_type) { + mime_type = g_content_type_get_mime_type (content_type); + } - if (!content_type) - return NULL; - - return g_content_type_get_mime_type (content_type); + g_object_unref (file_info); + return mime_type; } static gchar * get_mime_type_from_data (const gchar *uri, GError **error) { +#ifndef G_OS_WIN32 GFile *file; GFileInputStream *input_stream; gssize size_read; @@ -276,6 +495,13 @@ get_mime_type_from_data (const gchar *uri, GError **error) mime_type = g_content_type_get_mime_type (content_type); g_free (content_type); return mime_type; +#else + /* + * On Windows, the implementation of g_content_type_guess() is too limited at the moment, so we do not + * use it and fall back to get_mime_type_from_uri() + */ + return get_mime_type_from_uri (uri, error); +#endif /* G_OS_WIN32 */ } /** @@ -312,7 +538,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; @@ -335,20 +561,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; }