This source file includes following definitions.
- statfs
- statvfs_works
- filegui__check_attrs_on_fs
- file_frmt_time
- file_eta_prepare_for_show
- file_bps_prepare_for_show
- file_ui_op_dlg_callback
- overwrite_query_dialog
- is_wildcarded
- place_progress_buttons
- progress_button_callback
- file_op_context_new
- file_op_context_destroy
- file_progress_check_buttons
- file_progress_ui_create
- file_progress_ui_destroy
- file_progress_show
- file_progress_show_count
- file_progress_show_total
- file_progress_show_source
- file_progress_show_target
- file_progress_show_deleting
- file_progress_real_query_replace
- file_mask_dialog
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 #include <config.h>
54
55 #include <errno.h>
56 #include <ctype.h>
57 #include <limits.h>
58 #include <stdio.h>
59 #include <string.h>
60 #include <sys/types.h>
61 #include <sys/stat.h>
62
63 #if defined(USE_STATVFS)
64 #include <sys/statvfs.h>
65 #elif defined HAVE_SYS_VFS_H
66 #include <sys/vfs.h>
67 #elif defined HAVE_SYS_MOUNT_H && defined HAVE_SYS_PARAM_H
68
69
70
71
72 #include <sys/param.h>
73 #include <sys/mount.h>
74 #elif defined HAVE_OS_H
75 #include <fs_info.h>
76 #endif
77
78 #if defined(USE_STATVFS)
79 #if !defined STAT_STATVFS && defined STAT_STATVFS64
80 #define STRUCT_STATVFS struct statvfs64
81 #define STATFS statvfs64
82 #else
83 #define STRUCT_STATVFS struct statvfs
84 #define STATFS statvfs
85
86 #if defined __linux__ && (defined __GLIBC__ || defined __UCLIBC__)
87 #include <sys/utsname.h>
88 #include <sys/statfs.h>
89 #define STAT_STATFS2_BSIZE 1
90 #endif
91 #endif
92
93 #else
94 #define STATFS statfs
95 #define STRUCT_STATVFS struct statfs
96 #ifdef HAVE_OS_H
97
98
99
100 static int
101 statfs (char const *filename, struct fs_info *buf)
102 {
103 dev_t device;
104
105 device = dev_for_path (filename);
106
107 if (device < 0)
108 {
109 errno = (device == B_ENTRY_NOT_FOUND ? ENOENT
110 : device == B_BAD_VALUE ? EINVAL
111 : device == B_NAME_TOO_LONG ? ENAMETOOLONG
112 : device == B_NO_MEMORY ? ENOMEM
113 : device == B_FILE_ERROR ? EIO
114 : 0);
115 return -1;
116 }
117
118 return fs_stat_dev (device, buf);
119 }
120
121 #define STRUCT_STATVFS struct fs_info
122 #else
123 #define STRUCT_STATVFS struct statfs
124 #endif
125 #endif
126
127 #ifdef HAVE_STRUCT_STATVFS_F_BASETYPE
128 #define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_basetype
129 #else
130 #if defined HAVE_STRUCT_STATVFS_F_FSTYPENAME || defined HAVE_STRUCT_STATFS_F_FSTYPENAME
131 #define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_fstypename
132 #elif defined HAVE_OS_H
133 #define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME fsh_name
134 #endif
135 #endif
136
137 #include <unistd.h>
138
139 #include "lib/global.h"
140
141 #include "lib/tty/key.h"
142 #include "lib/mcconfig.h"
143 #include "lib/search.h"
144 #include "lib/vfs/vfs.h"
145 #include "lib/strutil.h"
146 #include "lib/timefmt.h"
147 #include "lib/util.h"
148 #include "lib/widget.h"
149
150 #include "src/setup.h"
151
152 #include "filemanager.h"
153
154 #include "filegui.h"
155
156
157
158
159
160 gboolean classic_progressbar = TRUE;
161
162
163
164 #define truncFileStringSecure(dlg, s) path_trunc (s, WIDGET (dlg)->rect.cols - 10)
165
166
167
168 typedef enum
169 {
170 MSDOS_SUPER_MAGIC = 0x4d44,
171 NTFS_SB_MAGIC = 0x5346544e,
172 FUSE_MAGIC = 0x65735546,
173 PROC_SUPER_MAGIC = 0x9fa0,
174 SMB_SUPER_MAGIC = 0x517B,
175 NCP_SUPER_MAGIC = 0x564c,
176 USBDEVICE_SUPER_MAGIC = 0x9fa2
177 } filegui_nonattrs_fs_t;
178
179
180 typedef enum
181 {
182 REPLACE_YES = B_USER,
183 REPLACE_NO,
184 REPLACE_APPEND,
185 REPLACE_REGET,
186 REPLACE_ALL,
187 REPLACE_OLDER,
188 REPLACE_NONE,
189 REPLACE_SMALLER,
190 REPLACE_SIZE,
191 REPLACE_ABORT
192 } replace_action_t;
193
194
195
196
197 typedef struct
198 {
199
200 gboolean showing_eta;
201 gboolean showing_bps;
202
203
204 WDialog *op_dlg;
205
206 WLabel *src_file_label;
207 WLabel *src_file;
208
209 WLabel *tgt_file_label;
210 WLabel *tgt_file;
211 WGauge *progress_file_gauge;
212 WLabel *progress_file_label;
213
214 WHLine *total_bytes_label;
215 WGauge *progress_total_gauge;
216 WLabel *total_files_processed_label;
217 WLabel *time_label;
218
219
220 WDialog *replace_dlg;
221 const char *src_filename;
222 const char *tgt_filename;
223 replace_action_t replace_result;
224 gboolean dont_overwrite_with_zero;
225
226 struct stat *src_stat, *dst_stat;
227 } file_progress_ui_t;
228
229
230
231
232
233 static struct
234 {
235 Widget *w;
236 FileProgressStatus action;
237 const char *text;
238 button_flags_t flags;
239 int len;
240 } progress_buttons[] = {
241 { NULL, FILE_SKIP, N_ ("&Skip"), NORMAL_BUTTON, -1 },
242 { NULL, FILE_SUSPEND, N_ ("S&uspend"), NORMAL_BUTTON, -1 },
243 { NULL, FILE_SUSPEND, N_ ("Con&tinue"), NORMAL_BUTTON, -1 },
244 { NULL, FILE_ABORT, N_ ("&Abort"), NORMAL_BUTTON, -1 },
245 };
246
247
248
249
250
251
252
253
254
255
256 #if defined(USE_STATVFS) && !(!defined STAT_STATVFS && defined STAT_STATVFS64)
257 static int
258 statvfs_works (void)
259 {
260 #if !(defined __linux__ && (defined __GLIBC__ || defined __UCLIBC__))
261 return 1;
262 #else
263 static int statvfs_works_cache = -1;
264 struct utsname name;
265
266 if (statvfs_works_cache < 0)
267 statvfs_works_cache = (uname (&name) == 0 && 0 <= str_verscmp (name.release, "2.6.36"));
268 return statvfs_works_cache;
269 #endif
270 }
271 #endif
272
273
274
275 static gboolean
276 filegui__check_attrs_on_fs (const char *fs_path)
277 {
278 STRUCT_STATVFS stfs;
279
280 #if defined(USE_STATVFS) && defined(STAT_STATVFS)
281 if (statvfs_works () && statvfs (fs_path, &stfs) != 0)
282 return TRUE;
283 #else
284 if (STATFS (fs_path, &stfs) != 0)
285 return TRUE;
286 #endif
287
288 #if (defined(USE_STATVFS) && defined(HAVE_STRUCT_STATVFS_F_TYPE)) \
289 || (!defined(USE_STATVFS) && defined(HAVE_STRUCT_STATFS_F_TYPE))
290 switch ((filegui_nonattrs_fs_t) stfs.f_type)
291 {
292 case MSDOS_SUPER_MAGIC:
293 case NTFS_SB_MAGIC:
294 case PROC_SUPER_MAGIC:
295 case SMB_SUPER_MAGIC:
296 case NCP_SUPER_MAGIC:
297 case USBDEVICE_SUPER_MAGIC:
298 return FALSE;
299 default:
300 break;
301 }
302 #elif defined(HAVE_STRUCT_STATVFS_F_FSTYPENAME) || defined(HAVE_STRUCT_STATFS_F_FSTYPENAME)
303 if (strcmp (stfs.STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME, "msdos") == 0
304 || strcmp (stfs.STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME, "msdosfs") == 0
305 || strcmp (stfs.STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME, "ntfs") == 0
306 || strcmp (stfs.STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME, "procfs") == 0
307 || strcmp (stfs.STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME, "smbfs") == 0
308 || strstr (stfs.STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME, "fusefs") != NULL)
309 return FALSE;
310 #elif defined(HAVE_STRUCT_STATVFS_F_BASETYPE)
311 if (strcmp (stfs.STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME, "pcfs") == 0
312 || strcmp (stfs.STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME, "ntfs") == 0
313 || strcmp (stfs.STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME, "proc") == 0
314 || strcmp (stfs.STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME, "smbfs") == 0
315 || strcmp (stfs.STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME, "fuse") == 0)
316 return FALSE;
317 #endif
318
319 return TRUE;
320 }
321
322
323
324 static void
325 file_frmt_time (char *buffer, double eta_secs)
326 {
327 int eta_hours, eta_mins, eta_s;
328
329 eta_hours = (int) (eta_secs / (60 * 60));
330 eta_mins = (int) ((eta_secs - (eta_hours * 60 * 60)) / 60);
331 eta_s = (int) (eta_secs - (eta_hours * 60 * 60 + eta_mins * 60));
332 g_snprintf (buffer, BUF_TINY, _ ("%d:%02d:%02d"), eta_hours, eta_mins, eta_s);
333 }
334
335
336
337 static void
338 file_eta_prepare_for_show (char *buffer, double eta_secs, gboolean always_show)
339 {
340 char _fmt_buff[BUF_TINY];
341
342 if (eta_secs >= INT_MAX)
343 {
344
345 g_strlcpy (_fmt_buff, "--", sizeof (_fmt_buff));
346 }
347 else
348 {
349 if (eta_secs <= 0.5)
350 {
351 if (!always_show)
352 {
353 *buffer = '\0';
354 return;
355 }
356
357 eta_secs = 1.0;
358 }
359
360 file_frmt_time (_fmt_buff, eta_secs);
361 }
362
363 g_snprintf (buffer, BUF_TINY, _ ("ETA %s"), _fmt_buff);
364 }
365
366
367
368 static void
369 file_bps_prepare_for_show (char *buffer, long bps)
370 {
371 if (bps > 1024 * 1024)
372 g_snprintf (buffer, BUF_TINY, _ ("%.2f MB/s"), bps / (1024 * 1024.0));
373 else if (bps > 1024)
374 g_snprintf (buffer, BUF_TINY, _ ("%.2f KB/s"), bps / 1024.0);
375 else if (bps > 1)
376 g_snprintf (buffer, BUF_TINY, _ ("%ld B/s"), bps);
377 else
378 *buffer = '\0';
379 }
380
381
382
383 static cb_ret_t
384 file_ui_op_dlg_callback (Widget *w, Widget *sender, widget_msg_t msg, int parm, void *data)
385 {
386 switch (msg)
387 {
388 case MSG_ACTION:
389
390 if (parm == CK_Cancel)
391 {
392 DIALOG (w)->ret_value = FILE_ABORT;
393 return MSG_HANDLED;
394 }
395 return MSG_NOT_HANDLED;
396
397 default:
398 return dlg_default_callback (w, sender, msg, parm, data);
399 }
400 }
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423 static replace_action_t
424 overwrite_query_dialog (file_op_context_t *ctx, enum OperationMode mode)
425 {
426 #define W(i) dlg_widgets[i].widget
427 #define WX(i) W (i)->rect.x
428 #define WY(i) W (i)->rect.y
429 #define WCOLS(i) W (i)->rect.cols
430
431 #define NEW_LABEL(i, text) W (i) = WIDGET (label_new (dlg_widgets[i].y, dlg_widgets[i].x, text))
432
433 #define ADD_LABEL(i) \
434 group_add_widget_autopos (g, W (i), dlg_widgets[i].pos_flags, \
435 g->current != NULL ? g->current->data : NULL)
436
437 #define NEW_BUTTON(i) \
438 W (i) = WIDGET (button_new (dlg_widgets[i].y, dlg_widgets[i].x, dlg_widgets[i].value, \
439 NORMAL_BUTTON, dlg_widgets[i].text, NULL))
440
441 #define ADD_BUTTON(i) \
442 group_add_widget_autopos (g, W (i), dlg_widgets[i].pos_flags, g->current->data)
443
444
445 const int dlg_height = 17;
446 int dlg_width = 60;
447
448 struct
449 {
450 Widget *widget;
451 const char *text;
452 int y;
453 int x;
454 widget_pos_flags_t pos_flags;
455 int value;
456 } dlg_widgets[] = {
457
458 { NULL, N_ ("New :"), 2, 3, WPOS_KEEP_DEFAULT, 0 },
459
460 { NULL, NULL, 2, 14, WPOS_KEEP_DEFAULT, 0 },
461
462 { NULL, NULL, 3, 3, WPOS_KEEP_DEFAULT, 0 },
463
464 { NULL, NULL, 3, 43, WPOS_KEEP_TOP | WPOS_KEEP_RIGHT, 0 },
465
466 { NULL, N_ ("Existing:"), 4, 3, WPOS_KEEP_DEFAULT, 0 },
467
468 { NULL, NULL, 4, 14, WPOS_KEEP_DEFAULT, 0 },
469
470 { NULL, NULL, 5, 3, WPOS_KEEP_DEFAULT, 0 },
471
472 { NULL, NULL, 5, 43, WPOS_KEEP_TOP | WPOS_KEEP_RIGHT, 0 },
473
474
475 { NULL, N_ ("Overwrite this file?"), 7, 21, WPOS_KEEP_TOP | WPOS_CENTER_HORZ, 0 },
476
477 { NULL, N_ ("&Yes"), 8, 14, WPOS_KEEP_DEFAULT, REPLACE_YES },
478
479 { NULL, N_ ("&No"), 8, 22, WPOS_KEEP_DEFAULT, REPLACE_NO },
480
481 { NULL, N_ ("A&ppend"), 8, 29, WPOS_KEEP_DEFAULT, REPLACE_APPEND },
482
483 { NULL, N_ ("&Reget"), 8, 40, WPOS_KEEP_DEFAULT, REPLACE_REGET },
484
485
486 { NULL, N_ ("Overwrite all files?"), 10, 21, WPOS_KEEP_TOP | WPOS_CENTER_HORZ, 0 },
487
488 { NULL, N_ ("Don't overwrite with &zero length file"), 11, 3, WPOS_KEEP_DEFAULT, 0 },
489
490 { NULL, N_ ("A&ll"), 12, 12, WPOS_KEEP_DEFAULT, REPLACE_ALL },
491
492 { NULL, N_ ("&Older"), 12, 12, WPOS_KEEP_DEFAULT, REPLACE_OLDER },
493
494 { NULL, N_ ("Non&e"), 12, 12, WPOS_KEEP_DEFAULT, REPLACE_NONE },
495
496 { NULL, N_ ("S&maller"), 12, 25, WPOS_KEEP_DEFAULT, REPLACE_SMALLER },
497
498 { NULL, N_ ("&Size differs"), 12, 40, WPOS_KEEP_DEFAULT, REPLACE_SIZE },
499
500
501 { NULL, N_ ("&Abort"), 14, 27, WPOS_KEEP_TOP | WPOS_CENTER_HORZ, REPLACE_ABORT }
502 };
503
504 const int gap = 1;
505
506 file_progress_ui_t *ui = ctx->ui;
507 Widget *wd;
508 WGroup *g;
509 const char *title;
510
511 vfs_path_t *p;
512 char *s1;
513 const char *cs1;
514 char s2[BUF_SMALL];
515 int w, bw1, bw2;
516 unsigned short i;
517
518 gboolean do_append = FALSE, do_reget = FALSE;
519 unsigned long yes_id, no_id;
520 int result;
521
522 const gint64 t = g_get_monotonic_time ();
523
524 if (mode == Foreground)
525 title = _ ("File exists");
526 else
527 title = _ ("Background process: File exists");
528
529 #ifdef ENABLE_NLS
530 {
531 const unsigned short num = G_N_ELEMENTS (dlg_widgets);
532
533 for (i = 0; i < num; i++)
534 if (dlg_widgets[i].text != NULL)
535 dlg_widgets[i].text = _ (dlg_widgets[i].text);
536 }
537 #endif
538
539
540
541 NEW_LABEL (0, dlg_widgets[0].text);
542
543 p = vfs_path_from_str (ui->src_filename);
544 s1 = vfs_path_to_str_flags (p, 0, VPF_STRIP_HOME | VPF_STRIP_PASSWORD);
545 NEW_LABEL (1, s1);
546 vfs_path_free (p, TRUE);
547 g_free (s1);
548
549 size_trunc_len (s2, sizeof (s2), ui->src_stat->st_size, 0, panels_options.kilobyte_si);
550 NEW_LABEL (2, s2);
551
552 cs1 = file_date (ui->src_stat->st_mtime);
553 NEW_LABEL (3, cs1);
554
555
556 NEW_LABEL (4, dlg_widgets[4].text);
557
558 p = vfs_path_from_str (ui->tgt_filename);
559 s1 = vfs_path_to_str_flags (p, 0, VPF_STRIP_HOME | VPF_STRIP_PASSWORD);
560 NEW_LABEL (5, s1);
561 vfs_path_free (p, TRUE);
562 g_free (s1);
563
564 size_trunc_len (s2, sizeof (s2), ui->dst_stat->st_size, 0, panels_options.kilobyte_si);
565 NEW_LABEL (6, s2);
566
567 cs1 = file_date (ui->dst_stat->st_mtime);
568 NEW_LABEL (7, cs1);
569
570
571 do_append = !S_ISDIR (ui->dst_stat->st_mode);
572 do_reget =
573 do_append && ui->dst_stat->st_size != 0 && ui->src_stat->st_size > ui->dst_stat->st_size;
574
575 NEW_LABEL (8, dlg_widgets[8].text);
576 NEW_BUTTON (9);
577 NEW_BUTTON (10);
578 if (do_append)
579 NEW_BUTTON (11);
580 if (do_reget)
581 NEW_BUTTON (12);
582
583 NEW_LABEL (13, dlg_widgets[13].text);
584 dlg_widgets[14].widget =
585 WIDGET (check_new (dlg_widgets[14].y, dlg_widgets[14].x, FALSE, dlg_widgets[14].text));
586 for (i = 15; i <= 20; i++)
587 NEW_BUTTON (i);
588
589
590 dlg_width -= 2 * (2 + gap);
591
592
593 bw1 = WCOLS (9) + gap + WCOLS (10);
594 if (do_append)
595 bw1 += gap + WCOLS (11);
596 if (do_reget)
597 bw1 += gap + WCOLS (12);
598 dlg_width = MAX (dlg_width, bw1);
599
600 bw2 = WCOLS (15);
601 for (i = 16; i <= 19; i++)
602 bw2 += gap + WCOLS (i);
603 dlg_width = MAX (dlg_width, bw2);
604
605 dlg_width = MAX (dlg_width, WCOLS (8));
606 dlg_width = MAX (dlg_width, WCOLS (13));
607 dlg_width = MAX (dlg_width, WCOLS (14));
608
609
610 w = WCOLS (0) + gap + WCOLS (1);
611 if (w > dlg_width)
612 {
613 WLabel *l = LABEL (W (1));
614
615 w = dlg_width - gap - WCOLS (0);
616 label_set_text (l, str_trunc (l->text, w));
617 }
618
619 w = WCOLS (4) + gap + WCOLS (5);
620 if (w > dlg_width)
621 {
622 WLabel *l = LABEL (W (5));
623
624 w = dlg_width - gap - WCOLS (4);
625 label_set_text (l, str_trunc (l->text, w));
626 }
627
628
629 dlg_width += 2 * (2 + gap);
630
631 WX (1) = WX (0) + WCOLS (0) + gap;
632 WX (5) = WX (4) + WCOLS (4) + gap;
633
634
635 WX (2) = dlg_width / 2 - WCOLS (2);
636 WX (6) = dlg_width / 2 - WCOLS (6);
637
638 w = dlg_width - (2 + gap);
639
640
641 WX (3) = w - WCOLS (3);
642 WX (7) = w - WCOLS (7);
643
644
645 WX (9) = dlg_width / 2 - bw1 / 2;
646 WX (10) = WX (9) + WCOLS (9) + gap;
647 if (do_append)
648 WX (11) = WX (10) + WCOLS (10) + gap;
649 if (do_reget)
650 WX (12) = WX (11) + WCOLS (11) + gap;
651
652 WX (15) = dlg_width / 2 - bw2 / 2;
653 for (i = 16; i <= 19; i++)
654 WX (i) = WX (i - 1) + WCOLS (i - 1) + gap;
655
656
657 ui->replace_dlg = dlg_create (TRUE, 0, 0, dlg_height, dlg_width, WPOS_CENTER, FALSE,
658 alarm_colors, NULL, NULL, "[Replace]", title);
659 wd = WIDGET (ui->replace_dlg);
660 g = GROUP (ui->replace_dlg);
661
662
663 for (i = 0; i <= 7; i++)
664 ADD_LABEL (i);
665 group_add_widget (g, hline_new (WY (7) - wd->rect.y + 1, -1, -1));
666
667
668 ADD_LABEL (8);
669 yes_id = ADD_BUTTON (9);
670 no_id = ADD_BUTTON (10);
671 if (do_append)
672 ADD_BUTTON (11);
673 if (do_reget)
674 ADD_BUTTON (12);
675 group_add_widget (g, hline_new (WY (10) - wd->rect.y + 1, -1, -1));
676
677
678 ADD_LABEL (13);
679 group_add_widget (g, dlg_widgets[14].widget);
680 for (i = 15; i <= 19; i++)
681 ADD_BUTTON (i);
682 group_add_widget (g, hline_new (WY (19) - wd->rect.y + 1, -1, -1));
683
684 ADD_BUTTON (20);
685
686 group_select_widget_by_id (g, safe_overwrite ? no_id : yes_id);
687
688 result = dlg_run (ui->replace_dlg);
689
690 if (result != B_CANCEL)
691 ui->dont_overwrite_with_zero = CHECK (dlg_widgets[14].widget)->state;
692
693 widget_destroy (wd);
694
695 ctx->pauses += g_get_monotonic_time () - t;
696
697 return (result == B_CANCEL) ? REPLACE_ABORT : (replace_action_t) result;
698
699 #undef ADD_BUTTON
700 #undef NEW_BUTTON
701 #undef ADD_LABEL
702 #undef NEW_LABEL
703 #undef WCOLS
704 #undef WX
705 #undef W
706 }
707
708
709
710 static gboolean
711 is_wildcarded (const char *p)
712 {
713 gboolean escaped = FALSE;
714
715 for (; *p != '\0'; p++)
716 {
717 if (*p == '\\')
718 {
719 if (p[1] >= '1' && p[1] <= '9' && !escaped)
720 return TRUE;
721 escaped = !escaped;
722 }
723 else
724 {
725 if ((*p == '*' || *p == '?') && !escaped)
726 return TRUE;
727 escaped = FALSE;
728 }
729 }
730 return FALSE;
731 }
732
733
734
735 static void
736 place_progress_buttons (WDialog *h, gboolean suspended)
737 {
738 const size_t i = suspended ? 2 : 1;
739 Widget *w = WIDGET (h);
740 int buttons_width;
741
742 buttons_width = 2 + progress_buttons[0].len + progress_buttons[3].len;
743 buttons_width += progress_buttons[i].len;
744 button_set_text (BUTTON (progress_buttons[i].w), progress_buttons[i].text);
745
746 progress_buttons[0].w->rect.x = w->rect.x + (w->rect.cols - buttons_width) / 2;
747 progress_buttons[i].w->rect.x = progress_buttons[0].w->rect.x + progress_buttons[0].len + 1;
748 progress_buttons[3].w->rect.x = progress_buttons[i].w->rect.x + progress_buttons[i].len + 1;
749 }
750
751
752
753 static int
754 progress_button_callback (WButton *button, int action)
755 {
756 (void) button;
757 (void) action;
758
759
760 return 0;
761 }
762
763
764
765
766
767
768
769
770
771
772
773
774
775 file_op_context_t *
776 file_op_context_new (FileOperation op)
777 {
778 file_op_context_t *ctx;
779
780 ctx = g_new0 (file_op_context_t, 1);
781 ctx->operation = op;
782 ctx->preserve = TRUE;
783 ctx->preserve_uidgid = (geteuid () == 0);
784 ctx->umask_kill = (mode_t) (~0);
785 ctx->erase_at_end = TRUE;
786 ctx->do_reget = -1;
787 ctx->stat_func = mc_lstat;
788 ctx->ask_overwrite = TRUE;
789
790 return ctx;
791 }
792
793
794
795
796
797
798
799
800
801
802 void
803 file_op_context_destroy (file_op_context_t *ctx)
804 {
805 if (ctx != NULL)
806 {
807 file_progress_ui_destroy (ctx);
808 mc_search_free (ctx->search_handle);
809 g_free (ctx);
810 }
811 }
812
813
814
815 FileProgressStatus
816 file_progress_check_buttons (file_op_context_t *ctx)
817 {
818 int c;
819 Gpm_Event event;
820 file_progress_ui_t *ui;
821
822 if (ctx == NULL || ctx->ui == NULL)
823 return FILE_CONT;
824
825 ui = ctx->ui;
826
827 get_event:
828 event.x = -1;
829 c = tty_get_event (&event, FALSE, ctx->suspended);
830 if (c == EV_NONE)
831 return FILE_CONT;
832
833
834 ui->op_dlg->ret_value = FILE_CONT;
835
836 dlg_process_event (ui->op_dlg, c, &event);
837 switch (ui->op_dlg->ret_value)
838 {
839 case FILE_SKIP:
840 if (ctx->suspended)
841 {
842
843 place_progress_buttons (ui->op_dlg, FALSE);
844 widget_draw (WIDGET (ui->op_dlg));
845 }
846 ctx->suspended = FALSE;
847 return FILE_SKIP;
848 case B_CANCEL:
849 case FILE_ABORT:
850 ctx->suspended = FALSE;
851 return FILE_ABORT;
852 case FILE_SUSPEND:
853 ctx->suspended = !ctx->suspended;
854 place_progress_buttons (ui->op_dlg, ctx->suspended);
855 widget_draw (WIDGET (ui->op_dlg));
856 MC_FALLTHROUGH;
857 default:
858 if (ctx->suspended)
859 goto get_event;
860 return FILE_CONT;
861 }
862 }
863
864
865
866
867 void
868 file_progress_ui_create (file_op_context_t *ctx, gboolean with_eta,
869 filegui_dialog_type_t dialog_type)
870 {
871 file_progress_ui_t *ui;
872 Widget *w;
873 WGroup *g;
874 int buttons_width;
875 int dlg_width = 58, dlg_height = 17;
876 int y = 2, x = 3;
877 WRect r;
878
879 if (ctx == NULL || ctx->ui != NULL)
880 return;
881
882 #ifdef ENABLE_NLS
883 if (progress_buttons[0].len == -1)
884 {
885 size_t i;
886
887 for (i = 0; i < G_N_ELEMENTS (progress_buttons); i++)
888 progress_buttons[i].text = _ (progress_buttons[i].text);
889 }
890 #endif
891
892 ctx->dialog_type = dialog_type;
893 ctx->recursive_result = RECURSIVE_YES;
894 ctx->ui = g_new0 (file_progress_ui_t, 1);
895
896 ui = ctx->ui;
897 ui->replace_result = REPLACE_YES;
898
899 ui->op_dlg = dlg_create (TRUE, 0, 0, dlg_height, dlg_width, WPOS_CENTER, FALSE, dialog_colors,
900 file_ui_op_dlg_callback, NULL, NULL, op_names[ctx->operation]);
901 w = WIDGET (ui->op_dlg);
902 g = GROUP (ui->op_dlg);
903
904 if (dialog_type != FILEGUI_DIALOG_DELETE_ITEM)
905 {
906 ui->showing_eta = with_eta && ctx->totals_computed;
907 ui->showing_bps = with_eta;
908
909 ui->src_file_label = label_new (y++, x, NULL);
910 group_add_widget (g, ui->src_file_label);
911
912 ui->src_file = label_new (y++, x, NULL);
913 group_add_widget (g, ui->src_file);
914
915 ui->tgt_file_label = label_new (y++, x, NULL);
916 group_add_widget (g, ui->tgt_file_label);
917
918 ui->tgt_file = label_new (y++, x, NULL);
919 group_add_widget (g, ui->tgt_file);
920
921 ui->progress_file_gauge = gauge_new (y++, x + 3, dlg_width - (x + 3) * 2, FALSE, 100, 0);
922 if (!classic_progressbar && (current_panel == right_panel))
923 ui->progress_file_gauge->from_left_to_right = FALSE;
924 group_add_widget_autopos (g, ui->progress_file_gauge, WPOS_KEEP_TOP | WPOS_KEEP_HORZ, NULL);
925
926 ui->progress_file_label = label_new (y++, x, NULL);
927 group_add_widget (g, ui->progress_file_label);
928
929 if (verbose && dialog_type == FILEGUI_DIALOG_MULTI_ITEM)
930 {
931 ui->total_bytes_label = hline_new (y++, -1, -1);
932 group_add_widget (g, ui->total_bytes_label);
933
934 if (ctx->totals_computed)
935 {
936 ui->progress_total_gauge =
937 gauge_new (y++, x + 3, dlg_width - (x + 3) * 2, FALSE, 100, 0);
938 if (!classic_progressbar && (current_panel == right_panel))
939 ui->progress_total_gauge->from_left_to_right = FALSE;
940 group_add_widget_autopos (g, ui->progress_total_gauge,
941 WPOS_KEEP_TOP | WPOS_KEEP_HORZ, NULL);
942 }
943
944 ui->total_files_processed_label = label_new (y++, x, NULL);
945 group_add_widget (g, ui->total_files_processed_label);
946
947 ui->time_label = label_new (y++, x, NULL);
948 group_add_widget (g, ui->time_label);
949 }
950 }
951 else
952 {
953 ui->src_file = label_new (y++, x, NULL);
954 group_add_widget (g, ui->src_file);
955
956 ui->total_files_processed_label = label_new (y++, x, NULL);
957 group_add_widget (g, ui->total_files_processed_label);
958 }
959
960 group_add_widget (g, hline_new (y++, -1, -1));
961
962 progress_buttons[0].w =
963 WIDGET (button_new (y, 0, progress_buttons[0].action, progress_buttons[0].flags,
964 progress_buttons[0].text, progress_button_callback));
965 if (progress_buttons[0].len == -1)
966 progress_buttons[0].len = button_get_len (BUTTON (progress_buttons[0].w));
967
968 progress_buttons[1].w =
969 WIDGET (button_new (y, 0, progress_buttons[1].action, progress_buttons[1].flags,
970 progress_buttons[1].text, progress_button_callback));
971 if (progress_buttons[1].len == -1)
972 progress_buttons[1].len = button_get_len (BUTTON (progress_buttons[1].w));
973
974 if (progress_buttons[2].len == -1)
975 {
976
977 progress_buttons[2].w =
978 WIDGET (button_new (y, 0, progress_buttons[2].action, progress_buttons[2].flags,
979 progress_buttons[2].text, progress_button_callback));
980 progress_buttons[2].len = button_get_len (BUTTON (progress_buttons[2].w));
981 widget_destroy (progress_buttons[2].w);
982 }
983 progress_buttons[2].w = progress_buttons[1].w;
984
985 progress_buttons[3].w =
986 WIDGET (button_new (y, 0, progress_buttons[3].action, progress_buttons[3].flags,
987 progress_buttons[3].text, progress_button_callback));
988 if (progress_buttons[3].len == -1)
989 progress_buttons[3].len = button_get_len (BUTTON (progress_buttons[3].w));
990
991 group_add_widget (g, progress_buttons[0].w);
992 group_add_widget (g, progress_buttons[1].w);
993 group_add_widget (g, progress_buttons[3].w);
994
995 buttons_width = 2 + progress_buttons[0].len
996 + MAX (progress_buttons[1].len, progress_buttons[2].len) + progress_buttons[3].len;
997
998
999 r = w->rect;
1000 r.lines = y + 3;
1001 r.cols = MAX (COLS * 2 / 3, buttons_width + 6);
1002 widget_set_size_rect (w, &r);
1003
1004 place_progress_buttons (ui->op_dlg, FALSE);
1005
1006 widget_select (progress_buttons[0].w);
1007
1008
1009
1010 dlg_init (ui->op_dlg);
1011 }
1012
1013
1014
1015 void
1016 file_progress_ui_destroy (file_op_context_t *ctx)
1017 {
1018 if (ctx != NULL && ctx->ui != NULL)
1019 {
1020 file_progress_ui_t *ui = (file_progress_ui_t *) ctx->ui;
1021
1022 dlg_run_done (ui->op_dlg);
1023 widget_destroy (WIDGET (ui->op_dlg));
1024 MC_PTR_FREE (ctx->ui);
1025 }
1026 }
1027
1028
1029
1030
1031
1032
1033 void
1034 file_progress_show (file_op_context_t *ctx, off_t done, off_t total, const char *stalled_msg,
1035 gboolean force_update)
1036 {
1037 file_progress_ui_t *ui;
1038
1039 if (ctx == NULL || ctx->ui == NULL)
1040 return;
1041
1042 ui = ctx->ui;
1043
1044 if (total == 0)
1045 {
1046 gauge_show (ui->progress_file_gauge, FALSE);
1047 return;
1048 }
1049
1050 gauge_set_value (ui->progress_file_gauge, 1024, (int) (1024 * done / total));
1051 gauge_show (ui->progress_file_gauge, TRUE);
1052
1053 if (!force_update)
1054 return;
1055
1056 if (!ui->showing_eta || ctx->eta_secs <= 0.5)
1057 label_set_text (ui->progress_file_label, stalled_msg);
1058 else
1059 {
1060 char buffer2[BUF_TINY];
1061
1062 file_eta_prepare_for_show (buffer2, ctx->eta_secs, FALSE);
1063 if (ctx->bps == 0)
1064 label_set_textv (ui->progress_file_label, "%s %s", buffer2, stalled_msg);
1065 else
1066 {
1067 char buffer3[BUF_TINY];
1068
1069 file_bps_prepare_for_show (buffer3, ctx->bps);
1070 label_set_textv (ui->progress_file_label, "%s (%s) %s", buffer2, buffer3, stalled_msg);
1071 }
1072 }
1073 }
1074
1075
1076
1077 void
1078 file_progress_show_count (file_op_context_t *ctx)
1079 {
1080 file_progress_ui_t *ui;
1081
1082 if (ctx == NULL || ctx->ui == NULL)
1083 return;
1084
1085 ui = ctx->ui;
1086
1087 if (ui->total_files_processed_label == NULL)
1088 return;
1089
1090 if (ctx->totals_computed)
1091 label_set_textv (ui->total_files_processed_label, _ ("Files processed: %zu / %zu"),
1092 ctx->total_progress_count, ctx->total_count);
1093 else
1094 label_set_textv (ui->total_files_processed_label, _ ("Files processed: %zu"),
1095 ctx->total_progress_count);
1096 }
1097
1098
1099
1100 void
1101 file_progress_show_total (file_op_context_t *ctx, uintmax_t copied_bytes, gint64 tv_current,
1102 gboolean show_summary)
1103 {
1104 char buffer2[BUF_TINY];
1105 char buffer3[BUF_TINY];
1106 file_progress_ui_t *ui;
1107
1108 if (ctx == NULL || ctx->ui == NULL)
1109 return;
1110
1111 ui = ctx->ui;
1112
1113 if (ui->progress_total_gauge != NULL)
1114 {
1115 if (ctx->total_bytes == 0)
1116 gauge_show (ui->progress_total_gauge, FALSE);
1117 else
1118 {
1119 gauge_set_value (ui->progress_total_gauge, 1024,
1120 (int) (1024 * copied_bytes / ctx->total_bytes));
1121 gauge_show (ui->progress_total_gauge, TRUE);
1122 }
1123 }
1124
1125 if (!show_summary && ctx->total_bps == 0)
1126 return;
1127
1128 if (ui->time_label != NULL)
1129 {
1130 char buffer4[BUF_TINY];
1131
1132 file_frmt_time (buffer2,
1133 (tv_current - ctx->pauses - ctx->total_transfer_start) / G_USEC_PER_SEC);
1134
1135 if (ctx->totals_computed)
1136 {
1137 file_eta_prepare_for_show (buffer3, ctx->total_eta_secs, TRUE);
1138 if (ctx->total_bps == 0)
1139 label_set_textv (ui->time_label, _ ("Time: %s %s"), buffer2, buffer3);
1140 else
1141 {
1142 file_bps_prepare_for_show (buffer4, ctx->total_bps);
1143 label_set_textv (ui->time_label, _ ("Time: %s %s (%s)"), buffer2, buffer3, buffer4);
1144 }
1145 }
1146 else
1147 {
1148 if (ctx->total_bps == 0)
1149 label_set_textv (ui->time_label, _ ("Time: %s"), buffer2);
1150 else
1151 {
1152 file_bps_prepare_for_show (buffer4, ctx->total_bps);
1153 label_set_textv (ui->time_label, _ ("Time: %s (%s)"), buffer2, buffer4);
1154 }
1155 }
1156 }
1157
1158 if (ui->total_bytes_label != NULL)
1159 {
1160 size_trunc_len (buffer2, 5, copied_bytes, 0, panels_options.kilobyte_si);
1161
1162 if (!ctx->totals_computed)
1163 hline_set_textv (ui->total_bytes_label, _ (" Total: %s "), buffer2);
1164 else
1165 {
1166 size_trunc_len (buffer3, 5, ctx->total_bytes, 0, panels_options.kilobyte_si);
1167 hline_set_textv (ui->total_bytes_label, _ (" Total: %s / %s "), buffer2, buffer3);
1168 }
1169 }
1170 }
1171
1172
1173
1174
1175
1176 void
1177 file_progress_show_source (file_op_context_t *ctx, const vfs_path_t *vpath)
1178 {
1179 file_progress_ui_t *ui;
1180
1181 if (ctx == NULL || ctx->ui == NULL)
1182 return;
1183
1184 ui = ctx->ui;
1185
1186 if (vpath != NULL)
1187 {
1188 label_set_text (ui->src_file_label, _ ("Source"));
1189 label_set_text (ui->src_file, truncFileStringSecure (ui->op_dlg, vfs_path_as_str (vpath)));
1190 }
1191 else
1192 {
1193 label_set_text (ui->src_file_label, NULL);
1194 label_set_text (ui->src_file, NULL);
1195 }
1196 }
1197
1198
1199
1200 void
1201 file_progress_show_target (file_op_context_t *ctx, const vfs_path_t *vpath)
1202 {
1203 file_progress_ui_t *ui;
1204
1205 if (ctx == NULL || ctx->ui == NULL)
1206 return;
1207
1208 ui = ctx->ui;
1209
1210 if (vpath != NULL)
1211 {
1212 label_set_text (ui->tgt_file_label, _ ("Target"));
1213 label_set_text (ui->tgt_file, truncFileStringSecure (ui->op_dlg, vfs_path_as_str (vpath)));
1214 }
1215 else
1216 {
1217 label_set_text (ui->tgt_file_label, NULL);
1218 label_set_text (ui->tgt_file, NULL);
1219 }
1220 }
1221
1222
1223
1224 gboolean
1225 file_progress_show_deleting (file_op_context_t *ctx, const vfs_path_t *vpath, size_t *count)
1226 {
1227 static gint64 timestamp = 0;
1228
1229 static const gint64 delay = G_USEC_PER_SEC / 25;
1230
1231 gboolean ret;
1232
1233 if (ctx == NULL || ctx->ui == NULL)
1234 return FALSE;
1235
1236 ret = mc_time_elapsed (×tamp, delay);
1237
1238 if (ret)
1239 {
1240 file_progress_ui_t *ui;
1241 const char *s;
1242
1243 ui = ctx->ui;
1244
1245 if (ui->src_file_label != NULL)
1246 label_set_text (ui->src_file_label, _ ("Deleting"));
1247
1248 s = vfs_path_as_str (vpath);
1249 label_set_text (ui->src_file, truncFileStringSecure (ui->op_dlg, s));
1250 }
1251
1252 if (count != NULL)
1253 (*count)++;
1254
1255 return ret;
1256 }
1257
1258
1259
1260 FileProgressStatus
1261 file_progress_real_query_replace (file_op_context_t *ctx, enum OperationMode mode, const char *src,
1262 struct stat *src_stat, const char *dst, struct stat *dst_stat)
1263 {
1264 file_progress_ui_t *ui;
1265 FileProgressStatus replace_with_zero;
1266
1267 if (ctx == NULL || ctx->ui == NULL)
1268 return FILE_CONT;
1269
1270 ui = ctx->ui;
1271
1272 if (ui->replace_result == REPLACE_YES || ui->replace_result == REPLACE_NO
1273 || ui->replace_result == REPLACE_APPEND)
1274 {
1275 ui->src_filename = src;
1276 ui->src_stat = src_stat;
1277 ui->tgt_filename = dst;
1278 ui->dst_stat = dst_stat;
1279 ui->replace_result = overwrite_query_dialog (ctx, mode);
1280 }
1281
1282 replace_with_zero =
1283 (src_stat->st_size == 0 && ui->dont_overwrite_with_zero) ? FILE_SKIP : FILE_CONT;
1284
1285 switch (ui->replace_result)
1286 {
1287 case REPLACE_OLDER:
1288 do_refresh ();
1289 if (src_stat->st_mtime > dst_stat->st_mtime)
1290 return replace_with_zero;
1291 else
1292 return FILE_SKIP;
1293
1294 case REPLACE_SIZE:
1295 do_refresh ();
1296 if (src_stat->st_size == dst_stat->st_size)
1297 return FILE_SKIP;
1298 else
1299 return replace_with_zero;
1300
1301 case REPLACE_SMALLER:
1302 do_refresh ();
1303 if (src_stat->st_size > dst_stat->st_size)
1304 return FILE_CONT;
1305 else
1306 return FILE_SKIP;
1307
1308 case REPLACE_ALL:
1309 do_refresh ();
1310 return replace_with_zero;
1311
1312 case REPLACE_REGET:
1313
1314 ctx->do_reget = dst_stat->st_size;
1315 MC_FALLTHROUGH;
1316
1317 case REPLACE_APPEND:
1318 ctx->do_append = TRUE;
1319 MC_FALLTHROUGH;
1320
1321 case REPLACE_YES:
1322 do_refresh ();
1323 return FILE_CONT;
1324
1325 case REPLACE_NO:
1326 case REPLACE_NONE:
1327 do_refresh ();
1328 return FILE_SKIP;
1329
1330 case REPLACE_ABORT:
1331 default:
1332 return FILE_ABORT;
1333 }
1334 }
1335
1336
1337
1338 char *
1339 file_mask_dialog (file_op_context_t *ctx, gboolean only_one, const char *format, const void *text,
1340 const char *def_text, gboolean *do_bg)
1341 {
1342 gboolean preserve;
1343 size_t fmd_xlen;
1344 vfs_path_t *vpath;
1345 gboolean source_easy_patterns = easy_patterns;
1346 char fmd_buf[BUF_MEDIUM];
1347 char *dest_dir = NULL;
1348 char *tmp;
1349 char *def_text_secure;
1350
1351 if (ctx == NULL)
1352 return NULL;
1353
1354
1355 preserve = copymove_persistent_attr && filegui__check_attrs_on_fs (def_text);
1356
1357 ctx->stable_symlinks = FALSE;
1358 *do_bg = FALSE;
1359
1360
1361 vpath = vfs_path_from_str_flags (def_text, only_one ? VPF_NO_CANON : VPF_NONE);
1362 tmp = vfs_path_to_str_flags (vpath, 0, VPF_STRIP_PASSWORD);
1363 vfs_path_free (vpath, TRUE);
1364
1365 if (source_easy_patterns)
1366 def_text_secure = str_glob_escape (tmp);
1367 else
1368 def_text_secure = str_regex_escape (tmp);
1369 g_free (tmp);
1370
1371 if (only_one)
1372 {
1373 int format_len, text_len;
1374 int max_len;
1375
1376 format_len = str_term_width1 (format);
1377 text_len = str_term_width1 (text);
1378 max_len = COLS - 2 - 6;
1379
1380 if (format_len + text_len <= max_len)
1381 {
1382 fmd_xlen = format_len + text_len + 6;
1383 fmd_xlen = MAX (fmd_xlen, 68);
1384 }
1385 else
1386 {
1387 text = str_trunc ((const char *) text, max_len - format_len);
1388 fmd_xlen = max_len + 6;
1389 }
1390
1391 g_snprintf (fmd_buf, sizeof (fmd_buf), format, (const char *) text);
1392 }
1393 else
1394 {
1395 fmd_xlen = COLS * 2 / 3;
1396 fmd_xlen = MAX (fmd_xlen, 68);
1397 g_snprintf (fmd_buf, sizeof (fmd_buf), format, *(const int *) text);
1398 }
1399
1400 {
1401 char *source_mask = NULL;
1402 char *orig_mask;
1403 int val;
1404 struct stat buf;
1405
1406 quick_widget_t quick_widgets[] = {
1407
1408 QUICK_LABELED_INPUT (fmd_buf, input_label_above, easy_patterns ? "*" : "^(.*)$",
1409 "input-def", &source_mask, NULL, FALSE, FALSE,
1410 INPUT_COMPLETE_FILENAMES),
1411 QUICK_START_COLUMNS,
1412 QUICK_SEPARATOR (FALSE),
1413 QUICK_NEXT_COLUMN,
1414 QUICK_CHECKBOX (N_ ("&Using shell patterns"), &source_easy_patterns, NULL),
1415 QUICK_STOP_COLUMNS,
1416 QUICK_LABELED_INPUT (N_ ("to:"), input_label_above, def_text_secure, "input2",
1417 &dest_dir, NULL, FALSE, FALSE, INPUT_COMPLETE_FILENAMES),
1418 QUICK_SEPARATOR (TRUE),
1419 QUICK_START_COLUMNS,
1420 QUICK_CHECKBOX (N_ ("Follow &links"), &ctx->follow_links, NULL),
1421 QUICK_CHECKBOX (N_ ("Preserve &attributes"), &preserve, NULL),
1422 QUICK_NEXT_COLUMN,
1423 QUICK_CHECKBOX (N_ ("Di&ve into subdir if exists"), &ctx->dive_into_subdirs, NULL),
1424 QUICK_CHECKBOX (N_ ("&Stable symlinks"), &ctx->stable_symlinks, NULL),
1425 QUICK_STOP_COLUMNS,
1426 QUICK_START_BUTTONS (TRUE, TRUE),
1427 QUICK_BUTTON (N_ ("&OK"), B_ENTER, NULL, NULL),
1428 #ifdef ENABLE_BACKGROUND
1429 QUICK_BUTTON (N_ ("&Background"), B_USER, NULL, NULL),
1430 #endif
1431 QUICK_BUTTON (N_ ("&Cancel"), B_CANCEL, NULL, NULL),
1432 QUICK_END,
1433
1434 };
1435
1436 WRect r = { -1, -1, 0, fmd_xlen };
1437
1438 quick_dialog_t qdlg = {
1439 .rect = r,
1440 .title = op_names[ctx->operation],
1441 .help = "[Mask Copy/Rename]",
1442 .widgets = quick_widgets,
1443 .callback = NULL,
1444 .mouse_callback = NULL,
1445 };
1446
1447 while (TRUE)
1448 {
1449 val = quick_dialog_skip (&qdlg, 4);
1450
1451 if (val == B_CANCEL)
1452 {
1453 g_free (def_text_secure);
1454 return NULL;
1455 }
1456
1457 ctx->stat_func = ctx->follow_links ? mc_stat : mc_lstat;
1458
1459 if (preserve)
1460 {
1461 ctx->preserve = TRUE;
1462 ctx->umask_kill = (mode_t) (~0);
1463 ctx->preserve_uidgid = (geteuid () == 0);
1464 }
1465 else
1466 {
1467 mode_t i2;
1468
1469 ctx->preserve = ctx->preserve_uidgid = FALSE;
1470 i2 = umask (0);
1471 umask (i2);
1472 ctx->umask_kill = i2 ^ ((mode_t) (~0));
1473 }
1474
1475 if (*dest_dir == '\0')
1476 {
1477 g_free (def_text_secure);
1478 g_free (source_mask);
1479 g_free (dest_dir);
1480 return NULL;
1481 }
1482
1483 ctx->search_handle = mc_search_new (source_mask, NULL);
1484 if (ctx->search_handle != NULL)
1485 break;
1486
1487 message (D_ERROR, MSG_ERROR, _ ("Invalid source pattern '%s'"), source_mask);
1488 MC_PTR_FREE (dest_dir);
1489 MC_PTR_FREE (source_mask);
1490 }
1491
1492 g_free (def_text_secure);
1493 g_free (source_mask);
1494
1495 ctx->search_handle->is_case_sensitive = TRUE;
1496 if (source_easy_patterns)
1497 ctx->search_handle->search_type = MC_SEARCH_T_GLOB;
1498 else
1499 ctx->search_handle->search_type = MC_SEARCH_T_REGEX;
1500
1501 tmp = dest_dir;
1502 dest_dir = tilde_expand (tmp);
1503 g_free (tmp);
1504 vpath = vfs_path_from_str (dest_dir);
1505
1506 ctx->dest_mask = strrchr (dest_dir, PATH_SEP);
1507 if (ctx->dest_mask == NULL)
1508 ctx->dest_mask = dest_dir;
1509 else
1510 ctx->dest_mask++;
1511
1512 orig_mask = ctx->dest_mask;
1513
1514 if (*ctx->dest_mask == '\0'
1515 || (!ctx->dive_into_subdirs && !is_wildcarded (ctx->dest_mask)
1516 && (!only_one || (mc_stat (vpath, &buf) == 0 && S_ISDIR (buf.st_mode))))
1517 || (ctx->dive_into_subdirs
1518 && ((!only_one && !is_wildcarded (ctx->dest_mask))
1519 || (only_one && mc_stat (vpath, &buf) == 0 && S_ISDIR (buf.st_mode)))))
1520 ctx->dest_mask = g_strdup ("\\0");
1521 else
1522 {
1523 ctx->dest_mask = g_strdup (ctx->dest_mask);
1524 *orig_mask = '\0';
1525 }
1526
1527 if (*dest_dir == '\0')
1528 {
1529 g_free (dest_dir);
1530 dest_dir = g_strdup ("./");
1531 }
1532
1533 vfs_path_free (vpath, TRUE);
1534
1535 if (val == B_USER)
1536 *do_bg = TRUE;
1537 }
1538
1539 return dest_dir;
1540 }
1541
1542