]>
Commit | Line | Data |
---|---|---|
9f107513 AL |
1 | /* |
2 | * Virtio 9p Posix callback | |
3 | * | |
4 | * Copyright IBM, Corp. 2010 | |
5 | * | |
6 | * Authors: | |
7 | * Anthony Liguori <aliguori@us.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 | */ | |
873c3213 SW |
13 | |
14 | #include "hw/virtio.h" | |
9f107513 | 15 | #include "virtio-9p.h" |
fc22118d | 16 | #include "virtio-9p-xattr.h" |
c494dd6f | 17 | #include <arpa/inet.h> |
131dcb25 AL |
18 | #include <pwd.h> |
19 | #include <grp.h> | |
c494dd6f AL |
20 | #include <sys/socket.h> |
21 | #include <sys/un.h> | |
758e8e38 | 22 | #include <attr/xattr.h> |
131dcb25 | 23 | |
1237ad76 VJ |
24 | |
25 | static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf) | |
131dcb25 | 26 | { |
1237ad76 | 27 | int err; |
faa44e3d VJ |
28 | char buffer[PATH_MAX]; |
29 | err = lstat(rpath(fs_ctx, path, buffer), stbuf); | |
1237ad76 VJ |
30 | if (err) { |
31 | return err; | |
32 | } | |
33 | if (fs_ctx->fs_sm == SM_MAPPED) { | |
34 | /* Actual credentials are part of extended attrs */ | |
35 | uid_t tmp_uid; | |
36 | gid_t tmp_gid; | |
37 | mode_t tmp_mode; | |
38 | dev_t tmp_dev; | |
faa44e3d | 39 | if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.uid", &tmp_uid, |
1237ad76 VJ |
40 | sizeof(uid_t)) > 0) { |
41 | stbuf->st_uid = tmp_uid; | |
42 | } | |
faa44e3d | 43 | if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.gid", &tmp_gid, |
1237ad76 VJ |
44 | sizeof(gid_t)) > 0) { |
45 | stbuf->st_gid = tmp_gid; | |
46 | } | |
faa44e3d VJ |
47 | if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.mode", |
48 | &tmp_mode, sizeof(mode_t)) > 0) { | |
1237ad76 VJ |
49 | stbuf->st_mode = tmp_mode; |
50 | } | |
faa44e3d | 51 | if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.rdev", &tmp_dev, |
1237ad76 VJ |
52 | sizeof(dev_t)) > 0) { |
53 | stbuf->st_rdev = tmp_dev; | |
54 | } | |
55 | } | |
56 | return err; | |
131dcb25 AL |
57 | } |
58 | ||
758e8e38 | 59 | static int local_set_xattr(const char *path, FsCred *credp) |
131dcb25 | 60 | { |
758e8e38 VJ |
61 | int err; |
62 | if (credp->fc_uid != -1) { | |
63 | err = setxattr(path, "user.virtfs.uid", &credp->fc_uid, sizeof(uid_t), | |
64 | 0); | |
65 | if (err) { | |
66 | return err; | |
67 | } | |
131dcb25 | 68 | } |
758e8e38 VJ |
69 | if (credp->fc_gid != -1) { |
70 | err = setxattr(path, "user.virtfs.gid", &credp->fc_gid, sizeof(gid_t), | |
71 | 0); | |
72 | if (err) { | |
73 | return err; | |
74 | } | |
131dcb25 | 75 | } |
758e8e38 VJ |
76 | if (credp->fc_mode != -1) { |
77 | err = setxattr(path, "user.virtfs.mode", &credp->fc_mode, | |
78 | sizeof(mode_t), 0); | |
79 | if (err) { | |
80 | return err; | |
81 | } | |
131dcb25 | 82 | } |
758e8e38 VJ |
83 | if (credp->fc_rdev != -1) { |
84 | err = setxattr(path, "user.virtfs.rdev", &credp->fc_rdev, | |
85 | sizeof(dev_t), 0); | |
86 | if (err) { | |
87 | return err; | |
88 | } | |
131dcb25 | 89 | } |
131dcb25 AL |
90 | return 0; |
91 | } | |
92 | ||
4750a96f VJ |
93 | static int local_post_create_passthrough(FsContext *fs_ctx, const char *path, |
94 | FsCred *credp) | |
95 | { | |
faa44e3d VJ |
96 | char buffer[PATH_MAX]; |
97 | if (chmod(rpath(fs_ctx, path, buffer), credp->fc_mode & 07777) < 0) { | |
4750a96f VJ |
98 | return -1; |
99 | } | |
faa44e3d VJ |
100 | if (lchown(rpath(fs_ctx, path, buffer), credp->fc_uid, |
101 | credp->fc_gid) < 0) { | |
12848bfc AK |
102 | /* |
103 | * If we fail to change ownership and if we are | |
104 | * using security model none. Ignore the error | |
105 | */ | |
106 | if (fs_ctx->fs_sm != SM_NONE) { | |
107 | return -1; | |
108 | } | |
4750a96f VJ |
109 | } |
110 | return 0; | |
111 | } | |
112 | ||
879c2813 VJ |
113 | static ssize_t local_readlink(FsContext *fs_ctx, const char *path, |
114 | char *buf, size_t bufsz) | |
131dcb25 | 115 | { |
879c2813 | 116 | ssize_t tsize = -1; |
faa44e3d | 117 | char buffer[PATH_MAX]; |
879c2813 VJ |
118 | if (fs_ctx->fs_sm == SM_MAPPED) { |
119 | int fd; | |
faa44e3d | 120 | fd = open(rpath(fs_ctx, path, buffer), O_RDONLY); |
879c2813 VJ |
121 | if (fd == -1) { |
122 | return -1; | |
123 | } | |
124 | do { | |
125 | tsize = read(fd, (void *)buf, bufsz); | |
126 | } while (tsize == -1 && errno == EINTR); | |
127 | close(fd); | |
128 | return tsize; | |
12848bfc AK |
129 | } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || |
130 | (fs_ctx->fs_sm == SM_NONE)) { | |
faa44e3d | 131 | tsize = readlink(rpath(fs_ctx, path, buffer), buf, bufsz); |
879c2813 VJ |
132 | } |
133 | return tsize; | |
131dcb25 AL |
134 | } |
135 | ||
136 | static int local_close(FsContext *ctx, int fd) | |
137 | { | |
138 | return close(fd); | |
139 | } | |
140 | ||
141 | static int local_closedir(FsContext *ctx, DIR *dir) | |
142 | { | |
143 | return closedir(dir); | |
144 | } | |
9f107513 | 145 | |
a6568fe2 AL |
146 | static int local_open(FsContext *ctx, const char *path, int flags) |
147 | { | |
faa44e3d VJ |
148 | char buffer[PATH_MAX]; |
149 | return open(rpath(ctx, path, buffer), flags); | |
a6568fe2 AL |
150 | } |
151 | ||
152 | static DIR *local_opendir(FsContext *ctx, const char *path) | |
153 | { | |
faa44e3d VJ |
154 | char buffer[PATH_MAX]; |
155 | return opendir(rpath(ctx, path, buffer)); | |
a6568fe2 AL |
156 | } |
157 | ||
a9231555 AL |
158 | static void local_rewinddir(FsContext *ctx, DIR *dir) |
159 | { | |
160 | return rewinddir(dir); | |
161 | } | |
162 | ||
163 | static off_t local_telldir(FsContext *ctx, DIR *dir) | |
164 | { | |
165 | return telldir(dir); | |
166 | } | |
167 | ||
5f524c1e HPB |
168 | static int local_readdir_r(FsContext *ctx, DIR *dir, struct dirent *entry, |
169 | struct dirent **result) | |
a9231555 | 170 | { |
5f524c1e | 171 | return readdir_r(dir, entry, result); |
a9231555 AL |
172 | } |
173 | ||
174 | static void local_seekdir(FsContext *ctx, DIR *dir, off_t off) | |
175 | { | |
176 | return seekdir(dir, off); | |
177 | } | |
178 | ||
56d15a53 SG |
179 | static ssize_t local_preadv(FsContext *ctx, int fd, const struct iovec *iov, |
180 | int iovcnt, off_t offset) | |
a9231555 | 181 | { |
56d15a53 SG |
182 | #ifdef CONFIG_PREADV |
183 | return preadv(fd, iov, iovcnt, offset); | |
184 | #else | |
185 | int err = lseek(fd, offset, SEEK_SET); | |
186 | if (err == -1) { | |
187 | return err; | |
188 | } else { | |
189 | return readv(fd, iov, iovcnt); | |
190 | } | |
191 | #endif | |
a9231555 AL |
192 | } |
193 | ||
56d15a53 SG |
194 | static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov, |
195 | int iovcnt, off_t offset) | |
8449360c | 196 | { |
56d15a53 SG |
197 | #ifdef CONFIG_PREADV |
198 | return pwritev(fd, iov, iovcnt, offset); | |
199 | #else | |
200 | int err = lseek(fd, offset, SEEK_SET); | |
201 | if (err == -1) { | |
202 | return err; | |
203 | } else { | |
204 | return writev(fd, iov, iovcnt); | |
205 | } | |
206 | #endif | |
8449360c AL |
207 | } |
208 | ||
e95ead32 | 209 | static int local_chmod(FsContext *fs_ctx, const char *path, FsCred *credp) |
c494dd6f | 210 | { |
faa44e3d | 211 | char buffer[PATH_MAX]; |
e95ead32 | 212 | if (fs_ctx->fs_sm == SM_MAPPED) { |
faa44e3d | 213 | return local_set_xattr(rpath(fs_ctx, path, buffer), credp); |
12848bfc AK |
214 | } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || |
215 | (fs_ctx->fs_sm == SM_NONE)) { | |
faa44e3d | 216 | return chmod(rpath(fs_ctx, path, buffer), credp->fc_mode); |
e95ead32 VJ |
217 | } |
218 | return -1; | |
c494dd6f AL |
219 | } |
220 | ||
1c293312 | 221 | static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp) |
c494dd6f | 222 | { |
1c293312 VJ |
223 | int err = -1; |
224 | int serrno = 0; | |
faa44e3d | 225 | char buffer[PATH_MAX]; |
1c293312 VJ |
226 | |
227 | /* Determine the security model */ | |
228 | if (fs_ctx->fs_sm == SM_MAPPED) { | |
faa44e3d VJ |
229 | err = mknod(rpath(fs_ctx, path, buffer), |
230 | SM_LOCAL_MODE_BITS|S_IFREG, 0); | |
1c293312 VJ |
231 | if (err == -1) { |
232 | return err; | |
233 | } | |
faa44e3d | 234 | local_set_xattr(rpath(fs_ctx, path, buffer), credp); |
1c293312 VJ |
235 | if (err == -1) { |
236 | serrno = errno; | |
237 | goto err_end; | |
238 | } | |
12848bfc AK |
239 | } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || |
240 | (fs_ctx->fs_sm == SM_NONE)) { | |
faa44e3d VJ |
241 | err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode, |
242 | credp->fc_rdev); | |
1c293312 VJ |
243 | if (err == -1) { |
244 | return err; | |
245 | } | |
246 | err = local_post_create_passthrough(fs_ctx, path, credp); | |
247 | if (err == -1) { | |
248 | serrno = errno; | |
249 | goto err_end; | |
250 | } | |
251 | } | |
252 | return err; | |
253 | ||
254 | err_end: | |
faa44e3d | 255 | remove(rpath(fs_ctx, path, buffer)); |
1c293312 VJ |
256 | errno = serrno; |
257 | return err; | |
c494dd6f AL |
258 | } |
259 | ||
00ec5c37 | 260 | static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp) |
c494dd6f | 261 | { |
00ec5c37 VJ |
262 | int err = -1; |
263 | int serrno = 0; | |
faa44e3d | 264 | char buffer[PATH_MAX]; |
00ec5c37 VJ |
265 | |
266 | /* Determine the security model */ | |
267 | if (fs_ctx->fs_sm == SM_MAPPED) { | |
faa44e3d | 268 | err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS); |
00ec5c37 VJ |
269 | if (err == -1) { |
270 | return err; | |
271 | } | |
272 | credp->fc_mode = credp->fc_mode|S_IFDIR; | |
faa44e3d | 273 | err = local_set_xattr(rpath(fs_ctx, path, buffer), credp); |
00ec5c37 VJ |
274 | if (err == -1) { |
275 | serrno = errno; | |
276 | goto err_end; | |
277 | } | |
12848bfc AK |
278 | } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || |
279 | (fs_ctx->fs_sm == SM_NONE)) { | |
faa44e3d | 280 | err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode); |
00ec5c37 VJ |
281 | if (err == -1) { |
282 | return err; | |
283 | } | |
284 | err = local_post_create_passthrough(fs_ctx, path, credp); | |
285 | if (err == -1) { | |
286 | serrno = errno; | |
287 | goto err_end; | |
288 | } | |
289 | } | |
290 | return err; | |
291 | ||
292 | err_end: | |
faa44e3d | 293 | remove(rpath(fs_ctx, path, buffer)); |
00ec5c37 VJ |
294 | errno = serrno; |
295 | return err; | |
c494dd6f AL |
296 | } |
297 | ||
1237ad76 | 298 | static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf) |
c494dd6f | 299 | { |
1237ad76 VJ |
300 | int err; |
301 | err = fstat(fd, stbuf); | |
302 | if (err) { | |
303 | return err; | |
304 | } | |
305 | if (fs_ctx->fs_sm == SM_MAPPED) { | |
306 | /* Actual credentials are part of extended attrs */ | |
307 | uid_t tmp_uid; | |
308 | gid_t tmp_gid; | |
309 | mode_t tmp_mode; | |
310 | dev_t tmp_dev; | |
311 | ||
312 | if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) { | |
313 | stbuf->st_uid = tmp_uid; | |
314 | } | |
315 | if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) { | |
316 | stbuf->st_gid = tmp_gid; | |
317 | } | |
318 | if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) { | |
319 | stbuf->st_mode = tmp_mode; | |
320 | } | |
321 | if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) { | |
322 | stbuf->st_rdev = tmp_dev; | |
323 | } | |
324 | } | |
325 | return err; | |
c494dd6f AL |
326 | } |
327 | ||
4750a96f VJ |
328 | static int local_open2(FsContext *fs_ctx, const char *path, int flags, |
329 | FsCred *credp) | |
c494dd6f | 330 | { |
4750a96f VJ |
331 | int fd = -1; |
332 | int err = -1; | |
333 | int serrno = 0; | |
faa44e3d | 334 | char buffer[PATH_MAX]; |
4750a96f VJ |
335 | |
336 | /* Determine the security model */ | |
337 | if (fs_ctx->fs_sm == SM_MAPPED) { | |
faa44e3d | 338 | fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS); |
4750a96f VJ |
339 | if (fd == -1) { |
340 | return fd; | |
341 | } | |
342 | credp->fc_mode = credp->fc_mode|S_IFREG; | |
343 | /* Set cleint credentials in xattr */ | |
faa44e3d | 344 | err = local_set_xattr(rpath(fs_ctx, path, buffer), credp); |
4750a96f VJ |
345 | if (err == -1) { |
346 | serrno = errno; | |
347 | goto err_end; | |
348 | } | |
12848bfc AK |
349 | } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || |
350 | (fs_ctx->fs_sm == SM_NONE)) { | |
faa44e3d | 351 | fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode); |
4750a96f VJ |
352 | if (fd == -1) { |
353 | return fd; | |
354 | } | |
355 | err = local_post_create_passthrough(fs_ctx, path, credp); | |
356 | if (err == -1) { | |
357 | serrno = errno; | |
358 | goto err_end; | |
359 | } | |
360 | } | |
361 | return fd; | |
362 | ||
363 | err_end: | |
364 | close(fd); | |
faa44e3d | 365 | remove(rpath(fs_ctx, path, buffer)); |
4750a96f VJ |
366 | errno = serrno; |
367 | return err; | |
c494dd6f AL |
368 | } |
369 | ||
758e8e38 | 370 | |
879c2813 VJ |
371 | static int local_symlink(FsContext *fs_ctx, const char *oldpath, |
372 | const char *newpath, FsCred *credp) | |
c494dd6f | 373 | { |
879c2813 VJ |
374 | int err = -1; |
375 | int serrno = 0; | |
faa44e3d | 376 | char buffer[PATH_MAX]; |
879c2813 VJ |
377 | |
378 | /* Determine the security model */ | |
379 | if (fs_ctx->fs_sm == SM_MAPPED) { | |
380 | int fd; | |
381 | ssize_t oldpath_size, write_size; | |
faa44e3d | 382 | fd = open(rpath(fs_ctx, newpath, buffer), O_CREAT|O_EXCL|O_RDWR, |
879c2813 VJ |
383 | SM_LOCAL_MODE_BITS); |
384 | if (fd == -1) { | |
385 | return fd; | |
386 | } | |
387 | /* Write the oldpath (target) to the file. */ | |
f35bde2f | 388 | oldpath_size = strlen(oldpath); |
879c2813 VJ |
389 | do { |
390 | write_size = write(fd, (void *)oldpath, oldpath_size); | |
391 | } while (write_size == -1 && errno == EINTR); | |
392 | ||
393 | if (write_size != oldpath_size) { | |
394 | serrno = errno; | |
395 | close(fd); | |
396 | err = -1; | |
397 | goto err_end; | |
398 | } | |
399 | close(fd); | |
400 | /* Set cleint credentials in symlink's xattr */ | |
401 | credp->fc_mode = credp->fc_mode|S_IFLNK; | |
faa44e3d | 402 | err = local_set_xattr(rpath(fs_ctx, newpath, buffer), credp); |
879c2813 VJ |
403 | if (err == -1) { |
404 | serrno = errno; | |
405 | goto err_end; | |
406 | } | |
12848bfc AK |
407 | } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || |
408 | (fs_ctx->fs_sm == SM_NONE)) { | |
faa44e3d | 409 | err = symlink(oldpath, rpath(fs_ctx, newpath, buffer)); |
879c2813 VJ |
410 | if (err) { |
411 | return err; | |
412 | } | |
faa44e3d VJ |
413 | err = lchown(rpath(fs_ctx, newpath, buffer), credp->fc_uid, |
414 | credp->fc_gid); | |
879c2813 | 415 | if (err == -1) { |
12848bfc AK |
416 | /* |
417 | * If we fail to change ownership and if we are | |
418 | * using security model none. Ignore the error | |
419 | */ | |
420 | if (fs_ctx->fs_sm != SM_NONE) { | |
421 | serrno = errno; | |
422 | goto err_end; | |
423 | } else | |
424 | err = 0; | |
879c2813 VJ |
425 | } |
426 | } | |
427 | return err; | |
428 | ||
429 | err_end: | |
faa44e3d | 430 | remove(rpath(fs_ctx, newpath, buffer)); |
879c2813 VJ |
431 | errno = serrno; |
432 | return err; | |
c494dd6f AL |
433 | } |
434 | ||
435 | static int local_link(FsContext *ctx, const char *oldpath, const char *newpath) | |
436 | { | |
faa44e3d | 437 | char buffer[PATH_MAX], buffer1[PATH_MAX]; |
c494dd6f | 438 | |
faa44e3d | 439 | return link(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1)); |
c494dd6f AL |
440 | } |
441 | ||
8cf89e00 AL |
442 | static int local_truncate(FsContext *ctx, const char *path, off_t size) |
443 | { | |
faa44e3d VJ |
444 | char buffer[PATH_MAX]; |
445 | return truncate(rpath(ctx, path, buffer), size); | |
8cf89e00 AL |
446 | } |
447 | ||
448 | static int local_rename(FsContext *ctx, const char *oldpath, | |
449 | const char *newpath) | |
450 | { | |
faa44e3d | 451 | char buffer[PATH_MAX], buffer1[PATH_MAX]; |
8cf89e00 | 452 | |
faa44e3d | 453 | return rename(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1)); |
8cf89e00 AL |
454 | } |
455 | ||
f7613bee | 456 | static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp) |
8cf89e00 | 457 | { |
faa44e3d | 458 | char buffer[PATH_MAX]; |
c79ce737 SK |
459 | if ((credp->fc_uid == -1 && credp->fc_gid == -1) || |
460 | (fs_ctx->fs_sm == SM_PASSTHROUGH)) { | |
faa44e3d VJ |
461 | return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid, |
462 | credp->fc_gid); | |
c79ce737 | 463 | } else if (fs_ctx->fs_sm == SM_MAPPED) { |
faa44e3d | 464 | return local_set_xattr(rpath(fs_ctx, path, buffer), credp); |
12848bfc AK |
465 | } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || |
466 | (fs_ctx->fs_sm == SM_NONE)) { | |
faa44e3d VJ |
467 | return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid, |
468 | credp->fc_gid); | |
f7613bee VJ |
469 | } |
470 | return -1; | |
8cf89e00 AL |
471 | } |
472 | ||
74bc02b2 | 473 | static int local_utimensat(FsContext *s, const char *path, |
38671423 | 474 | const struct timespec *buf) |
8cf89e00 | 475 | { |
faa44e3d VJ |
476 | char buffer[PATH_MAX]; |
477 | return qemu_utimensat(AT_FDCWD, rpath(s, path, buffer), buf, | |
478 | AT_SYMLINK_NOFOLLOW); | |
8cf89e00 AL |
479 | } |
480 | ||
5bae1900 AL |
481 | static int local_remove(FsContext *ctx, const char *path) |
482 | { | |
faa44e3d VJ |
483 | char buffer[PATH_MAX]; |
484 | return remove(rpath(ctx, path, buffer)); | |
5bae1900 AL |
485 | } |
486 | ||
49594973 | 487 | static int local_fsync(FsContext *ctx, int fd, int datasync) |
8cf89e00 | 488 | { |
49594973 VJ |
489 | if (datasync) { |
490 | return qemu_fdatasync(fd); | |
491 | } else { | |
492 | return fsync(fd); | |
493 | } | |
8cf89e00 AL |
494 | } |
495 | ||
be940c87 MK |
496 | static int local_statfs(FsContext *s, const char *path, struct statfs *stbuf) |
497 | { | |
faa44e3d VJ |
498 | char buffer[PATH_MAX]; |
499 | return statfs(rpath(s, path, buffer), stbuf); | |
be940c87 MK |
500 | } |
501 | ||
fa32ef88 AK |
502 | static ssize_t local_lgetxattr(FsContext *ctx, const char *path, |
503 | const char *name, void *value, size_t size) | |
504 | { | |
fc22118d | 505 | return v9fs_get_xattr(ctx, path, name, value, size); |
fa32ef88 AK |
506 | } |
507 | ||
508 | static ssize_t local_llistxattr(FsContext *ctx, const char *path, | |
509 | void *value, size_t size) | |
510 | { | |
fc22118d | 511 | return v9fs_list_xattr(ctx, path, value, size); |
fa32ef88 AK |
512 | } |
513 | ||
10b468bd AK |
514 | static int local_lsetxattr(FsContext *ctx, const char *path, const char *name, |
515 | void *value, size_t size, int flags) | |
516 | { | |
fc22118d | 517 | return v9fs_set_xattr(ctx, path, name, value, size, flags); |
10b468bd AK |
518 | } |
519 | ||
9ed3ef26 AK |
520 | static int local_lremovexattr(FsContext *ctx, |
521 | const char *path, const char *name) | |
522 | { | |
fc22118d | 523 | return v9fs_remove_xattr(ctx, path, name); |
9ed3ef26 AK |
524 | } |
525 | ||
526 | ||
9f107513 | 527 | FileOperations local_ops = { |
131dcb25 | 528 | .lstat = local_lstat, |
131dcb25 AL |
529 | .readlink = local_readlink, |
530 | .close = local_close, | |
531 | .closedir = local_closedir, | |
a6568fe2 AL |
532 | .open = local_open, |
533 | .opendir = local_opendir, | |
a9231555 AL |
534 | .rewinddir = local_rewinddir, |
535 | .telldir = local_telldir, | |
5f524c1e | 536 | .readdir_r = local_readdir_r, |
a9231555 | 537 | .seekdir = local_seekdir, |
56d15a53 SG |
538 | .preadv = local_preadv, |
539 | .pwritev = local_pwritev, | |
c494dd6f AL |
540 | .chmod = local_chmod, |
541 | .mknod = local_mknod, | |
c494dd6f AL |
542 | .mkdir = local_mkdir, |
543 | .fstat = local_fstat, | |
544 | .open2 = local_open2, | |
545 | .symlink = local_symlink, | |
546 | .link = local_link, | |
8cf89e00 AL |
547 | .truncate = local_truncate, |
548 | .rename = local_rename, | |
549 | .chown = local_chown, | |
74bc02b2 | 550 | .utimensat = local_utimensat, |
5bae1900 | 551 | .remove = local_remove, |
8cf89e00 | 552 | .fsync = local_fsync, |
be940c87 | 553 | .statfs = local_statfs, |
fa32ef88 AK |
554 | .lgetxattr = local_lgetxattr, |
555 | .llistxattr = local_llistxattr, | |
10b468bd | 556 | .lsetxattr = local_lsetxattr, |
9ed3ef26 | 557 | .lremovexattr = local_lremovexattr, |
9f107513 | 558 | }; |