aboutsummaryrefslogtreecommitdiff
path: root/hw/9pfs/9p-util-freebsd.c
blob: 9dd1d069f67d0283b1f3a8b97ca31a220d819299 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
 * 9p utilities (FreeBSD Implementation)
 *
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
 * See the COPYING file in the top-level directory.
 */

/*
 * Not so fast! You might want to read the 9p developer docs first:
 * https://wiki.qemu.org/Documentation/9p
 */

#include "qemu/osdep.h"
#include "qemu/xattr.h"
#include "9p-util.h"

static int mangle_xattr_name(const char **namep)
{
    const char *name = *namep;

    /*
     * ZFS forbids attributes in starting with "user." or "system.".
     */
    if (strncmp(name, "system.", 7) == 0) {
        *namep = name + 7;
        return EXTATTR_NAMESPACE_SYSTEM;
    }
    if (strncmp(name, "user.", 5) == 0) {
        *namep = name + 5;
    }
    return EXTATTR_NAMESPACE_USER;
}

ssize_t fgetxattr(int fd, const char *name, void *value, size_t size)
{
    int namespace;

    namespace = mangle_xattr_name(&name);
    return extattr_get_fd(fd, namespace, name, value, size);
}

ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name,
                             void *value, size_t size)
{
    ssize_t ret;
    int fd, namespace;

    fd = openat_file(dirfd, filename,
                     O_RDONLY | O_PATH_9P_UTIL | O_NOFOLLOW, 0);
    if (fd == -1) {
        return -1;
    }
    namespace = mangle_xattr_name(&name);
    ret = extattr_get_fd(fd, namespace, name, value, size);
    close_preserve_errno(fd);
    return ret;
}

ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
                              char *list, size_t size)
{
    ssize_t ret;
    int fd;

    fd = openat_file(dirfd, filename,
                     O_RDONLY | O_PATH_9P_UTIL | O_NOFOLLOW, 0);
    if (fd == -1) {
        return -1;
    }
    ret = extattr_list_fd(fd, EXTATTR_NAMESPACE_USER, list, size);
    close_preserve_errno(fd);
    return ret;
}

ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
                                const char *name)
{
    int fd, namespace, ret;

    fd = openat_file(dirfd, filename,
                     O_RDONLY | O_PATH_9P_UTIL | O_NOFOLLOW, 0);
    if (fd == -1) {
        return -1;
    }
    namespace = mangle_xattr_name(&name);
    ret = extattr_delete_fd(fd, namespace, name);
    close_preserve_errno(fd);
    return ret;
}

int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name,
                         void *value, size_t size, int flags)
{
    ssize_t ret;
    int fd, namespace;

    namespace = mangle_xattr_name(&name);
    if (flags == (XATTR_CREATE | XATTR_REPLACE)) {
        errno = EINVAL;
        return -1;
    }
    fd = openat_file(dirfd, filename,
                     O_RDONLY | O_PATH_9P_UTIL | O_NOFOLLOW, 0);
    if (fd == -1) {
        return -1;
    }
    if (flags & (XATTR_CREATE | XATTR_REPLACE)) {
        ret = extattr_get_fd(fd, namespace, name, NULL, 0);
        if (ret == -1 && errno != ENOATTR) {
            close_preserve_errno(fd);
            return -1;
        }
        if (ret >= 0 && (flags & XATTR_CREATE)) {
            errno = EEXIST;
            close_preserve_errno(fd);
            return -1;
        }
        if (ret == -1 && (flags & XATTR_REPLACE)) {
            errno = ENOATTR;
            close_preserve_errno(fd);
            return -1;
        }
    }
    ret = extattr_set_fd(fd, namespace, name, value, size);
    close_preserve_errno(fd);
    return ret;
}

int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev)
{
    return mknodat(dirfd, filename, mode, dev);
}