Coverage Report

Created: 2026-04-29 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/systemd/src/basic/btrfs.c
Line
Count
Source
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3
#include <linux/btrfs.h>
4
#include <sys/ioctl.h>
5
#include <sys/stat.h>
6
7
#include "alloc-util.h"
8
#include "btrfs.h"
9
#include "errno-util.h"
10
#include "fd-util.h"
11
#include "path-util.h"
12
#include "string-util.h"
13
14
0
int btrfs_validate_subvolume_name(const char *name) {
15
16
0
        if (!filename_is_valid(name))
17
0
                return -EINVAL;
18
19
0
        if (strlen(name) > BTRFS_SUBVOL_NAME_MAX)
20
0
                return -E2BIG;
21
22
0
        return 0;
23
0
}
24
25
0
static int extract_subvolume_name(const char *path, char **ret) {
26
0
        _cleanup_free_ char *fn = NULL;
27
0
        int r;
28
29
0
        assert(path);
30
0
        assert(ret);
31
32
0
        r = path_extract_filename(path, &fn);
33
0
        if (r < 0)
34
0
                return r;
35
36
0
        r = btrfs_validate_subvolume_name(fn);
37
0
        if (r < 0)
38
0
                return r;
39
40
0
        *ret = TAKE_PTR(fn);
41
0
        return 0;
42
0
}
43
44
0
int btrfs_subvol_make(int dir_fd, const char *path) {
45
0
        struct btrfs_ioctl_vol_args args = {};
46
0
        _cleanup_free_ char *subvolume = NULL, *parent = NULL;
47
0
        _cleanup_close_ int fd = -EBADF;
48
0
        int r;
49
50
0
        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
51
0
        assert(!isempty(path));
52
53
0
        r = extract_subvolume_name(path, &subvolume);
54
0
        if (r < 0)
55
0
                return r;
56
57
0
        r = path_extract_directory(path, &parent);
58
0
        if (r < 0) {
59
0
                if (r != -EDESTADDRREQ) /* Propagate error, unless only a filename was specified, which is OK */
60
0
                        return r;
61
62
0
                dir_fd = fd_reopen_condition(dir_fd, O_CLOEXEC, O_PATH, &fd); /* drop O_PATH if it is set */
63
0
                if (dir_fd < 0)
64
0
                        return dir_fd;
65
0
        } else {
66
0
                fd = openat(dir_fd, parent, O_DIRECTORY|O_RDONLY|O_CLOEXEC, 0);
67
0
                if (fd < 0)
68
0
                        return -errno;
69
70
0
                dir_fd = fd;
71
0
        }
72
73
0
        strncpy(args.name, subvolume, sizeof(args.name)-1);
74
75
0
        return RET_NERRNO(ioctl(dir_fd, BTRFS_IOC_SUBVOL_CREATE, &args));
76
0
}
77
78
0
int btrfs_subvol_make_fallback(int dir_fd, const char *path, mode_t mode) {
79
0
        mode_t old, combined;
80
0
        int r;
81
82
0
        assert(path);
83
84
        /* Let's work like mkdir(), i.e. take the specified mode, and mask it with the current umask. */
85
0
        old = umask(~mode);
86
0
        combined = old | ~mode;
87
0
        if (combined != ~mode)
88
0
                umask(combined);
89
0
        r = btrfs_subvol_make(dir_fd, path);
90
0
        umask(old);
91
92
0
        if (r >= 0)
93
0
                return 1; /* subvol worked */
94
0
        if (!ERRNO_IS_NOT_SUPPORTED(r))
95
0
                return r;
96
97
0
        if (mkdirat(dir_fd, path, mode) < 0)
98
0
                return -errno;
99
100
0
        return 0; /* plain directory */
101
0
}