]> www.fi.muni.cz Git - evince.git/blob - libdocument/ev-file-helpers.c
Add functions to delete temporary files created by evince in a safe way.
[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 #include <libgnomevfs/gnome-vfs-uri.h>
33 #include <libgnomevfs/gnome-vfs-utils.h>
34 #include <libgnomevfs/gnome-vfs-ops.h>
35 #include <libgnomevfs/gnome-vfs-xfer.h>
36
37 #if WITH_GNOME
38 #include <libgnome/gnome-init.h>
39 #endif
40
41 #include "ev-file-helpers.h"
42
43 static gchar *dot_dir = NULL;
44 static gchar *tmp_dir = NULL;
45 static gint   count = 0;
46
47 static gboolean
48 ensure_dir_exists (const char *dir)
49 {
50         if (g_file_test (dir, G_FILE_TEST_IS_DIR))
51                 return TRUE;
52         
53         if (g_mkdir_with_parents (dir, 488) == 0)
54                 return TRUE;
55
56         if (errno == EEXIST)
57                 return g_file_test (dir, G_FILE_TEST_IS_DIR);
58         
59         g_warning ("Failed to create directory %s: %s", dir, strerror (errno));
60         return FALSE;
61 }
62
63 const gchar *
64 ev_dot_dir (void)
65 {
66         if (dot_dir == NULL) {
67                 gboolean exists;
68
69 #if WITH_GNOME
70                 dot_dir = g_build_filename (gnome_user_dir_get (),
71                                             "evince",
72                                             NULL);
73 #else
74                 dot_dir = g_build_filename (g_get_user_config_dir (),
75                                             "evince",
76                                             NULL);
77 #endif
78
79                 exists = ensure_dir_exists (dot_dir);
80                 if (!exists)
81                         exit (1);
82         }
83
84         return dot_dir;
85 }
86
87 const gchar *
88 ev_tmp_dir (void)
89 {
90         if (tmp_dir == NULL) {
91                 gboolean exists;
92                 gchar   *dirname;
93
94                 dirname = g_strdup_printf ("evince-%u", getpid ());
95                 tmp_dir = g_build_filename (g_get_tmp_dir (),
96                                             dirname,
97                                             NULL);
98                 g_free (dirname);
99
100                 exists = ensure_dir_exists (tmp_dir);
101                 g_assert (exists);
102         }
103
104         return tmp_dir;
105 }
106
107 void
108 ev_file_helpers_init (void)
109 {
110 }
111
112 void
113 ev_file_helpers_shutdown (void)
114 {       
115         if (tmp_dir != NULL)    
116                 g_rmdir (tmp_dir);
117
118         g_free (tmp_dir);
119         g_free (dot_dir);
120
121         dot_dir = NULL;
122         tmp_dir = NULL;
123 }
124
125 gchar * 
126 ev_tmp_filename (const gchar *prefix)
127 {
128         gchar *basename;
129         gchar *filename = NULL;
130
131         do {
132                 if (filename != NULL)
133                         g_free (filename);
134                         
135                 basename = g_strdup_printf ("%s-%d",
136                                             prefix ? prefix : "document",
137                                             count ++);
138                 
139                 filename = g_build_filename (ev_tmp_dir (),
140                                              basename, NULL);
141                 
142                 g_free (basename);
143         } while (g_file_test (filename, G_FILE_TEST_EXISTS));
144                         
145         return filename;
146 }
147
148 /* Remove a local temp file created by evince */
149 void
150 ev_tmp_filename_unlink (const gchar *filename)
151 {
152         const gchar *tempdir;
153         
154         if (!filename)
155                 return;
156
157         tempdir = g_get_tmp_dir ();
158         if (g_ascii_strncasecmp (filename, tempdir, strlen (tempdir)) == 0) {
159                 g_unlink (filename);
160         }
161 }
162
163 void
164 ev_tmp_uri_unlink (const gchar *uri)
165 {
166         GnomeVFSURI *vfs_uri;
167         gchar       *filename;
168         
169         if (!uri)
170                 return;
171         
172         vfs_uri = gnome_vfs_uri_new (uri);
173         if (!gnome_vfs_uri_is_local (vfs_uri)) {
174                 g_warning ("Attempting to delete non local uri: %s\n", uri);
175                 gnome_vfs_uri_unref (vfs_uri);
176                 return;
177         }
178         gnome_vfs_uri_unref (vfs_uri);
179
180         filename = g_filename_from_uri (uri, NULL, NULL);
181         ev_tmp_filename_unlink (filename);
182         g_free (filename);
183 }
184
185 gboolean
186 ev_xfer_uri_simple (const char *from,
187                     const char *to,
188                     GError     **error)
189 {
190         GnomeVFSResult result;
191         GnomeVFSURI *source_uri;
192         GnomeVFSURI *target_uri;
193         
194         if (!from)
195                 return FALSE;
196         
197         source_uri = gnome_vfs_uri_new (from);
198         target_uri = gnome_vfs_uri_new (to);
199
200         result = gnome_vfs_xfer_uri (source_uri, target_uri, 
201                                      GNOME_VFS_XFER_DEFAULT | GNOME_VFS_XFER_FOLLOW_LINKS,
202                                      GNOME_VFS_XFER_ERROR_MODE_ABORT,
203                                      GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE,
204                                      NULL,
205                                      NULL);
206         gnome_vfs_uri_unref (target_uri);
207         gnome_vfs_uri_unref (source_uri);
208     
209         if (result != GNOME_VFS_OK)
210                 g_set_error (error,
211                              G_FILE_ERROR,
212                              G_FILE_ERROR_FAILED,
213                              gnome_vfs_result_to_string (result));
214         return (result == GNOME_VFS_OK);
215
216 }
217
218 /* Compressed files support */
219 #define BZIPCOMMAND "bzip2"
220 #define GZIPCOMMAND "gzip"
221 #define N_ARGS      4
222 #define BUFFER_SIZE 1024
223
224 static gchar *
225 compression_run (const gchar       *uri,
226                  EvCompressionType  type,
227                  gboolean           compress, 
228                  GError           **error)
229 {
230         gchar *argv[N_ARGS];
231         gchar *uri_dst = NULL;
232         gchar *filename, *filename_dst;
233         gchar *cmd;
234         gint   fd, pout;
235
236         if (type == EV_COMPRESSION_NONE)
237                 return NULL;
238
239         cmd = g_find_program_in_path ((type == EV_COMPRESSION_BZIP2) ? BZIPCOMMAND : GZIPCOMMAND);
240         if (!cmd)
241                 return NULL;
242
243         filename = g_filename_from_uri (uri, NULL, NULL);
244         if (!filename) {
245                 g_free (cmd);
246                 return NULL;
247         }
248         
249         filename_dst = g_build_filename (ev_tmp_dir (), "evinceXXXXXX", NULL);
250         fd = g_mkstemp (filename_dst);
251         if (fd < 0) {
252                 g_free (cmd);
253                 g_free (filename);
254                 g_free (filename_dst);
255                 return NULL;
256         }
257
258         argv[0] = cmd;
259         argv[1] = compress ? "-c" : "-cd";
260         argv[2] = filename;
261         argv[3] = NULL;
262
263         if (g_spawn_async_with_pipes (NULL, argv, NULL,
264                                       G_SPAWN_STDERR_TO_DEV_NULL,
265                                       NULL, NULL, NULL,
266                                       NULL, &pout, NULL, error)) {
267                 GIOChannel *in, *out;
268                 gchar buf[BUFFER_SIZE];
269                 GIOStatus read_st, write_st;
270                 gsize bytes_read, bytes_written;
271
272                 in = g_io_channel_unix_new (pout);
273                 g_io_channel_set_encoding (in, NULL, NULL);
274                 out = g_io_channel_unix_new (fd);
275                 g_io_channel_set_encoding (out, NULL, NULL);
276
277                 do {
278                         read_st = g_io_channel_read_chars (in, buf,
279                                                            BUFFER_SIZE,
280                                                            &bytes_read,
281                                                            error);
282                         if (read_st == G_IO_STATUS_NORMAL) {
283                                 write_st = g_io_channel_write_chars (out, buf,
284                                                                      bytes_read,
285                                                                      &bytes_written,
286                                                                      error);
287                                 if (write_st == G_IO_STATUS_ERROR)
288                                         break;
289                         } else if (read_st == G_IO_STATUS_ERROR) {
290                                 break;
291                         }
292                 } while (bytes_read > 0);
293
294                 g_io_channel_unref (in);
295                 g_io_channel_unref (out);
296         }
297
298         close (fd);
299
300         if (*error == NULL) {
301                 uri_dst = g_filename_to_uri (filename_dst, NULL, NULL);
302         }
303
304         g_free (cmd);
305         g_free (filename);
306         g_free (filename_dst);
307
308         return uri_dst;
309 }
310
311 gchar *
312 ev_file_uncompress (const gchar       *uri,
313                     EvCompressionType  type,
314                     GError           **error)
315 {
316         g_return_val_if_fail (uri != NULL, NULL);
317
318         return compression_run (uri, type, FALSE, error);
319 }
320
321 gchar *
322 ev_file_compress (const gchar       *uri,
323                   EvCompressionType  type,
324                   GError           **error)
325 {
326         g_return_val_if_fail (uri != NULL, NULL);
327
328         return compression_run (uri, type, TRUE, error);
329 }