| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Virtio 9p handle callback | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright IBM, Corp. 2011 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Authors: | 
					
						
							|  |  |  |  *    Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This work is licensed under the terms of the GNU GPL, version 2.  See | 
					
						
							|  |  |  |  * the COPYING file in the top-level directory. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "hw/virtio.h"
 | 
					
						
							|  |  |  | #include "virtio-9p.h"
 | 
					
						
							|  |  |  | #include "virtio-9p-xattr.h"
 | 
					
						
							|  |  |  | #include <arpa/inet.h>
 | 
					
						
							|  |  |  | #include <pwd.h>
 | 
					
						
							|  |  |  | #include <grp.h>
 | 
					
						
							|  |  |  | #include <sys/socket.h>
 | 
					
						
							|  |  |  | #include <sys/un.h>
 | 
					
						
							| 
									
										
										
										
											2011-11-09 14:44:52 +02:00
										 |  |  | #include "qemu-xattr.h"
 | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | #include <unistd.h>
 | 
					
						
							| 
									
										
										
										
											2011-10-12 19:11:25 +05:30
										 |  |  | #include <linux/fs.h>
 | 
					
						
							|  |  |  | #ifdef CONFIG_LINUX_MAGIC_H
 | 
					
						
							|  |  |  | #include <linux/magic.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #include <sys/ioctl.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef XFS_SUPER_MAGIC
 | 
					
						
							|  |  |  | #define XFS_SUPER_MAGIC  0x58465342
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #ifndef EXT2_SUPER_MAGIC
 | 
					
						
							|  |  |  | #define EXT2_SUPER_MAGIC 0xEF53
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #ifndef REISERFS_SUPER_MAGIC
 | 
					
						
							|  |  |  | #define REISERFS_SUPER_MAGIC 0x52654973
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #ifndef BTRFS_SUPER_MAGIC
 | 
					
						
							|  |  |  | #define BTRFS_SUPER_MAGIC 0x9123683E
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  | struct handle_data { | 
					
						
							|  |  |  |     int mountfd; | 
					
						
							|  |  |  |     int handle_bytes; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-12 19:11:24 +05:30
										 |  |  | #ifdef CONFIG_OPEN_BY_HANDLE
 | 
					
						
							|  |  |  | static inline int name_to_handle(int dirfd, const char *name, | 
					
						
							|  |  |  |                                  struct file_handle *fh, int *mnt_id, int flags) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return name_to_handle_at(dirfd, name, fh, mnt_id, flags); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline int open_by_handle(int mountfd, const char *fh, int flags) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return open_by_handle_at(mountfd, (struct file_handle *)fh, flags); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-18 17:35:37 +01:00
										 |  |  | struct rpl_file_handle { | 
					
						
							| 
									
										
										
										
											2011-10-12 19:11:24 +05:30
										 |  |  |     unsigned int handle_bytes; | 
					
						
							|  |  |  |     int handle_type; | 
					
						
							|  |  |  |     unsigned char handle[0]; | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2011-11-18 17:35:37 +01:00
										 |  |  | #define file_handle rpl_file_handle
 | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-18 17:35:38 +01:00
										 |  |  | #ifndef AT_REMOVEDIR
 | 
					
						
							|  |  |  | #define AT_REMOVEDIR    0x200
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | #ifndef AT_EMPTY_PATH
 | 
					
						
							|  |  |  | #define AT_EMPTY_PATH   0x1000  /* Allow empty relative pathname */
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #ifndef O_PATH
 | 
					
						
							|  |  |  | #define O_PATH    010000000
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline int name_to_handle(int dirfd, const char *name, | 
					
						
							|  |  |  |                                  struct file_handle *fh, int *mnt_id, int flags) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     errno = ENOSYS; | 
					
						
							|  |  |  |     return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline int open_by_handle(int mountfd, const char *fh, int flags) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     errno = ENOSYS; | 
					
						
							|  |  |  |     return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int handle_update_file_cred(int dirfd, const char *name, FsCred *credp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int fd, ret; | 
					
						
							|  |  |  |     fd = openat(dirfd, name, O_NONBLOCK | O_NOFOLLOW);; | 
					
						
							|  |  |  |     if (fd < 0) { | 
					
						
							|  |  |  |         return fd; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ret = fchmod(fd, credp->fc_mode & 07777); | 
					
						
							|  |  |  |     if (ret < 0) { | 
					
						
							|  |  |  |         goto err_out; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH); | 
					
						
							|  |  |  | err_out: | 
					
						
							|  |  |  |     close(fd); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int handle_lstat(FsContext *fs_ctx, V9fsPath *fs_path, | 
					
						
							|  |  |  |                         struct stat *stbuf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int fd, ret; | 
					
						
							|  |  |  |     struct handle_data *data = (struct handle_data *)fs_ctx->private; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fd = open_by_handle(data->mountfd, fs_path->data, O_PATH); | 
					
						
							|  |  |  |     if (fd < 0) { | 
					
						
							|  |  |  |         return fd; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ret = fstatat(fd, "", stbuf, AT_EMPTY_PATH); | 
					
						
							|  |  |  |     close(fd); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static ssize_t handle_readlink(FsContext *fs_ctx, V9fsPath *fs_path, | 
					
						
							|  |  |  |                                char *buf, size_t bufsz) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int fd, ret; | 
					
						
							|  |  |  |     struct handle_data *data = (struct handle_data *)fs_ctx->private; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fd = open_by_handle(data->mountfd, fs_path->data, O_PATH); | 
					
						
							|  |  |  |     if (fd < 0) { | 
					
						
							|  |  |  |         return fd; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ret = readlinkat(fd, "", buf, bufsz); | 
					
						
							|  |  |  |     close(fd); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  | static int handle_close(FsContext *ctx, V9fsFidOpenState *fs) | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  |     return close(fs->fd); | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  | static int handle_closedir(FsContext *ctx, V9fsFidOpenState *fs) | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  |     return closedir(fs->dir); | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  | static int handle_open(FsContext *ctx, V9fsPath *fs_path, | 
					
						
							|  |  |  |                        int flags, V9fsFidOpenState *fs) | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | { | 
					
						
							|  |  |  |     struct handle_data *data = (struct handle_data *)ctx->private; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  |     fs->fd = open_by_handle(data->mountfd, fs_path->data, flags); | 
					
						
							|  |  |  |     return fs->fd; | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  | static int handle_opendir(FsContext *ctx, | 
					
						
							|  |  |  |                           V9fsPath *fs_path, V9fsFidOpenState *fs) | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  |     int ret; | 
					
						
							|  |  |  |     ret = handle_open(ctx, fs_path, O_DIRECTORY, fs); | 
					
						
							|  |  |  |     if (ret < 0) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  |     fs->dir = fdopendir(ret); | 
					
						
							|  |  |  |     if (!fs->dir) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  | static void handle_rewinddir(FsContext *ctx, V9fsFidOpenState *fs) | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  |     return rewinddir(fs->dir); | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  | static off_t handle_telldir(FsContext *ctx, V9fsFidOpenState *fs) | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  |     return telldir(fs->dir); | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  | static int handle_readdir_r(FsContext *ctx, V9fsFidOpenState *fs, | 
					
						
							|  |  |  |                             struct dirent *entry, | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  |                             struct dirent **result) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  |     return readdir_r(fs->dir, entry, result); | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  | static void handle_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off) | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  |     return seekdir(fs->dir, off); | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  | static ssize_t handle_preadv(FsContext *ctx, V9fsFidOpenState *fs, | 
					
						
							|  |  |  |                              const struct iovec *iov, | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  |                              int iovcnt, off_t offset) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #ifdef CONFIG_PREADV
 | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  |     return preadv(fs->fd, iov, iovcnt, offset); | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  |     int err = lseek(fs->fd, offset, SEEK_SET); | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  |     if (err == -1) { | 
					
						
							|  |  |  |         return err; | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  |         return readv(fs->fd, iov, iovcnt); | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  |     } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  | static ssize_t handle_pwritev(FsContext *ctx, V9fsFidOpenState *fs, | 
					
						
							|  |  |  |                               const struct iovec *iov, | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  |                               int iovcnt, off_t offset) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-12 19:11:23 +05:30
										 |  |  |     ssize_t ret; | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | #ifdef CONFIG_PREADV
 | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  |     ret = pwritev(fs->fd, iov, iovcnt, offset); | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  |     int err = lseek(fs->fd, offset, SEEK_SET); | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  |     if (err == -1) { | 
					
						
							|  |  |  |         return err; | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  |         ret = writev(fs->fd, iov, iovcnt); | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  |     } | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2011-10-12 19:11:23 +05:30
										 |  |  | #ifdef CONFIG_SYNC_FILE_RANGE
 | 
					
						
							|  |  |  |     if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) { | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |          * Initiate a writeback. This is not a data integrity sync. | 
					
						
							|  |  |  |          * We want to ensure that we don't leave dirty pages in the cache | 
					
						
							|  |  |  |          * after write when writeout=immediate is sepcified. | 
					
						
							|  |  |  |          */ | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  |         sync_file_range(fs->fd, offset, ret, | 
					
						
							| 
									
										
										
										
											2011-10-12 19:11:23 +05:30
										 |  |  |                         SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |     return ret; | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int handle_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int fd, ret; | 
					
						
							|  |  |  |     struct handle_data *data = (struct handle_data *)fs_ctx->private; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK); | 
					
						
							|  |  |  |     if (fd < 0) { | 
					
						
							|  |  |  |         return fd; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ret = fchmod(fd, credp->fc_mode); | 
					
						
							|  |  |  |     close(fd); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int handle_mknod(FsContext *fs_ctx, V9fsPath *dir_path, | 
					
						
							|  |  |  |                        const char *name, FsCred *credp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int dirfd, ret; | 
					
						
							|  |  |  |     struct handle_data *data = (struct handle_data *)fs_ctx->private; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH); | 
					
						
							|  |  |  |     if (dirfd < 0) { | 
					
						
							|  |  |  |         return dirfd; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ret = mknodat(dirfd, name, credp->fc_mode, credp->fc_rdev); | 
					
						
							|  |  |  |     if (!ret) { | 
					
						
							|  |  |  |         ret = handle_update_file_cred(dirfd, name, credp); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     close(dirfd); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int handle_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, | 
					
						
							|  |  |  |                        const char *name, FsCred *credp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int dirfd, ret; | 
					
						
							|  |  |  |     struct handle_data *data = (struct handle_data *)fs_ctx->private; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH); | 
					
						
							|  |  |  |     if (dirfd < 0) { | 
					
						
							|  |  |  |         return dirfd; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ret = mkdirat(dirfd, name, credp->fc_mode); | 
					
						
							|  |  |  |     if (!ret) { | 
					
						
							|  |  |  |         ret = handle_update_file_cred(dirfd, name, credp); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     close(dirfd); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  | static int handle_fstat(FsContext *fs_ctx, V9fsFidOpenState *fs, | 
					
						
							|  |  |  |                         struct stat *stbuf) | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  |     return fstat(fs->fd, stbuf); | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int handle_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  |                         int flags, FsCred *credp, V9fsFidOpenState *fs) | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | { | 
					
						
							|  |  |  |     int ret; | 
					
						
							|  |  |  |     int dirfd, fd; | 
					
						
							|  |  |  |     struct handle_data *data = (struct handle_data *)fs_ctx->private; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH); | 
					
						
							|  |  |  |     if (dirfd < 0) { | 
					
						
							|  |  |  |         return dirfd; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     fd = openat(dirfd, name, flags | O_NOFOLLOW, credp->fc_mode); | 
					
						
							|  |  |  |     if (fd >= 0) { | 
					
						
							|  |  |  |         ret = handle_update_file_cred(dirfd, name, credp); | 
					
						
							|  |  |  |         if (ret < 0) { | 
					
						
							|  |  |  |             close(fd); | 
					
						
							|  |  |  |             fd = ret; | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  |         } else { | 
					
						
							|  |  |  |             fs->fd = fd; | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     close(dirfd); | 
					
						
							|  |  |  |     return fd; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int handle_symlink(FsContext *fs_ctx, const char *oldpath, | 
					
						
							|  |  |  |                           V9fsPath *dir_path, const char *name, FsCred *credp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int fd, dirfd, ret; | 
					
						
							|  |  |  |     struct handle_data *data = (struct handle_data *)fs_ctx->private; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH); | 
					
						
							|  |  |  |     if (dirfd < 0) { | 
					
						
							|  |  |  |         return dirfd; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ret = symlinkat(oldpath, dirfd, name); | 
					
						
							|  |  |  |     if (!ret) { | 
					
						
							|  |  |  |         fd = openat(dirfd, name, O_PATH | O_NOFOLLOW); | 
					
						
							|  |  |  |         if (fd < 0) { | 
					
						
							|  |  |  |             ret = fd; | 
					
						
							|  |  |  |             goto err_out; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH); | 
					
						
							|  |  |  |         close(fd); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | err_out: | 
					
						
							|  |  |  |     close(dirfd); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int handle_link(FsContext *ctx, V9fsPath *oldpath, | 
					
						
							|  |  |  |                        V9fsPath *dirpath, const char *name) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int oldfd, newdirfd, ret; | 
					
						
							|  |  |  |     struct handle_data *data = (struct handle_data *)ctx->private; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     oldfd = open_by_handle(data->mountfd, oldpath->data, O_PATH); | 
					
						
							|  |  |  |     if (oldfd < 0) { | 
					
						
							|  |  |  |         return oldfd; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     newdirfd = open_by_handle(data->mountfd, dirpath->data, O_PATH); | 
					
						
							|  |  |  |     if (newdirfd < 0) { | 
					
						
							|  |  |  |         close(oldfd); | 
					
						
							|  |  |  |         return newdirfd; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ret = linkat(oldfd, "", newdirfd, name, AT_EMPTY_PATH); | 
					
						
							|  |  |  |     close(newdirfd); | 
					
						
							|  |  |  |     close(oldfd); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int handle_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int fd, ret; | 
					
						
							|  |  |  |     struct handle_data *data = (struct handle_data *)ctx->private; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK | O_WRONLY); | 
					
						
							|  |  |  |     if (fd < 0) { | 
					
						
							|  |  |  |         return fd; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ret = ftruncate(fd, size); | 
					
						
							|  |  |  |     close(fd); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int handle_rename(FsContext *ctx, const char *oldpath, | 
					
						
							|  |  |  |                          const char *newpath) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     errno = EOPNOTSUPP; | 
					
						
							|  |  |  |     return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int handle_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int fd, ret; | 
					
						
							|  |  |  |     struct handle_data *data = (struct handle_data *)fs_ctx->private; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fd = open_by_handle(data->mountfd, fs_path->data, O_PATH); | 
					
						
							|  |  |  |     if (fd < 0) { | 
					
						
							|  |  |  |         return fd; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH); | 
					
						
							|  |  |  |     close(fd); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int handle_utimensat(FsContext *ctx, V9fsPath *fs_path, | 
					
						
							|  |  |  |                             const struct timespec *buf) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-12 19:11:24 +05:30
										 |  |  |     int ret; | 
					
						
							|  |  |  | #ifdef CONFIG_UTIMENSAT
 | 
					
						
							|  |  |  |     int fd; | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  |     struct handle_data *data = (struct handle_data *)ctx->private; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK); | 
					
						
							|  |  |  |     if (fd < 0) { | 
					
						
							|  |  |  |         return fd; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ret = futimens(fd, buf); | 
					
						
							|  |  |  |     close(fd); | 
					
						
							| 
									
										
										
										
											2011-10-12 19:11:24 +05:30
										 |  |  | #else
 | 
					
						
							|  |  |  |     ret = -1; | 
					
						
							|  |  |  |     errno = ENOSYS; | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int handle_remove(FsContext *ctx, const char *path) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     errno = EOPNOTSUPP; | 
					
						
							|  |  |  |     return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  | static int handle_fsync(FsContext *ctx, V9fsFidOpenState *fs, int datasync) | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | { | 
					
						
							|  |  |  |     if (datasync) { | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  |         return qemu_fdatasync(fs->fd); | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  |         return fsync(fs->fd); | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int handle_statfs(FsContext *ctx, V9fsPath *fs_path, | 
					
						
							|  |  |  |                          struct statfs *stbuf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int fd, ret; | 
					
						
							|  |  |  |     struct handle_data *data = (struct handle_data *)ctx->private; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK); | 
					
						
							|  |  |  |     if (fd < 0) { | 
					
						
							|  |  |  |         return fd; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ret = fstatfs(fd, stbuf); | 
					
						
							|  |  |  |     close(fd); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static ssize_t handle_lgetxattr(FsContext *ctx, V9fsPath *fs_path, | 
					
						
							|  |  |  |                                 const char *name, void *value, size_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int fd, ret; | 
					
						
							|  |  |  |     struct handle_data *data = (struct handle_data *)ctx->private; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK); | 
					
						
							|  |  |  |     if (fd < 0) { | 
					
						
							|  |  |  |         return fd; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ret = fgetxattr(fd, name, value, size); | 
					
						
							|  |  |  |     close(fd); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static ssize_t handle_llistxattr(FsContext *ctx, V9fsPath *fs_path, | 
					
						
							|  |  |  |                                  void *value, size_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int fd, ret; | 
					
						
							|  |  |  |     struct handle_data *data = (struct handle_data *)ctx->private; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK); | 
					
						
							|  |  |  |     if (fd < 0) { | 
					
						
							|  |  |  |         return fd; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ret = flistxattr(fd, value, size); | 
					
						
							|  |  |  |     close(fd); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int handle_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name, | 
					
						
							|  |  |  |                             void *value, size_t size, int flags) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int fd, ret; | 
					
						
							|  |  |  |     struct handle_data *data = (struct handle_data *)ctx->private; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK); | 
					
						
							|  |  |  |     if (fd < 0) { | 
					
						
							|  |  |  |         return fd; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ret = fsetxattr(fd, name, value, size, flags); | 
					
						
							|  |  |  |     close(fd); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int handle_lremovexattr(FsContext *ctx, V9fsPath *fs_path, | 
					
						
							|  |  |  |                                const char *name) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int fd, ret; | 
					
						
							|  |  |  |     struct handle_data *data = (struct handle_data *)ctx->private; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK); | 
					
						
							|  |  |  |     if (fd < 0) { | 
					
						
							|  |  |  |         return fd; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ret = fremovexattr(fd, name); | 
					
						
							|  |  |  |     close(fd); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int handle_name_to_path(FsContext *ctx, V9fsPath *dir_path, | 
					
						
							|  |  |  |                               const char *name, V9fsPath *target) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     char buffer[PATH_MAX]; | 
					
						
							|  |  |  |     struct file_handle *fh; | 
					
						
							|  |  |  |     int dirfd, ret, mnt_id; | 
					
						
							|  |  |  |     struct handle_data *data = (struct handle_data *)ctx->private; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* "." and ".." are not allowed */ | 
					
						
							|  |  |  |     if (!strcmp(name, ".") || !strcmp(name, "..")) { | 
					
						
							|  |  |  |         errno = EINVAL; | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (dir_path) { | 
					
						
							|  |  |  |         dirfd = open_by_handle(data->mountfd, dir_path->data, O_PATH); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         /* relative to export root */ | 
					
						
							|  |  |  |         dirfd = open(rpath(ctx, ".", buffer), O_DIRECTORY); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (dirfd < 0) { | 
					
						
							|  |  |  |         return dirfd; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     fh = g_malloc(sizeof(struct file_handle) + data->handle_bytes); | 
					
						
							|  |  |  |     fh->handle_bytes = data->handle_bytes; | 
					
						
							|  |  |  |     /* add a "./" at the begining of the path */ | 
					
						
							|  |  |  |     snprintf(buffer, PATH_MAX, "./%s", name); | 
					
						
							|  |  |  |     /* flag = 0 imply don't follow symlink */ | 
					
						
							|  |  |  |     ret = name_to_handle(dirfd, buffer, fh, &mnt_id, 0); | 
					
						
							|  |  |  |     if (!ret) { | 
					
						
							|  |  |  |         target->data = (char *)fh; | 
					
						
							|  |  |  |         target->size = sizeof(struct file_handle) + data->handle_bytes; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         g_free(fh); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     close(dirfd); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int handle_renameat(FsContext *ctx, V9fsPath *olddir, | 
					
						
							|  |  |  |                            const char *old_name, V9fsPath *newdir, | 
					
						
							|  |  |  |                            const char *new_name) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int olddirfd, newdirfd, ret; | 
					
						
							|  |  |  |     struct handle_data *data = (struct handle_data *)ctx->private; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     olddirfd = open_by_handle(data->mountfd, olddir->data, O_PATH); | 
					
						
							|  |  |  |     if (olddirfd < 0) { | 
					
						
							|  |  |  |         return olddirfd; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     newdirfd = open_by_handle(data->mountfd, newdir->data, O_PATH); | 
					
						
							|  |  |  |     if (newdirfd < 0) { | 
					
						
							|  |  |  |         close(olddirfd); | 
					
						
							|  |  |  |         return newdirfd; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ret = renameat(olddirfd, old_name, newdirfd, new_name); | 
					
						
							|  |  |  |     close(newdirfd); | 
					
						
							|  |  |  |     close(olddirfd); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int handle_unlinkat(FsContext *ctx, V9fsPath *dir, | 
					
						
							|  |  |  |                            const char *name, int flags) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int dirfd, ret; | 
					
						
							|  |  |  |     struct handle_data *data = (struct handle_data *)ctx->private; | 
					
						
							| 
									
										
										
										
											2011-11-18 17:35:38 +01:00
										 |  |  |     int rflags; | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  |     dirfd = open_by_handle(data->mountfd, dir->data, O_PATH); | 
					
						
							|  |  |  |     if (dirfd < 0) { | 
					
						
							|  |  |  |         return dirfd; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-18 17:35:38 +01:00
										 |  |  |     rflags = 0; | 
					
						
							|  |  |  |     if (flags & P9_DOTL_AT_REMOVEDIR) { | 
					
						
							|  |  |  |         rflags |= AT_REMOVEDIR; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ret = unlinkat(dirfd, name, rflags); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  |     close(dirfd); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-12 19:11:25 +05:30
										 |  |  | static int handle_ioc_getversion(FsContext *ctx, V9fsPath *path, | 
					
						
							|  |  |  |                                  mode_t st_mode, uint64_t *st_gen) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  |     int err; | 
					
						
							|  |  |  |     V9fsFidOpenState fid_open; | 
					
						
							| 
									
										
										
										
											2011-10-12 19:11:25 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Do not try to open special files like device nodes, fifos etc | 
					
						
							|  |  |  |      * We can get fd for regular files and directories only | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) { | 
					
						
							|  |  |  |             return 0; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  |     err = handle_open(ctx, path, O_RDONLY, &fid_open); | 
					
						
							|  |  |  |     if (err < 0) { | 
					
						
							|  |  |  |         return err; | 
					
						
							| 
									
										
										
										
											2011-10-12 19:11:25 +05:30
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-10-25 12:10:40 +05:30
										 |  |  |     err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen); | 
					
						
							|  |  |  |     handle_close(ctx, &fid_open); | 
					
						
							| 
									
										
										
										
											2011-10-12 19:11:25 +05:30
										 |  |  |     return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  | static int handle_init(FsContext *ctx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int ret, mnt_id; | 
					
						
							| 
									
										
										
										
											2011-10-12 19:11:25 +05:30
										 |  |  |     struct statfs stbuf; | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  |     struct file_handle fh; | 
					
						
							|  |  |  |     struct handle_data *data = g_malloc(sizeof(struct handle_data)); | 
					
						
							| 
									
										
										
										
											2011-10-12 19:11:24 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  |     data->mountfd = open(ctx->fs_root, O_DIRECTORY); | 
					
						
							|  |  |  |     if (data->mountfd < 0) { | 
					
						
							|  |  |  |         ret = data->mountfd; | 
					
						
							|  |  |  |         goto err_out; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-10-12 19:11:25 +05:30
										 |  |  |     ret = statfs(ctx->fs_root, &stbuf); | 
					
						
							|  |  |  |     if (!ret) { | 
					
						
							|  |  |  |         switch (stbuf.f_type) { | 
					
						
							|  |  |  |         case EXT2_SUPER_MAGIC: | 
					
						
							|  |  |  |         case BTRFS_SUPER_MAGIC: | 
					
						
							|  |  |  |         case REISERFS_SUPER_MAGIC: | 
					
						
							|  |  |  |         case XFS_SUPER_MAGIC: | 
					
						
							|  |  |  |             ctx->exops.get_st_gen = handle_ioc_getversion; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-08-02 11:35:54 +05:30
										 |  |  |     memset(&fh, 0, sizeof(struct file_handle)); | 
					
						
							|  |  |  |     ret = name_to_handle(data->mountfd, ".", &fh, &mnt_id, 0); | 
					
						
							|  |  |  |     if (ret && errno == EOVERFLOW) { | 
					
						
							|  |  |  |         data->handle_bytes = fh.handle_bytes; | 
					
						
							|  |  |  |         ctx->private = data; | 
					
						
							|  |  |  |         ret = 0; | 
					
						
							|  |  |  |         goto out; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     /* we got 0 byte handle ? */ | 
					
						
							|  |  |  |     ret = -1; | 
					
						
							|  |  |  |     close(data->mountfd); | 
					
						
							|  |  |  | err_out: | 
					
						
							|  |  |  |     g_free(data); | 
					
						
							|  |  |  | out: | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | FileOperations handle_ops = { | 
					
						
							|  |  |  |     .init         = handle_init, | 
					
						
							|  |  |  |     .lstat        = handle_lstat, | 
					
						
							|  |  |  |     .readlink     = handle_readlink, | 
					
						
							|  |  |  |     .close        = handle_close, | 
					
						
							|  |  |  |     .closedir     = handle_closedir, | 
					
						
							|  |  |  |     .open         = handle_open, | 
					
						
							|  |  |  |     .opendir      = handle_opendir, | 
					
						
							|  |  |  |     .rewinddir    = handle_rewinddir, | 
					
						
							|  |  |  |     .telldir      = handle_telldir, | 
					
						
							|  |  |  |     .readdir_r    = handle_readdir_r, | 
					
						
							|  |  |  |     .seekdir      = handle_seekdir, | 
					
						
							|  |  |  |     .preadv       = handle_preadv, | 
					
						
							|  |  |  |     .pwritev      = handle_pwritev, | 
					
						
							|  |  |  |     .chmod        = handle_chmod, | 
					
						
							|  |  |  |     .mknod        = handle_mknod, | 
					
						
							|  |  |  |     .mkdir        = handle_mkdir, | 
					
						
							|  |  |  |     .fstat        = handle_fstat, | 
					
						
							|  |  |  |     .open2        = handle_open2, | 
					
						
							|  |  |  |     .symlink      = handle_symlink, | 
					
						
							|  |  |  |     .link         = handle_link, | 
					
						
							|  |  |  |     .truncate     = handle_truncate, | 
					
						
							|  |  |  |     .rename       = handle_rename, | 
					
						
							|  |  |  |     .chown        = handle_chown, | 
					
						
							|  |  |  |     .utimensat    = handle_utimensat, | 
					
						
							|  |  |  |     .remove       = handle_remove, | 
					
						
							|  |  |  |     .fsync        = handle_fsync, | 
					
						
							|  |  |  |     .statfs       = handle_statfs, | 
					
						
							|  |  |  |     .lgetxattr    = handle_lgetxattr, | 
					
						
							|  |  |  |     .llistxattr   = handle_llistxattr, | 
					
						
							|  |  |  |     .lsetxattr    = handle_lsetxattr, | 
					
						
							|  |  |  |     .lremovexattr = handle_lremovexattr, | 
					
						
							|  |  |  |     .name_to_path = handle_name_to_path, | 
					
						
							|  |  |  |     .renameat     = handle_renameat, | 
					
						
							|  |  |  |     .unlinkat     = handle_unlinkat, | 
					
						
							|  |  |  | }; |