blob: 77c7a5796dfdf411b5ad376d26b7f2b7a444357c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/ioctl.c
3 *
4 * vfs operations that deal with io control
5 *
Steve French64a5cfa2013-10-14 15:31:32 -05006 * Copyright (C) International Business Machines Corp., 2005,2013
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * Author(s): Steve French (sfrench@us.ibm.com)
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
Steve Frenchf654bac2005-04-28 22:41:04 -070023
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <linux/fs.h>
Steve French41c13582013-11-14 00:05:36 -060025#include <linux/file.h>
26#include <linux/mount.h>
27#include <linux/mm.h>
28#include <linux/pagemap.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include "cifspdu.h"
30#include "cifsglob.h"
31#include "cifsproto.h"
32#include "cifs_debug.h"
Steve Frenchc67593a2005-04-28 22:41:04 -070033#include "cifsfs.h"
Steve French0de1f4c2015-07-04 18:40:10 -050034#include "cifs_ioctl.h"
Steve French02b16662015-06-27 21:18:36 -070035#include <linux/btrfs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
Ronnie Sahlbergf5b05d62018-10-07 19:19:58 -050037static long cifs_ioctl_query_info(unsigned int xid, struct file *filep,
38 unsigned long p)
39{
40 struct cifsFileInfo *pSMBFile = filep->private_data;
41 struct cifs_tcon *tcon;
42
43 cifs_dbg(FYI, "%s %p\n", __func__, pSMBFile);
44 if (pSMBFile == NULL)
45 return -EISDIR;
46 tcon = tlink_tcon(pSMBFile->tlink);
47
48 if (tcon->ses->server->ops->ioctl_query_info)
49 return tcon->ses->server->ops->ioctl_query_info(
50 xid, pSMBFile, p);
51 else
52 return -EOPNOTSUPP;
53}
54
Sachin Prabhu312bbc52017-04-04 02:12:04 -050055static long cifs_ioctl_copychunk(unsigned int xid, struct file *dst_file,
Christoph Hellwig04b38d62015-12-03 12:59:50 +010056 unsigned long srcfd)
Steve French41c13582013-11-14 00:05:36 -060057{
58 int rc;
Steve French41c13582013-11-14 00:05:36 -060059 struct fd src_file;
Steve French41c13582013-11-14 00:05:36 -060060 struct inode *src_inode;
Steve French41c13582013-11-14 00:05:36 -060061
Sachin Prabhu312bbc52017-04-04 02:12:04 -050062 cifs_dbg(FYI, "ioctl copychunk range\n");
Steve French41c13582013-11-14 00:05:36 -060063 /* the destination must be opened for writing */
64 if (!(dst_file->f_mode & FMODE_WRITE)) {
65 cifs_dbg(FYI, "file target not open for write\n");
66 return -EINVAL;
67 }
68
69 /* check if target volume is readonly and take reference */
70 rc = mnt_want_write_file(dst_file);
71 if (rc) {
72 cifs_dbg(FYI, "mnt_want_write failed with rc %d\n", rc);
73 return rc;
74 }
75
76 src_file = fdget(srcfd);
77 if (!src_file.file) {
78 rc = -EBADF;
79 goto out_drop_write;
80 }
81
Jann Horn4c17a6d2015-09-11 16:27:27 +020082 if (src_file.file->f_op->unlocked_ioctl != cifs_ioctl) {
83 rc = -EBADF;
84 cifs_dbg(VFS, "src file seems to be from a different filesystem type\n");
85 goto out_fput;
86 }
87
Libo Chen2d4f84b2013-12-11 11:02:27 +080088 src_inode = file_inode(src_file.file);
Al Viro378ff1a2015-01-18 23:37:32 -050089 rc = -EINVAL;
90 if (S_ISDIR(src_inode->i_mode))
91 goto out_fput;
Steve French41c13582013-11-14 00:05:36 -060092
Sachin Prabhu620d8742017-02-10 16:03:51 +053093 rc = cifs_file_copychunk_range(xid, src_file.file, 0, dst_file, 0,
94 src_inode->i_size, 0);
Sachin Prabhu7d0c2342017-04-26 17:10:17 +010095 if (rc > 0)
96 rc = 0;
Steve French41c13582013-11-14 00:05:36 -060097out_fput:
98 fdput(src_file);
99out_drop_write:
100 mnt_drop_write_file(dst_file);
101 return rc;
102}
103
Steve French0de1f4c2015-07-04 18:40:10 -0500104static long smb_mnt_get_fsinfo(unsigned int xid, struct cifs_tcon *tcon,
105 void __user *arg)
106{
107 int rc = 0;
108 struct smb_mnt_fs_info *fsinf;
109
110 fsinf = kzalloc(sizeof(struct smb_mnt_fs_info), GFP_KERNEL);
111 if (fsinf == NULL)
112 return -ENOMEM;
113
114 fsinf->version = 1;
115 fsinf->protocol_id = tcon->ses->server->vals->protocol_id;
116 fsinf->device_characteristics =
117 le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics);
118 fsinf->device_type = le32_to_cpu(tcon->fsDevInfo.DeviceType);
119 fsinf->fs_attributes = le32_to_cpu(tcon->fsAttrInfo.Attributes);
120 fsinf->max_path_component =
121 le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength);
Steve French0de1f4c2015-07-04 18:40:10 -0500122 fsinf->vol_serial_number = tcon->vol_serial_number;
123 fsinf->vol_create_time = le64_to_cpu(tcon->vol_create_time);
124 fsinf->share_flags = tcon->share_flags;
125 fsinf->share_caps = le32_to_cpu(tcon->capabilities);
126 fsinf->sector_flags = tcon->ss_flags;
127 fsinf->optimal_sector_size = tcon->perf_sector_size;
128 fsinf->max_bytes_chunk = tcon->max_bytes_chunk;
129 fsinf->maximal_access = tcon->maximal_access;
Steve French0de1f4c2015-07-04 18:40:10 -0500130 fsinf->cifs_posix_caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
131
132 if (copy_to_user(arg, fsinf, sizeof(struct smb_mnt_fs_info)))
133 rc = -EFAULT;
134
135 kfree(fsinf);
136 return rc;
137}
138
Steve Frenchf9ddcca2008-05-15 05:51:55 +0000139long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140{
Al Viro496ad9a2013-01-23 17:07:38 -0500141 struct inode *inode = file_inode(filep);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 int rc = -ENOTTY; /* strange error - but the precedent */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400143 unsigned int xid;
Jeff Laytonba00ba642010-09-20 16:01:31 -0700144 struct cifsFileInfo *pSMBFile = filep->private_data;
Steve French96daf2b2011-05-27 04:34:02 +0000145 struct cifs_tcon *tcon;
Steve Frenchf654bac2005-04-28 22:41:04 -0700146 __u64 ExtAttrBits = 0;
Jeff Layton61876392010-11-08 07:28:32 -0500147 __u64 caps;
Steve Frenchf654bac2005-04-28 22:41:04 -0700148
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400149 xid = get_xid();
Steve Frenchf654bac2005-04-28 22:41:04 -0700150
Pavel Shilovskyb0a752b2016-11-16 15:17:15 -0800151 cifs_dbg(FYI, "cifs ioctl 0x%x\n", command);
Steve French5fdae1f2007-06-05 18:30:44 +0000152 switch (command) {
David Howells36695672006-08-29 19:06:16 +0100153 case FS_IOC_GETFLAGS:
Jeff Layton61876392010-11-08 07:28:32 -0500154 if (pSMBFile == NULL)
155 break;
156 tcon = tlink_tcon(pSMBFile->tlink);
157 caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French64a5cfa2013-10-14 15:31:32 -0500158#ifdef CONFIG_CIFS_POSIX
Steve French5fdae1f2007-06-05 18:30:44 +0000159 if (CIFS_UNIX_EXTATTR_CAP & caps) {
Steve Frenchf10d9ba2013-10-13 22:32:30 -0500160 __u64 ExtAttrMask = 0;
Pavel Shilovsky4b4de762012-09-18 16:20:26 -0700161 rc = CIFSGetExtAttr(xid, tcon,
162 pSMBFile->fid.netfid,
163 &ExtAttrBits, &ExtAttrMask);
Steve French5fdae1f2007-06-05 18:30:44 +0000164 if (rc == 0)
Steve Frenchf654bac2005-04-28 22:41:04 -0700165 rc = put_user(ExtAttrBits &
David Howells36695672006-08-29 19:06:16 +0100166 FS_FL_USER_VISIBLE,
Steve Frenchf654bac2005-04-28 22:41:04 -0700167 (int __user *)arg);
Steve French64a5cfa2013-10-14 15:31:32 -0500168 if (rc != EOPNOTSUPP)
169 break;
170 }
171#endif /* CONFIG_CIFS_POSIX */
172 rc = 0;
173 if (CIFS_I(inode)->cifsAttrs & ATTR_COMPRESSED) {
174 /* add in the compressed bit */
175 ExtAttrBits = FS_COMPR_FL;
176 rc = put_user(ExtAttrBits & FS_FL_USER_VISIBLE,
177 (int __user *)arg);
Steve Frenchf654bac2005-04-28 22:41:04 -0700178 }
179 break;
David Howells36695672006-08-29 19:06:16 +0100180 case FS_IOC_SETFLAGS:
Jeff Layton61876392010-11-08 07:28:32 -0500181 if (pSMBFile == NULL)
182 break;
183 tcon = tlink_tcon(pSMBFile->tlink);
184 caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
Steve French64a5cfa2013-10-14 15:31:32 -0500185
186 if (get_user(ExtAttrBits, (int __user *)arg)) {
187 rc = -EFAULT;
188 break;
Steve Frenchf654bac2005-04-28 22:41:04 -0700189 }
Steve French64a5cfa2013-10-14 15:31:32 -0500190
191 /*
192 * if (CIFS_UNIX_EXTATTR_CAP & caps)
193 * rc = CIFSSetExtAttr(xid, tcon,
194 * pSMBFile->fid.netfid,
195 * extAttrBits,
196 * &ExtAttrMask);
197 * if (rc != EOPNOTSUPP)
198 * break;
199 */
200
201 /* Currently only flag we can set is compressed flag */
202 if ((ExtAttrBits & FS_COMPR_FL) == 0)
203 break;
204
205 /* Try to set compress flag */
206 if (tcon->ses->server->ops->set_compression) {
207 rc = tcon->ses->server->ops->set_compression(
208 xid, tcon, pSMBFile);
209 cifs_dbg(FYI, "set compress flag rc %d\n", rc);
210 }
Steve Frenchf654bac2005-04-28 22:41:04 -0700211 break;
Steve Frenchf19e84d2013-11-24 21:53:17 -0600212 case CIFS_IOC_COPYCHUNK_FILE:
Sachin Prabhu312bbc52017-04-04 02:12:04 -0500213 rc = cifs_ioctl_copychunk(xid, filep, arg);
Steve French41c13582013-11-14 00:05:36 -0600214 break;
Ronnie Sahlbergf5b05d62018-10-07 19:19:58 -0500215 case CIFS_QUERY_INFO:
216 rc = cifs_ioctl_query_info(xid, filep, arg);
217 break;
Steve Frenchb3152e22015-06-24 03:17:02 -0500218 case CIFS_IOC_SET_INTEGRITY:
219 if (pSMBFile == NULL)
220 break;
221 tcon = tlink_tcon(pSMBFile->tlink);
222 if (tcon->ses->server->ops->set_integrity)
223 rc = tcon->ses->server->ops->set_integrity(xid,
224 tcon, pSMBFile);
225 else
226 rc = -EOPNOTSUPP;
227 break;
Steve French0de1f4c2015-07-04 18:40:10 -0500228 case CIFS_IOC_GET_MNT_INFO:
David Disseldorpd8a6e502017-05-04 00:41:13 +0200229 if (pSMBFile == NULL)
230 break;
Steve French0de1f4c2015-07-04 18:40:10 -0500231 tcon = tlink_tcon(pSMBFile->tlink);
232 rc = smb_mnt_get_fsinfo(xid, tcon, (void __user *)arg);
233 break;
Steve French834170c2016-09-30 21:14:26 -0500234 case CIFS_ENUMERATE_SNAPSHOTS:
David Disseldorp60266852017-05-03 17:39:08 +0200235 if (pSMBFile == NULL)
236 break;
Steve French834170c2016-09-30 21:14:26 -0500237 if (arg == 0) {
238 rc = -EINVAL;
239 goto cifs_ioc_exit;
240 }
241 tcon = tlink_tcon(pSMBFile->tlink);
242 if (tcon->ses->server->ops->enum_snapshots)
243 rc = tcon->ses->server->ops->enum_snapshots(xid, tcon,
244 pSMBFile, (void __user *)arg);
245 else
246 rc = -EOPNOTSUPP;
247 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 default:
Joe Perchesf96637b2013-05-04 22:12:25 -0500249 cifs_dbg(FYI, "unsupported ioctl\n");
Steve Frenchf28ac912005-04-28 22:41:07 -0700250 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 }
Steve French834170c2016-09-30 21:14:26 -0500252cifs_ioc_exit:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400253 free_xid(xid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 return rc;
Steve French5fdae1f2007-06-05 18:30:44 +0000255}