comparison src/ui_fileops.c @ 9:d907d608745f

Sync to GQview 1.5.9 release. ######## DO NOT BASE ENHANCEMENTS OR TRANSLATION UPDATES ON CODE IN THIS CVS! This CVS is never up to date with current development and is provided solely for reference purposes, please use the latest official release package when making any changes or translation updates. ########
author gqview
date Sat, 26 Feb 2005 00:13:35 +0000
parents
children dcc04a6a58bf
comparison
equal deleted inserted replaced
8:e0d0593d519e 9:d907d608745f
1 /*
2 * (SLIK) SimpLIstic sKin functions
3 * (C) 2004 John Ellis
4 *
5 * Author: John Ellis
6 *
7 * This software is released under the GNU General Public License (GNU GPL).
8 * Please read the included file COPYING for more information.
9 * This software comes with no warranty of any kind, use at your own risk!
10 */
11
12 #ifdef HAVE_CONFIG_H
13 # include "config.h"
14 #endif
15
16 #include <pwd.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <sys/param.h>
22 #include <dirent.h>
23 #include <utime.h>
24
25 #include <glib.h>
26 #include <gtk/gtk.h> /* for locale warning dialog */
27
28 #include "ui_fileops.h"
29
30 #include "ui_utildlg.h" /* for locale warning dialog */
31
32 /*
33 *-----------------------------------------------------------------------------
34 * generic file information and manipulation routines (public)
35 *-----------------------------------------------------------------------------
36 */
37
38 /* file sorting method (case) */
39 gint file_sort_case_sensitive = FALSE;
40
41
42 void print_term(const gchar *text_utf8)
43 {
44 gchar *text_l;
45
46 text_l = g_locale_from_utf8(text_utf8, -1, NULL, NULL, NULL);
47 printf((text_l) ? text_l : text_utf8);
48 g_free(text_l);
49 }
50
51 static void encoding_dialog(const gchar *path);
52
53 static gint encoding_dialog_idle(gpointer data)
54 {
55 gchar *path = data;
56
57 encoding_dialog(path);
58 g_free(path);
59
60 return FALSE;
61 }
62
63 static gint encoding_dialog_delay(gpointer data)
64 {
65 g_idle_add(encoding_dialog_idle, data);
66
67 return 0;
68 }
69
70 static void encoding_dialog(const gchar *path)
71 {
72 static gint warned_user = FALSE;
73 GenericDialog *gd;
74 GString *string;
75 const gchar *lc;
76 const gchar *bf;
77
78 /* check that gtk is initialized (loop is level > 0) */
79 if (gtk_main_level() == 0)
80 {
81 /* gtk not initialized */
82 gtk_init_add(encoding_dialog_delay, g_strdup(path));
83 return;
84 }
85
86 if (warned_user) return;
87 warned_user = TRUE;
88
89 lc = getenv("LANG");
90 bf = getenv("G_BROKEN_FILENAMES");
91 warned_user = TRUE;
92
93 string = g_string_new("");
94 g_string_append(string, "One or more filenames are not encoded with the preferred locale character set.\n");
95 g_string_append_printf(string, "Operations on, and display of these files with %s may not succeed.\n\n", PACKAGE);
96 g_string_append(string, "If your filenames are not encoded in utf-8, try setting\n");
97 g_string_append(string, "the environment variable G_BROKEN_FILENAMES=1\n");
98 g_string_append_printf(string, "It appears G_BROKEN_FILENAMES is %s%s\n\n",
99 (bf) ? "set to " : "not set.", (bf) ? bf : "");
100 g_string_append_printf(string, "The locale appears to be set to \"%s\"\n(set by the LANG environment variable)\n", (lc) ? lc : "undefined");
101 if (lc && (strstr(lc, "UTF-8") || strstr(lc, "utf-8")))
102 {
103 gchar *name;
104 name = g_convert(path, -1, "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
105 string = g_string_append(string, "\nPreferred encoding appears to be UTF-8, however the file:\n");
106 g_string_append_printf(string, "\"%s\"\n%s encoded in valid UTF-8.\n",
107 (name) ? name : "[name not displayable]",
108 (g_utf8_validate(path, -1, NULL)) ? "is": "is NOT");
109 g_free(name);
110 }
111
112 gd = generic_dialog_new("Filename encoding locale mismatch",
113 PACKAGE, "locale warning", NULL, TRUE, NULL, NULL);
114 generic_dialog_add_button(gd, GTK_STOCK_CLOSE, NULL, NULL, TRUE);
115
116 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_WARNING,
117 "Filename encoding locale mismatch", string->str);
118
119 gtk_widget_show(gd->dialog);
120
121 g_string_free(string, TRUE);
122 }
123
124 gchar *path_to_utf8(const gchar *path)
125 {
126 gchar *utf8;
127 GError *error = NULL;
128
129 if (!path) return NULL;
130
131 utf8 = g_filename_to_utf8(path, -1, NULL, NULL, &error);
132 if (error)
133 {
134 printf("Unable to convert filename to UTF-8:\n%s\n%s\n", path, error->message);
135 g_error_free(error);
136 encoding_dialog(path);
137 }
138 if (!utf8)
139 {
140 /* just let it through, but bad things may happen */
141 utf8 = g_strdup(path);
142 }
143
144 return utf8;
145 }
146
147 gchar *path_from_utf8(const gchar *utf8)
148 {
149 gchar *path;
150 GError *error = NULL;
151
152 if (!utf8) return NULL;
153
154 path = g_filename_from_utf8(utf8, -1, NULL, NULL, &error);
155 if (error)
156 {
157 printf("Unable to convert filename to locale from UTF-8:\n%s\n%s\n", utf8, error->message);
158 g_error_free(error);
159 }
160 if (!path)
161 {
162 /* if invalid UTF-8, text probaby still in original form, so just copy it */
163 path = g_strdup(utf8);
164 }
165
166 return path;
167 }
168
169 /* first we try the HOME environment var, if that doesn't work, we try getpwuid(). */
170 const gchar *homedir(void)
171 {
172 static gchar *home = NULL;
173
174 if (!home)
175 {
176 home = path_to_utf8(getenv("HOME"));
177 }
178 if (!home)
179 {
180 struct passwd *pw = getpwuid(getuid());
181 if (pw) home = path_to_utf8(pw->pw_dir);
182 }
183
184 return home;
185 }
186
187 gint stat_utf8(const gchar *s, struct stat *st)
188 {
189 gchar *sl;
190 gint ret;
191
192 if (!s) return FALSE;
193 sl = path_from_utf8(s);
194 ret = (stat(sl, st) == 0);
195 g_free(sl);
196
197 return ret;
198 }
199
200 gint isname(const gchar *s)
201 {
202 struct stat st;
203
204 return stat_utf8(s, &st);
205 }
206
207 gint isfile(const gchar *s)
208 {
209 struct stat st;
210
211 return (stat_utf8(s, &st) && S_ISREG(st.st_mode));
212 }
213
214 gint isdir(const gchar *s)
215 {
216 struct stat st;
217
218 return (stat_utf8(s ,&st) && S_ISDIR(st.st_mode));
219 }
220
221 gint64 filesize(const gchar *s)
222 {
223 struct stat st;
224
225 if (!stat_utf8(s, &st)) return 0;
226 return (gint)st.st_size;
227 }
228
229 time_t filetime(const gchar *s)
230 {
231 struct stat st;
232
233 if (!stat_utf8(s, &st)) return 0;
234 return st.st_mtime;
235 }
236
237 gint filetime_set(const gchar *s, time_t tval)
238 {
239 gint ret = FALSE;
240
241 if (tval > 0)
242 {
243 struct utimbuf ut;
244 gchar *sl;
245
246 ut.actime = ut.modtime = tval;
247
248 sl = path_from_utf8(s);
249 ret = (utime(sl, &ut) == 0);
250 g_free(sl);
251 }
252
253 return ret;
254 }
255
256 gint access_file(const gchar *s, int mode)
257 {
258 gchar *sl;
259 gint ret;
260
261 if (!s) return FALSE;
262
263 sl = path_from_utf8(s);
264 ret = (access(sl, mode) == 0);
265 g_free(sl);
266
267 return ret;
268 }
269
270 gint unlink_file(const gchar *s)
271 {
272 gchar *sl;
273 gint ret;
274
275 if (!s) return FALSE;
276
277 sl = path_from_utf8(s);
278 ret = (unlink(sl) == 0);
279 g_free(sl);
280
281 return ret;
282 }
283
284 gint symlink_utf8(const gchar *source, const gchar *target)
285 {
286 gchar *sl;
287 gchar *tl;
288 gint ret;
289
290 if (!source || !target) return FALSE;
291
292 sl = path_from_utf8(source);
293 tl = path_from_utf8(target);
294
295 ret = (symlink(sl, tl) == 0);
296
297 g_free(sl);
298 g_free(tl);
299
300 return ret;
301 }
302
303 gint mkdir_utf8(const gchar *s, int mode)
304 {
305 gchar *sl;
306 gint ret;
307
308 if (!s) return FALSE;
309
310 sl = path_from_utf8(s);
311 ret = (mkdir(sl, mode) == 0);
312 g_free(sl);
313 return ret;
314 }
315
316 gint rmdir_utf8(const gchar *s)
317 {
318 gchar *sl;
319 gint ret;
320
321 if (!s) return FALSE;
322
323 sl = path_from_utf8(s);
324 ret = (rmdir(sl) == 0);
325 g_free(sl);
326
327 return ret;
328 }
329
330 gint copy_file_attributes(const gchar *s, const gchar *t, gint perms, gint mtime)
331 {
332 struct stat st;
333 gchar *sl, *tl;
334 gint ret = FALSE;
335
336 if (!s || !t) return FALSE;
337
338 sl = path_from_utf8(s);
339 tl = path_from_utf8(t);
340
341 if (stat(sl, &st) == 0)
342 {
343 struct utimbuf tb;
344
345 ret = TRUE;
346
347 /* set the dest file attributes to that of source (ignoring errors) */
348
349 if (perms && chown(tl, st.st_uid, st.st_gid) < 0) ret = FALSE;
350 if (perms && chmod(tl, st.st_mode) < 0) ret = FALSE;
351
352 tb.actime = st.st_atime;
353 tb.modtime = st.st_mtime;
354 if (mtime && utime(tl, &tb) < 0) ret = FALSE;
355 }
356
357 g_free(sl);
358 g_free(tl);
359
360 return ret;
361 }
362
363 /* paths are in filesystem encoding */
364 static gint hard_linked(const gchar *a, const gchar *b)
365 {
366 struct stat sta;
367 struct stat stb;
368
369 if (stat(a, &sta) != 0 || stat(b, &stb) != 0) return FALSE;
370
371 return (sta.st_dev == stb.st_dev &&
372 sta.st_ino == stb.st_ino);
373 }
374
375 gint copy_file(const gchar *s, const gchar *t)
376 {
377 FILE *fi = NULL;
378 FILE *fo = NULL;
379 gchar *sl, *tl;
380 gchar buf[4096];
381 gint b;
382
383 sl = path_from_utf8(s);
384 tl = path_from_utf8(t);
385
386 if (hard_linked(sl, tl))
387 {
388 g_free(sl);
389 g_free(tl);
390 return TRUE;
391 }
392
393 fi = fopen(sl, "rb");
394 if (fi)
395 {
396 fo = fopen(tl, "wb");
397 if (!fo)
398 {
399 fclose(fi);
400 fi = NULL;
401 }
402 }
403
404 g_free(sl);
405 g_free(tl);
406
407 if (!fi || !fo) return FALSE;
408
409 while((b = fread(buf, sizeof(char), 4096, fi)) && b != 0)
410 {
411 if (fwrite(buf, sizeof(char), b, fo) != b)
412 {
413 fclose(fi);
414 fclose(fo);
415 return FALSE;
416 }
417 }
418
419 fclose(fi);
420 fclose(fo);
421
422 copy_file_attributes(s, t, TRUE, TRUE);
423
424 return TRUE;
425 }
426
427 gint move_file(const gchar *s, const gchar *t)
428 {
429 gchar *sl, *tl;
430 gint ret = TRUE;
431
432 if (!s || !t) return FALSE;
433
434 sl = path_from_utf8(s);
435 tl = path_from_utf8(t);
436 if (rename(sl, tl) < 0)
437 {
438 /* this may have failed because moving a file across filesystems
439 was attempted, so try copy and delete instead */
440 if (copy_file(s, t))
441 {
442 if (unlink(sl) < 0)
443 {
444 /* err, now we can't delete the source file so return FALSE */
445 ret = FALSE;
446 }
447 }
448 else
449 {
450 ret = FALSE;
451 }
452 }
453 g_free(sl);
454 g_free(tl);
455
456 return ret;
457 }
458
459 gint rename_file(const gchar *s, const gchar *t)
460 {
461 gchar *sl, *tl;
462 gint ret;
463
464 if (!s || !t) return FALSE;
465
466 sl = path_from_utf8(s);
467 tl = path_from_utf8(t);
468 ret = (rename(sl, tl) == 0);
469 g_free(sl);
470 g_free(tl);
471
472 return ret;
473 }
474
475 gchar *get_current_dir(void)
476 {
477 gchar *pathl;
478 gchar *path8;
479
480 pathl = g_get_current_dir();
481 path8 = path_to_utf8(pathl);
482 g_free(pathl);
483
484 return path8;
485 }
486
487 gint path_list(const gchar *path, GList **files, GList **dirs)
488 {
489 DIR *dp;
490 struct dirent *dir;
491 struct stat ent_sbuf;
492 GList *f_list = NULL;
493 GList *d_list = NULL;
494 gchar *pathl;
495
496 if (!path) return FALSE;
497
498 pathl = path_from_utf8(path);
499 dp = opendir(pathl);
500 if (!dp)
501 {
502 /* dir not found */
503 g_free(pathl);
504 return FALSE;
505 }
506
507 /* root dir fix */
508 if (pathl[0] == '/' && pathl[1] == '\0')
509 {
510 g_free(pathl);
511 pathl = g_strdup("");
512 }
513
514 while ((dir = readdir(dp)) != NULL)
515 {
516 /* skip removed files */
517 if (dir->d_ino > 0)
518 {
519 gchar *name = dir->d_name;
520 gchar *filepath = g_strconcat(pathl, "/", name, NULL);
521 if (stat(filepath, &ent_sbuf) >= 0)
522 {
523 gchar *path8;
524 gchar *name8;
525
526 name8 = path_to_utf8(name);
527 path8 = g_strconcat(path, "/", name8, NULL);
528 g_free(name8);
529
530 if (dirs && S_ISDIR(ent_sbuf.st_mode) &&
531 !(name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) )
532 {
533 d_list = g_list_prepend(d_list, path8);
534 path8 = NULL;
535 }
536 else if (files && S_ISREG(ent_sbuf.st_mode))
537 {
538 f_list = g_list_prepend(f_list, path8);
539 path8 = NULL;
540 }
541 g_free(path8);
542 }
543 g_free(filepath);
544 }
545 }
546 closedir(dp);
547
548 g_free(pathl);
549
550 if (dirs) *dirs = g_list_reverse(d_list);
551 if (files) *files = g_list_reverse(f_list);
552
553 return TRUE;
554 }
555
556 void path_list_free(GList *list)
557 {
558 g_list_foreach(list, (GFunc)g_free, NULL);
559 g_list_free(list);
560 }
561
562 GList *path_list_copy(GList *list)
563 {
564 GList *new_list = NULL;
565 GList *work;
566
567 work = list;
568 while (work)
569 {
570 gchar *path;
571
572 path = work->data;
573 work = work->next;
574
575 new_list = g_list_prepend(new_list, g_strdup(path));
576 }
577
578 return g_list_reverse(new_list);
579 }
580
581 long checksum_simple(const gchar *path)
582 {
583 gchar *path8;
584 FILE *f;
585 long sum = 0;
586 gint c;
587
588 path8 = path_from_utf8(path);
589 f = fopen(path8, "r");
590 g_free(path8);
591 if (!f) return -1;
592
593 while((c = fgetc(f)) != EOF)
594 {
595 sum += c;
596 }
597
598 fclose(f);
599
600 return sum;
601 }
602
603 gchar *unique_filename(const gchar *path, const gchar *ext, const gchar *divider, gint pad)
604 {
605 gchar *unique;
606 gint n = 1;
607
608 if (!ext) ext = "";
609 if (!divider) divider = "";
610
611 unique = g_strconcat(path, ext, NULL);
612 while (isname(unique))
613 {
614 g_free(unique);
615 if (pad)
616 {
617 unique = g_strdup_printf("%s%s%03d%s", path, divider, n, ext);
618 }
619 else
620 {
621 unique = g_strdup_printf("%s%s%d%s", path, divider, n, ext);
622 }
623 n++;
624 if (n > 999)
625 {
626 /* well, we tried */
627 g_free(unique);
628 return NULL;
629 }
630 }
631
632 return unique;
633 }
634
635 gchar *unique_filename_simple(const gchar *path)
636 {
637 gchar *unique;
638 const gchar *name;
639 const gchar *ext;
640
641 if (!path) return NULL;
642
643 name = filename_from_path(path);
644 if (!name) return NULL;
645
646 ext = extension_from_path(name);
647
648 if (!ext)
649 {
650 unique = unique_filename(path, NULL, "_", TRUE);
651 }
652 else
653 {
654 gchar *base;
655
656 base = remove_extension_from_path(path);
657 unique = unique_filename(base, ext, "_", TRUE);
658 g_free(base);
659 }
660
661 return unique;
662 }
663
664 const gchar *filename_from_path(const gchar *path)
665 {
666 const gchar *base;
667
668 if (!path) return NULL;
669
670 base = strrchr(path, '/');
671 if (base) return base + 1;
672
673 return path;
674 }
675
676 gchar *remove_level_from_path(const gchar *path)
677 {
678 gchar *new_path;
679 const gchar *ptr = path;
680 gint p;
681
682 if (!path) return NULL;
683
684 p = strlen(path) - 1;
685 if (p < 0) return NULL;
686 while(ptr[p] != '/' && p > 0) p--;
687 if (p == 0 && ptr[p] == '/') p++;
688 new_path = g_strndup(path, (guint)p);
689 return new_path;
690 }
691
692 gchar *concat_dir_and_file(const gchar *base, const gchar *name)
693 {
694 if (!base || !name) return NULL;
695
696 if (strcmp(base, "/") == 0) return g_strconcat(base, name, NULL);
697
698 return g_strconcat(base, "/", name, NULL);
699 }
700
701 const gchar *extension_from_path(const gchar *path)
702 {
703 if (!path) return NULL;
704 return strrchr(path, '.');
705 }
706
707 gint file_extension_match(const gchar *path, const gchar *ext)
708 {
709 gint p;
710 gint e;
711
712 if (!path) return FALSE;
713 if (!ext) return TRUE;
714
715 p = strlen(path);
716 e = strlen(ext);
717
718 return (p > e && strncasecmp(path + p - e, ext, e) == 0);
719 }
720
721 gchar *remove_extension_from_path(const gchar *path)
722 {
723 gchar *new_path;
724 const gchar *ptr = path;
725 gint p;
726
727 if (!path) return NULL;
728 if (strlen(path) < 2) return g_strdup(path);
729
730 p = strlen(path) - 1;
731 while(ptr[p] != '.' && p > 0) p--;
732 if (p == 0) p = strlen(path) - 1;
733 new_path = g_strndup(path, (guint)p);
734 return new_path;
735 }
736
737 void parse_out_relatives(gchar *path)
738 {
739 gint s, t;
740
741 if (!path) return;
742
743 s = t = 0;
744
745 while (path[s] != '\0')
746 {
747 if (path[s] == '/' && path[s+1] == '.' && (path[s+2] == '/' || path[s+2] == '\0') )
748 {
749 s += 2;
750 }
751 else if (path[s] == '/' && path[s+1] == '.' && path[s+2] == '.' && (path[s+3] == '/' || path[s+3] == '\0') )
752 {
753 s += 3;
754 if (t > 0) t--;
755 while (path[t] != '/' && t > 0) t--;
756 }
757 else
758 {
759 if (s != t) path[t] = path[s];
760 t++;
761 s++;
762 }
763 }
764 if (t == 0 && path[t] == '/') t++;
765 if (t > 1 && path[t-1] == '/') t--;
766 path[t] = '\0';
767 }
768
769 gint file_in_path(const gchar *name)
770 {
771 gchar *path;
772 gchar *namel;
773 gint p, l;
774 gint ret = FALSE;
775
776 if (!name) return FALSE;
777 path = g_strdup(getenv("PATH"));
778 if (!path) return FALSE;
779 namel = path_from_utf8(name);
780
781 p = 0;
782 l = strlen(path);
783 while (p < l && !ret)
784 {
785 gchar *f;
786 gint e = p;
787 while (path[e] != ':' && path[e] != '\0') e++;
788 path[e] = '\0';
789 e++;
790 f = g_strconcat(path + p, "/", namel, NULL);
791 if (isfile(f)) ret = TRUE;
792 g_free(f);
793 p = e;
794 }
795 g_free(namel);
796 g_free(path);
797
798 return ret;
799 }
800