]> git.ipfire.org Git - people/ms/linux.git/blame - fs/fhandle.c
vfs: Add name to file handle conversion support
[people/ms/linux.git] / fs / fhandle.c
CommitLineData
990d6c2d
AK
1#include <linux/syscalls.h>
2#include <linux/slab.h>
3#include <linux/fs.h>
4#include <linux/file.h>
5#include <linux/mount.h>
6#include <linux/namei.h>
7#include <linux/exportfs.h>
8#include <asm/uaccess.h>
9#include "internal.h"
10
11static long do_sys_name_to_handle(struct path *path,
12 struct file_handle __user *ufh,
13 int __user *mnt_id)
14{
15 long retval;
16 struct file_handle f_handle;
17 int handle_dwords, handle_bytes;
18 struct file_handle *handle = NULL;
19
20 /*
21 * We need t make sure wether the file system
22 * support decoding of the file handle
23 */
24 if (!path->mnt->mnt_sb->s_export_op ||
25 !path->mnt->mnt_sb->s_export_op->fh_to_dentry)
26 return -EOPNOTSUPP;
27
28 if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle)))
29 return -EFAULT;
30
31 if (f_handle.handle_bytes > MAX_HANDLE_SZ)
32 return -EINVAL;
33
34 handle = kmalloc(sizeof(struct file_handle) + f_handle.handle_bytes,
35 GFP_KERNEL);
36 if (!handle)
37 return -ENOMEM;
38
39 /* convert handle size to multiple of sizeof(u32) */
40 handle_dwords = f_handle.handle_bytes >> 2;
41
42 /* we ask for a non connected handle */
43 retval = exportfs_encode_fh(path->dentry,
44 (struct fid *)handle->f_handle,
45 &handle_dwords, 0);
46 handle->handle_type = retval;
47 /* convert handle size to bytes */
48 handle_bytes = handle_dwords * sizeof(u32);
49 handle->handle_bytes = handle_bytes;
50 if ((handle->handle_bytes > f_handle.handle_bytes) ||
51 (retval == 255) || (retval == -ENOSPC)) {
52 /* As per old exportfs_encode_fh documentation
53 * we could return ENOSPC to indicate overflow
54 * But file system returned 255 always. So handle
55 * both the values
56 */
57 /*
58 * set the handle size to zero so we copy only
59 * non variable part of the file_handle
60 */
61 handle_bytes = 0;
62 retval = -EOVERFLOW;
63 } else
64 retval = 0;
65 /* copy the mount id */
66 if (copy_to_user(mnt_id, &path->mnt->mnt_id, sizeof(*mnt_id)) ||
67 copy_to_user(ufh, handle,
68 sizeof(struct file_handle) + handle_bytes))
69 retval = -EFAULT;
70 kfree(handle);
71 return retval;
72}
73
74/**
75 * sys_name_to_handle_at: convert name to handle
76 * @dfd: directory relative to which name is interpreted if not absolute
77 * @name: name that should be converted to handle.
78 * @handle: resulting file handle
79 * @mnt_id: mount id of the file system containing the file
80 * @flag: flag value to indicate whether to follow symlink or not
81 *
82 * @handle->handle_size indicate the space available to store the
83 * variable part of the file handle in bytes. If there is not
84 * enough space, the field is updated to return the minimum
85 * value required.
86 */
87SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
88 struct file_handle __user *, handle, int __user *, mnt_id,
89 int, flag)
90{
91 struct path path;
92 int lookup_flags;
93 int err;
94
95 if ((flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
96 return -EINVAL;
97
98 lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0;
99 if (flag & AT_EMPTY_PATH)
100 lookup_flags |= LOOKUP_EMPTY;
101 err = user_path_at(dfd, name, lookup_flags, &path);
102 if (!err) {
103 err = do_sys_name_to_handle(&path, handle, mnt_id);
104 path_put(&path);
105 }
106 return err;
107}