xaizek / vifm (License: GPLv2+) (since 2018-12-07)
Vifm is a file manager with curses interface, which provides Vi[m]-like environment for managing objects within file systems, extended with some useful ideas from mutt.
Commit cd31eebe43d310c8d30128d4f302c174ab41d234

Implement deep file copying in ior_cp()
Author: xaizek
Author date (UTC): 2026-02-01 14:09
Committer name: xaizek
Committer date (UTC): 2026-02-19 09:45
Parent(s): 4f18017ba9ef0241ec2aef86fcb29ec04dafc913
Signing key: 99DC5E4DB05F6BE2
Tree: 06d876ddcc6cf7b097267ea81ee1b3013c6a7977
File Lines added Lines deleted
src/io/ior.c 3 1
tests/ior/cp.c 128 0
tests/ior/suite.c 2 0
File src/io/ior.c changed (mode: 100644) (index 89ebdc394..9cb067895)
... ... ior_cp(io_args_t *args)
122 122 { {
123 123 const char *const src = args->arg1.src; const char *const src = args->arg1.src;
124 124 const char *const dst = args->arg2.dst; const char *const dst = args->arg2.dst;
125 const int deep_copying = args->arg4.deep_copying;
125 126
126 127 if(is_in_subtree(dst, src, 0)) if(is_in_subtree(dst, src, 0))
127 128 { {
 
... ... ior_cp(io_args_t *args)
154 155 } }
155 156 } }
156 157
157 return traverse(src, /*deep=*/0, &cp_visitor, args);
158 return traverse(src, deep_copying, &cp_visitor, args);
158 159 } }
159 160
160 161 /* Implementation of traverse() visitor for subtree copying. Returns 0 on /* Implementation of traverse() visitor for subtree copying. Returns 0 on
 
... ... cp_mv_visitor(const char full_path[], VisitAction action, void *param, int cp)
432 433 /* It's safe to always use fast file cloning on moving files. */ /* It's safe to always use fast file cloning on moving files. */
433 434 .arg4.fast_file_cloning = cp ? cp_args->arg4.fast_file_cloning : 1, .arg4.fast_file_cloning = cp ? cp_args->arg4.fast_file_cloning : 1,
434 435 .arg4.data_sync = cp_args->arg4.data_sync, .arg4.data_sync = cp_args->arg4.data_sync,
436 .arg4.deep_copying = cp ? cp_args->arg4.deep_copying : 0,
435 437
436 438 .cancellation = cp_args->cancellation, .cancellation = cp_args->cancellation,
437 439 .confirm = cp_args->confirm, .confirm = cp_args->confirm,
File tests/ior/cp.c changed (mode: 100644) (index fb3d408fa..0829b494f)
6 6
7 7 #include <test-utils.h> #include <test-utils.h>
8 8
9 #include "../../src/compat/fs_limits.h"
9 10 #include "../../src/compat/os.h" #include "../../src/compat/os.h"
10 11 #include "../../src/io/iop.h" #include "../../src/io/iop.h"
11 12 #include "../../src/io/ior.h" #include "../../src/io/ior.h"
 
... ... TEST(symlink_to_dir_is_symlink_after_copy, IF(not_windows))
652 653 } }
653 654 } }
654 655
656 /* Creating symbolic links on Windows requires administrator rights. */
657 TEST(symlink_to_dir_is_dir_after_copy, IF(not_windows))
658 {
659 {
660 char path[PATH_MAX + 1];
661 io_args_t args = {
662 .arg1.path = path,
663 .arg2.target = SANDBOX_PATH "/sym-link",
664 };
665 ioe_errlst_init(&args.result.errors);
666
667 make_abs_path(path, sizeof(path), TEST_DATA_PATH, "read", NULL);
668 assert_int_equal(IO_RES_SUCCEEDED, iop_ln(&args));
669 assert_int_equal(0, args.result.errors.error_count);
670 }
671
672 assert_true(is_symlink(SANDBOX_PATH "/sym-link"));
673
674 {
675 io_args_t args = {
676 .arg1.src = SANDBOX_PATH "/sym-link",
677 .arg2.dst = SANDBOX_PATH "/sym-link-copy",
678 .arg4.deep_copying = 1,
679 };
680 ioe_errlst_init(&args.result.errors);
681
682 assert_int_equal(IO_RES_SUCCEEDED, ior_cp(&args));
683 assert_int_equal(0, args.result.errors.error_count);
684 }
685
686 assert_true(is_symlink(SANDBOX_PATH "/sym-link"));
687 assert_false(is_symlink(SANDBOX_PATH "/sym-link-copy"));
688 assert_true(is_dir(SANDBOX_PATH "/sym-link-copy"));
689
690 {
691 io_args_t args = {
692 .arg1.path = SANDBOX_PATH "/sym-link",
693 };
694 ioe_errlst_init(&args.result.errors);
695
696 assert_int_equal(IO_RES_SUCCEEDED, iop_rmfile(&args));
697 assert_int_equal(0, args.result.errors.error_count);
698 }
699
700 /* Needed to be able to remove files from it. */
701 assert_success(chmod(SANDBOX_PATH "/sym-link-copy", 0700));
702
703 {
704 io_args_t args = {
705 .arg1.path = SANDBOX_PATH "/sym-link-copy",
706 };
707 ioe_errlst_init(&args.result.errors);
708
709 assert_int_equal(IO_RES_SUCCEEDED, ior_rm(&args));
710 assert_int_equal(0, args.result.errors.error_count);
711 }
712 }
713
714 /* Creating symbolic links on Windows requires administrator rights. */
715 TEST(nested_symlink_to_dir_is_dir_after_copy, IF(not_windows))
716 {
717 {
718 io_args_t args = {
719 .arg1.path = SANDBOX_PATH "/dir",
720 .arg3.mode = 0700,
721 };
722 ioe_errlst_init(&args.result.errors);
723
724 assert_int_equal(IO_RES_SUCCEEDED, iop_mkdir(&args));
725 assert_int_equal(0, args.result.errors.error_count);
726 }
727
728 {
729 char path[PATH_MAX + 1];
730 io_args_t args = {
731 .arg1.path = path,
732 .arg2.target = SANDBOX_PATH "/dir/sym-link",
733 };
734 ioe_errlst_init(&args.result.errors);
735
736 make_abs_path(path, sizeof(path), TEST_DATA_PATH, "read", NULL);
737 assert_int_equal(IO_RES_SUCCEEDED, iop_ln(&args));
738 assert_int_equal(0, args.result.errors.error_count);
739 }
740
741 assert_true(is_symlink(SANDBOX_PATH "/dir/sym-link"));
742
743 {
744 io_args_t args = {
745 .arg1.src = SANDBOX_PATH "/dir",
746 .arg2.dst = SANDBOX_PATH "/dir-copy",
747 .arg4.deep_copying = 1,
748 };
749 ioe_errlst_init(&args.result.errors);
750
751 assert_int_equal(IO_RES_SUCCEEDED, ior_cp(&args));
752 assert_int_equal(0, args.result.errors.error_count);
753 }
754
755 assert_true(is_symlink(SANDBOX_PATH "/dir/sym-link"));
756 assert_false(is_symlink(SANDBOX_PATH "/dir-copy/sym-link"));
757 assert_true(is_dir(SANDBOX_PATH "/dir-copy/sym-link"));
758
759 {
760 io_args_t args = {
761 .arg1.path = SANDBOX_PATH "/dir",
762 };
763 ioe_errlst_init(&args.result.errors);
764
765 assert_int_equal(IO_RES_SUCCEEDED, ior_rm(&args));
766 assert_int_equal(0, args.result.errors.error_count);
767 }
768
769 /* Needed to be able to remove files from it. */
770 assert_success(chmod(SANDBOX_PATH "/dir-copy/sym-link", 0700));
771
772 {
773 io_args_t args = {
774 .arg1.path = SANDBOX_PATH "/dir-copy",
775 };
776 ioe_errlst_init(&args.result.errors);
777
778 assert_int_equal(IO_RES_SUCCEEDED, ior_rm(&args));
779 assert_int_equal(0, args.result.errors.error_count);
780 }
781 }
782
655 783 static int static int
656 784 confirm_overwrite(io_args_t *args, const char src[], const char dst[]) confirm_overwrite(io_args_t *args, const char src[], const char dst[])
657 785 { {
File tests/ior/suite.c changed (mode: 100644) (index f78a2e5cf..2ef32e68b)
... ... SETUP()
11 11 { {
12 12 cfg.shell = strdup("/bin/bash"); cfg.shell = strdup("/bin/bash");
13 13 cfg.shell_cmd_flag = strdup("-c"); cfg.shell_cmd_flag = strdup("-c");
14 cfg.slow_fs_list = strdup("");
14 15 } }
15 16
16 17 TEARDOWN() TEARDOWN()
17 18 { {
18 19 free(cfg.shell_cmd_flag); free(cfg.shell_cmd_flag);
19 20 free(cfg.shell); free(cfg.shell);
21 free(cfg.slow_fs_list);
20 22 } }
21 23
22 24 /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */ /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/vifm

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/vifm

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master