]>
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> |
e06a765e HPB |
23 | #include <linux/fs.h> |
24 | #ifdef CONFIG_LINUX_MAGIC_H | |
25 | #include <linux/magic.h> | |
26 | #endif | |
27 | #include <sys/ioctl.h> | |
28 | ||
29 | #ifndef XFS_SUPER_MAGIC | |
30 | #define XFS_SUPER_MAGIC 0x58465342 | |
31 | #endif | |
32 | #ifndef EXT2_SUPER_MAGIC | |
33 | #define EXT2_SUPER_MAGIC 0xEF53 | |
34 | #endif | |
35 | #ifndef REISERFS_SUPER_MAGIC | |
36 | #define REISERFS_SUPER_MAGIC 0x52654973 | |
37 | #endif | |
38 | #ifndef BTRFS_SUPER_MAGIC | |
39 | #define BTRFS_SUPER_MAGIC 0x9123683E | |
40 | #endif | |
131dcb25 | 41 | |
2289be19 | 42 | static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) |
131dcb25 | 43 | { |
1237ad76 | 44 | int err; |
faa44e3d | 45 | char buffer[PATH_MAX]; |
2289be19 AK |
46 | char *path = fs_path->data; |
47 | ||
faa44e3d | 48 | err = lstat(rpath(fs_ctx, path, buffer), stbuf); |
1237ad76 VJ |
49 | if (err) { |
50 | return err; | |
51 | } | |
b97400ca | 52 | if (fs_ctx->export_flags & V9FS_SM_MAPPED) { |
1237ad76 VJ |
53 | /* Actual credentials are part of extended attrs */ |
54 | uid_t tmp_uid; | |
55 | gid_t tmp_gid; | |
56 | mode_t tmp_mode; | |
57 | dev_t tmp_dev; | |
faa44e3d | 58 | if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.uid", &tmp_uid, |
1237ad76 VJ |
59 | sizeof(uid_t)) > 0) { |
60 | stbuf->st_uid = tmp_uid; | |
61 | } | |
faa44e3d | 62 | if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.gid", &tmp_gid, |
1237ad76 VJ |
63 | sizeof(gid_t)) > 0) { |
64 | stbuf->st_gid = tmp_gid; | |
65 | } | |
faa44e3d VJ |
66 | if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.mode", |
67 | &tmp_mode, sizeof(mode_t)) > 0) { | |
1237ad76 VJ |
68 | stbuf->st_mode = tmp_mode; |
69 | } | |
faa44e3d | 70 | if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.rdev", &tmp_dev, |
1237ad76 VJ |
71 | sizeof(dev_t)) > 0) { |
72 | stbuf->st_rdev = tmp_dev; | |
73 | } | |
74 | } | |
75 | return err; | |
131dcb25 AL |
76 | } |
77 | ||
758e8e38 | 78 | static int local_set_xattr(const char *path, FsCred *credp) |
131dcb25 | 79 | { |
758e8e38 | 80 | int err; |
2289be19 | 81 | |
758e8e38 VJ |
82 | if (credp->fc_uid != -1) { |
83 | err = setxattr(path, "user.virtfs.uid", &credp->fc_uid, sizeof(uid_t), | |
84 | 0); | |
85 | if (err) { | |
86 | return err; | |
87 | } | |
131dcb25 | 88 | } |
758e8e38 VJ |
89 | if (credp->fc_gid != -1) { |
90 | err = setxattr(path, "user.virtfs.gid", &credp->fc_gid, sizeof(gid_t), | |
91 | 0); | |
92 | if (err) { | |
93 | return err; | |
94 | } | |
131dcb25 | 95 | } |
758e8e38 VJ |
96 | if (credp->fc_mode != -1) { |
97 | err = setxattr(path, "user.virtfs.mode", &credp->fc_mode, | |
98 | sizeof(mode_t), 0); | |
99 | if (err) { | |
100 | return err; | |
101 | } | |
131dcb25 | 102 | } |
758e8e38 VJ |
103 | if (credp->fc_rdev != -1) { |
104 | err = setxattr(path, "user.virtfs.rdev", &credp->fc_rdev, | |
105 | sizeof(dev_t), 0); | |
106 | if (err) { | |
107 | return err; | |
108 | } | |
131dcb25 | 109 | } |
131dcb25 AL |
110 | return 0; |
111 | } | |
112 | ||
4750a96f | 113 | static int local_post_create_passthrough(FsContext *fs_ctx, const char *path, |
2289be19 | 114 | FsCred *credp) |
4750a96f | 115 | { |
faa44e3d | 116 | char buffer[PATH_MAX]; |
2289be19 | 117 | |
faa44e3d | 118 | if (chmod(rpath(fs_ctx, path, buffer), credp->fc_mode & 07777) < 0) { |
4750a96f VJ |
119 | return -1; |
120 | } | |
faa44e3d VJ |
121 | if (lchown(rpath(fs_ctx, path, buffer), credp->fc_uid, |
122 | credp->fc_gid) < 0) { | |
12848bfc AK |
123 | /* |
124 | * If we fail to change ownership and if we are | |
125 | * using security model none. Ignore the error | |
126 | */ | |
b97400ca | 127 | if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) { |
12848bfc AK |
128 | return -1; |
129 | } | |
4750a96f VJ |
130 | } |
131 | return 0; | |
132 | } | |
133 | ||
2289be19 AK |
134 | static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path, |
135 | char *buf, size_t bufsz) | |
131dcb25 | 136 | { |
879c2813 | 137 | ssize_t tsize = -1; |
faa44e3d | 138 | char buffer[PATH_MAX]; |
2289be19 AK |
139 | char *path = fs_path->data; |
140 | ||
b97400ca | 141 | if (fs_ctx->export_flags & V9FS_SM_MAPPED) { |
879c2813 | 142 | int fd; |
faa44e3d | 143 | fd = open(rpath(fs_ctx, path, buffer), O_RDONLY); |
879c2813 VJ |
144 | if (fd == -1) { |
145 | return -1; | |
146 | } | |
147 | do { | |
148 | tsize = read(fd, (void *)buf, bufsz); | |
149 | } while (tsize == -1 && errno == EINTR); | |
150 | close(fd); | |
151 | return tsize; | |
b97400ca AK |
152 | } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || |
153 | (fs_ctx->export_flags & V9FS_SM_NONE)) { | |
faa44e3d | 154 | tsize = readlink(rpath(fs_ctx, path, buffer), buf, bufsz); |
879c2813 VJ |
155 | } |
156 | return tsize; | |
131dcb25 AL |
157 | } |
158 | ||
159 | static int local_close(FsContext *ctx, int fd) | |
160 | { | |
161 | return close(fd); | |
162 | } | |
163 | ||
164 | static int local_closedir(FsContext *ctx, DIR *dir) | |
165 | { | |
166 | return closedir(dir); | |
167 | } | |
9f107513 | 168 | |
2289be19 | 169 | static int local_open(FsContext *ctx, V9fsPath *fs_path, int flags) |
a6568fe2 | 170 | { |
faa44e3d | 171 | char buffer[PATH_MAX]; |
2289be19 AK |
172 | char *path = fs_path->data; |
173 | ||
faa44e3d | 174 | return open(rpath(ctx, path, buffer), flags); |
a6568fe2 AL |
175 | } |
176 | ||
2289be19 | 177 | static DIR *local_opendir(FsContext *ctx, V9fsPath *fs_path) |
a6568fe2 | 178 | { |
faa44e3d | 179 | char buffer[PATH_MAX]; |
2289be19 AK |
180 | char *path = fs_path->data; |
181 | ||
faa44e3d | 182 | return opendir(rpath(ctx, path, buffer)); |
a6568fe2 AL |
183 | } |
184 | ||
a9231555 AL |
185 | static void local_rewinddir(FsContext *ctx, DIR *dir) |
186 | { | |
187 | return rewinddir(dir); | |
188 | } | |
189 | ||
190 | static off_t local_telldir(FsContext *ctx, DIR *dir) | |
191 | { | |
192 | return telldir(dir); | |
193 | } | |
194 | ||
5f524c1e | 195 | static int local_readdir_r(FsContext *ctx, DIR *dir, struct dirent *entry, |
2289be19 | 196 | struct dirent **result) |
a9231555 | 197 | { |
5f524c1e | 198 | return readdir_r(dir, entry, result); |
a9231555 AL |
199 | } |
200 | ||
201 | static void local_seekdir(FsContext *ctx, DIR *dir, off_t off) | |
202 | { | |
203 | return seekdir(dir, off); | |
204 | } | |
205 | ||
56d15a53 SG |
206 | static ssize_t local_preadv(FsContext *ctx, int fd, const struct iovec *iov, |
207 | int iovcnt, off_t offset) | |
a9231555 | 208 | { |
56d15a53 SG |
209 | #ifdef CONFIG_PREADV |
210 | return preadv(fd, iov, iovcnt, offset); | |
211 | #else | |
212 | int err = lseek(fd, offset, SEEK_SET); | |
213 | if (err == -1) { | |
214 | return err; | |
215 | } else { | |
216 | return readv(fd, iov, iovcnt); | |
217 | } | |
218 | #endif | |
a9231555 AL |
219 | } |
220 | ||
56d15a53 | 221 | static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov, |
2289be19 | 222 | int iovcnt, off_t offset) |
8449360c | 223 | { |
d3ab98e6 AK |
224 | ssize_t ret |
225 | ; | |
56d15a53 | 226 | #ifdef CONFIG_PREADV |
d3ab98e6 | 227 | ret = pwritev(fd, iov, iovcnt, offset); |
56d15a53 SG |
228 | #else |
229 | int err = lseek(fd, offset, SEEK_SET); | |
230 | if (err == -1) { | |
231 | return err; | |
232 | } else { | |
d3ab98e6 | 233 | ret = writev(fd, iov, iovcnt); |
56d15a53 SG |
234 | } |
235 | #endif | |
d3ab98e6 AK |
236 | #ifdef CONFIG_SYNC_FILE_RANGE |
237 | if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) { | |
238 | /* | |
239 | * Initiate a writeback. This is not a data integrity sync. | |
240 | * We want to ensure that we don't leave dirty pages in the cache | |
241 | * after write when writeout=immediate is sepcified. | |
242 | */ | |
243 | sync_file_range(fd, offset, ret, | |
244 | SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE); | |
245 | } | |
246 | #endif | |
247 | return ret; | |
8449360c AL |
248 | } |
249 | ||
2289be19 | 250 | static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) |
c494dd6f | 251 | { |
faa44e3d | 252 | char buffer[PATH_MAX]; |
2289be19 AK |
253 | char *path = fs_path->data; |
254 | ||
b97400ca | 255 | if (fs_ctx->export_flags & V9FS_SM_MAPPED) { |
faa44e3d | 256 | return local_set_xattr(rpath(fs_ctx, path, buffer), credp); |
b97400ca AK |
257 | } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || |
258 | (fs_ctx->export_flags & V9FS_SM_NONE)) { | |
faa44e3d | 259 | return chmod(rpath(fs_ctx, path, buffer), credp->fc_mode); |
e95ead32 VJ |
260 | } |
261 | return -1; | |
c494dd6f AL |
262 | } |
263 | ||
2289be19 AK |
264 | static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path, |
265 | const char *name, FsCred *credp) | |
c494dd6f | 266 | { |
2289be19 | 267 | char *path; |
1c293312 VJ |
268 | int err = -1; |
269 | int serrno = 0; | |
2289be19 | 270 | V9fsString fullname; |
faa44e3d | 271 | char buffer[PATH_MAX]; |
1c293312 | 272 | |
2289be19 AK |
273 | v9fs_string_init(&fullname); |
274 | v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); | |
275 | path = fullname.data; | |
276 | ||
1c293312 | 277 | /* Determine the security model */ |
b97400ca | 278 | if (fs_ctx->export_flags & V9FS_SM_MAPPED) { |
faa44e3d VJ |
279 | err = mknod(rpath(fs_ctx, path, buffer), |
280 | SM_LOCAL_MODE_BITS|S_IFREG, 0); | |
1c293312 | 281 | if (err == -1) { |
2289be19 | 282 | goto out; |
1c293312 | 283 | } |
17b1971f | 284 | err = local_set_xattr(rpath(fs_ctx, path, buffer), credp); |
1c293312 VJ |
285 | if (err == -1) { |
286 | serrno = errno; | |
287 | goto err_end; | |
288 | } | |
b97400ca AK |
289 | } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || |
290 | (fs_ctx->export_flags & V9FS_SM_NONE)) { | |
faa44e3d VJ |
291 | err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode, |
292 | credp->fc_rdev); | |
1c293312 | 293 | if (err == -1) { |
2289be19 | 294 | goto out; |
1c293312 VJ |
295 | } |
296 | err = local_post_create_passthrough(fs_ctx, path, credp); | |
297 | if (err == -1) { | |
298 | serrno = errno; | |
299 | goto err_end; | |
300 | } | |
301 | } | |
2289be19 | 302 | goto out; |
1c293312 VJ |
303 | |
304 | err_end: | |
faa44e3d | 305 | remove(rpath(fs_ctx, path, buffer)); |
1c293312 | 306 | errno = serrno; |
2289be19 AK |
307 | out: |
308 | v9fs_string_free(&fullname); | |
1c293312 | 309 | return err; |
c494dd6f AL |
310 | } |
311 | ||
2289be19 AK |
312 | static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, |
313 | const char *name, FsCred *credp) | |
c494dd6f | 314 | { |
2289be19 | 315 | char *path; |
00ec5c37 VJ |
316 | int err = -1; |
317 | int serrno = 0; | |
2289be19 | 318 | V9fsString fullname; |
faa44e3d | 319 | char buffer[PATH_MAX]; |
00ec5c37 | 320 | |
2289be19 AK |
321 | v9fs_string_init(&fullname); |
322 | v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); | |
323 | path = fullname.data; | |
324 | ||
00ec5c37 | 325 | /* Determine the security model */ |
b97400ca | 326 | if (fs_ctx->export_flags & V9FS_SM_MAPPED) { |
faa44e3d | 327 | err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS); |
00ec5c37 | 328 | if (err == -1) { |
2289be19 | 329 | goto out; |
00ec5c37 VJ |
330 | } |
331 | credp->fc_mode = credp->fc_mode|S_IFDIR; | |
faa44e3d | 332 | err = local_set_xattr(rpath(fs_ctx, path, buffer), credp); |
00ec5c37 VJ |
333 | if (err == -1) { |
334 | serrno = errno; | |
335 | goto err_end; | |
336 | } | |
b97400ca AK |
337 | } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || |
338 | (fs_ctx->export_flags & V9FS_SM_NONE)) { | |
faa44e3d | 339 | err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode); |
00ec5c37 | 340 | if (err == -1) { |
2289be19 | 341 | goto out; |
00ec5c37 VJ |
342 | } |
343 | err = local_post_create_passthrough(fs_ctx, path, credp); | |
344 | if (err == -1) { | |
345 | serrno = errno; | |
346 | goto err_end; | |
347 | } | |
348 | } | |
2289be19 | 349 | goto out; |
00ec5c37 VJ |
350 | |
351 | err_end: | |
faa44e3d | 352 | remove(rpath(fs_ctx, path, buffer)); |
00ec5c37 | 353 | errno = serrno; |
2289be19 AK |
354 | out: |
355 | v9fs_string_free(&fullname); | |
00ec5c37 | 356 | return err; |
c494dd6f AL |
357 | } |
358 | ||
1237ad76 | 359 | static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf) |
c494dd6f | 360 | { |
1237ad76 VJ |
361 | int err; |
362 | err = fstat(fd, stbuf); | |
363 | if (err) { | |
364 | return err; | |
365 | } | |
b97400ca | 366 | if (fs_ctx->export_flags & V9FS_SM_MAPPED) { |
1237ad76 VJ |
367 | /* Actual credentials are part of extended attrs */ |
368 | uid_t tmp_uid; | |
369 | gid_t tmp_gid; | |
370 | mode_t tmp_mode; | |
371 | dev_t tmp_dev; | |
372 | ||
373 | if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) { | |
374 | stbuf->st_uid = tmp_uid; | |
375 | } | |
376 | if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) { | |
377 | stbuf->st_gid = tmp_gid; | |
378 | } | |
379 | if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) { | |
380 | stbuf->st_mode = tmp_mode; | |
381 | } | |
382 | if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) { | |
383 | stbuf->st_rdev = tmp_dev; | |
384 | } | |
385 | } | |
386 | return err; | |
c494dd6f AL |
387 | } |
388 | ||
2289be19 AK |
389 | static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, |
390 | int flags, FsCred *credp) | |
c494dd6f | 391 | { |
2289be19 | 392 | char *path; |
4750a96f VJ |
393 | int fd = -1; |
394 | int err = -1; | |
395 | int serrno = 0; | |
2289be19 | 396 | V9fsString fullname; |
faa44e3d | 397 | char buffer[PATH_MAX]; |
4750a96f | 398 | |
2289be19 AK |
399 | v9fs_string_init(&fullname); |
400 | v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); | |
401 | path = fullname.data; | |
402 | ||
4750a96f | 403 | /* Determine the security model */ |
b97400ca | 404 | if (fs_ctx->export_flags & V9FS_SM_MAPPED) { |
faa44e3d | 405 | fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS); |
4750a96f | 406 | if (fd == -1) { |
2289be19 AK |
407 | err = fd; |
408 | goto out; | |
4750a96f VJ |
409 | } |
410 | credp->fc_mode = credp->fc_mode|S_IFREG; | |
411 | /* Set cleint credentials in xattr */ | |
faa44e3d | 412 | err = local_set_xattr(rpath(fs_ctx, path, buffer), credp); |
4750a96f VJ |
413 | if (err == -1) { |
414 | serrno = errno; | |
415 | goto err_end; | |
416 | } | |
b97400ca AK |
417 | } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || |
418 | (fs_ctx->export_flags & V9FS_SM_NONE)) { | |
faa44e3d | 419 | fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode); |
4750a96f | 420 | if (fd == -1) { |
2289be19 AK |
421 | err = fd; |
422 | goto out; | |
4750a96f VJ |
423 | } |
424 | err = local_post_create_passthrough(fs_ctx, path, credp); | |
425 | if (err == -1) { | |
426 | serrno = errno; | |
427 | goto err_end; | |
428 | } | |
429 | } | |
2289be19 AK |
430 | err = fd; |
431 | goto out; | |
4750a96f VJ |
432 | |
433 | err_end: | |
434 | close(fd); | |
faa44e3d | 435 | remove(rpath(fs_ctx, path, buffer)); |
4750a96f | 436 | errno = serrno; |
2289be19 AK |
437 | out: |
438 | v9fs_string_free(&fullname); | |
4750a96f | 439 | return err; |
c494dd6f AL |
440 | } |
441 | ||
758e8e38 | 442 | |
879c2813 | 443 | static int local_symlink(FsContext *fs_ctx, const char *oldpath, |
2289be19 | 444 | V9fsPath *dir_path, const char *name, FsCred *credp) |
c494dd6f | 445 | { |
879c2813 VJ |
446 | int err = -1; |
447 | int serrno = 0; | |
2289be19 AK |
448 | char *newpath; |
449 | V9fsString fullname; | |
faa44e3d | 450 | char buffer[PATH_MAX]; |
879c2813 | 451 | |
2289be19 AK |
452 | v9fs_string_init(&fullname); |
453 | v9fs_string_sprintf(&fullname, "%s/%s", dir_path->data, name); | |
454 | newpath = fullname.data; | |
455 | ||
879c2813 | 456 | /* Determine the security model */ |
b97400ca | 457 | if (fs_ctx->export_flags & V9FS_SM_MAPPED) { |
879c2813 VJ |
458 | int fd; |
459 | ssize_t oldpath_size, write_size; | |
faa44e3d | 460 | fd = open(rpath(fs_ctx, newpath, buffer), O_CREAT|O_EXCL|O_RDWR, |
879c2813 VJ |
461 | SM_LOCAL_MODE_BITS); |
462 | if (fd == -1) { | |
2289be19 AK |
463 | err = fd; |
464 | goto out; | |
879c2813 VJ |
465 | } |
466 | /* Write the oldpath (target) to the file. */ | |
f35bde2f | 467 | oldpath_size = strlen(oldpath); |
879c2813 VJ |
468 | do { |
469 | write_size = write(fd, (void *)oldpath, oldpath_size); | |
470 | } while (write_size == -1 && errno == EINTR); | |
471 | ||
472 | if (write_size != oldpath_size) { | |
473 | serrno = errno; | |
474 | close(fd); | |
475 | err = -1; | |
476 | goto err_end; | |
477 | } | |
478 | close(fd); | |
479 | /* Set cleint credentials in symlink's xattr */ | |
480 | credp->fc_mode = credp->fc_mode|S_IFLNK; | |
faa44e3d | 481 | err = local_set_xattr(rpath(fs_ctx, newpath, buffer), credp); |
879c2813 VJ |
482 | if (err == -1) { |
483 | serrno = errno; | |
484 | goto err_end; | |
485 | } | |
b97400ca AK |
486 | } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || |
487 | (fs_ctx->export_flags & V9FS_SM_NONE)) { | |
faa44e3d | 488 | err = symlink(oldpath, rpath(fs_ctx, newpath, buffer)); |
879c2813 | 489 | if (err) { |
2289be19 | 490 | goto out; |
879c2813 | 491 | } |
faa44e3d | 492 | err = lchown(rpath(fs_ctx, newpath, buffer), credp->fc_uid, |
2289be19 | 493 | credp->fc_gid); |
879c2813 | 494 | if (err == -1) { |
12848bfc AK |
495 | /* |
496 | * If we fail to change ownership and if we are | |
497 | * using security model none. Ignore the error | |
498 | */ | |
b97400ca | 499 | if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) { |
12848bfc AK |
500 | serrno = errno; |
501 | goto err_end; | |
502 | } else | |
503 | err = 0; | |
879c2813 VJ |
504 | } |
505 | } | |
2289be19 | 506 | goto out; |
879c2813 VJ |
507 | |
508 | err_end: | |
faa44e3d | 509 | remove(rpath(fs_ctx, newpath, buffer)); |
879c2813 | 510 | errno = serrno; |
2289be19 AK |
511 | out: |
512 | v9fs_string_free(&fullname); | |
879c2813 | 513 | return err; |
c494dd6f AL |
514 | } |
515 | ||
2289be19 AK |
516 | static int local_link(FsContext *ctx, V9fsPath *oldpath, |
517 | V9fsPath *dirpath, const char *name) | |
c494dd6f | 518 | { |
2289be19 AK |
519 | int ret; |
520 | V9fsString newpath; | |
faa44e3d | 521 | char buffer[PATH_MAX], buffer1[PATH_MAX]; |
c494dd6f | 522 | |
2289be19 AK |
523 | v9fs_string_init(&newpath); |
524 | v9fs_string_sprintf(&newpath, "%s/%s", dirpath->data, name); | |
525 | ||
526 | ret = link(rpath(ctx, oldpath->data, buffer), | |
527 | rpath(ctx, newpath.data, buffer1)); | |
528 | v9fs_string_free(&newpath); | |
529 | return ret; | |
c494dd6f AL |
530 | } |
531 | ||
2289be19 | 532 | static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size) |
8cf89e00 | 533 | { |
faa44e3d | 534 | char buffer[PATH_MAX]; |
2289be19 AK |
535 | char *path = fs_path->data; |
536 | ||
faa44e3d | 537 | return truncate(rpath(ctx, path, buffer), size); |
8cf89e00 AL |
538 | } |
539 | ||
540 | static int local_rename(FsContext *ctx, const char *oldpath, | |
541 | const char *newpath) | |
542 | { | |
faa44e3d | 543 | char buffer[PATH_MAX], buffer1[PATH_MAX]; |
8cf89e00 | 544 | |
faa44e3d | 545 | return rename(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1)); |
8cf89e00 AL |
546 | } |
547 | ||
2289be19 | 548 | static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) |
8cf89e00 | 549 | { |
faa44e3d | 550 | char buffer[PATH_MAX]; |
2289be19 AK |
551 | char *path = fs_path->data; |
552 | ||
c79ce737 | 553 | if ((credp->fc_uid == -1 && credp->fc_gid == -1) || |
17b1971f AK |
554 | (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || |
555 | (fs_ctx->export_flags & V9FS_SM_NONE)) { | |
556 | return lchown(rpath(fs_ctx, path, buffer), | |
557 | credp->fc_uid, credp->fc_gid); | |
b97400ca | 558 | } else if (fs_ctx->export_flags & V9FS_SM_MAPPED) { |
faa44e3d | 559 | return local_set_xattr(rpath(fs_ctx, path, buffer), credp); |
f7613bee VJ |
560 | } |
561 | return -1; | |
8cf89e00 AL |
562 | } |
563 | ||
2289be19 | 564 | static int local_utimensat(FsContext *s, V9fsPath *fs_path, |
38671423 | 565 | const struct timespec *buf) |
8cf89e00 | 566 | { |
faa44e3d | 567 | char buffer[PATH_MAX]; |
2289be19 AK |
568 | char *path = fs_path->data; |
569 | ||
faa44e3d | 570 | return qemu_utimensat(AT_FDCWD, rpath(s, path, buffer), buf, |
2289be19 | 571 | AT_SYMLINK_NOFOLLOW); |
8cf89e00 AL |
572 | } |
573 | ||
5bae1900 AL |
574 | static int local_remove(FsContext *ctx, const char *path) |
575 | { | |
faa44e3d VJ |
576 | char buffer[PATH_MAX]; |
577 | return remove(rpath(ctx, path, buffer)); | |
5bae1900 AL |
578 | } |
579 | ||
49594973 | 580 | static int local_fsync(FsContext *ctx, int fd, int datasync) |
8cf89e00 | 581 | { |
49594973 VJ |
582 | if (datasync) { |
583 | return qemu_fdatasync(fd); | |
584 | } else { | |
585 | return fsync(fd); | |
586 | } | |
8cf89e00 AL |
587 | } |
588 | ||
2289be19 | 589 | static int local_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf) |
be940c87 | 590 | { |
faa44e3d | 591 | char buffer[PATH_MAX]; |
2289be19 AK |
592 | char *path = fs_path->data; |
593 | ||
594 | return statfs(rpath(s, path, buffer), stbuf); | |
be940c87 MK |
595 | } |
596 | ||
2289be19 | 597 | static ssize_t local_lgetxattr(FsContext *ctx, V9fsPath *fs_path, |
fa32ef88 AK |
598 | const char *name, void *value, size_t size) |
599 | { | |
2289be19 AK |
600 | char *path = fs_path->data; |
601 | ||
fc22118d | 602 | return v9fs_get_xattr(ctx, path, name, value, size); |
fa32ef88 AK |
603 | } |
604 | ||
2289be19 | 605 | static ssize_t local_llistxattr(FsContext *ctx, V9fsPath *fs_path, |
fa32ef88 AK |
606 | void *value, size_t size) |
607 | { | |
2289be19 AK |
608 | char *path = fs_path->data; |
609 | ||
fc22118d | 610 | return v9fs_list_xattr(ctx, path, value, size); |
fa32ef88 AK |
611 | } |
612 | ||
2289be19 | 613 | static int local_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name, |
10b468bd AK |
614 | void *value, size_t size, int flags) |
615 | { | |
2289be19 AK |
616 | char *path = fs_path->data; |
617 | ||
fc22118d | 618 | return v9fs_set_xattr(ctx, path, name, value, size, flags); |
10b468bd AK |
619 | } |
620 | ||
2289be19 AK |
621 | static int local_lremovexattr(FsContext *ctx, V9fsPath *fs_path, |
622 | const char *name) | |
9ed3ef26 | 623 | { |
2289be19 AK |
624 | char *path = fs_path->data; |
625 | ||
fc22118d | 626 | return v9fs_remove_xattr(ctx, path, name); |
9ed3ef26 AK |
627 | } |
628 | ||
2289be19 AK |
629 | static int local_name_to_path(FsContext *ctx, V9fsPath *dir_path, |
630 | const char *name, V9fsPath *target) | |
631 | { | |
632 | if (dir_path) { | |
633 | v9fs_string_sprintf((V9fsString *)target, "%s/%s", | |
634 | dir_path->data, name); | |
635 | } else { | |
636 | v9fs_string_sprintf((V9fsString *)target, "%s", name); | |
637 | } | |
638 | /* Bump the size for including terminating NULL */ | |
639 | target->size++; | |
640 | return 0; | |
641 | } | |
642 | ||
643 | static int local_renameat(FsContext *ctx, V9fsPath *olddir, | |
644 | const char *old_name, V9fsPath *newdir, | |
645 | const char *new_name) | |
646 | { | |
647 | int ret; | |
648 | V9fsString old_full_name, new_full_name; | |
649 | ||
650 | v9fs_string_init(&old_full_name); | |
651 | v9fs_string_init(&new_full_name); | |
652 | ||
653 | v9fs_string_sprintf(&old_full_name, "%s/%s", olddir->data, old_name); | |
654 | v9fs_string_sprintf(&new_full_name, "%s/%s", newdir->data, new_name); | |
655 | ||
656 | ret = local_rename(ctx, old_full_name.data, new_full_name.data); | |
657 | v9fs_string_free(&old_full_name); | |
658 | v9fs_string_free(&new_full_name); | |
659 | return ret; | |
660 | } | |
661 | ||
662 | static int local_unlinkat(FsContext *ctx, V9fsPath *dir, | |
663 | const char *name, int flags) | |
664 | { | |
665 | int ret; | |
666 | V9fsString fullname; | |
667 | char buffer[PATH_MAX]; | |
668 | v9fs_string_init(&fullname); | |
669 | ||
670 | v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name); | |
671 | ret = remove(rpath(ctx, fullname.data, buffer)); | |
672 | v9fs_string_free(&fullname); | |
673 | ||
674 | return ret; | |
675 | } | |
9ed3ef26 | 676 | |
e06a765e HPB |
677 | static int local_ioc_getversion(FsContext *ctx, V9fsPath *path, |
678 | mode_t st_mode, uint64_t *st_gen) | |
679 | { | |
680 | int err, fd; | |
681 | /* | |
682 | * Do not try to open special files like device nodes, fifos etc | |
683 | * We can get fd for regular files and directories only | |
684 | */ | |
685 | if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) { | |
686 | return 0; | |
687 | } | |
688 | fd = local_open(ctx, path, O_RDONLY); | |
689 | if (fd < 0) { | |
690 | return fd; | |
691 | } | |
692 | err = ioctl(fd, FS_IOC_GETVERSION, st_gen); | |
693 | local_close(ctx, fd); | |
694 | return err; | |
695 | } | |
696 | ||
0174fe73 AK |
697 | static int local_init(FsContext *ctx) |
698 | { | |
e06a765e HPB |
699 | int err; |
700 | struct statfs stbuf; | |
701 | ||
c98f1d4a | 702 | ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT; |
e06a765e HPB |
703 | err = statfs(ctx->fs_root, &stbuf); |
704 | if (!err) { | |
705 | switch (stbuf.f_type) { | |
706 | case EXT2_SUPER_MAGIC: | |
707 | case BTRFS_SUPER_MAGIC: | |
708 | case REISERFS_SUPER_MAGIC: | |
709 | case XFS_SUPER_MAGIC: | |
710 | ctx->exops.get_st_gen = local_ioc_getversion; | |
711 | break; | |
712 | } | |
713 | } | |
714 | return err; | |
0174fe73 AK |
715 | } |
716 | ||
9f107513 | 717 | FileOperations local_ops = { |
0174fe73 | 718 | .init = local_init, |
131dcb25 | 719 | .lstat = local_lstat, |
131dcb25 AL |
720 | .readlink = local_readlink, |
721 | .close = local_close, | |
722 | .closedir = local_closedir, | |
a6568fe2 AL |
723 | .open = local_open, |
724 | .opendir = local_opendir, | |
a9231555 AL |
725 | .rewinddir = local_rewinddir, |
726 | .telldir = local_telldir, | |
5f524c1e | 727 | .readdir_r = local_readdir_r, |
a9231555 | 728 | .seekdir = local_seekdir, |
56d15a53 SG |
729 | .preadv = local_preadv, |
730 | .pwritev = local_pwritev, | |
c494dd6f AL |
731 | .chmod = local_chmod, |
732 | .mknod = local_mknod, | |
c494dd6f AL |
733 | .mkdir = local_mkdir, |
734 | .fstat = local_fstat, | |
735 | .open2 = local_open2, | |
736 | .symlink = local_symlink, | |
737 | .link = local_link, | |
8cf89e00 AL |
738 | .truncate = local_truncate, |
739 | .rename = local_rename, | |
740 | .chown = local_chown, | |
74bc02b2 | 741 | .utimensat = local_utimensat, |
5bae1900 | 742 | .remove = local_remove, |
8cf89e00 | 743 | .fsync = local_fsync, |
be940c87 | 744 | .statfs = local_statfs, |
fa32ef88 AK |
745 | .lgetxattr = local_lgetxattr, |
746 | .llistxattr = local_llistxattr, | |
10b468bd | 747 | .lsetxattr = local_lsetxattr, |
9ed3ef26 | 748 | .lremovexattr = local_lremovexattr, |
2289be19 AK |
749 | .name_to_path = local_name_to_path, |
750 | .renameat = local_renameat, | |
751 | .unlinkat = local_unlinkat, | |
9f107513 | 752 | }; |