1 /* deletecore.cc
2 * This file belongs to Worker, a file manager for UN*X/X11.
3 * Copyright (C) 2013-2021 Ralf Hoffmann.
4 * You can contact me at: ralf@boomerangsworld.de
5 * or http://www.boomerangsworld.de/worker
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
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include "deletecore.hh"
23 #include "worker_locale.h"
24 #include "deleteop.h"
25 #include "nmcopyopdir.hh"
26 #include "deleteorder.hh"
27 #include "simplelist.hh"
28 #include "verzeichnis.hh"
29 #include "aguix/lowlevelfunc.h"
30 #include "aguix/util.h"
31 #include "worker.h"
32
DeleteCore(struct deleteorder * delorder)33 DeleteCore::DeleteCore( struct deleteorder *delorder ) :
34 m_delorder( delorder ),
35 m_cancel( false )
36 {
37 }
38
~DeleteCore()39 DeleteCore::~DeleteCore()
40 {
41 }
42
buildDeleteDatabase()43 int DeleteCore::buildDeleteDatabase()
44 {
45 unsigned long files = 0,
46 dirs = 0,
47 gf = 0,
48 gd = 0;
49
50 DeleteOpWin *dowin = m_delorder->dowin;
51
52 if ( dowin->redraw() != 0 ) m_cancel = true;
53
54 // create the NM_CopyOp_Dir for each dir in dellist
55
56 for ( auto &cbe : m_del_list ) {
57 if ( m_cancel == true ) break;
58
59 bool enter = false;
60
61 if ( cbe.entry().isDir() == true ) {
62 if ( cbe.entry().isLink == false ) enter = true;
63 }
64
65 if ( enter == true ) {
66 // fe is a dir so creating corresponding entry
67 NM_CopyOp_Dir *cod1 = new NM_CopyOp_Dir( &cbe.entry() );
68
69 if ( cod1->user_abort == false ) {
70 // recursive call
71 if ( cod1->createSubDirs( m_delorder, &gf, &gd ) != 0 ) {
72 m_cancel = true;
73 }
74 } else {
75 m_cancel = true;
76 }
77
78 // add the values from this subdir to this dir
79 files += cod1->files;
80 dirs += cod1->dirs;
81
82 cbe.m_cod = cod1;
83 // this is a dir so inc the counter
84 dirs++;
85 gd++;
86
87 dowin->set_files_to_delete( gf );
88 dowin->set_dirs_to_delete( gd );
89 if ( dowin->redraw() != 0 ) m_cancel = true;
90 } else {
91 // is not dir (mostly a file but can also be links ...)
92 files++;
93 gf++;
94 cbe.m_cod = NULL;
95 }
96 }
97
98 dowin->set_files_to_delete( files );
99 dowin->set_dirs_to_delete( dirs );
100
101 return 0;
102 }
103
executeDelete()104 int DeleteCore::executeDelete()
105 {
106 DeleteOpWin *dowin = m_delorder->dowin;
107
108 for ( auto &cbe : m_del_list ) {
109 if ( m_cancel ) break;
110
111 NM_CopyOp_Dir *tcod;
112
113 tcod = cbe.m_cod;
114
115 if ( m_pre_cb ) {
116 m_pre_cb( cbe.entry(), cbe.m_row, cbe.m_cod );
117 }
118
119 nm_delete_t ce1 = NM_DELETE_CANCEL;
120
121 if ( tcod != NULL ) {
122 // determine if the dir is empty or not
123 bool empty;
124 bool skip;
125
126 if ( ( tcod->files + tcod->dirs ) > 0 ) empty = false;
127 else empty = true;
128
129 skip = false;
130
131 // skip if the user doesn't want to delete non-empty dirs
132 if ( ( m_delorder->dirdel == m_delorder->NM_DIRDELETE_NONE ) && ( empty == false ) ) skip = true;
133
134 // if the user doesn't select ALL or NONE and the the dir isn't empty show a request
135 if ( ( m_delorder->dirdel == m_delorder->NM_DIRDELETE_NORMAL ) && ( empty == false ) ) {
136 char *buttonstr, *textstr;
137 int erg;
138
139 textstr = (char*)_allocsafe( strlen( catalog.getLocale( 146 ) ) +
140 strlen( cbe.entry().fullname ) + 1 );
141 sprintf( textstr, catalog.getLocale( 146 ), cbe.entry().fullname );
142 buttonstr = (char*)_allocsafe( strlen( catalog.getLocale( 11 ) ) + 1 +
143 strlen( catalog.getLocale( 287 ) ) + 1 +
144 strlen( catalog.getLocale( 288 ) ) + 1 +
145 strlen( catalog.getLocale( 225 ) ) + 1 +
146 strlen( catalog.getLocale( 8 ) ) + 1 );
147 sprintf( buttonstr, "%s|%s|%s|%s|%s", catalog.getLocale( 11 ),
148 catalog.getLocale( 287 ),
149 catalog.getLocale( 288 ),
150 catalog.getLocale( 225 ),
151 catalog.getLocale( 8 ) );
152 erg = dowin->request( catalog.getLocale( 123 ), textstr, buttonstr );
153 _freesafe( buttonstr );
154 _freesafe( textstr );
155 switch ( erg ) {
156 case 1:
157 m_delorder->dirdel = m_delorder->NM_DIRDELETE_ALL;
158 break;
159 case 2:
160 m_delorder->dirdel = m_delorder->NM_DIRDELETE_NONE;
161 skip = true;
162 break;
163 case 3:
164 skip = true;
165 break;
166 case 4:
167 m_cancel = true;
168 skip = true;
169 break;
170 }
171 }
172 if ( skip == false ) {
173 ce1 = deldir( &cbe.entry(), tcod, m_delorder );
174 if ( ce1 == DeleteCore::NM_DELETE_CANCEL ) {
175 m_cancel = true;
176 } else if ( ce1 == DeleteCore::NM_DELETE_OK ) {
177 Worker::pushCommandLog( catalog.getLocale( 1422 ),
178 cbe.entry().fullname,
179 cbe.entry().fullname );
180 }
181 } else {
182
183 // dir skiped so dec DeleteOpWin counter by the files/dirs skiped
184 dowin->dec_file_counter( tcod->files );
185 dowin->dec_dir_counter( tcod->dirs );
186
187 ce1 = NM_DELETE_SKIP;
188 }
189
190 if ( m_post_cb ) {
191 m_post_cb( cbe.entry(), cbe.m_row,
192 ce1, cbe.m_cod );
193 }
194 } else {
195 if ( dowin != NULL ) dowin->setfilename( cbe.entry().fullname );
196 ce1 = delfile( &cbe.entry(), m_delorder, false );
197 if ( ce1 == DeleteCore::NM_DELETE_CANCEL ) {
198 m_cancel = true;
199 } else if ( ce1 == DeleteCore::NM_DELETE_OK ) {
200 Worker::pushCommandLog( catalog.getLocale( 1422 ),
201 cbe.entry().fullname,
202 cbe.entry().fullname );
203 }
204
205 if ( m_post_cb ) {
206 m_post_cb( cbe.entry(), cbe.m_row,
207 ce1, NULL );
208 }
209 }
210
211 if ( dowin->redraw() != 0 ) m_cancel = true;
212 }
213
214 return 0;
215 }
216
deldir(const FileEntry * fe,NM_CopyOp_Dir * cod,struct deleteorder * delorder)217 DeleteCore::nm_delete_t DeleteCore::deldir( const FileEntry *fe, NM_CopyOp_Dir *cod, struct deleteorder *delorder )
218 {
219 NM_CopyOp_Dir *cod1 = NULL;
220 int id1;
221 bool skip;
222 nm_delete_t ce1;
223 DeleteOpWin *dowin = delorder->dowin;
224 bool delerror;
225
226 skip = false;
227
228 if ( dowin != NULL ) dowin->setfilename( fe->fullname );
229
230 // first del all subdirs
231 // then del all files
232 id1 = cod->subdirs->initEnum();
233 cod1 = (NM_CopyOp_Dir*)cod->subdirs->getFirstElement( id1 );
234 while ( cod1 != NULL ) {
235 ce1 = deldir( cod1->fileentry, cod1, delorder );
236 if ( ce1 == NM_DELETE_OK ) {
237 // success
238 cod->error_counter += cod1->error_counter;
239 } else {
240 cod->error_counter += cod1->error_counter + 1;
241 if ( ce1 == NM_DELETE_CANCEL ) {
242 setCancel( true );
243 break;
244 }
245 }
246 cod1 = (NM_CopyOp_Dir*)cod->subdirs->getNextElement( id1 );
247 }
248 cod->subdirs->closeEnum( id1 );
249
250 // next only if read this dir correctly
251 if ( ( cod->ok == true ) && ( getCancel() == false ) ) {
252 for ( Verzeichnis::verz_it subfe_it1 = cod->verz->begin();
253 subfe_it1 != cod->verz->end();
254 subfe_it1++ ) {
255 FileEntry *subfe = *subfe_it1;
256 if ( strcmp( subfe->name, ".." ) != 0 ) {
257 bool isdir = false;
258 if ( subfe->isDir() == true ) {
259 if ( subfe->isLink == false ) isdir = true;
260 }
261 if ( isdir == false ) {
262 ce1 = delfile( subfe, delorder, false );
263 if ( ce1 == NM_DELETE_OK ) {
264 // success
265 } else {
266 cod->error_counter++;
267 if ( ce1 == NM_DELETE_CANCEL ) {
268 setCancel( true );
269 break;
270 }
271 }
272 }
273 }
274 }
275 }
276
277 delerror = true;
278 if ( getCancel() == false ) {
279 if ( cod->error_counter == 0 ) {
280 ce1 = delfile( fe, delorder, true );
281 if ( ce1 == NM_DELETE_OK ) {
282 // success
283 delerror = false;
284 } else {
285 cod->error_counter++;
286 if ( ce1 == NM_DELETE_CANCEL ) {
287 setCancel( true );
288 }
289 }
290 }
291 }
292 if ( delerror == true ) {
293 char *textstr = (char*)_allocsafe( strlen( catalog.getLocale( 289 ) ) +
294 strlen( fe->fullname ) + 1 );
295 sprintf( textstr, catalog.getLocale( 289 ), fe->fullname );
296 char *buttonstr = (char*)_allocsafe( strlen( catalog.getLocale( 11 ) ) + 1 +
297 strlen( catalog.getLocale( 8 ) ) + 1 );
298 sprintf( buttonstr, "%s|%s", catalog.getLocale( 11 ),
299 catalog.getLocale( 8 ) );
300 int erg = dowin->request( catalog.getLocale( 125 ), textstr, buttonstr );
301 _freesafe( buttonstr );
302 _freesafe( textstr );
303 if ( erg == 1 ) setCancel( true );
304 else skip = true;
305 }
306 if ( getCancel() == true ) return NM_DELETE_CANCEL;
307 else if ( skip == true ) {
308 cod->error_counter++;
309 return NM_DELETE_SKIP;
310 }
311 return NM_DELETE_OK;
312 }
313
delfile(const FileEntry * fe,struct deleteorder * delorder,bool dir)314 DeleteCore::nm_delete_t DeleteCore::delfile( const FileEntry *fe, struct deleteorder *delorder, bool dir )
315 {
316 bool skip;
317 int erg;
318 DeleteOpWin *dowin = delorder->dowin;
319
320 skip = false;
321
322 if ( dir == true ) erg = worker_rmdir( fe->fullname );
323 else erg = worker_unlink( fe->fullname );
324
325 if ( erg != 0 ) {
326 // textstr="Failed to remove this file!";
327 // buttonstr="Ok|Cancel";
328
329 char *textstr, *buttonstr;
330
331 if ( dir == true ) {
332 textstr = (char*)_allocsafe( strlen( catalog.getLocale( 147 ) ) +
333 strlen( fe->fullname ) + 1 );
334 sprintf( textstr, catalog.getLocale( 147 ), fe->fullname );
335 } else {
336 textstr = (char*)_allocsafe( strlen( catalog.getLocale( 286 ) ) +
337 strlen( fe->fullname ) + 1 );
338 sprintf( textstr, catalog.getLocale( 286 ), fe->fullname );
339 }
340 buttonstr = (char*)_allocsafe( strlen( catalog.getLocale( 11 ) ) + 1 +
341 strlen( catalog.getLocale( 8 ) ) + 1 );
342 sprintf( buttonstr, "%s|%s", catalog.getLocale( 11 ),
343 catalog.getLocale( 8 ) );
344 erg = dowin->request( catalog.getLocale( 347 ), textstr, buttonstr );
345 _freesafe( buttonstr );
346 _freesafe( textstr );
347
348 if ( erg == 1 ) setCancel( true );
349 else skip = true;
350 }
351 if ( dowin != NULL ) {
352 if ( dir == true ) {
353 dowin->dir_finished();
354 if ( dowin->redraw() != 0 ) setCancel( true );
355 } else dowin->file_finished();
356 }
357 if ( getCancel() == true ) return NM_DELETE_CANCEL;
358 else if ( skip == true ) return NM_DELETE_SKIP;
359 return NM_DELETE_OK;
360 }
361
setPreDeleteCallback(std::function<void (const FileEntry & fe,int row,const NM_CopyOp_Dir * cod)> cb)362 void DeleteCore::setPreDeleteCallback( std::function< void( const FileEntry &fe, int row, const NM_CopyOp_Dir *cod ) > cb )
363 {
364 m_pre_cb = cb;
365 }
366
setPostDeleteCallback(std::function<void (const FileEntry & fe,int row,nm_delete_t res,const NM_CopyOp_Dir * cod)> cb)367 void DeleteCore::setPostDeleteCallback( std::function< void( const FileEntry &fe, int row,
368 nm_delete_t res, const NM_CopyOp_Dir *cod ) > cb )
369 {
370 m_post_cb = cb;
371 }
372
registerFEToDelete(const FileEntry & fe,int row)373 void DeleteCore::registerFEToDelete( const FileEntry &fe,
374 int row )
375 {
376 m_del_list.push_back( delete_base_entry( fe, row ) );
377 }
378
getCancel() const379 bool DeleteCore::getCancel() const
380 {
381 return m_cancel;
382 }
383
setCancel(bool nv)384 void DeleteCore::setCancel( bool nv )
385 {
386 // disallow clearing the flag
387 if ( nv == true ) {
388 m_cancel = nv;
389 }
390 }
391
delete_base_entry(const FileEntry & fe,int row)392 DeleteCore::delete_base_entry::delete_base_entry( const FileEntry &fe,
393 int row ) :
394 m_row( row ),
395 m_cod( NULL ),
396 m_fe( fe )
397 {
398 }
399
~delete_base_entry()400 DeleteCore::delete_base_entry::~delete_base_entry()
401 {
402 delete m_cod;
403 }
404