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