xref: /linux/fs/fhandle.c (revision 990d6c2d)
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 
11 static 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  */
87 SYSCALL_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 }
108