1 /* copycore.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 "copycore.hh"
23 #include "worker_locale.h"
24 #include "copyopwin.hh"
25 #include "nmcopyopdir.hh"
26 #include "datei.h"
27 #include "copyorder.hh"
28 #include "simplelist.hh"
29 #include "verzeichnis.hh"
30 #include "aguix/lowlevelfunc.h"
31 #include "aguix/util.h"
32 #include <chrono>
33 #include <ratio>
34 #include "nwc_path.hh"
35 #include "nwc_os.hh"
36 #include "worker.h"
37
CopyCore(std::shared_ptr<struct copyorder> co)38 CopyCore::CopyCore( std::shared_ptr< struct copyorder > co ) :
39 m_copyorder( co ),
40 m_cancel( false ),
41 m_bytes_to_copy( 0 ),
42 m_finished( false ),
43 m_ask_to_cancel( false )
44 {
45 buf = _allocsafe( BUFSIZE );
46 }
47
~CopyCore()48 CopyCore::~CopyCore()
49 {
50 _freesafe( buf );
51 }
52
getModeWithEnsureOption(const mode_t orig_mode,const struct copyorder & co)53 static mode_t getModeWithEnsureOption( const mode_t orig_mode,
54 const struct copyorder &co )
55 {
56 mode_t res = orig_mode;
57
58 if ( co.ensure_file_permissions() == CopyParams::ENSURE_USER_RW_PERMISSION ) {
59 res |= S_IRUSR | S_IWUSR;
60 } else if ( co.ensure_file_permissions() == CopyParams::ENSURE_USER_RW_GROUP_R_PERMISSION ) {
61 res |= S_IRUSR | S_IWUSR | S_IRGRP;
62 } else if ( co.ensure_file_permissions() == CopyParams::ENSURE_USER_RW_ALL_R_PERMISSION ) {
63 res |= S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
64 }
65
66 return res;
67 }
68
getNewName4Dir(const FileEntry * oldfe,const char * dest,char ** newname_return,bool acceptrename)69 CopyCore::nm_newname_t CopyCore::getNewName4Dir( const FileEntry *oldfe, const char *dest,
70 char **newname_return, bool acceptrename )
71 {
72 char *oldname=oldfe->name;
73 char *newname=dupstring(oldname);
74 bool nameok=false,skip=false,cancel=false;
75 char *buttonstr,*textstr,*newdest;
76 int erg;
77 Datei::d_fe_t se,lse;
78 int round=1;
79 nm_newname_t returnvalue=NM_NEWNAME_CANCEL;
80 bool trydel,do_rename,strongdirs;
81 char *title;
82
83 if ( m_copyorder->cowin != NULL ) m_copyorder->cowin->stoptimer();
84
85 title = (char*)_allocsafe( strlen( catalog.getLocale( 500 ) ) + strlen( oldfe->fullname ) + 1 );
86 sprintf( title, catalog.getLocale( 500 ), oldfe->fullname );
87
88 do_rename=false;
89 if(m_copyorder->do_rename==false) do_rename=false;
90 else if(acceptrename==true) do_rename=true;
91
92 strongdirs=false;
93
94 do {
95 if(!((round==1)&&(do_rename==false))) {
96 buttonstr=(char*)_allocsafe(strlen(catalog.getLocale(11))+1+
97 strlen(catalog.getLocale(225))+1+
98 strlen(catalog.getLocale(8))+1);
99 sprintf(buttonstr,"%s|%s|%s",catalog.getLocale(11),
100 catalog.getLocale(225),
101 catalog.getLocale(8));
102 textstr=(char*)_allocsafe(strlen(catalog.getLocale(148))+strlen(oldname)+1);
103 sprintf(textstr,catalog.getLocale(148),oldname);
104
105 std::string return_str;
106
107 erg = m_copyorder->cowin->string_request( catalog.getLocale( 149 ),
108 textstr,
109 newname,
110 buttonstr,
111 return_str,
112 Requester::REQUEST_SELECTALL );
113 _freesafe(buttonstr);
114 _freesafe(textstr);
115 if ( ! return_str.empty() ) {
116 _freesafe(newname);
117 newname = dupstring( return_str.c_str() );
118 }
119 if(erg==1) {
120 skip=true;
121 returnvalue=NM_NEWNAME_SKIP;
122 break;
123 } else if(erg==2) {
124 cancel=true;
125 returnvalue=NM_NEWNAME_CANCEL;
126 break;
127 }
128 }
129
130 if ( strlen( newname ) < 1 ) {
131 // empty name->request
132 round++; // not needed since empty names should only come from user input
133 // but perhaps there is (will be) a OS which allows empty names
134 continue;
135 }
136
137 newdest=(char*)_allocsafe(strlen(dest)+1+strlen(newname)+1);
138 strcpy(newdest,dest);
139 if(strlen(dest)>1) strcat(newdest,"/");
140 strcat(newdest,newname);
141 se=Datei::fileExistsExt(newdest);
142 lse=Datei::lfileExistsExt(newdest);
143
144 switch(lse) {
145 case Datei::D_FE_DIR:
146 if(strongdirs==true) {
147 textstr = (char*)_allocsafe( strlen( catalog.getLocale( 190 ) ) + strlen( newdest ) + 1 );
148 sprintf( textstr, catalog.getLocale( 190 ), newdest );
149
150 buttonstr=(char*)_allocsafe(strlen(catalog.getLocale(230))+1+
151 strlen(catalog.getLocale(273))+1+
152 strlen(catalog.getLocale(225))+1+
153 strlen(catalog.getLocale(8))+1);
154 sprintf(buttonstr,"%s|%s|%s|%s",catalog.getLocale(230),
155 catalog.getLocale(273),
156 catalog.getLocale(225),
157 catalog.getLocale(8));
158
159 erg = m_copyorder->cowin->request( title/*catalog.getLocale(123)*/, textstr, buttonstr );
160 _freesafe(buttonstr);
161 _freesafe(textstr);
162 if(erg==1) {
163 nameok=true;
164 returnvalue=NM_NEWNAME_USE;
165 } else if(erg==2) {
166 skip=true;
167 returnvalue=NM_NEWNAME_SKIP;
168 } else if(erg==3) {
169 cancel=true;
170 returnvalue=NM_NEWNAME_CANCEL;
171 }
172 } else {
173 // just use the dir
174 nameok=true;
175 returnvalue=NM_NEWNAME_USE;
176 }
177 break;
178 case Datei::D_FE_LINK:
179 case Datei::D_FE_FILE:
180 if((lse==Datei::D_FE_LINK)&&(se==Datei::D_FE_DIR)) {
181 // Symlink with dir as destination
182 if(strongdirs==true) {
183 // textstr="There is already a symlink called %s, which points to a dir|You can use this link or delete it to|create a real directory";
184 // buttonstr="Enter new name|Use this dir|Delete link|Skip|Cancel";
185
186 textstr = (char*)_allocsafe( strlen( catalog.getLocale( 275 ) ) + strlen( newdest ) + 1 );
187 sprintf( textstr, catalog.getLocale( 275 ), newdest );
188 buttonstr=(char*)_allocsafe(strlen(catalog.getLocale(230))+1+
189 strlen(catalog.getLocale(273))+1+
190 strlen(catalog.getLocale(274))+1+
191 strlen(catalog.getLocale(225))+1+
192 strlen(catalog.getLocale(8))+1);
193 sprintf(buttonstr,"%s|%s|%s|%s|%s",catalog.getLocale(230),
194 catalog.getLocale(273),
195 catalog.getLocale(274),
196 catalog.getLocale(225),
197 catalog.getLocale(8));
198
199 erg = m_copyorder->cowin->request( title/*catalog.getLocale(123)*/, textstr, buttonstr );
200 _freesafe(buttonstr);
201 _freesafe(textstr);
202 switch(erg) {
203 case 1:
204 nameok=true;
205 returnvalue=NM_NEWNAME_USE;
206 break;
207 case 2:
208 // try to remove the link
209 // if success set nameok to true
210 // in case of failure show a request and repeat the whole
211 if ( worker_unlink( newdest ) == 0 ) {
212 nameok=true;
213 returnvalue=NM_NEWNAME_OK;
214 } else {
215 // textstr="Failed to remove this file|Please enter new name!";
216 // buttonstr="Ok|Skip|Cancel";
217
218 textstr = dupstring( catalog.getLocale(276) );
219 buttonstr=(char*)_allocsafe(strlen(catalog.getLocale(11))+1+
220 strlen(catalog.getLocale(225))+1+
221 strlen(catalog.getLocale(8))+1);
222 sprintf(buttonstr,"%s|%s|%s",catalog.getLocale(11),
223 catalog.getLocale(225),
224 catalog.getLocale(8));
225
226 erg = m_copyorder->cowin->request( catalog.getLocale( 347 ), textstr, buttonstr );
227 _freesafe(buttonstr);
228 _freesafe( textstr );
229 if(erg==1) {
230 skip=true;
231 returnvalue=NM_NEWNAME_SKIP;
232 } else if(erg==2) {
233 cancel=true;
234 returnvalue=NM_NEWNAME_CANCEL;
235 }
236 }
237 break;
238 case 3:
239 skip=true;
240 returnvalue=NM_NEWNAME_SKIP;
241 break;
242 case 4:
243 cancel=true;
244 returnvalue=NM_NEWNAME_CANCEL;
245 break;
246 }
247 } else {
248 // just use the link to the dir
249 nameok=true;
250 returnvalue=NM_NEWNAME_USE;
251 }
252 } else {
253 trydel=false;
254 if((do_rename==false)&&(m_copyorder->overwrite==m_copyorder->COPY_OVERWRITE_ALWAYS)) {
255 trydel=true;
256 } else if((do_rename==false)&&(m_copyorder->overwrite==m_copyorder->COPY_OVERWRITE_NEVER)) {
257 // skip
258 skip=true;
259 returnvalue=NM_NEWNAME_SKIP;
260 } else {
261 if(lse==Datei::D_FE_LINK) {
262 // textstr="There is already a link named %s";
263 // buttonstr="Enter new name|Delete link|Skip|Cancel";
264
265 textstr = (char*)_allocsafe( strlen( catalog.getLocale( 278 ) ) + strlen( newdest ) + 1 );
266 sprintf( textstr, catalog.getLocale( 278 ), newdest );
267 buttonstr=(char*)_allocsafe(strlen(catalog.getLocale(230))+1+
268 strlen(catalog.getLocale(274))+1+
269 strlen(catalog.getLocale(225))+1+
270 strlen(catalog.getLocale(8))+1);
271 sprintf(buttonstr,"%s|%s|%s|%s",catalog.getLocale(230),
272 catalog.getLocale(274),
273 catalog.getLocale(225),
274 catalog.getLocale(8));
275 } else {
276 // textstr="There is already a file named %s";
277 // buttonstr="Enter new name|Delete file|Skip|Cancel";
278
279 textstr = (char*)_allocsafe( strlen( catalog.getLocale( 279 ) ) + strlen( newdest ) + 1 );
280 sprintf( textstr, catalog.getLocale( 279 ), newdest );
281 buttonstr=(char*)_allocsafe(strlen(catalog.getLocale(230))+1+
282 strlen(catalog.getLocale(277))+1+
283 strlen(catalog.getLocale(225))+1+
284 strlen(catalog.getLocale(8))+1);
285 sprintf(buttonstr,"%s|%s|%s|%s",catalog.getLocale(230),
286 catalog.getLocale(277),
287 catalog.getLocale(225),
288 catalog.getLocale(8));
289 }
290 erg = m_copyorder->cowin->request( title/*catalog.getLocale(123)*/, textstr, buttonstr );
291 _freesafe(buttonstr);
292 _freesafe(textstr);
293 switch(erg) {
294 case 1:
295 trydel=true;
296 break;
297 case 2:
298 skip=true;
299 returnvalue=NM_NEWNAME_SKIP;
300 break;
301 case 3:
302 cancel=true;
303 returnvalue=NM_NEWNAME_CANCEL;
304 break;
305 }
306 }
307 if(trydel==true) {
308 if ( worker_unlink( newdest ) == 0 ) {
309 nameok=true;
310 returnvalue=NM_NEWNAME_OK;
311 } else {
312 // textstr="Failed to remove this file|Please enter new name!";
313 // buttonstr="Ok|Skip|Cancel";
314
315 textstr = dupstring( catalog.getLocale(276) );
316 buttonstr=(char*)_allocsafe(strlen(catalog.getLocale(11))+1+
317 strlen(catalog.getLocale(225))+1+
318 strlen(catalog.getLocale(8))+1);
319 sprintf(buttonstr,"%s|%s|%s",catalog.getLocale(11),
320 catalog.getLocale(225),
321 catalog.getLocale(8));
322
323 erg = m_copyorder->cowin->request( catalog.getLocale( 347 ), textstr, buttonstr );
324 _freesafe(buttonstr);
325 _freesafe( textstr );
326 if(erg==1) {
327 skip=true;
328 returnvalue=NM_NEWNAME_SKIP;
329 } else if(erg==2) {
330 cancel=true;
331 returnvalue=NM_NEWNAME_CANCEL;
332 }
333 }
334 }
335 }
336 break;
337 default:
338 nameok=true;
339 returnvalue=NM_NEWNAME_OK;
340 break;
341 }
342 _freesafe(newdest);
343 round++;
344 } while((nameok==false)&&(skip==false)&&(cancel==false));
345 if((skip==true)||(cancel==true)) {
346 _freesafe(newname);
347 *newname_return=NULL;
348 } else {
349 *newname_return=newname;
350 }
351 _freesafe( title );
352
353 if ( m_copyorder->cowin != NULL ) m_copyorder->cowin->conttimer();
354
355 return returnvalue;
356 }
357
getNewName4File(const FileEntry * oldfe,const char * dest,char ** newname_return,bool acceptrename)358 CopyCore::nm_newname_t CopyCore::getNewName4File( const FileEntry *oldfe, const char *dest,
359 char **newname_return, bool acceptrename )
360 {
361 char *oldname=oldfe->name;
362 char *newname=dupstring(oldname);
363 bool nameok=false,skip=false,cancel=false;
364 char *buttonstr,*textstr,*newdest;
365 int erg;
366 Datei::d_fe_t lse;
367 int round=1;
368 nm_newname_t returnvalue=NM_NEWNAME_CANCEL;
369 bool do_rename,trydel;
370 char *extrastr,*tstr,*newtime,*oldtime;
371 int newsizelen,oldsizelen,maxsizelen;
372 char *title;
373 time_t tvar;
374 std::string newsize, oldsize;
375
376 if ( m_copyorder->cowin != NULL ) m_copyorder->cowin->stoptimer();
377
378 title = (char*)_allocsafe( strlen( catalog.getLocale( 116 ) ) + strlen( oldfe->fullname ) + 1 );
379 sprintf( title, catalog.getLocale( 116 ), oldfe->fullname );
380
381 do_rename=false;
382 if(m_copyorder->do_rename==false) do_rename=false;
383 else if(acceptrename==true) do_rename=true;
384
385 do {
386 if(!((round==1)&&(do_rename==false))) {
387 // buttonstr="Ok|Skip|Cancel";
388 // textstr="Enter new name for ...";
389 buttonstr=(char*)_allocsafe(strlen(catalog.getLocale(11))+1+
390 strlen(catalog.getLocale(225))+1+
391 strlen(catalog.getLocale(8))+1);
392 sprintf(buttonstr,"%s|%s|%s",catalog.getLocale(11),
393 catalog.getLocale(225),
394 catalog.getLocale(8));
395 textstr=(char*)_allocsafe(strlen(catalog.getLocale(148))+strlen(oldname)+1);
396 sprintf(textstr,catalog.getLocale(148),oldname);
397
398 std::string return_str;
399
400 erg = m_copyorder->cowin->string_request( catalog.getLocale( 149 ),
401 textstr,
402 newname,
403 buttonstr,
404 return_str,
405 Requester::REQUEST_SELECTALL );
406 _freesafe(buttonstr);
407 _freesafe(textstr);
408 if ( ! return_str.empty() ) {
409 _freesafe(newname);
410 newname = dupstring( return_str.c_str() );
411 }
412 if(erg==1) {
413 skip=true;
414 returnvalue=NM_NEWNAME_SKIP;
415 break;
416 } else if(erg==2) {
417 cancel=true;
418 returnvalue=NM_NEWNAME_CANCEL;
419 break;
420 }
421 }
422
423 if ( strlen( newname ) < 1 ) {
424 // empty name->request
425 round++; // not needed since empty names should only come from user input
426 // but perhaps there is (will be) a OS which allows empty names
427 continue;
428 }
429
430 newdest=(char*)_allocsafe(strlen(dest)+1+strlen(newname)+1);
431 strcpy(newdest,dest);
432 if(strlen(dest)>1) strcat(newdest,"/");
433 strcat(newdest,newname);
434 lse=Datei::lfileExistsExt(newdest);
435
436 switch(lse) {
437 case Datei::D_FE_DIR:
438 // textstr="there is already a dir called %s";
439 // buttonstr="Enter new name|Skip|Cancel";
440
441 textstr = (char*)_allocsafe( strlen( catalog.getLocale( 190 ) ) + strlen( newdest ) + 1 );
442 sprintf( textstr, catalog.getLocale( 190 ), newdest );
443
444 buttonstr=(char*)_allocsafe(strlen(catalog.getLocale(230))+1+
445 strlen(catalog.getLocale(225))+1+
446 strlen(catalog.getLocale(8))+1);
447 sprintf(buttonstr,"%s|%s|%s",catalog.getLocale(230),
448 catalog.getLocale(225),
449 catalog.getLocale(8));
450
451 erg = m_copyorder->cowin->request( title/*catalog.getLocale(123)*/, textstr, buttonstr );
452 _freesafe(buttonstr);
453 _freesafe(textstr);
454 if(erg==1) {
455 skip=true;
456 returnvalue=NM_NEWNAME_SKIP;
457 } else if(erg==2) {
458 cancel=true;
459 returnvalue=NM_NEWNAME_CANCEL;
460 }
461 break;
462 case Datei::D_FE_LINK:
463 trydel=false;
464 if((do_rename==false)&&(m_copyorder->overwrite==m_copyorder->COPY_OVERWRITE_ALWAYS)) {
465 trydel=true;
466 } else if((do_rename==false)&&(m_copyorder->overwrite==m_copyorder->COPY_OVERWRITE_NEVER)) {
467 // skip
468 skip=true;
469 returnvalue=NM_NEWNAME_SKIP;
470 } else {
471 // textstr="there is already a link named %s";
472 // buttonstr="Enter new name|Delete link|Skip|Cancel";
473
474 textstr = (char*)_allocsafe( strlen( catalog.getLocale( 278 ) ) + strlen( newdest ) + 1 );
475 sprintf( textstr, catalog.getLocale( 278 ), newdest );
476 buttonstr=(char*)_allocsafe(strlen(catalog.getLocale(230))+1+
477 strlen(catalog.getLocale(274))+1+
478 strlen(catalog.getLocale(225))+1+
479 strlen(catalog.getLocale(8))+1);
480 sprintf(buttonstr,"%s|%s|%s|%s",catalog.getLocale(230),
481 catalog.getLocale(274),
482 catalog.getLocale(225),
483 catalog.getLocale(8));
484
485 erg = m_copyorder->cowin->request( title/*catalog.getLocale(123)*/, textstr, buttonstr );
486 _freesafe(buttonstr);
487 _freesafe(textstr);
488 switch(erg) {
489 case 1:
490 trydel=true;
491 break;
492 case 2:
493 skip=true;
494 returnvalue=NM_NEWNAME_SKIP;
495 break;
496 case 3:
497 cancel=true;
498 returnvalue=NM_NEWNAME_CANCEL;
499 break;
500 }
501 }
502 if(trydel==true) {
503 if ( worker_unlink( newdest ) == 0 ) {
504 nameok=true;
505 returnvalue=NM_NEWNAME_OK;
506 } else {
507 // textstr="Failed to remove this file|Please enter new name!";
508 // buttonstr="Ok|Skip|Cancel";
509
510 textstr = dupstring( catalog.getLocale(276) );
511 buttonstr=(char*)_allocsafe(strlen(catalog.getLocale(11))+1+
512 strlen(catalog.getLocale(225))+1+
513 strlen(catalog.getLocale(8))+1);
514 sprintf(buttonstr,"%s|%s|%s",catalog.getLocale(11),
515 catalog.getLocale(225),
516 catalog.getLocale(8));
517
518 erg = m_copyorder->cowin->request( catalog.getLocale( 347 ), textstr, buttonstr );
519 _freesafe(buttonstr);
520 _freesafe( textstr );
521 if(erg==1) {
522 skip=true;
523 returnvalue=NM_NEWNAME_SKIP;
524 } else if(erg==2) {
525 cancel=true;
526 returnvalue=NM_NEWNAME_CANCEL;
527 }
528 }
529 }
530 break;
531 case Datei::D_FE_FILE:
532 if((do_rename==false)&&(m_copyorder->overwrite==m_copyorder->COPY_OVERWRITE_ALWAYS)) {
533 nameok=true;
534 returnvalue=NM_NEWNAME_OVERWRITE;
535 } else if((do_rename==false)&&(m_copyorder->overwrite==m_copyorder->COPY_OVERWRITE_NEVER)) {
536 skip=true;
537 returnvalue=NM_NEWNAME_SKIP;
538 } else {
539 FileEntry *newfe=new FileEntry();
540 if(newfe->name!=NULL) _freesafe(newfe->name);
541 if(newfe->fullname!=NULL) _freesafe(newfe->fullname);
542 newfe->name=dupstring(newname);
543 newfe->fullname=dupstring(newdest);
544 newfe->readInfos();
545
546 MakeLong2NiceStr( newfe->size(), newsize );
547 MakeLong2NiceStr( oldfe->size(), oldsize );
548 oldsizelen = oldsize.length();
549 newsizelen = newsize.length();
550 maxsizelen = ( newsizelen > oldsizelen ) ? newsizelen : oldsizelen;
551 if ( maxsizelen > newsizelen )
552 newsize.insert( newsize.begin(), maxsizelen - newsizelen, ' ' );
553 if ( maxsizelen > oldsizelen )
554 oldsize.insert( oldsize.begin(), maxsizelen - oldsizelen, ' ' );
555
556 tvar = newfe->lastmod();
557 newtime = dupstring( ctime( &( tvar ) ) );
558 tvar = oldfe->lastmod();
559 oldtime = dupstring( ctime( &( tvar ) ) );
560 newtime[strlen(newtime)-1]='\0'; // remove return
561 oldtime[strlen(oldtime)-1]='\0'; // remove return
562
563 extrastr=(char*)_allocsafe(strlen(catalog.getLocale(137))+newsize.length()+oldsize.length()+
564 strlen(newtime)+strlen(oldtime)+1);
565 sprintf(extrastr,catalog.getLocale(137),newsize.c_str(),oldsize.c_str(),newtime,oldtime);
566
567 _freesafe(newtime);
568 _freesafe(oldtime);
569 delete newfe;
570 // textstr="There is already a file named %s";
571 // buttonstr="Enter new name|Overwrite|Overwrite all|Overwrite none|Skip|Cancel";
572
573 textstr = (char*)_allocsafe( strlen( catalog.getLocale( 279 ) ) + strlen( newdest ) + 1 );
574 sprintf( textstr, catalog.getLocale( 279 ), newdest );
575
576 tstr=catstring(textstr,"|");
577 _freesafe(textstr);
578 textstr=catstring(tstr,extrastr);
579 _freesafe(tstr);
580 _freesafe(extrastr);
581
582 buttonstr=(char*)_allocsafe(strlen(catalog.getLocale(230))+1+
583 strlen(catalog.getLocale(280))+1+
584 strlen(catalog.getLocale(135))+1+
585 strlen(catalog.getLocale(136))+1+
586 strlen(catalog.getLocale(225))+1+
587 strlen(catalog.getLocale(8))+1);
588 sprintf(buttonstr,"%s|%s|%s|%s|%s|%s",catalog.getLocale(230),
589 catalog.getLocale(280),
590 catalog.getLocale(135),
591 catalog.getLocale(136),
592 catalog.getLocale(225),
593 catalog.getLocale(8));
594
595 erg = m_copyorder->cowin->request( title/*catalog.getLocale(123)*/, textstr, buttonstr );
596 _freesafe(buttonstr);
597 _freesafe(textstr);
598 switch(erg) {
599 case 1:
600 nameok=true;
601 returnvalue=NM_NEWNAME_OVERWRITE;
602 break;
603 case 2:
604 nameok=true;
605 returnvalue=NM_NEWNAME_OVERWRITE;
606 m_copyorder->overwrite=m_copyorder->COPY_OVERWRITE_ALWAYS;
607 break;
608 case 3:
609 skip=true;
610 returnvalue=NM_NEWNAME_SKIP;
611 m_copyorder->overwrite=m_copyorder->COPY_OVERWRITE_NEVER;
612 break;
613 case 4:
614 skip=true;
615 returnvalue=NM_NEWNAME_SKIP;
616 break;
617 case 5:
618 cancel=true;
619 returnvalue=NM_NEWNAME_CANCEL;
620 break;
621 }
622 }
623 break;
624 default:
625 nameok=true;
626 returnvalue=NM_NEWNAME_OK;
627 break;
628 }
629 _freesafe(newdest);
630 round++;
631 } while((nameok==false)&&(skip==false)&&(cancel==false));
632 if((skip==true)||(cancel==true)) {
633 _freesafe(newname);
634 *newname_return=NULL;
635 } else {
636 *newname_return=newname;
637 }
638 _freesafe( title );
639
640 if ( m_copyorder->cowin != NULL ) m_copyorder->cowin->conttimer();
641
642 return returnvalue;
643 }
644
645 CopyCore::nm_copy_t
copydir(const FileEntry * fe,NM_CopyOp_Dir * cod,bool acceptrename,const char * destdir,std::string * effective_target_fullname)646 CopyCore::copydir( const FileEntry *fe, NM_CopyOp_Dir *cod, bool acceptrename, const char *destdir,
647 std::string *effective_target_fullname )
648 {
649 NM_CopyOp_Dir *cod1 = NULL;
650 bool nameok,createdir;
651 nm_newname_t e1;
652 char *destsubdir;
653 Datei::d_fe_t de1;
654 char *newname=NULL;
655 int id1;
656 FileEntry *subfe;
657 bool isdir,skip;
658 char *buttonstr,*textstr;
659 int erg;
660 CopyOpWin *cowin=m_copyorder->cowin;
661 bool docopy,failedmove=false;
662 struct utimbuf utb;
663 bool corrupt_entries_skipped = false;
664
665 skip = false;
666 if ( cowin != NULL ) {
667 // call newfile without destination so the user
668 // can see the filename in the copyopwin when he will
669 // be asked for the new name
670 cowin->newfile( fe->name, "" );
671 }
672
673 if ( m_cancel == false ) {
674 e1=getNewName4Dir(fe,destdir,&newname,acceptrename);
675 if((e1==NM_NEWNAME_OK)||(e1==NM_NEWNAME_USE)) {
676 // build new name
677 destsubdir=(char*)_allocsafe(strlen(destdir)+1+strlen(newname)+1);
678 strcpy(destsubdir,destdir);
679 if(strlen(destsubdir)>1) {
680 if ( destsubdir[strlen(destsubdir) - 1] != '/' ) {
681 strcat( destsubdir, "/" );
682 }
683 }
684 strcat(destsubdir,newname);
685
686 nameok=false;
687 createdir=true;
688 if(e1==NM_NEWNAME_USE) {
689 // there is already such dir (or a symlink to a dir) -> use it
690 nameok=true;
691 createdir=false;
692 } else if(e1==NM_NEWNAME_OK) {
693 // check for fileexists (should not)
694 // if nethertheless then skip this dir because the rename-func wasn't able to remove it
695 de1=Datei::lfileExistsExt(destsubdir);
696 if(de1==Datei::D_FE_NOFILE) {
697 // everything is ok
698 nameok=true;
699 } else if(de1==Datei::D_FE_DIR) {
700 // dest is a dir
701 // should not happend but ok
702 nameok=true;
703 createdir=false;
704 e1=NM_NEWNAME_USE; // for moving it's important to set this, so it doesn't try to
705 // move
706 }
707 }
708 if(nameok==true) {
709 docopy=true;
710 failedmove=false;
711 if(m_copyorder->move==true) {
712 if(e1==NM_NEWNAME_USE) {
713 // because of using the destination dir
714 // we need to do as failed rename
715 failedmove=true;
716 } else {
717 if ( m_copyorder->adjust_relative_symlinks != m_copyorder->COPY_ADJUST_SYMLINK_NEVER ) {
718 // skip trying to rename dir so that we can handle symlinks within the dir
719
720 // assume that rename has failed so the source
721 // dir is removed if copying was successful
722 failedmove = true;
723 } else if ( worker_rename( fe->fullname, destsubdir ) == 0 ) {
724 // success
725 docopy=false;
726 } else {
727 // failure
728 failedmove=true;
729 }
730 }
731 }
732
733 if(docopy==true) {
734 if(cowin!=NULL) cowin->newfile(fe->name,destsubdir);
735 if(createdir==true) {
736 if ( worker_mkdir( destsubdir, 0700 ) != 0 ) {
737 // failed to create dir -> skip
738 // textstr="Failed to create dir|I will skip this dir!";
739 // buttonstr="Ok|Cancel";
740
741 if(cowin!=NULL) cowin->stoptimer();
742 textstr=(char*)_allocsafe(strlen(catalog.getLocale(126))+strlen(destsubdir)+1);
743 sprintf(textstr,catalog.getLocale(126),destsubdir);
744 buttonstr=(char*)_allocsafe(strlen(catalog.getLocale(11))+1+
745 strlen(catalog.getLocale(8))+1);
746 sprintf(buttonstr,"%s|%s",catalog.getLocale(11),
747 catalog.getLocale(8));
748 erg = m_copyorder->cowin->request( catalog.getLocale( 347 ), textstr, buttonstr );
749 _freesafe(buttonstr);
750 _freesafe(textstr);
751 if(erg==1) m_cancel=true;
752 nameok=false;
753 if(cowin!=NULL) cowin->conttimer();
754 }
755 }
756 if(nameok==true) {
757 // first copy all subdirs
758 // then copy all files
759 id1=cod->subdirs->initEnum();
760 cod1=(NM_CopyOp_Dir*)cod->subdirs->getFirstElement(id1);
761 while(cod1!=NULL) {
762 nm_copy_t ce1;
763 ce1=copydir(cod1->fileentry,cod1,false,destsubdir, NULL);
764 if((ce1==NM_COPY_OK)||(ce1==NM_COPY_NEED_DELETE)) {
765 // success
766 cod->error_counter+=cod1->error_counter;
767 } else {
768 cod->error_counter+=cod1->error_counter+1;
769 if(ce1==NM_COPY_CANCEL) {
770 m_cancel=true;
771 break;
772 }
773 }
774 cod1=(NM_CopyOp_Dir*)cod->subdirs->getNextElement(id1);
775 }
776 cod->subdirs->closeEnum(id1);
777
778 // next only if read this dir correctly
779 if((cod->ok==true)&&(m_cancel==false)) {
780 for ( Verzeichnis::verz_it subfe_it1 = cod->verz->begin();
781 subfe_it1 != cod->verz->end() && m_cancel == false;
782 subfe_it1++ ) {
783
784 checkAskToCancel();
785
786 subfe = *subfe_it1;
787
788 if ( subfe->isCorrupt == true && subfe->isLink == false ) {
789 if ( cowin != NULL ) cowin->stoptimer();
790
791 std::string text = AGUIXUtils::formatStringToString( catalog.getLocale( 909 ),
792 subfe->fullname );
793 std::string button = std::string( catalog.getLocale( 225 ) ) + "|" + catalog.getLocale( 8 );
794 erg = m_copyorder->cowin->request( catalog.getLocale( 347 ), text.c_str(), button.c_str() );
795 if ( erg == 0 ) {
796 } else {
797 m_cancel = true;
798 }
799
800 if ( cowin != NULL ) cowin->conttimer();
801
802 corrupt_entries_skipped = true;
803 continue;
804 }
805
806 if(strcmp(subfe->name,"..")!=0) {
807 isdir=false;
808 if(subfe->isDir()==true) {
809 if(subfe->isLink==false) isdir=true;
810 else if(m_copyorder->follow_symlinks==true) isdir=true;
811 }
812 if(isdir==false) {
813 nm_copy_t cf_res;
814 cf_res=copyfile(subfe,false,destsubdir, NULL);
815 if((cf_res==NM_COPY_OK)||(cf_res==NM_COPY_NEED_DELETE)) {
816 // success
817 } else {
818 cod->error_counter++;
819 if(cf_res==NM_COPY_CANCEL) {
820 m_cancel=true;
821 break;
822 }
823 }
824 }
825 }
826 }
827 }
828 // finally change the permissions of the dir
829 if((createdir==true)&&(m_copyorder->preserve_attr==true)) {
830 // fe is a dir so if it is a link it is not corrupt
831 mode_t m = ( fe->isLink == true ) ? fe->dmode() : fe->mode();
832 m = getModeWithEnsureOption( m, *m_copyorder );
833
834 int res = worker_chown( destsubdir, ( fe->isLink == true ) ? fe->duserid() : fe->userid(),
835 ( fe->isLink == true ) ? fe->dgroupid() : fe->groupid() );
836 (void)res; // ignore result for now
837 worker_chmod( destsubdir, m );
838 utb.actime = ( fe->isLink == true ) ? fe->dlastaccess() : fe->lastaccess();
839 utb.modtime = ( fe->isLink == true ) ? fe->dlastmod() : fe->lastmod();
840 worker_utime(destsubdir,&utb);
841 }
842 } else skip=true;
843 }
844 } else skip=true;
845
846 if ( effective_target_fullname != NULL ) {
847 *effective_target_fullname = destsubdir;
848 }
849
850 _freesafe(destsubdir);
851 } else {
852 switch(e1) {
853 case NM_NEWNAME_CANCEL:
854 m_cancel=true;
855 default:
856 skip=true;
857 break;
858 }
859 }
860 }
861 if((skip==true)&&(cowin!=NULL)) {
862 // dir skiped so dec CopyOpWin counter by the files/dirs skiped
863 cowin->dec_file_counter(cod->files);
864 cowin->dec_dir_counter(cod->dirs);
865 cowin->dec_byte_counter(cod->bytes);
866 }
867
868 if ( corrupt_entries_skipped == true ) skip = true;
869
870 if(cowin!=NULL) {
871 cowin->dir_finished();
872 }
873 if(newname!=NULL) _freesafe(newname);
874 if(m_cancel==true) return NM_COPY_CANCEL;
875 else if(skip==true) {
876 cod->error_counter++;
877 return NM_COPY_SKIP;
878 }
879 if(m_copyorder->move==true) {
880 if((cod->error_counter==0)&&(failedmove==true)) {
881 // put fe in list
882
883 // Man koennte das FE auch also Kopie benutzen
884 // man muesste nur den Vergleich beim spaeteren Loeschen anpassen
885 pushForPostDelete( fe );
886 return NM_COPY_NEED_DELETE;
887 }
888 }
889 return NM_COPY_OK;
890 }
891
892 CopyCore::nm_copy_t
copyfile(const FileEntry * fe,bool acceptrename,const char * destdir,std::string * effective_target_fullname)893 CopyCore::copyfile( const FileEntry *fe, bool acceptrename, const char *destdir, std::string *effective_target_fullname )
894 {
895 bool nameok;
896 nm_newname_t e1;
897 char *newfullname;
898 Datei::d_fe_t de1;
899 char *newname=NULL;
900 bool useregcopy, skip;
901 int erg;
902 CopyOpWin *cowin=m_copyorder->cowin;
903 bool docopy,failedmove=false,opok=false;
904 struct utimbuf utb;
905 const char *myerrstr;
906 loff_t bytesToCopy;
907 mode_t modeCheck;
908 bool useLinkDest;
909 std::string text, button;
910
911 if ( fe->isLink == true && fe->isCorrupt == false && m_copyorder->follow_symlinks ) {
912 bytesToCopy = fe->dsize();
913 } else {
914 bytesToCopy = fe->size();
915 }
916
917 skip = false;
918 if ( cowin != NULL ) {
919 // call newfile without destination so the user
920 // can see the filename in the copyopwin when he will
921 // be asked for the new name
922 cowin->newfile( fe->name, "" );
923 }
924
925 if ( fe->isLink == false && fe->isCorrupt == true ) {
926 if ( cowin != NULL ) cowin->stoptimer();
927
928 text = AGUIXUtils::formatStringToString( catalog.getLocale( 909 ),
929 fe->fullname );
930 button = std::string( catalog.getLocale( 225 ) ) + "|" + catalog.getLocale( 8 );
931 erg = cowin->request( catalog.getLocale( 347 ), text.c_str(), button.c_str() );
932 if ( erg == 0 ) {
933 skip = true;
934 } else {
935 m_cancel = true;
936 }
937
938 if ( cowin != NULL ) cowin->conttimer();
939 }
940
941 if ( m_cancel == false && skip == false ) {
942 e1=getNewName4File(fe,destdir,&newname,acceptrename);
943
944 if((e1==NM_NEWNAME_OK)||(e1==NM_NEWNAME_OVERWRITE)) {
945 // build new name
946 newfullname=(char*)_allocsafe(strlen(destdir)+1+strlen(newname)+1);
947 strcpy(newfullname,destdir);
948 if(strlen(newfullname)>1) {
949 if ( newfullname[strlen(newfullname) - 1] != '/' ) {
950 strcat( newfullname, "/" );
951 }
952 }
953 strcat(newfullname,newname);
954
955 nameok=false;
956 skip=false;
957 if(e1==NM_NEWNAME_OVERWRITE) {
958 nameok=true;
959 } else if(e1==NM_NEWNAME_OK) {
960 // check for fileexists (should not)
961 de1=Datei::lfileExistsExt(newfullname);
962 if(de1==Datei::D_FE_NOFILE) {
963 // everything is ok
964 nameok=true;
965 } else if(de1==Datei::D_FE_FILE) {
966 // dest is a dir
967 // should not happend but ok try to overwrite this
968 nameok=true;
969 }
970 }
971 if(nameok==true) {
972 if ( fe->isSameFile( newfullname, m_copyorder->follow_symlinks ) == false ) {
973 // wenn move true, dann rename probieren
974 // klappt rename nicht, muss flag gesetzt werden und normal weitergemacht
975 // werden und bei korrekten kopieren FE in liste gepackt werden und NEED_DELETE
976 // zurueckgeliefert werden
977 // also: 1.flag docopy am Anfang auf true setzen
978 // 2.bei move==true rename probieren
979 // 2.1.bei Erfolg docopy auf false, Rueckgabewert ist automatisch OK
980 // 2.2.bei Misslingen failedmove auf true setzen
981 // 3.bei docopy==true normal kopieren
982 // 3.1.bei Misslingen kommt halt skip zurueck
983 // 3.2.Bei Erfolg und failedmove==true muss FE in liste gepackt werden
984 // und NEED_DELETE zurueckgeliefert werden
985 docopy=true;
986 failedmove=false;
987
988 if ( cowin != NULL ) cowin->newfile( fe->name, newfullname );
989
990 if(m_copyorder->move==true) {
991 if ( fe->isLink == true &&
992 m_copyorder->adjust_relative_symlinks != m_copyorder->COPY_ADJUST_SYMLINK_NEVER ) {
993 // skip trying to rename file for symlinks that possibly need to be adjusted
994
995 // assume that rename has failed so the source
996 // file is removed if copying was successful
997 failedmove = true;
998 } else if ( worker_rename( fe->fullname, newfullname ) == 0 ) {
999 // success
1000 docopy=false;
1001 } else {
1002 // failure
1003 failedmove=true;
1004 }
1005 }
1006
1007 if(docopy==true) {
1008 // first try to open the file
1009 // in case of failure give a requester with choose "Delete"
1010 // then try to delete it and retry to open
1011 // if all fails, skip
1012 useregcopy = false;
1013 if ( S_ISREG( fe->mode() ) ) useregcopy = true;
1014 else if ( ( fe->isLink == true ) &&
1015 ( m_copyorder->follow_symlinks == true ) &&
1016 ( fe->isCorrupt == false ) &&
1017 ( S_ISREG( fe->dmode() ) ) ) useregcopy = true;
1018
1019 if ( useregcopy == true ) {
1020 reg_copy_erg_t rce = copyfile_reg( fe->fullname,
1021 newfullname,
1022 destdir,
1023 newname,
1024 ( fe->isLink == true ) ? fe->dmode() : fe->mode(),
1025 m_copyorder->cowin,
1026 bytesToCopy );
1027 if ( rce == REG_COPY_OK ) {
1028 opok = true;
1029 } else if ( rce == REG_COPY_SKIP ) {
1030 skip = true;
1031 } else {
1032 // everything else (including ERROR) is cancel
1033 m_cancel = true;
1034 }
1035 } else {
1036 // no regular copy
1037 if ( e1 == NM_NEWNAME_OVERWRITE ) {
1038 // there is already a file but because we cannot overwrite
1039 // with special file I will delete it
1040 // remember the user already choose to overwrite in getNewName!
1041 if ( worker_remove( newfullname ) != 0 ) {
1042 // remove failed => cannot continue
1043
1044 if ( cowin != NULL ) cowin->stoptimer();
1045 myerrstr = strerror( errno );
1046 text = AGUIXUtils::formatStringToString( catalog.getLocale( 516 ), fe->fullname, newfullname, myerrstr );
1047 button = std::string( catalog.getLocale( 225 ) ) + "|" + catalog.getLocale( 8 );
1048 erg = cowin->request( catalog.getLocale( 347 ), text.c_str(), button.c_str() );
1049 if ( erg == 0 ) {
1050 skip = true;
1051 } else {
1052 m_cancel = true;
1053 }
1054 if ( cowin != NULL ) cowin->conttimer();
1055 }
1056 }
1057 //TODO: mc will skip corrupt links when follow_symlinks is used
1058 // I could do this too if I set modeCheck = 0 so it will got to
1059 // the else part
1060 if ( ( fe->isLink == true ) &&
1061 ( m_copyorder->follow_symlinks == true ) &&
1062 ( fe->isCorrupt == false ) ) {
1063 useLinkDest = true;
1064 modeCheck = fe->dmode();
1065 } else {
1066 useLinkDest = false;
1067 modeCheck = fe->mode();
1068 }
1069
1070 if ( ( skip == false ) && ( m_cancel == false ) ) {
1071 if ( ( S_ISCHR( modeCheck ) ) ||
1072 #ifdef S_ISSOCK
1073 ( S_ISSOCK( modeCheck ) ) ||
1074 #endif
1075 ( S_ISBLK( modeCheck ) ) ) {
1076 worker_struct_stat statbuf;
1077
1078 if ( useLinkDest == true ) {
1079 erg = worker_stat( fe->fullname, &statbuf );
1080 } else {
1081 erg = worker_lstat( fe->fullname, &statbuf );
1082 }
1083 if ( erg == 0 ) {
1084 // mknod
1085 mode_t m = statbuf.st_mode;
1086 m = getModeWithEnsureOption( m, *m_copyorder );
1087
1088 if ( worker_mknod( newfullname, m, statbuf.st_rdev ) != 0 ) {
1089 if ( cowin != NULL ) cowin->stoptimer();
1090 myerrstr = strerror( errno );
1091 text = AGUIXUtils::formatStringToString( catalog.getLocale( 1090 ), fe->fullname, newfullname, "mknod", myerrstr );
1092 button = std::string( catalog.getLocale( 225 ) ) + "|" + catalog.getLocale( 8 );
1093 erg = cowin->request( catalog.getLocale( 347 ), text.c_str(), button.c_str() );
1094 if ( erg == 0 ) {
1095 skip = true;
1096 } else {
1097 m_cancel = true;
1098 }
1099 if ( cowin != NULL ) cowin->conttimer();
1100 } else opok = true;
1101 } else {
1102 if ( cowin != NULL ) cowin->stoptimer();
1103 myerrstr = strerror( errno );
1104 text = AGUIXUtils::formatStringToString( catalog.getLocale( 518 ), fe->fullname, newfullname, myerrstr );
1105 button = std::string( catalog.getLocale( 225 ) ) + "|" + catalog.getLocale( 8 );
1106 erg = cowin->request( catalog.getLocale( 347 ), text.c_str(), button.c_str() );
1107 if ( erg == 0 ) {
1108 skip = true;
1109 } else {
1110 m_cancel = true;
1111 }
1112 if ( cowin != NULL ) cowin->conttimer();
1113 }
1114 } else if ( S_ISFIFO( modeCheck ) ) {
1115 // mkfifo
1116 mode_t m = modeCheck;
1117 m = getModeWithEnsureOption( m, *m_copyorder );
1118
1119 if ( mkfifo( newfullname, m ) != 0 ) {
1120 if ( cowin != NULL ) cowin->stoptimer();
1121 myerrstr = strerror( errno );
1122 text = AGUIXUtils::formatStringToString( catalog.getLocale( 1090 ), fe->fullname, newfullname, "mkfifo", myerrstr );
1123 button = std::string( catalog.getLocale( 225 ) ) + "|" + catalog.getLocale( 8 );
1124 erg = cowin->request( catalog.getLocale( 347 ), text.c_str(), button.c_str() );
1125 if ( erg == 0 ) {
1126 skip = true;
1127 } else {
1128 m_cancel = true;
1129 }
1130 if ( cowin != NULL ) cowin->conttimer();
1131 } else opok = true;
1132 } else if ( S_ISLNK( modeCheck ) ) {
1133 // it's a link so create a new symlink which points to the same destination
1134 char *linkdest = fe->getDestination();
1135 if ( linkdest != NULL ) {
1136 if ( linkdest[0] != '/' ) {
1137 bool adjust = false;
1138
1139 if ( m_copyorder->adjust_relative_symlinks == m_copyorder->COPY_ADJUST_SYMLINK_ALWAYS ) {
1140 adjust = true;
1141 } else if ( m_copyorder->adjust_relative_symlinks == m_copyorder->COPY_ADJUST_SYMLINK_OUTSIDE ) {
1142 // relative symlink, try to determine new correct one
1143
1144 // that would be the new target directory of the link
1145 std::string dirname_of_target = NWC::Path::get_real_path( NWC::Path::dirname( newfullname ) );
1146 if ( dirname_of_target.empty() ) dirname_of_target = NWC::Path::dirname( newfullname );
1147
1148 std::string fullnewlink = NWC::Path::join( dirname_of_target,
1149 linkdest );
1150 fullnewlink = NWC::Path::normalize( fullnewlink );
1151
1152 // fullnewlink is the destination of the symlinks
1153
1154 std::string real_destdir = NWC::Path::get_real_path( m_copyorder->destdir );
1155 if ( real_destdir.empty() ) real_destdir = m_copyorder->destdir;
1156
1157 // check if points outside the copy destination dir
1158 // which means that the real_destdir must be a prefix of the link name
1159 if ( ! NWC::Path::is_prefix_dir( real_destdir,
1160 NWC::Path::dirname( fullnewlink ) ) ) {
1161 adjust = true;
1162 }
1163 }
1164
1165 if ( adjust ) {
1166 std::string dirname_of_source = NWC::Path::get_real_path( NWC::Path::dirname( fe->fullname ) );
1167 if ( dirname_of_source.empty() ) dirname_of_source = NWC::Path::dirname( fe->fullname );
1168
1169 std::string fulloldlink = NWC::Path::join( dirname_of_source,
1170 linkdest );
1171 fulloldlink = NWC::Path::normalize( fulloldlink );
1172
1173 char *newrellinkdest = Datei::getRelativePathExt( fulloldlink.c_str(),
1174 NWC::Path::dirname( newfullname ).c_str(),
1175 true );
1176
1177 if ( newrellinkdest && strlen( newrellinkdest ) > 0 ) {
1178 free( linkdest );
1179 linkdest = newrellinkdest;
1180 }
1181 }
1182 }
1183 if ( worker_symlink( linkdest, newfullname ) != 0 ) {
1184 if ( cowin != NULL ) cowin->stoptimer();
1185 myerrstr = strerror( errno );
1186 text = AGUIXUtils::formatStringToString( catalog.getLocale( 1090 ), fe->fullname, newfullname, "symlink", myerrstr );
1187 button = std::string( catalog.getLocale( 225 ) ) + "|" + catalog.getLocale( 8 );
1188 erg = cowin->request( catalog.getLocale( 347 ), text.c_str(), button.c_str() );
1189 if ( erg == 0 ) {
1190 skip = true;
1191 } else {
1192 m_cancel = true;
1193 }
1194 if ( cowin != NULL ) cowin->conttimer();
1195 } else opok = true;
1196 _freesafe( linkdest );
1197 } else {
1198 if ( cowin != NULL ) cowin->stoptimer();
1199 myerrstr = strerror( errno );
1200 text = AGUIXUtils::formatStringToString( catalog.getLocale( 519 ), fe->fullname, newfullname, myerrstr );
1201 button = std::string( catalog.getLocale( 225 ) ) + "|" + catalog.getLocale( 8 );
1202 erg = cowin->request( catalog.getLocale( 347 ), text.c_str(), button.c_str() );
1203 if ( erg == 0 ) {
1204 skip = true;
1205 } else {
1206 m_cancel = true;
1207 }
1208 if ( cowin != NULL ) cowin->conttimer();
1209 }
1210 } else {
1211 if ( cowin != NULL ) cowin->stoptimer();
1212 myerrstr = strerror( errno );
1213 text = AGUIXUtils::formatStringToString( catalog.getLocale( 520 ), fe->fullname );
1214 button = std::string( catalog.getLocale( 225 ) ) + "|" + catalog.getLocale( 8 );
1215 erg = cowin->request( catalog.getLocale( 347 ), text.c_str(), button.c_str() );
1216 if ( erg == 0 ) {
1217 skip = true;
1218 } else {
1219 m_cancel = true;
1220 }
1221 if ( cowin != NULL ) cowin->conttimer();
1222 }
1223 }
1224 //TODO: muss hier nicht eher add_curbytes_copied aufgerufen werden?
1225 // if(cowin!=NULL) cowin->set_bytes_to_copy_curfile(fe->size);
1226 if ( cowin != NULL ) cowin->add_curbytes_copied( fe->size() );
1227 }
1228 }
1229 } else {
1230 text = AGUIXUtils::formatStringToString( catalog.getLocale( 113 ), fe->fullname );
1231 button = catalog.getLocale( 11 );
1232
1233 cowin->request( catalog.getLocale( 347 ), text.c_str(), button.c_str() );
1234 }
1235 } else skip=true;
1236
1237 if ( opok == true ) {
1238 // try to change the mode because open modify it with umask
1239 // it doesn't matter if this fails
1240 if(m_copyorder->preserve_attr==true) {
1241 //TODO:currently deactivated
1242 // chown is necessary because link can have an owner
1243 // but chmod could be optional
1244 // only apply new mode and time if it's not a link
1245 // doing this would not do anything wrong
1246 // but chown/chmod/utime would update the access/change time
1247 // of the destination file although we don't have to touch it
1248 //if ( ( fe->isLink == false ) || ( copyorder->follow_symlinks == true ) ) {
1249 mode_t m = ( ( fe->isLink == true ) && ( fe->isCorrupt == false ) ) ? fe->dmode() : fe->mode();
1250 m = getModeWithEnsureOption( m, *m_copyorder );
1251
1252 tryApplyOwnerPerm( newfullname,
1253 ( ( fe->isLink == true ) && ( fe->isCorrupt == false ) ) ? fe->duserid() : fe->userid(),
1254 ( ( fe->isLink == true ) && ( fe->isCorrupt == false ) ) ? fe->dgroupid() : fe->groupid(),
1255 m );
1256 utb.actime = ( ( fe->isLink == true ) && ( fe->isCorrupt == false ) ) ? fe->dlastaccess() : fe->lastaccess();
1257 utb.modtime = ( ( fe->isLink == true ) && ( fe->isCorrupt == false ) ) ? fe->dlastmod() : fe->lastmod();
1258 worker_utime(newfullname,&utb);
1259 //}
1260 }
1261 }
1262
1263 if ( effective_target_fullname != NULL ) {
1264 *effective_target_fullname = newfullname;
1265 }
1266
1267 _freesafe(newfullname);
1268 } else {
1269 switch(e1) {
1270 case NM_NEWNAME_CANCEL:
1271 m_cancel=true;
1272 default:
1273 skip=true;
1274 break;
1275 }
1276 }
1277 }
1278
1279 if(cowin!=NULL) {
1280 if ( skip == true ) {
1281 // the CopyOpWin need to substract bytesToCopy from global bytes sum
1282 // and already copied bytes from copyied bytes sum
1283 // if we called newfile() (which resets this counter)
1284 cowin->file_skipped( bytesToCopy, true );
1285 } else {
1286 cowin->file_finished();
1287 }
1288 }
1289 if(newname!=NULL) _freesafe(newname);
1290 if(m_cancel==true) return NM_COPY_CANCEL;
1291 else if(skip==true) return NM_COPY_SKIP;
1292 if(m_copyorder->move==true) {
1293 if((opok==true)&&(failedmove==true)) {
1294 // remember: failedmove is true when OS function rename failed
1295 // in this case we have to copy the file and delete the source
1296 // so add this entry only when copy is complete (opok) AND
1297 // rename failed (failedmove)
1298 // put fe in list
1299 pushForPostDelete( fe );
1300 return NM_COPY_NEED_DELETE;
1301 }
1302 }
1303 return NM_COPY_OK;
1304 }
1305
copyfile_reg(const char * sourcename,const char * destname,const char * destdirname,const char * destbasename,mode_t create_mode,CopyOpWin * cowin,loff_t bytesToCopy)1306 CopyCore::reg_copy_erg_t CopyCore::copyfile_reg( const char *sourcename,
1307 const char *destname,
1308 const char *destdirname,
1309 const char *destbasename,
1310 mode_t create_mode,
1311 CopyOpWin *cowin,
1312 loff_t bytesToCopy )
1313 {
1314 int fdw, fdr;
1315 std::string text, button;
1316 ssize_t readbytes;
1317 reg_copy_erg_t return_value = REG_COPY_ERROR;
1318 int erg;
1319 const char *myerrstr;
1320
1321 create_mode = getModeWithEnsureOption( create_mode, *m_copyorder );
1322
1323 // firstly open source file
1324 fdr = worker_open( sourcename, O_RDONLY, 0 );
1325 if ( fdr == -1 ) {
1326 // can't open inputfile
1327 if ( cowin != NULL ) cowin->stoptimer();
1328
1329 text = AGUIXUtils::formatStringToString( catalog.getLocale( 281 ), sourcename );
1330 button = std::string( catalog.getLocale( 225 ) ) + "|" + catalog.getLocale( 8 );
1331 erg = cowin->request( catalog.getLocale( 347 ), text.c_str(), button.c_str() );
1332
1333 if ( erg == 1 ) return_value = REG_COPY_CANCEL;
1334 else return_value = REG_COPY_SKIP;
1335
1336 if ( cowin != NULL ) cowin->conttimer();
1337 return return_value;
1338 }
1339
1340 if ( cowin != NULL ) {
1341 cowin->set_bytes_to_copy_curfile( bytesToCopy );
1342 }
1343
1344 // secondly try to open destination file
1345 // two runs as I first try to open an existing file and only remove it if it doesn't
1346 // work. This is because we can overwrite a file but not create it
1347 for ( int i = 0; i < 2; i++ ) {
1348 // fe is a regular file or a working symlink to a regular file so we can use dmode() without checking
1349 // for corrupt link
1350 fdw = worker_open( destname, O_CREAT | O_TRUNC | O_WRONLY, create_mode );
1351
1352 if ( fdw != -1 ) break;
1353
1354 // open failed
1355 if ( cowin != NULL ) cowin->stoptimer();
1356 if ( errno == ENOSPC ) {
1357 text = AGUIXUtils::formatStringToString( catalog.getLocale( 545 ), destbasename, destdirname );
1358 button = std::string( catalog.getLocale( 225 ) ) + "|" + catalog.getLocale( 41 ) + "|" + catalog.getLocale( 8 );
1359 erg = cowin->request( catalog.getLocale( 347 ), text.c_str(), button.c_str() );
1360
1361 if ( erg == 2 ) {
1362 return_value = REG_COPY_CANCEL;
1363 } else if ( erg == 1 ) {
1364 // just try again
1365 i--;
1366 } else return_value = REG_COPY_SKIP;
1367 } else if ( errno == EACCES ) {
1368 if ( Datei::lfileExistsExt( destname ) != Datei::D_FE_NOFILE ) {
1369 /// error
1370 // give request
1371 // textstr="Can't overwrite the file|Shall I try to delete it?";
1372 // buttonstr="Delete file|Skip|Cancel";
1373
1374 text = AGUIXUtils::formatStringToString( catalog.getLocale( 282 ), destname );
1375 button = std::string( catalog.getLocale( 277 ) ) +
1376 "|" +
1377 catalog.getLocale( 225 ) +
1378 "|" +
1379 catalog.getLocale( 8 );
1380 erg = cowin->request( catalog.getLocale( 123 ), text.c_str(), button.c_str() );
1381
1382 if ( erg == 1 ) return_value = REG_COPY_SKIP;
1383 else if ( erg == 2 ) return_value = REG_COPY_CANCEL;
1384 else {
1385 if ( worker_remove( destname ) != 0 ) {
1386 // textstr="Failed to remove this file|I will skip this file!";
1387 // buttonstr="Ok|Cancel";
1388
1389 text = AGUIXUtils::formatStringToString( catalog.getLocale( 138 ), destname );
1390 button = std::string( catalog.getLocale( 11 ) ) + "|" + catalog.getLocale( 8 );
1391 erg = cowin->request( catalog.getLocale( 347 ), text.c_str(), button.c_str() );
1392
1393 if ( erg == 1 ) return_value = REG_COPY_CANCEL;
1394 else return_value = REG_COPY_SKIP;
1395 }
1396 }
1397 } else {
1398 // "Can't open dest file"
1399 text = AGUIXUtils::formatStringToString( catalog.getLocale( 198 ), destname );
1400 button = std::string( catalog.getLocale( 225 ) ) + "|" + catalog.getLocale( 8 );
1401 erg = cowin->request( catalog.getLocale( 347 ), text.c_str(), button.c_str() );
1402
1403 if ( erg == 1 ) return_value = REG_COPY_CANCEL;
1404 else return_value = REG_COPY_SKIP;
1405 }
1406 } else {
1407 text = AGUIXUtils::formatStringToString( catalog.getLocale( 198 ), destname );
1408 button = std::string( catalog.getLocale( 225 ) ) + "|" + catalog.getLocale( 8 );
1409 erg = cowin->request( catalog.getLocale( 347 ), text.c_str(), button.c_str() );
1410
1411 if ( erg == 1 ) return_value = REG_COPY_CANCEL;
1412 else return_value = REG_COPY_SKIP;
1413 }
1414 if ( cowin != NULL ) cowin->conttimer();
1415
1416 if ( ( return_value == REG_COPY_SKIP ) || ( return_value == REG_COPY_CANCEL ) ) break;
1417 }
1418
1419 if ( fdw == -1 ) {
1420 worker_close( fdr );
1421 return return_value;
1422 }
1423
1424 loff_t total_bytes = 0;
1425 bool asked_about_source_change = false;
1426
1427 // now copy from fdr to fdw
1428 do {
1429 readbytes = worker_read( fdr, buf, BUFSIZE );
1430 if ( readbytes < 0 ) {
1431 // error while reading
1432
1433 if ( cowin != NULL ) cowin->stoptimer();
1434
1435 myerrstr = strerror( errno );
1436 text = AGUIXUtils::formatStringToString( catalog.getLocale( 525 ), sourcename, myerrstr );
1437 button = std::string( catalog.getLocale( 225 ) ) + "|" + catalog.getLocale( 8 );
1438 erg = cowin->request( catalog.getLocale( 347 ), text.c_str(), button.c_str() );
1439
1440 if ( cowin != NULL ) cowin->conttimer();
1441
1442 if ( erg == 0 ) return_value = REG_COPY_SKIP;
1443 else return_value = REG_COPY_CANCEL;
1444 break;
1445 } else if ( readbytes == 0 ) {
1446 // end of file
1447 break;
1448 }
1449
1450 ssize_t bytes_written = 0;
1451
1452 for ( ; bytes_written < readbytes; ) {
1453 const ssize_t bytes_left_to_write = readbytes - bytes_written;
1454 ssize_t writebytes;
1455
1456 writebytes = worker_write( fdw, ((const char *)buf) + bytes_written, bytes_left_to_write );
1457
1458 if ( writebytes > 0 ) {
1459 bytes_written += writebytes;
1460 }
1461
1462 if ( writebytes > 0 && cowin != NULL ) {
1463 cowin->add_curbytes_copied( writebytes );
1464 }
1465
1466 checkAskToCancel();
1467
1468 if ( m_cancel ) {
1469 return_value = REG_COPY_CANCEL;
1470 }
1471
1472 if ( writebytes != bytes_left_to_write ) {
1473 // something went wrong
1474 // let the user choose to cancel or skip this file
1475 // Ask to delete the incomplete destfile
1476 // Attention: This method also moves files so be sure to
1477 // NOT delete the source!
1478 if( ( ( writebytes >= 0 ) && ( writebytes < bytes_left_to_write ) ) ||
1479 ( errno == ENOSPC ) ) {
1480 // ENOSPC isn't always reported so assume ENOSPC
1481 text = AGUIXUtils::formatStringToString( catalog.getLocale( 545 ), destbasename, destdirname );
1482 button = std::string( catalog.getLocale( 225 ) ) + "|" + catalog.getLocale( 41 ) + "|" + catalog.getLocale( 8 );
1483 erg = cowin->request( catalog.getLocale( 347 ), text.c_str(), button.c_str() );
1484
1485 if ( erg == 0 ) {
1486 return_value = REG_COPY_SKIP;
1487 } else if ( erg == 1 ) {
1488 // try again
1489 } else {
1490 return_value = REG_COPY_CANCEL;
1491 }
1492 } else {
1493 if ( writebytes < 0 ) {
1494 myerrstr = strerror( errno );
1495 text = AGUIXUtils::formatStringToString( catalog.getLocale( 526 ), destname, myerrstr );
1496 } else {
1497 text = AGUIXUtils::formatStringToString( catalog.getLocale( 359 ), destname );
1498 }
1499 button = std::string( catalog.getLocale( 225 ) ) + "|" + catalog.getLocale( 8 );
1500 erg = cowin->request( catalog.getLocale( 347 ), text.c_str(), button.c_str() );
1501
1502 if ( erg == 0 ) return_value = REG_COPY_SKIP;
1503 else return_value = REG_COPY_CANCEL;
1504 }
1505 }
1506
1507 if ( return_value == REG_COPY_CANCEL || return_value == REG_COPY_SKIP ) break;
1508 }
1509
1510 total_bytes += bytes_written;
1511
1512 if ( total_bytes > bytesToCopy ) {
1513 // more bytes read than initially known
1514 // probably the source file has changed
1515 // ask what to do
1516
1517 if ( ! asked_about_source_change ) {
1518
1519 text = AGUIXUtils::formatStringToString( catalog.getLocale( 1042 ), sourcename );
1520 button = std::string( catalog.getLocale( 629 ) ) + "|" + catalog.getLocale( 225 ) + "|" + catalog.getLocale( 8 );
1521 erg = cowin->request( catalog.getLocale( 347 ), text.c_str(), button.c_str() );
1522
1523 if ( erg == 0 ) {
1524 } else if ( erg == 1 ) {
1525 return_value = REG_COPY_SKIP;
1526 } else {
1527 return_value = REG_COPY_CANCEL;
1528 }
1529
1530 asked_about_source_change = true;
1531 }
1532 }
1533
1534 } while ( ( return_value != REG_COPY_CANCEL ) && ( return_value != REG_COPY_SKIP ) );
1535
1536 cowin->update_file_status();
1537
1538 if ( m_cancel ) {
1539 return_value = REG_COPY_CANCEL;
1540 }
1541
1542 worker_close( fdr );
1543 if ( worker_close( fdw ) != 0 ) {
1544 // oops, close error
1545 myerrstr = strerror( errno );
1546 text = AGUIXUtils::formatStringToString( catalog.getLocale( 526 ), destname, myerrstr );
1547 button = std::string( catalog.getLocale( 225 ) ) + "|" + catalog.getLocale( 8 );
1548 erg = cowin->request( catalog.getLocale( 347 ), text.c_str(), button.c_str() );
1549
1550 if ( erg == 0 ) return_value = REG_COPY_SKIP;
1551 else return_value = REG_COPY_CANCEL;
1552 }
1553
1554 if ( ( return_value == REG_COPY_CANCEL ) || ( return_value == REG_COPY_SKIP ) ) {
1555 // error while copying!
1556 // ask to remove the incomplete destination file
1557
1558 if ( cowin != NULL ) cowin->stoptimer();
1559
1560 text = AGUIXUtils::formatStringToString( catalog.getLocale( 393 ), destname );
1561 button = std::string( catalog.getLocale( 394 ) ) + "|" + catalog.getLocale( 395 );
1562 erg = cowin->request( catalog.getLocale( 123 ), text.c_str(), button.c_str() );
1563 if ( erg == 1 ) {
1564 if ( worker_unlink( destname ) != 0 ) {
1565 // textstr="Failed to remove the destination file|This file is probably incomplete!";
1566 text = AGUIXUtils::formatStringToString( catalog.getLocale( 139 ), destname );
1567 button = catalog.getLocale( 11 );
1568 erg = cowin->request( catalog.getLocale( 347 ), text.c_str(), button.c_str() );
1569 }
1570 }
1571 if ( cowin != NULL ) cowin->conttimer();
1572 } else {
1573 // copy complete
1574 return_value = REG_COPY_OK;
1575 }
1576 return return_value;
1577 }
1578
deleteCopiedButNotMoved(std::function<void (const std::pair<std::string,bool> &)> processed_callback)1579 int CopyCore::deleteCopiedButNotMoved( std::function< void( const std::pair< std::string, bool > & ) > processed_callback )
1580 {
1581 // now delete remaining files/dirs when moving
1582 if ( m_copyorder->move == true ) {
1583 bool delcancel; // additional cancel so we don't need to
1584 // clear cancel for the special case when move
1585 // has to copy&delete and was aborted somewhere
1586 // I ask the user what to do with the correctly copied
1587 // files
1588 std::string str1;
1589
1590 if ( m_copyorder->cowin != NULL ) m_copyorder->cowin->setmessage( "", 1 );
1591
1592 auto itfe1 = m_copy_deletefe_list.begin();
1593
1594 delcancel = false;
1595
1596 if ( m_cancel == true && itfe1 != m_copy_deletefe_list.end() ) {
1597 // copy was canceled
1598 // ask the user what to do with the correctly moved files
1599 // (exactly what to do with the sources!!)
1600 str1 = catalog.getLocale( 11 );
1601 str1 += "|";
1602 str1 += catalog.getLocale( 8 );
1603 int erg = m_copyorder->cowin->request( catalog.getLocale( 123 ),
1604 catalog.getLocale( 528 ),
1605 str1.c_str() );
1606 if ( erg != 0 ) {
1607 delcancel = true;
1608 }
1609 }
1610
1611 while ( itfe1 != m_copy_deletefe_list.end() && delcancel == false ) {
1612 if ( itfe1->second == true ) {
1613 if ( m_copyorder->cowin != NULL ) {
1614 char *tstr = (char*)_allocsafe( strlen( catalog.getLocale( 141 ) ) +
1615 strlen( itfe1->first.c_str() ) + 1 );
1616 sprintf( tstr, catalog.getLocale( 141 ), itfe1->first.c_str() );
1617 m_copyorder->cowin->setmessage( tstr, 0 );
1618 _freesafe( tstr );
1619 }
1620 }
1621
1622 int erg;
1623
1624 // remove tfe
1625 if ( itfe1->second == true ) {
1626 erg = worker_rmdir( itfe1->first.c_str() );
1627 } else {
1628 erg = worker_unlink( itfe1->first.c_str() );
1629 }
1630
1631 if ( erg == 0 ) {
1632 // success
1633 processed_callback( *itfe1 );
1634 } else {
1635 char *textstr = (char*)_allocsafe( strlen( catalog.getLocale( 291 ) ) +
1636 strlen( itfe1->first.c_str() ) + 1 );
1637 sprintf( textstr, catalog.getLocale( 291 ), itfe1->first.c_str() );
1638 char *buttonstr = (char*)_allocsafe( strlen( catalog.getLocale( 11 ) ) + 1 +
1639 strlen( catalog.getLocale( 8 ) ) + 1 );
1640 sprintf( buttonstr, "%s|%s", catalog.getLocale( 11 ),
1641 catalog.getLocale( 8 ) );
1642 erg = m_copyorder->cowin->request( catalog.getLocale( 347 ), textstr, buttonstr );
1643 _freesafe( buttonstr );
1644 _freesafe( textstr );
1645 if ( erg == 1 ) delcancel = true;
1646 }
1647 if ( itfe1 != m_copy_deletefe_list.end() ) itfe1++;
1648 }
1649 if ( delcancel == true ) m_cancel = true;
1650 }
1651
1652 return 0;
1653 }
1654
getCancel() const1655 bool CopyCore::getCancel() const
1656 {
1657 return m_cancel;
1658 }
1659
setCancel(bool nv)1660 void CopyCore::setCancel( bool nv )
1661 {
1662 // disallow clearing the flag
1663 if ( nv == true ) {
1664 m_cancel = nv;
1665 }
1666 }
1667
pushForPostDelete(const FileEntry * fe)1668 void CopyCore::pushForPostDelete( const FileEntry *fe )
1669 {
1670 if ( fe->isDir() == true && fe->isLink == false ) {
1671 m_copy_deletefe_list.push_back( std::make_pair( fe->fullname, true ) );
1672 } else {
1673 m_copy_deletefe_list.push_back( std::make_pair( fe->fullname, false ) );
1674 }
1675 }
1676
registerFEToCopy(const FileEntry & fe,int row,const std::vector<NWC::OS::deep_dir_info> & file_base_segments)1677 void CopyCore::registerFEToCopy( const FileEntry &fe,
1678 int row,
1679 const std::vector< NWC::OS::deep_dir_info > &file_base_segments )
1680 {
1681 m_copy_list.push_back( copy_base_entry( fe, row, file_base_segments ) );
1682 }
1683
copy_base_entry(const FileEntry & fe,int row,const std::vector<NWC::OS::deep_dir_info> & file_base_segments)1684 CopyCore::copy_base_entry::copy_base_entry( const FileEntry &fe,
1685 int row,
1686 const std::vector< NWC::OS::deep_dir_info > &file_base_segments ) :
1687 m_row( row ),
1688 m_cod( NULL ),
1689 m_fe( fe ),
1690 m_file_base_segments( file_base_segments )
1691 {
1692 }
1693
~copy_base_entry()1694 CopyCore::copy_base_entry::~copy_base_entry()
1695 {
1696 delete m_cod;
1697 }
1698
buildCopyDatabase()1699 int CopyCore::buildCopyDatabase()
1700 {
1701 unsigned long files = 0,
1702 dirs = 0,
1703 gf = 0,
1704 gd = 0;
1705 loff_t bytes = 0;
1706
1707 CopyOpWin *cowin = m_copyorder->cowin;
1708
1709 cowin->starttimer();
1710
1711 if ( cowin->redraw() & 1 ) m_cancel = true;
1712
1713 // create the NM_CopyOp_Dir for each dir in copylist
1714
1715 for ( auto &cbe : m_copy_list ) {
1716 if ( m_cancel == true ) break;
1717
1718 bool enter = false;
1719
1720 if ( cbe.entry().isDir() == true ) {
1721 // fe is a dir, check if it is a link and take it only when follow_symlinks==true
1722 // entry is a dir so it cannot be a corrupt link so no need to check
1723 if ( cbe.entry().isLink == false ) enter = true;
1724 else if ( m_copyorder->follow_symlinks == true ) enter = true;
1725 }
1726
1727 if ( enter == true ) {
1728 // fe is a dir so creating corresponding entry
1729 NM_CopyOp_Dir *cod1 = new NM_CopyOp_Dir( &cbe.entry() );
1730
1731 if ( cod1->user_abort == false ) {
1732 // recursive call
1733 if ( cod1->createSubDirs( m_copyorder, &gf, &gd ) != 0 ) {
1734 m_cancel = true;
1735 }
1736 } else {
1737 m_cancel = true;
1738 }
1739
1740 // add the values from this subdir to this dir
1741 files += cod1->files;
1742 dirs += cod1->dirs;
1743 bytes += cod1->bytes;
1744
1745 cbe.m_cod = cod1;
1746 // this is a dir so inc the counter
1747 dirs++;
1748 gd++;
1749
1750 cowin->set_files_to_copy( gf );
1751 cowin->set_dirs_to_copy( gd );
1752 if ( cowin->redraw() & 1 ) m_cancel = true;
1753 } else {
1754 // is not dir (mostly a file but can also be links ...)
1755 files++;
1756 gf++;
1757
1758 if ( cbe.entry().isLink == true &&
1759 m_copyorder->follow_symlinks == true &&
1760 cbe.entry().isCorrupt == false ) {
1761 bytes += cbe.entry().dsize();
1762 } else {
1763 bytes += cbe.entry().size();
1764 }
1765 cbe.m_cod = NULL;
1766 }
1767 }
1768
1769 cowin->set_files_to_copy( files );
1770 cowin->set_dirs_to_copy( dirs );
1771 cowin->set_bytes_to_copy( bytes );
1772
1773 m_bytes_to_copy = bytes;
1774
1775 // reset start timer for better time predictions
1776 cowin->starttimer();
1777
1778 return 0;
1779 }
1780
executeCopy()1781 int CopyCore::executeCopy()
1782 {
1783 m_copy_thread = std::thread( [this]() { executeCopyThread(); } );
1784
1785 return 0;
1786 }
1787
prepare_destination_dir(copy_base_entry & cbe,std::string & destdir,bool post_run)1788 int CopyCore::prepare_destination_dir( copy_base_entry &cbe,
1789 std::string &destdir,
1790 bool post_run )
1791 {
1792 destdir = m_copyorder->destdir;
1793 int res = 0;
1794
1795 if ( m_copyorder->vdir_preserve_dir_structure &&
1796 ! cbe.get_file_base_segments().empty() ) {
1797
1798 if ( post_run == false ||
1799 m_copyorder->preserve_attr == true ) {
1800 res = NWC::OS::make_dirs( destdir,
1801 cbe.get_file_base_segments(),
1802 post_run );
1803
1804 if ( res != 0 ) {
1805 if ( m_copyorder->cowin != NULL ) m_copyorder->cowin->stoptimer();
1806 auto text = AGUIXUtils::formatStringToString( catalog.getLocale( 1210 ), destdir.c_str() );
1807 auto button = std::string( catalog.getLocale( 225 ) ) + "|" + catalog.getLocale( 8 );
1808 auto erg = m_copyorder->cowin->request( catalog.getLocale( 347 ), text.c_str(), button.c_str() );
1809 if ( erg == 0 ) {
1810 } else {
1811 m_cancel = true;
1812 }
1813 if ( m_copyorder->cowin != NULL ) m_copyorder->cowin->conttimer();
1814 }
1815 }
1816
1817 for ( auto &s : cbe.get_file_base_segments() ) {
1818 destdir = NWC::Path::join( destdir, s.get_segment_name() );
1819 }
1820 }
1821
1822 return res;
1823 }
1824
executeCopyThread()1825 int CopyCore::executeCopyThread()
1826 {
1827 for ( auto &cbe : m_copy_list ) {
1828 checkAskToCancel();
1829
1830 if ( m_cancel ) break;
1831
1832 NM_CopyOp_Dir *tcod;
1833
1834 tcod = cbe.m_cod;
1835
1836 if ( m_pre_cb ) {
1837 loff_t size = 0;
1838
1839 if ( cbe.entry().isLink && ! cbe.entry().isCorrupt ) {
1840 size = cbe.entry().dsize();
1841 } else {
1842 size = cbe.entry().size();
1843 }
1844
1845 m_pre_cb( size, cbe.m_row, cbe.m_cod != NULL ? true : false );
1846 }
1847
1848 if ( tcod != NULL ) {
1849 nm_copy_t ce1;
1850 std::string target_fullname;
1851 std::string destdir;
1852
1853 if ( prepare_destination_dir( cbe, destdir, false ) == 0 ) {
1854 ce1 = copydir( &cbe.entry(), tcod, true, destdir.c_str(), &target_fullname );
1855 if ( ce1 == NM_COPY_OK || ce1 == NM_COPY_NEED_DELETE ) {
1856 // success
1857 Worker::pushCommandLog( m_copyorder->move ? catalog.getLocale( 1420 ) : catalog.getLocale( 1419 ),
1858 target_fullname,
1859 AGUIXUtils::formatStringToString( catalog.getLocale( 1421 ),
1860 cbe.entry().fullname,
1861 destdir.c_str() ) );
1862 } else if ( ce1 == NM_COPY_CANCEL ) {
1863 m_cancel = true;
1864 }
1865
1866 prepare_destination_dir( cbe, destdir, true );
1867 } else {
1868 if ( m_cancel ) {
1869 ce1 = NM_COPY_CANCEL;
1870 } else {
1871 ce1 = NM_COPY_SKIP;
1872 }
1873 }
1874
1875 if ( m_post_cb ) {
1876 m_post_cb( cbe.entry().fullname, cbe.m_row,
1877 ce1,
1878 cbe.m_cod != NULL ? true : false,
1879 cbe.m_cod != NULL ? cbe.m_cod->error_counter : 0,
1880 target_fullname );
1881 }
1882 } else {
1883 nm_copy_t ce1;
1884 std::string target_fullname;
1885 std::string destdir;
1886
1887 if ( prepare_destination_dir( cbe, destdir, false ) == 0 ) {
1888 ce1 = copyfile( &cbe.entry(), true, destdir.c_str(), &target_fullname );
1889
1890 if ( ce1 == NM_COPY_OK || ce1 == NM_COPY_NEED_DELETE ) {
1891 // success
1892 Worker::pushCommandLog( m_copyorder->move ? catalog.getLocale( 1420 ) : catalog.getLocale( 1419 ),
1893 target_fullname,
1894 AGUIXUtils::formatStringToString( catalog.getLocale( 1421 ),
1895 cbe.entry().fullname,
1896 destdir.c_str() ) );
1897 } else if ( ce1 == NM_COPY_CANCEL ) {
1898 m_cancel = true;
1899 }
1900
1901 prepare_destination_dir( cbe, destdir, true );
1902 } else {
1903 if ( m_cancel ) {
1904 ce1 = NM_COPY_CANCEL;
1905 } else {
1906 ce1 = NM_COPY_SKIP;
1907 }
1908 }
1909
1910 if ( m_post_cb ) {
1911 m_post_cb( cbe.entry().fullname, cbe.m_row,
1912 ce1,
1913 cbe.m_cod != NULL ? true : false,
1914 cbe.m_cod != NULL ? cbe.m_cod->error_counter : 0,
1915 target_fullname );
1916 }
1917 }
1918 }
1919
1920 setFinished();
1921
1922 return 0;
1923 }
1924
setPreCopyCallback(std::function<void (loff_t size,int row,bool is_dir)> cb)1925 void CopyCore::setPreCopyCallback( std::function< void( loff_t size, int row, bool is_dir ) > cb )
1926 {
1927 m_pre_cb = cb;
1928 }
1929
setPostCopyCallback(std::function<void (const std::string & source_fullname,int row,nm_copy_t res,bool is_dir,unsigned long dir_error_counter,const std::string & target_fullname)> cb)1930 void CopyCore::setPostCopyCallback( std::function< void( const std::string &source_fullname, int row,
1931 nm_copy_t res,
1932 bool is_dir, unsigned long dir_error_counter,
1933 const std::string &target_fullname ) > cb )
1934 {
1935 m_post_cb = cb;
1936 }
1937
getBytesToCopy() const1938 loff_t CopyCore::getBytesToCopy() const
1939 {
1940 return m_bytes_to_copy;
1941 }
1942
1943 /*
1944 * tryApplyOwnerPerm will try to set owner and permission
1945 * it will apply SUID/SGID only if owner or root (as root only
1946 * if chown don't fail)
1947 * this function don't care if chmod/chown fails
1948 *
1949 * returnvalue:
1950 * 0 okay
1951 * -1 wrong args
1952 * Bit 0 set: SUID cleared
1953 * Bit 1 set: SGID cleared
1954 * Bit 2 set: chown failed
1955 * Bit 3 set: chmod failed
1956 */
tryApplyOwnerPerm(const char * filename,const uid_t wanted_user,const gid_t wanted_group,const mode_t wanted_mode)1957 int CopyCore::tryApplyOwnerPerm( const char *filename,
1958 const uid_t wanted_user,
1959 const gid_t wanted_group,
1960 const mode_t wanted_mode )
1961 {
1962 mode_t use_mode;
1963 int erg = 0, chownres, chmodres;
1964
1965 if ( filename == NULL ) return -1;
1966
1967 chownres = worker_chown( filename, wanted_user, wanted_group );
1968 if ( chownres != 0 ) {
1969 erg |= 1<<2;
1970 }
1971 use_mode = wanted_mode;
1972 if ( ( use_mode & S_ISUID ) != 0 ) {
1973 // SUID bit set, check if we still want it
1974 // root will apply it (when chown didn't failed and)
1975 // and euid/egid == ower
1976 if ( ! ( ( geteuid() == wanted_user ) ||
1977 ( ( geteuid() == 0 ) && ( chownres == 0 ) ) ) ) {
1978 use_mode &= ~S_ISUID;
1979 erg |= 1<<0;
1980 }
1981 }
1982 if ( ( use_mode & S_ISGID ) != 0 ) {
1983 // SGID bit set, check if we still want it
1984 // root will apply it (when chown didn't failed and)
1985 // and euid/egid == ower
1986 if ( ! ( ( getegid() == wanted_group ) ||
1987 ( ( geteuid() == 0 ) && ( chownres == 0 ) ) ) ) {
1988 use_mode &= ~S_ISGID;
1989 erg |= 1<<1;
1990 }
1991 }
1992 chmodres = chmod ( filename, use_mode );
1993 if ( chmodres != 0 ) {
1994 erg |= 1<<3;
1995 }
1996 if ( ( ( erg & 3 ) != 0 ) && ( m_copyorder != NULL ) ) {
1997 // removed SUID/SGUID bit, let the user know this
1998 if ( m_copyorder->ignoreLosedAttr != true ) {
1999 int choose;
2000 char *textstr;
2001 std::string str2;
2002
2003 textstr = (char*)_allocsafe( strlen( catalog.getLocale( 536 ) ) + strlen( filename ) + 1 );
2004 sprintf( textstr, catalog.getLocale( 536 ), filename );
2005 str2 = catalog.getLocale( 11 );
2006 str2 += "|";
2007 str2 += catalog.getLocale( 537 );
2008 choose = m_copyorder->cowin->request( catalog.getLocale( 125 ),
2009 textstr,
2010 str2.c_str(),
2011 Requester::REQUEST_CANCELWITHLEFT );
2012 _freesafe( textstr );
2013 if ( choose == 1 ) {
2014 m_copyorder->ignoreLosedAttr = true;
2015 }
2016 }
2017 }
2018 return erg;
2019 }
2020
getCopyOrder()2021 std::shared_ptr< struct copyorder > CopyCore::getCopyOrder()
2022 {
2023 return m_copyorder;
2024 }
2025
finished()2026 bool CopyCore::finished()
2027 {
2028 std::unique_lock< std::mutex> l( m_finished_mutex );
2029
2030 return m_finished;
2031 }
2032
join()2033 void CopyCore::join()
2034 {
2035 m_copy_thread.join();
2036 }
2037
checkAskToCancel()2038 void CopyCore::checkAskToCancel()
2039 {
2040 if ( m_ask_to_cancel ) {
2041 m_ask_to_cancel = false;
2042
2043 std::string str1;
2044 int erg;
2045
2046 // user canceled -> request to be sure
2047 str1 = catalog.getLocale( 11 );
2048 str1 += "|";
2049 str1 += catalog.getLocale( 544 );
2050 erg = m_copyorder->cowin->request( catalog.getLocale( 123 ),
2051 catalog.getLocale( 543 ),
2052 str1.c_str() );
2053 if ( erg == 0 ) {
2054 m_cancel = true;
2055 }
2056 }
2057 }
2058
setAskToCancel()2059 void CopyCore::setAskToCancel()
2060 {
2061 m_ask_to_cancel = true;
2062 }
2063
timed_wait_for_finished()2064 bool CopyCore::timed_wait_for_finished()
2065 {
2066 std::unique_lock< std::mutex> l( m_finished_mutex );
2067
2068 if ( ! m_finished ) {
2069 m_finished_cond.wait_for( l,
2070 std::chrono::duration<long long, std::milli>( 1000 / 25 ) );
2071 }
2072
2073 return m_finished;
2074 }
2075
setFinished()2076 void CopyCore::setFinished()
2077 {
2078 std::unique_lock< std::mutex> l( m_finished_mutex );
2079
2080 m_finished = true;
2081
2082 m_finished_cond.notify_all();
2083 }
2084