]>
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 <aneesh.kumar@linux.vnet.ibm.com> | |
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 | ||
fc22118d AK |
63 | /* |
64 | * Get the list and pass to each layer to find out whether | |
65 | * to send the data or not | |
66 | */ | |
67 | ssize_t v9fs_list_xattr(FsContext *ctx, const char *path, | |
68 | void *value, size_t vsize) | |
69 | { | |
70 | ssize_t size = 0; | |
71 | void *ovalue = value; | |
72 | XattrOperations *xops; | |
73 | char *orig_value, *orig_value_start; | |
74 | ssize_t xattr_len, parsed_len = 0, attr_len; | |
5507904e GK |
75 | char *dirpath, *name; |
76 | int dirfd; | |
fc22118d AK |
77 | |
78 | /* Get the actual len */ | |
5507904e GK |
79 | dirpath = g_path_get_dirname(path); |
80 | dirfd = local_opendir_nofollow(ctx, dirpath); | |
81 | g_free(dirpath); | |
82 | if (dirfd == -1) { | |
83 | return -1; | |
84 | } | |
85 | ||
86 | name = g_path_get_basename(path); | |
87 | xattr_len = flistxattrat_nofollow(dirfd, name, value, 0); | |
0562c674 | 88 | if (xattr_len <= 0) { |
5507904e GK |
89 | g_free(name); |
90 | close_preserve_errno(dirfd); | |
0562c674 KK |
91 | return xattr_len; |
92 | } | |
fc22118d AK |
93 | |
94 | /* Now fetch the xattr and find the actual size */ | |
7267c094 | 95 | orig_value = g_malloc(xattr_len); |
5507904e GK |
96 | xattr_len = flistxattrat_nofollow(dirfd, name, orig_value, xattr_len); |
97 | g_free(name); | |
98 | close_preserve_errno(dirfd); | |
99 | if (xattr_len < 0) { | |
4ffcdef4 | 100 | g_free(orig_value); |
5507904e GK |
101 | return -1; |
102 | } | |
fc22118d AK |
103 | |
104 | /* store the orig pointer */ | |
105 | orig_value_start = orig_value; | |
106 | while (xattr_len > parsed_len) { | |
107 | xops = get_xattr_operations(ctx->xops, orig_value); | |
108 | if (!xops) { | |
109 | goto next_entry; | |
110 | } | |
111 | ||
112 | if (!value) { | |
113 | size += xops->listxattr(ctx, path, orig_value, value, vsize); | |
114 | } else { | |
115 | size = xops->listxattr(ctx, path, orig_value, value, vsize); | |
116 | if (size < 0) { | |
117 | goto err_out; | |
118 | } | |
119 | value += size; | |
120 | vsize -= size; | |
121 | } | |
122 | next_entry: | |
123 | /* Got the next entry */ | |
124 | attr_len = strlen(orig_value) + 1; | |
125 | parsed_len += attr_len; | |
126 | orig_value += attr_len; | |
127 | } | |
128 | if (value) { | |
129 | size = value - ovalue; | |
130 | } | |
131 | ||
132 | err_out: | |
7267c094 | 133 | g_free(orig_value_start); |
fc22118d AK |
134 | return size; |
135 | } | |
136 | ||
137 | int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name, | |
138 | void *value, size_t size, int flags) | |
139 | { | |
140 | XattrOperations *xops = get_xattr_operations(ctx->xops, name); | |
141 | if (xops) { | |
142 | return xops->setxattr(ctx, path, name, value, size, flags); | |
143 | } | |
8af00205 | 144 | errno = EOPNOTSUPP; |
fc22118d AK |
145 | return -1; |
146 | ||
147 | } | |
148 | ||
149 | int v9fs_remove_xattr(FsContext *ctx, | |
150 | const char *path, const char *name) | |
151 | { | |
152 | XattrOperations *xops = get_xattr_operations(ctx->xops, name); | |
153 | if (xops) { | |
154 | return xops->removexattr(ctx, path, name); | |
155 | } | |
8af00205 | 156 | errno = EOPNOTSUPP; |
fc22118d AK |
157 | return -1; |
158 | ||
159 | } | |
160 | ||
56ad3e54 GK |
161 | ssize_t local_getxattr_nofollow(FsContext *ctx, const char *path, |
162 | const char *name, void *value, size_t size) | |
56fc494b | 163 | { |
56ad3e54 GK |
164 | char *dirpath = g_path_get_dirname(path); |
165 | char *filename = g_path_get_basename(path); | |
166 | int dirfd; | |
167 | ssize_t ret = -1; | |
168 | ||
169 | dirfd = local_opendir_nofollow(ctx, dirpath); | |
170 | if (dirfd == -1) { | |
171 | goto out; | |
172 | } | |
56fc494b | 173 | |
56ad3e54 GK |
174 | ret = fgetxattrat_nofollow(dirfd, filename, name, value, size); |
175 | close_preserve_errno(dirfd); | |
176 | out: | |
177 | g_free(dirpath); | |
178 | g_free(filename); | |
56fc494b GK |
179 | return ret; |
180 | } | |
181 | ||
56ad3e54 GK |
182 | ssize_t pt_getxattr(FsContext *ctx, const char *path, const char *name, |
183 | void *value, size_t size) | |
184 | { | |
185 | return local_getxattr_nofollow(ctx, path, name, value, size); | |
186 | } | |
187 | ||
3e36aba7 GK |
188 | ssize_t local_setxattr_nofollow(FsContext *ctx, const char *path, |
189 | const char *name, void *value, size_t size, | |
190 | int flags) | |
191 | { | |
192 | char *dirpath = g_path_get_dirname(path); | |
193 | char *filename = g_path_get_basename(path); | |
194 | int dirfd; | |
195 | ssize_t ret = -1; | |
196 | ||
197 | dirfd = local_opendir_nofollow(ctx, dirpath); | |
198 | if (dirfd == -1) { | |
199 | goto out; | |
200 | } | |
201 | ||
202 | ret = fsetxattrat_nofollow(dirfd, filename, name, value, size, flags); | |
203 | close_preserve_errno(dirfd); | |
204 | out: | |
205 | g_free(dirpath); | |
206 | g_free(filename); | |
56fc494b GK |
207 | return ret; |
208 | } | |
209 | ||
3e36aba7 GK |
210 | int pt_setxattr(FsContext *ctx, const char *path, const char *name, void *value, |
211 | size_t size, int flags) | |
212 | { | |
213 | return local_setxattr_nofollow(ctx, path, name, value, size, flags); | |
214 | } | |
215 | ||
72f0d0bf GK |
216 | ssize_t local_removexattr_nofollow(FsContext *ctx, const char *path, |
217 | const char *name) | |
218 | { | |
219 | char *dirpath = g_path_get_dirname(path); | |
220 | char *filename = g_path_get_basename(path); | |
221 | int dirfd; | |
222 | ssize_t ret = -1; | |
223 | ||
224 | dirfd = local_opendir_nofollow(ctx, dirpath); | |
225 | if (dirfd == -1) { | |
226 | goto out; | |
227 | } | |
228 | ||
229 | ret = fremovexattrat_nofollow(dirfd, filename, name); | |
230 | close_preserve_errno(dirfd); | |
231 | out: | |
232 | g_free(dirpath); | |
233 | g_free(filename); | |
234 | return ret; | |
235 | } | |
236 | ||
237 | int pt_removexattr(FsContext *ctx, const char *path, const char *name) | |
238 | { | |
239 | return local_removexattr_nofollow(ctx, path, name); | |
240 | } | |
241 | ||
56fc494b GK |
242 | ssize_t notsup_getxattr(FsContext *ctx, const char *path, const char *name, |
243 | void *value, size_t size) | |
244 | { | |
245 | errno = ENOTSUP; | |
246 | return -1; | |
247 | } | |
248 | ||
249 | int notsup_setxattr(FsContext *ctx, const char *path, const char *name, | |
250 | void *value, size_t size, int flags) | |
251 | { | |
252 | errno = ENOTSUP; | |
253 | return -1; | |
254 | } | |
255 | ||
256 | ssize_t notsup_listxattr(FsContext *ctx, const char *path, char *name, | |
257 | void *value, size_t size) | |
258 | { | |
259 | return 0; | |
260 | } | |
261 | ||
262 | int notsup_removexattr(FsContext *ctx, const char *path, const char *name) | |
263 | { | |
264 | errno = ENOTSUP; | |
265 | return -1; | |
266 | } | |
267 | ||
fc22118d AK |
268 | XattrOperations *mapped_xattr_ops[] = { |
269 | &mapped_user_xattr, | |
70fc55eb AK |
270 | &mapped_pacl_xattr, |
271 | &mapped_dacl_xattr, | |
fc22118d AK |
272 | NULL, |
273 | }; | |
274 | ||
275 | XattrOperations *passthrough_xattr_ops[] = { | |
276 | &passthrough_user_xattr, | |
70fc55eb | 277 | &passthrough_acl_xattr, |
fc22118d AK |
278 | NULL, |
279 | }; | |
280 | ||
281 | /* for .user none model should be same as passthrough */ | |
282 | XattrOperations *none_xattr_ops[] = { | |
283 | &passthrough_user_xattr, | |
70fc55eb | 284 | &none_acl_xattr, |
fc22118d AK |
285 | NULL, |
286 | }; |