#include <glib.h>
#include <glib/gstdio.h>
#include <errno.h>
-#include <libgnomevfs/gnome-vfs-uri.h>
-#include <libgnomevfs/gnome-vfs-utils.h>
-#include <libgnomevfs/gnome-vfs-ops.h>
-#include <libgnomevfs/gnome-vfs-xfer.h>
-#include <libgnome/gnome-init.h>
#include "ev-file-helpers.h"
-static gchar *dot_dir = NULL;
static gchar *tmp_dir = NULL;
static gint count = 0;
-static gboolean
-ensure_dir_exists (const char *dir)
+gboolean
+ev_dir_ensure_exists (const gchar *dir,
+ int mode)
{
- if (g_file_test (dir, G_FILE_TEST_IS_DIR))
- return TRUE;
-
- if (g_mkdir (dir, 488) == 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, strerror (errno));
+ g_warning ("Failed to create directory %s: %s", dir, g_strerror (errno));
return FALSE;
}
-const gchar *
-ev_dot_dir (void)
-{
- if (dot_dir == NULL) {
- gboolean exists;
-
- dot_dir = g_build_filename (gnome_user_dir_get (),
- "evince",
- NULL);
-
- exists = ensure_dir_exists (dot_dir);
- if (!exists)
- exit (1);
- }
-
- return dot_dir;
-}
-
const gchar *
ev_tmp_dir (void)
{
if (tmp_dir == NULL) {
gboolean exists;
- gchar *dirname;
+ gchar *dirname, *prgname;
- dirname = g_strdup_printf ("evince-%u", getpid ());
+ 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 = ensure_dir_exists (tmp_dir);
+ exists = ev_dir_ensure_exists (tmp_dir, 0700);
g_assert (exists);
}
}
void
-ev_file_helpers_init (void)
+_ev_file_helpers_init (void)
{
}
void
-ev_file_helpers_shutdown (void)
+_ev_file_helpers_shutdown (void)
{
if (tmp_dir != NULL)
g_rmdir (tmp_dir);
g_free (tmp_dir);
- g_free (dot_dir);
-
- dot_dir = NULL;
tmp_dir = NULL;
}
+GFile *
+ev_tmp_file_get (const gchar *prefix)
+{
+ gchar *path;
+ GFile *file;
+
+ path = ev_tmp_filename (prefix);
+ file = g_file_new_for_path (path);
+
+ g_free (path);
+
+ return file;
+}
+
gchar *
ev_tmp_filename (const gchar *prefix)
{
return filename;
}
+gchar *
+ev_tmp_directory (const gchar *prefix)
+{
+ return ev_tmp_filename (prefix ? prefix : "directory");
+}
+
+/* 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) {
+ g_unlink (filename);
+ }
+}
+
+void
+ev_tmp_file_unlink (GFile *file)
+{
+ gboolean res;
+ GError *error = NULL;
+
+ if (!file)
+ return;
+
+ res = g_file_delete (file, NULL, &error);
+ if (!res) {
+ char *uri;
+
+ uri = g_file_get_uri (file);
+ g_warning ("Unable to delete temp file %s: %s\n", uri, error->message);
+ g_free (uri);
+ g_error_free (error);
+ }
+}
+
+void
+ev_tmp_uri_unlink (const gchar *uri)
+{
+ GFile *file;
+
+ if (!uri)
+ return;
+
+ file = g_file_new_for_uri (uri);
+ if (!g_file_is_native (file)) {
+ g_warning ("Attempting to delete non native uri: %s\n", uri);
+ g_object_unref (file);
+ return;
+ }
+
+ ev_tmp_file_unlink (file);
+ g_object_unref (file);
+}
+
+/**
+ * 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,
GError **error)
{
- GnomeVFSResult result;
- GnomeVFSURI *source_uri;
- GnomeVFSURI *target_uri;
+ GFile *source_file;
+ GFile *target_file;
+ 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);
- source_uri = gnome_vfs_uri_new (from);
- target_uri = gnome_vfs_uri_new (to);
-
- result = gnome_vfs_xfer_uri (source_uri, target_uri,
- GNOME_VFS_XFER_DEFAULT | GNOME_VFS_XFER_FOLLOW_LINKS,
- GNOME_VFS_XFER_ERROR_MODE_ABORT,
- GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE,
- NULL,
- NULL);
- gnome_vfs_uri_unref (target_uri);
- gnome_vfs_uri_unref (source_uri);
+ 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, error);
+
+ g_object_unref (target_file);
+ g_object_unref (source_file);
- if (result != GNOME_VFS_OK)
- g_set_error (error,
- G_FILE_ERROR,
- G_FILE_ERROR_FAILED,
- gnome_vfs_result_to_string (result));
- return (result == GNOME_VFS_OK);
+ return result;
+}
+
+static gchar *
+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,
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+ 0, NULL, error);
+ g_object_unref (file);
+
+ if (file_info == NULL)
+ return NULL;
+
+ content_type = g_file_info_get_content_type (file_info);
+ if (content_type) {
+ mime_type = 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)
+{
+ GFile *file;
+ GFileInputStream *input_stream;
+ gssize size_read;
+ guchar buffer[1024];
+ gboolean retval;
+ gchar *content_type, *mime_type;
+
+ file = g_file_new_for_uri (uri);
+
+ input_stream = g_file_read (file, NULL, error);
+ if (!input_stream) {
+ g_object_unref (file);
+ return NULL;
+ }
+
+ size_read = g_input_stream_read (G_INPUT_STREAM (input_stream),
+ buffer, sizeof (buffer), NULL, error);
+ if (size_read == -1) {
+ g_object_unref (input_stream);
+ g_object_unref (file);
+ return NULL;
+ }
+
+ retval = g_input_stream_close (G_INPUT_STREAM (input_stream), NULL, error);
+
+ g_object_unref (input_stream);
+ g_object_unref (file);
+ if (!retval)
+ return NULL;
+ content_type = g_content_type_guess (NULL, /* no filename */
+ buffer, size_read,
+ NULL);
+ if (!content_type)
+ return NULL;
+
+ mime_type = g_content_type_get_mime_type (content_type);
+ g_free (content_type);
+ return mime_type;
+}
+
+/**
+ * ev_file_get_mime_type:
+ * @uri: the URI
+ * @fast: whether to use fast MIME type detection
+ * @error: a #GError location to store an error, or %NULL
+ *
+ * Note: on unknown MIME types, this may return NULL without @error
+ * being filled in.
+ *
+ * Returns: a newly allocated string with the MIME type of the file at
+ * @uri, or %NULL on error or if the MIME type could not be determined
+ */
+gchar *
+ev_file_get_mime_type (const gchar *uri,
+ gboolean fast,
+ GError **error)
+{
+ return fast ? get_mime_type_from_uri (uri, error) : get_mime_type_from_data (uri, error);
}
/* Compressed files support */
#define BZIPCOMMAND "bzip2"
#define GZIPCOMMAND "gzip"
-#define N_ARGS 5
+#define N_ARGS 4
#define BUFFER_SIZE 1024
-gchar *
-ev_file_uncompress (const gchar *uri,
- EvCompressionType type,
- GError **error)
+static gchar *
+compression_run (const gchar *uri,
+ EvCompressionType type,
+ gboolean compress,
+ GError **error)
{
gchar *argv[N_ARGS];
- gchar *uri_unc = NULL;
- gchar *filename, *filename_unc;
+ gchar *uri_dst = NULL;
+ gchar *filename, *filename_dst;
gchar *cmd;
gint fd, pout;
-
- g_return_val_if_fail (uri != NULL, NULL);
+ GError *err = NULL;
if (type == EV_COMPRESSION_NONE)
return NULL;
cmd = g_find_program_in_path ((type == EV_COMPRESSION_BZIP2) ? BZIPCOMMAND : GZIPCOMMAND);
- if (!cmd)
+ if (!cmd) {
+ /* FIXME: better error codes! */
+ /* FIXME: i18n later */
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+ "Failed to find the \"%s\" command in the search path.",
+ type == EV_COMPRESSION_BZIP2 ? BZIPCOMMAND : GZIPCOMMAND);
return NULL;
+ }
-
- filename = g_filename_from_uri (uri, NULL, NULL);
+ filename = g_filename_from_uri (uri, NULL, error);
if (!filename) {
g_free (cmd);
return NULL;
}
- filename_unc = g_build_filename (ev_tmp_dir (), "evinceXXXXXX", NULL);
- fd = g_mkstemp (filename_unc);
+ filename_dst = g_build_filename (ev_tmp_dir (), "evinceXXXXXX", NULL);
+ fd = g_mkstemp (filename_dst);
if (fd < 0) {
+ int errsv = errno;
+
g_free (cmd);
g_free (filename);
- g_free (filename_unc);
+ 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;
}
-
+
argv[0] = cmd;
- argv[1] = "-cd";
+ argv[1] = compress ? "-c" : "-cd";
argv[2] = filename;
- argv[3] = filename_unc;
- argv[4] = NULL;
+ argv[3] = NULL;
if (g_spawn_async_with_pipes (NULL, argv, NULL,
G_SPAWN_STDERR_TO_DEV_NULL,
NULL, NULL, NULL,
- NULL, &pout, NULL, error)) {
+ NULL, &pout, NULL, &err)) {
GIOChannel *in, *out;
gchar buf[BUFFER_SIZE];
GIOStatus read_st, write_st;
break;
}
} while (bytes_read > 0);
-
+
g_io_channel_unref (in);
g_io_channel_unref (out);
}
close (fd);
- if (*error == NULL) {
- uri_unc = g_filename_to_uri (filename_unc,
- NULL, NULL);
+ if (err) {
+ g_propagate_error (error, err);
+ } else {
+ uri_dst = g_filename_to_uri (filename_dst, NULL, error);
}
g_free (cmd);
g_free (filename);
- g_free (filename_unc);
+ g_free (filename_dst);
+
+ return uri_dst;
+}
+
+/**
+ * ev_file_uncompress:
+ * @uri: a file URI
+ * @type: the compression type
+ * @error: a #GError location to store an error, or %NULL
+ *
+ * Uncompresses the file at @uri.
+ *
+ * If @type is %EV_COMPRESSION_NONE, it does nothing and returns %NULL.
+ *
+ * Otherwise, it returns the filename of a
+ * temporary file containing the decompressed data from the file at @uri.
+ * On error it returns %NULL and fills in @error.
+ *
+ * It is the caller's responsibility to unlink the temp file after use.
+ *
+ * Returns: a newly allocated string URI, or %NULL on error
+ */
+gchar *
+ev_file_uncompress (const gchar *uri,
+ EvCompressionType type,
+ GError **error)
+{
+ g_return_val_if_fail (uri != NULL, NULL);
+
+ return compression_run (uri, type, FALSE, error);
+}
+
+/**
+ * ev_file_compress:
+ * @uri: a file URI
+ * @type: the compression type
+ * @error: a #GError location to store an error, or %NULL
+ *
+ * Compresses the file at @uri.
+
+ * If @type is %EV_COMPRESSION_NONE, it does nothing and returns %NULL.
+ *
+ * Otherwise, it returns the filename of a
+ * temporary file containing the compressed data from the file at @uri.
+ *
+ * On error it returns %NULL and fills in @error.
+ *
+ * It is the caller's responsibility to unlink the temp file after use.
+ *
+ * Returns: a newly allocated string URI, or %NULL on error
+ */
+gchar *
+ev_file_compress (const gchar *uri,
+ EvCompressionType type,
+ GError **error)
+{
+ g_return_val_if_fail (uri != NULL, NULL);
- return uri_unc;
+ return compression_run (uri, type, TRUE, error);
}