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