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