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 : */ |