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