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