/* -*- Mode: C; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3 -*- */ /* * GImageView * Copyright (C) 2001 Takuro Ashie * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * $Id: gfileutil.c,v 1.43 2004/09/21 08:44:31 makeinu Exp $ */ #include #include #include #include #include #include #include #include #include "charset.h" #include "fileutil.h" #include "fr-archive.h" #include "gfileutil.h" #include "gimv_comment.h" #include "gimv_image.h" #include "gimv_thumb.h" #include "gimv_thumb_cache.h" #include "gtkutils.h" #include "intl.h" #include "prefs.h" #ifndef BUF_SIZE #define BUF_SIZE 4096 #endif #ifndef MAX_PATH_LEN #define MAX_PATH_LEN 1024 #endif gchar * add_slash (const gchar *path) { g_return_val_if_fail (path, NULL); if (!*path) return g_strdup ("/"); if (path [strlen (path) - 1] == '/') return g_strdup (path); else return g_strconcat (path, "/", NULL); } gchar * remove_slash (const gchar *path) { g_return_val_if_fail (path, NULL); g_return_val_if_fail (*path, g_strdup (path)); if (path[strlen (path) - 1] == '/') return g_dirname (path); else return g_strdup (path); } gboolean getting_dir = FALSE; gboolean stop_getting_dir = FALSE; static gchar* tmpdir = NULL; gchar * get_temp_dir_name (void) { if (tmpdir) return tmpdir; tmpdir = g_strdup_printf ("%s%s.%d", g_get_tmp_dir (), "/gimv", getpid ()); return tmpdir; } void remove_dir (const gchar *dirname) { GList *node, *list; if (!isdir(dirname)) return; list = get_dir_all (dirname); for (node = list; node; node = g_list_next (node)) remove (node->data); if (list) { remove (dirname); g_list_foreach (list, (GFunc) g_free, NULL); g_list_free (list); } } void remove_temp_dir (void) { if (!tmpdir) return; remove_dir (tmpdir); g_free (tmpdir); tmpdir = NULL; } /* * get_dir: * @ Get image files in specified directory. * * dirname : Directory to scan. * files : Pointer to OpenFiles struct for store directory list. */ void get_dir (const gchar *dirname, GetDirFlags flags, GList **filelist_ret, GList **dirlist_ret) { DIR *dp; struct dirent *entry; gchar buf[MAX_PATH_LEN], *path; GList *filelist = NULL, *dirlist = NULL, *list; g_return_if_fail (dirname && *dirname); getting_dir = TRUE; if (flags & GETDIR_DISP_STDERR) fprintf (stderr, _("scandir = %s\n"), dirname); else if (flags & GETDIR_DISP_STDOUT) fprintf (stdout, _("scandir = %s\n"), dirname); if ((dp = opendir (dirname))) { while ((entry = readdir (dp))) { if (flags & GETDIR_ENABLE_CANCEL) { while (gtk_events_pending()) gtk_main_iteration(); if (stop_getting_dir) break; } /* ignore dot file */ if (!(flags & GETDIR_READ_DOT) && entry->d_name[0] == '.') continue; /* get full path */ if (dirname [strlen (dirname) - 1] == '/') g_snprintf (buf, MAX_PATH_LEN, "%s%s", dirname, entry->d_name); else g_snprintf (buf, MAX_PATH_LEN, "%s/%s", dirname, entry->d_name); /* if path is file */ if (!isdir (buf) || (!(flags & GETDIR_FOLLOW_SYMLINK) && islink (buf))) { if (!filelist_ret) continue; if (!(flags & GETDIR_DETECT_EXT) || gimv_image_detect_type_by_ext (buf) || ((flags & GETDIR_GET_ARCHIVE) && fr_archive_utils_get_file_name_ext (buf))) { path = g_strdup (buf); if (flags & GETDIR_DISP_STDERR) fprintf (stderr, _("filename = %s\n"), path); else if (flags & GETDIR_DISP_STDOUT) fprintf (stdout, _("filename = %s\n"), path); filelist = g_list_append (filelist, path); } /* if path is dir */ } else if (isdir(buf)) { if (dirlist_ret && strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) { path = g_strdup (buf); if (flags & GETDIR_DISP_STDERR) fprintf (stderr, _("dirname = %s\n"), path); else if (flags & GETDIR_DISP_STDOUT) fprintf (stdout, _("dirname = %s\n"), path); dirlist = g_list_append (dirlist, path); } } } closedir (dp); if (filelist) filelist = g_list_sort (filelist, gtkutil_comp_spel); if (dirlist) dirlist = g_list_sort (dirlist, gtkutil_comp_spel); } else { g_warning ("cannot open directory: %s", dirname); } /* recursive get */ if (flags & GETDIR_RECURSIVE) { GList *tmplist = g_list_copy (dirlist); gint tmp_flags = flags | GETDIR_RECURSIVE_IS_BRANCH; list = tmplist; while (list) { GList *tmp_filelist = NULL, *tmp_dirlist = NULL; if (flags & GETDIR_ENABLE_CANCEL) { while (gtk_events_pending()) gtk_main_iteration(); if (stop_getting_dir) break; } get_dir ((const gchar *) list->data, tmp_flags, &tmp_filelist, &tmp_dirlist); filelist = g_list_concat (filelist, tmp_filelist); dirlist = g_list_concat (dirlist, tmp_dirlist); list = g_list_next (list); } g_list_free (tmplist); } /* return value */ if (filelist_ret) *filelist_ret = filelist; if (dirlist_ret) *dirlist_ret = dirlist; if (!(flags & GETDIR_RECURSIVE_IS_BRANCH)) { getting_dir = FALSE; stop_getting_dir = FALSE; } } void get_dir_stop (void) { if (getting_dir) stop_getting_dir = TRUE; } /* * get_dir_all: * @ * * dirname : * Return : */ GList * get_dir_all (const gchar *dirname) { GList *filelist, *dirlist, *sub_dirlist, *node; gchar *sub_dirname; get_dir (dirname, GETDIR_READ_DOT, &filelist, &dirlist); if (dirlist) { node = dirlist; while (node) { sub_dirname = node->data; sub_dirlist = get_dir_all (sub_dirname); if (sub_dirlist) filelist = g_list_concat (sub_dirlist, filelist); node = g_list_next (node); } filelist = g_list_concat (filelist, dirlist); } return filelist; } /* * get_dir_all_file: * @ * * dirname : * Return : */ static GList * get_dir_all_file (const gchar *dirname) { GList *filelist, *dirlist, *sub_dirlist, *node; gchar *sub_dirname; get_dir (dirname, GETDIR_READ_DOT, &filelist, &dirlist); if (dirlist) { node = dirlist; while (node) { sub_dirname = node->data; sub_dirlist = get_dir_all_file (sub_dirname); if (sub_dirlist) filelist = g_list_concat (sub_dirlist, filelist); node = g_list_next (node); } } return filelist; } /* * merge from misc/misc.c in Text maid (Copyright(C) Kazuki Iwamoto). */ gchar * relpath2abs (const gchar *path) { gchar *dir, *dest; gint i,j,len; g_return_val_if_fail (path && *path, NULL); if (path[0] != '/') { dir = g_get_current_dir (); dest = g_strjoin ("/", dir, path, NULL); g_free (dir); } else { dest = g_strdup (path); } len = strlen (dest) + 1; i = 0; while (i < len - 2) { if (dest[i] == '/' && dest[i + 1] == '.' && (dest[i + 2] == '/' || dest[i + 2] == '\0')) { len -= 2; memmove (dest + i, dest + i + 2, len - i); } i++; } i = 0; while (i < len - 3) { if (dest[i] == '/' && dest[i + 1] == '.' && dest[i + 2] == '.' && (dest[i + 3] == '/' || dest[i + 3] == '\0')) { len -= 3; memmove (dest + i, dest + i + 3, len - i); for (j = i - 1; j >= 0; j--) { if (dest[j] == '/') break; } if (j >= 0) { memmove (dest + j, dest + i, len - i); len -= i - j; i = j; } } i++; } return dest; } gchar * link2abs (const gchar *path) { gchar *retval = NULL, **dirs, buf[MAX_PATH_LEN], *tmpstr; gint i, num; g_return_val_if_fail (path && *path, NULL); g_return_val_if_fail (path[0] == '/', g_strdup (path)); if (!strcmp (path, "/")) return g_strdup (path); dirs = g_strsplit (path, "/", -1); g_return_val_if_fail (dirs, g_strdup (path)); retval = g_strdup(""); for (i = 0; dirs[i]; i++) { gchar *endchr; if (!*dirs[i]) continue; tmpstr = g_strconcat (retval, "/", dirs[i], NULL); g_free (retval); retval = tmpstr; num = readlink (retval, buf, MAX_PATH_LEN); if (num < 1) continue; buf[num] = '\0'; if (buf[0] == '/') { g_free (retval); retval = g_strdup (buf); } else { endchr = strrchr (retval, '/'); if (!endchr) { g_free (retval); retval = g_strdup (path); break; } *endchr = '\0'; /* FIXME: what about link to link? */ tmpstr = g_strconcat (retval, "/", buf, NULL); g_free (retval); retval = tmpstr; } } g_strfreev (dirs); if (!retval) { g_warning ("invalid link: %s\n", path); } else { tmpstr = relpath2abs (retval); g_free (retval); retval = tmpstr; } return retval; } static gboolean move_file_check_path (const gchar *from_path, struct stat *from_st, const gchar *dir, gboolean show_error, GtkWindow *window) { gchar *from_dir, error_message[BUF_SIZE]; gchar *from_path_internal, *dir_internal; gboolean retval = FALSE; from_path_internal = charset_to_internal (from_path, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); dir_internal = charset_to_internal (dir, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); /******************** * check source file ********************/ if (lstat (from_path, from_st)) { if (show_error) { g_snprintf (error_message, BUF_SIZE, _("Can't find source file :\n%s"), from_path_internal); gtkutil_message_dialog (_("Error!!"), error_message, window); } goto ERROR; } /***************** * check dest dir *****************/ if (!iswritable (dir)) { if (show_error) { g_snprintf (error_message, BUF_SIZE, _("Can't move file : %s\n" "Permission denied: %s\n"), from_path_internal, dir_internal); gtkutil_message_dialog (_("Error!!"), error_message, window); } goto ERROR; } /******************* * check source dir *******************/ from_dir = g_dirname (from_path); if (!iswritable (from_dir)) { if (show_error) { gchar *from_dir_internal; from_dir_internal = charset_to_internal (from_dir, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); g_snprintf (error_message, BUF_SIZE, _("Can't move file : %s\n" "Permission denied: %s\n"), from_path_internal, from_dir_internal); gtkutil_message_dialog (_("Error!!"), error_message, window); g_free (from_dir_internal); } g_free (from_dir); goto ERROR; } g_free (from_dir); retval = TRUE; ERROR: g_free (from_path_internal); g_free (dir_internal); return retval; } static gboolean move_file_check_over_write (const gchar *from_path, struct stat *from_st, const gchar *to_path, struct stat *to_st, gchar *new_path, gint new_path_len, ConfirmType *action, gboolean show_error, GtkWindow *window) { gchar error_message[BUF_SIZE], *to_path_internal; gint exist; gboolean retval = FALSE; if (new_path) new_path[0] = '\0'; to_path_internal = charset_to_internal (to_path, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); exist = !lstat(to_path, to_st); if (exist && (!strcmp (from_path, to_path) || from_st->st_ino == to_st->st_ino)) { if (show_error) { g_snprintf (error_message, BUF_SIZE, _("Same file :\n%s"), to_path_internal); gtkutil_message_dialog (_("Error!!"), error_message, window); } goto ERROR; } else if (exist && *action == CONFIRM_ASK) { if (isdir (from_path)) { g_snprintf (error_message, BUF_SIZE, _("File exist : %s"), to_path_internal); gtkutil_message_dialog (_("ERROR!!"), error_message, window); } else { g_snprintf (error_message, BUF_SIZE, _("The file exists : %s\n" "Overwrite?"), to_path_internal); *action = gtkutil_overwrite_confirm_dialog (_("File exist!!"), error_message, to_path, from_path, new_path, MAX_PATH_LEN, ConfirmDialogMultipleFlag, window); } } if (new_path && *new_path) { retval = TRUE; } else { switch (*action) { case CONFIRM_YES: case CONFIRM_YES_TO_ALL: retval = TRUE; break; case CONFIRM_NO: case CONFIRM_CANCEL: retval = FALSE; break; case CONFIRM_NO_TO_ALL: if (exist) retval = FALSE; else retval = TRUE; break; default: if (!exist) retval = TRUE; else retval = FALSE; break; } } ERROR: g_free (to_path_internal); return retval; } /* * move_file: * @ * * from_path : * dir : * action : * show_error : * Return : TRUE if success to move file. */ gboolean move_file (const gchar *from_path, const gchar *dir, ConfirmType *action, gboolean show_error, GtkWindow *window) { gchar *to_path, error_message[BUF_SIZE]; struct stat from_st, to_st, todir_st; struct utimbuf ut; gboolean move_file = FALSE, move_faild = FALSE, copy_success = FALSE, retval; gchar *from_path_internal, *to_path_internal, new_path[MAX_PATH_LEN]; new_path[0] = '\0'; g_return_val_if_fail (action, FALSE); retval = move_file_check_path (from_path, &from_st, dir, show_error, window); if (!retval) return FALSE; /* set dest path */ to_path = g_strconcat (dir, g_basename (from_path), NULL); move_file = move_file_check_over_write (from_path, &from_st, to_path, &to_st, new_path, MAX_PATH_LEN, action, show_error, window); if (!move_file) { retval = FALSE; goto ERROR0; } from_path_internal = charset_to_internal (from_path, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); if (*new_path) { g_free (to_path); to_path = g_strdup (new_path); } to_path_internal = charset_to_internal (to_path, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); /************** * move file!! **************/ stat (dir, &todir_st); if (from_st.st_dev != todir_st.st_dev) { copy_success = copy_file_to_file (from_path, to_path, action, show_error, window); if (copy_success) { /* reset new file's time info */ ut.actime = from_st.st_atime; ut.modtime = from_st.st_mtime; utime(to_path, &ut); /* remove old file */ if (remove (from_path) < 0) { /* faild to remove file */ if (show_error) { g_snprintf (error_message, BUF_SIZE, _("Faild to remove file :\n" "%s"), from_path_internal); gtkutil_message_dialog (_("Error!!"), error_message, window); } retval = FALSE; goto ERROR1; } } else { move_faild = TRUE; } } else { move_faild = rename (from_path, to_path); } /************************ * if faild to move file ************************/ if (move_faild) { if (show_error) { g_snprintf (error_message, BUF_SIZE, _("Faild to move file :\n" "From : %s\n" "To : %s"), from_path_internal, to_path_internal); gtkutil_message_dialog (_("Error!!"), error_message, window); } retval = FALSE; } ERROR1: g_free (from_path_internal); g_free (to_path_internal); ERROR0: g_free (to_path); return retval; } static gboolean copy_dir_check_source (const gchar *from_dir, gboolean show_error, GtkWindow *window) { gchar error_message[BUF_SIZE], *from_dir_internal; gboolean retval = TRUE; from_dir_internal = charset_to_internal (from_dir, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); if (islink (from_dir)) { /* check path is link or not */ if (show_error) { g_snprintf (error_message, BUF_SIZE, _("%s is link!!.\n"), from_dir_internal); gtkutil_message_dialog (_("Error!!"), error_message, window); } retval = FALSE; goto ERROR; } if (!file_exists (from_dir)) { /* check path exists or not */ if (show_error) { g_snprintf (error_message, BUF_SIZE, _("Can't find source file :\n%s"), from_dir_internal); gtkutil_message_dialog (_("Error!!"), error_message, window); } retval = FALSE; goto ERROR; } if (!isdir (from_dir)) { /* check path is directory or not */ if (show_error) { g_snprintf (error_message, BUF_SIZE, _("%s is not directory!!.\n"), from_dir_internal); gtkutil_message_dialog (_("Error!!"), error_message, window); } retval = FALSE; goto ERROR; } ERROR: g_free (from_dir_internal); return TRUE; } static gboolean copy_dir_check_dest (const gchar *from_path, const gchar *dirname, const gchar *to_dir, gboolean show_error, GtkWindow *window) { gchar error_message[BUF_SIZE]; gchar *from_path_internal, *dirname_internal, *to_dir_internal; gboolean retval = TRUE; from_path_internal = charset_to_internal (from_path, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); dirname_internal = charset_to_internal (dirname, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); to_dir_internal = charset_to_internal (to_dir, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); if (!iswritable (dirname)) { /* check permission */ if (show_error) { g_snprintf (error_message, BUF_SIZE, _("Can't copy directory : %s\n" "Permission denied: %s\n"), from_path_internal, dirname_internal); gtkutil_message_dialog (_("Error!!"), error_message, window); } retval = FALSE; goto ERROR; } if (file_exists (to_dir)) { /* check dest path */ if (show_error) { g_snprintf (error_message, BUF_SIZE, _("File exists!! : %s\n"), to_dir_internal); gtkutil_message_dialog (_("Error!!"), error_message, window); } retval = FALSE; goto ERROR; } ERROR: g_free (from_path_internal); g_free (dirname_internal); g_free (to_dir_internal); return retval; } /* * copy_dir: * @ * * from_path : * dir : * action : * show_error : * Return : TRUE if success to copy directory. */ static gboolean copy_dir (const gchar *from_path, const gchar *dir, ConfirmType *action, gboolean show_error, GtkWindow *window) { GtkWidget *progress_win; gchar message[BUF_SIZE]; GList *filelist, *node; gchar *from_dir, *to_dir, *to_path, *dirname; ConfirmType confirm; gboolean result, cancel = FALSE; gfloat progress; gint pos, length; from_dir = g_strdup (from_path); if (from_dir[strlen (from_dir) - 1] == '/') from_dir[strlen (from_dir) - 1] = '\0'; dirname = g_strdup (dir); if (dirname[strlen (dirname) - 1] == '/') dirname[strlen (dirname) - 1] = '\0'; to_dir = g_strconcat (dirname, "/", g_basename (from_dir), NULL); /******************* * check source dir *******************/ result = copy_dir_check_source (from_dir, show_error, window); if (!result) goto ERROR; /***************** * check dest dir *****************/ result = copy_dir_check_dest (from_path, dirname, to_dir, show_error, window); g_free (dirname); if (!result) goto ERROR; /**************** * do copy files ****************/ filelist = node = get_dir_all_file (from_path); confirm = CONFIRM_YES_TO_ALL; progress_win = gtkutil_create_progress_window (_("Copy directory"), "...", &cancel, 300, -1, window); gtk_grab_add (progress_win); length = g_list_length (filelist); while (node) { guint len; gchar *filename = node->data; gchar *tmpstr; while (gtk_events_pending()) gtk_main_iteration(); pos = g_list_position (filelist, node); progress = (gfloat) pos / (gfloat) length; { /********** convert charset **********/ gchar *filename_internal; filename_internal = charset_to_internal (filename, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); g_snprintf (message, BUF_SIZE, _("Copying %s ..."), filename_internal); g_free (filename_internal); } gtkutil_progress_window_update (progress_win, _("Copying directory"), message, NULL, progress); len = strlen (from_path); if (strlen (filename) > len) { tmpstr = filename + len; if (tmpstr[0] == '/') tmpstr++; to_path = g_strconcat (to_dir, "/", tmpstr, NULL); /* realy do copy :-) */ mkdirs (to_path); copy_file_to_file (filename, to_path, &confirm, show_error, window); g_free (to_path); } node = g_list_next (node); } gtk_grab_remove (progress_win); gtk_widget_destroy (progress_win); g_list_foreach (filelist, (GFunc) g_free, NULL); g_list_free (filelist); g_free (from_dir); g_free (to_dir); return TRUE; ERROR: g_free (from_dir); g_free (to_dir); return FALSE; } /* * copy_file_to_file: * @ * * from_path : * to_path : * action : * show_error : * Return : TRUE if success to copy file. */ gboolean copy_file_to_file (const gchar *from_path, const gchar *to_path, ConfirmType *action, gboolean show_error, GtkWindow *window) { gint b; gchar buf[BUFSIZ], *from_path_internal, *to_path_internal; gchar error_message[BUF_SIZE]; FILE *from, *to; struct stat from_st, to_st; gint exist; gchar new_path[MAX_PATH_LEN]; new_path[0] = '\0'; g_return_val_if_fail (action, FALSE); /******************** * check source file ********************/ if (isdir (from_path)) { return copy_dir (from_path, to_path, action, show_error, window); } from_path_internal = charset_to_internal (from_path, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); to_path_internal = charset_to_internal (to_path, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); if (lstat (from_path, &from_st)) { if (show_error) { g_snprintf (error_message, BUF_SIZE, _("Can't find source file :\n%s"), from_path_internal); gtkutil_message_dialog (_("Error!!"), error_message, window); } goto ERROR; } /****************** * check dest file ******************/ exist = !lstat(to_path, &to_st); if (exist && (!strcmp (from_path, to_path) || from_st.st_ino == to_st.st_ino)) { if (show_error) { g_snprintf (error_message, BUF_SIZE, _("Same file :\n%s"), to_path_internal); gtkutil_message_dialog (_("Error!!"), error_message, window); } goto ERROR; } else if (exist && *action == CONFIRM_ASK) { g_snprintf (error_message, BUF_SIZE, _("The file exists : %s\n" "Overwrite?"), to_path_internal); *action = gtkutil_overwrite_confirm_dialog (_("File exist!!"), error_message, to_path, from_path, new_path, MAX_PATH_LEN, ConfirmDialogMultipleFlag, window); } if (*new_path) { g_free (to_path_internal); to_path = new_path; to_path_internal = charset_to_internal (to_path, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); } else { switch (*action) { case CONFIRM_YES: case CONFIRM_YES_TO_ALL: break; case CONFIRM_NO: case CONFIRM_CANCEL: goto ERROR; break; case CONFIRM_NO_TO_ALL: if (exist) goto ERROR; break; default: if (exist) goto ERROR; break; } } /********** * do copy **********/ from = fopen (from_path, "rb"); if (!from) { if (show_error) { g_snprintf (error_message, BUF_SIZE, _("Can't open file for read :\n%s"), to_path_internal); gtkutil_message_dialog (_("Error!!"), error_message, window); } goto ERROR; } to = fopen (to_path, "wb"); if (!to) { fclose (from); if (show_error) { g_snprintf (error_message, BUF_SIZE, _("Can't open file for write :\n%s"), to_path_internal); gtkutil_message_dialog (_("Error!!"), error_message, window); } goto ERROR; } while ((b = fread (buf, sizeof (char), BUFSIZ, from)) > 0) { fwrite (buf, sizeof (char), b, to); if (ferror (to)) { fclose (from); fclose (to); if (show_error) { g_snprintf (error_message, BUF_SIZE, _("An error occured while copying file :\n%s"), to_path_internal); gtkutil_message_dialog (_("Error!!"), error_message, window); } goto ERROR; } } fclose (from); fclose (to); g_free (to_path_internal); g_free (from_path_internal); return TRUE; ERROR: g_free (to_path_internal); g_free (from_path_internal); return FALSE; } /* * copy_file: * @ * * from_path : * dir : * action : * show_error : * Return : TRUE if success to copy file. */ gboolean copy_file (const gchar *from_path, const gchar *dir, ConfirmType *action, gboolean show_error, GtkWindow *window) { gchar *to_path; gboolean retval; gchar error_message[BUF_SIZE]; g_return_val_if_fail (action, FALSE); /* check source file is directory or not */ if (isdir (from_path)) { return copy_dir (from_path, dir, action, show_error, window); } /***************** * check dest dir *****************/ if (!iswritable (dir)) { if (show_error) { gchar *from_path_internal, *dir_internal; from_path_internal = charset_to_internal (from_path, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); dir_internal = charset_to_internal (dir, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); g_snprintf (error_message, BUF_SIZE, _("Can't copy file : %s\n" "Permission denied: %s\n"), from_path_internal, dir_internal); gtkutil_message_dialog (_("Error!!"), error_message, window); g_free (from_path_internal); g_free (dir_internal); } return FALSE; } to_path = g_strconcat (dir, g_basename (from_path), NULL); retval = copy_file_to_file (from_path, to_path, action, show_error, window); g_free (to_path); return retval; } /* * link_file: * @ * * from_path : * dir : * action : * show_error : * Return : TRUE if success to link file. */ gboolean link_file (const gchar *from_path, const gchar *dir, gboolean show_error, GtkWindow *window) { gchar *to_path, *to_path_internal, *from_path_internal, *dir_internal; struct stat from_st, to_st; gboolean link_faild; gchar error_message[BUF_SIZE]; from_path_internal = charset_to_internal (from_path, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); dir_internal = charset_to_internal (dir, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); /******************** * check source file ********************/ if (lstat (from_path, &from_st)) { if (show_error) { g_snprintf (error_message, BUF_SIZE, _("Can't find source file :\n%s"), from_path_internal); gtkutil_message_dialog (_("Error!!"), error_message, window); } goto ERROR0; } /***************** * check dest dir *****************/ if (!iswritable (dir)) { if (show_error) { g_snprintf (error_message, BUF_SIZE, _("Can't create link : %s\n" "Permission denied: %s\n"), from_path_internal, dir_internal); gtkutil_message_dialog (_("Error!!"), error_message, window); } goto ERROR0; } to_path = g_strconcat(dir_internal, g_basename(from_path), NULL); to_path_internal = charset_to_internal (to_path, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); /****************** * check dest path ******************/ if (!lstat (to_path, &to_st)) { if (show_error) { g_snprintf (error_message, BUF_SIZE, _("File exist : %s"), to_path_internal); gtkutil_message_dialog (_("Error!!"), error_message, window); } goto ERROR1; } link_faild = symlink(from_path, to_path); if (link_faild) { if (show_error) { g_snprintf (error_message, BUF_SIZE, _("Faild to create link :\n" "From : %s\n" "To : %s"), from_path_internal, to_path_internal); gtkutil_message_dialog (_("Error!!"), error_message, window); } goto ERROR1; } g_free (to_path); g_free (to_path_internal); g_free (from_path_internal); g_free (dir_internal); return TRUE; ERROR1: g_free (to_path); g_free (to_path_internal); ERROR0: g_free (from_path_internal); g_free (dir_internal); return FALSE; } static gchar * get_dest_cache_dir (const gchar *src_file, const gchar *dest_dir, const gchar *cache_type) { gchar *dest_file, *dest_cache_dir; if (!src_file || !dest_dir || !cache_type) return NULL; dest_file = g_strconcat (dest_dir, g_basename (src_file), NULL); dest_cache_dir = gimv_thumb_cache_get_path (dest_file, cache_type); if (dest_cache_dir) { gchar *endchr; endchr = strrchr (dest_cache_dir, '/'); if (endchr) { *(endchr + 1) = '\0'; mkdirs (dest_cache_dir); } else { g_free (dest_cache_dir); dest_cache_dir = NULL; } } g_free (dest_file); return dest_cache_dir; } static gchar * get_dest_comment_dir (const gchar *src_file, const gchar *dest_dir) { gchar *dest_file, *dest_comment_dir; if (!src_file || !dest_dir) return NULL; dest_file = g_strconcat (dest_dir, g_basename (src_file), NULL); dest_comment_dir = gimv_comment_get_path (dest_file); if (dest_comment_dir) { gchar *endchr; endchr = strrchr (dest_comment_dir, '/'); if (endchr) { *(endchr + 1) = '\0'; mkdirs (dest_comment_dir); } else { g_free (dest_comment_dir); dest_comment_dir = NULL; } } g_free (dest_file); return dest_comment_dir; } static gboolean do_file_operate (const gchar *src_file, const gchar *dest_dir, ConfirmType *over_write, FileOperateType action, GtkWidget *progress_win, gfloat progress, GtkWindow *window) { gchar *src_cache, *dest_cache_dir; gchar *src_comment, *dest_comment_dir; gchar *cache_type; gchar *src_file_internal; struct stat src_st, dest_st; ConfirmType cache_over_write = CONFIRM_YES_TO_ALL; gboolean success = TRUE, delete_src = FALSE, result; gchar message[BUF_SIZE]; /* FIXME!! */ /* get cache file & dir */ src_cache = gimv_thumb_find_thumbcache (src_file, &cache_type); dest_cache_dir = get_dest_cache_dir (src_file, dest_dir, cache_type); src_comment = gimv_comment_find_file (src_file); dest_comment_dir = get_dest_comment_dir (src_file, dest_dir); /* if move to different file system, change to copy */ lstat (src_file, &src_st); lstat (dest_dir, &dest_st); if (src_st.st_dev != dest_st.st_dev && action == FILE_MOVE ) { action = FILE_COPY; delete_src = TRUE; } src_file_internal = charset_to_internal (src_file, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); switch (action) { case FILE_MOVE: g_snprintf (message, BUF_SIZE, _("Moving %s ..."), src_file_internal); gtkutil_progress_window_update (progress_win, _("Moving files"), message, NULL, progress); result = move_file (src_file, dest_dir, over_write, TRUE, window); if (!result) success = FALSE; /* FIXME!! */ /* move cache file */ if (result && src_cache && dest_cache_dir) move_file (src_cache, dest_cache_dir, &cache_over_write, FALSE, window); if (result && src_comment && dest_comment_dir) move_file (src_comment, dest_comment_dir, &cache_over_write, FALSE, window); break; case FILE_COPY: { gboolean delete_src_cache = FALSE, delete_src_comment = FALSE; g_snprintf (message, BUF_SIZE, _("Copying %s ..."), src_file_internal); gtkutil_progress_window_update (progress_win, _("Copying files"), message, NULL, progress); result = copy_file (src_file, dest_dir, over_write, TRUE, window); if (!result) success = FALSE; /* FIXME!! */ /* copy cache file */ if (result && src_cache && dest_cache_dir) { if (copy_file (src_cache, dest_cache_dir, &cache_over_write, FALSE, window)) delete_src_cache = TRUE; } if (result && src_comment && dest_comment_dir) { if (copy_file (src_comment, dest_comment_dir, &cache_over_write, FALSE, window)) delete_src_comment = TRUE; } /* FIXME: delete src? */ if (result && delete_src) { GList *delete_file_list = NULL; delete_file_list = g_list_append (delete_file_list, (gpointer) src_file); if (delete_src_cache) delete_file_list = g_list_append (delete_file_list, src_cache); if (delete_src_comment) delete_file_list = g_list_append (delete_file_list, src_comment); if (delete_file_list) delete_files (delete_file_list, CONFIRM_YES, window); g_list_free (delete_file_list); } break; } case FILE_LINK: g_snprintf (message, BUF_SIZE, _("Creating Link %s ..."), src_file_internal); gtkutil_progress_window_update (progress_win, _("Creating Links"), message, NULL, progress); result = link_file (src_file, dest_dir, TRUE, window); if (!result) success = FALSE; /* FIXME!! */ /* link cache file */ if (result && src_cache && dest_cache_dir) link_file (src_cache, dest_cache_dir, FALSE, window); if (result && src_comment && dest_comment_dir) link_file (src_comment, dest_comment_dir, FALSE, window); break; default: success = FALSE; break; } g_free (src_file_internal); /* FIXME!! */ g_free (src_cache); g_free (dest_cache_dir); g_free (src_comment); g_free (dest_comment_dir); return success; } gboolean files2dir (GList *filelist, const gchar *dir, FileOperateType action, GtkWindow *window) { GtkWidget *progress_win; GList *node; ConfirmType over_write = CONFIRM_ASK; gboolean success = TRUE, cancel = FALSE, result; gchar message[BUF_SIZE], *src_file, *dest_dir, *dir_internal; gint length, pos; gfloat progress; g_return_val_if_fail (filelist, FALSE); g_return_val_if_fail (dir, FALSE); dir_internal = charset_to_internal (dir, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); /***************** * check dest dir *****************/ if (!file_exists (dir)) { g_snprintf (message, BUF_SIZE, _("Directory doesn't exist!!: %s"), dir_internal); gtkutil_message_dialog (_("Error!!"), message, window); goto ERROR; } if (!iswritable (dir)) { g_snprintf (message, BUF_SIZE, _("Permission denied!!: %s"), dir_internal); gtkutil_message_dialog (_("Error!!"), message, window); goto ERROR; } /* add "/" character */ if (dir[strlen(dir) - 1] == '/') dest_dir = g_strdup (dir); else dest_dir = g_strconcat (dir, "/", NULL); /* create progress window */ progress_win = gtkutil_create_progress_window ("File Operation", "...", &cancel, 300, -1, window); gtk_grab_add (progress_win); /* do file operation */ length = g_list_length (filelist); for (node = filelist; node; node = g_list_next (node)) { src_file = node->data; while (gtk_events_pending()) gtk_main_iteration(); pos = g_list_position (filelist, node); progress = (gfloat) pos / (gfloat) length; result = do_file_operate (src_file, dest_dir, &over_write, action, progress_win, progress, window); if (!result) success = FALSE; /* cancel */ if (cancel || (over_write == CONFIRM_CANCEL)) break; /* reset to CONFIRM_ASK mode */ if (over_write != CONFIRM_YES_TO_ALL && over_write != CONFIRM_NO_TO_ALL) { over_write = CONFIRM_ASK; } } gtk_grab_remove (progress_win); gtk_widget_destroy (progress_win); g_free (dest_dir); g_free (dir_internal); return success; ERROR: g_free (dir_internal); return FALSE; } gboolean files2dir_with_dialog (GList *filelist, gchar **default_dir, FileOperateType action, GtkWindow *window) { gchar *dir; gboolean retval = FALSE; gchar *title, *label, *tmpstr; g_return_val_if_fail (filelist, FALSE); g_return_val_if_fail (default_dir, FALSE); if (!*default_dir) *default_dir = g_strdup (g_getenv("HOME")); switch (action) { case FILE_MOVE: title = _("Move files to..."); label = _("Move files to: "); break; case FILE_COPY: title = _("Copy files to..."); label = _("Copy files to: "); break; case FILE_LINK: title = _("Link files to..."); label = _("Link files to: "); break; default: dir = *default_dir; goto FUNC_END; break; } tmpstr = charset_to_internal (*default_dir, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); dir = gtkutil_modal_file_dialog (title, tmpstr, MODAL_FILE_DIALOG_DIR_ONLY, window); g_free (tmpstr); tmpstr = NULL; if (dir) { if (dir[strlen(dir) - 1] != '/') { tmpstr = dir; dir = g_strconcat (dir, "/", NULL); g_free (tmpstr); } tmpstr = dir; dir = charset_internal_to_locale (dir); g_free (tmpstr); retval = files2dir (filelist, dir, action, window); } FUNC_END: if (*default_dir != dir) g_free (*default_dir); *default_dir = dir; return retval; } gboolean delete_dir (const gchar *path, GtkWindow *window) { gboolean exist, cancel, not_empty = FALSE; struct stat st; gchar message[BUF_SIZE], *path_internal; GList *filelist, *listnode; gint length, pos; gfloat progress; GtkWidget *progress_win; ConfirmType action; g_return_val_if_fail (path && *path, FALSE); path_internal = charset_to_internal (path, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); /* check direcotry exist or not */ exist = !lstat (path, &st); if (!exist) { g_snprintf (message, BUF_SIZE, _("Directory not exist : %s"), path_internal); gtkutil_message_dialog (_("Error!!"), message, window); goto ERROR; } /* check path is link or not */ if (islink (path)) { g_snprintf (message, BUF_SIZE, _("%s is symbolic link.\n" "Remove link ?"), path_internal); action = gtkutil_confirm_dialog (_("Confirm Deleting Directory"), message, 0, window); if (action == CONFIRM_YES) { remove (path); } goto SUCCESS; } /* confirm */ g_snprintf (message, BUF_SIZE, _("Delete %s\n" "OK?"), path_internal); action = gtkutil_confirm_dialog (_("Confirm Deleting Directory"), message, 0, window); if (action != CONFIRM_YES) goto ERROR; /* remove sub directories recursively */ filelist = get_dir_all (path); if (filelist) { g_snprintf (message, BUF_SIZE, _("%s is not empty\n" "Delete all files under %s ?"), path_internal, path_internal); action = gtkutil_confirm_dialog (_("Confirm Deleting Directory"), message, 0, window); if (action != CONFIRM_YES) goto ERROR; /* create progress bar */ progress_win = gtkutil_create_progress_window ("Delete File", "Deleting Files", &cancel, 300, -1, window); gtk_grab_add (progress_win); length = g_list_length (filelist); listnode = filelist; while (listnode) { /* update progress */ pos = g_list_position (filelist, listnode); if ((pos % 50) == 0) { while (gtk_events_pending()) gtk_main_iteration(); pos = g_list_position (filelist, listnode); progress = (gfloat) pos / (gfloat) length; { /********** convert charset **********/ gchar *tmpstr; tmpstr = charset_to_internal (listnode->data, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); g_snprintf (message, BUF_SIZE, _("Deleting %s ..."), tmpstr); g_free (tmpstr); } gtkutil_progress_window_update (progress_win, NULL, message, NULL, progress); } /* remove a file */ if (remove ((gchar *) listnode->data) < 0) not_empty = TRUE; listnode = g_list_next (listnode); /* cancel */ if (cancel) break; } gtk_grab_remove (progress_win); gtk_widget_destroy (progress_win); g_list_foreach (filelist, (GFunc) g_free, NULL); g_list_free (filelist); } /* remove the directory */ if (not_empty) { g_snprintf (message, BUF_SIZE, _("Faild to remove directory :\n" "%s is not empty."), path_internal); gtkutil_message_dialog (_("Error!!"), message, window); } else if (remove (path) < 0) { g_snprintf (message, BUF_SIZE, _("Faild to remove directory : %s"), path_internal); gtkutil_message_dialog (_("Error!!"), message, window); } SUCCESS: g_free (path_internal); return TRUE; ERROR: g_free (path_internal); return FALSE; } gboolean delete_files (GList *filelist, ConfirmType confirm, GtkWindow *window) { GtkWidget *progress_win = NULL; GList *node; gboolean cancel = FALSE, dialog = FALSE; gint pos, length; gfloat progress; gchar message[BUF_SIZE], *dirname; g_return_val_if_fail (filelist, FALSE); length = g_list_length (filelist); if (confirm == CONFIRM_ASK) dialog = TRUE; if (dialog) { g_snprintf (message, BUF_SIZE, _("Delete these %d files.\n" "OK?"), length); confirm = gtkutil_confirm_dialog (_("Confirm Deleting Files"), message, 0, window); } if (!(confirm == CONFIRM_YES || confirm == CONFIRM_YES_TO_ALL)) { return FALSE; } if (dialog) { progress_win = gtkutil_create_progress_window (_("Delete File"), _("Deleting Files"), &cancel, 300, -1, window); gtk_grab_add (progress_win); } node = filelist; while (node) { gchar *filename = node->data, *filename_internal, *dirname_internal; node = g_list_next (node); if (!filename || !*filename) continue; filename_internal = charset_to_internal (filename, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); while (gtk_events_pending()) gtk_main_iteration(); pos = g_list_position (filelist, node); progress = (gfloat) pos / (gfloat) length; if (dialog && progress_win) { g_snprintf (message, BUF_SIZE, _("Deleting %s ..."), filename_internal); gtkutil_progress_window_update (progress_win, NULL, message, NULL, progress); } dirname = g_dirname (filename); dirname_internal = charset_to_internal (dirname, conf.charset_filename, conf.charset_auto_detect_fn, conf.charset_filename_mode); if (!iswritable (dirname)) { g_snprintf (message, BUF_SIZE, _("Permission denied : %s"), dirname_internal); gtkutil_message_dialog (_("Error!!"), message, window); } else { /* remove file!! */ gboolean success; gint ret; if (isdir (filename)) { success = delete_dir (filename, window); } else { ret = remove (filename); if (ret < 0) success = FALSE; else success = TRUE; } if (!success) { g_snprintf (message, BUF_SIZE, _("Faild to delete file :\n%s"), filename_internal); gtkutil_message_dialog (_("Error!!"), message, window); } } g_free (dirname); g_free (dirname_internal); g_free (filename_internal); dirname = NULL; dirname_internal = NULL; filename_internal = NULL; /* cancel */ if (cancel) break; } if (dialog && progress_win) { gtk_grab_remove (progress_win); gtk_widget_destroy (progress_win); } return TRUE; } gboolean make_dir_dialog (const gchar *parent_dir, GtkWindow *window) { gchar *dirname, *path, *parent_path, *tmpstr; gboolean success = FALSE, exist; struct stat st; gchar error_message[BUF_SIZE]; g_return_val_if_fail (parent_dir && *parent_dir, FALSE); parent_path = add_slash (parent_dir); if (!iswritable (parent_path)) { g_snprintf (error_message, BUF_SIZE, _("Permission denied : %s"), parent_path); gtkutil_message_dialog (_("Error!!"), error_message, window); goto ERROR0; } dirname = gtkutil_popup_textentry (_("Make directory"), _("New directory name: "), NULL, NULL, -1, 0, window); if (!dirname) goto ERROR0; tmpstr = charset_internal_to_locale (dirname); g_free (dirname); dirname = tmpstr; path = g_strconcat (parent_path, dirname, NULL); exist = !lstat (path, &st); if (exist) { if (isdir (path)) g_snprintf (error_message, BUF_SIZE, _("Directory exist : %s"), path); else g_snprintf (error_message, BUF_SIZE, _("File exist : %s"), path); gtkutil_message_dialog (_("Error!!"), error_message, window); g_free (path); goto ERROR1; } success = makedir (path); if (!success) { g_snprintf (error_message, BUF_SIZE, _("Faild to create directory : %s"), path); gtkutil_message_dialog (_("Error!!"), error_message, window); } ERROR1: g_free (path); ERROR0: g_free (parent_path); return success; } gboolean rename_dir_dialog (const gchar *dir, GtkWindow *window) { gboolean exist, success = FALSE; struct stat st; gchar message[BUF_SIZE]; gchar *path, *parent_dir, *dirname, *src_path, *src_file_internal; gchar *dest_path, *tmpstr; g_return_val_if_fail (dir && *dir, FALSE); path = add_slash (dir); /* check direcotry */ exist = !lstat (path, &st); if (!exist) { g_snprintf (message, BUF_SIZE, _("Directory not exist :%s"), path); gtkutil_message_dialog (_("Error!!"), message, window); goto ERROR0; } src_path = remove_slash (path); parent_dir = g_dirname (src_path); /* popup rename directory dialog */ src_file_internal = charset_locale_to_internal (g_basename (src_path)); dirname = gtkutil_popup_textentry (_("Rename directory"), _("New directory name: "), src_file_internal, NULL, -1, 0, window); g_free (src_file_internal); if (!dirname) goto ERROR1; tmpstr = charset_internal_to_locale (dirname); g_free (dirname); dirname = tmpstr; dest_path = g_strconcat (parent_dir, "/", dirname, NULL); if (rename (src_path, dest_path) < 0) { g_snprintf (message, BUF_SIZE, _("Faild to rename directory : %s"), src_path); gtkutil_message_dialog (_("Error!!"), message, window); } else { success = TRUE; } g_free (dirname); g_free (dest_path); ERROR1: g_free (src_path); g_free (parent_dir); ERROR0: g_free (path); return success; }