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