| File src/fops_put.c changed (mode: 100644) (index 794f017df..798211f5a) |
| ... |
... |
static int is_dir_clash(const char src_path[], const char dst_dir[]); |
| 59 |
59 |
static int put_files_i(view_t *view, int start); |
static int put_files_i(view_t *view, int start); |
| 60 |
60 |
static void update_cursor_position(view_t *view); |
static void update_cursor_position(view_t *view); |
| 61 |
61 |
static int put_next(int force); |
static int put_next(int force); |
|
62 |
|
static int unprocessed_dirs_present(void); |
| 62 |
63 |
TSTATIC int merge_dirs(const char src[], const char dst[], ops_t *ops); |
TSTATIC int merge_dirs(const char src[], const char dst[], ops_t *ops); |
| 63 |
64 |
static int handle_clashing(int move, const char src[], const char dst[]); |
static int handle_clashing(int move, const char src[], const char dst[]); |
| 64 |
65 |
static void prompt_what_to_do(const char fname[], const char caused_by[]); |
static void prompt_what_to_do(const char fname[], const char caused_by[]); |
| |
| ... |
... |
static struct |
| 85 |
86 |
int overwrite_all; /* Overwrite all future conflicting files/directories. */ |
int overwrite_all; /* Overwrite all future conflicting files/directories. */ |
| 86 |
87 |
int append; /* Whether we're appending ending of a file or not. */ |
int append; /* Whether we're appending ending of a file or not. */ |
| 87 |
88 |
int allow_merge; /* Allow merging of files in directories. */ |
int allow_merge; /* Allow merging of files in directories. */ |
|
89 |
|
int allow_merge_all; /* Allow merging of files in directories by default. */ |
| 88 |
90 |
int merge; /* Merge conflicting directory once. */ |
int merge; /* Merge conflicting directory once. */ |
| 89 |
91 |
int merge_all; /* Merge all conflicting directories. */ |
int merge_all; /* Merge all conflicting directories. */ |
| 90 |
92 |
ops_t *ops; /* Currently running operation. */ |
ops_t *ops; /* Currently running operation. */ |
| |
| ... |
... |
put_next(int force) |
| 639 |
641 |
else |
else |
| 640 |
642 |
{ |
{ |
| 641 |
643 |
struct stat dst_st; |
struct stat dst_st; |
| 642 |
|
put_confirm.allow_merge = os_lstat(dst_buf, &dst_st) == 0 && |
|
| 643 |
|
S_ISDIR(dst_st.st_mode) && S_ISDIR(src_st.st_mode); |
|
|
644 |
|
put_confirm.allow_merge = S_ISDIR(src_st.st_mode) |
|
645 |
|
&& (os_lstat(dst_buf, &dst_st) == 0) |
|
646 |
|
&& S_ISDIR(dst_st.st_mode); |
|
647 |
|
|
|
648 |
|
/* Enable "merge all" in conflict resolution options if at least one of |
|
649 |
|
* source paths left to process (including current) is a directory. */ |
|
650 |
|
put_confirm.allow_merge_all = unprocessed_dirs_present(); |
|
651 |
|
|
| 644 |
652 |
prompt_what_to_do(dst_name, src_buf); |
prompt_what_to_do(dst_name, src_buf); |
| 645 |
653 |
return 1; |
return 1; |
| 646 |
654 |
} |
} |
| |
| ... |
... |
put_next(int force) |
| 771 |
779 |
return 0; |
return 0; |
| 772 |
780 |
} |
} |
| 773 |
781 |
|
|
|
782 |
|
/* Checks whether current or any other unprocessed paths point to directories. |
|
783 |
|
* Returns non-zero if so, otherwise zero is returned. */ |
|
784 |
|
static int |
|
785 |
|
unprocessed_dirs_present(void) |
|
786 |
|
{ |
|
787 |
|
int i; |
|
788 |
|
for(i = put_confirm.index; i < put_confirm.reg->nfiles; ++i) |
|
789 |
|
{ |
|
790 |
|
const char *path = put_confirm.reg->files[put_confirm.file_order[i]]; |
|
791 |
|
if(path == NULL) |
|
792 |
|
{ |
|
793 |
|
/* This file has been excluded from processing. */ |
|
794 |
|
continue; |
|
795 |
|
} |
|
796 |
|
|
|
797 |
|
struct stat src_st; |
|
798 |
|
if(os_lstat(path, &src_st) == 0 && S_ISDIR(src_st.st_mode)) |
|
799 |
|
{ |
|
800 |
|
return 1; |
|
801 |
|
} |
|
802 |
|
} |
|
803 |
|
return 0; |
|
804 |
|
} |
|
805 |
|
|
| 774 |
806 |
/* Merges src into dst. Returns zero on success, otherwise non-zero is |
/* Merges src into dst. Returns zero on success, otherwise non-zero is |
| 775 |
807 |
* returned. */ |
* returned. */ |
| 776 |
808 |
TSTATIC int |
TSTATIC int |
| |
| ... |
... |
prompt_what_to_do(const char fname[], const char caused_by[]) |
| 948 |
980 |
/* Strange spacing is for left alignment. Doesn't look nice here, but it is |
/* Strange spacing is for left alignment. Doesn't look nice here, but it is |
| 949 |
981 |
* problematic to get such alignment otherwise. */ |
* problematic to get such alignment otherwise. */ |
| 950 |
982 |
static const response_variant |
static const response_variant |
| 951 |
|
compare = { .key = 'c', .descr = "[c]ompare files \n" }, |
|
| 952 |
|
rename = { .key = 'r', .descr = "[r]ename (also Enter) \n" }, |
|
| 953 |
|
enter = { .key = '\r', .descr = "" }, |
|
| 954 |
|
skip = { .key = 's', .descr = "[s]kip " }, |
|
| 955 |
|
skip_all = { .key = 'S', .descr = " [S]kip all \n" }, |
|
| 956 |
|
append = { .key = 'a', .descr = "[a]ppend the tail \n" }, |
|
| 957 |
|
overwrite = { .key = 'o', .descr = "[o]verwrite " }, |
|
| 958 |
|
overwrite_all = { .key = 'O', .descr = " [O]verwrite all\n" }, |
|
| 959 |
|
merge = { .key = 'm', .descr = "[m]erge " }, |
|
| 960 |
|
merge_all = { .key = 'M', .descr = " [M]erge all \n" }, |
|
| 961 |
|
escape = { .key = NC_C_c, .descr = "\nEsc or Ctrl-C to cancel" }; |
|
|
983 |
|
compare = { .key = 'c', .descr = "[c]ompare files \n" }, |
|
984 |
|
rename = { .key = 'r', .descr = "[r]ename (also Enter) \n" }, |
|
985 |
|
enter = { .key = '\r', .descr = "" }, |
|
986 |
|
skip = { .key = 's', .descr = "[s]kip " }, |
|
987 |
|
skip_all = { .key = 'S', .descr = " [S]kip all \n" }, |
|
988 |
|
append = { .key = 'a', .descr = "[a]ppend the tail \n" }, |
|
989 |
|
overwrite = { .key = 'o', .descr = "[o]verwrite " }, |
|
990 |
|
overwrite_all = { .key = 'O', .descr = " [O]verwrite all\n" }, |
|
991 |
|
merge = { .key = 'm', .descr = "[m]erge " }, |
|
992 |
|
merge_all = { .key = 'M', .descr = " [M]erge all \n" }, |
|
993 |
|
merge_all_only = { .key = 'M', .descr = "[M]erge all \n" }, |
|
994 |
|
escape = { .key = NC_C_c, .descr = "\nEsc or Ctrl-C to cancel" }; |
| 962 |
995 |
|
|
| 963 |
996 |
char response; |
char response; |
| 964 |
|
response_variant responses[11] = {}; |
|
|
997 |
|
/* Last element is a terminator. */ |
|
998 |
|
response_variant responses[12] = {}; |
| 965 |
999 |
size_t i = 0; |
size_t i = 0; |
| 966 |
1000 |
|
|
| 967 |
1001 |
char dst_buf[PATH_MAX + 1]; |
char dst_buf[PATH_MAX + 1]; |
| |
| ... |
... |
prompt_what_to_do(const char fname[], const char caused_by[]) |
| 991 |
1025 |
if(put_confirm.allow_merge) |
if(put_confirm.allow_merge) |
| 992 |
1026 |
{ |
{ |
| 993 |
1027 |
responses[i++] = merge; |
responses[i++] = merge; |
| 994 |
|
responses[i++] = merge_all; |
|
|
1028 |
|
} |
|
1029 |
|
if(put_confirm.allow_merge_all) |
|
1030 |
|
{ |
|
1031 |
|
responses[i++] = (put_confirm.allow_merge ? merge_all : merge_all_only); |
| 995 |
1032 |
} |
} |
| 996 |
1033 |
} |
} |
| 997 |
1034 |
|
|
| 998 |
1035 |
responses[i++] = escape; |
responses[i++] = escape; |
| 999 |
|
assert(i < ARRAY_LEN(responses) && "Array is too small."); |
|
|
1036 |
|
assert(i + 1 <= ARRAY_LEN(responses) && "Array is too small."); |
| 1000 |
1037 |
|
|
| 1001 |
1038 |
/* Screen needs to be restored after displaying progress dialog. */ |
/* Screen needs to be restored after displaying progress dialog. */ |
| 1002 |
1039 |
modes_update(); |
modes_update(); |
| |
| ... |
... |
handle_prompt_response(const char fname[], const char caused_by[], |
| 1074 |
1111 |
put_confirm.merge = 1; |
put_confirm.merge = 1; |
| 1075 |
1112 |
put_continue(1); |
put_continue(1); |
| 1076 |
1113 |
} |
} |
| 1077 |
|
else if(put_confirm.allow_merge && response == 'M') |
|
|
1114 |
|
else if(put_confirm.allow_merge_all && response == 'M') |
| 1078 |
1115 |
{ |
{ |
| 1079 |
1116 |
put_confirm.merge_all = 1; |
put_confirm.merge_all = 1; |
| 1080 |
1117 |
put_continue(1); |
put_continue(1); |
| File tests/fileops/put_files.c changed (mode: 100644) (index 863ac6f69..c83329060) |
| 10 |
10 |
|
|
| 11 |
11 |
#include "../../src/cfg/config.h" |
#include "../../src/cfg/config.h" |
| 12 |
12 |
#include "../../src/compat/fs_limits.h" |
#include "../../src/compat/fs_limits.h" |
|
13 |
|
#include "../../src/modes/dialogs/msg_dialog.h" |
| 13 |
14 |
#include "../../src/utils/fs.h" |
#include "../../src/utils/fs.h" |
| 14 |
15 |
#include "../../src/utils/path.h" |
#include "../../src/utils/path.h" |
| 15 |
16 |
#include "../../src/filelist.h" |
#include "../../src/filelist.h" |
| |
| ... |
... |
static void parent_overwrite_with_put(int move); |
| 45 |
46 |
static void double_clash_with_put(int move); |
static void double_clash_with_put(int move); |
| 46 |
47 |
|
|
| 47 |
48 |
static fo_prompt_cb rename_cb; |
static fo_prompt_cb rename_cb; |
|
49 |
|
static int options_count; |
| 48 |
50 |
|
|
| 49 |
51 |
static char *saved_cwd; |
static char *saved_cwd; |
| 50 |
52 |
|
|
| |
| ... |
... |
TEARDOWN() |
| 69 |
71 |
view_teardown(&lwin); |
view_teardown(&lwin); |
| 70 |
72 |
regs_reset(); |
regs_reset(); |
| 71 |
73 |
restore_cwd(saved_cwd); |
restore_cwd(saved_cwd); |
|
74 |
|
fops_init(NULL, NULL); |
| 72 |
75 |
} |
} |
| 73 |
76 |
|
|
| 74 |
77 |
static void |
static void |
| |
| ... |
... |
static char |
| 112 |
115 |
options_prompt_abort(const char title[], const char message[], |
options_prompt_abort(const char title[], const char message[], |
| 113 |
116 |
const struct response_variant *variants) |
const struct response_variant *variants) |
| 114 |
117 |
{ |
{ |
|
118 |
|
options_count = 0; |
|
119 |
|
while(variants->key != '\0') |
|
120 |
|
{ |
|
121 |
|
++options_count; |
|
122 |
|
++variants; |
|
123 |
|
} |
|
124 |
|
|
| 115 |
125 |
return '\x03'; |
return '\x03'; |
| 116 |
126 |
} |
} |
| 117 |
127 |
|
|
| |
| ... |
... |
TEST(files_can_be_diffed) |
| 682 |
692 |
assert_success(rmdir(SANDBOX_PATH "/dir")); |
assert_success(rmdir(SANDBOX_PATH "/dir")); |
| 683 |
693 |
} |
} |
| 684 |
694 |
|
|
|
695 |
|
TEST(show_merge_all_option_if_paths_include_dir) |
|
696 |
|
{ |
|
697 |
|
char path[PATH_MAX + 1]; |
|
698 |
|
|
|
699 |
|
create_file(SANDBOX_PATH "/a"); |
|
700 |
|
create_dir(SANDBOX_PATH "/dir"); |
|
701 |
|
create_file(SANDBOX_PATH "/dir/a"); |
|
702 |
|
create_file(SANDBOX_PATH "/dir/b"); |
|
703 |
|
create_dir(SANDBOX_PATH "/dir/sub"); |
|
704 |
|
|
|
705 |
|
fops_init(&line_prompt, &options_prompt_abort); |
|
706 |
|
|
|
707 |
|
make_abs_path(path, sizeof(path), SANDBOX_PATH, "/dir/a", saved_cwd); |
|
708 |
|
assert_success(regs_append('a', path)); |
|
709 |
|
make_abs_path(path, sizeof(path), SANDBOX_PATH, "/dir/b", saved_cwd); |
|
710 |
|
assert_success(regs_append('a', path)); |
|
711 |
|
|
|
712 |
|
options_count = 0; |
|
713 |
|
(void)fops_put(&lwin, -1, 'a', 0); |
|
714 |
|
assert_int_equal(9, options_count); |
|
715 |
|
|
|
716 |
|
restore_cwd(saved_cwd); |
|
717 |
|
saved_cwd = save_cwd(); |
|
718 |
|
|
|
719 |
|
make_abs_path(path, sizeof(path), SANDBOX_PATH, "/dir/sub", saved_cwd); |
|
720 |
|
assert_success(regs_append('a', path)); |
|
721 |
|
|
|
722 |
|
options_count = 0; |
|
723 |
|
(void)fops_put(&lwin, -1, 'a', 0); |
|
724 |
|
assert_int_equal(10, options_count); |
|
725 |
|
|
|
726 |
|
restore_cwd(saved_cwd); |
|
727 |
|
saved_cwd = save_cwd(); |
|
728 |
|
|
|
729 |
|
assert_success(unlink(SANDBOX_PATH "/dir/a")); |
|
730 |
|
assert_success(unlink(SANDBOX_PATH "/dir/b")); |
|
731 |
|
assert_success(rmdir(SANDBOX_PATH "/dir/sub")); |
|
732 |
|
assert_success(rmdir(SANDBOX_PATH "/dir")); |
|
733 |
|
assert_success(unlink(SANDBOX_PATH "/a")); |
|
734 |
|
/* This one doesn't always get copied. */ |
|
735 |
|
(void)unlink(SANDBOX_PATH "/b"); |
|
736 |
|
} |
|
737 |
|
|
| 685 |
738 |
/* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */ |
/* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */ |
| 686 |
739 |
/* vim: set cinoptions+=t0 filetype=c : */ |
/* vim: set cinoptions+=t0 filetype=c : */ |