root / hw / 9pfs / virtio-9p-handle.c @ cc720ddb
History | View | Annotate | Download (17.5 kB)
1 |
/*
|
---|---|
2 |
* Virtio 9p handle callback
|
3 |
*
|
4 |
* Copyright IBM, Corp. 2011
|
5 |
*
|
6 |
* Authors:
|
7 |
* Aneesh Kumar K.V <aneesh.kumar@linux.vnet.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 |
|
14 |
#include "hw/virtio.h" |
15 |
#include "virtio-9p.h" |
16 |
#include "virtio-9p-xattr.h" |
17 |
#include <arpa/inet.h> |
18 |
#include <pwd.h> |
19 |
#include <grp.h> |
20 |
#include <sys/socket.h> |
21 |
#include <sys/un.h> |
22 |
#include <attr/xattr.h> |
23 |
#include <unistd.h> |
24 |
#include <linux/fs.h> |
25 |
#ifdef CONFIG_LINUX_MAGIC_H
|
26 |
#include <linux/magic.h> |
27 |
#endif
|
28 |
#include <sys/ioctl.h> |
29 |
|
30 |
#ifndef XFS_SUPER_MAGIC
|
31 |
#define XFS_SUPER_MAGIC 0x58465342 |
32 |
#endif
|
33 |
#ifndef EXT2_SUPER_MAGIC
|
34 |
#define EXT2_SUPER_MAGIC 0xEF53 |
35 |
#endif
|
36 |
#ifndef REISERFS_SUPER_MAGIC
|
37 |
#define REISERFS_SUPER_MAGIC 0x52654973 |
38 |
#endif
|
39 |
#ifndef BTRFS_SUPER_MAGIC
|
40 |
#define BTRFS_SUPER_MAGIC 0x9123683E |
41 |
#endif
|
42 |
|
43 |
struct handle_data {
|
44 |
int mountfd;
|
45 |
int handle_bytes;
|
46 |
}; |
47 |
|
48 |
#ifdef CONFIG_OPEN_BY_HANDLE
|
49 |
static inline int name_to_handle(int dirfd, const char *name, |
50 |
struct file_handle *fh, int *mnt_id, int flags) |
51 |
{ |
52 |
return name_to_handle_at(dirfd, name, fh, mnt_id, flags);
|
53 |
} |
54 |
|
55 |
static inline int open_by_handle(int mountfd, const char *fh, int flags) |
56 |
{ |
57 |
return open_by_handle_at(mountfd, (struct file_handle *)fh, flags); |
58 |
} |
59 |
#else
|
60 |
|
61 |
struct file_handle {
|
62 |
unsigned int handle_bytes; |
63 |
int handle_type;
|
64 |
unsigned char handle[0]; |
65 |
}; |
66 |
|
67 |
#ifndef AT_EMPTY_PATH
|
68 |
#define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */ |
69 |
#endif
|
70 |
#ifndef O_PATH
|
71 |
#define O_PATH 010000000 |
72 |
#endif
|
73 |
|
74 |
static inline int name_to_handle(int dirfd, const char *name, |
75 |
struct file_handle *fh, int *mnt_id, int flags) |
76 |
{ |
77 |
errno = ENOSYS; |
78 |
return -1; |
79 |
} |
80 |
|
81 |
static inline int open_by_handle(int mountfd, const char *fh, int flags) |
82 |
{ |
83 |
errno = ENOSYS; |
84 |
return -1; |
85 |
} |
86 |
#endif
|
87 |
|
88 |
static int handle_update_file_cred(int dirfd, const char *name, FsCred *credp) |
89 |
{ |
90 |
int fd, ret;
|
91 |
fd = openat(dirfd, name, O_NONBLOCK | O_NOFOLLOW);; |
92 |
if (fd < 0) { |
93 |
return fd;
|
94 |
} |
95 |
ret = fchmod(fd, credp->fc_mode & 07777);
|
96 |
if (ret < 0) { |
97 |
goto err_out;
|
98 |
} |
99 |
ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
|
100 |
err_out:
|
101 |
close(fd); |
102 |
return ret;
|
103 |
} |
104 |
|
105 |
|
106 |
static int handle_lstat(FsContext *fs_ctx, V9fsPath *fs_path, |
107 |
struct stat *stbuf)
|
108 |
{ |
109 |
int fd, ret;
|
110 |
struct handle_data *data = (struct handle_data *)fs_ctx->private; |
111 |
|
112 |
fd = open_by_handle(data->mountfd, fs_path->data, O_PATH); |
113 |
if (fd < 0) { |
114 |
return fd;
|
115 |
} |
116 |
ret = fstatat(fd, "", stbuf, AT_EMPTY_PATH);
|
117 |
close(fd); |
118 |
return ret;
|
119 |
} |
120 |
|
121 |
static ssize_t handle_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
|
122 |
char *buf, size_t bufsz)
|
123 |
{ |
124 |
int fd, ret;
|
125 |
struct handle_data *data = (struct handle_data *)fs_ctx->private; |
126 |
|
127 |
fd = open_by_handle(data->mountfd, fs_path->data, O_PATH); |
128 |
if (fd < 0) { |
129 |
return fd;
|
130 |
} |
131 |
ret = readlinkat(fd, "", buf, bufsz);
|
132 |
close(fd); |
133 |
return ret;
|
134 |
} |
135 |
|
136 |
static int handle_close(FsContext *ctx, V9fsFidOpenState *fs) |
137 |
{ |
138 |
return close(fs->fd);
|
139 |
} |
140 |
|
141 |
static int handle_closedir(FsContext *ctx, V9fsFidOpenState *fs) |
142 |
{ |
143 |
return closedir(fs->dir);
|
144 |
} |
145 |
|
146 |
static int handle_open(FsContext *ctx, V9fsPath *fs_path, |
147 |
int flags, V9fsFidOpenState *fs)
|
148 |
{ |
149 |
struct handle_data *data = (struct handle_data *)ctx->private; |
150 |
|
151 |
fs->fd = open_by_handle(data->mountfd, fs_path->data, flags); |
152 |
return fs->fd;
|
153 |
} |
154 |
|
155 |
static int handle_opendir(FsContext *ctx, |
156 |
V9fsPath *fs_path, V9fsFidOpenState *fs) |
157 |
{ |
158 |
int ret;
|
159 |
ret = handle_open(ctx, fs_path, O_DIRECTORY, fs); |
160 |
if (ret < 0) { |
161 |
return -1; |
162 |
} |
163 |
fs->dir = fdopendir(ret); |
164 |
if (!fs->dir) {
|
165 |
return -1; |
166 |
} |
167 |
return 0; |
168 |
} |
169 |
|
170 |
static void handle_rewinddir(FsContext *ctx, V9fsFidOpenState *fs) |
171 |
{ |
172 |
return rewinddir(fs->dir);
|
173 |
} |
174 |
|
175 |
static off_t handle_telldir(FsContext *ctx, V9fsFidOpenState *fs)
|
176 |
{ |
177 |
return telldir(fs->dir);
|
178 |
} |
179 |
|
180 |
static int handle_readdir_r(FsContext *ctx, V9fsFidOpenState *fs, |
181 |
struct dirent *entry,
|
182 |
struct dirent **result)
|
183 |
{ |
184 |
return readdir_r(fs->dir, entry, result);
|
185 |
} |
186 |
|
187 |
static void handle_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off) |
188 |
{ |
189 |
return seekdir(fs->dir, off);
|
190 |
} |
191 |
|
192 |
static ssize_t handle_preadv(FsContext *ctx, V9fsFidOpenState *fs,
|
193 |
const struct iovec *iov, |
194 |
int iovcnt, off_t offset)
|
195 |
{ |
196 |
#ifdef CONFIG_PREADV
|
197 |
return preadv(fs->fd, iov, iovcnt, offset);
|
198 |
#else
|
199 |
int err = lseek(fs->fd, offset, SEEK_SET);
|
200 |
if (err == -1) { |
201 |
return err;
|
202 |
} else {
|
203 |
return readv(fs->fd, iov, iovcnt);
|
204 |
} |
205 |
#endif
|
206 |
} |
207 |
|
208 |
static ssize_t handle_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
|
209 |
const struct iovec *iov, |
210 |
int iovcnt, off_t offset)
|
211 |
{ |
212 |
ssize_t ret; |
213 |
#ifdef CONFIG_PREADV
|
214 |
ret = pwritev(fs->fd, iov, iovcnt, offset); |
215 |
#else
|
216 |
int err = lseek(fs->fd, offset, SEEK_SET);
|
217 |
if (err == -1) { |
218 |
return err;
|
219 |
} else {
|
220 |
ret = writev(fs->fd, iov, iovcnt); |
221 |
} |
222 |
#endif
|
223 |
#ifdef CONFIG_SYNC_FILE_RANGE
|
224 |
if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) { |
225 |
/*
|
226 |
* Initiate a writeback. This is not a data integrity sync.
|
227 |
* We want to ensure that we don't leave dirty pages in the cache
|
228 |
* after write when writeout=immediate is sepcified.
|
229 |
*/
|
230 |
sync_file_range(fs->fd, offset, ret, |
231 |
SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE); |
232 |
} |
233 |
#endif
|
234 |
return ret;
|
235 |
} |
236 |
|
237 |
static int handle_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) |
238 |
{ |
239 |
int fd, ret;
|
240 |
struct handle_data *data = (struct handle_data *)fs_ctx->private; |
241 |
|
242 |
fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK); |
243 |
if (fd < 0) { |
244 |
return fd;
|
245 |
} |
246 |
ret = fchmod(fd, credp->fc_mode); |
247 |
close(fd); |
248 |
return ret;
|
249 |
} |
250 |
|
251 |
static int handle_mknod(FsContext *fs_ctx, V9fsPath *dir_path, |
252 |
const char *name, FsCred *credp) |
253 |
{ |
254 |
int dirfd, ret;
|
255 |
struct handle_data *data = (struct handle_data *)fs_ctx->private; |
256 |
|
257 |
dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH); |
258 |
if (dirfd < 0) { |
259 |
return dirfd;
|
260 |
} |
261 |
ret = mknodat(dirfd, name, credp->fc_mode, credp->fc_rdev); |
262 |
if (!ret) {
|
263 |
ret = handle_update_file_cred(dirfd, name, credp); |
264 |
} |
265 |
close(dirfd); |
266 |
return ret;
|
267 |
} |
268 |
|
269 |
static int handle_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, |
270 |
const char *name, FsCred *credp) |
271 |
{ |
272 |
int dirfd, ret;
|
273 |
struct handle_data *data = (struct handle_data *)fs_ctx->private; |
274 |
|
275 |
dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH); |
276 |
if (dirfd < 0) { |
277 |
return dirfd;
|
278 |
} |
279 |
ret = mkdirat(dirfd, name, credp->fc_mode); |
280 |
if (!ret) {
|
281 |
ret = handle_update_file_cred(dirfd, name, credp); |
282 |
} |
283 |
close(dirfd); |
284 |
return ret;
|
285 |
} |
286 |
|
287 |
static int handle_fstat(FsContext *fs_ctx, V9fsFidOpenState *fs, |
288 |
struct stat *stbuf)
|
289 |
{ |
290 |
return fstat(fs->fd, stbuf);
|
291 |
} |
292 |
|
293 |
static int handle_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, |
294 |
int flags, FsCred *credp, V9fsFidOpenState *fs)
|
295 |
{ |
296 |
int ret;
|
297 |
int dirfd, fd;
|
298 |
struct handle_data *data = (struct handle_data *)fs_ctx->private; |
299 |
|
300 |
dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH); |
301 |
if (dirfd < 0) { |
302 |
return dirfd;
|
303 |
} |
304 |
fd = openat(dirfd, name, flags | O_NOFOLLOW, credp->fc_mode); |
305 |
if (fd >= 0) { |
306 |
ret = handle_update_file_cred(dirfd, name, credp); |
307 |
if (ret < 0) { |
308 |
close(fd); |
309 |
fd = ret; |
310 |
} else {
|
311 |
fs->fd = fd; |
312 |
} |
313 |
} |
314 |
close(dirfd); |
315 |
return fd;
|
316 |
} |
317 |
|
318 |
|
319 |
static int handle_symlink(FsContext *fs_ctx, const char *oldpath, |
320 |
V9fsPath *dir_path, const char *name, FsCred *credp) |
321 |
{ |
322 |
int fd, dirfd, ret;
|
323 |
struct handle_data *data = (struct handle_data *)fs_ctx->private; |
324 |
|
325 |
dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH); |
326 |
if (dirfd < 0) { |
327 |
return dirfd;
|
328 |
} |
329 |
ret = symlinkat(oldpath, dirfd, name); |
330 |
if (!ret) {
|
331 |
fd = openat(dirfd, name, O_PATH | O_NOFOLLOW); |
332 |
if (fd < 0) { |
333 |
ret = fd; |
334 |
goto err_out;
|
335 |
} |
336 |
ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
|
337 |
close(fd); |
338 |
} |
339 |
err_out:
|
340 |
close(dirfd); |
341 |
return ret;
|
342 |
} |
343 |
|
344 |
static int handle_link(FsContext *ctx, V9fsPath *oldpath, |
345 |
V9fsPath *dirpath, const char *name) |
346 |
{ |
347 |
int oldfd, newdirfd, ret;
|
348 |
struct handle_data *data = (struct handle_data *)ctx->private; |
349 |
|
350 |
oldfd = open_by_handle(data->mountfd, oldpath->data, O_PATH); |
351 |
if (oldfd < 0) { |
352 |
return oldfd;
|
353 |
} |
354 |
newdirfd = open_by_handle(data->mountfd, dirpath->data, O_PATH); |
355 |
if (newdirfd < 0) { |
356 |
close(oldfd); |
357 |
return newdirfd;
|
358 |
} |
359 |
ret = linkat(oldfd, "", newdirfd, name, AT_EMPTY_PATH);
|
360 |
close(newdirfd); |
361 |
close(oldfd); |
362 |
return ret;
|
363 |
} |
364 |
|
365 |
static int handle_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size) |
366 |
{ |
367 |
int fd, ret;
|
368 |
struct handle_data *data = (struct handle_data *)ctx->private; |
369 |
|
370 |
fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK | O_WRONLY); |
371 |
if (fd < 0) { |
372 |
return fd;
|
373 |
} |
374 |
ret = ftruncate(fd, size); |
375 |
close(fd); |
376 |
return ret;
|
377 |
} |
378 |
|
379 |
static int handle_rename(FsContext *ctx, const char *oldpath, |
380 |
const char *newpath) |
381 |
{ |
382 |
errno = EOPNOTSUPP; |
383 |
return -1; |
384 |
} |
385 |
|
386 |
static int handle_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) |
387 |
{ |
388 |
int fd, ret;
|
389 |
struct handle_data *data = (struct handle_data *)fs_ctx->private; |
390 |
|
391 |
fd = open_by_handle(data->mountfd, fs_path->data, O_PATH); |
392 |
if (fd < 0) { |
393 |
return fd;
|
394 |
} |
395 |
ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
|
396 |
close(fd); |
397 |
return ret;
|
398 |
} |
399 |
|
400 |
static int handle_utimensat(FsContext *ctx, V9fsPath *fs_path, |
401 |
const struct timespec *buf) |
402 |
{ |
403 |
int ret;
|
404 |
#ifdef CONFIG_UTIMENSAT
|
405 |
int fd;
|
406 |
struct handle_data *data = (struct handle_data *)ctx->private; |
407 |
|
408 |
fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK); |
409 |
if (fd < 0) { |
410 |
return fd;
|
411 |
} |
412 |
ret = futimens(fd, buf); |
413 |
close(fd); |
414 |
#else
|
415 |
ret = -1;
|
416 |
errno = ENOSYS; |
417 |
#endif
|
418 |
return ret;
|
419 |
} |
420 |
|
421 |
static int handle_remove(FsContext *ctx, const char *path) |
422 |
{ |
423 |
errno = EOPNOTSUPP; |
424 |
return -1; |
425 |
} |
426 |
|
427 |
static int handle_fsync(FsContext *ctx, V9fsFidOpenState *fs, int datasync) |
428 |
{ |
429 |
if (datasync) {
|
430 |
return qemu_fdatasync(fs->fd);
|
431 |
} else {
|
432 |
return fsync(fs->fd);
|
433 |
} |
434 |
} |
435 |
|
436 |
static int handle_statfs(FsContext *ctx, V9fsPath *fs_path, |
437 |
struct statfs *stbuf)
|
438 |
{ |
439 |
int fd, ret;
|
440 |
struct handle_data *data = (struct handle_data *)ctx->private; |
441 |
|
442 |
fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK); |
443 |
if (fd < 0) { |
444 |
return fd;
|
445 |
} |
446 |
ret = fstatfs(fd, stbuf); |
447 |
close(fd); |
448 |
return ret;
|
449 |
} |
450 |
|
451 |
static ssize_t handle_lgetxattr(FsContext *ctx, V9fsPath *fs_path,
|
452 |
const char *name, void *value, size_t size) |
453 |
{ |
454 |
int fd, ret;
|
455 |
struct handle_data *data = (struct handle_data *)ctx->private; |
456 |
|
457 |
fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK); |
458 |
if (fd < 0) { |
459 |
return fd;
|
460 |
} |
461 |
ret = fgetxattr(fd, name, value, size); |
462 |
close(fd); |
463 |
return ret;
|
464 |
} |
465 |
|
466 |
static ssize_t handle_llistxattr(FsContext *ctx, V9fsPath *fs_path,
|
467 |
void *value, size_t size)
|
468 |
{ |
469 |
int fd, ret;
|
470 |
struct handle_data *data = (struct handle_data *)ctx->private; |
471 |
|
472 |
fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK); |
473 |
if (fd < 0) { |
474 |
return fd;
|
475 |
} |
476 |
ret = flistxattr(fd, value, size); |
477 |
close(fd); |
478 |
return ret;
|
479 |
} |
480 |
|
481 |
static int handle_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name, |
482 |
void *value, size_t size, int flags) |
483 |
{ |
484 |
int fd, ret;
|
485 |
struct handle_data *data = (struct handle_data *)ctx->private; |
486 |
|
487 |
fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK); |
488 |
if (fd < 0) { |
489 |
return fd;
|
490 |
} |
491 |
ret = fsetxattr(fd, name, value, size, flags); |
492 |
close(fd); |
493 |
return ret;
|
494 |
} |
495 |
|
496 |
static int handle_lremovexattr(FsContext *ctx, V9fsPath *fs_path, |
497 |
const char *name) |
498 |
{ |
499 |
int fd, ret;
|
500 |
struct handle_data *data = (struct handle_data *)ctx->private; |
501 |
|
502 |
fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK); |
503 |
if (fd < 0) { |
504 |
return fd;
|
505 |
} |
506 |
ret = fremovexattr(fd, name); |
507 |
close(fd); |
508 |
return ret;
|
509 |
} |
510 |
|
511 |
static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path, |
512 |
const char *name, V9fsPath *target) |
513 |
{ |
514 |
char buffer[PATH_MAX];
|
515 |
struct file_handle *fh;
|
516 |
int dirfd, ret, mnt_id;
|
517 |
struct handle_data *data = (struct handle_data *)ctx->private; |
518 |
|
519 |
/* "." and ".." are not allowed */
|
520 |
if (!strcmp(name, ".") || !strcmp(name, "..")) { |
521 |
errno = EINVAL; |
522 |
return -1; |
523 |
|
524 |
} |
525 |
if (dir_path) {
|
526 |
dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH); |
527 |
} else {
|
528 |
/* relative to export root */
|
529 |
dirfd = open(rpath(ctx, ".", buffer), O_DIRECTORY);
|
530 |
} |
531 |
if (dirfd < 0) { |
532 |
return dirfd;
|
533 |
} |
534 |
fh = g_malloc(sizeof(struct file_handle) + data->handle_bytes); |
535 |
fh->handle_bytes = data->handle_bytes; |
536 |
/* add a "./" at the begining of the path */
|
537 |
snprintf(buffer, PATH_MAX, "./%s", name);
|
538 |
/* flag = 0 imply don't follow symlink */
|
539 |
ret = name_to_handle(dirfd, buffer, fh, &mnt_id, 0);
|
540 |
if (!ret) {
|
541 |
target->data = (char *)fh;
|
542 |
target->size = sizeof(struct file_handle) + data->handle_bytes; |
543 |
} else {
|
544 |
g_free(fh); |
545 |
} |
546 |
close(dirfd); |
547 |
return ret;
|
548 |
} |
549 |
|
550 |
static int handle_renameat(FsContext *ctx, V9fsPath *olddir, |
551 |
const char *old_name, V9fsPath *newdir, |
552 |
const char *new_name) |
553 |
{ |
554 |
int olddirfd, newdirfd, ret;
|
555 |
struct handle_data *data = (struct handle_data *)ctx->private; |
556 |
|
557 |
olddirfd = open_by_handle(data->mountfd, olddir->data, O_PATH); |
558 |
if (olddirfd < 0) { |
559 |
return olddirfd;
|
560 |
} |
561 |
newdirfd = open_by_handle(data->mountfd, newdir->data, O_PATH); |
562 |
if (newdirfd < 0) { |
563 |
close(olddirfd); |
564 |
return newdirfd;
|
565 |
} |
566 |
ret = renameat(olddirfd, old_name, newdirfd, new_name); |
567 |
close(newdirfd); |
568 |
close(olddirfd); |
569 |
return ret;
|
570 |
} |
571 |
|
572 |
static int handle_unlinkat(FsContext *ctx, V9fsPath *dir, |
573 |
const char *name, int flags) |
574 |
{ |
575 |
int dirfd, ret;
|
576 |
struct handle_data *data = (struct handle_data *)ctx->private; |
577 |
|
578 |
dirfd = open_by_handle(data->mountfd, dir->data, O_PATH); |
579 |
if (dirfd < 0) { |
580 |
return dirfd;
|
581 |
} |
582 |
|
583 |
ret = unlinkat(dirfd, name, flags); |
584 |
close(dirfd); |
585 |
return ret;
|
586 |
} |
587 |
|
588 |
static int handle_ioc_getversion(FsContext *ctx, V9fsPath *path, |
589 |
mode_t st_mode, uint64_t *st_gen) |
590 |
{ |
591 |
int err;
|
592 |
V9fsFidOpenState fid_open; |
593 |
|
594 |
/*
|
595 |
* Do not try to open special files like device nodes, fifos etc
|
596 |
* We can get fd for regular files and directories only
|
597 |
*/
|
598 |
if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
|
599 |
return 0; |
600 |
} |
601 |
err = handle_open(ctx, path, O_RDONLY, &fid_open); |
602 |
if (err < 0) { |
603 |
return err;
|
604 |
} |
605 |
err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen); |
606 |
handle_close(ctx, &fid_open); |
607 |
return err;
|
608 |
} |
609 |
|
610 |
static int handle_init(FsContext *ctx) |
611 |
{ |
612 |
int ret, mnt_id;
|
613 |
struct statfs stbuf;
|
614 |
struct file_handle fh;
|
615 |
struct handle_data *data = g_malloc(sizeof(struct handle_data)); |
616 |
|
617 |
data->mountfd = open(ctx->fs_root, O_DIRECTORY); |
618 |
if (data->mountfd < 0) { |
619 |
ret = data->mountfd; |
620 |
goto err_out;
|
621 |
} |
622 |
ret = statfs(ctx->fs_root, &stbuf); |
623 |
if (!ret) {
|
624 |
switch (stbuf.f_type) {
|
625 |
case EXT2_SUPER_MAGIC:
|
626 |
case BTRFS_SUPER_MAGIC:
|
627 |
case REISERFS_SUPER_MAGIC:
|
628 |
case XFS_SUPER_MAGIC:
|
629 |
ctx->exops.get_st_gen = handle_ioc_getversion; |
630 |
break;
|
631 |
} |
632 |
} |
633 |
memset(&fh, 0, sizeof(struct file_handle)); |
634 |
ret = name_to_handle(data->mountfd, ".", &fh, &mnt_id, 0); |
635 |
if (ret && errno == EOVERFLOW) {
|
636 |
data->handle_bytes = fh.handle_bytes; |
637 |
ctx->private = data; |
638 |
ret = 0;
|
639 |
goto out;
|
640 |
} |
641 |
/* we got 0 byte handle ? */
|
642 |
ret = -1;
|
643 |
close(data->mountfd); |
644 |
err_out:
|
645 |
g_free(data); |
646 |
out:
|
647 |
return ret;
|
648 |
} |
649 |
|
650 |
FileOperations handle_ops = { |
651 |
.init = handle_init, |
652 |
.lstat = handle_lstat, |
653 |
.readlink = handle_readlink, |
654 |
.close = handle_close, |
655 |
.closedir = handle_closedir, |
656 |
.open = handle_open, |
657 |
.opendir = handle_opendir, |
658 |
.rewinddir = handle_rewinddir, |
659 |
.telldir = handle_telldir, |
660 |
.readdir_r = handle_readdir_r, |
661 |
.seekdir = handle_seekdir, |
662 |
.preadv = handle_preadv, |
663 |
.pwritev = handle_pwritev, |
664 |
.chmod = handle_chmod, |
665 |
.mknod = handle_mknod, |
666 |
.mkdir = handle_mkdir, |
667 |
.fstat = handle_fstat, |
668 |
.open2 = handle_open2, |
669 |
.symlink = handle_symlink, |
670 |
.link = handle_link, |
671 |
.truncate = handle_truncate, |
672 |
.rename = handle_rename, |
673 |
.chown = handle_chown, |
674 |
.utimensat = handle_utimensat, |
675 |
.remove = handle_remove, |
676 |
.fsync = handle_fsync, |
677 |
.statfs = handle_statfs, |
678 |
.lgetxattr = handle_lgetxattr, |
679 |
.llistxattr = handle_llistxattr, |
680 |
.lsetxattr = handle_lsetxattr, |
681 |
.lremovexattr = handle_lremovexattr, |
682 |
.name_to_path = handle_name_to_path, |
683 |
.renameat = handle_renameat, |
684 |
.unlinkat = handle_unlinkat, |
685 |
}; |