]>
Commit | Line | Data |
---|---|---|
fc22118d | 1 | /* |
267ae092 | 2 | * 9p xattr callback |
fc22118d AK |
3 | * |
4 | * Copyright IBM, Corp. 2010 | |
5 | * | |
6 | * Authors: | |
7 | * Aneesh Kumar K.V <[email protected]> | |
8 | * | |
9 | * This work is licensed under the terms of the GNU GPL, version 2. See | |
10 | * the COPYING file in the top-level directory. | |
11 | * | |
12 | */ | |
13 | ||
fbc04127 | 14 | #include "qemu/osdep.h" |
ebe74f8b | 15 | #include "9p.h" |
353ac78d | 16 | #include "fsdev/file-op-9p.h" |
267ae092 | 17 | #include "9p-xattr.h" |
56ad3e54 GK |
18 | #include "9p-util.h" |
19 | #include "9p-local.h" | |
fc22118d AK |
20 | |
21 | ||
22 | static XattrOperations *get_xattr_operations(XattrOperations **h, | |
23 | const char *name) | |
24 | { | |
25 | XattrOperations *xops; | |
26 | for (xops = *(h)++; xops != NULL; xops = *(h)++) { | |
27 | if (!strncmp(name, xops->name, strlen(xops->name))) { | |
28 | return xops; | |
29 | } | |
30 | } | |
31 | return NULL; | |
32 | } | |
33 | ||
34 | ssize_t v9fs_get_xattr(FsContext *ctx, const char *path, | |
35 | const char *name, void *value, size_t size) | |
36 | { | |
37 | XattrOperations *xops = get_xattr_operations(ctx->xops, name); | |
38 | if (xops) { | |
39 | return xops->getxattr(ctx, path, name, value, size); | |
40 | } | |
8af00205 | 41 | errno = EOPNOTSUPP; |
fc22118d AK |
42 | return -1; |
43 | } | |
44 | ||
45 | ssize_t pt_listxattr(FsContext *ctx, const char *path, | |
46 | char *name, void *value, size_t size) | |
47 | { | |
48 | int name_size = strlen(name) + 1; | |
49 | if (!value) { | |
50 | return name_size; | |
51 | } | |
52 | ||
53 | if (size < name_size) { | |
54 | errno = ERANGE; | |
55 | return -1; | |
56 | } | |
57 | ||
9238c209 JM |
58 | /* no need for strncpy: name_size is strlen(name)+1 */ |
59 | memcpy(value, name, name_size); | |
fc22118d AK |
60 | return name_size; |
61 | } | |
62 | ||
63 | ||
64 | /* | |
65 | * Get the list and pass to each layer to find out whether | |
66 | * to send the data or not | |
67 | */ | |
68 | ssize_t v9fs_list_xattr(FsContext *ctx, const char *path, | |
69 | void *value, size_t vsize) | |
70 | { | |
71 | ssize_t size = 0; | |
4fa4ce71 | 72 | char *buffer; |
fc22118d AK |
73 | void *ovalue = value; |
74 | XattrOperations *xops; | |
75 | char *orig_value, *orig_value_start; | |
76 | ssize_t xattr_len, parsed_len = 0, attr_len; | |
77 | ||
78 | /* Get the actual len */ | |
4fa4ce71 CG |
79 | buffer = rpath(ctx, path); |
80 | xattr_len = llistxattr(buffer, value, 0); | |
0562c674 | 81 | if (xattr_len <= 0) { |
4fa4ce71 | 82 | g_free(buffer); |
0562c674 KK |
83 | return xattr_len; |
84 | } | |
fc22118d AK |
85 | |
86 | /* Now fetch the xattr and find the actual size */ | |
7267c094 | 87 | orig_value = g_malloc(xattr_len); |
4fa4ce71 CG |
88 | xattr_len = llistxattr(buffer, orig_value, xattr_len); |
89 | g_free(buffer); | |
fc22118d AK |
90 | |
91 | /* store the orig pointer */ | |
92 | orig_value_start = orig_value; | |
93 | while (xattr_len > parsed_len) { | |
94 | xops = get_xattr_operations(ctx->xops, orig_value); | |
95 | if (!xops) { | |
96 | goto next_entry; | |
97 | } | |
98 | ||
99 | if (!value) { | |
100 | size += xops->listxattr(ctx, path, orig_value, value, vsize); | |
101 | } else { | |
102 | size = xops->listxattr(ctx, path, orig_value, value, vsize); | |
103 | if (size < 0) { | |
104 | goto err_out; | |
105 | } | |
106 | value += size; | |
107 | vsize -= size; | |
108 | } | |
109 | next_entry: | |
110 | /* Got the next entry */ | |
111 | attr_len = strlen(orig_value) + 1; | |
112 | parsed_len += attr_len; | |
113 | orig_value += attr_len; | |
114 | } | |
115 | if (value) { | |
116 | size = value - ovalue; | |
117 | } | |
118 | ||
119 | err_out: | |
7267c094 | 120 | g_free(orig_value_start); |
fc22118d AK |
121 | return size; |
122 | } | |
123 | ||
124 | int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name, | |
125 | void *value, size_t size, int flags) | |
126 | { | |
127 | XattrOperations *xops = get_xattr_operations(ctx->xops, name); | |
128 | if (xops) { | |
129 | return xops->setxattr(ctx, path, name, value, size, flags); | |
130 | } | |
8af00205 | 131 | errno = EOPNOTSUPP; |
fc22118d AK |
132 | return -1; |
133 | ||
134 | } | |
135 | ||
136 | int v9fs_remove_xattr(FsContext *ctx, | |
137 | const char *path, const char *name) | |
138 | { | |
139 | XattrOperations *xops = get_xattr_operations(ctx->xops, name); | |
140 | if (xops) { | |
141 | return xops->removexattr(ctx, path, name); | |
142 | } | |
8af00205 | 143 | errno = EOPNOTSUPP; |
fc22118d AK |
144 | return -1; |
145 | ||
146 | } | |
147 | ||
56ad3e54 GK |
148 | ssize_t local_getxattr_nofollow(FsContext *ctx, const char *path, |
149 | const char *name, void *value, size_t size) | |
56fc494b | 150 | { |
56ad3e54 GK |
151 | char *dirpath = g_path_get_dirname(path); |
152 | char *filename = g_path_get_basename(path); | |
153 | int dirfd; | |
154 | ssize_t ret = -1; | |
155 | ||
156 | dirfd = local_opendir_nofollow(ctx, dirpath); | |
157 | if (dirfd == -1) { | |
158 | goto out; | |
159 | } | |
56fc494b | 160 | |
56ad3e54 GK |
161 | ret = fgetxattrat_nofollow(dirfd, filename, name, value, size); |
162 | close_preserve_errno(dirfd); | |
163 | out: | |
164 | g_free(dirpath); | |
165 | g_free(filename); | |
56fc494b GK |
166 | return ret; |
167 | } | |
168 | ||
56ad3e54 GK |
169 | ssize_t pt_getxattr(FsContext *ctx, const char *path, const char *name, |
170 | void *value, size_t size) | |
171 | { | |
172 | return local_getxattr_nofollow(ctx, path, name, value, size); | |
173 | } | |
174 | ||
56fc494b GK |
175 | int pt_setxattr(FsContext *ctx, const char *path, const char *name, void *value, |
176 | size_t size, int flags) | |
177 | { | |
178 | char *buffer; | |
179 | int ret; | |
180 | ||
181 | buffer = rpath(ctx, path); | |
182 | ret = lsetxattr(buffer, name, value, size, flags); | |
183 | g_free(buffer); | |
184 | return ret; | |
185 | } | |
186 | ||
187 | int pt_removexattr(FsContext *ctx, const char *path, const char *name) | |
188 | { | |
189 | char *buffer; | |
190 | int ret; | |
191 | ||
192 | buffer = rpath(ctx, path); | |
193 | ret = lremovexattr(path, name); | |
194 | g_free(buffer); | |
195 | return ret; | |
196 | } | |
197 | ||
198 | ssize_t notsup_getxattr(FsContext *ctx, const char *path, const char *name, | |
199 | void *value, size_t size) | |
200 | { | |
201 | errno = ENOTSUP; | |
202 | return -1; | |
203 | } | |
204 | ||
205 | int notsup_setxattr(FsContext *ctx, const char *path, const char *name, | |
206 | void *value, size_t size, int flags) | |
207 | { | |
208 | errno = ENOTSUP; | |
209 | return -1; | |
210 | } | |
211 | ||
212 | ssize_t notsup_listxattr(FsContext *ctx, const char *path, char *name, | |
213 | void *value, size_t size) | |
214 | { | |
215 | return 0; | |
216 | } | |
217 | ||
218 | int notsup_removexattr(FsContext *ctx, const char *path, const char *name) | |
219 | { | |
220 | errno = ENOTSUP; | |
221 | return -1; | |
222 | } | |
223 | ||
fc22118d AK |
224 | XattrOperations *mapped_xattr_ops[] = { |
225 | &mapped_user_xattr, | |
70fc55eb AK |
226 | &mapped_pacl_xattr, |
227 | &mapped_dacl_xattr, | |
fc22118d AK |
228 | NULL, |
229 | }; | |
230 | ||
231 | XattrOperations *passthrough_xattr_ops[] = { | |
232 | &passthrough_user_xattr, | |
70fc55eb | 233 | &passthrough_acl_xattr, |
fc22118d AK |
234 | NULL, |
235 | }; | |
236 | ||
237 | /* for .user none model should be same as passthrough */ | |
238 | XattrOperations *none_xattr_ops[] = { | |
239 | &passthrough_user_xattr, | |
70fc55eb | 240 | &none_acl_xattr, |
fc22118d AK |
241 | NULL, |
242 | }; |