Bug fix: Run-time errors when removing a toolbar icon
[geeqie.git] / src / trash.cc
1 /*
2  * Copyright (C) 2006 John Ellis
3  * Copyright (C) 2008 - 2016 The Geeqie Team
4  *
5  * Author: John Ellis
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include "main.h"
23 #include "trash.h"
24 #include "utilops.h"
25 #include "window.h"
26
27 #include "editors.h"
28 #include "filedata.h"
29 #include "ui-fileops.h"
30
31 /*
32  *--------------------------------------------------------------------------
33  * Safe Delete
34  *--------------------------------------------------------------------------
35  */
36
37 static gint file_util_safe_number(gint64 free_space)
38 {
39         gint n = 0;
40         gint64 total = 0;
41         GList *list;
42         GList *work;
43         gboolean sorted = FALSE;
44         gboolean warned = FALSE;
45         FileData *dir_fd;
46
47         dir_fd = file_data_new_dir(options->file_ops.safe_delete_path);
48         if (!filelist_read(dir_fd, &list, nullptr))
49                 {
50                 file_data_unref(dir_fd);
51                 return 0;
52                 }
53         file_data_unref(dir_fd);
54
55         work = list;
56         while (work)
57                 {
58                 FileData *fd;
59                 gint v;
60
61                 fd = static_cast<FileData *>(work->data);
62                 work = work->next;
63
64                 v = static_cast<gint>(strtol(fd->name, nullptr, 10));
65                 if (v >= n) n = v + 1;
66
67                 total += fd->size;
68                 }
69
70         while (options->file_ops.safe_delete_folder_maxsize > 0 && list &&
71                (free_space < 0 || total + free_space > static_cast<gint64>(options->file_ops.safe_delete_folder_maxsize) * 1048576) )
72                 {
73                 FileData *fd;
74
75                 if (!sorted)
76                         {
77                         list = filelist_sort(list, SORT_NAME, TRUE, TRUE);
78                         sorted = TRUE;
79                         }
80
81                 fd = static_cast<FileData *>(list->data);
82                 list = g_list_remove(list, fd);
83
84                 DEBUG_1("expunging from trash for space: %s", fd->name);
85                 if (!unlink_file(fd->path) && !warned)
86                         {
87                         file_util_warning_dialog(_("Delete failed"),
88                                                  _("Unable to remove old file from trash folder"),
89                                                  GQ_ICON_DIALOG_WARNING, nullptr);
90                         warned = TRUE;
91                         }
92                 total -= fd->size;
93                 file_data_unref(fd);
94                 }
95
96         filelist_free(list);
97
98         return n;
99 }
100
101 void file_util_trash_clear()
102 {
103         file_util_safe_number(-1);
104 }
105
106 static gchar *file_util_safe_dest(const gchar *path)
107 {
108         gint n;
109         gchar *name;
110         gchar *dest;
111
112         n = file_util_safe_number(filesize(path));
113         name = g_strdup_printf("%06d_%s", n, filename_from_path(path));
114         dest = g_build_filename(options->file_ops.safe_delete_path, name, NULL);
115         g_free(name);
116
117         return dest;
118 }
119
120 static void move_to_trash_failed_cb(GenericDialog *, gpointer)
121 {
122         help_window_show("TrashFailed.html");
123 }
124
125 gboolean file_util_safe_unlink(const gchar *path)
126 {
127         static GenericDialog *gd = nullptr;
128         gchar *result = nullptr;
129         gboolean success = TRUE;
130         gchar *message;
131
132         if (!isfile(path)) return FALSE;
133
134         if (options->file_ops.no_trash)
135                 {
136                 if (!unlink_file(path))
137                         {
138                         file_util_warning_dialog(_("Delete failed"),
139                                                  _("Unable to remove file"),
140                                                  GQ_ICON_DIALOG_WARNING, nullptr);
141                         success = FALSE;
142                         }
143                 }
144         else if (!options->file_ops.use_system_trash)
145                 {
146                 if (!isdir(options->file_ops.safe_delete_path))
147                         {
148                         DEBUG_1("creating trash: %s", options->file_ops.safe_delete_path);
149                         if (!options->file_ops.safe_delete_path || !mkdir_utf8(options->file_ops.safe_delete_path, 0755))
150                                 {
151                                 result = _("Could not create folder");
152                                 success = FALSE;
153                                 }
154                         }
155
156                 if (success)
157                         {
158                         gchar *dest;
159
160                         dest = file_util_safe_dest(path);
161                         if (dest)
162                                 {
163                                 DEBUG_1("safe deleting %s to %s", path, dest);
164                                 success = move_file(path, dest);
165                                 }
166                         else
167                                 {
168                                 success = FALSE;
169                                 }
170
171                         if (!success && !access_file(path, W_OK))
172                                 {
173                                 result = _("Permission denied");
174                                 }
175                         g_free(dest);
176                         }
177
178                 if (result && !gd)
179                         {
180                         gchar *buf;
181
182                         buf = g_strdup_printf(_("Unable to access or create the trash folder.\n\"%s\""), options->file_ops.safe_delete_path);
183                         gd = file_util_warning_dialog(result, buf, GQ_ICON_DIALOG_WARNING, nullptr);
184                         g_free(buf);
185                         }
186                 }
187         else
188                 {
189                 GFile *tmp = g_file_new_for_path(path);
190                 GError *error = nullptr;
191
192                 if (!g_file_trash(tmp, FALSE, &error) )
193                         {
194                         message = g_strconcat("See the Help file for a possible workaround.\n\n", error->message, NULL);
195                         gd = warning_dialog(_("Move to trash failed\n\n"), message, GQ_ICON_DIALOG_ERROR, nullptr);
196                         generic_dialog_add_button(gd, GQ_ICON_HELP, _("Help"), move_to_trash_failed_cb, FALSE);
197
198                         g_free(message);
199                         g_error_free(error);
200
201                         /* A second warning dialog is not necessary */
202                         }
203         }
204
205         return success;
206 }
207
208 gchar *file_util_safe_delete_status()
209 {
210         gchar *buf = nullptr;
211
212         if (is_valid_editor_command(CMD_DELETE))
213                 {
214                 buf = g_strdup(_("Deletion by external command"));
215                 }
216         else if (options->file_ops.no_trash)
217                 {
218                 buf = g_strdup(_("Deleting without trash"));
219                 }
220         else if (options->file_ops.safe_delete_enable)
221                 {
222                 if (!options->file_ops.use_system_trash)
223                         {
224                         gchar *buf2;
225                         if (options->file_ops.safe_delete_folder_maxsize > 0)
226                                 buf2 = g_strdup_printf(_(" (max. %d MiB)"), options->file_ops.safe_delete_folder_maxsize);
227                         else
228                                 buf2 = g_strdup("");
229
230                         buf = g_strdup_printf(_("Using Geeqie Trash bin\n%s"), buf2);
231                         g_free(buf2);
232                         }
233                 else
234                         {
235                         buf = g_strdup(_("Using system Trash bin"));
236                         }
237                 }
238
239         return buf;
240 }
241 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */