]>
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 | */ | |
13 | #include "virtio.h" | |
14 | #include "virtio-9p.h" | |
c494dd6f | 15 | #include <arpa/inet.h> |
131dcb25 AL |
16 | #include <pwd.h> |
17 | #include <grp.h> | |
c494dd6f AL |
18 | #include <sys/socket.h> |
19 | #include <sys/un.h> | |
758e8e38 | 20 | #include <attr/xattr.h> |
131dcb25 AL |
21 | |
22 | static const char *rpath(FsContext *ctx, const char *path) | |
23 | { | |
24 | /* FIXME: so wrong... */ | |
25 | static char buffer[4096]; | |
26 | snprintf(buffer, sizeof(buffer), "%s/%s", ctx->fs_root, path); | |
27 | return buffer; | |
28 | } | |
29 | ||
1237ad76 VJ |
30 | |
31 | static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf) | |
131dcb25 | 32 | { |
1237ad76 VJ |
33 | int err; |
34 | err = lstat(rpath(fs_ctx, path), stbuf); | |
35 | if (err) { | |
36 | return err; | |
37 | } | |
38 | if (fs_ctx->fs_sm == SM_MAPPED) { | |
39 | /* Actual credentials are part of extended attrs */ | |
40 | uid_t tmp_uid; | |
41 | gid_t tmp_gid; | |
42 | mode_t tmp_mode; | |
43 | dev_t tmp_dev; | |
44 | if (getxattr(rpath(fs_ctx, path), "user.virtfs.uid", &tmp_uid, | |
45 | sizeof(uid_t)) > 0) { | |
46 | stbuf->st_uid = tmp_uid; | |
47 | } | |
48 | if (getxattr(rpath(fs_ctx, path), "user.virtfs.gid", &tmp_gid, | |
49 | sizeof(gid_t)) > 0) { | |
50 | stbuf->st_gid = tmp_gid; | |
51 | } | |
52 | if (getxattr(rpath(fs_ctx, path), "user.virtfs.mode", &tmp_mode, | |
53 | sizeof(mode_t)) > 0) { | |
54 | stbuf->st_mode = tmp_mode; | |
55 | } | |
56 | if (getxattr(rpath(fs_ctx, path), "user.virtfs.rdev", &tmp_dev, | |
57 | sizeof(dev_t)) > 0) { | |
58 | stbuf->st_rdev = tmp_dev; | |
59 | } | |
60 | } | |
61 | return err; | |
131dcb25 AL |
62 | } |
63 | ||
758e8e38 | 64 | static int local_set_xattr(const char *path, FsCred *credp) |
131dcb25 | 65 | { |
758e8e38 VJ |
66 | int err; |
67 | if (credp->fc_uid != -1) { | |
68 | err = setxattr(path, "user.virtfs.uid", &credp->fc_uid, sizeof(uid_t), | |
69 | 0); | |
70 | if (err) { | |
71 | return err; | |
72 | } | |
131dcb25 | 73 | } |
758e8e38 VJ |
74 | if (credp->fc_gid != -1) { |
75 | err = setxattr(path, "user.virtfs.gid", &credp->fc_gid, sizeof(gid_t), | |
76 | 0); | |
77 | if (err) { | |
78 | return err; | |
79 | } | |
131dcb25 | 80 | } |
758e8e38 VJ |
81 | if (credp->fc_mode != -1) { |
82 | err = setxattr(path, "user.virtfs.mode", &credp->fc_mode, | |
83 | sizeof(mode_t), 0); | |
84 | if (err) { | |
85 | return err; | |
86 | } | |
131dcb25 | 87 | } |
758e8e38 VJ |
88 | if (credp->fc_rdev != -1) { |
89 | err = setxattr(path, "user.virtfs.rdev", &credp->fc_rdev, | |
90 | sizeof(dev_t), 0); | |
91 | if (err) { | |
92 | return err; | |
93 | } | |
131dcb25 | 94 | } |
131dcb25 AL |
95 | return 0; |
96 | } | |
97 | ||
98 | static ssize_t local_readlink(FsContext *ctx, const char *path, | |
99 | char *buf, size_t bufsz) | |
100 | { | |
101 | return readlink(rpath(ctx, path), buf, bufsz); | |
102 | } | |
103 | ||
104 | static int local_close(FsContext *ctx, int fd) | |
105 | { | |
106 | return close(fd); | |
107 | } | |
108 | ||
109 | static int local_closedir(FsContext *ctx, DIR *dir) | |
110 | { | |
111 | return closedir(dir); | |
112 | } | |
9f107513 | 113 | |
a6568fe2 AL |
114 | static int local_open(FsContext *ctx, const char *path, int flags) |
115 | { | |
116 | return open(rpath(ctx, path), flags); | |
117 | } | |
118 | ||
119 | static DIR *local_opendir(FsContext *ctx, const char *path) | |
120 | { | |
121 | return opendir(rpath(ctx, path)); | |
122 | } | |
123 | ||
a9231555 AL |
124 | static void local_rewinddir(FsContext *ctx, DIR *dir) |
125 | { | |
126 | return rewinddir(dir); | |
127 | } | |
128 | ||
129 | static off_t local_telldir(FsContext *ctx, DIR *dir) | |
130 | { | |
131 | return telldir(dir); | |
132 | } | |
133 | ||
134 | static struct dirent *local_readdir(FsContext *ctx, DIR *dir) | |
135 | { | |
136 | return readdir(dir); | |
137 | } | |
138 | ||
139 | static void local_seekdir(FsContext *ctx, DIR *dir, off_t off) | |
140 | { | |
141 | return seekdir(dir, off); | |
142 | } | |
143 | ||
144 | static ssize_t local_readv(FsContext *ctx, int fd, const struct iovec *iov, | |
145 | int iovcnt) | |
146 | { | |
147 | return readv(fd, iov, iovcnt); | |
148 | } | |
149 | ||
150 | static off_t local_lseek(FsContext *ctx, int fd, off_t offset, int whence) | |
151 | { | |
152 | return lseek(fd, offset, whence); | |
153 | } | |
154 | ||
8449360c AL |
155 | static ssize_t local_writev(FsContext *ctx, int fd, const struct iovec *iov, |
156 | int iovcnt) | |
157 | { | |
158 | return writev(fd, iov, iovcnt); | |
159 | } | |
160 | ||
e95ead32 | 161 | static int local_chmod(FsContext *fs_ctx, const char *path, FsCred *credp) |
c494dd6f | 162 | { |
e95ead32 VJ |
163 | if (fs_ctx->fs_sm == SM_MAPPED) { |
164 | return local_set_xattr(rpath(fs_ctx, path), credp); | |
165 | } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) { | |
166 | return chmod(rpath(fs_ctx, path), credp->fc_mode); | |
167 | } | |
168 | return -1; | |
c494dd6f AL |
169 | } |
170 | ||
171 | static int local_mknod(FsContext *ctx, const char *path, mode_t mode, dev_t dev) | |
172 | { | |
173 | return mknod(rpath(ctx, path), mode, dev); | |
174 | } | |
175 | ||
176 | static int local_mksock(FsContext *ctx2, const char *path) | |
177 | { | |
178 | struct sockaddr_un addr; | |
179 | int s; | |
180 | ||
181 | addr.sun_family = AF_UNIX; | |
182 | snprintf(addr.sun_path, 108, "%s", rpath(ctx2, path)); | |
183 | ||
184 | s = socket(PF_UNIX, SOCK_STREAM, 0); | |
185 | if (s == -1) { | |
186 | return -1; | |
187 | } | |
188 | ||
189 | if (bind(s, (struct sockaddr *)&addr, sizeof(addr))) { | |
190 | close(s); | |
191 | return -1; | |
192 | } | |
193 | ||
194 | close(s); | |
195 | return 0; | |
196 | } | |
197 | ||
198 | static int local_mkdir(FsContext *ctx, const char *path, mode_t mode) | |
199 | { | |
200 | return mkdir(rpath(ctx, path), mode); | |
201 | } | |
202 | ||
1237ad76 | 203 | static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf) |
c494dd6f | 204 | { |
1237ad76 VJ |
205 | int err; |
206 | err = fstat(fd, stbuf); | |
207 | if (err) { | |
208 | return err; | |
209 | } | |
210 | if (fs_ctx->fs_sm == SM_MAPPED) { | |
211 | /* Actual credentials are part of extended attrs */ | |
212 | uid_t tmp_uid; | |
213 | gid_t tmp_gid; | |
214 | mode_t tmp_mode; | |
215 | dev_t tmp_dev; | |
216 | ||
217 | if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) { | |
218 | stbuf->st_uid = tmp_uid; | |
219 | } | |
220 | if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) { | |
221 | stbuf->st_gid = tmp_gid; | |
222 | } | |
223 | if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) { | |
224 | stbuf->st_mode = tmp_mode; | |
225 | } | |
226 | if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) { | |
227 | stbuf->st_rdev = tmp_dev; | |
228 | } | |
229 | } | |
230 | return err; | |
c494dd6f AL |
231 | } |
232 | ||
233 | static int local_open2(FsContext *ctx, const char *path, int flags, mode_t mode) | |
234 | { | |
235 | return open(rpath(ctx, path), flags, mode); | |
236 | } | |
237 | ||
758e8e38 | 238 | |
c494dd6f AL |
239 | static int local_symlink(FsContext *ctx, const char *oldpath, |
240 | const char *newpath) | |
241 | { | |
242 | return symlink(oldpath, rpath(ctx, newpath)); | |
243 | } | |
244 | ||
245 | static int local_link(FsContext *ctx, const char *oldpath, const char *newpath) | |
246 | { | |
247 | char *tmp = qemu_strdup(rpath(ctx, oldpath)); | |
248 | int err, serrno = 0; | |
249 | ||
250 | if (tmp == NULL) { | |
251 | return -ENOMEM; | |
252 | } | |
253 | ||
254 | err = link(tmp, rpath(ctx, newpath)); | |
255 | if (err == -1) { | |
256 | serrno = errno; | |
257 | } | |
258 | ||
259 | qemu_free(tmp); | |
260 | ||
261 | if (err == -1) { | |
262 | errno = serrno; | |
263 | } | |
264 | ||
265 | return err; | |
266 | } | |
267 | ||
8cf89e00 AL |
268 | static int local_truncate(FsContext *ctx, const char *path, off_t size) |
269 | { | |
270 | return truncate(rpath(ctx, path), size); | |
271 | } | |
272 | ||
273 | static int local_rename(FsContext *ctx, const char *oldpath, | |
274 | const char *newpath) | |
275 | { | |
276 | char *tmp; | |
277 | int err; | |
278 | ||
279 | tmp = qemu_strdup(rpath(ctx, oldpath)); | |
280 | if (tmp == NULL) { | |
281 | return -1; | |
282 | } | |
283 | ||
284 | err = rename(tmp, rpath(ctx, newpath)); | |
285 | if (err == -1) { | |
286 | int serrno = errno; | |
287 | qemu_free(tmp); | |
288 | errno = serrno; | |
289 | } else { | |
290 | qemu_free(tmp); | |
291 | } | |
292 | ||
293 | return err; | |
294 | ||
295 | } | |
296 | ||
f7613bee | 297 | static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp) |
8cf89e00 | 298 | { |
f7613bee VJ |
299 | if (fs_ctx->fs_sm == SM_MAPPED) { |
300 | return local_set_xattr(rpath(fs_ctx, path), credp); | |
301 | } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) { | |
302 | return lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid); | |
303 | } | |
304 | return -1; | |
8cf89e00 AL |
305 | } |
306 | ||
307 | static int local_utime(FsContext *ctx, const char *path, | |
308 | const struct utimbuf *buf) | |
309 | { | |
310 | return utime(rpath(ctx, path), buf); | |
311 | } | |
312 | ||
5bae1900 AL |
313 | static int local_remove(FsContext *ctx, const char *path) |
314 | { | |
315 | return remove(rpath(ctx, path)); | |
316 | } | |
317 | ||
8cf89e00 AL |
318 | static int local_fsync(FsContext *ctx, int fd) |
319 | { | |
320 | return fsync(fd); | |
321 | } | |
322 | ||
9f107513 | 323 | FileOperations local_ops = { |
131dcb25 | 324 | .lstat = local_lstat, |
131dcb25 AL |
325 | .readlink = local_readlink, |
326 | .close = local_close, | |
327 | .closedir = local_closedir, | |
a6568fe2 AL |
328 | .open = local_open, |
329 | .opendir = local_opendir, | |
a9231555 AL |
330 | .rewinddir = local_rewinddir, |
331 | .telldir = local_telldir, | |
332 | .readdir = local_readdir, | |
333 | .seekdir = local_seekdir, | |
334 | .readv = local_readv, | |
335 | .lseek = local_lseek, | |
8449360c | 336 | .writev = local_writev, |
c494dd6f AL |
337 | .chmod = local_chmod, |
338 | .mknod = local_mknod, | |
339 | .mksock = local_mksock, | |
340 | .mkdir = local_mkdir, | |
341 | .fstat = local_fstat, | |
342 | .open2 = local_open2, | |
343 | .symlink = local_symlink, | |
344 | .link = local_link, | |
8cf89e00 AL |
345 | .truncate = local_truncate, |
346 | .rename = local_rename, | |
347 | .chown = local_chown, | |
348 | .utime = local_utime, | |
5bae1900 | 349 | .remove = local_remove, |
8cf89e00 | 350 | .fsync = local_fsync, |
9f107513 | 351 | }; |