Allow to disable trash completely
[geeqie.git] / src / trash.c
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
26 #include "editors.h"
27 #include "filedata.h"
28 #include "ui_fileops.h"
29 #include "ui_misc.h"
30
31
32 /*
33  *--------------------------------------------------------------------------
34  * Safe Delete
35  *--------------------------------------------------------------------------
36  */
37
38 static gint file_util_safe_number(gint64 free_space)
39 {
40         gint n = 0;
41         gint64 total = 0;
42         GList *list;
43         GList *work;
44         gboolean sorted = FALSE;
45         gboolean warned = FALSE;
46         FileData *dir_fd;
47
48         dir_fd = file_data_new_dir(options->file_ops.safe_delete_path);
49         if (!filelist_read(dir_fd, &list, NULL))
50                 {
51                 file_data_unref(dir_fd);
52                 return 0;
53                 }
54         file_data_unref(dir_fd);
55
56         work = list;
57         while (work)
58                 {
59                 FileData *fd;
60                 gint v;
61
62                 fd = work->data;
63                 work = work->next;
64
65                 v = (gint)strtol(fd->name, NULL, 10);
66                 if (v >= n) n = v + 1;
67
68                 total += fd->size;
69                 }
70
71         while (options->file_ops.safe_delete_folder_maxsize > 0 && list &&
72                (free_space < 0 || total + free_space > (gint64)options->file_ops.safe_delete_folder_maxsize * 1048576) )
73                 {
74                 FileData *fd;
75
76                 if (!sorted)
77                         {
78                         list = filelist_sort(list, SORT_NAME, TRUE);
79                         sorted = TRUE;
80                         }
81
82                 fd = list->data;
83                 list = g_list_remove(list, fd);
84
85                 DEBUG_1("expunging from trash for space: %s", fd->name);
86                 if (!unlink_file(fd->path) && !warned)
87                         {
88                         file_util_warning_dialog(_("Delete failed"),
89                                                  _("Unable to remove old file from trash folder"),
90                                                  GTK_STOCK_DIALOG_WARNING, NULL);
91                         warned = TRUE;
92                         }
93                 total -= fd->size;
94                 file_data_unref(fd);
95                 }
96
97         filelist_free(list);
98
99         return n;
100 }
101
102 void file_util_trash_clear(void)
103 {
104         file_util_safe_number(-1);
105 }
106
107 static gchar *file_util_safe_dest(const gchar *path)
108 {
109         gint n;
110         gchar *name;
111         gchar *dest;
112
113         n = file_util_safe_number(filesize(path));
114         name = g_strdup_printf("%06d_%s", n, filename_from_path(path));
115         dest = g_build_filename(options->file_ops.safe_delete_path, name, NULL);
116         g_free(name);
117
118         return dest;
119 }
120
121 static void file_util_safe_del_close_cb(GtkWidget *dialog, gpointer data)
122 {
123         GenericDialog **gd = data;
124
125         *gd = NULL;
126 }
127
128 gboolean file_util_safe_unlink(const gchar *path)
129 {
130         static GenericDialog *gd = NULL;
131         gchar *result = NULL;
132         gboolean success = TRUE;
133
134         if (!isfile(path)) return FALSE;
135
136         if (options->file_ops.no_trash)
137                 {
138                 if (!unlink_file(path))
139                         {
140                         file_util_warning_dialog(_("Delete failed"),
141                                                  _("Unable to remove file"),
142                                                  GTK_STOCK_DIALOG_WARNING, NULL);
143                         success = FALSE;
144                         }
145                 }
146         else if (!options->file_ops.use_system_trash)
147                 {
148                 if (!isdir(options->file_ops.safe_delete_path))
149                         {
150                         DEBUG_1("creating trash: %s", options->file_ops.safe_delete_path);
151                         if (!options->file_ops.safe_delete_path || !mkdir_utf8(options->file_ops.safe_delete_path, 0755))
152                                 {
153                                 result = _("Could not create folder");
154                                 success = FALSE;
155                                 }
156                         }
157
158                 if (success)
159                         {
160                         gchar *dest;
161
162                         dest = file_util_safe_dest(path);
163                         if (dest)
164                                 {
165                                 DEBUG_1("safe deleting %s to %s", path, dest);
166                                 success = move_file(path, dest);
167                                 }
168                         else
169                                 {
170                                 success = FALSE;
171                                 }
172
173                         if (!success && !access_file(path, W_OK))
174                                 {
175                                 result = _("Permission denied");
176                                 }
177                         g_free(dest);
178                         }
179
180                 if (result && !gd)
181                         {
182                         GtkWidget *button;
183                         gchar *buf;
184
185                         buf = g_strdup_printf(_("Unable to access or create the trash folder.\n\"%s\""), options->file_ops.safe_delete_path);
186                         gd = file_util_warning_dialog(result, buf, GTK_STOCK_DIALOG_WARNING, NULL);
187                         g_free(buf);
188                         }
189                 }
190         else
191                 {
192                 GFile *tmp = g_file_new_for_path (path);
193                 g_file_trash(tmp, FALSE, NULL);
194                 g_object_unref(tmp);
195                 }
196
197         return success;
198 }
199
200 gchar *file_util_safe_delete_status(void)
201 {
202         gchar *buf = NULL;
203
204         if (is_valid_editor_command(CMD_DELETE))
205                 {
206                 buf = g_strdup(_("Deletion by external command"));
207                 }
208         else if (options->file_ops.no_trash)
209                 {
210                 buf = g_strdup(_("Deleting without trash"));
211                 }
212         else if (options->file_ops.safe_delete_enable)
213                 {
214                 if (!options->file_ops.use_system_trash)
215                         {
216                         gchar *buf2;
217                         if (options->file_ops.safe_delete_folder_maxsize > 0)
218                                 buf2 = g_strdup_printf(_(" (max. %d MB)"), options->file_ops.safe_delete_folder_maxsize);
219                         else
220                                 buf2 = g_strdup("");
221
222                         buf = g_strdup_printf(_("Using Geeqie Trash bin\n%s"), buf2);
223                         g_free(buf2);
224                         }
225                 else
226                         {
227                         buf = g_strdup(_("Using system Trash bin"));
228                         }
229                 }
230
231         return buf;
232 }
233 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */