1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 
3 /*
4  *  Engrampa
5  *
6  *  Copyright (C) 2001, 2003 Free Software Foundation, Inc.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02110-1301, USA.
21  */
22 
23 #include <config.h>
24 #include <pwd.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <time.h>
30 #include <unistd.h>
31 #include <sys/param.h>
32 #include <sys/stat.h>
33 #include <sys/time.h>
34 #include <sys/types.h>
35 #include <dirent.h>
36 
37 #include <glib.h>
38 #include <gio/gio.h>
39 #include "file-utils.h"
40 #include "glib-utils.h"
41 #include "fr-init.h"
42 
43 
44 #ifndef HAVE_MKDTEMP
45 #include "mkdtemp.h"
46 #endif
47 
48 #define BUF_SIZE 4096
49 #define FILE_PREFIX    "file://"
50 #define FILE_PREFIX_L  7
51 #define SPECIAL_DIR(x) ((strcmp ((x), "..") == 0) || (strcmp ((x), ".") == 0))
52 
53 
54 gboolean
uri_exists(const char * uri)55 uri_exists (const char *uri)
56 {
57 	GFile     *file;
58 	gboolean   exists;
59 
60 	if (uri == NULL)
61 		return FALSE;
62 
63 	file = g_file_new_for_uri (uri);
64 	exists = g_file_query_exists (file, NULL);
65 	g_object_unref (file);
66 
67 	return exists;
68 }
69 
70 
71 static gboolean
uri_is_filetype(const char * uri,GFileType file_type)72 uri_is_filetype (const char *uri,
73 		 GFileType   file_type)
74 {
75 	gboolean   result = FALSE;
76 	GFile     *file;
77 	GFileInfo *info;
78 	GError    *error = NULL;
79 
80 	file = g_file_new_for_uri (uri);
81 
82 	if (! g_file_query_exists (file, NULL)) {
83 		g_object_unref (file);
84 		return FALSE;
85 	}
86 
87 	info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE, 0, NULL, &error);
88 	if (error == NULL) {
89 		result = (g_file_info_get_file_type (info) == file_type);
90 	}
91 	else {
92 		g_warning ("Failed to get file type for uri %s: %s", uri, error->message);
93 		g_error_free (error);
94 	}
95 
96 	g_object_unref (info);
97 	g_object_unref (file);
98 
99 	return result;
100 }
101 
102 
103 gboolean
uri_is_file(const char * uri)104 uri_is_file (const char *uri)
105 {
106 	return uri_is_filetype (uri, G_FILE_TYPE_REGULAR);
107 }
108 
109 
110 gboolean
uri_is_dir(const char * uri)111 uri_is_dir (const char *uri)
112 {
113 	return uri_is_filetype (uri, G_FILE_TYPE_DIRECTORY);
114 }
115 
116 
117 gboolean
path_is_dir(const char * path)118 path_is_dir (const char *path)
119 {
120 	char     *uri;
121 	gboolean  result;
122 
123 	uri = g_filename_to_uri (path, NULL, NULL);
124 	result = uri_is_dir (uri);
125 	g_free (uri);
126 
127 	return result;
128 }
129 
130 gboolean
uri_is_local(const char * uri)131 uri_is_local (const char  *uri)
132 {
133 	return strncmp (uri, "file://", 7) == 0;
134 }
135 
136 
137 gboolean
dir_is_empty(const char * uri)138 dir_is_empty (const char *uri)
139 {
140 	GFile           *file;
141 	GFileEnumerator *file_enum;
142 	GFileInfo       *info;
143 	GError          *error = NULL;
144 	int              n = 0;
145 
146 	file = g_file_new_for_uri (uri);
147 
148 	if (! g_file_query_exists (file, NULL)) {
149 		g_object_unref (file);
150 		return TRUE;
151 	}
152 
153 	file_enum = g_file_enumerate_children (file, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, &error);
154 	if (error != NULL) {
155 		g_warning ("Failed to enumerate children of %s: %s", uri, error->message);
156 		g_error_free (error);
157 		g_object_unref (file_enum);
158 		g_object_unref (file);
159 		return TRUE;
160 	}
161 
162 	while ((n == 0) && ((info = g_file_enumerator_next_file (file_enum, NULL, &error)) != NULL)) {
163 		if (error != NULL) {
164 			g_warning ("Encountered error while enumerating children of %s (ignoring): %s", uri, error->message);
165 			g_error_free (error);
166 		}
167 		else if (! SPECIAL_DIR (g_file_info_get_name (info)))
168 			n++;
169 		g_object_unref (info);
170 	}
171 
172 	g_object_unref (file);
173 	g_object_unref (file_enum);
174 
175 	return (n == 0);
176 }
177 
178 
179 gboolean
dir_contains_one_object(const char * uri)180 dir_contains_one_object (const char *uri)
181 {
182 	GFile           *file;
183 	GFileEnumerator *file_enum;
184 	GFileInfo       *info;
185 	GError          *err = NULL;
186 	int              n = 0;
187 
188 	file = g_file_new_for_uri (uri);
189 
190 	if (! g_file_query_exists (file, NULL)) {
191 		g_object_unref (file);
192 		return FALSE;
193 	}
194 
195 	file_enum = g_file_enumerate_children (file, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, &err);
196 	if (err != NULL) {
197 		g_warning ("Failed to enumerate children of %s: %s", uri, err->message);
198 		g_error_free (err);
199 		g_object_unref (file_enum);
200 		g_object_unref (file);
201 		return FALSE;
202 	}
203 
204 	while ((info = g_file_enumerator_next_file (file_enum, NULL, &err)) != NULL) {
205 		const char *name;
206 
207 		if (err != NULL) {
208 			g_warning ("Encountered error while enumerating children of %s, ignoring: %s", uri, err->message);
209 			g_error_free (err);
210 			g_object_unref (info);
211 			continue;
212 		}
213 
214 		name = g_file_info_get_name (info);
215 		if (strcmp (name, ".") == 0 || strcmp (name, "..") == 0) {
216 			g_object_unref (info);
217  			continue;
218 		}
219 
220 		g_object_unref (info);
221 
222 		if (++n > 1)
223 			break;
224 	}
225 
226 	g_object_unref (file);
227 	g_object_unref (file_enum);
228 
229 	return (n == 1);
230 }
231 
232 
233 char *
get_dir_content_if_unique(const char * uri)234 get_dir_content_if_unique (const char  *uri)
235 {
236 	GFile           *file;
237 	GFileEnumerator *file_enum;
238 	GFileInfo       *info;
239 	GError          *err = NULL;
240 	char            *content_uri = NULL;
241 
242 	file = g_file_new_for_uri (uri);
243 
244 	if (! g_file_query_exists (file, NULL)) {
245 		g_object_unref (file);
246 		return NULL;
247 	}
248 
249 	file_enum = g_file_enumerate_children (file, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, &err);
250 	if (err != NULL) {
251 		g_warning ("Failed to enumerate children of %s: %s", uri, err->message);
252 		g_error_free (err);
253 		return NULL;
254 	}
255 
256 	while ((info = g_file_enumerator_next_file (file_enum, NULL, &err)) != NULL) {
257 		const char *name;
258 
259 		if (err != NULL) {
260 			g_warning ("Failed to get info while enumerating children: %s", err->message);
261 			g_clear_error (&err);
262 			g_object_unref (info);
263 			continue;
264 		}
265 
266 		name = g_file_info_get_name (info);
267 		if ((strcmp (name, ".") == 0) || (strcmp (name, "..") == 0)) {
268 			g_object_unref (info);
269 			continue;
270 		}
271 
272 		if (content_uri != NULL) {
273 			g_free (content_uri);
274 			g_object_unref (info);
275 			content_uri = NULL;
276 			break;
277 		}
278 
279 		content_uri = build_uri (uri, name, NULL);
280 		g_object_unref (info);
281 	}
282 
283 	if (err != NULL) {
284 		g_warning ("Failed to get info after enumerating children: %s", err->message);
285 		g_clear_error (&err);
286 	}
287 
288 	g_object_unref (file_enum);
289 	g_object_unref (file);
290 
291 	return content_uri;
292 }
293 
294 
295 /* Check whether the dirname is contained in filename */
296 gboolean
path_in_path(const char * dirname,const char * filename)297 path_in_path (const char *dirname,
298 	      const char *filename)
299 {
300 	int dirname_l, filename_l, separator_position;
301 
302 	if ((dirname == NULL) || (filename == NULL))
303 		return FALSE;
304 
305 	dirname_l = strlen (dirname);
306 	filename_l = strlen (filename);
307 
308 	if ((dirname_l == filename_l + 1)
309 	     && (dirname[dirname_l - 1] == '/'))
310 		return FALSE;
311 
312 	if ((filename_l == dirname_l + 1)
313 	     && (filename[filename_l - 1] == '/'))
314 		return FALSE;
315 
316 	if (dirname[dirname_l - 1] == '/')
317 		separator_position = dirname_l - 1;
318 	else
319 		separator_position = dirname_l;
320 
321 	return ((filename_l > dirname_l)
322 		&& (strncmp (dirname, filename, dirname_l) == 0)
323 		&& (filename[separator_position] == '/'));
324 }
325 
326 
327 goffset
get_file_size(const char * uri)328 get_file_size (const char *uri)
329 {
330 	goffset    size = 0;
331 	GFile     *file;
332 	GFileInfo *info;
333 	GError    *err = NULL;
334 
335 	if ((uri == NULL) || (*uri == '\0'))
336 		return 0;
337 
338 	file = g_file_new_for_uri (uri);
339 	info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_SIZE, 0, NULL, &err);
340 	if (err == NULL) {
341 		size = g_file_info_get_size (info);
342 	}
343 	else {
344 		g_warning ("Failed to get file size for %s: %s", uri, err->message);
345 		g_error_free (err);
346 	}
347 
348 	g_object_unref (info);
349 	g_object_unref (file);
350 
351 	return size;
352 }
353 
354 
355 goffset
get_file_size_for_path(const char * path)356 get_file_size_for_path (const char *path)
357 {
358 	char    *uri;
359 	goffset  result;
360 
361 	uri = g_filename_to_uri (path, NULL, NULL);
362 	result = get_file_size (uri);
363 	g_free (uri);
364 
365 	return result;
366 }
367 
368 
369 static time_t
get_file_time_type(const char * uri,const char * type)370 get_file_time_type (const char *uri,
371 		    const char *type)
372 {
373 	time_t     result = 0;
374 	GFile     *file;
375 	GFileInfo *info;
376 	GError    *err = NULL;
377 
378 	if ((uri == NULL) || (*uri == '\0'))
379  		return 0;
380 
381 	file = g_file_new_for_uri (uri);
382 	info = g_file_query_info (file, type, 0, NULL, &err);
383 	if (err == NULL) {
384 		result = (time_t) g_file_info_get_attribute_uint64 (info, type);
385 	}
386 	else {
387 		g_warning ("Failed to get %s: %s", type, err->message);
388 		g_error_free (err);
389 		result = 0;
390 	}
391 
392 	g_object_unref (info);
393 	g_object_unref (file);
394 
395 	return result;
396 }
397 
398 
399 time_t
get_file_mtime(const char * uri)400 get_file_mtime (const char *uri)
401 {
402 	return get_file_time_type (uri, G_FILE_ATTRIBUTE_TIME_MODIFIED);
403 }
404 
405 
406 time_t
get_file_mtime_for_path(const char * path)407 get_file_mtime_for_path (const char *path)
408 {
409 	char   *uri;
410 	time_t  result;
411 
412 	uri = g_filename_to_uri (path, NULL, NULL);
413 	result = get_file_mtime (uri);
414 	g_free (uri);
415 
416 	return result;
417 }
418 
419 
420 time_t
get_file_ctime(const char * uri)421 get_file_ctime (const char *uri)
422 {
423 	return get_file_time_type (uri, G_FILE_ATTRIBUTE_TIME_CREATED);
424 }
425 
426 
427 gboolean
file_is_hidden(const gchar * name)428 file_is_hidden (const gchar *name)
429 {
430 	if (name[0] != '.') return FALSE;
431 	if (name[1] == '\0') return FALSE;
432 	if ((name[1] == '.') && (name[2] == '\0')) return FALSE;
433 
434 	return TRUE;
435 }
436 
437 
438 /* like g_path_get_basename but does not warn about NULL and does not
439  * alloc a new string. */
file_name_from_path(const gchar * file_name)440 const gchar* file_name_from_path(const gchar *file_name)
441 {
442 	register char   *base;
443 	register gssize  last_char;
444 
445 	if (file_name == NULL)
446 		return NULL;
447 
448 	if (file_name[0] == '\0')
449 		return "";
450 
451 	last_char = strlen (file_name) - 1;
452 
453 	if (file_name [last_char] == G_DIR_SEPARATOR)
454 		return "";
455 
456 	base = g_utf8_strrchr (file_name, -1, G_DIR_SEPARATOR);
457 	if (! base)
458 		return file_name;
459 
460 	return base + 1;
461 }
462 
463 
464 char *
dir_name_from_path(const gchar * path)465 dir_name_from_path (const gchar *path)
466 {
467 	register gssize base;
468 	register gssize last_char;
469 
470 	if (path == NULL)
471 		return NULL;
472 
473 	if (path[0] == '\0')
474 		return g_strdup ("");
475 
476 	last_char = strlen (path) - 1;
477 	if (path[last_char] == G_DIR_SEPARATOR)
478 		last_char--;
479 
480 	base = last_char;
481 	while ((base >= 0) && (path[base] != G_DIR_SEPARATOR))
482 		base--;
483 
484 	return g_strndup (path + base + 1, last_char - base);
485 }
486 
487 
488 gchar *
remove_level_from_path(const gchar * path)489 remove_level_from_path (const gchar *path)
490 {
491 	int         p;
492 	const char *ptr = path;
493 	char       *new_path;
494 
495 	if (path == NULL)
496 		return NULL;
497 
498 	p = strlen (path) - 1;
499 	if (p < 0)
500 		return NULL;
501 
502 	while ((p > 0) && (ptr[p] != '/'))
503 		p--;
504 	if ((p == 0) && (ptr[p] == '/'))
505 		p++;
506 	new_path = g_strndup (path, (guint)p);
507 
508 	return new_path;
509 }
510 
511 
512 char *
remove_ending_separator(const char * path)513 remove_ending_separator (const char *path)
514 {
515 	gint len, copy_len;
516 
517 	if (path == NULL)
518 		return NULL;
519 
520 	copy_len = len = strlen (path);
521 	if ((len > 1) && (path[len - 1] == '/'))
522 		copy_len--;
523 
524 	return g_strndup (path, copy_len);
525 }
526 
527 
528 char *
build_uri(const char * base,...)529 build_uri (const char *base, ...)
530 {
531 	va_list     args;
532 	const char *child;
533 	GString    *uri;
534 
535 	uri = g_string_new (base);
536 
537 	va_start (args, base);
538         while ((child = va_arg (args, const char *)) != NULL) {
539         	if (! g_str_has_suffix (uri->str, "/") && ! g_str_has_prefix (child, "/"))
540         		g_string_append (uri, "/");
541         	g_string_append (uri, child);
542         }
543 	va_end (args);
544 
545 	return g_string_free (uri, FALSE);
546 }
547 
548 
549 gchar *
remove_extension_from_path(const gchar * path)550 remove_extension_from_path (const gchar *path)
551 {
552 	int         len;
553 	int         p;
554 	const char *ptr = path;
555 	char       *new_path;
556 
557 	if (! path)
558 		return NULL;
559 
560 	len = strlen (path);
561 	if (len == 1)
562 		return g_strdup (path);
563 
564 	p = len - 1;
565 	while ((p > 0) && (ptr[p] != '.'))
566 		p--;
567 	if (p == 0)
568 		p = len;
569 	new_path = g_strndup (path, (guint) p);
570 
571 	return new_path;
572 }
573 
574 
575 gboolean
make_directory_tree(GFile * dir,mode_t mode,GError ** error)576 make_directory_tree (GFile    *dir,
577 		     mode_t    mode,
578 		     GError  **error)
579 {
580 	gboolean  success = TRUE;
581 	GFile    *parent;
582 
583 	if ((dir == NULL) || g_file_query_exists (dir, NULL))
584 		return TRUE;
585 
586 	parent = g_file_get_parent (dir);
587 	if (parent != NULL) {
588 		success = make_directory_tree (parent, mode, error);
589 		g_object_unref (parent);
590 		if (! success)
591 			return FALSE;
592 	}
593 
594 	success = g_file_make_directory (dir, NULL, error);
595 	if ((error != NULL) && (*error != NULL) && g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_EXISTS)) {
596 		g_clear_error (error);
597 		success = TRUE;
598 	}
599 
600 	if (success)
601 		g_file_set_attribute_uint32 (dir,
602 					     G_FILE_ATTRIBUTE_UNIX_MODE,
603 					     mode,
604 					     0,
605 					     NULL,
606 					     NULL);
607 
608 	return success;
609 }
610 
611 
612 gboolean
ensure_dir_exists(const char * uri,mode_t mode,GError ** error)613 ensure_dir_exists (const char  *uri,
614 		   mode_t       mode,
615 		   GError     **error)
616 {
617 	GFile  *dir;
618 	GError *priv_error = NULL;
619 
620 	if (uri == NULL)
621 		return FALSE;
622 
623 	if (error == NULL)
624 		error = &priv_error;
625 
626 	dir = g_file_new_for_uri (uri);
627 	if (! make_directory_tree (dir, mode, error)) {
628 		g_warning ("could create directory %s: %s", uri, (*error)->message);
629 		if (priv_error != NULL)
630 			g_clear_error (&priv_error);
631 		return FALSE;
632 	}
633 
634 	return TRUE;
635 }
636 
637 
638 gboolean
make_directory_tree_from_path(const char * path,mode_t mode,GError ** error)639 make_directory_tree_from_path (const char  *path,
640 		   	       mode_t       mode,
641 		   	       GError     **error)
642 {
643 	char     *uri;
644 	gboolean  result;
645 
646 	uri = g_filename_to_uri (path, NULL, NULL);
647 	result = ensure_dir_exists (uri, mode, error);
648 	g_free (uri);
649 
650 	return result;
651 }
652 
653 
654 const char *
get_file_extension(const char * filename)655 get_file_extension (const char *filename)
656 {
657 	const char *ptr = filename;
658 	int         len;
659 	int         p;
660 	const char *ext;
661 
662 	if (filename == NULL)
663 		return NULL;
664 
665 	len = strlen (filename);
666 	if (len <= 1)
667 		return NULL;
668 
669 	p = len - 1;
670 	while ((p >= 0) && (ptr[p] != '.'))
671 		p--;
672 	if (p < 0)
673 		return NULL;
674 
675 	ext = filename + p;
676 	if (ext - 4 > filename) {
677 		const char *test = ext - 4;
678 		if (strncmp (test, ".tar", 4) == 0)
679 			ext = ext - 4;
680 	}
681 	return ext;
682 }
683 
684 
685 gboolean
file_extension_is(const char * filename,const char * ext)686 file_extension_is (const char *filename,
687 		   const char *ext)
688 {
689 	int filename_l, ext_l;
690 
691 	filename_l = strlen (filename);
692 	ext_l = strlen (ext);
693 
694 	if (filename_l < ext_l)
695 		return FALSE;
696 	return strcasecmp (filename + filename_l - ext_l, ext) == 0;
697 }
698 
699 
700 gboolean
is_mime_type(const char * mime_type,const char * pattern)701 is_mime_type (const char *mime_type,
702 	      const char *pattern)
703 {
704 	return (strcasecmp (mime_type, pattern) == 0);
705 }
706 
707 
708 const char*
get_file_mime_type(const char * uri,gboolean fast_file_type)709 get_file_mime_type (const char *uri,
710                     gboolean    fast_file_type)
711 {
712 	GFile      *file;
713 	GFileInfo  *info;
714 	GError     *err = NULL;
715  	const char *result = NULL;
716 
717  	file = g_file_new_for_uri (uri);
718 	info = g_file_query_info (file,
719 				  fast_file_type ?
720 				  G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE :
721 				  G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
722 				  0, NULL, &err);
723 	if (info == NULL) {
724 		g_warning ("could not get content type for %s: %s", uri, err->message);
725 		g_clear_error (&err);
726 	}
727 	else {
728 		result = get_static_string (g_file_info_get_content_type (info));
729 		g_object_unref (info);
730 	}
731 
732 	g_object_unref (file);
733 
734 	return result;
735 }
736 
737 
738 const char*
get_file_mime_type_for_path(const char * filename,gboolean fast_file_type)739 get_file_mime_type_for_path (const char  *filename,
740                     	     gboolean     fast_file_type)
741 {
742 	char       *uri;
743 	const char *mime_type;
744 
745 	uri = g_filename_to_uri (filename, NULL, NULL);
746 	mime_type = get_file_mime_type (uri, fast_file_type);
747 	g_free (uri);
748 
749 	return mime_type;
750 }
751 
752 
753 void
path_list_free(GList * path_list)754 path_list_free (GList *path_list)
755 {
756 	if (path_list == NULL)
757 		return;
758 	g_list_foreach (path_list, (GFunc) g_free, NULL);
759 	g_list_free (path_list);
760 }
761 
762 
763 GList *
path_list_dup(GList * path_list)764 path_list_dup (GList *path_list)
765 {
766 	GList *new_list = NULL;
767 	GList *scan;
768 
769 	for (scan = path_list; scan; scan = scan->next)
770 		new_list = g_list_prepend (new_list, g_strdup (scan->data));
771 
772 	return g_list_reverse (new_list);
773 }
774 
775 
776 guint64
get_dest_free_space(const char * path)777 get_dest_free_space (const char *path)
778 {
779 	guint64    freespace = 0;
780 	GFile     *file;
781 	GFileInfo *info;
782 	GError    *err = NULL;
783 
784 	file = g_file_new_for_path (path);
785 	info = g_file_query_filesystem_info (file, G_FILE_ATTRIBUTE_FILESYSTEM_FREE, NULL, &err);
786 	if (info != NULL) {
787 		freespace = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
788 		g_object_unref (info);
789 	}
790 	else {
791 		g_warning ("Could not get filesystem free space on volume that contains %s: %s", path, err->message);
792 		g_error_free (err);
793 	}
794 	g_object_unref (file);
795 
796 	return freespace;
797 }
798 
799 
800 static gboolean
delete_directory_recursive(GFile * dir,GError ** error)801 delete_directory_recursive (GFile   *dir,
802 			    GError **error)
803 {
804 	char            *uri;
805 	GFileEnumerator *file_enum;
806 	GFileInfo       *info;
807 	gboolean         error_occurred = FALSE;
808 
809 	if (error != NULL)
810 		*error = NULL;
811 
812 	file_enum = g_file_enumerate_children (dir,
813 					       G_FILE_ATTRIBUTE_STANDARD_NAME ","
814 					       G_FILE_ATTRIBUTE_STANDARD_TYPE,
815 					       0, NULL, error);
816 
817 	uri = g_file_get_uri (dir);
818 	while (! error_occurred && (info = g_file_enumerator_next_file (file_enum, NULL, error)) != NULL) {
819 		char  *child_uri;
820 		GFile *child;
821 
822 		child_uri = build_uri (uri, g_file_info_get_name (info), NULL);
823 		child = g_file_new_for_uri (child_uri);
824 
825 		switch (g_file_info_get_file_type (info)) {
826 		case G_FILE_TYPE_DIRECTORY:
827 			if (! delete_directory_recursive (child, error))
828 				error_occurred = TRUE;
829 			break;
830 		default:
831 			if (! g_file_delete (child, NULL, error))
832 				error_occurred = TRUE;
833 			break;
834 		}
835 
836 		g_object_unref (child);
837 		g_free (child_uri);
838 		g_object_unref (info);
839 	}
840 	g_free (uri);
841 
842 	if (! error_occurred && ! g_file_delete (dir, NULL, error))
843  		error_occurred = TRUE;
844 
845 	g_object_unref (file_enum);
846 
847 	return ! error_occurred;
848 }
849 
850 
851 gboolean
remove_directory(const char * uri)852 remove_directory (const char *uri)
853 {
854 	GFile     *dir;
855 	gboolean   result;
856 	GError    *error = NULL;
857 
858 	dir = g_file_new_for_uri (uri);
859 	result = delete_directory_recursive (dir, &error);
860 	if (! result) {
861 		g_warning ("Cannot delete %s: %s", uri, error->message);
862 		g_clear_error (&error);
863 	}
864 	g_object_unref (dir);
865 
866 	return result;
867 }
868 
869 
870 gboolean
remove_local_directory(const char * path)871 remove_local_directory (const char *path)
872 {
873 	char     *uri;
874 	gboolean  result;
875 
876 	if (path == NULL)
877 		return TRUE;
878 
879 	uri = g_filename_to_uri (path, NULL, NULL);
880 	result = remove_directory (uri);
881 	g_free (uri);
882 
883 	return result;
884 }
885 
886 
887 static const char *try_folder[] = { "cache", "~", "tmp", NULL };
888 
889 
890 static char *
ith_temp_folder_to_try(int n)891 ith_temp_folder_to_try (int n)
892 {
893 	const char *folder;
894 
895 	folder = try_folder[n];
896 	if (strcmp (folder, "cache") == 0)
897 		folder = g_get_user_cache_dir ();
898 	else if (strcmp (folder, "~") == 0)
899 		folder = g_get_home_dir ();
900 	else if (strcmp (folder, "tmp") == 0)
901 		folder = g_get_tmp_dir ();
902 
903 	return g_strdup (folder);
904 }
905 
906 
907 char *
get_temp_work_dir(const char * parent_folder)908 get_temp_work_dir (const char *parent_folder)
909 {
910 	guint64  max_size = 0;
911 	char    *best_folder = NULL;
912 	int      i;
913 	char    *template;
914 	char    *result = NULL;
915 
916 	if (parent_folder == NULL) {
917 		/* find the folder with more free space. */
918 
919 		for (i = 0; try_folder[i] != NULL; i++) {
920 			char    *folder;
921 			guint64  size;
922 
923 			folder = ith_temp_folder_to_try (i);
924 			size = get_dest_free_space (folder);
925 			if (max_size < size) {
926 				max_size = size;
927 				g_free (best_folder);
928 				best_folder = folder;
929 			}
930 			else
931 				g_free (folder);
932 		}
933 	}
934 	else
935 		best_folder = g_strdup (parent_folder);
936 
937 	if (best_folder == NULL)
938 		return NULL;
939 
940 	template = g_strconcat (best_folder, "/.fr-XXXXXX", NULL);
941 	result = mkdtemp (template);
942 
943 	if ((result == NULL) || (*result == '\0')) {
944 		g_free (template);
945 		result = NULL;
946 	}
947 
948 	g_free(best_folder);
949 
950 	return result;
951 }
952 
953 
954 gboolean
is_temp_work_dir(const char * dir)955 is_temp_work_dir (const char *dir)
956 {
957 	int i;
958 	char *folder = NULL;
959 
960 	if (strncmp (dir, "file://", 7) == 0)
961 		dir = dir + 7;
962 	else if (dir[0] != '/')
963 		return FALSE;
964 
965 	for (i = 0; try_folder[i] != NULL; i++) {
966 		folder = ith_temp_folder_to_try (i);
967 		if (strncmp (dir, folder, strlen (folder)) == 0)
968 			if (strncmp (dir + strlen (folder), "/.fr-", 5) == 0) {
969 				g_free (folder);
970 				return TRUE;
971 			}
972 		g_free (folder);
973 	}
974 
975 	return FALSE;
976 }
977 
978 
979 gboolean
is_temp_dir(const char * dir)980 is_temp_dir (const char *dir)
981 {
982 	if (strncmp (dir, "file://", 7) == 0)
983 		dir = dir + 7;
984 	if (strcmp (g_get_tmp_dir (), dir) == 0)
985 		return TRUE;
986 	if (path_in_path (g_get_tmp_dir (), dir))
987 		return TRUE;
988 	else
989 		return is_temp_work_dir (dir);
990 }
991 
992 
993 /* file list utils */
994 
995 
996 gboolean
file_list__match_pattern(const char * line,const char * pattern)997 file_list__match_pattern (const char *line,
998 			  const char *pattern)
999 {
1000 	const char *l = line, *p = pattern;
1001 
1002 	for (; (*p != 0) && (*l != 0); p++, l++) {
1003 		if (*p != '%') {
1004 			if (*p != *l)
1005 				return FALSE;
1006 		}
1007 		else {
1008 			p++;
1009 			switch (*p) {
1010 			case 'a':
1011 				break;
1012 			case 'n':
1013 				if (!isdigit (*l))
1014 					return FALSE;
1015 				break;
1016 			case 'c':
1017 				if (!isalpha (*l))
1018 					return FALSE;
1019 				break;
1020 			default:
1021 				return FALSE;
1022 			}
1023 		}
1024 	}
1025 
1026 	return (*p == 0);
1027 }
1028 
1029 
1030 int
file_list__get_index_from_pattern(const char * line,const char * pattern)1031 file_list__get_index_from_pattern (const char *line,
1032 				   const char *pattern)
1033 {
1034 	int         line_l, pattern_l;
1035 	const char *l;
1036 
1037 	line_l = strlen (line);
1038 	pattern_l = strlen (pattern);
1039 
1040 	if ((pattern_l == 0) || (line_l == 0))
1041 		return -1;
1042 
1043 	for (l = line; *l != 0; l++)
1044 		if (file_list__match_pattern (l, pattern))
1045 			return (l - line);
1046 
1047 	return -1;
1048 }
1049 
1050 
1051 char*
file_list__get_next_field(const char * line,int start_from,int field_n)1052 file_list__get_next_field (const char *line,
1053 			   int         start_from,
1054 			   int         field_n)
1055 {
1056 	const char *f_start, *f_end;
1057 
1058 	line = line + start_from;
1059 
1060 	f_start = line;
1061 	while ((*f_start == ' ') && (*f_start != *line))
1062 		f_start++;
1063 	f_end = f_start;
1064 
1065 	while ((field_n > 0) && (*f_end != 0)) {
1066 		if (*f_end == ' ') {
1067 			field_n--;
1068 			if (field_n != 0) {
1069 				while ((*f_end == ' ') && (*f_end != *line))
1070 					f_end++;
1071 				f_start = f_end;
1072 			}
1073 		} else
1074 			f_end++;
1075 	}
1076 
1077 	return g_strndup (f_start, f_end - f_start);
1078 }
1079 
1080 
1081 char*
file_list__get_prev_field(const char * line,int start_from,int field_n)1082 file_list__get_prev_field (const char *line,
1083 			   int         start_from,
1084 			   int         field_n)
1085 {
1086 	const char *f_start, *f_end;
1087 
1088 	f_start = line + start_from - 1;
1089 	while ((*f_start == ' ') && (*f_start != *line))
1090 		f_start--;
1091 	f_end = f_start;
1092 
1093 	while ((field_n > 0) && (*f_start != *line)) {
1094 		if (*f_start == ' ') {
1095 			field_n--;
1096 			if (field_n != 0) {
1097 				while ((*f_start == ' ') && (*f_start != *line))
1098 					f_start--;
1099 				f_end = f_start;
1100 			}
1101 		} else
1102 			f_start--;
1103 	}
1104 
1105 	return g_strndup (f_start + 1, f_end - f_start);
1106 }
1107 
1108 
1109 gboolean
check_permissions(const char * uri,int mode)1110 check_permissions (const char *uri,
1111 		   int         mode)
1112 {
1113 	GFile    *file;
1114 	gboolean  result;
1115 
1116 	file = g_file_new_for_uri (uri);
1117 	result = check_file_permissions (file, mode);
1118 
1119 	g_object_unref (file);
1120 
1121 	return result;
1122 }
1123 
1124 
1125 gboolean
check_file_permissions(GFile * file,int mode)1126 check_file_permissions (GFile *file,
1127 		        int    mode)
1128 {
1129 	gboolean   result = TRUE;
1130 	GFileInfo *info;
1131 	GError    *err = NULL;
1132 	gboolean   default_permission_when_unknown = TRUE;
1133 
1134 	info = g_file_query_info (file, "access::*", 0, NULL, &err);
1135 	if (err != NULL) {
1136 		g_clear_error (&err);
1137 		result = FALSE;
1138 	}
1139 	else {
1140 		if ((mode & R_OK) == R_OK) {
1141 			if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ))
1142 				result = (result && g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ));
1143 			else
1144 				result = (result && default_permission_when_unknown);
1145 		}
1146 
1147 		if ((mode & W_OK) == W_OK) {
1148 			if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE))
1149 				result = (result && g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE));
1150 			else
1151 				result = (result && default_permission_when_unknown);
1152 		}
1153 
1154 		if ((mode & X_OK) == X_OK) {
1155 			if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE))
1156 				result = (result && g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE));
1157 			else
1158 				result = (result && default_permission_when_unknown);
1159 		}
1160 
1161 		g_object_unref (info);
1162 	}
1163 
1164 	return result;
1165 }
1166 
1167 
1168 gboolean
is_program_in_path(const char * filename)1169 is_program_in_path (const char *filename)
1170 {
1171 	char *str;
1172 	char *value;
1173 	int   result = FALSE;
1174 
1175 	value = g_hash_table_lookup (ProgramsCache, filename);
1176 	if (value != NULL) {
1177 		result = (strcmp (value, "1") == 0);
1178 		return result;
1179 	}
1180 
1181 	str = g_find_program_in_path (filename);
1182 	if (str != NULL) {
1183 		g_free (str);
1184 		result = TRUE;
1185 	}
1186 
1187 	g_hash_table_insert (ProgramsCache,
1188 			     g_strdup (filename),
1189 			     result ? "1" : "0");
1190 
1191 	return result;
1192 }
1193 
1194 
1195 gboolean
is_program_available(const char * filename,gboolean check)1196 is_program_available (const char *filename,
1197 		      gboolean    check)
1198 {
1199 	return ! check || is_program_in_path (filename);
1200 }
1201 
1202 
1203 const char *
get_home_uri(void)1204 get_home_uri (void)
1205 {
1206 	static char *home_uri = NULL;
1207 	if (home_uri == NULL)
1208 		home_uri = g_filename_to_uri (g_get_home_dir (), NULL, NULL);
1209 	return home_uri;
1210 }
1211 
1212 
1213 char *
get_home_relative_uri(const char * partial_uri)1214 get_home_relative_uri (const char *partial_uri)
1215 {
1216 	return g_strconcat (get_home_uri (),
1217 			    "/",
1218 			    partial_uri,
1219 			    NULL);
1220 }
1221 
1222 
1223 GFile *
get_home_relative_file(const char * partial_uri)1224 get_home_relative_file (const char *partial_uri)
1225 {
1226 	GFile *file;
1227 	char  *uri;
1228 
1229 	uri = g_strconcat (get_home_uri (), "/", partial_uri, NULL);
1230 	file = g_file_new_for_uri (uri);
1231 	g_free (uri);
1232 
1233 	return file;
1234 }
1235 
1236 
1237 GFile *
get_user_config_subdirectory(const char * child_name,gboolean create_child)1238 get_user_config_subdirectory (const char *child_name,
1239 			      gboolean    create_child)
1240 {
1241 	char   *full_path;
1242 	GFile  *file;
1243 	GError *error = NULL;
1244 
1245 	full_path = g_strconcat (g_get_user_config_dir (), "/", child_name, NULL);
1246 	file = g_file_new_for_path (full_path);
1247 	g_free (full_path);
1248 
1249 	if  (create_child && ! make_directory_tree (file, 0700, &error)) {
1250 		g_warning ("%s", error->message);
1251 		g_error_free (error);
1252 		g_object_unref (file);
1253 		file = NULL;
1254 	}
1255 
1256 	return file;
1257 }
1258 
1259 
1260 const char *
remove_host_from_uri(const char * uri)1261 remove_host_from_uri (const char *uri)
1262 {
1263         const char *idx, *sep;
1264 
1265         if (uri == NULL)
1266                 return NULL;
1267 
1268         idx = strstr (uri, "://");
1269         if (idx == NULL)
1270                 return uri;
1271         idx += 3;
1272         if (*idx == '\0')
1273                 return "/";
1274         sep = strstr (idx, "/");
1275         if (sep == NULL)
1276                 return idx;
1277         return sep;
1278 }
1279 
1280 
1281 char *
get_uri_host(const char * uri)1282 get_uri_host (const char *uri)
1283 {
1284 	const char *idx;
1285 
1286 	idx = strstr (uri, "://");
1287 	if (idx == NULL)
1288 		return NULL;
1289 	idx = strstr (idx + 3, "/");
1290 	if (idx == NULL)
1291 		return NULL;
1292 	return g_strndup (uri, (idx - uri));
1293 }
1294 
1295 
1296 char *
get_uri_root(const char * uri)1297 get_uri_root (const char *uri)
1298 {
1299 	char *host;
1300 	char *root;
1301 
1302 	host = get_uri_host (uri);
1303 	if (host == NULL)
1304 		return NULL;
1305 	root = g_strconcat (host, "/", NULL);
1306 	g_free (host);
1307 
1308 	return root;
1309 }
1310 
1311 
1312 int
uricmp(const char * uri1,const char * uri2)1313 uricmp (const char *uri1,
1314 	const char *uri2)
1315 {
1316 	return strcmp_null_tolerant (uri1, uri2);
1317 }
1318 
1319 
1320 char *
get_alternative_uri(const char * folder,const char * name)1321 get_alternative_uri (const char *folder,
1322 	     const char *name)
1323 {
1324 	char *new_uri = NULL;
1325 	int   n = 1;
1326 
1327 	do {
1328 		g_free (new_uri);
1329 		if (n == 1)
1330 			new_uri = g_strconcat (folder, "/", name, NULL);
1331 		else
1332 			new_uri = g_strdup_printf ("%s/%s%%20(%d)", folder, name, n);
1333 		n++;
1334 	} while (uri_exists (new_uri));
1335 
1336 	return new_uri;
1337 }
1338 
1339 
1340 char *
get_alternative_uri_for_uri(const char * uri)1341 get_alternative_uri_for_uri (const char *uri)
1342 {
1343 	char *base_uri;
1344 	char *new_uri;
1345 
1346 	base_uri = remove_level_from_path (uri);
1347 	new_uri = get_alternative_uri (base_uri, file_name_from_path (uri));
1348 	g_free (base_uri);
1349 
1350 	return new_uri;
1351 }
1352 
1353 
1354 GList *
gio_file_list_dup(GList * l)1355 gio_file_list_dup (GList *l)
1356 {
1357 	GList *r = NULL, *scan;
1358 	for (scan = l; scan; scan = scan->next)
1359 		r = g_list_prepend (r, g_file_dup ((GFile*)scan->data));
1360 	return g_list_reverse (r);
1361 }
1362 
1363 
1364 void
gio_file_list_free(GList * l)1365 gio_file_list_free (GList *l)
1366 {
1367 	GList *scan;
1368 	for (scan = l; scan; scan = scan->next)
1369 		g_object_unref (scan->data);
1370 	g_list_free (l);
1371 }
1372 
1373 
1374 GList *
gio_file_list_new_from_uri_list(GList * uris)1375 gio_file_list_new_from_uri_list (GList *uris)
1376 {
1377 	GList *r = NULL, *scan;
1378 	for (scan = uris; scan; scan = scan->next)
1379 		r = g_list_prepend (r, g_file_new_for_uri ((char*)scan->data));
1380 	return g_list_reverse (r);
1381 }
1382 
1383 
1384 void
g_key_file_save(GKeyFile * key_file,GFile * file)1385 g_key_file_save (GKeyFile *key_file,
1386 	         GFile    *file)
1387 {
1388 	char   *file_data;
1389 	gsize   size;
1390 	GError *error = NULL;
1391 
1392 	file_data = g_key_file_to_data (key_file, &size, &error);
1393 	if (error != NULL) {
1394 		g_warning ("Could not save options: %s\n", error->message);
1395 		g_clear_error (&error);
1396 	}
1397 	else {
1398 		GFileOutputStream *stream;
1399 
1400 		stream = g_file_replace (file, NULL, FALSE, 0, NULL, &error);
1401 		if (stream == NULL) {
1402 			g_warning ("Could not save options: %s\n", error->message);
1403 			g_clear_error (&error);
1404 		}
1405 		else if (! g_output_stream_write_all (G_OUTPUT_STREAM (stream), file_data, size, NULL, NULL, &error)) {
1406 			g_warning ("Could not save options: %s\n", error->message);
1407 			g_clear_error (&error);
1408 		}
1409 		else if (! g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, &error)) {
1410 			g_warning ("Could not save options: %s\n", error->message);
1411 			g_clear_error (&error);
1412 		}
1413 
1414 		g_object_unref (stream);
1415 	}
1416 
1417 	g_free (file_data);
1418 }
1419