]> www.fi.muni.cz Git - evince.git/blob - libdocument/ev-file-helpers.c
More docs.
[evince.git] / libdocument / ev-file-helpers.c
1 /*
2  *  Copyright (C) 2002 Jorn Baayen
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2, or (at your option)
7  *  any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  *
18  *  $Id$
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <stdlib.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <glib.h>
30 #include <glib/gstdio.h>
31 #include <errno.h>
32
33 #include "ev-file-helpers.h"
34
35 static gchar *tmp_dir = NULL;
36 static gint   count = 0;
37
38 gboolean
39 ev_dir_ensure_exists (const gchar *dir,
40                       int          mode)
41 {
42         if (g_mkdir_with_parents (dir, mode) == 0)
43                 return TRUE;
44
45         if (errno == EEXIST)
46                 return g_file_test (dir, G_FILE_TEST_IS_DIR);
47         
48         g_warning ("Failed to create directory %s: %s", dir, g_strerror (errno));
49         return FALSE;
50 }
51
52 const gchar *
53 ev_tmp_dir (void)
54 {
55         if (tmp_dir == NULL) {
56                 gboolean exists;
57                 gchar   *dirname, *prgname;
58
59                 prgname = g_get_prgname ();
60                 dirname = g_strdup_printf ("%s-%u", prgname ? prgname : "unknown", getpid ());
61                 tmp_dir = g_build_filename (g_get_tmp_dir (),
62                                             dirname,
63                                             NULL);
64                 g_free (dirname);
65
66                 exists = ev_dir_ensure_exists (tmp_dir, 0700);
67                 g_assert (exists);
68         }
69
70         return tmp_dir;
71 }
72
73 void
74 _ev_file_helpers_init (void)
75 {
76 }
77
78 void
79 _ev_file_helpers_shutdown (void)
80 {       
81         if (tmp_dir != NULL)    
82                 g_rmdir (tmp_dir);
83
84         g_free (tmp_dir);
85         tmp_dir = NULL;
86 }
87
88 GFile *
89 ev_tmp_file_get (const gchar *prefix)
90 {
91         gchar *path;
92         GFile *file;
93
94         path = ev_tmp_filename (prefix);
95         file = g_file_new_for_path (path);
96         
97         g_free (path);
98         
99         return file;
100 }
101
102 gchar * 
103 ev_tmp_filename (const gchar *prefix)
104 {
105         gchar *basename;
106         gchar *filename = NULL;
107
108         do {
109                 if (filename != NULL)
110                         g_free (filename);
111                         
112                 basename = g_strdup_printf ("%s-%d",
113                                             prefix ? prefix : "document",
114                                             count ++);
115                 
116                 filename = g_build_filename (ev_tmp_dir (),
117                                              basename, NULL);
118                 
119                 g_free (basename);
120         } while (g_file_test (filename, G_FILE_TEST_EXISTS));
121                         
122         return filename;
123 }
124
125 /* Remove a local temp file created by evince */
126 void
127 ev_tmp_filename_unlink (const gchar *filename)
128 {
129         const gchar *tempdir;
130         
131         if (!filename)
132                 return;
133
134         tempdir = g_get_tmp_dir ();
135         if (g_ascii_strncasecmp (filename, tempdir, strlen (tempdir)) == 0) {
136                 g_unlink (filename);
137         }
138 }
139
140 void
141 ev_tmp_file_unlink (GFile *file)
142 {
143         gboolean res;
144         GError  *error = NULL;
145
146         if (!file)
147                 return;
148         
149         res = g_file_delete (file, NULL, &error);
150         if (!res) {
151                 char *uri;
152                 
153                 uri = g_file_get_uri (file);
154                 g_warning ("Unable to delete temp file %s: %s\n", uri, error->message);
155                 g_free (uri);
156                 g_error_free (error);
157         }
158 }
159
160 void
161 ev_tmp_uri_unlink (const gchar *uri)
162 {
163         GFile *file;
164         
165         if (!uri)
166                 return;
167         
168         file = g_file_new_for_uri (uri);
169         if (!g_file_is_native (file)) {
170                 g_warning ("Attempting to delete non native uri: %s\n", uri);
171                 g_object_unref (file);
172                 return;
173         }
174         
175         ev_tmp_file_unlink (file);
176         g_object_unref (file);
177 }
178
179 gboolean
180 ev_xfer_uri_simple (const char *from,
181                     const char *to,
182                     GError     **error)
183 {
184         GFile *source_file;
185         GFile *target_file;
186         GError *ioerror = NULL;
187         gboolean result;
188         
189         if (!from)
190                 return FALSE;
191         
192         source_file = g_file_new_for_uri (from);
193         target_file = g_file_new_for_uri (to);
194         
195         result = g_file_copy (source_file, target_file,
196 #if GLIB_CHECK_VERSION(2,19,0)
197                               G_FILE_COPY_TARGET_DEFAULT_PERMS |
198 #endif
199                               G_FILE_COPY_OVERWRITE,
200                               NULL, NULL, NULL, &ioerror);
201
202         g_object_unref (target_file);
203         g_object_unref (source_file);
204     
205         if (!result) {
206                 g_propagate_error (error, ioerror);
207         }
208         return result;
209
210 }
211
212 static gchar *
213 get_mime_type_from_uri (const gchar *uri, GError **error)
214 {
215         GFile     *file;
216         GFileInfo *file_info;
217         gchar     *mime_type;
218
219         file = g_file_new_for_uri (uri);
220         file_info = g_file_query_info (file,
221                                        G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
222                                        0, NULL, error);
223         g_object_unref (file);
224
225         if (file_info == NULL)
226                 return NULL;
227
228         mime_type = g_content_type_get_mime_type (
229                         g_file_info_get_content_type (file_info));
230         g_object_unref (file_info);
231
232         return mime_type;
233 }
234
235 static gchar *
236 get_mime_type_from_data (const gchar *uri, GError **error)
237 {
238         GFile            *file;
239         GFileInputStream *input_stream;
240         gssize            size_read;
241         guchar            buffer[1024];
242
243         file = g_file_new_for_uri (uri);
244         
245         input_stream = g_file_read (file, NULL, error);
246         if (!input_stream) {
247                 g_object_unref (file);
248                 return NULL;
249         }
250
251         size_read = g_input_stream_read (G_INPUT_STREAM (input_stream),
252                                          buffer, 1024, NULL, NULL);
253         g_input_stream_close (G_INPUT_STREAM (input_stream), NULL, error);
254
255         g_object_unref (file);
256
257         if (size_read == -1)
258                 return NULL;
259
260         return g_content_type_guess (NULL, /* no filename */
261                                      buffer, 1024,
262                                      NULL);
263 }
264
265 /**
266  * ev_file_get_mime_type:
267  * @uri: the URI
268  * @fast: whether to use fast MIME type detection
269  * @error: a #GError location to store an error, or %NULL
270  *
271  * Note: on unknown MIME types, this may return NULL without @error
272  * being filled in.
273  * 
274  * Returns: a newly allocated string with the MIME type of the file at
275  *   @uri, or %NULL on error or if the MIME type could not be determined
276  */
277 gchar *
278 ev_file_get_mime_type (const gchar *uri,
279                        gboolean     fast,
280                        GError     **error)
281 {
282         return fast ? get_mime_type_from_uri (uri, error) : get_mime_type_from_data (uri, error);
283 }
284
285 /* Compressed files support */
286 #define BZIPCOMMAND "bzip2"
287 #define GZIPCOMMAND "gzip"
288 #define N_ARGS      4
289 #define BUFFER_SIZE 1024
290
291 static gchar *
292 compression_run (const gchar       *uri,
293                  EvCompressionType  type,
294                  gboolean           compress, 
295                  GError           **error)
296 {
297         gchar *argv[N_ARGS];
298         gchar *uri_dst = NULL;
299         gchar *filename, *filename_dst;
300         gchar *cmd;
301         gint   fd, pout;
302
303         if (type == EV_COMPRESSION_NONE)
304                 return NULL;
305
306         cmd = g_find_program_in_path ((type == EV_COMPRESSION_BZIP2) ? BZIPCOMMAND : GZIPCOMMAND);
307         if (!cmd)
308                 return NULL;
309
310         filename = g_filename_from_uri (uri, NULL, NULL);
311         if (!filename) {
312                 g_free (cmd);
313                 return NULL;
314         }
315         
316         filename_dst = g_build_filename (ev_tmp_dir (), "evinceXXXXXX", NULL);
317         fd = g_mkstemp (filename_dst);
318         if (fd < 0) {
319                 g_free (cmd);
320                 g_free (filename);
321                 g_free (filename_dst);
322                 return NULL;
323         }
324
325         argv[0] = cmd;
326         argv[1] = compress ? "-c" : "-cd";
327         argv[2] = filename;
328         argv[3] = NULL;
329
330         if (g_spawn_async_with_pipes (NULL, argv, NULL,
331                                       G_SPAWN_STDERR_TO_DEV_NULL,
332                                       NULL, NULL, NULL,
333                                       NULL, &pout, NULL, error)) {
334                 GIOChannel *in, *out;
335                 gchar buf[BUFFER_SIZE];
336                 GIOStatus read_st, write_st;
337                 gsize bytes_read, bytes_written;
338
339                 in = g_io_channel_unix_new (pout);
340                 g_io_channel_set_encoding (in, NULL, NULL);
341                 out = g_io_channel_unix_new (fd);
342                 g_io_channel_set_encoding (out, NULL, NULL);
343
344                 do {
345                         read_st = g_io_channel_read_chars (in, buf,
346                                                            BUFFER_SIZE,
347                                                            &bytes_read,
348                                                            error);
349                         if (read_st == G_IO_STATUS_NORMAL) {
350                                 write_st = g_io_channel_write_chars (out, buf,
351                                                                      bytes_read,
352                                                                      &bytes_written,
353                                                                      error);
354                                 if (write_st == G_IO_STATUS_ERROR)
355                                         break;
356                         } else if (read_st == G_IO_STATUS_ERROR) {
357                                 break;
358                         }
359                 } while (bytes_read > 0);
360
361                 g_io_channel_unref (in);
362                 g_io_channel_unref (out);
363         }
364
365         close (fd);
366
367         if (*error == NULL) {
368                 uri_dst = g_filename_to_uri (filename_dst, NULL, NULL);
369         }
370
371         g_free (cmd);
372         g_free (filename);
373         g_free (filename_dst);
374
375         return uri_dst;
376 }
377
378 gchar *
379 ev_file_uncompress (const gchar       *uri,
380                     EvCompressionType  type,
381                     GError           **error)
382 {
383         g_return_val_if_fail (uri != NULL, NULL);
384
385         return compression_run (uri, type, FALSE, error);
386 }
387
388 gchar *
389 ev_file_compress (const gchar       *uri,
390                   EvCompressionType  type,
391                   GError           **error)
392 {
393         g_return_val_if_fail (uri != NULL, NULL);
394
395         return compression_run (uri, type, TRUE, error);
396 }