blob: f82fd342bca56de2dcddea0cdbd3eb0c1122c218 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve Frenchf19159d2010-04-21 04:12:10 +00004 * Copyright (C) International Business Machines Corp., 2002,2010
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
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 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/posix_acl_xattr.h>
Jeff Laytonc28c89f2011-05-19 16:22:56 -040035#include <linux/pagemap.h>
Jeff Laytone28bc5b2011-10-19 15:30:07 -040036#include <linux/swap.h>
37#include <linux/task_io_accounting_ops.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -080038#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include "cifspdu.h"
40#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000041#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include "cifsproto.h"
43#include "cifs_unicode.h"
44#include "cifs_debug.h"
Jeff Laytone28bc5b2011-10-19 15:30:07 -040045#include "fscache.h"
Long Lidb223a52017-11-22 17:38:45 -070046#include "smbdirect.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
48#ifdef CONFIG_CIFS_POSIX
49static struct {
50 int index;
51 char *name;
52} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000053#ifdef CONFIG_CIFS_WEAK_PW_HASH
54 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000055 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000056#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000057 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000058 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 {BAD_PROT, "\2"}
60};
61#else
62static struct {
63 int index;
64 char *name;
65} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000066#ifdef CONFIG_CIFS_WEAK_PW_HASH
67 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000068 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000069#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000070 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 {BAD_PROT, "\2"}
72};
73#endif
74
Steve French39798772006-05-31 22:40:51 +000075/* define the number of elements in the cifs dialect array */
76#ifdef CONFIG_CIFS_POSIX
77#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000078#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000079#else
80#define CIFS_NUM_PROT 2
81#endif /* CIFS_WEAK_PW_HASH */
82#else /* not posix */
83#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000084#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000085#else
86#define CIFS_NUM_PROT 1
87#endif /* CONFIG_CIFS_WEAK_PW_HASH */
88#endif /* CIFS_POSIX */
89
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040090/*
91 * Mark as invalid, all open files on tree connections since they
92 * were closed when session to server was lost.
93 */
94void
95cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070096{
97 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000098 struct list_head *tmp;
99 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400101 /* list all files open on tree connection and mark them invalid */
Steve French3afca262016-09-22 18:58:16 -0500102 spin_lock(&tcon->open_file_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400103 list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +0000104 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000105 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -0400106 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 }
Steve French3afca262016-09-22 18:58:16 -0500108 spin_unlock(&tcon->open_file_lock);
Steve French3d4ef9a2018-04-25 22:19:09 -0500109
Ronnie Sahlberga93864d2018-06-14 06:48:35 +1000110 mutex_lock(&tcon->crfid.fid_mutex);
111 tcon->crfid.is_valid = false;
112 memset(tcon->crfid.fid, 0, sizeof(struct cifs_fid));
113 mutex_unlock(&tcon->crfid.fid_mutex);
Steve French3d4ef9a2018-04-25 22:19:09 -0500114
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400115 /*
116 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
117 * to this tcon.
118 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119}
120
Jeff Layton9162ab22009-09-03 12:07:17 -0400121/* reconnect the socket, tcon, and smb session if needed */
122static int
Steve French96daf2b2011-05-27 04:34:02 +0000123cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400124{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400125 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000126 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400127 struct TCP_Server_Info *server;
128 struct nls_table *nls_codepage;
129
130 /*
131 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
132 * tcp and smb session status done differently for those three - in the
133 * calling routine
134 */
135 if (!tcon)
136 return 0;
137
138 ses = tcon->ses;
139 server = ses->server;
140
141 /*
142 * only tree disconnect, open, and write, (and ulogoff which does not
143 * have tcon) are allowed as we start force umount
144 */
145 if (tcon->tidStatus == CifsExiting) {
146 if (smb_command != SMB_COM_WRITE_ANDX &&
147 smb_command != SMB_COM_OPEN_ANDX &&
148 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500149 cifs_dbg(FYI, "can not send cmd %d while umounting\n",
150 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400151 return -ENODEV;
152 }
153 }
154
Jeff Layton9162ab22009-09-03 12:07:17 -0400155 /*
156 * Give demultiplex thread up to 10 seconds to reconnect, should be
157 * greater than cifs socket timeout which is 7 seconds
158 */
159 while (server->tcpStatus == CifsNeedReconnect) {
Paulo Alcantara7ffbe652018-07-05 13:46:34 -0300160 rc = wait_event_interruptible_timeout(server->response_q,
161 (server->tcpStatus != CifsNeedReconnect),
162 10 * HZ);
163 if (rc < 0) {
164 cifs_dbg(FYI, "%s: aborting reconnect due to a received"
165 " signal by the process\n", __func__);
166 return -ERESTARTSYS;
167 }
Jeff Layton9162ab22009-09-03 12:07:17 -0400168
Steve Frenchfd88ce92011-04-12 01:01:14 +0000169 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400170 if (server->tcpStatus != CifsNeedReconnect)
171 break;
172
173 /*
174 * on "soft" mounts we wait once. Hard mounts keep
175 * retrying until process is killed or server comes
176 * back on-line
177 */
Jeff Laytond4025392011-02-07 08:54:35 -0500178 if (!tcon->retry) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500179 cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
Jeff Layton9162ab22009-09-03 12:07:17 -0400180 return -EHOSTDOWN;
181 }
182 }
183
184 if (!ses->need_reconnect && !tcon->need_reconnect)
185 return 0;
186
187 nls_codepage = load_nls_default();
188
189 /*
190 * need to prevent multiple threads trying to simultaneously
191 * reconnect the same SMB session
192 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000193 mutex_lock(&ses->session_mutex);
Samuel Cabrero76e75272017-07-11 12:44:39 +0200194
195 /*
196 * Recheck after acquire mutex. If another thread is negotiating
197 * and the server never sends an answer the socket will be closed
198 * and tcpStatus set to reconnect.
199 */
200 if (server->tcpStatus == CifsNeedReconnect) {
201 rc = -EHOSTDOWN;
202 mutex_unlock(&ses->session_mutex);
203 goto out;
204 }
205
Jeff Layton198b5682010-04-24 07:57:48 -0400206 rc = cifs_negotiate_protocol(0, ses);
207 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400208 rc = cifs_setup_session(0, ses, nls_codepage);
209
210 /* do we need to reconnect tcon? */
211 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000212 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400213 goto out;
214 }
215
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400216 cifs_mark_open_files_invalid(tcon);
Jeff Layton9162ab22009-09-03 12:07:17 -0400217 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000218 mutex_unlock(&ses->session_mutex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500219 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400220
Steve Frenchc318e6c2018-04-04 14:08:52 -0500221 if (rc) {
222 printk_once(KERN_WARNING "reconnect tcon failed rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400223 goto out;
Steve Frenchc318e6c2018-04-04 14:08:52 -0500224 }
Jeff Layton9162ab22009-09-03 12:07:17 -0400225
Jeff Layton9162ab22009-09-03 12:07:17 -0400226 atomic_inc(&tconInfoReconnectCount);
227
228 /* tell server Unix caps we support */
229 if (ses->capabilities & CAP_UNIX)
230 reset_cifs_unix_caps(0, tcon, NULL, NULL);
231
232 /*
233 * Removed call to reopen open files here. It is safer (and faster) to
234 * reopen files one at a time as needed in read and write.
235 *
236 * FIXME: what about file locks? don't we need to reclaim them ASAP?
237 */
238
239out:
240 /*
241 * Check if handle based operation so we know whether we can continue
242 * or not without returning to caller to reset file handle
243 */
244 switch (smb_command) {
245 case SMB_COM_READ_ANDX:
246 case SMB_COM_WRITE_ANDX:
247 case SMB_COM_CLOSE:
248 case SMB_COM_FIND_CLOSE2:
249 case SMB_COM_LOCKING_ANDX:
250 rc = -EAGAIN;
251 }
252
253 unload_nls(nls_codepage);
254 return rc;
255}
256
Steve Frenchad7a2922008-02-07 23:25:02 +0000257/* Allocate and return pointer to an SMB request buffer, and set basic
258 SMB information in the SMB header. If the return code is zero, this
259 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260static int
Steve French96daf2b2011-05-27 04:34:02 +0000261small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000262 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263{
Jeff Laytonf5695992010-09-29 15:27:08 -0400264 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265
Jeff Layton9162ab22009-09-03 12:07:17 -0400266 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000267 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 return rc;
269
270 *request_buf = cifs_small_buf_get();
271 if (*request_buf == NULL) {
272 /* BB should we add a retry in here if not a writepage? */
273 return -ENOMEM;
274 }
275
Steve French63135e02007-07-17 17:34:02 +0000276 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000277 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
Steve French790fe572007-07-07 19:25:05 +0000279 if (tcon != NULL)
280 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700281
Jeff Laytonf5695992010-09-29 15:27:08 -0400282 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000283}
284
Steve French12b3b8f2006-02-09 21:12:47 +0000285int
Steve French50c2f752007-07-13 00:33:32 +0000286small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000287 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000288{
289 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000290 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000291
Steve French5815449d2006-02-14 01:36:20 +0000292 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000293 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000294 return rc;
295
Steve French04fdabe2006-02-10 05:52:50 +0000296 buffer = (struct smb_hdr *)*request_buf;
Pavel Shilovsky88257362012-05-23 14:01:59 +0400297 buffer->Mid = get_next_mid(ses->server);
Steve French12b3b8f2006-02-09 21:12:47 +0000298 if (ses->capabilities & CAP_UNICODE)
299 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000300 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000301 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
302
303 /* uid, tid can stay at zero as set in header assemble */
304
Steve French50c2f752007-07-13 00:33:32 +0000305 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000306 this function is used after 1st of session setup requests */
307
308 return rc;
309}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
311/* If the return code is zero, this function must fill in request_buf pointer */
312static int
Steve French96daf2b2011-05-27 04:34:02 +0000313__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400314 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 *request_buf = cifs_buf_get();
317 if (*request_buf == NULL) {
318 /* BB should we add a retry in here if not a writepage? */
319 return -ENOMEM;
320 }
321 /* Although the original thought was we needed the response buf for */
322 /* potential retries of smb operations it turns out we can determine */
323 /* from the mid flags when the request buffer can be resent without */
324 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000325 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000326 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
328 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000329 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
Steve French790fe572007-07-07 19:25:05 +0000331 if (tcon != NULL)
332 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700333
Jeff Laytonf5695992010-09-29 15:27:08 -0400334 return 0;
335}
336
337/* If the return code is zero, this function must fill in request_buf pointer */
338static int
Steve French96daf2b2011-05-27 04:34:02 +0000339smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400340 void **request_buf, void **response_buf)
341{
342 int rc;
343
344 rc = cifs_reconnect_tcon(tcon, smb_command);
345 if (rc)
346 return rc;
347
348 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
349}
350
351static int
Steve French96daf2b2011-05-27 04:34:02 +0000352smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400353 void **request_buf, void **response_buf)
354{
355 if (tcon->ses->need_reconnect || tcon->need_reconnect)
356 return -EHOSTDOWN;
357
358 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359}
360
Steve French50c2f752007-07-13 00:33:32 +0000361static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362{
Jeff Layton12df83c2011-01-20 13:36:51 -0500363 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
Jeff Layton12df83c2011-01-20 13:36:51 -0500365 /* check for plausible wct */
366 if (pSMB->hdr.WordCount < 10)
367 goto vt2_err;
368
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500370 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
371 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
372 goto vt2_err;
373
Jeff Layton12df83c2011-01-20 13:36:51 -0500374 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
375 if (total_size >= 512)
376 goto vt2_err;
377
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400378 /* check that bcc is at least as big as parms + data, and that it is
379 * less than negotiated smb buffer
380 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500381 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
382 if (total_size > get_bcc(&pSMB->hdr) ||
383 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
384 goto vt2_err;
385
386 return 0;
387vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000388 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500390 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391}
Jeff Layton690c5222011-01-20 13:36:51 -0500392
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400393static int
Jeff Layton3f618222013-06-12 19:52:14 -0500394decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400395{
396 int rc = 0;
397 u16 count;
398 char *guid = pSMBr->u.extended_response.GUID;
Jeff Layton3f618222013-06-12 19:52:14 -0500399 struct TCP_Server_Info *server = ses->server;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400400
401 count = get_bcc(&pSMBr->hdr);
402 if (count < SMB1_CLIENT_GUID_SIZE)
403 return -EIO;
404
405 spin_lock(&cifs_tcp_ses_lock);
406 if (server->srv_count > 1) {
407 spin_unlock(&cifs_tcp_ses_lock);
408 if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
409 cifs_dbg(FYI, "server UID changed\n");
410 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
411 }
412 } else {
413 spin_unlock(&cifs_tcp_ses_lock);
414 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
415 }
416
417 if (count == SMB1_CLIENT_GUID_SIZE) {
Jeff Layton3f618222013-06-12 19:52:14 -0500418 server->sec_ntlmssp = true;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400419 } else {
420 count -= SMB1_CLIENT_GUID_SIZE;
421 rc = decode_negTokenInit(
422 pSMBr->u.extended_response.SecurityBlob, count, server);
423 if (rc != 1)
424 return -EINVAL;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400425 }
426
427 return 0;
428}
429
Jeff Layton9ddec562013-05-26 07:00:58 -0400430int
Jeff Layton38d77c52013-05-26 07:01:00 -0400431cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
Jeff Layton9ddec562013-05-26 07:00:58 -0400432{
Jeff Layton502858822013-06-27 12:45:00 -0400433 bool srv_sign_required = server->sec_mode & server->vals->signing_required;
434 bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled;
Jeff Layton38d77c52013-05-26 07:01:00 -0400435 bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN;
436
437 /*
438 * Is signing required by mnt options? If not then check
439 * global_secflags to see if it is there.
440 */
441 if (!mnt_sign_required)
442 mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
443 CIFSSEC_MUST_SIGN);
444
445 /*
446 * If signing is required then it's automatically enabled too,
447 * otherwise, check to see if the secflags allow it.
448 */
449 mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
450 (global_secflags & CIFSSEC_MAY_SIGN);
451
452 /* If server requires signing, does client allow it? */
453 if (srv_sign_required) {
454 if (!mnt_sign_enabled) {
455 cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!");
456 return -ENOTSUPP;
Jeff Layton9ddec562013-05-26 07:00:58 -0400457 }
Jeff Layton38d77c52013-05-26 07:01:00 -0400458 server->sign = true;
459 }
460
461 /* If client requires signing, does server allow it? */
462 if (mnt_sign_required) {
463 if (!srv_sign_enabled) {
464 cifs_dbg(VFS, "Server does not support signing!");
465 return -ENOTSUPP;
466 }
467 server->sign = true;
Jeff Layton9ddec562013-05-26 07:00:58 -0400468 }
469
Long Libb4c0412018-04-17 12:17:08 -0700470 if (cifs_rdma_enabled(server) && server->sign)
471 cifs_dbg(VFS, "Signing is enabled, and RDMA read/write will be disabled");
472
Jeff Layton9ddec562013-05-26 07:00:58 -0400473 return 0;
474}
475
Jeff Layton2190eca2013-05-26 07:00:57 -0400476#ifdef CONFIG_CIFS_WEAK_PW_HASH
477static int
Jeff Layton3f618222013-06-12 19:52:14 -0500478decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400479{
480 __s16 tmp;
481 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
482
483 if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
484 return -EOPNOTSUPP;
485
Jeff Layton2190eca2013-05-26 07:00:57 -0400486 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
487 server->maxReq = min_t(unsigned int,
488 le16_to_cpu(rsp->MaxMpxCount),
489 cifs_max_pending);
490 set_credits(server, server->maxReq);
491 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Jeff Layton2190eca2013-05-26 07:00:57 -0400492 /* even though we do not use raw we might as well set this
493 accurately, in case we ever find a need for it */
494 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
495 server->max_rw = 0xFF00;
496 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
497 } else {
498 server->max_rw = 0;/* do not need to use raw anyway */
499 server->capabilities = CAP_MPX_MODE;
500 }
501 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
502 if (tmp == -1) {
503 /* OS/2 often does not set timezone therefore
504 * we must use server time to calc time zone.
505 * Could deviate slightly from the right zone.
506 * Smallest defined timezone difference is 15 minutes
507 * (i.e. Nepal). Rounding up/down is done to match
508 * this requirement.
509 */
510 int val, seconds, remain, result;
Arnd Bergmann95390202018-06-19 17:27:58 +0200511 struct timespec64 ts;
512 time64_t utc = ktime_get_real_seconds();
Jeff Layton2190eca2013-05-26 07:00:57 -0400513 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
514 rsp->SrvTime.Time, 0);
Arnd Bergmann95390202018-06-19 17:27:58 +0200515 cifs_dbg(FYI, "SrvTime %lld sec since 1970 (utc: %lld) diff: %lld\n",
516 ts.tv_sec, utc,
517 utc - ts.tv_sec);
Deepa Dinamanie37fea52017-05-08 15:59:16 -0700518 val = (int)(utc - ts.tv_sec);
Jeff Layton2190eca2013-05-26 07:00:57 -0400519 seconds = abs(val);
520 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
521 remain = seconds % MIN_TZ_ADJ;
522 if (remain >= (MIN_TZ_ADJ / 2))
523 result += MIN_TZ_ADJ;
524 if (val < 0)
525 result = -result;
526 server->timeAdj = result;
527 } else {
528 server->timeAdj = (int)tmp;
529 server->timeAdj *= 60; /* also in seconds */
530 }
531 cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
532
533
534 /* BB get server time for time conversions and add
535 code to use it and timezone since this is not UTC */
536
537 if (rsp->EncryptionKeyLength ==
538 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
539 memcpy(server->cryptkey, rsp->EncryptionKey,
540 CIFS_CRYPTO_KEY_SIZE);
541 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
542 return -EIO; /* need cryptkey unless plain text */
543 }
544
545 cifs_dbg(FYI, "LANMAN negotiated\n");
546 return 0;
547}
548#else
549static inline int
Jeff Layton3f618222013-06-12 19:52:14 -0500550decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400551{
552 cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
553 return -EOPNOTSUPP;
554}
555#endif
556
Jeff Layton91934002013-05-26 07:00:58 -0400557static bool
Jeff Layton3f618222013-06-12 19:52:14 -0500558should_set_ext_sec_flag(enum securityEnum sectype)
Jeff Layton91934002013-05-26 07:00:58 -0400559{
Jeff Layton3f618222013-06-12 19:52:14 -0500560 switch (sectype) {
561 case RawNTLMSSP:
562 case Kerberos:
Jeff Layton91934002013-05-26 07:00:58 -0400563 return true;
Jeff Layton3f618222013-06-12 19:52:14 -0500564 case Unspecified:
565 if (global_secflags &
566 (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
567 return true;
568 /* Fallthrough */
569 default:
570 return false;
571 }
Jeff Layton91934002013-05-26 07:00:58 -0400572}
573
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400575CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576{
577 NEGOTIATE_REQ *pSMB;
578 NEGOTIATE_RSP *pSMBr;
579 int rc = 0;
580 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000581 int i;
Jeff Layton3534b852013-05-24 07:41:01 -0400582 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 u16 count;
584
Jeff Layton3534b852013-05-24 07:41:01 -0400585 if (!server) {
586 WARN(1, "%s: server is NULL!\n", __func__);
587 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 }
Jeff Layton3534b852013-05-24 07:41:01 -0400589
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
591 (void **) &pSMB, (void **) &pSMBr);
592 if (rc)
593 return rc;
Steve French750d1152006-06-27 06:28:30 +0000594
Pavel Shilovsky88257362012-05-23 14:01:59 +0400595 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000596 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000597
Jeff Layton3f618222013-06-12 19:52:14 -0500598 if (should_set_ext_sec_flag(ses->sectype)) {
Jeff Layton91934002013-05-26 07:00:58 -0400599 cifs_dbg(FYI, "Requesting extended security.");
Steve Frenchac683922009-05-06 04:16:04 +0000600 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
601 }
Steve French50c2f752007-07-13 00:33:32 +0000602
Steve French39798772006-05-31 22:40:51 +0000603 count = 0;
Stephen Rothwellbcfb84a2018-09-03 13:15:58 +1000604 /*
605 * We know that all the name entries in the protocols array
606 * are short (< 16 bytes anyway) and are NUL terminated.
607 */
Steve French50c2f752007-07-13 00:33:32 +0000608 for (i = 0; i < CIFS_NUM_PROT; i++) {
Stephen Rothwellbcfb84a2018-09-03 13:15:58 +1000609 size_t len = strlen(protocols[i].name) + 1;
610
611 memcpy(pSMB->DialectsArray+count, protocols[i].name, len);
612 count += len;
Steve French39798772006-05-31 22:40:51 +0000613 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000614 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 pSMB->ByteCount = cpu_to_le16(count);
616
617 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
618 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000619 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000620 goto neg_err_exit;
621
Jeff Layton9bf67e52010-04-24 07:57:46 -0400622 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500623 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000624 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400625 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000626 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000627 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000628 could not negotiate a common dialect */
629 rc = -EOPNOTSUPP;
630 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000631 } else if (pSMBr->hdr.WordCount == 13) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400632 server->negflavor = CIFS_NEGFLAVOR_LANMAN;
Jeff Layton3f618222013-06-12 19:52:14 -0500633 rc = decode_lanman_negprot_rsp(server, pSMBr);
Jeff Layton9ddec562013-05-26 07:00:58 -0400634 goto signing_check;
Steve French790fe572007-07-07 19:25:05 +0000635 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000636 /* unknown wct */
637 rc = -EOPNOTSUPP;
638 goto neg_err_exit;
639 }
Jeff Layton2190eca2013-05-26 07:00:57 -0400640 /* else wct == 17, NTLM or better */
641
Steve French96daf2b2011-05-27 04:34:02 +0000642 server->sec_mode = pSMBr->SecurityMode;
643 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500644 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000645
Steve French254e55e2006-06-04 05:53:15 +0000646 /* one byte, so no need to convert this or EncryptionKeyLen from
647 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300648 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
649 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400650 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000651 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400652 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000653 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500654 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000655 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000656 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
657 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400658
Jeff Laytone598d1d82013-05-26 07:00:59 -0400659 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
660 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500661 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000662 CIFS_CRYPTO_KEY_SIZE);
Noel Powerf2910952015-05-27 09:22:10 +0100663 } else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
664 server->capabilities & CAP_EXTENDED_SECURITY) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400665 server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
Jeff Layton3f618222013-06-12 19:52:14 -0500666 rc = decode_ext_sec_blob(ses, pSMBr);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400667 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000668 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Laytone598d1d82013-05-26 07:00:59 -0400669 } else {
670 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Steve French254e55e2006-06-04 05:53:15 +0000671 server->capabilities &= ~CAP_EXTENDED_SECURITY;
Jeff Laytone598d1d82013-05-26 07:00:59 -0400672 }
Steve French254e55e2006-06-04 05:53:15 +0000673
674signing_check:
Jeff Layton9ddec562013-05-26 07:00:58 -0400675 if (!rc)
Jeff Layton38d77c52013-05-26 07:01:00 -0400676 rc = cifs_enable_signing(server, ses->sign);
Steve French50c2f752007-07-13 00:33:32 +0000677neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700678 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000679
Joe Perchesf96637b2013-05-04 22:12:25 -0500680 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 return rc;
682}
683
684int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400685CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686{
687 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
Joe Perchesf96637b2013-05-04 22:12:25 -0500690 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500691
692 /* BB: do we need to check this? These should never be NULL. */
693 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
694 return -EIO;
695
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500697 * No need to return error on this operation if tid invalidated and
698 * closed on server already e.g. due to tcp session crashing. Also,
699 * the tcon is no longer on the list, so no need to take lock before
700 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 */
Steve French268875b2009-06-25 00:29:21 +0000702 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000703 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
Steve French50c2f752007-07-13 00:33:32 +0000705 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700706 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500707 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 return rc;
Steve French133672e2007-11-13 22:41:37 +0000709
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400710 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700711 cifs_small_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500713 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714
Steve French50c2f752007-07-13 00:33:32 +0000715 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500716 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 if (rc == -EAGAIN)
718 rc = 0;
719
720 return rc;
721}
722
Jeff Layton766fdbb2011-01-11 07:24:21 -0500723/*
724 * This is a no-op for now. We're not really interested in the reply, but
725 * rather in the fact that the server sent one and that server->lstrp
726 * gets updated.
727 *
728 * FIXME: maybe we should consider checking that the reply matches request?
729 */
730static void
731cifs_echo_callback(struct mid_q_entry *mid)
732{
733 struct TCP_Server_Info *server = mid->callback_data;
734
735 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400736 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500737}
738
739int
740CIFSSMBEcho(struct TCP_Server_Info *server)
741{
742 ECHO_REQ *smb;
743 int rc = 0;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800744 struct kvec iov[2];
745 struct smb_rqst rqst = { .rq_iov = iov,
746 .rq_nvec = 2 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500747
Joe Perchesf96637b2013-05-04 22:12:25 -0500748 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500749
750 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
751 if (rc)
752 return rc;
753
Steve French26c9cb62017-05-02 13:35:20 -0500754 if (server->capabilities & CAP_UNICODE)
755 smb->hdr.Flags2 |= SMBFLG2_UNICODE;
756
Jeff Layton766fdbb2011-01-11 07:24:21 -0500757 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000758 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500759 smb->hdr.WordCount = 1;
760 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400761 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500762 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000763 inc_rfc1001_len(smb, 3);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800764
765 iov[0].iov_len = 4;
766 iov[0].iov_base = smb;
767 iov[1].iov_len = get_rfc1002_length(smb);
768 iov[1].iov_base = (char *)smb + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500769
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -0800770 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400771 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500772 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500773 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500774
775 cifs_small_buf_release(smb);
776
777 return rc;
778}
779
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400781CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 LOGOFF_ANDX_REQ *pSMB;
784 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785
Joe Perchesf96637b2013-05-04 22:12:25 -0500786 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500787
788 /*
789 * BB: do we need to check validity of ses and server? They should
790 * always be valid since we have an active reference. If not, that
791 * should probably be a BUG()
792 */
793 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 return -EIO;
795
Steve Frenchd7b619c2010-02-25 05:36:46 +0000796 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000797 if (ses->need_reconnect)
798 goto session_already_dead; /* no need to send SMBlogoff if uid
799 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
801 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000802 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 return rc;
804 }
805
Pavel Shilovsky88257362012-05-23 14:01:59 +0400806 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700807
Jeff Layton38d77c52013-05-26 07:01:00 -0400808 if (ses->server->sign)
809 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810
811 pSMB->hdr.Uid = ses->Suid;
812
813 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400814 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700815 cifs_small_buf_release(pSMB);
Steve French3b795212008-11-13 19:45:32 +0000816session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000817 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818
819 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000820 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 error */
822 if (rc == -EAGAIN)
823 rc = 0;
824 return rc;
825}
826
827int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400828CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
829 const char *fileName, __u16 type,
830 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000831{
832 TRANSACTION2_SPI_REQ *pSMB = NULL;
833 TRANSACTION2_SPI_RSP *pSMBr = NULL;
834 struct unlink_psx_rq *pRqD;
835 int name_len;
836 int rc = 0;
837 int bytes_returned = 0;
838 __u16 params, param_offset, offset, byte_count;
839
Joe Perchesf96637b2013-05-04 22:12:25 -0500840 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000841PsxDelete:
842 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
843 (void **) &pSMBr);
844 if (rc)
845 return rc;
846
847 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
848 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600849 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
850 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000851 name_len++; /* trailing null */
852 name_len *= 2;
853 } else { /* BB add path length overrun check */
854 name_len = strnlen(fileName, PATH_MAX);
855 name_len++; /* trailing null */
856 strncpy(pSMB->FileName, fileName, name_len);
857 }
858
859 params = 6 + name_len;
860 pSMB->MaxParameterCount = cpu_to_le16(2);
861 pSMB->MaxDataCount = 0; /* BB double check this with jra */
862 pSMB->MaxSetupCount = 0;
863 pSMB->Reserved = 0;
864 pSMB->Flags = 0;
865 pSMB->Timeout = 0;
866 pSMB->Reserved2 = 0;
867 param_offset = offsetof(struct smb_com_transaction2_spi_req,
868 InformationLevel) - 4;
869 offset = param_offset + params;
870
871 /* Setup pointer to Request Data (inode type) */
872 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
873 pRqD->type = cpu_to_le16(type);
874 pSMB->ParameterOffset = cpu_to_le16(param_offset);
875 pSMB->DataOffset = cpu_to_le16(offset);
876 pSMB->SetupCount = 1;
877 pSMB->Reserved3 = 0;
878 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
879 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
880
881 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
882 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
883 pSMB->ParameterCount = cpu_to_le16(params);
884 pSMB->TotalParameterCount = pSMB->ParameterCount;
885 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
886 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000887 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000888 pSMB->ByteCount = cpu_to_le16(byte_count);
889 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
890 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000891 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500892 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000893 cifs_buf_release(pSMB);
894
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400895 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000896
897 if (rc == -EAGAIN)
898 goto PsxDelete;
899
900 return rc;
901}
902
903int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700904CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
905 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906{
907 DELETE_FILE_REQ *pSMB = NULL;
908 DELETE_FILE_RSP *pSMBr = NULL;
909 int rc = 0;
910 int bytes_returned;
911 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500912 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
914DelFileRetry:
915 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
916 (void **) &pSMBr);
917 if (rc)
918 return rc;
919
920 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700921 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
922 PATH_MAX, cifs_sb->local_nls,
923 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 name_len++; /* trailing null */
925 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700926 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700927 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700929 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 }
931 pSMB->SearchAttributes =
932 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
933 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000934 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 pSMB->ByteCount = cpu_to_le16(name_len + 1);
936 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
937 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400938 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000939 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500940 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
942 cifs_buf_release(pSMB);
943 if (rc == -EAGAIN)
944 goto DelFileRetry;
945
946 return rc;
947}
948
949int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400950CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
951 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952{
953 DELETE_DIRECTORY_REQ *pSMB = NULL;
954 DELETE_DIRECTORY_RSP *pSMBr = NULL;
955 int rc = 0;
956 int bytes_returned;
957 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500958 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
Joe Perchesf96637b2013-05-04 22:12:25 -0500960 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961RmDirRetry:
962 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
963 (void **) &pSMBr);
964 if (rc)
965 return rc;
966
967 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400968 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
969 PATH_MAX, cifs_sb->local_nls,
970 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 name_len++; /* trailing null */
972 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700973 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400974 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400976 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 }
978
979 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000980 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 pSMB->ByteCount = cpu_to_le16(name_len + 1);
982 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
983 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400984 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000985 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500986 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
988 cifs_buf_release(pSMB);
989 if (rc == -EAGAIN)
990 goto RmDirRetry;
991 return rc;
992}
993
994int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300995CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
996 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997{
998 int rc = 0;
999 CREATE_DIRECTORY_REQ *pSMB = NULL;
1000 CREATE_DIRECTORY_RSP *pSMBr = NULL;
1001 int bytes_returned;
1002 int name_len;
Steve French2baa2682014-09-27 02:19:01 -05001003 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004
Joe Perchesf96637b2013-05-04 22:12:25 -05001005 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006MkDirRetry:
1007 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1008 (void **) &pSMBr);
1009 if (rc)
1010 return rc;
1011
1012 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06001013 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001014 PATH_MAX, cifs_sb->local_nls,
1015 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 name_len++; /* trailing null */
1017 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001018 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 name_len = strnlen(name, PATH_MAX);
1020 name_len++; /* trailing null */
1021 strncpy(pSMB->DirName, name, name_len);
1022 }
1023
1024 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001025 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1027 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1028 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001029 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001030 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001031 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001032
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 cifs_buf_release(pSMB);
1034 if (rc == -EAGAIN)
1035 goto MkDirRetry;
1036 return rc;
1037}
1038
Steve French2dd29d32007-04-23 22:07:35 +00001039int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001040CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1041 __u32 posix_flags, __u64 mode, __u16 *netfid,
1042 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1043 const char *name, const struct nls_table *nls_codepage,
1044 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001045{
1046 TRANSACTION2_SPI_REQ *pSMB = NULL;
1047 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1048 int name_len;
1049 int rc = 0;
1050 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001051 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001052 OPEN_PSX_REQ *pdata;
1053 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001054
Joe Perchesf96637b2013-05-04 22:12:25 -05001055 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001056PsxCreat:
1057 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1058 (void **) &pSMBr);
1059 if (rc)
1060 return rc;
1061
1062 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1063 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001064 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1065 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001066 name_len++; /* trailing null */
1067 name_len *= 2;
1068 } else { /* BB improve the check for buffer overruns BB */
1069 name_len = strnlen(name, PATH_MAX);
1070 name_len++; /* trailing null */
1071 strncpy(pSMB->FileName, name, name_len);
1072 }
1073
1074 params = 6 + name_len;
1075 count = sizeof(OPEN_PSX_REQ);
1076 pSMB->MaxParameterCount = cpu_to_le16(2);
1077 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1078 pSMB->MaxSetupCount = 0;
1079 pSMB->Reserved = 0;
1080 pSMB->Flags = 0;
1081 pSMB->Timeout = 0;
1082 pSMB->Reserved2 = 0;
1083 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001084 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001085 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001086 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001087 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001088 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001089 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001090 pdata->OpenFlags = cpu_to_le32(*pOplock);
1091 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1092 pSMB->DataOffset = cpu_to_le16(offset);
1093 pSMB->SetupCount = 1;
1094 pSMB->Reserved3 = 0;
1095 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1096 byte_count = 3 /* pad */ + params + count;
1097
1098 pSMB->DataCount = cpu_to_le16(count);
1099 pSMB->ParameterCount = cpu_to_le16(params);
1100 pSMB->TotalDataCount = pSMB->DataCount;
1101 pSMB->TotalParameterCount = pSMB->ParameterCount;
1102 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1103 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001104 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001105 pSMB->ByteCount = cpu_to_le16(byte_count);
1106 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1107 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1108 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001109 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001110 goto psx_create_err;
1111 }
1112
Joe Perchesf96637b2013-05-04 22:12:25 -05001113 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001114 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1115
Jeff Layton820a8032011-05-04 08:05:26 -04001116 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001117 rc = -EIO; /* bad smb */
1118 goto psx_create_err;
1119 }
1120
1121 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001122 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001123 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001124
Steve French2dd29d32007-04-23 22:07:35 +00001125 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001126 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001127 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1128 /* Let caller know file was created so we can set the mode. */
1129 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001130 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001131 *pOplock |= CIFS_CREATE_ACTION;
1132 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001133 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1134 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001135 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001136 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001137 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001138 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001139 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001140 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001141 goto psx_create_err;
1142 }
Steve French50c2f752007-07-13 00:33:32 +00001143 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001144 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001145 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001146 }
Steve French2dd29d32007-04-23 22:07:35 +00001147
1148psx_create_err:
1149 cifs_buf_release(pSMB);
1150
Steve French65bc98b2009-07-10 15:27:25 +00001151 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001152 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001153 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001154 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001155
1156 if (rc == -EAGAIN)
1157 goto PsxCreat;
1158
Steve French50c2f752007-07-13 00:33:32 +00001159 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001160}
1161
Steve Frencha9d02ad2005-08-24 23:06:05 -07001162static __u16 convert_disposition(int disposition)
1163{
1164 __u16 ofun = 0;
1165
1166 switch (disposition) {
1167 case FILE_SUPERSEDE:
1168 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1169 break;
1170 case FILE_OPEN:
1171 ofun = SMBOPEN_OAPPEND;
1172 break;
1173 case FILE_CREATE:
1174 ofun = SMBOPEN_OCREATE;
1175 break;
1176 case FILE_OPEN_IF:
1177 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1178 break;
1179 case FILE_OVERWRITE:
1180 ofun = SMBOPEN_OTRUNC;
1181 break;
1182 case FILE_OVERWRITE_IF:
1183 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1184 break;
1185 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001186 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001187 ofun = SMBOPEN_OAPPEND; /* regular open */
1188 }
1189 return ofun;
1190}
1191
Jeff Layton35fc37d2008-05-14 10:22:03 -07001192static int
1193access_flags_to_smbopen_mode(const int access_flags)
1194{
1195 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1196
1197 if (masked_flags == GENERIC_READ)
1198 return SMBOPEN_READ;
1199 else if (masked_flags == GENERIC_WRITE)
1200 return SMBOPEN_WRITE;
1201
1202 /* just go for read/write */
1203 return SMBOPEN_READWRITE;
1204}
1205
Steve Frencha9d02ad2005-08-24 23:06:05 -07001206int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001207SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001208 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001209 const int access_flags, const int create_options, __u16 *netfid,
1210 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001211 const struct nls_table *nls_codepage, int remap)
1212{
1213 int rc = -EACCES;
1214 OPENX_REQ *pSMB = NULL;
1215 OPENX_RSP *pSMBr = NULL;
1216 int bytes_returned;
1217 int name_len;
1218 __u16 count;
1219
1220OldOpenRetry:
1221 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1222 (void **) &pSMBr);
1223 if (rc)
1224 return rc;
1225
1226 pSMB->AndXCommand = 0xFF; /* none */
1227
1228 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1229 count = 1; /* account for one byte pad to word boundary */
1230 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001231 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1232 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001233 name_len++; /* trailing null */
1234 name_len *= 2;
1235 } else { /* BB improve check for buffer overruns BB */
1236 count = 0; /* no pad */
1237 name_len = strnlen(fileName, PATH_MAX);
1238 name_len++; /* trailing null */
1239 strncpy(pSMB->fileName, fileName, name_len);
1240 }
1241 if (*pOplock & REQ_OPLOCK)
1242 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001243 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001244 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001245
Steve Frencha9d02ad2005-08-24 23:06:05 -07001246 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001247 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001248 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1249 /* set file as system file if special file such
1250 as fifo and server expecting SFU style and
1251 no Unix extensions */
1252
Steve French790fe572007-07-07 19:25:05 +00001253 if (create_options & CREATE_OPTION_SPECIAL)
1254 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001255 else /* BB FIXME BB */
1256 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001257
Jeff Layton67750fb2008-05-09 22:28:02 +00001258 if (create_options & CREATE_OPTION_READONLY)
1259 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001260
1261 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001262/* pSMB->CreateOptions = cpu_to_le32(create_options &
1263 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001264 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001265
1266 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001267 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001268 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001269 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001270
1271 pSMB->ByteCount = cpu_to_le16(count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001272 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001273 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001274 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001275 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001276 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001277 } else {
1278 /* BB verify if wct == 15 */
1279
Steve French582d21e2008-05-13 04:54:12 +00001280/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001281
1282 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1283 /* Let caller know file was created so we can set the mode. */
1284 /* Do we care about the CreateAction in any other cases? */
1285 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001286/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001287 *pOplock |= CIFS_CREATE_ACTION; */
1288 /* BB FIXME END */
1289
Steve French790fe572007-07-07 19:25:05 +00001290 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001291 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1292 pfile_info->LastAccessTime = 0; /* BB fixme */
1293 pfile_info->LastWriteTime = 0; /* BB fixme */
1294 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001295 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001296 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001297 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001298 pfile_info->AllocationSize =
1299 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1300 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001301 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001302 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001303 }
1304 }
1305
1306 cifs_buf_release(pSMB);
1307 if (rc == -EAGAIN)
1308 goto OldOpenRetry;
1309 return rc;
1310}
1311
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312int
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001313CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
1314 FILE_ALL_INFO *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315{
1316 int rc = -EACCES;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001317 OPEN_REQ *req = NULL;
1318 OPEN_RSP *rsp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 int bytes_returned;
1320 int name_len;
1321 __u16 count;
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001322 struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
1323 struct cifs_tcon *tcon = oparms->tcon;
Steve French2baa2682014-09-27 02:19:01 -05001324 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001325 const struct nls_table *nls = cifs_sb->local_nls;
1326 int create_options = oparms->create_options;
1327 int desired_access = oparms->desired_access;
1328 int disposition = oparms->disposition;
1329 const char *path = oparms->path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330
1331openRetry:
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001332 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
1333 (void **)&rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 if (rc)
1335 return rc;
1336
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001337 /* no commands go after this */
1338 req->AndXCommand = 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001340 if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
1341 /* account for one byte pad to word boundary */
1342 count = 1;
1343 name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
1344 path, PATH_MAX, nls, remap);
1345 /* trailing null */
1346 name_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 name_len *= 2;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001348 req->NameLength = cpu_to_le16(name_len);
1349 } else {
1350 /* BB improve check for buffer overruns BB */
1351 /* no pad */
1352 count = 0;
1353 name_len = strnlen(path, PATH_MAX);
1354 /* trailing null */
1355 name_len++;
1356 req->NameLength = cpu_to_le16(name_len);
1357 strncpy(req->fileName, path, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 }
Jeff Layton67750fb2008-05-09 22:28:02 +00001359
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001360 if (*oplock & REQ_OPLOCK)
1361 req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1362 else if (*oplock & REQ_BATCHOPLOCK)
1363 req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1364
1365 req->DesiredAccess = cpu_to_le32(desired_access);
1366 req->AllocationSize = 0;
1367
1368 /*
1369 * Set file as system file if special file such as fifo and server
1370 * expecting SFU style and no Unix extensions.
1371 */
1372 if (create_options & CREATE_OPTION_SPECIAL)
1373 req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1374 else
1375 req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1376
1377 /*
1378 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
1379 * sensitive checks for other servers such as Samba.
1380 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 if (tcon->ses->capabilities & CAP_UNIX)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001382 req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383
Jeff Layton67750fb2008-05-09 22:28:02 +00001384 if (create_options & CREATE_OPTION_READONLY)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001385 req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
Jeff Layton67750fb2008-05-09 22:28:02 +00001386
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001387 req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1388 req->CreateDisposition = cpu_to_le32(disposition);
1389 req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1390
Steve French09d1db52005-04-28 22:41:08 -07001391 /* BB Expirement with various impersonation levels and verify */
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001392 req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1393 req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394
1395 count += name_len;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001396 inc_rfc1001_len(req, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001398 req->ByteCount = cpu_to_le16(count);
1399 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
1400 (struct smb_hdr *)rsp, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001401 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001403 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001404 cifs_buf_release(req);
1405 if (rc == -EAGAIN)
1406 goto openRetry;
1407 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001409
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001410 /* 1 byte no need to le_to_cpu */
1411 *oplock = rsp->OplockLevel;
1412 /* cifs fid stays in le */
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001413 oparms->fid->netfid = rsp->Fid;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001414
1415 /* Let caller know file was created so we can set the mode. */
1416 /* Do we care about the CreateAction in any other cases? */
1417 if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
1418 *oplock |= CIFS_CREATE_ACTION;
1419
1420 if (buf) {
1421 /* copy from CreationTime to Attributes */
1422 memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
1423 /* the file_info buf is endian converted by caller */
1424 buf->AllocationSize = rsp->AllocationSize;
1425 buf->EndOfFile = rsp->EndOfFile;
1426 buf->NumberOfLinks = cpu_to_le32(1);
1427 buf->DeletePending = 0;
1428 }
1429
1430 cifs_buf_release(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 return rc;
1432}
1433
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001434/*
1435 * Discard any remaining data in the current SMB. To do this, we borrow the
1436 * current bigbuf.
1437 */
Pavel Shilovskyc42a6ab2016-11-17 16:20:23 -08001438int
Pavel Shilovsky350be252017-04-10 10:31:33 -07001439cifs_discard_remaining_data(struct TCP_Server_Info *server)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001440{
Ronnie Sahlberg05432e22018-04-09 18:06:31 +10001441 unsigned int rfclen = server->pdu_size;
1442 int remaining = rfclen + server->vals->header_preamble_size -
1443 server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001444
1445 while (remaining > 0) {
1446 int length;
1447
1448 length = cifs_read_from_socket(server, server->bigbuf,
1449 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001450 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001451 if (length < 0)
1452 return length;
1453 server->total_read += length;
1454 remaining -= length;
1455 }
1456
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001457 return 0;
1458}
1459
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001460static int
1461cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1462{
1463 int length;
1464 struct cifs_readdata *rdata = mid->callback_data;
1465
Pavel Shilovsky350be252017-04-10 10:31:33 -07001466 length = cifs_discard_remaining_data(server);
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001467 dequeue_mid(mid, rdata->result);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001468 mid->resp_buf = server->smallbuf;
1469 server->smallbuf = NULL;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001470 return length;
1471}
1472
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001473int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001474cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1475{
1476 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001477 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001478 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001479 char *buf = server->smallbuf;
Ronnie Sahlberg2e964672018-04-09 18:06:26 +10001480 unsigned int buflen = server->pdu_size +
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +11001481 server->vals->header_preamble_size;
Long Li74dcf412017-11-22 17:38:46 -07001482 bool use_rdma_mr = false;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001483
Joe Perchesf96637b2013-05-04 22:12:25 -05001484 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1485 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001486
1487 /*
1488 * read the rest of READ_RSP header (sans Data array), or whatever we
1489 * can if there's not enough data. At this point, we've read down to
1490 * the Mid.
1491 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001492 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001493 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001494
Al Viroa6137302016-01-09 19:37:16 -05001495 length = cifs_read_from_socket(server,
1496 buf + HEADER_SIZE(server) - 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001497 if (length < 0)
1498 return length;
1499 server->total_read += length;
1500
Pavel Shilovsky511c54a2017-07-08 14:32:00 -07001501 if (server->ops->is_session_expired &&
1502 server->ops->is_session_expired(buf)) {
1503 cifs_reconnect(server);
1504 wake_up(&server->response_q);
1505 return -1;
1506 }
1507
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001508 if (server->ops->is_status_pending &&
1509 server->ops->is_status_pending(buf, server, 0)) {
Pavel Shilovsky350be252017-04-10 10:31:33 -07001510 cifs_discard_remaining_data(server);
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001511 return -1;
1512 }
1513
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001514 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001515 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001516 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001517 cifs_dbg(FYI, "%s: server returned error %d\n",
1518 __func__, rdata->result);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001519 return cifs_readv_discard(server, mid);
1520 }
1521
1522 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001523 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001524 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1525 __func__, server->total_read,
1526 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001527 rdata->result = -EIO;
1528 return cifs_readv_discard(server, mid);
1529 }
1530
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +11001531 data_offset = server->ops->read_data_offset(buf) +
1532 server->vals->header_preamble_size;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001533 if (data_offset < server->total_read) {
1534 /*
1535 * win2k8 sometimes sends an offset of 0 when the read
1536 * is beyond the EOF. Treat it as if the data starts just after
1537 * the header.
1538 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001539 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1540 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001541 data_offset = server->total_read;
1542 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1543 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001544 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1545 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001546 rdata->result = -EIO;
1547 return cifs_readv_discard(server, mid);
1548 }
1549
Joe Perchesf96637b2013-05-04 22:12:25 -05001550 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1551 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001552
1553 len = data_offset - server->total_read;
1554 if (len > 0) {
1555 /* read any junk before data into the rest of smallbuf */
Al Viroa6137302016-01-09 19:37:16 -05001556 length = cifs_read_from_socket(server,
1557 buf + server->total_read, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001558 if (length < 0)
1559 return length;
1560 server->total_read += length;
1561 }
1562
1563 /* set up first iov for signature check */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001564 rdata->iov[0].iov_base = buf;
1565 rdata->iov[0].iov_len = 4;
1566 rdata->iov[1].iov_base = buf + 4;
1567 rdata->iov[1].iov_len = server->total_read - 4;
1568 cifs_dbg(FYI, "0: iov_base=%p iov_len=%u\n",
1569 rdata->iov[0].iov_base, server->total_read);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001570
1571 /* how much data is in the response? */
Long Li74dcf412017-11-22 17:38:46 -07001572#ifdef CONFIG_CIFS_SMB_DIRECT
1573 use_rdma_mr = rdata->mr;
1574#endif
1575 data_len = server->ops->read_data_length(buf, use_rdma_mr);
1576 if (!use_rdma_mr && (data_offset + data_len > buflen)) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001577 /* data_len is corrupt -- discard frame */
1578 rdata->result = -EIO;
1579 return cifs_readv_discard(server, mid);
1580 }
1581
Jeff Layton8321fec2012-09-19 06:22:32 -07001582 length = rdata->read_into_pages(server, rdata, data_len);
1583 if (length < 0)
1584 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001585
Jeff Layton8321fec2012-09-19 06:22:32 -07001586 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001587
Joe Perchesf96637b2013-05-04 22:12:25 -05001588 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1589 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001590
1591 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001592 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001593 return cifs_readv_discard(server, mid);
1594
1595 dequeue_mid(mid, false);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001596 mid->resp_buf = server->smallbuf;
1597 server->smallbuf = NULL;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001598 return length;
1599}
1600
1601static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001602cifs_readv_callback(struct mid_q_entry *mid)
1603{
1604 struct cifs_readdata *rdata = mid->callback_data;
1605 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1606 struct TCP_Server_Info *server = tcon->ses->server;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001607 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1608 .rq_nvec = 2,
Jeff Layton8321fec2012-09-19 06:22:32 -07001609 .rq_pages = rdata->pages,
Long Li6d3adb22018-09-20 21:18:38 +00001610 .rq_offset = rdata->page_offset,
Jeff Layton8321fec2012-09-19 06:22:32 -07001611 .rq_npages = rdata->nr_pages,
1612 .rq_pagesz = rdata->pagesz,
1613 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001614
Joe Perchesf96637b2013-05-04 22:12:25 -05001615 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1616 __func__, mid->mid, mid->mid_state, rdata->result,
1617 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001618
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001619 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001620 case MID_RESPONSE_RECEIVED:
1621 /* result already set, check signature */
Jeff Layton38d77c52013-05-26 07:01:00 -04001622 if (server->sign) {
Steve French985e4ff02012-08-03 09:42:45 -05001623 int rc = 0;
1624
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001625 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001626 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001627 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001628 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1629 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001630 }
1631 /* FIXME: should this be counted toward the initiating task? */
Pavel Shilovsky34a54d62014-07-10 10:03:29 +04001632 task_io_account_read(rdata->got_bytes);
1633 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001634 break;
1635 case MID_REQUEST_SUBMITTED:
1636 case MID_RETRY_NEEDED:
1637 rdata->result = -EAGAIN;
Pavel Shilovskyd913ed12014-07-10 11:31:48 +04001638 if (server->sign && rdata->got_bytes)
1639 /* reset bytes number since we can not check a sign */
1640 rdata->got_bytes = 0;
1641 /* FIXME: should this be counted toward the initiating task? */
1642 task_io_account_read(rdata->got_bytes);
1643 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001644 break;
1645 default:
1646 rdata->result = -EIO;
1647 }
1648
Jeff Laytonda472fc2012-03-23 14:40:53 -04001649 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001650 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001651 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001652}
1653
1654/* cifs_async_readv - send an async write, and set up mid to handle result */
1655int
1656cifs_async_readv(struct cifs_readdata *rdata)
1657{
1658 int rc;
1659 READ_REQ *smb = NULL;
1660 int wct;
1661 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001662 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1663 .rq_nvec = 2 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001664
Joe Perchesf96637b2013-05-04 22:12:25 -05001665 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1666 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001667
1668 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1669 wct = 12;
1670 else {
1671 wct = 10; /* old style read */
1672 if ((rdata->offset >> 32) > 0) {
1673 /* can not handle this big offset for old */
1674 return -EIO;
1675 }
1676 }
1677
1678 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1679 if (rc)
1680 return rc;
1681
1682 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1683 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1684
1685 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001686 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001687 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1688 if (wct == 12)
1689 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1690 smb->Remaining = 0;
1691 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1692 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1693 if (wct == 12)
1694 smb->ByteCount = 0;
1695 else {
1696 /* old style read */
1697 struct smb_com_readx_req *smbr =
1698 (struct smb_com_readx_req *)smb;
1699 smbr->ByteCount = 0;
1700 }
1701
1702 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001703 rdata->iov[0].iov_base = smb;
1704 rdata->iov[0].iov_len = 4;
1705 rdata->iov[1].iov_base = (char *)smb + 4;
1706 rdata->iov[1].iov_len = get_rfc1002_length(smb);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001707
Jeff Layton6993f742012-05-16 07:13:17 -04001708 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001709 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -08001710 cifs_readv_callback, NULL, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001711
1712 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001713 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001714 else
1715 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001716
1717 cifs_small_buf_release(smb);
1718 return rc;
1719}
1720
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001722CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1723 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724{
1725 int rc = -EACCES;
1726 READ_REQ *pSMB = NULL;
1727 READ_RSP *pSMBr = NULL;
1728 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001729 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001730 int resp_buf_type = 0;
1731 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001732 struct kvec rsp_iov;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001733 __u32 pid = io_parms->pid;
1734 __u16 netfid = io_parms->netfid;
1735 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001736 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001737 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738
Joe Perchesf96637b2013-05-04 22:12:25 -05001739 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001740 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001741 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001742 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001743 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001744 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001745 /* can not handle this big offset for old */
1746 return -EIO;
1747 }
1748 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749
1750 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001751 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 if (rc)
1753 return rc;
1754
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001755 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1756 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1757
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 /* tcon and ses pointer are checked in smb_init */
1759 if (tcon->ses->server == NULL)
1760 return -ECONNABORTED;
1761
Steve Frenchec637e32005-12-12 20:53:18 -08001762 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001764 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001765 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001766 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001767
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 pSMB->Remaining = 0;
1769 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1770 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001771 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001772 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1773 else {
1774 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001775 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001776 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001777 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001778 }
Steve Frenchec637e32005-12-12 20:53:18 -08001779
1780 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001781 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001782 rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
1783 CIFS_LOG_ERROR, &rsp_iov);
1784 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001785 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001786 pSMBr = (READ_RSP *)rsp_iov.iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001788 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 } else {
1790 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1791 data_length = data_length << 16;
1792 data_length += le16_to_cpu(pSMBr->DataLength);
1793 *nbytes = data_length;
1794
1795 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001796 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001798 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001799 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 rc = -EIO;
1801 *nbytes = 0;
1802 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001803 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001804 le16_to_cpu(pSMBr->DataOffset);
1805/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001806 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001807 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001808 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001809 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001810 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 }
1812 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813
Steve French790fe572007-07-07 19:25:05 +00001814 if (*buf) {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001815 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French790fe572007-07-07 19:25:05 +00001816 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001817 /* return buffer to caller to free */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001818 *buf = rsp_iov.iov_base;
Steve French790fe572007-07-07 19:25:05 +00001819 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001820 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001821 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001822 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001823 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001824
1825 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 since file handle passed in no longer valid */
1827 return rc;
1828}
1829
Steve Frenchec637e32005-12-12 20:53:18 -08001830
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001832CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Al Virodbbab322016-09-05 17:53:43 -04001833 unsigned int *nbytes, const char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834{
1835 int rc = -EACCES;
1836 WRITE_REQ *pSMB = NULL;
1837 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001838 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 __u32 bytes_sent;
1840 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001841 __u32 pid = io_parms->pid;
1842 __u16 netfid = io_parms->netfid;
1843 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001844 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001845 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846
Steve Frencha24e2d72010-04-03 17:20:21 +00001847 *nbytes = 0;
1848
Joe Perchesf96637b2013-05-04 22:12:25 -05001849 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001850 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001851 return -ECONNABORTED;
1852
Steve French790fe572007-07-07 19:25:05 +00001853 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001854 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001855 else {
Steve French1c955182005-08-30 20:58:07 -07001856 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001857 if ((offset >> 32) > 0) {
1858 /* can not handle big offset for old srv */
1859 return -EIO;
1860 }
1861 }
Steve French1c955182005-08-30 20:58:07 -07001862
1863 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 (void **) &pSMBr);
1865 if (rc)
1866 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001867
1868 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1869 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1870
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 /* tcon and ses pointer are checked in smb_init */
1872 if (tcon->ses->server == NULL)
1873 return -ECONNABORTED;
1874
1875 pSMB->AndXCommand = 0xFF; /* none */
1876 pSMB->Fid = netfid;
1877 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001878 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001879 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001880
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 pSMB->Reserved = 0xFFFFFFFF;
1882 pSMB->WriteMode = 0;
1883 pSMB->Remaining = 0;
1884
Steve French50c2f752007-07-13 00:33:32 +00001885 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 can send more if LARGE_WRITE_X capability returned by the server and if
1887 our buffer is big enough or if we convert to iovecs on socket writes
1888 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001889 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1891 } else {
1892 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1893 & ~0xFF;
1894 }
1895
1896 if (bytes_sent > count)
1897 bytes_sent = count;
1898 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001899 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001900 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001901 memcpy(pSMB->Data, buf, bytes_sent);
Al Virodbbab322016-09-05 17:53:43 -04001902 else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 /* No buffer */
1904 cifs_buf_release(pSMB);
1905 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001906 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001907 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001908 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001909 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001910 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001911
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1913 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001914 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001915
Steve French790fe572007-07-07 19:25:05 +00001916 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001917 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001918 else { /* old style write has byte count 4 bytes earlier
1919 so 4 bytes pad */
1920 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001921 (struct smb_com_writex_req *)pSMB;
1922 pSMBW->ByteCount = cpu_to_le16(byte_count);
1923 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924
1925 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Al Virodbbab322016-09-05 17:53:43 -04001926 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001927 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001929 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 } else {
1931 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1932 *nbytes = (*nbytes) << 16;
1933 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301934
1935 /*
1936 * Mask off high 16 bits when bytes written as returned by the
1937 * server is greater than bytes requested by the client. Some
1938 * OS/2 servers are known to set incorrect CountHigh values.
1939 */
1940 if (*nbytes > count)
1941 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 }
1943
1944 cifs_buf_release(pSMB);
1945
Steve French50c2f752007-07-13 00:33:32 +00001946 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 since file handle passed in no longer valid */
1948
1949 return rc;
1950}
1951
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001952void
1953cifs_writedata_release(struct kref *refcount)
1954{
1955 struct cifs_writedata *wdata = container_of(refcount,
1956 struct cifs_writedata, refcount);
Long Lidb223a52017-11-22 17:38:45 -07001957#ifdef CONFIG_CIFS_SMB_DIRECT
1958 if (wdata->mr) {
1959 smbd_deregister_mr(wdata->mr);
1960 wdata->mr = NULL;
1961 }
1962#endif
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001963
1964 if (wdata->cfile)
1965 cifsFileInfo_put(wdata->cfile);
1966
Long Li8e7360f2018-05-30 12:47:56 -07001967 kvfree(wdata->pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001968 kfree(wdata);
1969}
1970
1971/*
1972 * Write failed with a retryable error. Resend the write request. It's also
1973 * possible that the page was redirtied so re-clean the page.
1974 */
1975static void
1976cifs_writev_requeue(struct cifs_writedata *wdata)
1977{
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001978 int i, rc = 0;
David Howells2b0143b2015-03-17 22:25:59 +00001979 struct inode *inode = d_inode(wdata->cfile->dentry);
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001980 struct TCP_Server_Info *server;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001981 unsigned int rest_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001982
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001983 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1984 i = 0;
1985 rest_len = wdata->bytes;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001986 do {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001987 struct cifs_writedata *wdata2;
1988 unsigned int j, nr_pages, wsize, tailsz, cur_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001989
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001990 wsize = server->ops->wp_retry_size(inode);
1991 if (wsize < rest_len) {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001992 nr_pages = wsize / PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001993 if (!nr_pages) {
1994 rc = -ENOTSUPP;
1995 break;
1996 }
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001997 cur_len = nr_pages * PAGE_SIZE;
1998 tailsz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001999 } else {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002000 nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002001 cur_len = rest_len;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002002 tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE;
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06002003 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002004
2005 wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
2006 if (!wdata2) {
2007 rc = -ENOMEM;
2008 break;
2009 }
2010
2011 for (j = 0; j < nr_pages; j++) {
2012 wdata2->pages[j] = wdata->pages[i + j];
2013 lock_page(wdata2->pages[j]);
2014 clear_page_dirty_for_io(wdata2->pages[j]);
2015 }
2016
2017 wdata2->sync_mode = wdata->sync_mode;
2018 wdata2->nr_pages = nr_pages;
2019 wdata2->offset = page_offset(wdata2->pages[0]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002020 wdata2->pagesz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002021 wdata2->tailsz = tailsz;
2022 wdata2->bytes = cur_len;
2023
2024 wdata2->cfile = find_writable_file(CIFS_I(inode), false);
2025 if (!wdata2->cfile) {
2026 cifs_dbg(VFS, "No writable handles for inode\n");
2027 rc = -EBADF;
2028 break;
2029 }
2030 wdata2->pid = wdata2->cfile->pid;
2031 rc = server->ops->async_writev(wdata2, cifs_writedata_release);
2032
2033 for (j = 0; j < nr_pages; j++) {
2034 unlock_page(wdata2->pages[j]);
2035 if (rc != 0 && rc != -EAGAIN) {
2036 SetPageError(wdata2->pages[j]);
2037 end_page_writeback(wdata2->pages[j]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002038 put_page(wdata2->pages[j]);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002039 }
2040 }
2041
2042 if (rc) {
2043 kref_put(&wdata2->refcount, cifs_writedata_release);
2044 if (rc == -EAGAIN)
2045 continue;
2046 break;
2047 }
2048
2049 rest_len -= cur_len;
2050 i += nr_pages;
2051 } while (i < wdata->nr_pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002052
2053 mapping_set_error(inode->i_mapping, rc);
2054 kref_put(&wdata->refcount, cifs_writedata_release);
2055}
2056
Jeff Laytonc2e87642012-03-23 14:40:55 -04002057void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002058cifs_writev_complete(struct work_struct *work)
2059{
2060 struct cifs_writedata *wdata = container_of(work,
2061 struct cifs_writedata, work);
David Howells2b0143b2015-03-17 22:25:59 +00002062 struct inode *inode = d_inode(wdata->cfile->dentry);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002063 int i = 0;
2064
2065 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04002066 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002067 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04002068 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002069 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2070 wdata->bytes);
2071 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2072 return cifs_writev_requeue(wdata);
2073
2074 for (i = 0; i < wdata->nr_pages; i++) {
2075 struct page *page = wdata->pages[i];
2076 if (wdata->result == -EAGAIN)
2077 __set_page_dirty_nobuffers(page);
2078 else if (wdata->result < 0)
2079 SetPageError(page);
2080 end_page_writeback(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002081 put_page(page);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002082 }
2083 if (wdata->result != -EAGAIN)
2084 mapping_set_error(inode->i_mapping, wdata->result);
2085 kref_put(&wdata->refcount, cifs_writedata_release);
2086}
2087
2088struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04002089cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002090{
Long Li8e7360f2018-05-30 12:47:56 -07002091 struct page **pages =
Kees Cook6396bb22018-06-12 14:03:40 -07002092 kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
Long Li8e7360f2018-05-30 12:47:56 -07002093 if (pages)
2094 return cifs_writedata_direct_alloc(pages, complete);
2095
2096 return NULL;
2097}
2098
2099struct cifs_writedata *
2100cifs_writedata_direct_alloc(struct page **pages, work_func_t complete)
2101{
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002102 struct cifs_writedata *wdata;
2103
Long Li8e7360f2018-05-30 12:47:56 -07002104 wdata = kzalloc(sizeof(*wdata), GFP_NOFS);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002105 if (wdata != NULL) {
Long Li8e7360f2018-05-30 12:47:56 -07002106 wdata->pages = pages;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002107 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04002108 INIT_LIST_HEAD(&wdata->list);
2109 init_completion(&wdata->done);
2110 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002111 }
2112 return wdata;
2113}
2114
2115/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002116 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002117 * workqueue completion task.
2118 */
2119static void
2120cifs_writev_callback(struct mid_q_entry *mid)
2121{
2122 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002123 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002124 unsigned int written;
2125 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2126
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002127 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002128 case MID_RESPONSE_RECEIVED:
2129 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2130 if (wdata->result != 0)
2131 break;
2132
2133 written = le16_to_cpu(smb->CountHigh);
2134 written <<= 16;
2135 written += le16_to_cpu(smb->Count);
2136 /*
2137 * Mask off high 16 bits when bytes written as returned
2138 * by the server is greater than bytes requested by the
2139 * client. OS/2 servers are known to set incorrect
2140 * CountHigh values.
2141 */
2142 if (written > wdata->bytes)
2143 written &= 0xFFFF;
2144
2145 if (written < wdata->bytes)
2146 wdata->result = -ENOSPC;
2147 else
2148 wdata->bytes = written;
2149 break;
2150 case MID_REQUEST_SUBMITTED:
2151 case MID_RETRY_NEEDED:
2152 wdata->result = -EAGAIN;
2153 break;
2154 default:
2155 wdata->result = -EIO;
2156 break;
2157 }
2158
Jeff Laytonda472fc2012-03-23 14:40:53 -04002159 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002160 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002161 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002162}
2163
2164/* cifs_async_writev - send an async write, and set up mid to handle result */
2165int
Steve French4a5c80d2014-02-07 20:45:12 -06002166cifs_async_writev(struct cifs_writedata *wdata,
2167 void (*release)(struct kref *kref))
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002168{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002169 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002170 WRITE_REQ *smb = NULL;
2171 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002172 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002173 struct kvec iov[2];
Jeff Laytonfec344e2012-09-18 16:20:35 -07002174 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002175
2176 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2177 wct = 14;
2178 } else {
2179 wct = 12;
2180 if (wdata->offset >> 32 > 0) {
2181 /* can not handle big offset for old srv */
2182 return -EIO;
2183 }
2184 }
2185
2186 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2187 if (rc)
2188 goto async_writev_out;
2189
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002190 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2191 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002192
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002193 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002194 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002195 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2196 if (wct == 14)
2197 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2198 smb->Reserved = 0xFFFFFFFF;
2199 smb->WriteMode = 0;
2200 smb->Remaining = 0;
2201
2202 smb->DataOffset =
2203 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2204
2205 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002206 iov[0].iov_len = 4;
2207 iov[0].iov_base = smb;
2208 iov[1].iov_len = get_rfc1002_length(smb) + 1;
2209 iov[1].iov_base = (char *)smb + 4;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002210
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002211 rqst.rq_iov = iov;
2212 rqst.rq_nvec = 2;
Jeff Laytoneddb0792012-09-18 16:20:35 -07002213 rqst.rq_pages = wdata->pages;
Long Li6d3adb22018-09-20 21:18:38 +00002214 rqst.rq_offset = wdata->page_offset;
Jeff Laytoneddb0792012-09-18 16:20:35 -07002215 rqst.rq_npages = wdata->nr_pages;
2216 rqst.rq_pagesz = wdata->pagesz;
2217 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002218
Joe Perchesf96637b2013-05-04 22:12:25 -05002219 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2220 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002221
2222 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2223 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2224
2225 if (wct == 14) {
2226 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2227 put_bcc(wdata->bytes + 1, &smb->hdr);
2228 } else {
2229 /* wct == 12 */
2230 struct smb_com_writex_req *smbw =
2231 (struct smb_com_writex_req *)smb;
2232 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2233 put_bcc(wdata->bytes + 5, &smbw->hdr);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002234 iov[1].iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002235 }
2236
2237 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002238 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -08002239 cifs_writev_callback, NULL, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002240
2241 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002242 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002243 else
Steve French4a5c80d2014-02-07 20:45:12 -06002244 kref_put(&wdata->refcount, release);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002245
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002246async_writev_out:
2247 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002248 return rc;
2249}
2250
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002251int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002252CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002253 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254{
2255 int rc = -EACCES;
2256 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002257 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002258 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002259 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002260 __u32 pid = io_parms->pid;
2261 __u16 netfid = io_parms->netfid;
2262 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002263 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002264 unsigned int count = io_parms->length;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002265 struct kvec rsp_iov;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002267 *nbytes = 0;
2268
Joe Perchesf96637b2013-05-04 22:12:25 -05002269 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002270
Steve French4c3130e2008-12-09 00:28:16 +00002271 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002272 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002273 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002274 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002275 if ((offset >> 32) > 0) {
2276 /* can not handle big offset for old srv */
2277 return -EIO;
2278 }
2279 }
Steve French8cc64c62005-10-03 13:49:43 -07002280 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 if (rc)
2282 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002283
2284 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2285 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2286
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 /* tcon and ses pointer are checked in smb_init */
2288 if (tcon->ses->server == NULL)
2289 return -ECONNABORTED;
2290
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002291 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 pSMB->Fid = netfid;
2293 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002294 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002295 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 pSMB->Reserved = 0xFFFFFFFF;
2297 pSMB->WriteMode = 0;
2298 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002299
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002301 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302
Steve French3e844692005-10-03 13:37:24 -07002303 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2304 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002305 /* header + 1 byte pad */
2306 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002307 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002308 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002309 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002310 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002311 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002312 pSMB->ByteCount = cpu_to_le16(count + 1);
2313 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002314 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002315 (struct smb_com_writex_req *)pSMB;
2316 pSMBW->ByteCount = cpu_to_le16(count + 5);
2317 }
Steve French3e844692005-10-03 13:37:24 -07002318 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002319 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002320 iov[0].iov_len = smb_hdr_len + 4;
2321 else /* wct == 12 pad bigger by four bytes */
2322 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002323
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002324 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
2325 &rsp_iov);
2326 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002327 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002329 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002330 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002331 /* presumably this can not happen, but best to be safe */
2332 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002333 } else {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002334 WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002335 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2336 *nbytes = (*nbytes) << 16;
2337 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302338
2339 /*
2340 * Mask off high 16 bits when bytes written as returned by the
2341 * server is greater than bytes requested by the client. OS/2
2342 * servers are known to set incorrect CountHigh values.
2343 */
2344 if (*nbytes > count)
2345 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002346 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002348 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349
Steve French50c2f752007-07-13 00:33:32 +00002350 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 since file handle passed in no longer valid */
2352
2353 return rc;
2354}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002355
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002356int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2357 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002358 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2359{
2360 int rc = 0;
2361 LOCK_REQ *pSMB = NULL;
2362 struct kvec iov[2];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002363 struct kvec rsp_iov;
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002364 int resp_buf_type;
2365 __u16 count;
2366
Joe Perchesf96637b2013-05-04 22:12:25 -05002367 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2368 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002369
2370 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2371 if (rc)
2372 return rc;
2373
2374 pSMB->Timeout = 0;
2375 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2376 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2377 pSMB->LockType = lock_type;
2378 pSMB->AndXCommand = 0xFF; /* none */
2379 pSMB->Fid = netfid; /* netfid stays le */
2380
2381 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2382 inc_rfc1001_len(pSMB, count);
2383 pSMB->ByteCount = cpu_to_le16(count);
2384
2385 iov[0].iov_base = (char *)pSMB;
2386 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2387 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2388 iov[1].iov_base = (char *)buf;
2389 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2390
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002391 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002392 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP,
2393 &rsp_iov);
2394 cifs_small_buf_release(pSMB);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002395 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002396 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002397
2398 return rc;
2399}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002400
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002402CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002403 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002405 const __u32 numLock, const __u8 lockType,
2406 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407{
2408 int rc = 0;
2409 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002410/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002412 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 __u16 count;
2414
Joe Perchesf96637b2013-05-04 22:12:25 -05002415 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2416 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002417 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2418
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 if (rc)
2420 return rc;
2421
Steve French790fe572007-07-07 19:25:05 +00002422 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002423 /* no response expected */
2424 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002426 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002427 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2429 } else {
2430 pSMB->Timeout = 0;
2431 }
2432
2433 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2434 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2435 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002436 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 pSMB->AndXCommand = 0xFF; /* none */
2438 pSMB->Fid = smb_file_id; /* netfid stays le */
2439
Steve French790fe572007-07-07 19:25:05 +00002440 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002441 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 /* BB where to store pid high? */
2443 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2444 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2445 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2446 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2447 count = sizeof(LOCKING_ANDX_RANGE);
2448 } else {
2449 /* oplock break */
2450 count = 0;
2451 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002452 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 pSMB->ByteCount = cpu_to_le16(count);
2454
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002455 if (waitFlag)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002456 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002457 (struct smb_hdr *) pSMB, &bytes_returned);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002458 else
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002459 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002460 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002461 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002462 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002463 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464
Steve French50c2f752007-07-13 00:33:32 +00002465 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 since file handle passed in no longer valid */
2467 return rc;
2468}
2469
2470int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002471CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002472 const __u16 smb_file_id, const __u32 netpid,
2473 const loff_t start_offset, const __u64 len,
2474 struct file_lock *pLockData, const __u16 lock_type,
2475 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002476{
2477 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2478 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002479 struct cifs_posix_lock *parm_data;
2480 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002481 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002482 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002483 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002484 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002485 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002486 struct kvec rsp_iov;
Steve French08547b02006-02-28 22:39:25 +00002487
Joe Perchesf96637b2013-05-04 22:12:25 -05002488 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002489
Steve French08547b02006-02-28 22:39:25 +00002490 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2491
2492 if (rc)
2493 return rc;
2494
2495 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2496
Steve French50c2f752007-07-13 00:33:32 +00002497 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002498 pSMB->MaxSetupCount = 0;
2499 pSMB->Reserved = 0;
2500 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002501 pSMB->Reserved2 = 0;
2502 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2503 offset = param_offset + params;
2504
Steve French08547b02006-02-28 22:39:25 +00002505 count = sizeof(struct cifs_posix_lock);
2506 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002507 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002508 pSMB->SetupCount = 1;
2509 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002510 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002511 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2512 else
2513 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2514 byte_count = 3 /* pad */ + params + count;
2515 pSMB->DataCount = cpu_to_le16(count);
2516 pSMB->ParameterCount = cpu_to_le16(params);
2517 pSMB->TotalDataCount = pSMB->DataCount;
2518 pSMB->TotalParameterCount = pSMB->ParameterCount;
2519 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002520 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002521 (((char *) &pSMB->hdr.Protocol) + offset);
2522
2523 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002524 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002525 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002526 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002527 pSMB->Timeout = cpu_to_le32(-1);
2528 } else
2529 pSMB->Timeout = 0;
2530
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002531 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002532 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002533 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002534
2535 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002536 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002537 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2538 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002539 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002540 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002541 if (waitFlag) {
2542 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2543 (struct smb_hdr *) pSMBr, &bytes_returned);
2544 } else {
Steve French133672e2007-11-13 22:41:37 +00002545 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002546 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002547 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002548 &resp_buf_type, timeout, &rsp_iov);
2549 pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002550 }
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002551 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002552
Steve French08547b02006-02-28 22:39:25 +00002553 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002554 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002555 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002556 /* lock structure can be returned on get */
2557 __u16 data_offset;
2558 __u16 data_count;
2559 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002560
Jeff Layton820a8032011-05-04 08:05:26 -04002561 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002562 rc = -EIO; /* bad smb */
2563 goto plk_err_exit;
2564 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002565 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2566 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002567 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002568 rc = -EIO;
2569 goto plk_err_exit;
2570 }
2571 parm_data = (struct cifs_posix_lock *)
2572 ((char *)&pSMBr->hdr.Protocol + data_offset);
Fabian Frederickbc09d142014-12-10 15:41:15 -08002573 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002574 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002575 else {
2576 if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002577 cpu_to_le16(CIFS_RDLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002578 pLockData->fl_type = F_RDLCK;
2579 else if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002580 cpu_to_le16(CIFS_WRLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002581 pLockData->fl_type = F_WRLCK;
2582
Steve French5443d132011-03-13 05:08:25 +00002583 pLockData->fl_start = le64_to_cpu(parm_data->start);
2584 pLockData->fl_end = pLockData->fl_start +
2585 le64_to_cpu(parm_data->length) - 1;
Benjamin Coddington9d5b86a2017-07-16 10:28:22 -04002586 pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002587 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002588 }
Steve French50c2f752007-07-13 00:33:32 +00002589
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002590plk_err_exit:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002591 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French133672e2007-11-13 22:41:37 +00002592
Steve French08547b02006-02-28 22:39:25 +00002593 /* Note: On -EAGAIN error only caller can retry on handle based calls
2594 since file handle passed in no longer valid */
2595
2596 return rc;
2597}
2598
2599
2600int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002601CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602{
2603 int rc = 0;
2604 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002605 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606
2607/* do not retry on dead session on close */
2608 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002609 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 return 0;
2611 if (rc)
2612 return rc;
2613
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002615 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002617 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002618 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002619 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002621 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002623 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 }
2625 }
2626
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002628 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 rc = 0;
2630
2631 return rc;
2632}
2633
2634int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002635CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002636{
2637 int rc = 0;
2638 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002639 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002640
2641 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2642 if (rc)
2643 return rc;
2644
2645 pSMB->FileID = (__u16) smb_file_id;
2646 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002647 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002648 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002649 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002650 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002651 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002652
2653 return rc;
2654}
2655
2656int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002657CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002658 const char *from_name, const char *to_name,
2659 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660{
2661 int rc = 0;
2662 RENAME_REQ *pSMB = NULL;
2663 RENAME_RSP *pSMBr = NULL;
2664 int bytes_returned;
2665 int name_len, name_len2;
2666 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002667 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668
Joe Perchesf96637b2013-05-04 22:12:25 -05002669 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670renameRetry:
2671 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2672 (void **) &pSMBr);
2673 if (rc)
2674 return rc;
2675
2676 pSMB->BufferFormat = 0x04;
2677 pSMB->SearchAttributes =
2678 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2679 ATTR_DIRECTORY);
2680
2681 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002682 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2683 from_name, PATH_MAX,
2684 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 name_len++; /* trailing null */
2686 name_len *= 2;
2687 pSMB->OldFileName[name_len] = 0x04; /* pad */
2688 /* protocol requires ASCII signature byte on Unicode string */
2689 pSMB->OldFileName[name_len + 1] = 0x00;
2690 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002691 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002692 to_name, PATH_MAX, cifs_sb->local_nls,
2693 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2695 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002696 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002697 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002699 strncpy(pSMB->OldFileName, from_name, name_len);
2700 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 name_len2++; /* trailing null */
2702 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002703 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 name_len2++; /* trailing null */
2705 name_len2++; /* signature byte */
2706 }
2707
2708 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002709 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 pSMB->ByteCount = cpu_to_le16(count);
2711
2712 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2713 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002714 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002715 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002716 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 cifs_buf_release(pSMB);
2719
2720 if (rc == -EAGAIN)
2721 goto renameRetry;
2722
2723 return rc;
2724}
2725
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002726int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002727 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002728 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729{
2730 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2731 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002732 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 char *data_offset;
2734 char dummy_string[30];
2735 int rc = 0;
2736 int bytes_returned = 0;
2737 int len_of_str;
2738 __u16 params, param_offset, offset, count, byte_count;
2739
Joe Perchesf96637b2013-05-04 22:12:25 -05002740 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2742 (void **) &pSMBr);
2743 if (rc)
2744 return rc;
2745
2746 params = 6;
2747 pSMB->MaxSetupCount = 0;
2748 pSMB->Reserved = 0;
2749 pSMB->Flags = 0;
2750 pSMB->Timeout = 0;
2751 pSMB->Reserved2 = 0;
2752 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2753 offset = param_offset + params;
2754
2755 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2756 rename_info = (struct set_file_rename *) data_offset;
2757 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002758 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 pSMB->SetupCount = 1;
2760 pSMB->Reserved3 = 0;
2761 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2762 byte_count = 3 /* pad */ + params;
2763 pSMB->ParameterCount = cpu_to_le16(params);
2764 pSMB->TotalParameterCount = pSMB->ParameterCount;
2765 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2766 pSMB->DataOffset = cpu_to_le16(offset);
2767 /* construct random name ".cifs_tmp<inodenum><mid>" */
2768 rename_info->overwrite = cpu_to_le32(1);
2769 rename_info->root_fid = 0;
2770 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002771 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002772 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002773 len_of_str =
2774 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002775 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002777 len_of_str =
2778 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002779 target_name, PATH_MAX, nls_codepage,
2780 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 }
2782 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002783 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 byte_count += count;
2785 pSMB->DataCount = cpu_to_le16(count);
2786 pSMB->TotalDataCount = pSMB->DataCount;
2787 pSMB->Fid = netfid;
2788 pSMB->InformationLevel =
2789 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2790 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002791 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 pSMB->ByteCount = cpu_to_le16(byte_count);
2793 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002794 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002795 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002796 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002797 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2798 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002799
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 cifs_buf_release(pSMB);
2801
2802 /* Note: On -EAGAIN error only caller can retry on handle based calls
2803 since file handle passed in no longer valid */
2804
2805 return rc;
2806}
2807
2808int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002809CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2810 const char *fromName, const __u16 target_tid, const char *toName,
2811 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812{
2813 int rc = 0;
2814 COPY_REQ *pSMB = NULL;
2815 COPY_RSP *pSMBr = NULL;
2816 int bytes_returned;
2817 int name_len, name_len2;
2818 __u16 count;
2819
Joe Perchesf96637b2013-05-04 22:12:25 -05002820 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821copyRetry:
2822 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2823 (void **) &pSMBr);
2824 if (rc)
2825 return rc;
2826
2827 pSMB->BufferFormat = 0x04;
2828 pSMB->Tid2 = target_tid;
2829
2830 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2831
2832 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002833 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2834 fromName, PATH_MAX, nls_codepage,
2835 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836 name_len++; /* trailing null */
2837 name_len *= 2;
2838 pSMB->OldFileName[name_len] = 0x04; /* pad */
2839 /* protocol requires ASCII signature byte on Unicode string */
2840 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002841 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002842 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2843 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2845 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002846 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 name_len = strnlen(fromName, PATH_MAX);
2848 name_len++; /* trailing null */
2849 strncpy(pSMB->OldFileName, fromName, name_len);
2850 name_len2 = strnlen(toName, PATH_MAX);
2851 name_len2++; /* trailing null */
2852 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2853 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2854 name_len2++; /* trailing null */
2855 name_len2++; /* signature byte */
2856 }
2857
2858 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002859 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 pSMB->ByteCount = cpu_to_le16(count);
2861
2862 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2863 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2864 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002865 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2866 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 }
Steve French0d817bc2008-05-22 02:02:03 +00002868 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869
2870 if (rc == -EAGAIN)
2871 goto copyRetry;
2872
2873 return rc;
2874}
2875
2876int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002877CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 const char *fromName, const char *toName,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002879 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880{
2881 TRANSACTION2_SPI_REQ *pSMB = NULL;
2882 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2883 char *data_offset;
2884 int name_len;
2885 int name_len_target;
2886 int rc = 0;
2887 int bytes_returned = 0;
2888 __u16 params, param_offset, offset, byte_count;
2889
Joe Perchesf96637b2013-05-04 22:12:25 -05002890 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891createSymLinkRetry:
2892 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2893 (void **) &pSMBr);
2894 if (rc)
2895 return rc;
2896
2897 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2898 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002899 cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
2900 /* find define for this maxpathcomponent */
2901 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 name_len++; /* trailing null */
2903 name_len *= 2;
2904
Steve French50c2f752007-07-13 00:33:32 +00002905 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 name_len = strnlen(fromName, PATH_MAX);
2907 name_len++; /* trailing null */
2908 strncpy(pSMB->FileName, fromName, name_len);
2909 }
2910 params = 6 + name_len;
2911 pSMB->MaxSetupCount = 0;
2912 pSMB->Reserved = 0;
2913 pSMB->Flags = 0;
2914 pSMB->Timeout = 0;
2915 pSMB->Reserved2 = 0;
2916 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002917 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918 offset = param_offset + params;
2919
2920 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2921 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2922 name_len_target =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002923 cifsConvertToUTF16((__le16 *) data_offset, toName,
2924 /* find define for this maxpathcomponent */
2925 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 name_len_target++; /* trailing null */
2927 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002928 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 name_len_target = strnlen(toName, PATH_MAX);
2930 name_len_target++; /* trailing null */
2931 strncpy(data_offset, toName, name_len_target);
2932 }
2933
2934 pSMB->MaxParameterCount = cpu_to_le16(2);
2935 /* BB find exact max on data count below from sess */
2936 pSMB->MaxDataCount = cpu_to_le16(1000);
2937 pSMB->SetupCount = 1;
2938 pSMB->Reserved3 = 0;
2939 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2940 byte_count = 3 /* pad */ + params + name_len_target;
2941 pSMB->DataCount = cpu_to_le16(name_len_target);
2942 pSMB->ParameterCount = cpu_to_le16(params);
2943 pSMB->TotalDataCount = pSMB->DataCount;
2944 pSMB->TotalParameterCount = pSMB->ParameterCount;
2945 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2946 pSMB->DataOffset = cpu_to_le16(offset);
2947 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2948 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002949 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 pSMB->ByteCount = cpu_to_le16(byte_count);
2951 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2952 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002953 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002954 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002955 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2956 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957
Steve French0d817bc2008-05-22 02:02:03 +00002958 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959
2960 if (rc == -EAGAIN)
2961 goto createSymLinkRetry;
2962
2963 return rc;
2964}
2965
2966int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002967CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002969 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970{
2971 TRANSACTION2_SPI_REQ *pSMB = NULL;
2972 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2973 char *data_offset;
2974 int name_len;
2975 int name_len_target;
2976 int rc = 0;
2977 int bytes_returned = 0;
2978 __u16 params, param_offset, offset, byte_count;
2979
Joe Perchesf96637b2013-05-04 22:12:25 -05002980 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981createHardLinkRetry:
2982 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2983 (void **) &pSMBr);
2984 if (rc)
2985 return rc;
2986
2987 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002988 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2989 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 name_len++; /* trailing null */
2991 name_len *= 2;
2992
Steve French50c2f752007-07-13 00:33:32 +00002993 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 name_len = strnlen(toName, PATH_MAX);
2995 name_len++; /* trailing null */
2996 strncpy(pSMB->FileName, toName, name_len);
2997 }
2998 params = 6 + name_len;
2999 pSMB->MaxSetupCount = 0;
3000 pSMB->Reserved = 0;
3001 pSMB->Flags = 0;
3002 pSMB->Timeout = 0;
3003 pSMB->Reserved2 = 0;
3004 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003005 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 offset = param_offset + params;
3007
3008 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3009 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3010 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06003011 cifsConvertToUTF16((__le16 *) data_offset, fromName,
3012 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 name_len_target++; /* trailing null */
3014 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003015 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016 name_len_target = strnlen(fromName, PATH_MAX);
3017 name_len_target++; /* trailing null */
3018 strncpy(data_offset, fromName, name_len_target);
3019 }
3020
3021 pSMB->MaxParameterCount = cpu_to_le16(2);
3022 /* BB find exact max on data count below from sess*/
3023 pSMB->MaxDataCount = cpu_to_le16(1000);
3024 pSMB->SetupCount = 1;
3025 pSMB->Reserved3 = 0;
3026 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3027 byte_count = 3 /* pad */ + params + name_len_target;
3028 pSMB->ParameterCount = cpu_to_le16(params);
3029 pSMB->TotalParameterCount = pSMB->ParameterCount;
3030 pSMB->DataCount = cpu_to_le16(name_len_target);
3031 pSMB->TotalDataCount = pSMB->DataCount;
3032 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3033 pSMB->DataOffset = cpu_to_le16(offset);
3034 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
3035 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003036 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 pSMB->ByteCount = cpu_to_le16(byte_count);
3038 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3039 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003040 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003041 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003042 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
3043 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044
3045 cifs_buf_release(pSMB);
3046 if (rc == -EAGAIN)
3047 goto createHardLinkRetry;
3048
3049 return rc;
3050}
3051
3052int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003053CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07003054 const char *from_name, const char *to_name,
3055 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056{
3057 int rc = 0;
3058 NT_RENAME_REQ *pSMB = NULL;
3059 RENAME_RSP *pSMBr = NULL;
3060 int bytes_returned;
3061 int name_len, name_len2;
3062 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05003063 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064
Joe Perchesf96637b2013-05-04 22:12:25 -05003065 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066winCreateHardLinkRetry:
3067
3068 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
3069 (void **) &pSMBr);
3070 if (rc)
3071 return rc;
3072
3073 pSMB->SearchAttributes =
3074 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3075 ATTR_DIRECTORY);
3076 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3077 pSMB->ClusterCount = 0;
3078
3079 pSMB->BufferFormat = 0x04;
3080
3081 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3082 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07003083 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
3084 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 name_len++; /* trailing null */
3086 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05003087
3088 /* protocol specifies ASCII buffer format (0x04) for unicode */
3089 pSMB->OldFileName[name_len] = 0x04;
3090 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06003092 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07003093 to_name, PATH_MAX, cifs_sb->local_nls,
3094 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3096 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00003097 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003098 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003100 strncpy(pSMB->OldFileName, from_name, name_len);
3101 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 name_len2++; /* trailing null */
3103 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003104 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 name_len2++; /* trailing null */
3106 name_len2++; /* signature byte */
3107 }
3108
3109 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003110 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 pSMB->ByteCount = cpu_to_le16(count);
3112
3113 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3114 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003115 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003116 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003117 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003118
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119 cifs_buf_release(pSMB);
3120 if (rc == -EAGAIN)
3121 goto winCreateHardLinkRetry;
3122
3123 return rc;
3124}
3125
3126int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003127CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003128 const unsigned char *searchName, char **symlinkinfo,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003129 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130{
3131/* SMB_QUERY_FILE_UNIX_LINK */
3132 TRANSACTION2_QPI_REQ *pSMB = NULL;
3133 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3134 int rc = 0;
3135 int bytes_returned;
3136 int name_len;
3137 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003138 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139
Joe Perchesf96637b2013-05-04 22:12:25 -05003140 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141
3142querySymLinkRetry:
3143 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3144 (void **) &pSMBr);
3145 if (rc)
3146 return rc;
3147
3148 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3149 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003150 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3151 searchName, PATH_MAX, nls_codepage,
3152 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 name_len++; /* trailing null */
3154 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003155 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 name_len = strnlen(searchName, PATH_MAX);
3157 name_len++; /* trailing null */
3158 strncpy(pSMB->FileName, searchName, name_len);
3159 }
3160
3161 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3162 pSMB->TotalDataCount = 0;
3163 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003164 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 pSMB->MaxSetupCount = 0;
3166 pSMB->Reserved = 0;
3167 pSMB->Flags = 0;
3168 pSMB->Timeout = 0;
3169 pSMB->Reserved2 = 0;
3170 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003171 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 pSMB->DataCount = 0;
3173 pSMB->DataOffset = 0;
3174 pSMB->SetupCount = 1;
3175 pSMB->Reserved3 = 0;
3176 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3177 byte_count = params + 1 /* pad */ ;
3178 pSMB->TotalParameterCount = cpu_to_le16(params);
3179 pSMB->ParameterCount = pSMB->TotalParameterCount;
3180 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3181 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003182 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183 pSMB->ByteCount = cpu_to_le16(byte_count);
3184
3185 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3186 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3187 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003188 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189 } else {
3190 /* decode response */
3191
3192 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003194 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003195 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003197 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003198 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199
Jeff Layton460b9692009-04-30 07:17:56 -04003200 data_start = ((char *) &pSMBr->hdr.Protocol) +
3201 le16_to_cpu(pSMBr->t2.DataOffset);
3202
Steve French0e0d2cf2009-05-01 05:27:32 +00003203 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3204 is_unicode = true;
3205 else
3206 is_unicode = false;
3207
Steve French737b7582005-04-28 22:41:06 -07003208 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003209 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3210 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003211 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003212 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 }
3214 }
3215 cifs_buf_release(pSMB);
3216 if (rc == -EAGAIN)
3217 goto querySymLinkRetry;
3218 return rc;
3219}
3220
Steve Frenchc52a95542011-02-24 06:16:22 +00003221/*
3222 * Recent Windows versions now create symlinks more frequently
3223 * and they use the "reparse point" mechanism below. We can of course
3224 * do symlinks nicely to Samba and other servers which support the
3225 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3226 * "MF" symlinks optionally, but for recent Windows we really need to
3227 * reenable the code below and fix the cifs_symlink callers to handle this.
3228 * In the interim this code has been moved to its own config option so
3229 * it is not compiled in by default until callers fixed up and more tested.
3230 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003232CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3233 __u16 fid, char **symlinkinfo,
3234 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235{
3236 int rc = 0;
3237 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003238 struct smb_com_transaction_ioctl_req *pSMB;
3239 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003240 bool is_unicode;
3241 unsigned int sub_len;
3242 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003243 struct reparse_symlink_data *reparse_buf;
3244 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003245 __u32 data_offset, data_count;
3246 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003248 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3250 (void **) &pSMBr);
3251 if (rc)
3252 return rc;
3253
3254 pSMB->TotalParameterCount = 0 ;
3255 pSMB->TotalDataCount = 0;
3256 pSMB->MaxParameterCount = cpu_to_le32(2);
3257 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003258 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003259 pSMB->MaxSetupCount = 4;
3260 pSMB->Reserved = 0;
3261 pSMB->ParameterOffset = 0;
3262 pSMB->DataCount = 0;
3263 pSMB->DataOffset = 0;
3264 pSMB->SetupCount = 4;
3265 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3266 pSMB->ParameterCount = pSMB->TotalParameterCount;
3267 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3268 pSMB->IsFsctl = 1; /* FSCTL */
3269 pSMB->IsRootFlag = 0;
3270 pSMB->Fid = fid; /* file handle always le */
3271 pSMB->ByteCount = 0;
3272
3273 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3274 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3275 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003276 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003277 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003278 }
Steve French989c7e52009-05-02 05:32:20 +00003279
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003280 data_offset = le32_to_cpu(pSMBr->DataOffset);
3281 data_count = le32_to_cpu(pSMBr->DataCount);
3282 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3283 /* BB also check enough total bytes returned */
3284 rc = -EIO; /* bad smb */
3285 goto qreparse_out;
3286 }
3287 if (!data_count || (data_count > 2048)) {
3288 rc = -EIO;
3289 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3290 goto qreparse_out;
3291 }
3292 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003293 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003294 ((char *)&pSMBr->hdr.Protocol + data_offset);
3295 if ((char *)reparse_buf >= end_of_smb) {
3296 rc = -EIO;
3297 goto qreparse_out;
3298 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003299 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3300 cifs_dbg(FYI, "NFS style reparse tag\n");
3301 posix_buf = (struct reparse_posix_data *)reparse_buf;
3302
3303 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3304 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3305 le64_to_cpu(posix_buf->InodeType));
3306 rc = -EOPNOTSUPP;
3307 goto qreparse_out;
3308 }
3309 is_unicode = true;
3310 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3311 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3312 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3313 rc = -EIO;
3314 goto qreparse_out;
3315 }
3316 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3317 sub_len, is_unicode, nls_codepage);
3318 goto qreparse_out;
3319 } else if (reparse_buf->ReparseTag !=
3320 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3321 rc = -EOPNOTSUPP;
3322 goto qreparse_out;
3323 }
3324
3325 /* Reparse tag is NTFS symlink */
3326 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3327 reparse_buf->PathBuffer;
3328 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3329 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003330 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3331 rc = -EIO;
3332 goto qreparse_out;
3333 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003334 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3335 is_unicode = true;
3336 else
3337 is_unicode = false;
3338
3339 /* BB FIXME investigate remapping reserved chars here */
3340 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3341 nls_codepage);
3342 if (!*symlinkinfo)
3343 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003345 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003347 /*
3348 * Note: On -EAGAIN error only caller can retry on handle based calls
3349 * since file handle passed in no longer valid.
3350 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 return rc;
3352}
3353
Steve Frenchc7f508a2013-10-14 15:27:32 -05003354int
3355CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3356 __u16 fid)
3357{
3358 int rc = 0;
3359 int bytes_returned;
3360 struct smb_com_transaction_compr_ioctl_req *pSMB;
3361 struct smb_com_transaction_ioctl_rsp *pSMBr;
3362
3363 cifs_dbg(FYI, "Set compression for %u\n", fid);
3364 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3365 (void **) &pSMBr);
3366 if (rc)
3367 return rc;
3368
3369 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3370
3371 pSMB->TotalParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003372 pSMB->TotalDataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003373 pSMB->MaxParameterCount = 0;
3374 pSMB->MaxDataCount = 0;
3375 pSMB->MaxSetupCount = 4;
3376 pSMB->Reserved = 0;
3377 pSMB->ParameterOffset = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003378 pSMB->DataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003379 pSMB->DataOffset =
3380 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3381 compression_state) - 4); /* 84 */
3382 pSMB->SetupCount = 4;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003383 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003384 pSMB->ParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003385 pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003386 pSMB->IsFsctl = 1; /* FSCTL */
3387 pSMB->IsRootFlag = 0;
3388 pSMB->Fid = fid; /* file handle always le */
3389 /* 3 byte pad, followed by 2 byte compress state */
Fabian Frederickbc09d142014-12-10 15:41:15 -08003390 pSMB->ByteCount = cpu_to_le16(5);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003391 inc_rfc1001_len(pSMB, 5);
3392
3393 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3394 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3395 if (rc)
3396 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3397
3398 cifs_buf_release(pSMB);
3399
3400 /*
3401 * Note: On -EAGAIN error only caller can retry on handle based calls
3402 * since file handle passed in no longer valid.
3403 */
3404 return rc;
3405}
3406
3407
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408#ifdef CONFIG_CIFS_POSIX
3409
3410/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003411static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
Steve French50c2f752007-07-13 00:33:32 +00003412 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413{
3414 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003415 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3416 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3417 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003418/*
3419 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3420 ace->e_perm, ace->e_tag, ace->e_id);
3421*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422
3423 return;
3424}
3425
3426/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003427static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3428 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429{
3430 int size = 0;
3431 int i;
3432 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003433 struct cifs_posix_ace *pACE;
3434 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003435 struct posix_acl_xattr_header *local_acl = (void *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436
3437 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3438 return -EOPNOTSUPP;
3439
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003440 if (acl_type == ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441 count = le16_to_cpu(cifs_acl->access_entry_count);
3442 pACE = &cifs_acl->ace_array[0];
3443 size = sizeof(struct cifs_posix_acl);
3444 size += sizeof(struct cifs_posix_ace) * count;
3445 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003446 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003447 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3448 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449 return -EINVAL;
3450 }
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003451 } else if (acl_type == ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452 count = le16_to_cpu(cifs_acl->access_entry_count);
3453 size = sizeof(struct cifs_posix_acl);
3454 size += sizeof(struct cifs_posix_ace) * count;
3455/* skip past access ACEs to get to default ACEs */
3456 pACE = &cifs_acl->ace_array[count];
3457 count = le16_to_cpu(cifs_acl->default_entry_count);
3458 size += sizeof(struct cifs_posix_ace) * count;
3459 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003460 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461 return -EINVAL;
3462 } else {
3463 /* illegal type */
3464 return -EINVAL;
3465 }
3466
3467 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003468 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003469 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003470 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 return -ERANGE;
3472 } else /* buffer big enough */ {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003473 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
3474
Steve Frenchff7feac2005-11-15 16:45:16 -08003475 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003476 for (i = 0; i < count ; i++) {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003477 cifs_convert_ace(&ace[i], pACE);
Steve French50c2f752007-07-13 00:33:32 +00003478 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479 }
3480 }
3481 return size;
3482}
3483
Steve French50c2f752007-07-13 00:33:32 +00003484static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003485 const struct posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486{
3487 __u16 rc = 0; /* 0 = ACL converted ok */
3488
Steve Frenchff7feac2005-11-15 16:45:16 -08003489 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3490 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003492 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493 /* Probably no need to le convert -1 on any arch but can not hurt */
3494 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003495 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003496 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003497/*
3498 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3499 ace->e_perm, ace->e_tag, ace->e_id);
3500*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501 return rc;
3502}
3503
3504/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003505static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3506 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507{
3508 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003509 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003510 struct posix_acl_xattr_header *local_acl = (void *)pACL;
Eryu Guanae9ebe72016-10-24 20:46:40 +08003511 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512 int count;
3513 int i;
3514
Steve French790fe572007-07-07 19:25:05 +00003515 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 return 0;
3517
3518 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003519 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3520 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003521 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003522 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3523 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524 return 0;
3525 }
3526 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003527 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003528 cifs_acl->access_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003529 cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003530 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003531 cifs_acl->default_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003532 cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003533 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003534 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 return 0;
3536 }
Steve French50c2f752007-07-13 00:33:32 +00003537 for (i = 0; i < count; i++) {
Eryu Guanae9ebe72016-10-24 20:46:40 +08003538 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
Steve French790fe572007-07-07 19:25:05 +00003539 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540 /* ACE not converted */
3541 break;
3542 }
3543 }
Steve French790fe572007-07-07 19:25:05 +00003544 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3546 rc += sizeof(struct cifs_posix_acl);
3547 /* BB add check to make sure ACL does not overflow SMB */
3548 }
3549 return rc;
3550}
3551
3552int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003553CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003554 const unsigned char *searchName,
3555 char *acl_inf, const int buflen, const int acl_type,
3556 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557{
3558/* SMB_QUERY_POSIX_ACL */
3559 TRANSACTION2_QPI_REQ *pSMB = NULL;
3560 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3561 int rc = 0;
3562 int bytes_returned;
3563 int name_len;
3564 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003565
Joe Perchesf96637b2013-05-04 22:12:25 -05003566 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567
3568queryAclRetry:
3569 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3570 (void **) &pSMBr);
3571 if (rc)
3572 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003573
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3575 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003576 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3577 searchName, PATH_MAX, nls_codepage,
3578 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 name_len++; /* trailing null */
3580 name_len *= 2;
3581 pSMB->FileName[name_len] = 0;
3582 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003583 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584 name_len = strnlen(searchName, PATH_MAX);
3585 name_len++; /* trailing null */
3586 strncpy(pSMB->FileName, searchName, name_len);
3587 }
3588
3589 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3590 pSMB->TotalDataCount = 0;
3591 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003592 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593 pSMB->MaxDataCount = cpu_to_le16(4000);
3594 pSMB->MaxSetupCount = 0;
3595 pSMB->Reserved = 0;
3596 pSMB->Flags = 0;
3597 pSMB->Timeout = 0;
3598 pSMB->Reserved2 = 0;
3599 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003600 offsetof(struct smb_com_transaction2_qpi_req,
3601 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 pSMB->DataCount = 0;
3603 pSMB->DataOffset = 0;
3604 pSMB->SetupCount = 1;
3605 pSMB->Reserved3 = 0;
3606 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3607 byte_count = params + 1 /* pad */ ;
3608 pSMB->TotalParameterCount = cpu_to_le16(params);
3609 pSMB->ParameterCount = pSMB->TotalParameterCount;
3610 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3611 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003612 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 pSMB->ByteCount = cpu_to_le16(byte_count);
3614
3615 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3616 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003617 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003619 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 } else {
3621 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003622
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003625 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 rc = -EIO; /* bad smb */
3627 else {
3628 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3629 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3630 rc = cifs_copy_posix_acl(acl_inf,
3631 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003632 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633 }
3634 }
3635 cifs_buf_release(pSMB);
3636 if (rc == -EAGAIN)
3637 goto queryAclRetry;
3638 return rc;
3639}
3640
3641int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003642CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003643 const unsigned char *fileName,
3644 const char *local_acl, const int buflen,
3645 const int acl_type,
3646 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647{
3648 struct smb_com_transaction2_spi_req *pSMB = NULL;
3649 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3650 char *parm_data;
3651 int name_len;
3652 int rc = 0;
3653 int bytes_returned = 0;
3654 __u16 params, byte_count, data_count, param_offset, offset;
3655
Joe Perchesf96637b2013-05-04 22:12:25 -05003656 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657setAclRetry:
3658 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003659 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660 if (rc)
3661 return rc;
3662 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3663 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003664 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3665 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666 name_len++; /* trailing null */
3667 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003668 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 name_len = strnlen(fileName, PATH_MAX);
3670 name_len++; /* trailing null */
3671 strncpy(pSMB->FileName, fileName, name_len);
3672 }
3673 params = 6 + name_len;
3674 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003675 /* BB find max SMB size from sess */
3676 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 pSMB->MaxSetupCount = 0;
3678 pSMB->Reserved = 0;
3679 pSMB->Flags = 0;
3680 pSMB->Timeout = 0;
3681 pSMB->Reserved2 = 0;
3682 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003683 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684 offset = param_offset + params;
3685 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3686 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3687
3688 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003689 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690
Steve French790fe572007-07-07 19:25:05 +00003691 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 rc = -EOPNOTSUPP;
3693 goto setACLerrorExit;
3694 }
3695 pSMB->DataOffset = cpu_to_le16(offset);
3696 pSMB->SetupCount = 1;
3697 pSMB->Reserved3 = 0;
3698 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3699 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3700 byte_count = 3 /* pad */ + params + data_count;
3701 pSMB->DataCount = cpu_to_le16(data_count);
3702 pSMB->TotalDataCount = pSMB->DataCount;
3703 pSMB->ParameterCount = cpu_to_le16(params);
3704 pSMB->TotalParameterCount = pSMB->ParameterCount;
3705 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003706 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707 pSMB->ByteCount = cpu_to_le16(byte_count);
3708 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003709 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003710 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003711 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712
3713setACLerrorExit:
3714 cifs_buf_release(pSMB);
3715 if (rc == -EAGAIN)
3716 goto setAclRetry;
3717 return rc;
3718}
3719
Steve Frenchf654bac2005-04-28 22:41:04 -07003720/* BB fix tabs in this function FIXME BB */
3721int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003722CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003723 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003724{
Steve French50c2f752007-07-13 00:33:32 +00003725 int rc = 0;
3726 struct smb_t2_qfi_req *pSMB = NULL;
3727 struct smb_t2_qfi_rsp *pSMBr = NULL;
3728 int bytes_returned;
3729 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003730
Joe Perchesf96637b2013-05-04 22:12:25 -05003731 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003732 if (tcon == NULL)
3733 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003734
3735GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003736 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3737 (void **) &pSMBr);
3738 if (rc)
3739 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003740
Steve Frenchad7a2922008-02-07 23:25:02 +00003741 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003742 pSMB->t2.TotalDataCount = 0;
3743 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3744 /* BB find exact max data count below from sess structure BB */
3745 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3746 pSMB->t2.MaxSetupCount = 0;
3747 pSMB->t2.Reserved = 0;
3748 pSMB->t2.Flags = 0;
3749 pSMB->t2.Timeout = 0;
3750 pSMB->t2.Reserved2 = 0;
3751 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3752 Fid) - 4);
3753 pSMB->t2.DataCount = 0;
3754 pSMB->t2.DataOffset = 0;
3755 pSMB->t2.SetupCount = 1;
3756 pSMB->t2.Reserved3 = 0;
3757 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3758 byte_count = params + 1 /* pad */ ;
3759 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3760 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3761 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3762 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003763 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003764 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003765 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003766
Steve French790fe572007-07-07 19:25:05 +00003767 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3768 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3769 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003770 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003771 } else {
3772 /* decode response */
3773 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003774 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003775 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003776 /* If rc should we check for EOPNOSUPP and
3777 disable the srvino flag? or in caller? */
3778 rc = -EIO; /* bad smb */
3779 else {
3780 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3781 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3782 struct file_chattr_info *pfinfo;
3783 /* BB Do we need a cast or hash here ? */
3784 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003785 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003786 rc = -EIO;
3787 goto GetExtAttrOut;
3788 }
3789 pfinfo = (struct file_chattr_info *)
3790 (data_offset + (char *) &pSMBr->hdr.Protocol);
3791 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003792 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003793 }
3794 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003795GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003796 cifs_buf_release(pSMB);
3797 if (rc == -EAGAIN)
3798 goto GetExtAttrRetry;
3799 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003800}
3801
Steve Frenchf654bac2005-04-28 22:41:04 -07003802#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803
Jeff Layton79df1ba2010-12-06 12:52:08 -05003804#ifdef CONFIG_CIFS_ACL
3805/*
3806 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3807 * all NT TRANSACTS that we init here have total parm and data under about 400
3808 * bytes (to fit in small cifs buffer size), which is the case so far, it
3809 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3810 * returned setup area) and MaxParameterCount (returned parms size) must be set
3811 * by caller
3812 */
3813static int
3814smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003815 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003816 void **ret_buf)
3817{
3818 int rc;
3819 __u32 temp_offset;
3820 struct smb_com_ntransact_req *pSMB;
3821
3822 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3823 (void **)&pSMB);
3824 if (rc)
3825 return rc;
3826 *ret_buf = (void *)pSMB;
3827 pSMB->Reserved = 0;
3828 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3829 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003830 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003831 pSMB->ParameterCount = pSMB->TotalParameterCount;
3832 pSMB->DataCount = pSMB->TotalDataCount;
3833 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3834 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3835 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3836 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3837 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3838 pSMB->SubCommand = cpu_to_le16(sub_command);
3839 return 0;
3840}
3841
3842static int
3843validate_ntransact(char *buf, char **ppparm, char **ppdata,
3844 __u32 *pparmlen, __u32 *pdatalen)
3845{
3846 char *end_of_smb;
3847 __u32 data_count, data_offset, parm_count, parm_offset;
3848 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003849 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003850
3851 *pdatalen = 0;
3852 *pparmlen = 0;
3853
3854 if (buf == NULL)
3855 return -EINVAL;
3856
3857 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3858
Jeff Layton820a8032011-05-04 08:05:26 -04003859 bcc = get_bcc(&pSMBr->hdr);
3860 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003861 (char *)&pSMBr->ByteCount;
3862
3863 data_offset = le32_to_cpu(pSMBr->DataOffset);
3864 data_count = le32_to_cpu(pSMBr->DataCount);
3865 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3866 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3867
3868 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3869 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3870
3871 /* should we also check that parm and data areas do not overlap? */
3872 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003873 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003874 return -EINVAL;
3875 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003876 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003877 return -EINVAL;
3878 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003879 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003880 return -EINVAL;
3881 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003882 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3883 *ppdata, data_count, (data_count + *ppdata),
3884 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003885 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003886 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003887 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003888 return -EINVAL;
3889 }
3890 *pdatalen = data_count;
3891 *pparmlen = parm_count;
3892 return 0;
3893}
3894
Steve French0a4b92c2006-01-12 15:44:21 -08003895/* Get Security Descriptor (by handle) from remote server for a file or dir */
3896int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003897CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003898 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003899{
3900 int rc = 0;
3901 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003902 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003903 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003904 struct kvec rsp_iov;
Steve French0a4b92c2006-01-12 15:44:21 -08003905
Joe Perchesf96637b2013-05-04 22:12:25 -05003906 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003907
Steve French630f3f0c2007-10-25 21:17:17 +00003908 *pbuflen = 0;
3909 *acl_inf = NULL;
3910
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003911 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003912 8 /* parm len */, tcon, (void **) &pSMB);
3913 if (rc)
3914 return rc;
3915
3916 pSMB->MaxParameterCount = cpu_to_le32(4);
3917 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3918 pSMB->MaxSetupCount = 0;
3919 pSMB->Fid = fid; /* file handle always le */
3920 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3921 CIFS_ACL_DACL);
3922 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003923 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003924 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003925 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003926
Steve Frencha761ac52007-10-18 21:45:27 +00003927 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003928 0, &rsp_iov);
3929 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003930 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003931 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003932 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003933 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003934 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003935 __u32 parm_len;
3936 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003937 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003938 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003939
3940/* validate_nttransact */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003941 rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003942 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003943 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003944 goto qsec_out;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003945 pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
Steve French0a4b92c2006-01-12 15:44:21 -08003946
Joe Perchesf96637b2013-05-04 22:12:25 -05003947 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3948 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003949
3950 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3951 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003952 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003953 goto qsec_out;
3954 }
3955
3956/* BB check that data area is minimum length and as big as acl_len */
3957
Steve Frenchaf6f4612007-10-16 18:40:37 +00003958 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003959 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003960 cifs_dbg(VFS, "acl length %d does not match %d\n",
3961 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003962 if (*pbuflen > acl_len)
3963 *pbuflen = acl_len;
3964 }
Steve French0a4b92c2006-01-12 15:44:21 -08003965
Steve French630f3f0c2007-10-25 21:17:17 +00003966 /* check if buffer is big enough for the acl
3967 header followed by the smallest SID */
3968 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3969 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003970 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003971 rc = -EINVAL;
3972 *pbuflen = 0;
3973 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003974 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003975 if (*acl_inf == NULL) {
3976 *pbuflen = 0;
3977 rc = -ENOMEM;
3978 }
Steve French630f3f0c2007-10-25 21:17:17 +00003979 }
Steve French0a4b92c2006-01-12 15:44:21 -08003980 }
3981qsec_out:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003982 free_rsp_buf(buf_type, rsp_iov.iov_base);
Steve French0a4b92c2006-01-12 15:44:21 -08003983 return rc;
3984}
Steve French97837582007-12-31 07:47:21 +00003985
3986int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003987CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003988 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003989{
3990 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3991 int rc = 0;
3992 int bytes_returned = 0;
3993 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003994 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003995
3996setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003997 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003998 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003999 return rc;
Steve French97837582007-12-31 07:47:21 +00004000
4001 pSMB->MaxSetupCount = 0;
4002 pSMB->Reserved = 0;
4003
4004 param_count = 8;
4005 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
4006 data_count = acllen;
4007 data_offset = param_offset + param_count;
4008 byte_count = 3 /* pad */ + param_count;
4009
4010 pSMB->DataCount = cpu_to_le32(data_count);
4011 pSMB->TotalDataCount = pSMB->DataCount;
4012 pSMB->MaxParameterCount = cpu_to_le32(4);
4013 pSMB->MaxDataCount = cpu_to_le32(16384);
4014 pSMB->ParameterCount = cpu_to_le32(param_count);
4015 pSMB->ParameterOffset = cpu_to_le32(param_offset);
4016 pSMB->TotalParameterCount = pSMB->ParameterCount;
4017 pSMB->DataOffset = cpu_to_le32(data_offset);
4018 pSMB->SetupCount = 0;
4019 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
4020 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
4021
4022 pSMB->Fid = fid; /* file handle always le */
4023 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05004024 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00004025
4026 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04004027 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
4028 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004029 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00004030 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004031 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00004032
4033 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4034 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4035
Joe Perchesf96637b2013-05-04 22:12:25 -05004036 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
4037 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00004038 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004039 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00004040 cifs_buf_release(pSMB);
4041
4042 if (rc == -EAGAIN)
4043 goto setCifsAclRetry;
4044
4045 return (rc);
4046}
4047
Jeff Layton79df1ba2010-12-06 12:52:08 -05004048#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08004049
Steve French6b8edfe2005-08-23 20:26:03 -07004050/* Legacy Query Path Information call for lookup to old servers such
4051 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004052int
4053SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
4054 const char *search_name, FILE_ALL_INFO *data,
4055 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07004056{
Steve Frenchad7a2922008-02-07 23:25:02 +00004057 QUERY_INFORMATION_REQ *pSMB;
4058 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07004059 int rc = 0;
4060 int bytes_returned;
4061 int name_len;
4062
Joe Perchesf96637b2013-05-04 22:12:25 -05004063 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004064QInfRetry:
4065 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004066 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07004067 if (rc)
4068 return rc;
4069
4070 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4071 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004072 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004073 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004074 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07004075 name_len++; /* trailing null */
4076 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004077 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004078 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07004079 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004080 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004081 }
4082 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00004083 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004084 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004085 pSMB->ByteCount = cpu_to_le16(name_len);
4086
4087 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004088 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07004089 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004090 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004091 } else if (data) {
Arnd Bergmann95390202018-06-19 17:27:58 +02004092 struct timespec64 ts;
Steve French1bd5bbc2006-09-28 03:35:57 +00004093 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00004094
4095 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00004096 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004097 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00004098 ts.tv_nsec = 0;
4099 ts.tv_sec = time;
4100 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004101 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
4102 data->LastWriteTime = data->ChangeTime;
4103 data->LastAccessTime = 0;
4104 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07004105 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004106 data->EndOfFile = data->AllocationSize;
4107 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07004108 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07004109 } else
4110 rc = -EIO; /* bad buffer passed in */
4111
4112 cifs_buf_release(pSMB);
4113
4114 if (rc == -EAGAIN)
4115 goto QInfRetry;
4116
4117 return rc;
4118}
4119
Jeff Laytonbcd53572010-02-12 07:44:16 -05004120int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004121CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004122 u16 netfid, FILE_ALL_INFO *pFindData)
4123{
4124 struct smb_t2_qfi_req *pSMB = NULL;
4125 struct smb_t2_qfi_rsp *pSMBr = NULL;
4126 int rc = 0;
4127 int bytes_returned;
4128 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004129
Jeff Laytonbcd53572010-02-12 07:44:16 -05004130QFileInfoRetry:
4131 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4132 (void **) &pSMBr);
4133 if (rc)
4134 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004135
Jeff Laytonbcd53572010-02-12 07:44:16 -05004136 params = 2 /* level */ + 2 /* fid */;
4137 pSMB->t2.TotalDataCount = 0;
4138 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4139 /* BB find exact max data count below from sess structure BB */
4140 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4141 pSMB->t2.MaxSetupCount = 0;
4142 pSMB->t2.Reserved = 0;
4143 pSMB->t2.Flags = 0;
4144 pSMB->t2.Timeout = 0;
4145 pSMB->t2.Reserved2 = 0;
4146 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4147 Fid) - 4);
4148 pSMB->t2.DataCount = 0;
4149 pSMB->t2.DataOffset = 0;
4150 pSMB->t2.SetupCount = 1;
4151 pSMB->t2.Reserved3 = 0;
4152 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4153 byte_count = params + 1 /* pad */ ;
4154 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4155 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4156 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4157 pSMB->Pad = 0;
4158 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004159 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004160 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004161
4162 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4163 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4164 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004165 cifs_dbg(FYI, "Send error in QFileInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004166 } else { /* decode response */
4167 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4168
4169 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4170 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004171 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004172 rc = -EIO; /* bad smb */
4173 else if (pFindData) {
4174 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4175 memcpy((char *) pFindData,
4176 (char *) &pSMBr->hdr.Protocol +
4177 data_offset, sizeof(FILE_ALL_INFO));
4178 } else
4179 rc = -ENOMEM;
4180 }
4181 cifs_buf_release(pSMB);
4182 if (rc == -EAGAIN)
4183 goto QFileInfoRetry;
4184
4185 return rc;
4186}
Steve French6b8edfe2005-08-23 20:26:03 -07004187
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004189CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004190 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004191 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004192 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004194 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195 TRANSACTION2_QPI_REQ *pSMB = NULL;
4196 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4197 int rc = 0;
4198 int bytes_returned;
4199 int name_len;
4200 __u16 params, byte_count;
4201
Joe Perchesf96637b2013-05-04 22:12:25 -05004202 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203QPathInfoRetry:
4204 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4205 (void **) &pSMBr);
4206 if (rc)
4207 return rc;
4208
4209 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4210 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004211 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004212 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213 name_len++; /* trailing null */
4214 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004215 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004216 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004218 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219 }
4220
Steve French50c2f752007-07-13 00:33:32 +00004221 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222 pSMB->TotalDataCount = 0;
4223 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004224 /* BB find exact max SMB PDU from sess structure BB */
4225 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226 pSMB->MaxSetupCount = 0;
4227 pSMB->Reserved = 0;
4228 pSMB->Flags = 0;
4229 pSMB->Timeout = 0;
4230 pSMB->Reserved2 = 0;
4231 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004232 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233 pSMB->DataCount = 0;
4234 pSMB->DataOffset = 0;
4235 pSMB->SetupCount = 1;
4236 pSMB->Reserved3 = 0;
4237 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4238 byte_count = params + 1 /* pad */ ;
4239 pSMB->TotalParameterCount = cpu_to_le16(params);
4240 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004241 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004242 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4243 else
4244 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004246 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247 pSMB->ByteCount = cpu_to_le16(byte_count);
4248
4249 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4250 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4251 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004252 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253 } else { /* decode response */
4254 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4255
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004256 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4257 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004258 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004260 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004261 rc = -EIO; /* 24 or 26 expected but we do not read
4262 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004263 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004264 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004266
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004267 /*
4268 * On legacy responses we do not read the last field,
4269 * EAsize, fortunately since it varies by subdialect and
4270 * also note it differs on Set vs Get, ie two bytes or 4
4271 * bytes depending but we don't care here.
4272 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004273 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004274 size = sizeof(FILE_INFO_STANDARD);
4275 else
4276 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004277 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004278 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279 } else
4280 rc = -ENOMEM;
4281 }
4282 cifs_buf_release(pSMB);
4283 if (rc == -EAGAIN)
4284 goto QPathInfoRetry;
4285
4286 return rc;
4287}
4288
4289int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004290CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004291 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4292{
4293 struct smb_t2_qfi_req *pSMB = NULL;
4294 struct smb_t2_qfi_rsp *pSMBr = NULL;
4295 int rc = 0;
4296 int bytes_returned;
4297 __u16 params, byte_count;
4298
4299UnixQFileInfoRetry:
4300 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4301 (void **) &pSMBr);
4302 if (rc)
4303 return rc;
4304
4305 params = 2 /* level */ + 2 /* fid */;
4306 pSMB->t2.TotalDataCount = 0;
4307 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4308 /* BB find exact max data count below from sess structure BB */
4309 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4310 pSMB->t2.MaxSetupCount = 0;
4311 pSMB->t2.Reserved = 0;
4312 pSMB->t2.Flags = 0;
4313 pSMB->t2.Timeout = 0;
4314 pSMB->t2.Reserved2 = 0;
4315 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4316 Fid) - 4);
4317 pSMB->t2.DataCount = 0;
4318 pSMB->t2.DataOffset = 0;
4319 pSMB->t2.SetupCount = 1;
4320 pSMB->t2.Reserved3 = 0;
4321 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4322 byte_count = params + 1 /* pad */ ;
4323 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4324 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4325 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4326 pSMB->Pad = 0;
4327 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004328 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004329 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004330
4331 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4332 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4333 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004334 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004335 } else { /* decode response */
4336 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4337
Jeff Layton820a8032011-05-04 08:05:26 -04004338 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004339 cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004340 rc = -EIO; /* bad smb */
4341 } else {
4342 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4343 memcpy((char *) pFindData,
4344 (char *) &pSMBr->hdr.Protocol +
4345 data_offset,
4346 sizeof(FILE_UNIX_BASIC_INFO));
4347 }
4348 }
4349
4350 cifs_buf_release(pSMB);
4351 if (rc == -EAGAIN)
4352 goto UnixQFileInfoRetry;
4353
4354 return rc;
4355}
4356
4357int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004358CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004360 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004361 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362{
4363/* SMB_QUERY_FILE_UNIX_BASIC */
4364 TRANSACTION2_QPI_REQ *pSMB = NULL;
4365 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4366 int rc = 0;
4367 int bytes_returned = 0;
4368 int name_len;
4369 __u16 params, byte_count;
4370
Joe Perchesf96637b2013-05-04 22:12:25 -05004371 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372UnixQPathInfoRetry:
4373 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4374 (void **) &pSMBr);
4375 if (rc)
4376 return rc;
4377
4378 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4379 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004380 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4381 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382 name_len++; /* trailing null */
4383 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004384 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385 name_len = strnlen(searchName, PATH_MAX);
4386 name_len++; /* trailing null */
4387 strncpy(pSMB->FileName, searchName, name_len);
4388 }
4389
Steve French50c2f752007-07-13 00:33:32 +00004390 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391 pSMB->TotalDataCount = 0;
4392 pSMB->MaxParameterCount = cpu_to_le16(2);
4393 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004394 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004395 pSMB->MaxSetupCount = 0;
4396 pSMB->Reserved = 0;
4397 pSMB->Flags = 0;
4398 pSMB->Timeout = 0;
4399 pSMB->Reserved2 = 0;
4400 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004401 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402 pSMB->DataCount = 0;
4403 pSMB->DataOffset = 0;
4404 pSMB->SetupCount = 1;
4405 pSMB->Reserved3 = 0;
4406 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4407 byte_count = params + 1 /* pad */ ;
4408 pSMB->TotalParameterCount = cpu_to_le16(params);
4409 pSMB->ParameterCount = pSMB->TotalParameterCount;
4410 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4411 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004412 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413 pSMB->ByteCount = cpu_to_le16(byte_count);
4414
4415 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4416 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4417 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004418 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419 } else { /* decode response */
4420 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4421
Jeff Layton820a8032011-05-04 08:05:26 -04004422 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004423 cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions can be disabled on mount by specifying the nosfu mount option.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 rc = -EIO; /* bad smb */
4425 } else {
4426 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4427 memcpy((char *) pFindData,
4428 (char *) &pSMBr->hdr.Protocol +
4429 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004430 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004431 }
4432 }
4433 cifs_buf_release(pSMB);
4434 if (rc == -EAGAIN)
4435 goto UnixQPathInfoRetry;
4436
4437 return rc;
4438}
4439
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440/* xid, tcon, searchName and codepage are input parms, rest are returned */
4441int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004442CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004443 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004444 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004445 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446{
4447/* level 257 SMB_ */
4448 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4449 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004450 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451 int rc = 0;
4452 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004453 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004455 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456
Joe Perchesf96637b2013-05-04 22:12:25 -05004457 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458
4459findFirstRetry:
4460 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4461 (void **) &pSMBr);
4462 if (rc)
4463 return rc;
4464
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004465 nls_codepage = cifs_sb->local_nls;
Steve French2baa2682014-09-27 02:19:01 -05004466 remap = cifs_remap(cifs_sb);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004467
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4469 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004470 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4471 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004472 /* We can not add the asterik earlier in case
4473 it got remapped to 0xF03A as if it were part of the
4474 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004476 if (msearch) {
4477 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4478 pSMB->FileName[name_len+1] = 0;
4479 pSMB->FileName[name_len+2] = '*';
4480 pSMB->FileName[name_len+3] = 0;
4481 name_len += 4; /* now the trailing null */
4482 /* null terminate just in case */
4483 pSMB->FileName[name_len] = 0;
4484 pSMB->FileName[name_len+1] = 0;
4485 name_len += 2;
4486 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487 } else { /* BB add check for overrun of SMB buf BB */
4488 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004490 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491 free buffer exit; BB */
4492 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004493 if (msearch) {
4494 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4495 pSMB->FileName[name_len+1] = '*';
4496 pSMB->FileName[name_len+2] = 0;
4497 name_len += 3;
4498 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499 }
4500
4501 params = 12 + name_len /* includes null */ ;
4502 pSMB->TotalDataCount = 0; /* no EAs */
4503 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004504 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004505 pSMB->MaxSetupCount = 0;
4506 pSMB->Reserved = 0;
4507 pSMB->Flags = 0;
4508 pSMB->Timeout = 0;
4509 pSMB->Reserved2 = 0;
4510 byte_count = params + 1 /* pad */ ;
4511 pSMB->TotalParameterCount = cpu_to_le16(params);
4512 pSMB->ParameterCount = pSMB->TotalParameterCount;
4513 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004514 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4515 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004516 pSMB->DataCount = 0;
4517 pSMB->DataOffset = 0;
4518 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4519 pSMB->Reserved3 = 0;
4520 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4521 pSMB->SearchAttributes =
4522 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4523 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004524 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004525 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4527
4528 /* BB what should we set StorageType to? Does it matter? BB */
4529 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004530 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531 pSMB->ByteCount = cpu_to_le16(byte_count);
4532
4533 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4534 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004535 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536
Steve French88274812006-03-09 22:21:45 +00004537 if (rc) {/* BB add logic to retry regular search if Unix search
4538 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004540 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004541
Steve French88274812006-03-09 22:21:45 +00004542 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543
4544 /* BB eventually could optimize out free and realloc of buf */
4545 /* for this case */
4546 if (rc == -EAGAIN)
4547 goto findFirstRetry;
4548 } else { /* decode response */
4549 /* BB remember to free buffer if error BB */
4550 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004551 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004552 unsigned int lnoff;
4553
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004555 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556 else
Steve French4b18f2a2008-04-29 00:06:05 +00004557 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558
4559 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004560 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004561 psrch_inf->srch_entries_start =
4562 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4565 le16_to_cpu(pSMBr->t2.ParameterOffset));
4566
Steve French790fe572007-07-07 19:25:05 +00004567 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004568 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 else
Steve French4b18f2a2008-04-29 00:06:05 +00004570 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571
Steve French50c2f752007-07-13 00:33:32 +00004572 psrch_inf->entries_in_buffer =
4573 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004574 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004576 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004577 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004578 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004579 psrch_inf->last_entry = NULL;
4580 return rc;
4581 }
4582
Steve French0752f152008-10-07 20:03:33 +00004583 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004584 lnoff;
4585
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004586 if (pnetfid)
4587 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588 } else {
4589 cifs_buf_release(pSMB);
4590 }
4591 }
4592
4593 return rc;
4594}
4595
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004596int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4597 __u16 searchHandle, __u16 search_flags,
4598 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599{
4600 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4601 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004602 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603 char *response_data;
4604 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004605 int bytes_returned;
4606 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607 __u16 params, byte_count;
4608
Joe Perchesf96637b2013-05-04 22:12:25 -05004609 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004610
Steve French4b18f2a2008-04-29 00:06:05 +00004611 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 return -ENOENT;
4613
4614 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4615 (void **) &pSMBr);
4616 if (rc)
4617 return rc;
4618
Steve French50c2f752007-07-13 00:33:32 +00004619 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 byte_count = 0;
4621 pSMB->TotalDataCount = 0; /* no EAs */
4622 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004623 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624 pSMB->MaxSetupCount = 0;
4625 pSMB->Reserved = 0;
4626 pSMB->Flags = 0;
4627 pSMB->Timeout = 0;
4628 pSMB->Reserved2 = 0;
4629 pSMB->ParameterOffset = cpu_to_le16(
4630 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4631 pSMB->DataCount = 0;
4632 pSMB->DataOffset = 0;
4633 pSMB->SetupCount = 1;
4634 pSMB->Reserved3 = 0;
4635 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4636 pSMB->SearchHandle = searchHandle; /* always kept as le */
4637 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004638 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4640 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004641 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642
4643 name_len = psrch_inf->resume_name_len;
4644 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004645 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004646 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4647 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004648 /* 14 byte parm len above enough for 2 byte null terminator */
4649 pSMB->ResumeFileName[name_len] = 0;
4650 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651 } else {
4652 rc = -EINVAL;
4653 goto FNext2_err_exit;
4654 }
4655 byte_count = params + 1 /* pad */ ;
4656 pSMB->TotalParameterCount = cpu_to_le16(params);
4657 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004658 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004659 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004660
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4662 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004663 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004664 if (rc) {
4665 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004666 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004667 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004668 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004670 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671 } else { /* decode response */
4672 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004673
Steve French790fe572007-07-07 19:25:05 +00004674 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004675 unsigned int lnoff;
4676
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677 /* BB fixme add lock for file (srch_info) struct here */
4678 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004679 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004680 else
Steve French4b18f2a2008-04-29 00:06:05 +00004681 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004682 response_data = (char *) &pSMBr->hdr.Protocol +
4683 le16_to_cpu(pSMBr->t2.ParameterOffset);
4684 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4685 response_data = (char *)&pSMBr->hdr.Protocol +
4686 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004687 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004688 cifs_small_buf_release(
4689 psrch_inf->ntwrk_buf_start);
4690 else
4691 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692 psrch_inf->srch_entries_start = response_data;
4693 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004694 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004695 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004696 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697 else
Steve French4b18f2a2008-04-29 00:06:05 +00004698 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004699 psrch_inf->entries_in_buffer =
4700 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701 psrch_inf->index_of_last_entry +=
4702 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004703 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004704 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004705 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004706 psrch_inf->last_entry = NULL;
4707 return rc;
4708 } else
4709 psrch_inf->last_entry =
4710 psrch_inf->srch_entries_start + lnoff;
4711
Joe Perchesf96637b2013-05-04 22:12:25 -05004712/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4713 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004714
4715 /* BB fixme add unlock here */
4716 }
4717
4718 }
4719
4720 /* BB On error, should we leave previous search buf (and count and
4721 last entry fields) intact or free the previous one? */
4722
4723 /* Note: On -EAGAIN error only caller can retry on handle based calls
4724 since file handle passed in no longer valid */
4725FNext2_err_exit:
4726 if (rc != 0)
4727 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728 return rc;
4729}
4730
4731int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004732CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004733 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734{
4735 int rc = 0;
4736 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737
Joe Perchesf96637b2013-05-04 22:12:25 -05004738 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4740
4741 /* no sense returning error if session restarted
4742 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004743 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744 return 0;
4745 if (rc)
4746 return rc;
4747
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748 pSMB->FileID = searchHandle;
4749 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004750 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004751 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00004752 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004753 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004754
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004755 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756
4757 /* Since session is dead, search handle closed on server already */
4758 if (rc == -EAGAIN)
4759 rc = 0;
4760
4761 return rc;
4762}
4763
Linus Torvalds1da177e2005-04-16 15:20:36 -07004764int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004765CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004766 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004767 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768{
4769 int rc = 0;
4770 TRANSACTION2_QPI_REQ *pSMB = NULL;
4771 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4772 int name_len, bytes_returned;
4773 __u16 params, byte_count;
4774
Joe Perchesf96637b2013-05-04 22:12:25 -05004775 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004776 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004777 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778
4779GetInodeNumberRetry:
4780 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004781 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782 if (rc)
4783 return rc;
4784
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4786 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004787 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004788 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004789 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 name_len++; /* trailing null */
4791 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004792 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004793 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004795 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796 }
4797
4798 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4799 pSMB->TotalDataCount = 0;
4800 pSMB->MaxParameterCount = cpu_to_le16(2);
4801 /* BB find exact max data count below from sess structure BB */
4802 pSMB->MaxDataCount = cpu_to_le16(4000);
4803 pSMB->MaxSetupCount = 0;
4804 pSMB->Reserved = 0;
4805 pSMB->Flags = 0;
4806 pSMB->Timeout = 0;
4807 pSMB->Reserved2 = 0;
4808 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004809 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810 pSMB->DataCount = 0;
4811 pSMB->DataOffset = 0;
4812 pSMB->SetupCount = 1;
4813 pSMB->Reserved3 = 0;
4814 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4815 byte_count = params + 1 /* pad */ ;
4816 pSMB->TotalParameterCount = cpu_to_le16(params);
4817 pSMB->ParameterCount = pSMB->TotalParameterCount;
4818 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4819 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004820 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821 pSMB->ByteCount = cpu_to_le16(byte_count);
4822
4823 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4824 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4825 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004826 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827 } else {
4828 /* decode response */
4829 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004831 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832 /* If rc should we check for EOPNOSUPP and
4833 disable the srvino flag? or in caller? */
4834 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004835 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004836 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4837 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004838 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004840 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004841 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004842 rc = -EIO;
4843 goto GetInodeNumOut;
4844 }
4845 pfinfo = (struct file_internal_info *)
4846 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004847 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004848 }
4849 }
4850GetInodeNumOut:
4851 cifs_buf_release(pSMB);
4852 if (rc == -EAGAIN)
4853 goto GetInodeNumberRetry;
4854 return rc;
4855}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004856
4857int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004858CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004859 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004860 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004861 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862{
4863/* TRANS2_GET_DFS_REFERRAL */
4864 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4865 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866 int rc = 0;
4867 int bytes_returned;
4868 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004870 *num_of_nodes = 0;
4871 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872
Joe Perchesf96637b2013-05-04 22:12:25 -05004873 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004874 if (ses == NULL || ses->tcon_ipc == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875 return -ENODEV;
Aurelien Aptelb327a712018-01-24 13:46:10 +01004876
Linus Torvalds1da177e2005-04-16 15:20:36 -07004877getDFSRetry:
Aurelien Aptelb327a712018-01-24 13:46:10 +01004878 rc = smb_init(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879 (void **) &pSMBr);
4880 if (rc)
4881 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004882
4883 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004884 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004885 pSMB->hdr.Mid = get_next_mid(ses->server);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004886 pSMB->hdr.Tid = ses->tcon_ipc->tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004887 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004888 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004889 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004890 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892
4893 if (ses->capabilities & CAP_UNICODE) {
4894 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4895 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004896 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004897 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004898 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004899 name_len++; /* trailing null */
4900 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004901 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004902 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004903 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004904 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004905 }
4906
Dan Carpenter65c3b202015-04-30 17:30:24 +03004907 if (ses->server->sign)
Jeff Layton38d77c52013-05-26 07:01:00 -04004908 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00004909
Steve French50c2f752007-07-13 00:33:32 +00004910 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004911
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912 params = 2 /* level */ + name_len /*includes null */ ;
4913 pSMB->TotalDataCount = 0;
4914 pSMB->DataCount = 0;
4915 pSMB->DataOffset = 0;
4916 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004917 /* BB find exact max SMB PDU from sess structure BB */
4918 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919 pSMB->MaxSetupCount = 0;
4920 pSMB->Reserved = 0;
4921 pSMB->Flags = 0;
4922 pSMB->Timeout = 0;
4923 pSMB->Reserved2 = 0;
4924 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004925 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004926 pSMB->SetupCount = 1;
4927 pSMB->Reserved3 = 0;
4928 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4929 byte_count = params + 3 /* pad */ ;
4930 pSMB->ParameterCount = cpu_to_le16(params);
4931 pSMB->TotalParameterCount = pSMB->ParameterCount;
4932 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004933 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004934 pSMB->ByteCount = cpu_to_le16(byte_count);
4935
4936 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4937 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4938 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004939 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004940 goto GetDFSRefExit;
4941 }
4942 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004944 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004945 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004946 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004947 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004948 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004949
Joe Perchesf96637b2013-05-04 22:12:25 -05004950 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4951 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004952
4953 /* parse returned result into more usable form */
Aurelien Aptel4ecce922017-02-13 16:03:47 +01004954 rc = parse_dfs_referrals(&pSMBr->dfs_data,
4955 le16_to_cpu(pSMBr->t2.DataCount),
4956 num_of_nodes, target_nodes, nls_codepage,
4957 remap, search_name,
Steve French284316d2017-03-02 15:42:48 -06004958 (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0);
Igor Mammedovfec45852008-05-16 13:06:30 +04004959
Linus Torvalds1da177e2005-04-16 15:20:36 -07004960GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004961 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004962
4963 if (rc == -EAGAIN)
4964 goto getDFSRetry;
4965
4966 return rc;
4967}
4968
Steve French20962432005-09-21 22:05:57 -07004969/* Query File System Info such as free space to old servers such as Win 9x */
4970int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004971SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4972 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004973{
4974/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4975 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4976 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4977 FILE_SYSTEM_ALLOC_INFO *response_data;
4978 int rc = 0;
4979 int bytes_returned = 0;
4980 __u16 params, byte_count;
4981
Joe Perchesf96637b2013-05-04 22:12:25 -05004982 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004983oldQFSInfoRetry:
4984 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4985 (void **) &pSMBr);
4986 if (rc)
4987 return rc;
Steve French20962432005-09-21 22:05:57 -07004988
4989 params = 2; /* level */
4990 pSMB->TotalDataCount = 0;
4991 pSMB->MaxParameterCount = cpu_to_le16(2);
4992 pSMB->MaxDataCount = cpu_to_le16(1000);
4993 pSMB->MaxSetupCount = 0;
4994 pSMB->Reserved = 0;
4995 pSMB->Flags = 0;
4996 pSMB->Timeout = 0;
4997 pSMB->Reserved2 = 0;
4998 byte_count = params + 1 /* pad */ ;
4999 pSMB->TotalParameterCount = cpu_to_le16(params);
5000 pSMB->ParameterCount = pSMB->TotalParameterCount;
5001 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5002 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
5003 pSMB->DataCount = 0;
5004 pSMB->DataOffset = 0;
5005 pSMB->SetupCount = 1;
5006 pSMB->Reserved3 = 0;
5007 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5008 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005009 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07005010 pSMB->ByteCount = cpu_to_le16(byte_count);
5011
5012 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5013 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5014 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005015 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07005016 } else { /* decode response */
5017 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5018
Jeff Layton820a8032011-05-04 08:05:26 -04005019 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07005020 rc = -EIO; /* bad smb */
5021 else {
5022 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05005023 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04005024 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07005025
Steve French50c2f752007-07-13 00:33:32 +00005026 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07005027 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5028 FSData->f_bsize =
5029 le16_to_cpu(response_data->BytesPerSector) *
5030 le32_to_cpu(response_data->
5031 SectorsPerAllocationUnit);
Steve French5a519be2018-09-15 14:07:09 -05005032 /*
5033 * much prefer larger but if server doesn't report
5034 * a valid size than 4K is a reasonable minimum
5035 */
5036 if (FSData->f_bsize < 512)
5037 FSData->f_bsize = 4096;
5038
Steve French20962432005-09-21 22:05:57 -07005039 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00005040 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07005041 FSData->f_bfree = FSData->f_bavail =
5042 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005043 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5044 (unsigned long long)FSData->f_blocks,
5045 (unsigned long long)FSData->f_bfree,
5046 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07005047 }
5048 }
5049 cifs_buf_release(pSMB);
5050
5051 if (rc == -EAGAIN)
5052 goto oldQFSInfoRetry;
5053
5054 return rc;
5055}
5056
Linus Torvalds1da177e2005-04-16 15:20:36 -07005057int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005058CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5059 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005060{
5061/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5062 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5063 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5064 FILE_SYSTEM_INFO *response_data;
5065 int rc = 0;
5066 int bytes_returned = 0;
5067 __u16 params, byte_count;
5068
Joe Perchesf96637b2013-05-04 22:12:25 -05005069 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070QFSInfoRetry:
5071 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5072 (void **) &pSMBr);
5073 if (rc)
5074 return rc;
5075
5076 params = 2; /* level */
5077 pSMB->TotalDataCount = 0;
5078 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005079 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005080 pSMB->MaxSetupCount = 0;
5081 pSMB->Reserved = 0;
5082 pSMB->Flags = 0;
5083 pSMB->Timeout = 0;
5084 pSMB->Reserved2 = 0;
5085 byte_count = params + 1 /* pad */ ;
5086 pSMB->TotalParameterCount = cpu_to_le16(params);
5087 pSMB->ParameterCount = pSMB->TotalParameterCount;
5088 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005089 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090 pSMB->DataCount = 0;
5091 pSMB->DataOffset = 0;
5092 pSMB->SetupCount = 1;
5093 pSMB->Reserved3 = 0;
5094 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5095 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005096 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005097 pSMB->ByteCount = cpu_to_le16(byte_count);
5098
5099 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5100 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5101 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005102 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005103 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005104 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005105
Jeff Layton820a8032011-05-04 08:05:26 -04005106 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005107 rc = -EIO; /* bad smb */
5108 else {
5109 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005110
5111 response_data =
5112 (FILE_SYSTEM_INFO
5113 *) (((char *) &pSMBr->hdr.Protocol) +
5114 data_offset);
5115 FSData->f_bsize =
5116 le32_to_cpu(response_data->BytesPerSector) *
5117 le32_to_cpu(response_data->
5118 SectorsPerAllocationUnit);
Steve French5a519be2018-09-15 14:07:09 -05005119 /*
5120 * much prefer larger but if server doesn't report
5121 * a valid size than 4K is a reasonable minimum
5122 */
5123 if (FSData->f_bsize < 512)
5124 FSData->f_bsize = 4096;
5125
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126 FSData->f_blocks =
5127 le64_to_cpu(response_data->TotalAllocationUnits);
5128 FSData->f_bfree = FSData->f_bavail =
5129 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005130 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5131 (unsigned long long)FSData->f_blocks,
5132 (unsigned long long)FSData->f_bfree,
5133 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005134 }
5135 }
5136 cifs_buf_release(pSMB);
5137
5138 if (rc == -EAGAIN)
5139 goto QFSInfoRetry;
5140
5141 return rc;
5142}
5143
5144int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005145CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146{
5147/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5148 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5149 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5150 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5151 int rc = 0;
5152 int bytes_returned = 0;
5153 __u16 params, byte_count;
5154
Joe Perchesf96637b2013-05-04 22:12:25 -05005155 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156QFSAttributeRetry:
5157 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5158 (void **) &pSMBr);
5159 if (rc)
5160 return rc;
5161
5162 params = 2; /* level */
5163 pSMB->TotalDataCount = 0;
5164 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005165 /* BB find exact max SMB PDU from sess structure BB */
5166 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167 pSMB->MaxSetupCount = 0;
5168 pSMB->Reserved = 0;
5169 pSMB->Flags = 0;
5170 pSMB->Timeout = 0;
5171 pSMB->Reserved2 = 0;
5172 byte_count = params + 1 /* pad */ ;
5173 pSMB->TotalParameterCount = cpu_to_le16(params);
5174 pSMB->ParameterCount = pSMB->TotalParameterCount;
5175 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005176 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005177 pSMB->DataCount = 0;
5178 pSMB->DataOffset = 0;
5179 pSMB->SetupCount = 1;
5180 pSMB->Reserved3 = 0;
5181 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5182 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005183 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184 pSMB->ByteCount = cpu_to_le16(byte_count);
5185
5186 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5187 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5188 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005189 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005190 } else { /* decode response */
5191 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5192
Jeff Layton820a8032011-05-04 08:05:26 -04005193 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005194 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195 rc = -EIO; /* bad smb */
5196 } else {
5197 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5198 response_data =
5199 (FILE_SYSTEM_ATTRIBUTE_INFO
5200 *) (((char *) &pSMBr->hdr.Protocol) +
5201 data_offset);
5202 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005203 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005204 }
5205 }
5206 cifs_buf_release(pSMB);
5207
5208 if (rc == -EAGAIN)
5209 goto QFSAttributeRetry;
5210
5211 return rc;
5212}
5213
5214int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005215CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005216{
5217/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5218 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5219 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5220 FILE_SYSTEM_DEVICE_INFO *response_data;
5221 int rc = 0;
5222 int bytes_returned = 0;
5223 __u16 params, byte_count;
5224
Joe Perchesf96637b2013-05-04 22:12:25 -05005225 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226QFSDeviceRetry:
5227 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5228 (void **) &pSMBr);
5229 if (rc)
5230 return rc;
5231
5232 params = 2; /* level */
5233 pSMB->TotalDataCount = 0;
5234 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005235 /* BB find exact max SMB PDU from sess structure BB */
5236 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237 pSMB->MaxSetupCount = 0;
5238 pSMB->Reserved = 0;
5239 pSMB->Flags = 0;
5240 pSMB->Timeout = 0;
5241 pSMB->Reserved2 = 0;
5242 byte_count = params + 1 /* pad */ ;
5243 pSMB->TotalParameterCount = cpu_to_le16(params);
5244 pSMB->ParameterCount = pSMB->TotalParameterCount;
5245 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005246 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005247
5248 pSMB->DataCount = 0;
5249 pSMB->DataOffset = 0;
5250 pSMB->SetupCount = 1;
5251 pSMB->Reserved3 = 0;
5252 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5253 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005254 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005255 pSMB->ByteCount = cpu_to_le16(byte_count);
5256
5257 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5258 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5259 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005260 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005261 } else { /* decode response */
5262 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5263
Jeff Layton820a8032011-05-04 08:05:26 -04005264 if (rc || get_bcc(&pSMBr->hdr) <
5265 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005266 rc = -EIO; /* bad smb */
5267 else {
5268 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5269 response_data =
Steve French737b7582005-04-28 22:41:06 -07005270 (FILE_SYSTEM_DEVICE_INFO *)
5271 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005272 data_offset);
5273 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005274 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005275 }
5276 }
5277 cifs_buf_release(pSMB);
5278
5279 if (rc == -EAGAIN)
5280 goto QFSDeviceRetry;
5281
5282 return rc;
5283}
5284
5285int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005286CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005287{
5288/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5289 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5290 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5291 FILE_SYSTEM_UNIX_INFO *response_data;
5292 int rc = 0;
5293 int bytes_returned = 0;
5294 __u16 params, byte_count;
5295
Joe Perchesf96637b2013-05-04 22:12:25 -05005296 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005297QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005298 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5299 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005300 if (rc)
5301 return rc;
5302
5303 params = 2; /* level */
5304 pSMB->TotalDataCount = 0;
5305 pSMB->DataCount = 0;
5306 pSMB->DataOffset = 0;
5307 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005308 /* BB find exact max SMB PDU from sess structure BB */
5309 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005310 pSMB->MaxSetupCount = 0;
5311 pSMB->Reserved = 0;
5312 pSMB->Flags = 0;
5313 pSMB->Timeout = 0;
5314 pSMB->Reserved2 = 0;
5315 byte_count = params + 1 /* pad */ ;
5316 pSMB->ParameterCount = cpu_to_le16(params);
5317 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005318 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5319 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005320 pSMB->SetupCount = 1;
5321 pSMB->Reserved3 = 0;
5322 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5323 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005324 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005325 pSMB->ByteCount = cpu_to_le16(byte_count);
5326
5327 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5328 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5329 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005330 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005331 } else { /* decode response */
5332 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5333
Jeff Layton820a8032011-05-04 08:05:26 -04005334 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005335 rc = -EIO; /* bad smb */
5336 } else {
5337 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5338 response_data =
5339 (FILE_SYSTEM_UNIX_INFO
5340 *) (((char *) &pSMBr->hdr.Protocol) +
5341 data_offset);
5342 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005343 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005344 }
5345 }
5346 cifs_buf_release(pSMB);
5347
5348 if (rc == -EAGAIN)
5349 goto QFSUnixRetry;
5350
5351
5352 return rc;
5353}
5354
Jeremy Allisonac670552005-06-22 17:26:35 -07005355int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005356CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005357{
5358/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5359 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5360 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5361 int rc = 0;
5362 int bytes_returned = 0;
5363 __u16 params, param_offset, offset, byte_count;
5364
Joe Perchesf96637b2013-05-04 22:12:25 -05005365 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005366SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005367 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005368 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5369 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005370 if (rc)
5371 return rc;
5372
5373 params = 4; /* 2 bytes zero followed by info level. */
5374 pSMB->MaxSetupCount = 0;
5375 pSMB->Reserved = 0;
5376 pSMB->Flags = 0;
5377 pSMB->Timeout = 0;
5378 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005379 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5380 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005381 offset = param_offset + params;
5382
5383 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005384 /* BB find exact max SMB PDU from sess structure BB */
5385 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005386 pSMB->SetupCount = 1;
5387 pSMB->Reserved3 = 0;
5388 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5389 byte_count = 1 /* pad */ + params + 12;
5390
5391 pSMB->DataCount = cpu_to_le16(12);
5392 pSMB->ParameterCount = cpu_to_le16(params);
5393 pSMB->TotalDataCount = pSMB->DataCount;
5394 pSMB->TotalParameterCount = pSMB->ParameterCount;
5395 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5396 pSMB->DataOffset = cpu_to_le16(offset);
5397
5398 /* Params. */
5399 pSMB->FileNum = 0;
5400 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5401
5402 /* Data. */
5403 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5404 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5405 pSMB->ClientUnixCap = cpu_to_le64(cap);
5406
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005407 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005408 pSMB->ByteCount = cpu_to_le16(byte_count);
5409
5410 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5411 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5412 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005413 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005414 } else { /* decode response */
5415 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005416 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005417 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005418 }
5419 cifs_buf_release(pSMB);
5420
5421 if (rc == -EAGAIN)
5422 goto SETFSUnixRetry;
5423
5424 return rc;
5425}
5426
5427
Linus Torvalds1da177e2005-04-16 15:20:36 -07005428
5429int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005430CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005431 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432{
5433/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5434 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5435 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5436 FILE_SYSTEM_POSIX_INFO *response_data;
5437 int rc = 0;
5438 int bytes_returned = 0;
5439 __u16 params, byte_count;
5440
Joe Perchesf96637b2013-05-04 22:12:25 -05005441 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005442QFSPosixRetry:
5443 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5444 (void **) &pSMBr);
5445 if (rc)
5446 return rc;
5447
5448 params = 2; /* level */
5449 pSMB->TotalDataCount = 0;
5450 pSMB->DataCount = 0;
5451 pSMB->DataOffset = 0;
5452 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005453 /* BB find exact max SMB PDU from sess structure BB */
5454 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455 pSMB->MaxSetupCount = 0;
5456 pSMB->Reserved = 0;
5457 pSMB->Flags = 0;
5458 pSMB->Timeout = 0;
5459 pSMB->Reserved2 = 0;
5460 byte_count = params + 1 /* pad */ ;
5461 pSMB->ParameterCount = cpu_to_le16(params);
5462 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005463 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5464 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005465 pSMB->SetupCount = 1;
5466 pSMB->Reserved3 = 0;
5467 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5468 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005469 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470 pSMB->ByteCount = cpu_to_le16(byte_count);
5471
5472 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5473 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5474 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005475 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476 } else { /* decode response */
5477 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5478
Jeff Layton820a8032011-05-04 08:05:26 -04005479 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480 rc = -EIO; /* bad smb */
5481 } else {
5482 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5483 response_data =
5484 (FILE_SYSTEM_POSIX_INFO
5485 *) (((char *) &pSMBr->hdr.Protocol) +
5486 data_offset);
5487 FSData->f_bsize =
5488 le32_to_cpu(response_data->BlockSize);
Steve French5a519be2018-09-15 14:07:09 -05005489 /*
5490 * much prefer larger but if server doesn't report
5491 * a valid size than 4K is a reasonable minimum
5492 */
5493 if (FSData->f_bsize < 512)
5494 FSData->f_bsize = 4096;
5495
Linus Torvalds1da177e2005-04-16 15:20:36 -07005496 FSData->f_blocks =
5497 le64_to_cpu(response_data->TotalBlocks);
5498 FSData->f_bfree =
5499 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005500 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501 FSData->f_bavail = FSData->f_bfree;
5502 } else {
5503 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005504 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005505 }
Steve French790fe572007-07-07 19:25:05 +00005506 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005508 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005509 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005510 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005511 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005512 }
5513 }
5514 cifs_buf_release(pSMB);
5515
5516 if (rc == -EAGAIN)
5517 goto QFSPosixRetry;
5518
5519 return rc;
5520}
5521
5522
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005523/*
5524 * We can not use write of zero bytes trick to set file size due to need for
5525 * large file support. Also note that this SetPathInfo is preferred to
5526 * SetFileInfo based method in next routine which is only needed to work around
5527 * a sharing violation bugin Samba which this routine can run into.
5528 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005529int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005530CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005531 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5532 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005533{
5534 struct smb_com_transaction2_spi_req *pSMB = NULL;
5535 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5536 struct file_end_of_file_info *parm_data;
5537 int name_len;
5538 int rc = 0;
5539 int bytes_returned = 0;
Steve French2baa2682014-09-27 02:19:01 -05005540 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005541
Linus Torvalds1da177e2005-04-16 15:20:36 -07005542 __u16 params, byte_count, data_count, param_offset, offset;
5543
Joe Perchesf96637b2013-05-04 22:12:25 -05005544 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005545SetEOFRetry:
5546 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5547 (void **) &pSMBr);
5548 if (rc)
5549 return rc;
5550
5551 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5552 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005553 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5554 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 name_len++; /* trailing null */
5556 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005557 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005558 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005560 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561 }
5562 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005563 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005564 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005565 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566 pSMB->MaxSetupCount = 0;
5567 pSMB->Reserved = 0;
5568 pSMB->Flags = 0;
5569 pSMB->Timeout = 0;
5570 pSMB->Reserved2 = 0;
5571 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005572 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005573 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005574 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005575 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5576 pSMB->InformationLevel =
5577 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5578 else
5579 pSMB->InformationLevel =
5580 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5581 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5583 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005584 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585 else
5586 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005587 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005588 }
5589
5590 parm_data =
5591 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5592 offset);
5593 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5594 pSMB->DataOffset = cpu_to_le16(offset);
5595 pSMB->SetupCount = 1;
5596 pSMB->Reserved3 = 0;
5597 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5598 byte_count = 3 /* pad */ + params + data_count;
5599 pSMB->DataCount = cpu_to_le16(data_count);
5600 pSMB->TotalDataCount = pSMB->DataCount;
5601 pSMB->ParameterCount = cpu_to_le16(params);
5602 pSMB->TotalParameterCount = pSMB->ParameterCount;
5603 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005604 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005605 parm_data->FileSize = cpu_to_le64(size);
5606 pSMB->ByteCount = cpu_to_le16(byte_count);
5607 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5608 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005609 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005610 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611
5612 cifs_buf_release(pSMB);
5613
5614 if (rc == -EAGAIN)
5615 goto SetEOFRetry;
5616
5617 return rc;
5618}
5619
5620int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005621CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5622 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623{
5624 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005625 struct file_end_of_file_info *parm_data;
5626 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005627 __u16 params, param_offset, offset, byte_count, count;
5628
Joe Perchesf96637b2013-05-04 22:12:25 -05005629 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5630 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005631 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5632
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633 if (rc)
5634 return rc;
5635
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005636 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5637 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005638
Linus Torvalds1da177e2005-04-16 15:20:36 -07005639 params = 6;
5640 pSMB->MaxSetupCount = 0;
5641 pSMB->Reserved = 0;
5642 pSMB->Flags = 0;
5643 pSMB->Timeout = 0;
5644 pSMB->Reserved2 = 0;
5645 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5646 offset = param_offset + params;
5647
Linus Torvalds1da177e2005-04-16 15:20:36 -07005648 count = sizeof(struct file_end_of_file_info);
5649 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005650 /* BB find exact max SMB PDU from sess structure BB */
5651 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005652 pSMB->SetupCount = 1;
5653 pSMB->Reserved3 = 0;
5654 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5655 byte_count = 3 /* pad */ + params + count;
5656 pSMB->DataCount = cpu_to_le16(count);
5657 pSMB->ParameterCount = cpu_to_le16(params);
5658 pSMB->TotalDataCount = pSMB->DataCount;
5659 pSMB->TotalParameterCount = pSMB->ParameterCount;
5660 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5661 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005662 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5663 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005664 pSMB->DataOffset = cpu_to_le16(offset);
5665 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005666 pSMB->Fid = cfile->fid.netfid;
5667 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005668 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5669 pSMB->InformationLevel =
5670 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5671 else
5672 pSMB->InformationLevel =
5673 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005674 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5676 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005677 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005678 else
5679 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005680 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005681 }
5682 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005683 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005684 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005685 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005686 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005687 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005688 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5689 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005690 }
5691
Steve French50c2f752007-07-13 00:33:32 +00005692 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005693 since file handle passed in no longer valid */
5694
5695 return rc;
5696}
5697
Steve French50c2f752007-07-13 00:33:32 +00005698/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005699 an open handle, rather than by pathname - this is awkward due to
5700 potential access conflicts on the open, but it is unavoidable for these
5701 old servers since the only other choice is to go from 100 nanosecond DCE
5702 time and resort to the original setpathinfo level which takes the ancient
5703 DOS time format with 2 second granularity */
5704int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005705CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005706 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005707{
5708 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005709 char *data_offset;
5710 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005711 __u16 params, param_offset, offset, byte_count, count;
5712
Joe Perchesf96637b2013-05-04 22:12:25 -05005713 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005714 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5715
Linus Torvalds1da177e2005-04-16 15:20:36 -07005716 if (rc)
5717 return rc;
5718
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005719 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5720 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005721
Linus Torvalds1da177e2005-04-16 15:20:36 -07005722 params = 6;
5723 pSMB->MaxSetupCount = 0;
5724 pSMB->Reserved = 0;
5725 pSMB->Flags = 0;
5726 pSMB->Timeout = 0;
5727 pSMB->Reserved2 = 0;
5728 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5729 offset = param_offset + params;
5730
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005731 data_offset = (char *)pSMB +
5732 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005733
Steve French26f57362007-08-30 22:09:15 +00005734 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005735 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005736 /* BB find max SMB PDU from sess */
5737 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005738 pSMB->SetupCount = 1;
5739 pSMB->Reserved3 = 0;
5740 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5741 byte_count = 3 /* pad */ + params + count;
5742 pSMB->DataCount = cpu_to_le16(count);
5743 pSMB->ParameterCount = cpu_to_le16(params);
5744 pSMB->TotalDataCount = pSMB->DataCount;
5745 pSMB->TotalParameterCount = pSMB->ParameterCount;
5746 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5747 pSMB->DataOffset = cpu_to_le16(offset);
5748 pSMB->Fid = fid;
5749 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5750 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5751 else
5752 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5753 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005754 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005755 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005756 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005757 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005758 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00005759 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005760 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5761 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005762
Steve French50c2f752007-07-13 00:33:32 +00005763 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005764 since file handle passed in no longer valid */
5765
5766 return rc;
5767}
5768
Jeff Layton6d22f092008-09-23 11:48:35 -04005769int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005770CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005771 bool delete_file, __u16 fid, __u32 pid_of_opener)
5772{
5773 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5774 char *data_offset;
5775 int rc = 0;
5776 __u16 params, param_offset, offset, byte_count, count;
5777
Joe Perchesf96637b2013-05-04 22:12:25 -05005778 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005779 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5780
5781 if (rc)
5782 return rc;
5783
5784 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5785 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5786
5787 params = 6;
5788 pSMB->MaxSetupCount = 0;
5789 pSMB->Reserved = 0;
5790 pSMB->Flags = 0;
5791 pSMB->Timeout = 0;
5792 pSMB->Reserved2 = 0;
5793 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5794 offset = param_offset + params;
5795
5796 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5797
5798 count = 1;
5799 pSMB->MaxParameterCount = cpu_to_le16(2);
5800 /* BB find max SMB PDU from sess */
5801 pSMB->MaxDataCount = cpu_to_le16(1000);
5802 pSMB->SetupCount = 1;
5803 pSMB->Reserved3 = 0;
5804 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5805 byte_count = 3 /* pad */ + params + count;
5806 pSMB->DataCount = cpu_to_le16(count);
5807 pSMB->ParameterCount = cpu_to_le16(params);
5808 pSMB->TotalDataCount = pSMB->DataCount;
5809 pSMB->TotalParameterCount = pSMB->ParameterCount;
5810 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5811 pSMB->DataOffset = cpu_to_le16(offset);
5812 pSMB->Fid = fid;
5813 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5814 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005815 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005816 pSMB->ByteCount = cpu_to_le16(byte_count);
5817 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005818 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005819 cifs_small_buf_release(pSMB);
Jeff Layton6d22f092008-09-23 11:48:35 -04005820 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005821 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005822
5823 return rc;
5824}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005825
5826int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005827CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005828 const char *fileName, const FILE_BASIC_INFO *data,
5829 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005830{
5831 TRANSACTION2_SPI_REQ *pSMB = NULL;
5832 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5833 int name_len;
5834 int rc = 0;
5835 int bytes_returned = 0;
5836 char *data_offset;
5837 __u16 params, param_offset, offset, byte_count, count;
5838
Joe Perchesf96637b2013-05-04 22:12:25 -05005839 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005840
5841SetTimesRetry:
5842 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5843 (void **) &pSMBr);
5844 if (rc)
5845 return rc;
5846
5847 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5848 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005849 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5850 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851 name_len++; /* trailing null */
5852 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005853 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005854 name_len = strnlen(fileName, PATH_MAX);
5855 name_len++; /* trailing null */
5856 strncpy(pSMB->FileName, fileName, name_len);
5857 }
5858
5859 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005860 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005861 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005862 /* BB find max SMB PDU from sess structure BB */
5863 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005864 pSMB->MaxSetupCount = 0;
5865 pSMB->Reserved = 0;
5866 pSMB->Flags = 0;
5867 pSMB->Timeout = 0;
5868 pSMB->Reserved2 = 0;
5869 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005870 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005871 offset = param_offset + params;
5872 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5873 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5874 pSMB->DataOffset = cpu_to_le16(offset);
5875 pSMB->SetupCount = 1;
5876 pSMB->Reserved3 = 0;
5877 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5878 byte_count = 3 /* pad */ + params + count;
5879
5880 pSMB->DataCount = cpu_to_le16(count);
5881 pSMB->ParameterCount = cpu_to_le16(params);
5882 pSMB->TotalDataCount = pSMB->DataCount;
5883 pSMB->TotalParameterCount = pSMB->ParameterCount;
5884 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5885 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5886 else
5887 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5888 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005889 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005890 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005891 pSMB->ByteCount = cpu_to_le16(byte_count);
5892 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5893 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005894 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005895 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005896
5897 cifs_buf_release(pSMB);
5898
5899 if (rc == -EAGAIN)
5900 goto SetTimesRetry;
5901
5902 return rc;
5903}
5904
5905/* Can not be used to set time stamps yet (due to old DOS time format) */
5906/* Can be used to set attributes */
5907#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5908 handling it anyway and NT4 was what we thought it would be needed for
5909 Do not delete it until we prove whether needed for Win9x though */
5910int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005911CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005912 __u16 dos_attrs, const struct nls_table *nls_codepage)
5913{
5914 SETATTR_REQ *pSMB = NULL;
5915 SETATTR_RSP *pSMBr = NULL;
5916 int rc = 0;
5917 int bytes_returned;
5918 int name_len;
5919
Joe Perchesf96637b2013-05-04 22:12:25 -05005920 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005921
5922SetAttrLgcyRetry:
5923 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5924 (void **) &pSMBr);
5925 if (rc)
5926 return rc;
5927
5928 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5929 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005930 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5931 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005932 name_len++; /* trailing null */
5933 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005934 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005935 name_len = strnlen(fileName, PATH_MAX);
5936 name_len++; /* trailing null */
5937 strncpy(pSMB->fileName, fileName, name_len);
5938 }
5939 pSMB->attr = cpu_to_le16(dos_attrs);
5940 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005941 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005942 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5943 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5944 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005945 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005946 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005947
5948 cifs_buf_release(pSMB);
5949
5950 if (rc == -EAGAIN)
5951 goto SetAttrLgcyRetry;
5952
5953 return rc;
5954}
5955#endif /* temporarily unneeded SetAttr legacy function */
5956
Jeff Layton654cf142009-07-09 20:02:49 -04005957static void
5958cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5959 const struct cifs_unix_set_info_args *args)
5960{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005961 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005962 u64 mode = args->mode;
5963
Eric W. Biederman49418b22013-02-06 00:57:56 -08005964 if (uid_valid(args->uid))
5965 uid = from_kuid(&init_user_ns, args->uid);
5966 if (gid_valid(args->gid))
5967 gid = from_kgid(&init_user_ns, args->gid);
5968
Jeff Layton654cf142009-07-09 20:02:49 -04005969 /*
5970 * Samba server ignores set of file size to zero due to bugs in some
5971 * older clients, but we should be precise - we use SetFileSize to
5972 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005973 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005974 * zero instead of -1 here
5975 */
5976 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5977 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5978 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5979 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5980 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005981 data_offset->Uid = cpu_to_le64(uid);
5982 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005983 /* better to leave device as zero when it is */
5984 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5985 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5986 data_offset->Permissions = cpu_to_le64(mode);
5987
5988 if (S_ISREG(mode))
5989 data_offset->Type = cpu_to_le32(UNIX_FILE);
5990 else if (S_ISDIR(mode))
5991 data_offset->Type = cpu_to_le32(UNIX_DIR);
5992 else if (S_ISLNK(mode))
5993 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5994 else if (S_ISCHR(mode))
5995 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5996 else if (S_ISBLK(mode))
5997 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5998 else if (S_ISFIFO(mode))
5999 data_offset->Type = cpu_to_le32(UNIX_FIFO);
6000 else if (S_ISSOCK(mode))
6001 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
6002}
6003
Linus Torvalds1da177e2005-04-16 15:20:36 -07006004int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006005CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006006 const struct cifs_unix_set_info_args *args,
6007 u16 fid, u32 pid_of_opener)
6008{
6009 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006010 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006011 int rc = 0;
6012 u16 params, param_offset, offset, byte_count, count;
6013
Joe Perchesf96637b2013-05-04 22:12:25 -05006014 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006015 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
6016
6017 if (rc)
6018 return rc;
6019
6020 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
6021 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
6022
6023 params = 6;
6024 pSMB->MaxSetupCount = 0;
6025 pSMB->Reserved = 0;
6026 pSMB->Flags = 0;
6027 pSMB->Timeout = 0;
6028 pSMB->Reserved2 = 0;
6029 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
6030 offset = param_offset + params;
6031
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006032 data_offset = (char *)pSMB +
6033 offsetof(struct smb_hdr, Protocol) + offset;
6034
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006035 count = sizeof(FILE_UNIX_BASIC_INFO);
6036
6037 pSMB->MaxParameterCount = cpu_to_le16(2);
6038 /* BB find max SMB PDU from sess */
6039 pSMB->MaxDataCount = cpu_to_le16(1000);
6040 pSMB->SetupCount = 1;
6041 pSMB->Reserved3 = 0;
6042 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
6043 byte_count = 3 /* pad */ + params + count;
6044 pSMB->DataCount = cpu_to_le16(count);
6045 pSMB->ParameterCount = cpu_to_le16(params);
6046 pSMB->TotalDataCount = pSMB->DataCount;
6047 pSMB->TotalParameterCount = pSMB->ParameterCount;
6048 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6049 pSMB->DataOffset = cpu_to_le16(offset);
6050 pSMB->Fid = fid;
6051 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6052 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006053 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006054 pSMB->ByteCount = cpu_to_le16(byte_count);
6055
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006056 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006057
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04006058 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07006059 cifs_small_buf_release(pSMB);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006060 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006061 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
6062 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006063
6064 /* Note: On -EAGAIN error only caller can retry on handle based calls
6065 since file handle passed in no longer valid */
6066
6067 return rc;
6068}
6069
6070int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006071CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006072 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006073 const struct cifs_unix_set_info_args *args,
6074 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006075{
6076 TRANSACTION2_SPI_REQ *pSMB = NULL;
6077 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6078 int name_len;
6079 int rc = 0;
6080 int bytes_returned = 0;
6081 FILE_UNIX_BASIC_INFO *data_offset;
6082 __u16 params, param_offset, offset, count, byte_count;
6083
Joe Perchesf96637b2013-05-04 22:12:25 -05006084 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006085setPermsRetry:
6086 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6087 (void **) &pSMBr);
6088 if (rc)
6089 return rc;
6090
6091 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6092 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006093 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06006094 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006095 name_len++; /* trailing null */
6096 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07006097 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006098 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006099 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006100 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006101 }
6102
6103 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006104 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006105 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006106 /* BB find max SMB PDU from sess structure BB */
6107 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006108 pSMB->MaxSetupCount = 0;
6109 pSMB->Reserved = 0;
6110 pSMB->Flags = 0;
6111 pSMB->Timeout = 0;
6112 pSMB->Reserved2 = 0;
6113 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006114 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006115 offset = param_offset + params;
6116 data_offset =
6117 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6118 offset);
6119 memset(data_offset, 0, count);
6120 pSMB->DataOffset = cpu_to_le16(offset);
6121 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6122 pSMB->SetupCount = 1;
6123 pSMB->Reserved3 = 0;
6124 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6125 byte_count = 3 /* pad */ + params + count;
6126 pSMB->ParameterCount = cpu_to_le16(params);
6127 pSMB->DataCount = cpu_to_le16(count);
6128 pSMB->TotalParameterCount = pSMB->ParameterCount;
6129 pSMB->TotalDataCount = pSMB->DataCount;
6130 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6131 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006132 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006133
Jeff Layton654cf142009-07-09 20:02:49 -04006134 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006135
6136 pSMB->ByteCount = cpu_to_le16(byte_count);
6137 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6138 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006139 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006140 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006141
Steve French0d817bc2008-05-22 02:02:03 +00006142 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006143 if (rc == -EAGAIN)
6144 goto setPermsRetry;
6145 return rc;
6146}
6147
Linus Torvalds1da177e2005-04-16 15:20:36 -07006148#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006149/*
6150 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6151 * function used by listxattr and getxattr type calls. When ea_name is set,
6152 * it looks for that attribute name and stuffs that value into the EAData
6153 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6154 * buffer. In both cases, the return value is either the length of the
6155 * resulting data or a negative error code. If EAData is a NULL pointer then
6156 * the data isn't copied to it, but the length is returned.
6157 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006158ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006159CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006160 const unsigned char *searchName, const unsigned char *ea_name,
6161 char *EAData, size_t buf_size,
Steve French67b4c882017-05-12 20:59:10 -05006162 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006163{
6164 /* BB assumes one setup word */
6165 TRANSACTION2_QPI_REQ *pSMB = NULL;
6166 TRANSACTION2_QPI_RSP *pSMBr = NULL;
Steve French67b4c882017-05-12 20:59:10 -05006167 int remap = cifs_remap(cifs_sb);
6168 struct nls_table *nls_codepage = cifs_sb->local_nls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006169 int rc = 0;
6170 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006171 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006172 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006173 struct fea *temp_fea;
6174 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006175 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006176 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006177 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006178
Joe Perchesf96637b2013-05-04 22:12:25 -05006179 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006180QAllEAsRetry:
6181 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6182 (void **) &pSMBr);
6183 if (rc)
6184 return rc;
6185
6186 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006187 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006188 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6189 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006190 list_len++; /* trailing null */
6191 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006192 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006193 list_len = strnlen(searchName, PATH_MAX);
6194 list_len++; /* trailing null */
6195 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006196 }
6197
Jeff Layton6e462b92010-02-10 16:18:26 -05006198 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006199 pSMB->TotalDataCount = 0;
6200 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006201 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006202 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006203 pSMB->MaxSetupCount = 0;
6204 pSMB->Reserved = 0;
6205 pSMB->Flags = 0;
6206 pSMB->Timeout = 0;
6207 pSMB->Reserved2 = 0;
6208 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006209 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006210 pSMB->DataCount = 0;
6211 pSMB->DataOffset = 0;
6212 pSMB->SetupCount = 1;
6213 pSMB->Reserved3 = 0;
6214 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6215 byte_count = params + 1 /* pad */ ;
6216 pSMB->TotalParameterCount = cpu_to_le16(params);
6217 pSMB->ParameterCount = pSMB->TotalParameterCount;
6218 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6219 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006220 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006221 pSMB->ByteCount = cpu_to_le16(byte_count);
6222
6223 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6224 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6225 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006226 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006227 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006228 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006229
6230
6231 /* BB also check enough total bytes returned */
6232 /* BB we need to improve the validity checking
6233 of these trans2 responses */
6234
6235 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006236 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006237 rc = -EIO; /* bad smb */
6238 goto QAllEAsOut;
6239 }
6240
6241 /* check that length of list is not more than bcc */
6242 /* check that each entry does not go beyond length
6243 of list */
6244 /* check that each element of each entry does not
6245 go beyond end of list */
6246 /* validate_trans2_offsets() */
6247 /* BB check if start of smb + data_offset > &bcc+ bcc */
6248
6249 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6250 ea_response_data = (struct fealist *)
6251 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6252
Jeff Layton6e462b92010-02-10 16:18:26 -05006253 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006254 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006255 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006256 cifs_dbg(FYI, "empty EA list returned from server\n");
Steve French60977fc2014-03-25 19:46:36 -05006257 /* didn't find the named attribute */
6258 if (ea_name)
6259 rc = -ENODATA;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006260 goto QAllEAsOut;
6261 }
6262
Jeff Layton0cd126b2010-02-10 16:18:26 -05006263 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006264 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006265 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006266 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006267 rc = -EIO;
6268 goto QAllEAsOut;
6269 }
6270
Jeff Laytonf0d38682010-02-10 16:18:26 -05006271 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006272 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006273 temp_fea = ea_response_data->list;
6274 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006275 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006276 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006277 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006278
Jeff Layton6e462b92010-02-10 16:18:26 -05006279 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006280 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006281 /* make sure we can read name_len and value_len */
6282 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006283 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006284 rc = -EIO;
6285 goto QAllEAsOut;
6286 }
6287
6288 name_len = temp_fea->name_len;
6289 value_len = le16_to_cpu(temp_fea->value_len);
6290 list_len -= name_len + 1 + value_len;
6291 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006292 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006293 rc = -EIO;
6294 goto QAllEAsOut;
6295 }
6296
Jeff Layton31c05192010-02-10 16:18:26 -05006297 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006298 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006299 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006300 temp_ptr += name_len + 1;
6301 rc = value_len;
6302 if (buf_size == 0)
6303 goto QAllEAsOut;
6304 if ((size_t)value_len > buf_size) {
6305 rc = -ERANGE;
6306 goto QAllEAsOut;
6307 }
6308 memcpy(EAData, temp_ptr, value_len);
6309 goto QAllEAsOut;
6310 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006311 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006312 /* account for prefix user. and trailing null */
6313 rc += (5 + 1 + name_len);
6314 if (rc < (int) buf_size) {
6315 memcpy(EAData, "user.", 5);
6316 EAData += 5;
6317 memcpy(EAData, temp_ptr, name_len);
6318 EAData += name_len;
6319 /* null terminate name */
6320 *EAData = 0;
6321 ++EAData;
6322 } else if (buf_size == 0) {
6323 /* skip copy - calc size only */
6324 } else {
6325 /* stop before overrun buffer */
6326 rc = -ERANGE;
6327 break;
6328 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006329 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006330 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006331 temp_fea = (struct fea *)temp_ptr;
6332 }
6333
Jeff Layton31c05192010-02-10 16:18:26 -05006334 /* didn't find the named attribute */
6335 if (ea_name)
6336 rc = -ENODATA;
6337
Jeff Laytonf0d38682010-02-10 16:18:26 -05006338QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006339 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006340 if (rc == -EAGAIN)
6341 goto QAllEAsRetry;
6342
6343 return (ssize_t)rc;
6344}
6345
Linus Torvalds1da177e2005-04-16 15:20:36 -07006346int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006347CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6348 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006349 const __u16 ea_value_len, const struct nls_table *nls_codepage,
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006350 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006351{
6352 struct smb_com_transaction2_spi_req *pSMB = NULL;
6353 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6354 struct fealist *parm_data;
6355 int name_len;
6356 int rc = 0;
6357 int bytes_returned = 0;
6358 __u16 params, param_offset, byte_count, offset, count;
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006359 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006360
Joe Perchesf96637b2013-05-04 22:12:25 -05006361 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006362SetEARetry:
6363 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6364 (void **) &pSMBr);
6365 if (rc)
6366 return rc;
6367
6368 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6369 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006370 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6371 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006372 name_len++; /* trailing null */
6373 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006374 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006375 name_len = strnlen(fileName, PATH_MAX);
6376 name_len++; /* trailing null */
6377 strncpy(pSMB->FileName, fileName, name_len);
6378 }
6379
6380 params = 6 + name_len;
6381
6382 /* done calculating parms using name_len of file name,
6383 now use name_len to calculate length of ea name
6384 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006385 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006386 name_len = 0;
6387 else
Steve French50c2f752007-07-13 00:33:32 +00006388 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006389
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006390 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006391 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006392 /* BB find max SMB PDU from sess */
6393 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006394 pSMB->MaxSetupCount = 0;
6395 pSMB->Reserved = 0;
6396 pSMB->Flags = 0;
6397 pSMB->Timeout = 0;
6398 pSMB->Reserved2 = 0;
6399 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006400 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006401 offset = param_offset + params;
6402 pSMB->InformationLevel =
6403 cpu_to_le16(SMB_SET_FILE_EA);
6404
Arnd Bergmannade7db92018-02-02 16:48:47 +01006405 parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006406 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6407 pSMB->DataOffset = cpu_to_le16(offset);
6408 pSMB->SetupCount = 1;
6409 pSMB->Reserved3 = 0;
6410 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6411 byte_count = 3 /* pad */ + params + count;
6412 pSMB->DataCount = cpu_to_le16(count);
6413 parm_data->list_len = cpu_to_le32(count);
6414 parm_data->list[0].EA_flags = 0;
6415 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006416 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006417 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006418 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006419 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006420 parm_data->list[0].name[name_len] = 0;
6421 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6422 /* caller ensures that ea_value_len is less than 64K but
6423 we need to ensure that it fits within the smb */
6424
Steve French50c2f752007-07-13 00:33:32 +00006425 /*BB add length check to see if it would fit in
6426 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006427 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6428 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006429 memcpy(parm_data->list[0].name+name_len+1,
6430 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006431
6432 pSMB->TotalDataCount = pSMB->DataCount;
6433 pSMB->ParameterCount = cpu_to_le16(params);
6434 pSMB->TotalParameterCount = pSMB->ParameterCount;
6435 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006436 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006437 pSMB->ByteCount = cpu_to_le16(byte_count);
6438 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6439 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006440 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006441 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006442
6443 cifs_buf_release(pSMB);
6444
6445 if (rc == -EAGAIN)
6446 goto SetEARetry;
6447
6448 return rc;
6449}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006450#endif
Steve French0eff0e22011-02-24 05:39:23 +00006451
6452#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6453/*
6454 * Years ago the kernel added a "dnotify" function for Samba server,
6455 * to allow network clients (such as Windows) to display updated
6456 * lists of files in directory listings automatically when
6457 * files are added by one user when another user has the
6458 * same directory open on their desktop. The Linux cifs kernel
6459 * client hooked into the kernel side of this interface for
6460 * the same reason, but ironically when the VFS moved from
6461 * "dnotify" to "inotify" it became harder to plug in Linux
6462 * network file system clients (the most obvious use case
6463 * for notify interfaces is when multiple users can update
6464 * the contents of the same directory - exactly what network
6465 * file systems can do) although the server (Samba) could
6466 * still use it. For the short term we leave the worker
6467 * function ifdeffed out (below) until inotify is fixed
6468 * in the VFS to make it easier to plug in network file
6469 * system clients. If inotify turns out to be permanently
6470 * incompatible for network fs clients, we could instead simply
6471 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6472 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006473int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006474 const int notify_subdirs, const __u16 netfid,
6475 __u32 filter, struct file *pfile, int multishot,
6476 const struct nls_table *nls_codepage)
6477{
6478 int rc = 0;
6479 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6480 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6481 struct dir_notify_req *dnotify_req;
6482 int bytes_returned;
6483
Joe Perchesf96637b2013-05-04 22:12:25 -05006484 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006485 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6486 (void **) &pSMBr);
6487 if (rc)
6488 return rc;
6489
6490 pSMB->TotalParameterCount = 0 ;
6491 pSMB->TotalDataCount = 0;
6492 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006493 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006494 pSMB->MaxSetupCount = 4;
6495 pSMB->Reserved = 0;
6496 pSMB->ParameterOffset = 0;
6497 pSMB->DataCount = 0;
6498 pSMB->DataOffset = 0;
6499 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6500 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6501 pSMB->ParameterCount = pSMB->TotalParameterCount;
6502 if (notify_subdirs)
6503 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6504 pSMB->Reserved2 = 0;
6505 pSMB->CompletionFilter = cpu_to_le32(filter);
6506 pSMB->Fid = netfid; /* file handle always le */
6507 pSMB->ByteCount = 0;
6508
6509 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6510 (struct smb_hdr *)pSMBr, &bytes_returned,
6511 CIFS_ASYNC_OP);
6512 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006513 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006514 } else {
6515 /* Add file to outstanding requests */
6516 /* BB change to kmem cache alloc */
6517 dnotify_req = kmalloc(
6518 sizeof(struct dir_notify_req),
6519 GFP_KERNEL);
6520 if (dnotify_req) {
6521 dnotify_req->Pid = pSMB->hdr.Pid;
6522 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6523 dnotify_req->Mid = pSMB->hdr.Mid;
6524 dnotify_req->Tid = pSMB->hdr.Tid;
6525 dnotify_req->Uid = pSMB->hdr.Uid;
6526 dnotify_req->netfid = netfid;
6527 dnotify_req->pfile = pfile;
6528 dnotify_req->filter = filter;
6529 dnotify_req->multishot = multishot;
6530 spin_lock(&GlobalMid_Lock);
6531 list_add_tail(&dnotify_req->lhead,
6532 &GlobalDnotifyReqList);
6533 spin_unlock(&GlobalMid_Lock);
6534 } else
6535 rc = -ENOMEM;
6536 }
6537 cifs_buf_release(pSMB);
6538 return rc;
6539}
6540#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */