Manual pages: mcmcdiffmceditmcview

root/tests/lib/vfs/vfs_clone_file.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. copy_file_range
  2. ioctl
  3. my_clonefile
  4. reflink
  5. setup
  6. teardown
  7. prepare_files
  8. cleanup_files
  9. START_TEST
  10. START_TEST
  11. main

   1 /*
   2    lib/vfs - test vfs_clone_file() functionality
   3 
   4    Copyright (C) 2026
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Phil Krylov <phil@krylov.eu>, 2026
   9 
  10    This file is part of the Midnight Commander.
  11 
  12    The Midnight Commander is free software: you can redistribute it
  13    and/or modify it under the terms of the GNU General Public License as
  14    published by the Free Software Foundation, either version 3 of the License,
  15    or (at your option) any later version.
  16 
  17    The Midnight Commander is distributed in the hope that it will be useful,
  18    but WITHOUT ANY WARRANTY; without even the implied warranty of
  19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20    GNU General Public License for more details.
  21 
  22    You should have received a copy of the GNU General Public License
  23    along with this program.  If not, see <https://www.gnu.org/licenses/>.
  24  */
  25 
  26 #define TEST_SUITE_NAME "/lib/vfs"
  27 
  28 #include "tests/mctest.h"
  29 
  30 #include <stdarg.h>
  31 #include <stdlib.h>
  32 
  33 #ifdef HAVE_FICLONERANGE
  34 #include <linux/fs.h>   // FICLONERANGE
  35 #include <sys/ioctl.h>  // ioctl()
  36 #elif defined(HAVE_COPY_FILE_RANGE)
  37 #include <unistd.h>  // copy_file_range()
  38 #elif defined(HAVE_REFLINK)
  39 #include <unistd.h>  // reflink()
  40 #elif defined(HAVE_SYS_CLONEFILE_H)
  41 #include <sys/clonefile.h>  // clonefile()
  42 #endif
  43 
  44 #include "lib/strutil.h"
  45 #include "lib/util.h"
  46 #include "src/vfs/local/local.c"
  47 
  48 /* --------------------------------------------------------------------------------------------- */
  49 
  50 static int clone_syscall__call_count = 0;
  51 static gboolean clone_syscall__call_arguments_are_proper = FALSE;
  52 
  53 static const char test_filename1[] = "mctestclone1.tst";
  54 static const char test_filename2[] = "mctestclone2.tst";
  55 
  56 #ifdef HAVE_COPY_FILE_RANGE
  57 /* @Mock */
  58 ssize_t
  59 copy_file_range (int infd, off_t *inoffp, int outfd, off_t *outoffp, size_t len, unsigned int flags)
     /* [previous][next][first][last][top][bottom][index][help]  */
  60 {
  61     (void) infd;
  62     (void) inoffp;
  63     (void) outfd;
  64     (void) outoffp;
  65     (void) len;
  66 
  67     clone_syscall__call_count++;
  68     clone_syscall__call_arguments_are_proper = (flags == COPY_FILE_RANGE_CLONE);
  69 
  70     return -1;
  71 }
  72 #endif
  73 
  74 #ifdef HAVE_FICLONERANGE
  75 #ifdef __GLIBC__
  76 /* @Mock */
  77 int
  78 ioctl (int fd, unsigned long request, ...)
     /* [previous][next][first][last][top][bottom][index][help]  */
  79 #else  // POSIX, musl
  80 /* @Mock */
  81 int
  82 ioctl (int fd, int request, ...)
  83 #endif
  84 {
  85     (void) fd;
  86 
  87     clone_syscall__call_count++;
  88     clone_syscall__call_arguments_are_proper = (request == FICLONERANGE);
  89     return -1;
  90 }
  91 #endif
  92 
  93 #ifdef HAVE_SYS_CLONEFILE_H
  94 /* @Mock */
  95 int
  96 my_clonefile (const char *src, const char *dst, uint32_t flags)
     /* [previous][next][first][last][top][bottom][index][help]  */
  97 {
  98     (void) src;
  99     (void) dst;
 100 
 101     clone_syscall__call_count++;
 102     clone_syscall__call_arguments_are_proper = (flags == 0);
 103     return -1;
 104 }
 105 #endif
 106 
 107 #ifdef HAVE_REFLINK
 108 /* @Mock */
 109 int
 110 reflink (const char *src, const char *dst, int preserve)
     /* [previous][next][first][last][top][bottom][index][help]  */
 111 {
 112     (void) src;
 113     (void) dst;
 114 
 115     clone_syscall__call_count++;
 116     clone_syscall__call_arguments_are_proper = (preserve != 0);
 117     return -1;
 118 }
 119 #endif
 120 
 121 /* --------------------------------------------------------------------------------------------- */
 122 
 123 /* @Before */
 124 static void
 125 setup (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 126 {
 127     str_init_strings (NULL);
 128 
 129     vfs_init ();
 130     vfs_init_localfs ();
 131     vfs_setup_work_dir ();
 132 }
 133 
 134 /* --------------------------------------------------------------------------------------------- */
 135 
 136 /* @After */
 137 static void
 138 teardown (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 139 {
 140     vfs_shut ();
 141     str_uninit_strings ();
 142 }
 143 
 144 /* --------------------------------------------------------------------------------------------- */
 145 extern GPtrArray *vfs_openfiles;
 146 static void
 147 prepare_files (vfs_path_t **vpath1, vfs_path_t **vpath2)
     /* [previous][next][first][last][top][bottom][index][help]  */
 148 {
 149     unlink (test_filename1);  // remove a possible leftover from a previous run
 150     g_file_set_contents (test_filename1, "test", sizeof ("test") - 1, NULL);
 151     unlink (test_filename2);  // remove a possible leftover from a previous run
 152 
 153     *vpath1 = vfs_path_from_str (test_filename1);
 154     *vpath2 = vfs_path_from_str (test_filename2);
 155 }
 156 
 157 static void
 158 cleanup_files (vfs_path_t *vpath1, vfs_path_t *vpath2)
     /* [previous][next][first][last][top][bottom][index][help]  */
 159 {
 160     vfs_path_free (vpath1, TRUE);
 161     vfs_path_free (vpath2, TRUE);
 162     unlink (test_filename1);
 163     unlink (test_filename2);
 164 }
 165 
 166 /* @Test */
 167 START_TEST (test_vfs_clone_file)
     /* [previous][next][first][last][top][bottom][index][help]  */
 168 {
 169     vfs_path_t *vpath1;
 170     vfs_path_t *vpath2;
 171     int fdin;
 172     int fdout;
 173 
 174     // given
 175     clone_syscall__call_count = 0;
 176     clone_syscall__call_arguments_are_proper = FALSE;
 177     prepare_files (&vpath1, &vpath2);
 178     fdin = mc_open (vpath1, O_RDONLY | O_BINARY);
 179     fdout = mc_open (vpath2, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0600);
 180 
 181     // when
 182     vfs_clone_file (fdout, fdin);
 183 
 184     // then
 185 #ifdef HAVE_FILE_CLONING_BY_RANGE
 186     ck_assert (clone_syscall__call_count > 0);
 187     ck_assert (clone_syscall__call_arguments_are_proper);
 188 #else
 189     ck_assert (errno == ENOTSUP);
 190 #endif
 191 
 192     // cleanup
 193     mc_close (fdout);
 194     mc_close (fdin);
 195     cleanup_files (vpath1, vpath2);
 196 }
 197 END_TEST
 198 
 199 /* --------------------------------------------------------------------------------------------- */
 200 
 201 /* @Test */
 202 START_TEST (test_vfs_clone_file_by_path)
     /* [previous][next][first][last][top][bottom][index][help]  */
 203 {
 204     vfs_path_t *vpath1;
 205     vfs_path_t *vpath2;
 206 
 207     // given
 208     clone_syscall__call_count = 0;
 209     clone_syscall__call_arguments_are_proper = FALSE;
 210     prepare_files (&vpath1, &vpath2);
 211 
 212     // when
 213     vfs_clone_file_by_path (vpath1, vpath2, TRUE);
 214 
 215     // then
 216 #ifdef HAVE_FILE_CLONING_BY_PATH
 217     ck_assert (clone_syscall__call_count > 0);
 218     ck_assert (clone_syscall__call_arguments_are_proper);
 219 #else
 220     ck_assert (errno == ENOTSUP);
 221 #endif
 222 
 223     // cleanup
 224     cleanup_files (vpath1, vpath2);
 225 }
 226 END_TEST
 227 
 228 /* --------------------------------------------------------------------------------------------- */
 229 
 230 int
 231 main (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 232 {
 233     TCase *tc_core;
 234 
 235     tc_core = tcase_create ("Core");
 236 
 237     tcase_add_checked_fixture (tc_core, setup, teardown);
 238 
 239     // Add new tests here: ***************
 240     tcase_add_test (tc_core, test_vfs_clone_file);
 241     tcase_add_test (tc_core, test_vfs_clone_file_by_path);
 242     // ***********************************
 243 
 244     return mctest_run_all (tc_core);
 245 }

/* [previous][next][first][last][top][bottom][index][help]  */