~ahs3/+junk/cq-qemu

« back to all changes in this revision

Viewing changes to hw/9pfs/virtio-9p-handle.c

  • Committer: Al Stone
  • Date: 2012-02-09 01:17:20 UTC
  • Revision ID: albert.stone@canonical.com-20120209011720-tztl7ik3qayz80p4
first commit to bzr for qemu

Show diffs side-by-side

added added

removed removed

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