1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /*
4 * File-Roller
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, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <config.h>
23 #include <pwd.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include <time.h>
29 #include <unistd.h>
30 #include <sys/param.h>
31 #include <sys/stat.h>
32 #include <sys/time.h>
33 #include <sys/types.h>
34 #include <dirent.h>
35 #include <glib.h>
36 #include <gio/gio.h>
37 #include "file-utils.h"
38 #include "glib-utils.h"
39 #include "fr-init.h"
40
41
42 #ifndef HAVE_MKDTEMP
43 #include "mkdtemp.h"
44 #endif
45
46 #define BUF_SIZE 4096
47 #define FILE_PREFIX "file://"
48 #define FILE_PREFIX_L 7
49 #define IS_SPECIAL_DIR(x) ((strcmp ((x), "..") == 0) || (strcmp ((x), ".") == 0))
50
51
52 /* path */
53
54
55 static const char *try_folder[] = { "cache", "~", "tmp", NULL };
56
57
58 static const char *
get_nth_temp_folder_to_try(int n)59 get_nth_temp_folder_to_try (int n)
60 {
61 const char *folder;
62
63 folder = try_folder[n];
64 if (strcmp (folder, "cache") == 0)
65 folder = g_get_user_cache_dir ();
66 else if (strcmp (folder, "~") == 0)
67 folder = g_get_home_dir ();
68 else if (strcmp (folder, "tmp") == 0)
69 folder = g_get_tmp_dir ();
70
71 return folder;
72 }
73
74
75 char *
_g_path_get_temp_work_dir(const char * parent_folder)76 _g_path_get_temp_work_dir (const char *parent_folder)
77 {
78 guint64 max_size = 0;
79 char *best_folder = NULL;
80 int i;
81 char *template;
82 char *result = NULL;
83
84 if (parent_folder == NULL) {
85 /* find the folder with more free space. */
86
87 for (i = 0; try_folder[i] != NULL; i++) {
88 const char *folder;
89 GFile *file;
90 guint64 size;
91
92 folder = get_nth_temp_folder_to_try (i);
93 file = g_file_new_for_path (folder);
94 size = _g_file_get_free_space (file);
95 g_object_unref (file);
96
97 if (max_size < size) {
98 max_size = size;
99 g_free (best_folder);
100 best_folder = g_strdup (folder);
101 }
102 }
103 }
104 else
105 best_folder = g_strdup (parent_folder);
106
107 if (best_folder == NULL)
108 return NULL;
109
110 template = g_strconcat (best_folder, "/.fr-XXXXXX", NULL);
111 result = mkdtemp (template);
112 g_free (best_folder);
113
114 if ((result == NULL) || (*result == '\0')) {
115 g_free (template);
116 result = NULL;
117 }
118
119 return result;
120 }
121
122
123 /* GFile */
124
125
126 static gboolean
_g_file_is_filetype(GFile * file,GFileType file_type)127 _g_file_is_filetype (GFile *file,
128 GFileType file_type)
129 {
130 gboolean result = FALSE;
131 GFileInfo *info;
132
133 if (! g_file_query_exists (file, NULL))
134 return FALSE;
135
136 info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE, 0, NULL, NULL);
137 if (info != NULL) {
138 result = (g_file_info_get_file_type (info) == file_type);
139 g_object_unref (info);
140 }
141
142 return result;
143 }
144
145
146 gboolean
_g_file_query_is_file(GFile * file)147 _g_file_query_is_file (GFile *file)
148 {
149 return _g_file_is_filetype (file, G_FILE_TYPE_REGULAR);
150 }
151
152
153 gboolean
_g_file_query_is_dir(GFile * file)154 _g_file_query_is_dir (GFile *file)
155 {
156 return _g_file_is_filetype (file, G_FILE_TYPE_DIRECTORY);
157 }
158
159
160 static time_t
_g_file_get_file_time_type(GFile * file,const char * type)161 _g_file_get_file_time_type (GFile *file,
162 const char *type)
163 {
164 time_t result = 0;
165 GFileInfo *info;
166 GError *err = NULL;
167
168 if (file == NULL)
169 return 0;
170
171 info = g_file_query_info (file, type, 0, NULL, &err);
172 if (err == NULL) {
173 result = (time_t) g_file_info_get_attribute_uint64 (info, type);
174 }
175 else {
176 g_warning ("Failed to get %s: %s", type, err->message);
177 g_error_free (err);
178 result = 0;
179 }
180
181 g_object_unref (info);
182
183 return result;
184 }
185
186
187 goffset
_g_file_get_file_size(GFile * file)188 _g_file_get_file_size (GFile *file)
189 {
190 goffset size = 0;
191 GFileInfo *info;
192 GError *error = NULL;
193
194 if (file == NULL)
195 return 0;
196
197 info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_SIZE, 0, NULL, &error);
198 if (info != NULL) {
199 size = g_file_info_get_size (info);
200 g_object_unref (info);
201 }
202 else {
203 g_warning ("%s", error->message);
204 g_error_free (error);
205 }
206
207 return size;
208 }
209
210
211 time_t
_g_file_get_file_mtime(GFile * file)212 _g_file_get_file_mtime (GFile *file)
213 {
214 return _g_file_get_file_time_type (file, G_FILE_ATTRIBUTE_TIME_MODIFIED);
215 }
216
217
218 time_t
_g_file_get_file_ctime(GFile * file)219 _g_file_get_file_ctime (GFile *file)
220 {
221 return _g_file_get_file_time_type (file, G_FILE_ATTRIBUTE_TIME_CREATED);
222 }
223
224
225 const char *
_g_file_get_mime_type(GFile * file,gboolean fast_file_type)226 _g_file_get_mime_type (GFile *file,
227 gboolean fast_file_type)
228 {
229 GFileInfo *info;
230 GError *error = NULL;
231 const char *result = NULL;
232
233 info = g_file_query_info (file,
234 (fast_file_type ?
235 G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE :
236 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE),
237 0,
238 NULL,
239 &error);
240 if (info == NULL) {
241 g_warning ("%s", error->message);
242 g_clear_error (&error);
243 }
244 else {
245 result = _g_str_get_static (g_file_info_get_content_type (info));
246 g_object_unref (info);
247 }
248
249 return result;
250 }
251
252
253 gboolean
_g_file_is_temp_dir(GFile * file)254 _g_file_is_temp_dir (GFile *file)
255 {
256 gboolean result = FALSE;
257 char *path;
258
259 path = g_file_get_path (file);
260 if (path == NULL)
261 result = TRUE;
262 else if (strcmp (g_get_tmp_dir (), path) == 0)
263 result = TRUE;
264 else if (_g_path_is_parent_of (g_get_tmp_dir (), path))
265 result = TRUE;
266 else
267 result = _g_file_is_temp_work_dir (file);
268
269 g_free (path);
270
271 return result;
272 }
273
274
275 GFile *
_g_file_create_alternative(GFile * folder,const char * name)276 _g_file_create_alternative (GFile *folder,
277 const char *name)
278 {
279 GFile *file = NULL;
280 int n = 1;
281
282 do {
283 char *new_name;
284
285 _g_object_unref (file);
286
287 if (n == 1)
288 new_name = g_strdup (name);
289 else
290 new_name = g_strdup_printf ("%s (%d)", name, n);
291 n++;
292
293 file = g_file_get_child (folder, new_name);
294
295 g_free (new_name);
296 }
297 while (g_file_query_exists (file, NULL));
298
299 return file;
300 }
301
302
303 GFile *
_g_file_create_alternative_for_file(GFile * file)304 _g_file_create_alternative_for_file (GFile *file)
305 {
306 GFile *parent;
307 char *name;
308 GFile *new_file;
309
310 parent = g_file_get_parent (file);
311 name = g_file_get_basename (file);
312 new_file = _g_file_create_alternative (parent, name);
313
314 g_free (name);
315 g_object_unref (parent);
316
317 return new_file;
318 }
319
320
321 gboolean
_g_file_check_permissions(GFile * file,int mode)322 _g_file_check_permissions (GFile *file,
323 int mode)
324 {
325 gboolean result = TRUE;
326 GFileInfo *info;
327 GError *err = NULL;
328 gboolean default_permission_when_unknown = TRUE;
329
330 info = g_file_query_info (file, "access::*", 0, NULL, &err);
331 if (err != NULL) {
332 g_clear_error (&err);
333 result = FALSE;
334 }
335 else {
336 if ((mode & R_OK) == R_OK) {
337 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ))
338 result = (result && g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ));
339 else
340 result = (result && default_permission_when_unknown);
341 }
342
343 if ((mode & W_OK) == W_OK) {
344 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE))
345 result = (result && g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE));
346 else
347 result = (result && default_permission_when_unknown);
348 }
349
350 if ((mode & X_OK) == X_OK) {
351 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE))
352 result = (result && g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE));
353 else
354 result = (result && default_permission_when_unknown);
355 }
356
357 g_object_unref (info);
358 }
359
360 return result;
361 }
362
363
364 gboolean
_g_file_make_directory_tree(GFile * dir,mode_t mode,GError ** error)365 _g_file_make_directory_tree (GFile *dir,
366 mode_t mode,
367 GError **error)
368 {
369 gboolean success = TRUE;
370 GFile *parent;
371
372 if ((dir == NULL) || g_file_query_exists (dir, NULL))
373 return TRUE;
374
375 parent = g_file_get_parent (dir);
376 if (parent != NULL) {
377 success = _g_file_make_directory_tree (parent, mode, error);
378 g_object_unref (parent);
379 if (! success)
380 return FALSE;
381 }
382
383 success = g_file_make_directory (dir, NULL, error);
384 if ((error != NULL) && (*error != NULL) && g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_EXISTS)) {
385 g_clear_error (error);
386 success = TRUE;
387 }
388
389 if (success)
390 g_file_set_attribute_uint32 (dir,
391 G_FILE_ATTRIBUTE_UNIX_MODE,
392 mode,
393 0,
394 NULL,
395 NULL);
396
397 return success;
398 }
399
400
401 gboolean
_g_file_remove_directory(GFile * directory,GCancellable * cancellable,GError ** error)402 _g_file_remove_directory (GFile *directory,
403 GCancellable *cancellable,
404 GError **error)
405 {
406 GFileEnumerator *enumerator;
407 GFileInfo *info;
408 gboolean error_occurred = FALSE;
409
410 if (directory == NULL)
411 return TRUE;
412
413 enumerator = g_file_enumerate_children (directory,
414 G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_TYPE,
415 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
416 cancellable,
417 error);
418
419 while (! error_occurred && (info = g_file_enumerator_next_file (enumerator, cancellable, error)) != NULL) {
420 GFile *child;
421
422 child = g_file_get_child (directory, g_file_info_get_name (info));
423 switch (g_file_info_get_file_type (info)) {
424 case G_FILE_TYPE_DIRECTORY:
425 if (! _g_file_remove_directory (child, cancellable, error))
426 error_occurred = TRUE;
427 break;
428 default:
429 if (! g_file_delete (child, cancellable, error))
430 error_occurred = TRUE;
431 break;
432 }
433
434 g_object_unref (child);
435 g_object_unref (info);
436 }
437
438 if (! error_occurred && ! g_file_delete (directory, cancellable, error))
439 error_occurred = TRUE;
440
441 g_object_unref (enumerator);
442
443 return ! error_occurred;
444 }
445
446
447 GFile *
_g_file_new_user_config_subdir(const char * child_name,gboolean create_child)448 _g_file_new_user_config_subdir (const char *child_name,
449 gboolean create_child)
450 {
451 char *full_path;
452 GFile *file;
453 GError *error = NULL;
454
455 full_path = g_strconcat (g_get_user_config_dir (), "/", child_name, NULL);
456 file = g_file_new_for_path (full_path);
457 g_free (full_path);
458
459 if (create_child && ! _g_file_make_directory_tree (file, 0700, &error)) {
460 g_warning ("%s", error->message);
461 g_error_free (error);
462 g_object_unref (file);
463 file = NULL;
464 }
465
466 return file;
467 }
468
469
470 GFile *
_g_file_get_dir_content_if_unique(GFile * file)471 _g_file_get_dir_content_if_unique (GFile *file)
472 {
473 GFileEnumerator *enumarator;
474 GFileInfo *info;
475 GError *error = NULL;
476 GFile *content = NULL;
477
478 if (! g_file_query_exists (file, NULL)) {
479 g_object_unref (file);
480 return NULL;
481 }
482
483 enumarator = g_file_enumerate_children (file, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, &error);
484 if (error != NULL) {
485 g_warning ("%s", error->message);
486 g_error_free (error);
487 return NULL;
488 }
489
490 while ((info = g_file_enumerator_next_file (enumarator, NULL, &error)) != NULL) {
491 const char *name;
492
493 if (error != NULL) {
494 g_warning ("Failed to get info while enumerating children: %s", error->message);
495 g_clear_error (&error);
496 g_object_unref (info);
497 continue;
498 }
499
500 name = g_file_info_get_name (info);
501 if ((strcmp (name, ".") == 0) || (strcmp (name, "..") == 0)) {
502 g_object_unref (info);
503 continue;
504 }
505
506 if (content != NULL) {
507 g_object_unref (content);
508 g_object_unref (info);
509 content = NULL;
510 break;
511 }
512
513 content = g_file_get_child (file, name);
514
515 g_object_unref (info);
516 }
517
518 if (error != NULL) {
519 g_warning ("Failed to get info after enumerating children: %s", error->message);
520 g_clear_error (&error);
521 }
522
523 g_object_unref (enumarator);
524
525 return content;
526 }
527
528
529 guint64
_g_file_get_free_space(GFile * file)530 _g_file_get_free_space (GFile *file)
531 {
532 GFileInfo *info;
533 guint64 freespace = 0;
534 GError *error = NULL;
535
536 info = g_file_query_filesystem_info (file, G_FILE_ATTRIBUTE_FILESYSTEM_FREE, NULL, &error);
537 if (info != NULL) {
538 freespace = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
539 g_object_unref (info);
540 }
541 else {
542 g_warning ("%s", error->message);
543 g_error_free (error);
544 }
545
546 return freespace;
547 }
548
549
550 GFile *
_g_file_get_temp_work_dir(GFile * parent_folder)551 _g_file_get_temp_work_dir (GFile *parent_folder)
552 {
553 char *parent_path;
554 char *tmp;
555 GFile *file;
556
557 parent_path = (parent_folder != NULL) ? g_file_get_path (parent_folder) : NULL;
558 tmp = _g_path_get_temp_work_dir (parent_path);
559 file = g_file_new_for_path (tmp);
560
561 g_free (tmp);
562 g_free (parent_path);
563
564 return file;
565 }
566
567
568 gboolean
_g_file_is_temp_work_dir(GFile * file)569 _g_file_is_temp_work_dir (GFile *file)
570 {
571 gboolean result = FALSE;
572 char *path;
573 int i;
574
575 path = g_file_get_path (file);
576 if (path[0] != '/') {
577 g_free (path);
578 return FALSE;
579 }
580
581 for (i = 0; try_folder[i] != NULL; i++) {
582 const char *folder;
583
584 folder = get_nth_temp_folder_to_try (i);
585 if (strncmp (path, folder, strlen (folder)) == 0) {
586 if (strncmp (path + strlen (folder), "/.fr-", 5) == 0) {
587 result = TRUE;
588 break;
589 }
590 }
591 }
592
593 g_free (path);
594
595 return result;
596 }
597
598
599 gboolean
_g_file_query_dir_is_empty(GFile * file)600 _g_file_query_dir_is_empty (GFile *file)
601 {
602 GFileEnumerator *enumerator;
603 GFileInfo *info;
604 GError *error = NULL;
605 int n = 0;
606
607 if (! g_file_query_exists (file, NULL))
608 return TRUE;
609
610 enumerator = g_file_enumerate_children (file, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, &error);
611 if (error != NULL) {
612 g_warning ("%s", error->message);
613 g_error_free (error);
614 g_object_unref (enumerator);
615 return TRUE;
616 }
617
618 while ((n == 0) && ((info = g_file_enumerator_next_file (enumerator, NULL, &error)) != NULL)) {
619 if (error != NULL) {
620 g_warning ("%s", error->message);
621 g_error_free (error);
622 }
623 else if (! IS_SPECIAL_DIR (g_file_info_get_name (info)))
624 n++;
625 g_object_unref (info);
626 }
627
628 g_object_unref (enumerator);
629
630 return (n == 0);
631 }
632
633
634 gboolean
_g_file_dir_contains_one_object(GFile * file)635 _g_file_dir_contains_one_object (GFile *file)
636 {
637 GFileEnumerator *enumerator;
638 GFileInfo *info;
639 GError *error = NULL;
640 int n = 0;
641
642 if (! g_file_query_exists (file, NULL))
643 return FALSE;
644
645 enumerator = g_file_enumerate_children (file, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, &error);
646 if (error != NULL) {
647 g_warning ("%s", error->message);
648 g_error_free (error);
649 g_object_unref (enumerator);
650 return FALSE;
651 }
652
653 while ((info = g_file_enumerator_next_file (enumerator, NULL, &error)) != NULL) {
654 const char *name;
655
656 if (error != NULL) {
657 g_warning ("%s", error->message);
658 g_error_free (error);
659 g_object_unref (info);
660 continue;
661 }
662
663 name = g_file_info_get_name (info);
664 if (strcmp (name, ".") == 0 || strcmp (name, "..") == 0) {
665 g_object_unref (info);
666 continue;
667 }
668
669 g_object_unref (info);
670
671 if (++n > 1)
672 break;
673 }
674
675 g_object_unref (enumerator);
676
677 return (n == 1);
678 }
679
680
681 /* program */
682
683
684 gboolean
_g_program_is_in_path(const char * filename)685 _g_program_is_in_path (const char *filename)
686 {
687 char *str;
688 char *value;
689 int result = FALSE;
690
691 value = g_hash_table_lookup (ProgramsCache, filename);
692 if (value != NULL) {
693 result = (strcmp (value, "1") == 0);
694 return result;
695 }
696
697 str = g_find_program_in_path (filename);
698 if (str != NULL) {
699 g_free (str);
700 result = TRUE;
701 }
702
703 g_hash_table_insert (ProgramsCache,
704 g_strdup (filename),
705 result ? "1" : "0");
706
707 return result;
708 }
709
710
711 gboolean
_g_program_is_available(const char * filename,gboolean check)712 _g_program_is_available (const char *filename,
713 gboolean check)
714 {
715 return ! check || _g_program_is_in_path (filename);
716 }
717
718
719 /* GKeyFile */
720
721
722 void
_g_key_file_save(GKeyFile * key_file,GFile * file)723 _g_key_file_save (GKeyFile *key_file,
724 GFile *file)
725 {
726 char *file_data;
727 gsize size;
728 GError *error = NULL;
729
730 file_data = g_key_file_to_data (key_file, &size, &error);
731 if (error != NULL) {
732 g_warning ("Could not save options: %s\n", error->message);
733 g_clear_error (&error);
734 }
735 else {
736 GFileOutputStream *stream;
737
738 stream = g_file_replace (file, NULL, FALSE, 0, NULL, &error);
739 if (stream == NULL) {
740 g_warning ("Could not save options: %s\n", error->message);
741 g_clear_error (&error);
742 }
743 else if (! g_output_stream_write_all (G_OUTPUT_STREAM (stream), file_data, size, NULL, NULL, &error)) {
744 g_warning ("Could not save options: %s\n", error->message);
745 g_clear_error (&error);
746 }
747 else if (! g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, &error)) {
748 g_warning ("Could not save options: %s\n", error->message);
749 g_clear_error (&error);
750 }
751
752 g_object_unref (stream);
753 }
754
755 g_free (file_data);
756 }
757