1#!/bin/sh
2# Test cp handles extents correctly
3
4# Copyright (C) 2011-2023 Free Software Foundation, Inc.
5
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15
16# You should have received a copy of the GNU General Public License
17# along with this program.  If not, see <https://www.gnu.org/licenses/>.
18
19. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
20print_ver_ cp
21
22require_sparse_support_
23
24touch sparse_chk || framework_failure_
25seek_data_capable_ sparse_chk ||
26  skip_ 'insufficient SEEK_DATA support'
27
28fallocate --help >/dev/null || skip_ 'The fallocate utility is required'
29touch falloc.test || framework_failure_
30fallocate -l 1 -o 1 -n falloc.test ||
31  skip_ 'this file system lacks FALLOCATE support'
32rm falloc.test
33
34# We don't currently handle unwritten extents specially
35if false; then
36# Require more space than we'll actually use, so that
37# tests run in parallel do not run out of space.
38# Otherwise, with inadequate space, simply running the following
39# fallocate command would induce a temporary file-system-full condition,
40# which would cause failure of unrelated tests run in parallel.
41require_file_system_bytes_free_ 800000000
42
43fallocate -l 1MiB num.test ||
44  skip_ "this fallocate doesn't support numbers with IEX suffixes"
45
46fallocate -l 600MiB space.test ||
47  skip_ 'this test needs at least 600MiB free space'
48
49# Disable this test on old BTRFS (e.g. Fedora 14)
50# which reports ordinary extents for unwritten ones.
51filefrag space.test || skip_ 'the 'filefrag' utility is missing'
52filefrag -v space.test | grep -F 'unwritten' > /dev/null ||
53  skip_ 'this file system does not report empty extents as "unwritten"'
54
55rm space.test
56
57# Ensure we read a large empty file quickly
58fallocate -l 300MiB empty.big || framework_failure_
59timeout 3 cp --reflink=never --sparse=always empty.big cp.test || fail=1
60test $(stat -c %s empty.big) = $(stat -c %s cp.test) || fail=1
61rm empty.big cp.test
62fi
63
64# Ensure we handle extents beyond file size correctly.
65# Note until we support fallocate, we will not maintain
66# the file allocation.  FIXME: amend this test if fallocate is supported.
67# Note currently this only uses SEEK_DATA logic when the allocation (-l)
68# is smaller than the size, thus identifying the file as sparse.
69# Note the '-l 1' case is an effective noop, and just checks
70# a file with a trailing hole is copied correctly.
71for sparse_arg in always auto never; do
72  for alloc in '-l 4194304' '-l 1048576 -o 4194304' '-l 1'; do
73    dd count=10 if=/dev/urandom iflag=fullblock of=unwritten.withdata
74    truncate -s 2MiB unwritten.withdata || framework_failure_
75    fallocate $alloc -n unwritten.withdata || framework_failure_
76    cp --reflink=never --sparse=$sparse_arg unwritten.withdata cp.test || fail=1
77    test $(stat -c %s unwritten.withdata) = $(stat -c %s cp.test) || fail=1
78    cmp unwritten.withdata cp.test || fail=1
79    rm unwritten.withdata cp.test || framework_failure_
80  done
81done
82
83Exit $fail
84