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