blob: 93408eab92e78988bcf79b715ac77049db643e7f [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;
Deepa Dinamanie37fea52017-05-08 15:59:16 -0700511 struct timespec ts;
512 unsigned long utc = ktime_get_real_seconds();
Jeff Layton2190eca2013-05-26 07:00:57 -0400513 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
514 rsp->SrvTime.Time, 0);
515 cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
Deepa Dinamanie37fea52017-05-08 15:59:16 -0700516 (int)ts.tv_sec, (int)utc,
517 (int)(utc - ts.tv_sec));
518 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;
Steve French50c2f752007-07-13 00:33:32 +0000604 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000605 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
606 count += strlen(protocols[i].name) + 1;
607 /* null at end of source and target buffers anyway */
608 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000609 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 pSMB->ByteCount = cpu_to_le16(count);
611
612 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
613 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000614 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000615 goto neg_err_exit;
616
Jeff Layton9bf67e52010-04-24 07:57:46 -0400617 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500618 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000619 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400620 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000621 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000622 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000623 could not negotiate a common dialect */
624 rc = -EOPNOTSUPP;
625 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000626 } else if (pSMBr->hdr.WordCount == 13) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400627 server->negflavor = CIFS_NEGFLAVOR_LANMAN;
Jeff Layton3f618222013-06-12 19:52:14 -0500628 rc = decode_lanman_negprot_rsp(server, pSMBr);
Jeff Layton9ddec562013-05-26 07:00:58 -0400629 goto signing_check;
Steve French790fe572007-07-07 19:25:05 +0000630 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000631 /* unknown wct */
632 rc = -EOPNOTSUPP;
633 goto neg_err_exit;
634 }
Jeff Layton2190eca2013-05-26 07:00:57 -0400635 /* else wct == 17, NTLM or better */
636
Steve French96daf2b2011-05-27 04:34:02 +0000637 server->sec_mode = pSMBr->SecurityMode;
638 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500639 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000640
Steve French254e55e2006-06-04 05:53:15 +0000641 /* one byte, so no need to convert this or EncryptionKeyLen from
642 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300643 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
644 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400645 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000646 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400647 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000648 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500649 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000650 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000651 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
652 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400653
Jeff Laytone598d1d82013-05-26 07:00:59 -0400654 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
655 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500656 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000657 CIFS_CRYPTO_KEY_SIZE);
Noel Powerf2910952015-05-27 09:22:10 +0100658 } else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
659 server->capabilities & CAP_EXTENDED_SECURITY) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400660 server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
Jeff Layton3f618222013-06-12 19:52:14 -0500661 rc = decode_ext_sec_blob(ses, pSMBr);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400662 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000663 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Laytone598d1d82013-05-26 07:00:59 -0400664 } else {
665 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Steve French254e55e2006-06-04 05:53:15 +0000666 server->capabilities &= ~CAP_EXTENDED_SECURITY;
Jeff Laytone598d1d82013-05-26 07:00:59 -0400667 }
Steve French254e55e2006-06-04 05:53:15 +0000668
669signing_check:
Jeff Layton9ddec562013-05-26 07:00:58 -0400670 if (!rc)
Jeff Layton38d77c52013-05-26 07:01:00 -0400671 rc = cifs_enable_signing(server, ses->sign);
Steve French50c2f752007-07-13 00:33:32 +0000672neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700673 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000674
Joe Perchesf96637b2013-05-04 22:12:25 -0500675 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 return rc;
677}
678
679int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400680CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681{
682 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
Joe Perchesf96637b2013-05-04 22:12:25 -0500685 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500686
687 /* BB: do we need to check this? These should never be NULL. */
688 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
689 return -EIO;
690
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500692 * No need to return error on this operation if tid invalidated and
693 * closed on server already e.g. due to tcp session crashing. Also,
694 * the tcon is no longer on the list, so no need to take lock before
695 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 */
Steve French268875b2009-06-25 00:29:21 +0000697 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000698 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699
Steve French50c2f752007-07-13 00:33:32 +0000700 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700701 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500702 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 return rc;
Steve French133672e2007-11-13 22:41:37 +0000704
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400705 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700706 cifs_small_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500708 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
Steve French50c2f752007-07-13 00:33:32 +0000710 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500711 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 if (rc == -EAGAIN)
713 rc = 0;
714
715 return rc;
716}
717
Jeff Layton766fdbb2011-01-11 07:24:21 -0500718/*
719 * This is a no-op for now. We're not really interested in the reply, but
720 * rather in the fact that the server sent one and that server->lstrp
721 * gets updated.
722 *
723 * FIXME: maybe we should consider checking that the reply matches request?
724 */
725static void
726cifs_echo_callback(struct mid_q_entry *mid)
727{
728 struct TCP_Server_Info *server = mid->callback_data;
729
730 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400731 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500732}
733
734int
735CIFSSMBEcho(struct TCP_Server_Info *server)
736{
737 ECHO_REQ *smb;
738 int rc = 0;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800739 struct kvec iov[2];
740 struct smb_rqst rqst = { .rq_iov = iov,
741 .rq_nvec = 2 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500742
Joe Perchesf96637b2013-05-04 22:12:25 -0500743 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500744
745 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
746 if (rc)
747 return rc;
748
Steve French26c9cb62017-05-02 13:35:20 -0500749 if (server->capabilities & CAP_UNICODE)
750 smb->hdr.Flags2 |= SMBFLG2_UNICODE;
751
Jeff Layton766fdbb2011-01-11 07:24:21 -0500752 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000753 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500754 smb->hdr.WordCount = 1;
755 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400756 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500757 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000758 inc_rfc1001_len(smb, 3);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800759
760 iov[0].iov_len = 4;
761 iov[0].iov_base = smb;
762 iov[1].iov_len = get_rfc1002_length(smb);
763 iov[1].iov_base = (char *)smb + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500764
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -0800765 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400766 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500767 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500768 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500769
770 cifs_small_buf_release(smb);
771
772 return rc;
773}
774
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400776CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 LOGOFF_ANDX_REQ *pSMB;
779 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
Joe Perchesf96637b2013-05-04 22:12:25 -0500781 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500782
783 /*
784 * BB: do we need to check validity of ses and server? They should
785 * always be valid since we have an active reference. If not, that
786 * should probably be a BUG()
787 */
788 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 return -EIO;
790
Steve Frenchd7b619c2010-02-25 05:36:46 +0000791 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000792 if (ses->need_reconnect)
793 goto session_already_dead; /* no need to send SMBlogoff if uid
794 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
796 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000797 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 return rc;
799 }
800
Pavel Shilovsky88257362012-05-23 14:01:59 +0400801 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700802
Jeff Layton38d77c52013-05-26 07:01:00 -0400803 if (ses->server->sign)
804 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805
806 pSMB->hdr.Uid = ses->Suid;
807
808 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400809 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700810 cifs_small_buf_release(pSMB);
Steve French3b795212008-11-13 19:45:32 +0000811session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000812 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813
814 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000815 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 error */
817 if (rc == -EAGAIN)
818 rc = 0;
819 return rc;
820}
821
822int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400823CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
824 const char *fileName, __u16 type,
825 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000826{
827 TRANSACTION2_SPI_REQ *pSMB = NULL;
828 TRANSACTION2_SPI_RSP *pSMBr = NULL;
829 struct unlink_psx_rq *pRqD;
830 int name_len;
831 int rc = 0;
832 int bytes_returned = 0;
833 __u16 params, param_offset, offset, byte_count;
834
Joe Perchesf96637b2013-05-04 22:12:25 -0500835 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000836PsxDelete:
837 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
838 (void **) &pSMBr);
839 if (rc)
840 return rc;
841
842 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
843 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600844 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
845 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000846 name_len++; /* trailing null */
847 name_len *= 2;
848 } else { /* BB add path length overrun check */
849 name_len = strnlen(fileName, PATH_MAX);
850 name_len++; /* trailing null */
851 strncpy(pSMB->FileName, fileName, name_len);
852 }
853
854 params = 6 + name_len;
855 pSMB->MaxParameterCount = cpu_to_le16(2);
856 pSMB->MaxDataCount = 0; /* BB double check this with jra */
857 pSMB->MaxSetupCount = 0;
858 pSMB->Reserved = 0;
859 pSMB->Flags = 0;
860 pSMB->Timeout = 0;
861 pSMB->Reserved2 = 0;
862 param_offset = offsetof(struct smb_com_transaction2_spi_req,
863 InformationLevel) - 4;
864 offset = param_offset + params;
865
866 /* Setup pointer to Request Data (inode type) */
867 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
868 pRqD->type = cpu_to_le16(type);
869 pSMB->ParameterOffset = cpu_to_le16(param_offset);
870 pSMB->DataOffset = cpu_to_le16(offset);
871 pSMB->SetupCount = 1;
872 pSMB->Reserved3 = 0;
873 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
874 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
875
876 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
877 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
878 pSMB->ParameterCount = cpu_to_le16(params);
879 pSMB->TotalParameterCount = pSMB->ParameterCount;
880 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
881 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000882 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000883 pSMB->ByteCount = cpu_to_le16(byte_count);
884 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
885 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000886 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500887 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000888 cifs_buf_release(pSMB);
889
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400890 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000891
892 if (rc == -EAGAIN)
893 goto PsxDelete;
894
895 return rc;
896}
897
898int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700899CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
900 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901{
902 DELETE_FILE_REQ *pSMB = NULL;
903 DELETE_FILE_RSP *pSMBr = NULL;
904 int rc = 0;
905 int bytes_returned;
906 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500907 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908
909DelFileRetry:
910 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
911 (void **) &pSMBr);
912 if (rc)
913 return rc;
914
915 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700916 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
917 PATH_MAX, cifs_sb->local_nls,
918 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 name_len++; /* trailing null */
920 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700921 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700922 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700924 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 }
926 pSMB->SearchAttributes =
927 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
928 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000929 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 pSMB->ByteCount = cpu_to_le16(name_len + 1);
931 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
932 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400933 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000934 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500935 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
937 cifs_buf_release(pSMB);
938 if (rc == -EAGAIN)
939 goto DelFileRetry;
940
941 return rc;
942}
943
944int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400945CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
946 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947{
948 DELETE_DIRECTORY_REQ *pSMB = NULL;
949 DELETE_DIRECTORY_RSP *pSMBr = NULL;
950 int rc = 0;
951 int bytes_returned;
952 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500953 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954
Joe Perchesf96637b2013-05-04 22:12:25 -0500955 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956RmDirRetry:
957 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
958 (void **) &pSMBr);
959 if (rc)
960 return rc;
961
962 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400963 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
964 PATH_MAX, cifs_sb->local_nls,
965 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 name_len++; /* trailing null */
967 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700968 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400969 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400971 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 }
973
974 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000975 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 pSMB->ByteCount = cpu_to_le16(name_len + 1);
977 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
978 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400979 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000980 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500981 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
983 cifs_buf_release(pSMB);
984 if (rc == -EAGAIN)
985 goto RmDirRetry;
986 return rc;
987}
988
989int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300990CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
991 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992{
993 int rc = 0;
994 CREATE_DIRECTORY_REQ *pSMB = NULL;
995 CREATE_DIRECTORY_RSP *pSMBr = NULL;
996 int bytes_returned;
997 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500998 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
Joe Perchesf96637b2013-05-04 22:12:25 -05001000 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001MkDirRetry:
1002 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1003 (void **) &pSMBr);
1004 if (rc)
1005 return rc;
1006
1007 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06001008 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001009 PATH_MAX, cifs_sb->local_nls,
1010 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 name_len++; /* trailing null */
1012 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001013 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 name_len = strnlen(name, PATH_MAX);
1015 name_len++; /* trailing null */
1016 strncpy(pSMB->DirName, name, name_len);
1017 }
1018
1019 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001020 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1022 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1023 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001024 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001025 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001026 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001027
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 cifs_buf_release(pSMB);
1029 if (rc == -EAGAIN)
1030 goto MkDirRetry;
1031 return rc;
1032}
1033
Steve French2dd29d32007-04-23 22:07:35 +00001034int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001035CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1036 __u32 posix_flags, __u64 mode, __u16 *netfid,
1037 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1038 const char *name, const struct nls_table *nls_codepage,
1039 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001040{
1041 TRANSACTION2_SPI_REQ *pSMB = NULL;
1042 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1043 int name_len;
1044 int rc = 0;
1045 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001046 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001047 OPEN_PSX_REQ *pdata;
1048 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001049
Joe Perchesf96637b2013-05-04 22:12:25 -05001050 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001051PsxCreat:
1052 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1053 (void **) &pSMBr);
1054 if (rc)
1055 return rc;
1056
1057 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1058 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001059 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1060 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001061 name_len++; /* trailing null */
1062 name_len *= 2;
1063 } else { /* BB improve the check for buffer overruns BB */
1064 name_len = strnlen(name, PATH_MAX);
1065 name_len++; /* trailing null */
1066 strncpy(pSMB->FileName, name, name_len);
1067 }
1068
1069 params = 6 + name_len;
1070 count = sizeof(OPEN_PSX_REQ);
1071 pSMB->MaxParameterCount = cpu_to_le16(2);
1072 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1073 pSMB->MaxSetupCount = 0;
1074 pSMB->Reserved = 0;
1075 pSMB->Flags = 0;
1076 pSMB->Timeout = 0;
1077 pSMB->Reserved2 = 0;
1078 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001079 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001080 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001081 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001082 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001083 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001084 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001085 pdata->OpenFlags = cpu_to_le32(*pOplock);
1086 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1087 pSMB->DataOffset = cpu_to_le16(offset);
1088 pSMB->SetupCount = 1;
1089 pSMB->Reserved3 = 0;
1090 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1091 byte_count = 3 /* pad */ + params + count;
1092
1093 pSMB->DataCount = cpu_to_le16(count);
1094 pSMB->ParameterCount = cpu_to_le16(params);
1095 pSMB->TotalDataCount = pSMB->DataCount;
1096 pSMB->TotalParameterCount = pSMB->ParameterCount;
1097 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1098 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001099 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001100 pSMB->ByteCount = cpu_to_le16(byte_count);
1101 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1102 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1103 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001104 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001105 goto psx_create_err;
1106 }
1107
Joe Perchesf96637b2013-05-04 22:12:25 -05001108 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001109 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1110
Jeff Layton820a8032011-05-04 08:05:26 -04001111 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001112 rc = -EIO; /* bad smb */
1113 goto psx_create_err;
1114 }
1115
1116 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001117 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001118 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001119
Steve French2dd29d32007-04-23 22:07:35 +00001120 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001121 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001122 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1123 /* Let caller know file was created so we can set the mode. */
1124 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001125 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001126 *pOplock |= CIFS_CREATE_ACTION;
1127 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001128 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1129 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001130 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001131 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001132 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001133 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001134 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001135 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001136 goto psx_create_err;
1137 }
Steve French50c2f752007-07-13 00:33:32 +00001138 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001139 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001140 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001141 }
Steve French2dd29d32007-04-23 22:07:35 +00001142
1143psx_create_err:
1144 cifs_buf_release(pSMB);
1145
Steve French65bc98b2009-07-10 15:27:25 +00001146 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001147 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001148 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001149 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001150
1151 if (rc == -EAGAIN)
1152 goto PsxCreat;
1153
Steve French50c2f752007-07-13 00:33:32 +00001154 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001155}
1156
Steve Frencha9d02ad2005-08-24 23:06:05 -07001157static __u16 convert_disposition(int disposition)
1158{
1159 __u16 ofun = 0;
1160
1161 switch (disposition) {
1162 case FILE_SUPERSEDE:
1163 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1164 break;
1165 case FILE_OPEN:
1166 ofun = SMBOPEN_OAPPEND;
1167 break;
1168 case FILE_CREATE:
1169 ofun = SMBOPEN_OCREATE;
1170 break;
1171 case FILE_OPEN_IF:
1172 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1173 break;
1174 case FILE_OVERWRITE:
1175 ofun = SMBOPEN_OTRUNC;
1176 break;
1177 case FILE_OVERWRITE_IF:
1178 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1179 break;
1180 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001181 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001182 ofun = SMBOPEN_OAPPEND; /* regular open */
1183 }
1184 return ofun;
1185}
1186
Jeff Layton35fc37d2008-05-14 10:22:03 -07001187static int
1188access_flags_to_smbopen_mode(const int access_flags)
1189{
1190 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1191
1192 if (masked_flags == GENERIC_READ)
1193 return SMBOPEN_READ;
1194 else if (masked_flags == GENERIC_WRITE)
1195 return SMBOPEN_WRITE;
1196
1197 /* just go for read/write */
1198 return SMBOPEN_READWRITE;
1199}
1200
Steve Frencha9d02ad2005-08-24 23:06:05 -07001201int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001202SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001203 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001204 const int access_flags, const int create_options, __u16 *netfid,
1205 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001206 const struct nls_table *nls_codepage, int remap)
1207{
1208 int rc = -EACCES;
1209 OPENX_REQ *pSMB = NULL;
1210 OPENX_RSP *pSMBr = NULL;
1211 int bytes_returned;
1212 int name_len;
1213 __u16 count;
1214
1215OldOpenRetry:
1216 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1217 (void **) &pSMBr);
1218 if (rc)
1219 return rc;
1220
1221 pSMB->AndXCommand = 0xFF; /* none */
1222
1223 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1224 count = 1; /* account for one byte pad to word boundary */
1225 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001226 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1227 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001228 name_len++; /* trailing null */
1229 name_len *= 2;
1230 } else { /* BB improve check for buffer overruns BB */
1231 count = 0; /* no pad */
1232 name_len = strnlen(fileName, PATH_MAX);
1233 name_len++; /* trailing null */
1234 strncpy(pSMB->fileName, fileName, name_len);
1235 }
1236 if (*pOplock & REQ_OPLOCK)
1237 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001238 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001239 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001240
Steve Frencha9d02ad2005-08-24 23:06:05 -07001241 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001242 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001243 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1244 /* set file as system file if special file such
1245 as fifo and server expecting SFU style and
1246 no Unix extensions */
1247
Steve French790fe572007-07-07 19:25:05 +00001248 if (create_options & CREATE_OPTION_SPECIAL)
1249 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001250 else /* BB FIXME BB */
1251 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001252
Jeff Layton67750fb2008-05-09 22:28:02 +00001253 if (create_options & CREATE_OPTION_READONLY)
1254 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001255
1256 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001257/* pSMB->CreateOptions = cpu_to_le32(create_options &
1258 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001259 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001260
1261 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001262 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001263 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001264 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001265
1266 pSMB->ByteCount = cpu_to_le16(count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001267 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001268 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001269 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001270 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001271 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001272 } else {
1273 /* BB verify if wct == 15 */
1274
Steve French582d21e2008-05-13 04:54:12 +00001275/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001276
1277 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1278 /* Let caller know file was created so we can set the mode. */
1279 /* Do we care about the CreateAction in any other cases? */
1280 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001281/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001282 *pOplock |= CIFS_CREATE_ACTION; */
1283 /* BB FIXME END */
1284
Steve French790fe572007-07-07 19:25:05 +00001285 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001286 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1287 pfile_info->LastAccessTime = 0; /* BB fixme */
1288 pfile_info->LastWriteTime = 0; /* BB fixme */
1289 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001290 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001291 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001292 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001293 pfile_info->AllocationSize =
1294 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1295 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001296 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001297 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001298 }
1299 }
1300
1301 cifs_buf_release(pSMB);
1302 if (rc == -EAGAIN)
1303 goto OldOpenRetry;
1304 return rc;
1305}
1306
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307int
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001308CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
1309 FILE_ALL_INFO *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310{
1311 int rc = -EACCES;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001312 OPEN_REQ *req = NULL;
1313 OPEN_RSP *rsp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 int bytes_returned;
1315 int name_len;
1316 __u16 count;
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001317 struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
1318 struct cifs_tcon *tcon = oparms->tcon;
Steve French2baa2682014-09-27 02:19:01 -05001319 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001320 const struct nls_table *nls = cifs_sb->local_nls;
1321 int create_options = oparms->create_options;
1322 int desired_access = oparms->desired_access;
1323 int disposition = oparms->disposition;
1324 const char *path = oparms->path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325
1326openRetry:
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001327 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
1328 (void **)&rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 if (rc)
1330 return rc;
1331
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001332 /* no commands go after this */
1333 req->AndXCommand = 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001335 if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
1336 /* account for one byte pad to word boundary */
1337 count = 1;
1338 name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
1339 path, PATH_MAX, nls, remap);
1340 /* trailing null */
1341 name_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 name_len *= 2;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001343 req->NameLength = cpu_to_le16(name_len);
1344 } else {
1345 /* BB improve check for buffer overruns BB */
1346 /* no pad */
1347 count = 0;
1348 name_len = strnlen(path, PATH_MAX);
1349 /* trailing null */
1350 name_len++;
1351 req->NameLength = cpu_to_le16(name_len);
1352 strncpy(req->fileName, path, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 }
Jeff Layton67750fb2008-05-09 22:28:02 +00001354
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001355 if (*oplock & REQ_OPLOCK)
1356 req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1357 else if (*oplock & REQ_BATCHOPLOCK)
1358 req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1359
1360 req->DesiredAccess = cpu_to_le32(desired_access);
1361 req->AllocationSize = 0;
1362
1363 /*
1364 * Set file as system file if special file such as fifo and server
1365 * expecting SFU style and no Unix extensions.
1366 */
1367 if (create_options & CREATE_OPTION_SPECIAL)
1368 req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1369 else
1370 req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1371
1372 /*
1373 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
1374 * sensitive checks for other servers such as Samba.
1375 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 if (tcon->ses->capabilities & CAP_UNIX)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001377 req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378
Jeff Layton67750fb2008-05-09 22:28:02 +00001379 if (create_options & CREATE_OPTION_READONLY)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001380 req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
Jeff Layton67750fb2008-05-09 22:28:02 +00001381
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001382 req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1383 req->CreateDisposition = cpu_to_le32(disposition);
1384 req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1385
Steve French09d1db52005-04-28 22:41:08 -07001386 /* BB Expirement with various impersonation levels and verify */
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001387 req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1388 req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389
1390 count += name_len;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001391 inc_rfc1001_len(req, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001393 req->ByteCount = cpu_to_le16(count);
1394 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
1395 (struct smb_hdr *)rsp, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001396 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001398 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001399 cifs_buf_release(req);
1400 if (rc == -EAGAIN)
1401 goto openRetry;
1402 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001404
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001405 /* 1 byte no need to le_to_cpu */
1406 *oplock = rsp->OplockLevel;
1407 /* cifs fid stays in le */
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001408 oparms->fid->netfid = rsp->Fid;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001409
1410 /* Let caller know file was created so we can set the mode. */
1411 /* Do we care about the CreateAction in any other cases? */
1412 if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
1413 *oplock |= CIFS_CREATE_ACTION;
1414
1415 if (buf) {
1416 /* copy from CreationTime to Attributes */
1417 memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
1418 /* the file_info buf is endian converted by caller */
1419 buf->AllocationSize = rsp->AllocationSize;
1420 buf->EndOfFile = rsp->EndOfFile;
1421 buf->NumberOfLinks = cpu_to_le32(1);
1422 buf->DeletePending = 0;
1423 }
1424
1425 cifs_buf_release(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 return rc;
1427}
1428
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001429/*
1430 * Discard any remaining data in the current SMB. To do this, we borrow the
1431 * current bigbuf.
1432 */
Pavel Shilovskyc42a6ab2016-11-17 16:20:23 -08001433int
Pavel Shilovsky350be252017-04-10 10:31:33 -07001434cifs_discard_remaining_data(struct TCP_Server_Info *server)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001435{
Ronnie Sahlberg05432e22018-04-09 18:06:31 +10001436 unsigned int rfclen = server->pdu_size;
1437 int remaining = rfclen + server->vals->header_preamble_size -
1438 server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001439
1440 while (remaining > 0) {
1441 int length;
1442
1443 length = cifs_read_from_socket(server, server->bigbuf,
1444 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001445 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001446 if (length < 0)
1447 return length;
1448 server->total_read += length;
1449 remaining -= length;
1450 }
1451
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001452 return 0;
1453}
1454
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001455static int
1456cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1457{
1458 int length;
1459 struct cifs_readdata *rdata = mid->callback_data;
1460
Pavel Shilovsky350be252017-04-10 10:31:33 -07001461 length = cifs_discard_remaining_data(server);
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001462 dequeue_mid(mid, rdata->result);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001463 mid->resp_buf = server->smallbuf;
1464 server->smallbuf = NULL;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001465 return length;
1466}
1467
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001468int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001469cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1470{
1471 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001472 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001473 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001474 char *buf = server->smallbuf;
Ronnie Sahlberg2e964672018-04-09 18:06:26 +10001475 unsigned int buflen = server->pdu_size +
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +11001476 server->vals->header_preamble_size;
Long Li74dcf412017-11-22 17:38:46 -07001477 bool use_rdma_mr = false;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001478
Joe Perchesf96637b2013-05-04 22:12:25 -05001479 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1480 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001481
1482 /*
1483 * read the rest of READ_RSP header (sans Data array), or whatever we
1484 * can if there's not enough data. At this point, we've read down to
1485 * the Mid.
1486 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001487 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001488 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001489
Al Viroa6137302016-01-09 19:37:16 -05001490 length = cifs_read_from_socket(server,
1491 buf + HEADER_SIZE(server) - 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001492 if (length < 0)
1493 return length;
1494 server->total_read += length;
1495
Pavel Shilovsky511c54a2017-07-08 14:32:00 -07001496 if (server->ops->is_session_expired &&
1497 server->ops->is_session_expired(buf)) {
1498 cifs_reconnect(server);
1499 wake_up(&server->response_q);
1500 return -1;
1501 }
1502
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001503 if (server->ops->is_status_pending &&
1504 server->ops->is_status_pending(buf, server, 0)) {
Pavel Shilovsky350be252017-04-10 10:31:33 -07001505 cifs_discard_remaining_data(server);
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001506 return -1;
1507 }
1508
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001509 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001510 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001511 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001512 cifs_dbg(FYI, "%s: server returned error %d\n",
1513 __func__, rdata->result);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001514 return cifs_readv_discard(server, mid);
1515 }
1516
1517 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001518 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001519 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1520 __func__, server->total_read,
1521 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001522 rdata->result = -EIO;
1523 return cifs_readv_discard(server, mid);
1524 }
1525
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +11001526 data_offset = server->ops->read_data_offset(buf) +
1527 server->vals->header_preamble_size;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001528 if (data_offset < server->total_read) {
1529 /*
1530 * win2k8 sometimes sends an offset of 0 when the read
1531 * is beyond the EOF. Treat it as if the data starts just after
1532 * the header.
1533 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001534 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1535 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001536 data_offset = server->total_read;
1537 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1538 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001539 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1540 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001541 rdata->result = -EIO;
1542 return cifs_readv_discard(server, mid);
1543 }
1544
Joe Perchesf96637b2013-05-04 22:12:25 -05001545 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1546 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001547
1548 len = data_offset - server->total_read;
1549 if (len > 0) {
1550 /* read any junk before data into the rest of smallbuf */
Al Viroa6137302016-01-09 19:37:16 -05001551 length = cifs_read_from_socket(server,
1552 buf + server->total_read, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001553 if (length < 0)
1554 return length;
1555 server->total_read += length;
1556 }
1557
1558 /* set up first iov for signature check */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001559 rdata->iov[0].iov_base = buf;
1560 rdata->iov[0].iov_len = 4;
1561 rdata->iov[1].iov_base = buf + 4;
1562 rdata->iov[1].iov_len = server->total_read - 4;
1563 cifs_dbg(FYI, "0: iov_base=%p iov_len=%u\n",
1564 rdata->iov[0].iov_base, server->total_read);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001565
1566 /* how much data is in the response? */
Long Li74dcf412017-11-22 17:38:46 -07001567#ifdef CONFIG_CIFS_SMB_DIRECT
1568 use_rdma_mr = rdata->mr;
1569#endif
1570 data_len = server->ops->read_data_length(buf, use_rdma_mr);
1571 if (!use_rdma_mr && (data_offset + data_len > buflen)) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001572 /* data_len is corrupt -- discard frame */
1573 rdata->result = -EIO;
1574 return cifs_readv_discard(server, mid);
1575 }
1576
Jeff Layton8321fec2012-09-19 06:22:32 -07001577 length = rdata->read_into_pages(server, rdata, data_len);
1578 if (length < 0)
1579 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001580
Jeff Layton8321fec2012-09-19 06:22:32 -07001581 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001582
Joe Perchesf96637b2013-05-04 22:12:25 -05001583 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1584 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001585
1586 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001587 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001588 return cifs_readv_discard(server, mid);
1589
1590 dequeue_mid(mid, false);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001591 mid->resp_buf = server->smallbuf;
1592 server->smallbuf = NULL;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001593 return length;
1594}
1595
1596static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001597cifs_readv_callback(struct mid_q_entry *mid)
1598{
1599 struct cifs_readdata *rdata = mid->callback_data;
1600 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1601 struct TCP_Server_Info *server = tcon->ses->server;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001602 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1603 .rq_nvec = 2,
Jeff Layton8321fec2012-09-19 06:22:32 -07001604 .rq_pages = rdata->pages,
1605 .rq_npages = rdata->nr_pages,
1606 .rq_pagesz = rdata->pagesz,
1607 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001608
Joe Perchesf96637b2013-05-04 22:12:25 -05001609 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1610 __func__, mid->mid, mid->mid_state, rdata->result,
1611 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001612
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001613 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001614 case MID_RESPONSE_RECEIVED:
1615 /* result already set, check signature */
Jeff Layton38d77c52013-05-26 07:01:00 -04001616 if (server->sign) {
Steve French985e4ff02012-08-03 09:42:45 -05001617 int rc = 0;
1618
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001619 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001620 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001621 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001622 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1623 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001624 }
1625 /* FIXME: should this be counted toward the initiating task? */
Pavel Shilovsky34a54d62014-07-10 10:03:29 +04001626 task_io_account_read(rdata->got_bytes);
1627 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001628 break;
1629 case MID_REQUEST_SUBMITTED:
1630 case MID_RETRY_NEEDED:
1631 rdata->result = -EAGAIN;
Pavel Shilovskyd913ed12014-07-10 11:31:48 +04001632 if (server->sign && rdata->got_bytes)
1633 /* reset bytes number since we can not check a sign */
1634 rdata->got_bytes = 0;
1635 /* FIXME: should this be counted toward the initiating task? */
1636 task_io_account_read(rdata->got_bytes);
1637 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001638 break;
1639 default:
1640 rdata->result = -EIO;
1641 }
1642
Jeff Laytonda472fc2012-03-23 14:40:53 -04001643 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001644 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001645 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001646}
1647
1648/* cifs_async_readv - send an async write, and set up mid to handle result */
1649int
1650cifs_async_readv(struct cifs_readdata *rdata)
1651{
1652 int rc;
1653 READ_REQ *smb = NULL;
1654 int wct;
1655 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001656 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1657 .rq_nvec = 2 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001658
Joe Perchesf96637b2013-05-04 22:12:25 -05001659 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1660 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001661
1662 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1663 wct = 12;
1664 else {
1665 wct = 10; /* old style read */
1666 if ((rdata->offset >> 32) > 0) {
1667 /* can not handle this big offset for old */
1668 return -EIO;
1669 }
1670 }
1671
1672 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1673 if (rc)
1674 return rc;
1675
1676 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1677 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1678
1679 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001680 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001681 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1682 if (wct == 12)
1683 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1684 smb->Remaining = 0;
1685 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1686 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1687 if (wct == 12)
1688 smb->ByteCount = 0;
1689 else {
1690 /* old style read */
1691 struct smb_com_readx_req *smbr =
1692 (struct smb_com_readx_req *)smb;
1693 smbr->ByteCount = 0;
1694 }
1695
1696 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001697 rdata->iov[0].iov_base = smb;
1698 rdata->iov[0].iov_len = 4;
1699 rdata->iov[1].iov_base = (char *)smb + 4;
1700 rdata->iov[1].iov_len = get_rfc1002_length(smb);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001701
Jeff Layton6993f742012-05-16 07:13:17 -04001702 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001703 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -08001704 cifs_readv_callback, NULL, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001705
1706 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001707 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001708 else
1709 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001710
1711 cifs_small_buf_release(smb);
1712 return rc;
1713}
1714
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001716CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1717 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718{
1719 int rc = -EACCES;
1720 READ_REQ *pSMB = NULL;
1721 READ_RSP *pSMBr = NULL;
1722 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001723 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001724 int resp_buf_type = 0;
1725 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001726 struct kvec rsp_iov;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001727 __u32 pid = io_parms->pid;
1728 __u16 netfid = io_parms->netfid;
1729 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001730 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001731 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732
Joe Perchesf96637b2013-05-04 22:12:25 -05001733 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001734 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001735 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001736 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001737 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001738 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001739 /* can not handle this big offset for old */
1740 return -EIO;
1741 }
1742 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743
1744 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001745 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 if (rc)
1747 return rc;
1748
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001749 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1750 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1751
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 /* tcon and ses pointer are checked in smb_init */
1753 if (tcon->ses->server == NULL)
1754 return -ECONNABORTED;
1755
Steve Frenchec637e32005-12-12 20:53:18 -08001756 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001758 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001759 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001760 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001761
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 pSMB->Remaining = 0;
1763 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1764 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001765 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001766 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1767 else {
1768 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001769 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001770 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001771 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001772 }
Steve Frenchec637e32005-12-12 20:53:18 -08001773
1774 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001775 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001776 rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
1777 CIFS_LOG_ERROR, &rsp_iov);
1778 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001779 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001780 pSMBr = (READ_RSP *)rsp_iov.iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001782 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 } else {
1784 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1785 data_length = data_length << 16;
1786 data_length += le16_to_cpu(pSMBr->DataLength);
1787 *nbytes = data_length;
1788
1789 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001790 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001792 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001793 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 rc = -EIO;
1795 *nbytes = 0;
1796 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001797 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001798 le16_to_cpu(pSMBr->DataOffset);
1799/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001800 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001801 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001802 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001803 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001804 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 }
1806 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807
Steve French790fe572007-07-07 19:25:05 +00001808 if (*buf) {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001809 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French790fe572007-07-07 19:25:05 +00001810 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001811 /* return buffer to caller to free */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001812 *buf = rsp_iov.iov_base;
Steve French790fe572007-07-07 19:25:05 +00001813 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001814 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001815 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001816 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001817 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001818
1819 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 since file handle passed in no longer valid */
1821 return rc;
1822}
1823
Steve Frenchec637e32005-12-12 20:53:18 -08001824
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001826CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Al Virodbbab322016-09-05 17:53:43 -04001827 unsigned int *nbytes, const char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828{
1829 int rc = -EACCES;
1830 WRITE_REQ *pSMB = NULL;
1831 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001832 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 __u32 bytes_sent;
1834 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001835 __u32 pid = io_parms->pid;
1836 __u16 netfid = io_parms->netfid;
1837 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001838 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001839 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840
Steve Frencha24e2d72010-04-03 17:20:21 +00001841 *nbytes = 0;
1842
Joe Perchesf96637b2013-05-04 22:12:25 -05001843 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001844 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001845 return -ECONNABORTED;
1846
Steve French790fe572007-07-07 19:25:05 +00001847 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001848 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001849 else {
Steve French1c955182005-08-30 20:58:07 -07001850 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001851 if ((offset >> 32) > 0) {
1852 /* can not handle big offset for old srv */
1853 return -EIO;
1854 }
1855 }
Steve French1c955182005-08-30 20:58:07 -07001856
1857 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 (void **) &pSMBr);
1859 if (rc)
1860 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001861
1862 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1863 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1864
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 /* tcon and ses pointer are checked in smb_init */
1866 if (tcon->ses->server == NULL)
1867 return -ECONNABORTED;
1868
1869 pSMB->AndXCommand = 0xFF; /* none */
1870 pSMB->Fid = netfid;
1871 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001872 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001873 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001874
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 pSMB->Reserved = 0xFFFFFFFF;
1876 pSMB->WriteMode = 0;
1877 pSMB->Remaining = 0;
1878
Steve French50c2f752007-07-13 00:33:32 +00001879 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 can send more if LARGE_WRITE_X capability returned by the server and if
1881 our buffer is big enough or if we convert to iovecs on socket writes
1882 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001883 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1885 } else {
1886 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1887 & ~0xFF;
1888 }
1889
1890 if (bytes_sent > count)
1891 bytes_sent = count;
1892 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001893 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001894 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001895 memcpy(pSMB->Data, buf, bytes_sent);
Al Virodbbab322016-09-05 17:53:43 -04001896 else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 /* No buffer */
1898 cifs_buf_release(pSMB);
1899 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001900 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001901 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001902 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001903 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001904 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001905
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1907 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001908 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001909
Steve French790fe572007-07-07 19:25:05 +00001910 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001911 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001912 else { /* old style write has byte count 4 bytes earlier
1913 so 4 bytes pad */
1914 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001915 (struct smb_com_writex_req *)pSMB;
1916 pSMBW->ByteCount = cpu_to_le16(byte_count);
1917 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918
1919 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Al Virodbbab322016-09-05 17:53:43 -04001920 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001921 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001923 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 } else {
1925 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1926 *nbytes = (*nbytes) << 16;
1927 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301928
1929 /*
1930 * Mask off high 16 bits when bytes written as returned by the
1931 * server is greater than bytes requested by the client. Some
1932 * OS/2 servers are known to set incorrect CountHigh values.
1933 */
1934 if (*nbytes > count)
1935 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 }
1937
1938 cifs_buf_release(pSMB);
1939
Steve French50c2f752007-07-13 00:33:32 +00001940 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 since file handle passed in no longer valid */
1942
1943 return rc;
1944}
1945
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001946void
1947cifs_writedata_release(struct kref *refcount)
1948{
1949 struct cifs_writedata *wdata = container_of(refcount,
1950 struct cifs_writedata, refcount);
Long Lidb223a52017-11-22 17:38:45 -07001951#ifdef CONFIG_CIFS_SMB_DIRECT
1952 if (wdata->mr) {
1953 smbd_deregister_mr(wdata->mr);
1954 wdata->mr = NULL;
1955 }
1956#endif
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001957
1958 if (wdata->cfile)
1959 cifsFileInfo_put(wdata->cfile);
1960
Long Li8e7360f2018-05-30 12:47:56 -07001961 kvfree(wdata->pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001962 kfree(wdata);
1963}
1964
1965/*
1966 * Write failed with a retryable error. Resend the write request. It's also
1967 * possible that the page was redirtied so re-clean the page.
1968 */
1969static void
1970cifs_writev_requeue(struct cifs_writedata *wdata)
1971{
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001972 int i, rc = 0;
David Howells2b0143b2015-03-17 22:25:59 +00001973 struct inode *inode = d_inode(wdata->cfile->dentry);
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001974 struct TCP_Server_Info *server;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001975 unsigned int rest_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001976
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001977 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1978 i = 0;
1979 rest_len = wdata->bytes;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001980 do {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001981 struct cifs_writedata *wdata2;
1982 unsigned int j, nr_pages, wsize, tailsz, cur_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001983
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001984 wsize = server->ops->wp_retry_size(inode);
1985 if (wsize < rest_len) {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001986 nr_pages = wsize / PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001987 if (!nr_pages) {
1988 rc = -ENOTSUPP;
1989 break;
1990 }
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001991 cur_len = nr_pages * PAGE_SIZE;
1992 tailsz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001993 } else {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001994 nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001995 cur_len = rest_len;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001996 tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE;
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001997 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001998
1999 wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
2000 if (!wdata2) {
2001 rc = -ENOMEM;
2002 break;
2003 }
2004
2005 for (j = 0; j < nr_pages; j++) {
2006 wdata2->pages[j] = wdata->pages[i + j];
2007 lock_page(wdata2->pages[j]);
2008 clear_page_dirty_for_io(wdata2->pages[j]);
2009 }
2010
2011 wdata2->sync_mode = wdata->sync_mode;
2012 wdata2->nr_pages = nr_pages;
2013 wdata2->offset = page_offset(wdata2->pages[0]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002014 wdata2->pagesz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002015 wdata2->tailsz = tailsz;
2016 wdata2->bytes = cur_len;
2017
2018 wdata2->cfile = find_writable_file(CIFS_I(inode), false);
2019 if (!wdata2->cfile) {
2020 cifs_dbg(VFS, "No writable handles for inode\n");
2021 rc = -EBADF;
2022 break;
2023 }
2024 wdata2->pid = wdata2->cfile->pid;
2025 rc = server->ops->async_writev(wdata2, cifs_writedata_release);
2026
2027 for (j = 0; j < nr_pages; j++) {
2028 unlock_page(wdata2->pages[j]);
2029 if (rc != 0 && rc != -EAGAIN) {
2030 SetPageError(wdata2->pages[j]);
2031 end_page_writeback(wdata2->pages[j]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002032 put_page(wdata2->pages[j]);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002033 }
2034 }
2035
2036 if (rc) {
2037 kref_put(&wdata2->refcount, cifs_writedata_release);
2038 if (rc == -EAGAIN)
2039 continue;
2040 break;
2041 }
2042
2043 rest_len -= cur_len;
2044 i += nr_pages;
2045 } while (i < wdata->nr_pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002046
2047 mapping_set_error(inode->i_mapping, rc);
2048 kref_put(&wdata->refcount, cifs_writedata_release);
2049}
2050
Jeff Laytonc2e87642012-03-23 14:40:55 -04002051void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002052cifs_writev_complete(struct work_struct *work)
2053{
2054 struct cifs_writedata *wdata = container_of(work,
2055 struct cifs_writedata, work);
David Howells2b0143b2015-03-17 22:25:59 +00002056 struct inode *inode = d_inode(wdata->cfile->dentry);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002057 int i = 0;
2058
2059 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04002060 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002061 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04002062 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002063 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2064 wdata->bytes);
2065 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2066 return cifs_writev_requeue(wdata);
2067
2068 for (i = 0; i < wdata->nr_pages; i++) {
2069 struct page *page = wdata->pages[i];
2070 if (wdata->result == -EAGAIN)
2071 __set_page_dirty_nobuffers(page);
2072 else if (wdata->result < 0)
2073 SetPageError(page);
2074 end_page_writeback(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002075 put_page(page);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002076 }
2077 if (wdata->result != -EAGAIN)
2078 mapping_set_error(inode->i_mapping, wdata->result);
2079 kref_put(&wdata->refcount, cifs_writedata_release);
2080}
2081
2082struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04002083cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002084{
Long Li8e7360f2018-05-30 12:47:56 -07002085 struct page **pages =
Kees Cook6396bb22018-06-12 14:03:40 -07002086 kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
Long Li8e7360f2018-05-30 12:47:56 -07002087 if (pages)
2088 return cifs_writedata_direct_alloc(pages, complete);
2089
2090 return NULL;
2091}
2092
2093struct cifs_writedata *
2094cifs_writedata_direct_alloc(struct page **pages, work_func_t complete)
2095{
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002096 struct cifs_writedata *wdata;
2097
Long Li8e7360f2018-05-30 12:47:56 -07002098 wdata = kzalloc(sizeof(*wdata), GFP_NOFS);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002099 if (wdata != NULL) {
Long Li8e7360f2018-05-30 12:47:56 -07002100 wdata->pages = pages;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002101 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04002102 INIT_LIST_HEAD(&wdata->list);
2103 init_completion(&wdata->done);
2104 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002105 }
2106 return wdata;
2107}
2108
2109/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002110 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002111 * workqueue completion task.
2112 */
2113static void
2114cifs_writev_callback(struct mid_q_entry *mid)
2115{
2116 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002117 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002118 unsigned int written;
2119 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2120
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002121 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002122 case MID_RESPONSE_RECEIVED:
2123 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2124 if (wdata->result != 0)
2125 break;
2126
2127 written = le16_to_cpu(smb->CountHigh);
2128 written <<= 16;
2129 written += le16_to_cpu(smb->Count);
2130 /*
2131 * Mask off high 16 bits when bytes written as returned
2132 * by the server is greater than bytes requested by the
2133 * client. OS/2 servers are known to set incorrect
2134 * CountHigh values.
2135 */
2136 if (written > wdata->bytes)
2137 written &= 0xFFFF;
2138
2139 if (written < wdata->bytes)
2140 wdata->result = -ENOSPC;
2141 else
2142 wdata->bytes = written;
2143 break;
2144 case MID_REQUEST_SUBMITTED:
2145 case MID_RETRY_NEEDED:
2146 wdata->result = -EAGAIN;
2147 break;
2148 default:
2149 wdata->result = -EIO;
2150 break;
2151 }
2152
Jeff Laytonda472fc2012-03-23 14:40:53 -04002153 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002154 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002155 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002156}
2157
2158/* cifs_async_writev - send an async write, and set up mid to handle result */
2159int
Steve French4a5c80d2014-02-07 20:45:12 -06002160cifs_async_writev(struct cifs_writedata *wdata,
2161 void (*release)(struct kref *kref))
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002162{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002163 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002164 WRITE_REQ *smb = NULL;
2165 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002166 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002167 struct kvec iov[2];
Jeff Laytonfec344e2012-09-18 16:20:35 -07002168 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002169
2170 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2171 wct = 14;
2172 } else {
2173 wct = 12;
2174 if (wdata->offset >> 32 > 0) {
2175 /* can not handle big offset for old srv */
2176 return -EIO;
2177 }
2178 }
2179
2180 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2181 if (rc)
2182 goto async_writev_out;
2183
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002184 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2185 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002186
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002187 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002188 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002189 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2190 if (wct == 14)
2191 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2192 smb->Reserved = 0xFFFFFFFF;
2193 smb->WriteMode = 0;
2194 smb->Remaining = 0;
2195
2196 smb->DataOffset =
2197 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2198
2199 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002200 iov[0].iov_len = 4;
2201 iov[0].iov_base = smb;
2202 iov[1].iov_len = get_rfc1002_length(smb) + 1;
2203 iov[1].iov_base = (char *)smb + 4;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002204
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002205 rqst.rq_iov = iov;
2206 rqst.rq_nvec = 2;
Jeff Laytoneddb0792012-09-18 16:20:35 -07002207 rqst.rq_pages = wdata->pages;
2208 rqst.rq_npages = wdata->nr_pages;
2209 rqst.rq_pagesz = wdata->pagesz;
2210 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002211
Joe Perchesf96637b2013-05-04 22:12:25 -05002212 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2213 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002214
2215 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2216 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2217
2218 if (wct == 14) {
2219 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2220 put_bcc(wdata->bytes + 1, &smb->hdr);
2221 } else {
2222 /* wct == 12 */
2223 struct smb_com_writex_req *smbw =
2224 (struct smb_com_writex_req *)smb;
2225 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2226 put_bcc(wdata->bytes + 5, &smbw->hdr);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002227 iov[1].iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002228 }
2229
2230 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002231 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -08002232 cifs_writev_callback, NULL, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002233
2234 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002235 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002236 else
Steve French4a5c80d2014-02-07 20:45:12 -06002237 kref_put(&wdata->refcount, release);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002238
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002239async_writev_out:
2240 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002241 return rc;
2242}
2243
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002244int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002245CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002246 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247{
2248 int rc = -EACCES;
2249 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002250 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002251 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002252 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002253 __u32 pid = io_parms->pid;
2254 __u16 netfid = io_parms->netfid;
2255 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002256 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002257 unsigned int count = io_parms->length;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002258 struct kvec rsp_iov;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002260 *nbytes = 0;
2261
Joe Perchesf96637b2013-05-04 22:12:25 -05002262 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002263
Steve French4c3130e2008-12-09 00:28:16 +00002264 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002265 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002266 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002267 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002268 if ((offset >> 32) > 0) {
2269 /* can not handle big offset for old srv */
2270 return -EIO;
2271 }
2272 }
Steve French8cc64c62005-10-03 13:49:43 -07002273 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 if (rc)
2275 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002276
2277 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2278 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2279
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 /* tcon and ses pointer are checked in smb_init */
2281 if (tcon->ses->server == NULL)
2282 return -ECONNABORTED;
2283
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002284 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 pSMB->Fid = netfid;
2286 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002287 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002288 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 pSMB->Reserved = 0xFFFFFFFF;
2290 pSMB->WriteMode = 0;
2291 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002292
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002294 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295
Steve French3e844692005-10-03 13:37:24 -07002296 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2297 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002298 /* header + 1 byte pad */
2299 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002300 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002301 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002302 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002303 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002304 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002305 pSMB->ByteCount = cpu_to_le16(count + 1);
2306 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002307 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002308 (struct smb_com_writex_req *)pSMB;
2309 pSMBW->ByteCount = cpu_to_le16(count + 5);
2310 }
Steve French3e844692005-10-03 13:37:24 -07002311 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002312 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002313 iov[0].iov_len = smb_hdr_len + 4;
2314 else /* wct == 12 pad bigger by four bytes */
2315 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002316
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002317 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
2318 &rsp_iov);
2319 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002320 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002322 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002323 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002324 /* presumably this can not happen, but best to be safe */
2325 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002326 } else {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002327 WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002328 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2329 *nbytes = (*nbytes) << 16;
2330 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302331
2332 /*
2333 * Mask off high 16 bits when bytes written as returned by the
2334 * server is greater than bytes requested by the client. OS/2
2335 * servers are known to set incorrect CountHigh values.
2336 */
2337 if (*nbytes > count)
2338 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002339 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002341 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342
Steve French50c2f752007-07-13 00:33:32 +00002343 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344 since file handle passed in no longer valid */
2345
2346 return rc;
2347}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002348
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002349int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2350 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002351 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2352{
2353 int rc = 0;
2354 LOCK_REQ *pSMB = NULL;
2355 struct kvec iov[2];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002356 struct kvec rsp_iov;
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002357 int resp_buf_type;
2358 __u16 count;
2359
Joe Perchesf96637b2013-05-04 22:12:25 -05002360 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2361 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002362
2363 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2364 if (rc)
2365 return rc;
2366
2367 pSMB->Timeout = 0;
2368 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2369 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2370 pSMB->LockType = lock_type;
2371 pSMB->AndXCommand = 0xFF; /* none */
2372 pSMB->Fid = netfid; /* netfid stays le */
2373
2374 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2375 inc_rfc1001_len(pSMB, count);
2376 pSMB->ByteCount = cpu_to_le16(count);
2377
2378 iov[0].iov_base = (char *)pSMB;
2379 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2380 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2381 iov[1].iov_base = (char *)buf;
2382 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2383
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002384 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002385 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP,
2386 &rsp_iov);
2387 cifs_small_buf_release(pSMB);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002388 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002389 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002390
2391 return rc;
2392}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002393
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002395CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002396 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002398 const __u32 numLock, const __u8 lockType,
2399 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400{
2401 int rc = 0;
2402 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002403/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002405 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 __u16 count;
2407
Joe Perchesf96637b2013-05-04 22:12:25 -05002408 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2409 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002410 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2411
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 if (rc)
2413 return rc;
2414
Steve French790fe572007-07-07 19:25:05 +00002415 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002416 /* no response expected */
2417 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002419 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002420 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2422 } else {
2423 pSMB->Timeout = 0;
2424 }
2425
2426 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2427 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2428 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002429 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 pSMB->AndXCommand = 0xFF; /* none */
2431 pSMB->Fid = smb_file_id; /* netfid stays le */
2432
Steve French790fe572007-07-07 19:25:05 +00002433 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002434 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 /* BB where to store pid high? */
2436 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2437 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2438 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2439 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2440 count = sizeof(LOCKING_ANDX_RANGE);
2441 } else {
2442 /* oplock break */
2443 count = 0;
2444 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002445 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 pSMB->ByteCount = cpu_to_le16(count);
2447
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002448 if (waitFlag)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002449 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002450 (struct smb_hdr *) pSMB, &bytes_returned);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002451 else
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002452 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002453 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002454 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002455 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002456 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457
Steve French50c2f752007-07-13 00:33:32 +00002458 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 since file handle passed in no longer valid */
2460 return rc;
2461}
2462
2463int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002464CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002465 const __u16 smb_file_id, const __u32 netpid,
2466 const loff_t start_offset, const __u64 len,
2467 struct file_lock *pLockData, const __u16 lock_type,
2468 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002469{
2470 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2471 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002472 struct cifs_posix_lock *parm_data;
2473 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002474 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002475 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002476 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002477 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002478 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002479 struct kvec rsp_iov;
Steve French08547b02006-02-28 22:39:25 +00002480
Joe Perchesf96637b2013-05-04 22:12:25 -05002481 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002482
Steve French08547b02006-02-28 22:39:25 +00002483 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2484
2485 if (rc)
2486 return rc;
2487
2488 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2489
Steve French50c2f752007-07-13 00:33:32 +00002490 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002491 pSMB->MaxSetupCount = 0;
2492 pSMB->Reserved = 0;
2493 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002494 pSMB->Reserved2 = 0;
2495 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2496 offset = param_offset + params;
2497
Steve French08547b02006-02-28 22:39:25 +00002498 count = sizeof(struct cifs_posix_lock);
2499 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002500 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002501 pSMB->SetupCount = 1;
2502 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002503 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002504 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2505 else
2506 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2507 byte_count = 3 /* pad */ + params + count;
2508 pSMB->DataCount = cpu_to_le16(count);
2509 pSMB->ParameterCount = cpu_to_le16(params);
2510 pSMB->TotalDataCount = pSMB->DataCount;
2511 pSMB->TotalParameterCount = pSMB->ParameterCount;
2512 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002513 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002514 (((char *) &pSMB->hdr.Protocol) + offset);
2515
2516 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002517 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002518 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002519 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002520 pSMB->Timeout = cpu_to_le32(-1);
2521 } else
2522 pSMB->Timeout = 0;
2523
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002524 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002525 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002526 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002527
2528 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002529 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002530 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2531 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002532 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002533 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002534 if (waitFlag) {
2535 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2536 (struct smb_hdr *) pSMBr, &bytes_returned);
2537 } else {
Steve French133672e2007-11-13 22:41:37 +00002538 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002539 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002540 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002541 &resp_buf_type, timeout, &rsp_iov);
2542 pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002543 }
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002544 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002545
Steve French08547b02006-02-28 22:39:25 +00002546 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002547 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002548 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002549 /* lock structure can be returned on get */
2550 __u16 data_offset;
2551 __u16 data_count;
2552 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002553
Jeff Layton820a8032011-05-04 08:05:26 -04002554 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002555 rc = -EIO; /* bad smb */
2556 goto plk_err_exit;
2557 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002558 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2559 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002560 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002561 rc = -EIO;
2562 goto plk_err_exit;
2563 }
2564 parm_data = (struct cifs_posix_lock *)
2565 ((char *)&pSMBr->hdr.Protocol + data_offset);
Fabian Frederickbc09d142014-12-10 15:41:15 -08002566 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002567 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002568 else {
2569 if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002570 cpu_to_le16(CIFS_RDLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002571 pLockData->fl_type = F_RDLCK;
2572 else if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002573 cpu_to_le16(CIFS_WRLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002574 pLockData->fl_type = F_WRLCK;
2575
Steve French5443d132011-03-13 05:08:25 +00002576 pLockData->fl_start = le64_to_cpu(parm_data->start);
2577 pLockData->fl_end = pLockData->fl_start +
2578 le64_to_cpu(parm_data->length) - 1;
Benjamin Coddington9d5b86a2017-07-16 10:28:22 -04002579 pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002580 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002581 }
Steve French50c2f752007-07-13 00:33:32 +00002582
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002583plk_err_exit:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002584 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French133672e2007-11-13 22:41:37 +00002585
Steve French08547b02006-02-28 22:39:25 +00002586 /* Note: On -EAGAIN error only caller can retry on handle based calls
2587 since file handle passed in no longer valid */
2588
2589 return rc;
2590}
2591
2592
2593int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002594CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595{
2596 int rc = 0;
2597 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002598 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599
2600/* do not retry on dead session on close */
2601 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002602 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 return 0;
2604 if (rc)
2605 return rc;
2606
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002608 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002610 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002611 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002612 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002614 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002616 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 }
2618 }
2619
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002621 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 rc = 0;
2623
2624 return rc;
2625}
2626
2627int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002628CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002629{
2630 int rc = 0;
2631 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002632 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002633
2634 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2635 if (rc)
2636 return rc;
2637
2638 pSMB->FileID = (__u16) smb_file_id;
2639 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002640 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002641 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002642 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002643 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002644 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002645
2646 return rc;
2647}
2648
2649int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002650CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002651 const char *from_name, const char *to_name,
2652 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653{
2654 int rc = 0;
2655 RENAME_REQ *pSMB = NULL;
2656 RENAME_RSP *pSMBr = NULL;
2657 int bytes_returned;
2658 int name_len, name_len2;
2659 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002660 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661
Joe Perchesf96637b2013-05-04 22:12:25 -05002662 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663renameRetry:
2664 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2665 (void **) &pSMBr);
2666 if (rc)
2667 return rc;
2668
2669 pSMB->BufferFormat = 0x04;
2670 pSMB->SearchAttributes =
2671 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2672 ATTR_DIRECTORY);
2673
2674 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002675 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2676 from_name, PATH_MAX,
2677 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 name_len++; /* trailing null */
2679 name_len *= 2;
2680 pSMB->OldFileName[name_len] = 0x04; /* pad */
2681 /* protocol requires ASCII signature byte on Unicode string */
2682 pSMB->OldFileName[name_len + 1] = 0x00;
2683 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002684 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002685 to_name, PATH_MAX, cifs_sb->local_nls,
2686 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2688 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002689 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002690 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002692 strncpy(pSMB->OldFileName, from_name, name_len);
2693 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 name_len2++; /* trailing null */
2695 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002696 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 name_len2++; /* trailing null */
2698 name_len2++; /* signature byte */
2699 }
2700
2701 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002702 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 pSMB->ByteCount = cpu_to_le16(count);
2704
2705 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2706 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002707 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002708 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002709 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 cifs_buf_release(pSMB);
2712
2713 if (rc == -EAGAIN)
2714 goto renameRetry;
2715
2716 return rc;
2717}
2718
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002719int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002720 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002721 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722{
2723 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2724 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002725 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 char *data_offset;
2727 char dummy_string[30];
2728 int rc = 0;
2729 int bytes_returned = 0;
2730 int len_of_str;
2731 __u16 params, param_offset, offset, count, byte_count;
2732
Joe Perchesf96637b2013-05-04 22:12:25 -05002733 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2735 (void **) &pSMBr);
2736 if (rc)
2737 return rc;
2738
2739 params = 6;
2740 pSMB->MaxSetupCount = 0;
2741 pSMB->Reserved = 0;
2742 pSMB->Flags = 0;
2743 pSMB->Timeout = 0;
2744 pSMB->Reserved2 = 0;
2745 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2746 offset = param_offset + params;
2747
2748 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2749 rename_info = (struct set_file_rename *) data_offset;
2750 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002751 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 pSMB->SetupCount = 1;
2753 pSMB->Reserved3 = 0;
2754 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2755 byte_count = 3 /* pad */ + params;
2756 pSMB->ParameterCount = cpu_to_le16(params);
2757 pSMB->TotalParameterCount = pSMB->ParameterCount;
2758 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2759 pSMB->DataOffset = cpu_to_le16(offset);
2760 /* construct random name ".cifs_tmp<inodenum><mid>" */
2761 rename_info->overwrite = cpu_to_le32(1);
2762 rename_info->root_fid = 0;
2763 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002764 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002765 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002766 len_of_str =
2767 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002768 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002770 len_of_str =
2771 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002772 target_name, PATH_MAX, nls_codepage,
2773 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 }
2775 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002776 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 byte_count += count;
2778 pSMB->DataCount = cpu_to_le16(count);
2779 pSMB->TotalDataCount = pSMB->DataCount;
2780 pSMB->Fid = netfid;
2781 pSMB->InformationLevel =
2782 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2783 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002784 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 pSMB->ByteCount = cpu_to_le16(byte_count);
2786 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002787 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002788 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002789 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002790 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2791 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002792
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 cifs_buf_release(pSMB);
2794
2795 /* Note: On -EAGAIN error only caller can retry on handle based calls
2796 since file handle passed in no longer valid */
2797
2798 return rc;
2799}
2800
2801int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002802CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2803 const char *fromName, const __u16 target_tid, const char *toName,
2804 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805{
2806 int rc = 0;
2807 COPY_REQ *pSMB = NULL;
2808 COPY_RSP *pSMBr = NULL;
2809 int bytes_returned;
2810 int name_len, name_len2;
2811 __u16 count;
2812
Joe Perchesf96637b2013-05-04 22:12:25 -05002813 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814copyRetry:
2815 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2816 (void **) &pSMBr);
2817 if (rc)
2818 return rc;
2819
2820 pSMB->BufferFormat = 0x04;
2821 pSMB->Tid2 = target_tid;
2822
2823 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2824
2825 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002826 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2827 fromName, PATH_MAX, nls_codepage,
2828 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829 name_len++; /* trailing null */
2830 name_len *= 2;
2831 pSMB->OldFileName[name_len] = 0x04; /* pad */
2832 /* protocol requires ASCII signature byte on Unicode string */
2833 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002834 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002835 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2836 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2838 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002839 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 name_len = strnlen(fromName, PATH_MAX);
2841 name_len++; /* trailing null */
2842 strncpy(pSMB->OldFileName, fromName, name_len);
2843 name_len2 = strnlen(toName, PATH_MAX);
2844 name_len2++; /* trailing null */
2845 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2846 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2847 name_len2++; /* trailing null */
2848 name_len2++; /* signature byte */
2849 }
2850
2851 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002852 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 pSMB->ByteCount = cpu_to_le16(count);
2854
2855 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2856 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2857 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002858 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2859 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 }
Steve French0d817bc2008-05-22 02:02:03 +00002861 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862
2863 if (rc == -EAGAIN)
2864 goto copyRetry;
2865
2866 return rc;
2867}
2868
2869int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002870CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 const char *fromName, const char *toName,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002872 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873{
2874 TRANSACTION2_SPI_REQ *pSMB = NULL;
2875 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2876 char *data_offset;
2877 int name_len;
2878 int name_len_target;
2879 int rc = 0;
2880 int bytes_returned = 0;
2881 __u16 params, param_offset, offset, byte_count;
2882
Joe Perchesf96637b2013-05-04 22:12:25 -05002883 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884createSymLinkRetry:
2885 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2886 (void **) &pSMBr);
2887 if (rc)
2888 return rc;
2889
2890 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2891 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002892 cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
2893 /* find define for this maxpathcomponent */
2894 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 name_len++; /* trailing null */
2896 name_len *= 2;
2897
Steve French50c2f752007-07-13 00:33:32 +00002898 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 name_len = strnlen(fromName, PATH_MAX);
2900 name_len++; /* trailing null */
2901 strncpy(pSMB->FileName, fromName, name_len);
2902 }
2903 params = 6 + name_len;
2904 pSMB->MaxSetupCount = 0;
2905 pSMB->Reserved = 0;
2906 pSMB->Flags = 0;
2907 pSMB->Timeout = 0;
2908 pSMB->Reserved2 = 0;
2909 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002910 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911 offset = param_offset + params;
2912
2913 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2914 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2915 name_len_target =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002916 cifsConvertToUTF16((__le16 *) data_offset, toName,
2917 /* find define for this maxpathcomponent */
2918 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919 name_len_target++; /* trailing null */
2920 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002921 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 name_len_target = strnlen(toName, PATH_MAX);
2923 name_len_target++; /* trailing null */
2924 strncpy(data_offset, toName, name_len_target);
2925 }
2926
2927 pSMB->MaxParameterCount = cpu_to_le16(2);
2928 /* BB find exact max on data count below from sess */
2929 pSMB->MaxDataCount = cpu_to_le16(1000);
2930 pSMB->SetupCount = 1;
2931 pSMB->Reserved3 = 0;
2932 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2933 byte_count = 3 /* pad */ + params + name_len_target;
2934 pSMB->DataCount = cpu_to_le16(name_len_target);
2935 pSMB->ParameterCount = cpu_to_le16(params);
2936 pSMB->TotalDataCount = pSMB->DataCount;
2937 pSMB->TotalParameterCount = pSMB->ParameterCount;
2938 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2939 pSMB->DataOffset = cpu_to_le16(offset);
2940 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2941 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002942 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 pSMB->ByteCount = cpu_to_le16(byte_count);
2944 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2945 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002946 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002947 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002948 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2949 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950
Steve French0d817bc2008-05-22 02:02:03 +00002951 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952
2953 if (rc == -EAGAIN)
2954 goto createSymLinkRetry;
2955
2956 return rc;
2957}
2958
2959int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002960CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002962 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963{
2964 TRANSACTION2_SPI_REQ *pSMB = NULL;
2965 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2966 char *data_offset;
2967 int name_len;
2968 int name_len_target;
2969 int rc = 0;
2970 int bytes_returned = 0;
2971 __u16 params, param_offset, offset, byte_count;
2972
Joe Perchesf96637b2013-05-04 22:12:25 -05002973 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974createHardLinkRetry:
2975 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2976 (void **) &pSMBr);
2977 if (rc)
2978 return rc;
2979
2980 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002981 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2982 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 name_len++; /* trailing null */
2984 name_len *= 2;
2985
Steve French50c2f752007-07-13 00:33:32 +00002986 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 name_len = strnlen(toName, PATH_MAX);
2988 name_len++; /* trailing null */
2989 strncpy(pSMB->FileName, toName, name_len);
2990 }
2991 params = 6 + name_len;
2992 pSMB->MaxSetupCount = 0;
2993 pSMB->Reserved = 0;
2994 pSMB->Flags = 0;
2995 pSMB->Timeout = 0;
2996 pSMB->Reserved2 = 0;
2997 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002998 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 offset = param_offset + params;
3000
3001 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3002 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3003 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06003004 cifsConvertToUTF16((__le16 *) data_offset, fromName,
3005 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 name_len_target++; /* trailing null */
3007 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003008 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 name_len_target = strnlen(fromName, PATH_MAX);
3010 name_len_target++; /* trailing null */
3011 strncpy(data_offset, fromName, name_len_target);
3012 }
3013
3014 pSMB->MaxParameterCount = cpu_to_le16(2);
3015 /* BB find exact max on data count below from sess*/
3016 pSMB->MaxDataCount = cpu_to_le16(1000);
3017 pSMB->SetupCount = 1;
3018 pSMB->Reserved3 = 0;
3019 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3020 byte_count = 3 /* pad */ + params + name_len_target;
3021 pSMB->ParameterCount = cpu_to_le16(params);
3022 pSMB->TotalParameterCount = pSMB->ParameterCount;
3023 pSMB->DataCount = cpu_to_le16(name_len_target);
3024 pSMB->TotalDataCount = pSMB->DataCount;
3025 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3026 pSMB->DataOffset = cpu_to_le16(offset);
3027 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
3028 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003029 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030 pSMB->ByteCount = cpu_to_le16(byte_count);
3031 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3032 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003033 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003034 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003035 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
3036 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037
3038 cifs_buf_release(pSMB);
3039 if (rc == -EAGAIN)
3040 goto createHardLinkRetry;
3041
3042 return rc;
3043}
3044
3045int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003046CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07003047 const char *from_name, const char *to_name,
3048 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049{
3050 int rc = 0;
3051 NT_RENAME_REQ *pSMB = NULL;
3052 RENAME_RSP *pSMBr = NULL;
3053 int bytes_returned;
3054 int name_len, name_len2;
3055 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05003056 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057
Joe Perchesf96637b2013-05-04 22:12:25 -05003058 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059winCreateHardLinkRetry:
3060
3061 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
3062 (void **) &pSMBr);
3063 if (rc)
3064 return rc;
3065
3066 pSMB->SearchAttributes =
3067 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3068 ATTR_DIRECTORY);
3069 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3070 pSMB->ClusterCount = 0;
3071
3072 pSMB->BufferFormat = 0x04;
3073
3074 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3075 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07003076 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
3077 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 name_len++; /* trailing null */
3079 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05003080
3081 /* protocol specifies ASCII buffer format (0x04) for unicode */
3082 pSMB->OldFileName[name_len] = 0x04;
3083 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06003085 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07003086 to_name, PATH_MAX, cifs_sb->local_nls,
3087 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3089 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00003090 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003091 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003093 strncpy(pSMB->OldFileName, from_name, name_len);
3094 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 name_len2++; /* trailing null */
3096 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003097 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098 name_len2++; /* trailing null */
3099 name_len2++; /* signature byte */
3100 }
3101
3102 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003103 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 pSMB->ByteCount = cpu_to_le16(count);
3105
3106 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3107 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003108 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003109 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003110 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003111
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 cifs_buf_release(pSMB);
3113 if (rc == -EAGAIN)
3114 goto winCreateHardLinkRetry;
3115
3116 return rc;
3117}
3118
3119int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003120CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003121 const unsigned char *searchName, char **symlinkinfo,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003122 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123{
3124/* SMB_QUERY_FILE_UNIX_LINK */
3125 TRANSACTION2_QPI_REQ *pSMB = NULL;
3126 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3127 int rc = 0;
3128 int bytes_returned;
3129 int name_len;
3130 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003131 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132
Joe Perchesf96637b2013-05-04 22:12:25 -05003133 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134
3135querySymLinkRetry:
3136 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3137 (void **) &pSMBr);
3138 if (rc)
3139 return rc;
3140
3141 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3142 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003143 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3144 searchName, PATH_MAX, nls_codepage,
3145 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146 name_len++; /* trailing null */
3147 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003148 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149 name_len = strnlen(searchName, PATH_MAX);
3150 name_len++; /* trailing null */
3151 strncpy(pSMB->FileName, searchName, name_len);
3152 }
3153
3154 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3155 pSMB->TotalDataCount = 0;
3156 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003157 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 pSMB->MaxSetupCount = 0;
3159 pSMB->Reserved = 0;
3160 pSMB->Flags = 0;
3161 pSMB->Timeout = 0;
3162 pSMB->Reserved2 = 0;
3163 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003164 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 pSMB->DataCount = 0;
3166 pSMB->DataOffset = 0;
3167 pSMB->SetupCount = 1;
3168 pSMB->Reserved3 = 0;
3169 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3170 byte_count = params + 1 /* pad */ ;
3171 pSMB->TotalParameterCount = cpu_to_le16(params);
3172 pSMB->ParameterCount = pSMB->TotalParameterCount;
3173 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3174 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003175 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 pSMB->ByteCount = cpu_to_le16(byte_count);
3177
3178 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3179 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3180 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003181 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182 } else {
3183 /* decode response */
3184
3185 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003187 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003188 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003190 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003191 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192
Jeff Layton460b9692009-04-30 07:17:56 -04003193 data_start = ((char *) &pSMBr->hdr.Protocol) +
3194 le16_to_cpu(pSMBr->t2.DataOffset);
3195
Steve French0e0d2cf2009-05-01 05:27:32 +00003196 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3197 is_unicode = true;
3198 else
3199 is_unicode = false;
3200
Steve French737b7582005-04-28 22:41:06 -07003201 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003202 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3203 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003204 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003205 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206 }
3207 }
3208 cifs_buf_release(pSMB);
3209 if (rc == -EAGAIN)
3210 goto querySymLinkRetry;
3211 return rc;
3212}
3213
Steve Frenchc52a95542011-02-24 06:16:22 +00003214/*
3215 * Recent Windows versions now create symlinks more frequently
3216 * and they use the "reparse point" mechanism below. We can of course
3217 * do symlinks nicely to Samba and other servers which support the
3218 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3219 * "MF" symlinks optionally, but for recent Windows we really need to
3220 * reenable the code below and fix the cifs_symlink callers to handle this.
3221 * In the interim this code has been moved to its own config option so
3222 * it is not compiled in by default until callers fixed up and more tested.
3223 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003225CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3226 __u16 fid, char **symlinkinfo,
3227 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228{
3229 int rc = 0;
3230 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003231 struct smb_com_transaction_ioctl_req *pSMB;
3232 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003233 bool is_unicode;
3234 unsigned int sub_len;
3235 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003236 struct reparse_symlink_data *reparse_buf;
3237 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003238 __u32 data_offset, data_count;
3239 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003241 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3243 (void **) &pSMBr);
3244 if (rc)
3245 return rc;
3246
3247 pSMB->TotalParameterCount = 0 ;
3248 pSMB->TotalDataCount = 0;
3249 pSMB->MaxParameterCount = cpu_to_le32(2);
3250 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003251 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252 pSMB->MaxSetupCount = 4;
3253 pSMB->Reserved = 0;
3254 pSMB->ParameterOffset = 0;
3255 pSMB->DataCount = 0;
3256 pSMB->DataOffset = 0;
3257 pSMB->SetupCount = 4;
3258 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3259 pSMB->ParameterCount = pSMB->TotalParameterCount;
3260 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3261 pSMB->IsFsctl = 1; /* FSCTL */
3262 pSMB->IsRootFlag = 0;
3263 pSMB->Fid = fid; /* file handle always le */
3264 pSMB->ByteCount = 0;
3265
3266 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3267 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3268 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003269 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003270 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 }
Steve French989c7e52009-05-02 05:32:20 +00003272
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003273 data_offset = le32_to_cpu(pSMBr->DataOffset);
3274 data_count = le32_to_cpu(pSMBr->DataCount);
3275 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3276 /* BB also check enough total bytes returned */
3277 rc = -EIO; /* bad smb */
3278 goto qreparse_out;
3279 }
3280 if (!data_count || (data_count > 2048)) {
3281 rc = -EIO;
3282 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3283 goto qreparse_out;
3284 }
3285 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003286 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003287 ((char *)&pSMBr->hdr.Protocol + data_offset);
3288 if ((char *)reparse_buf >= end_of_smb) {
3289 rc = -EIO;
3290 goto qreparse_out;
3291 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003292 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3293 cifs_dbg(FYI, "NFS style reparse tag\n");
3294 posix_buf = (struct reparse_posix_data *)reparse_buf;
3295
3296 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3297 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3298 le64_to_cpu(posix_buf->InodeType));
3299 rc = -EOPNOTSUPP;
3300 goto qreparse_out;
3301 }
3302 is_unicode = true;
3303 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3304 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3305 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3306 rc = -EIO;
3307 goto qreparse_out;
3308 }
3309 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3310 sub_len, is_unicode, nls_codepage);
3311 goto qreparse_out;
3312 } else if (reparse_buf->ReparseTag !=
3313 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3314 rc = -EOPNOTSUPP;
3315 goto qreparse_out;
3316 }
3317
3318 /* Reparse tag is NTFS symlink */
3319 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3320 reparse_buf->PathBuffer;
3321 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3322 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003323 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3324 rc = -EIO;
3325 goto qreparse_out;
3326 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003327 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3328 is_unicode = true;
3329 else
3330 is_unicode = false;
3331
3332 /* BB FIXME investigate remapping reserved chars here */
3333 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3334 nls_codepage);
3335 if (!*symlinkinfo)
3336 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003338 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003340 /*
3341 * Note: On -EAGAIN error only caller can retry on handle based calls
3342 * since file handle passed in no longer valid.
3343 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344 return rc;
3345}
3346
Steve Frenchc7f508a2013-10-14 15:27:32 -05003347int
3348CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3349 __u16 fid)
3350{
3351 int rc = 0;
3352 int bytes_returned;
3353 struct smb_com_transaction_compr_ioctl_req *pSMB;
3354 struct smb_com_transaction_ioctl_rsp *pSMBr;
3355
3356 cifs_dbg(FYI, "Set compression for %u\n", fid);
3357 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3358 (void **) &pSMBr);
3359 if (rc)
3360 return rc;
3361
3362 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3363
3364 pSMB->TotalParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003365 pSMB->TotalDataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003366 pSMB->MaxParameterCount = 0;
3367 pSMB->MaxDataCount = 0;
3368 pSMB->MaxSetupCount = 4;
3369 pSMB->Reserved = 0;
3370 pSMB->ParameterOffset = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003371 pSMB->DataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003372 pSMB->DataOffset =
3373 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3374 compression_state) - 4); /* 84 */
3375 pSMB->SetupCount = 4;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003376 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003377 pSMB->ParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003378 pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003379 pSMB->IsFsctl = 1; /* FSCTL */
3380 pSMB->IsRootFlag = 0;
3381 pSMB->Fid = fid; /* file handle always le */
3382 /* 3 byte pad, followed by 2 byte compress state */
Fabian Frederickbc09d142014-12-10 15:41:15 -08003383 pSMB->ByteCount = cpu_to_le16(5);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003384 inc_rfc1001_len(pSMB, 5);
3385
3386 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3387 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3388 if (rc)
3389 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3390
3391 cifs_buf_release(pSMB);
3392
3393 /*
3394 * Note: On -EAGAIN error only caller can retry on handle based calls
3395 * since file handle passed in no longer valid.
3396 */
3397 return rc;
3398}
3399
3400
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401#ifdef CONFIG_CIFS_POSIX
3402
3403/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003404static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
Steve French50c2f752007-07-13 00:33:32 +00003405 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406{
3407 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003408 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3409 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3410 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003411/*
3412 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3413 ace->e_perm, ace->e_tag, ace->e_id);
3414*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415
3416 return;
3417}
3418
3419/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003420static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3421 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422{
3423 int size = 0;
3424 int i;
3425 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003426 struct cifs_posix_ace *pACE;
3427 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003428 struct posix_acl_xattr_header *local_acl = (void *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429
3430 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3431 return -EOPNOTSUPP;
3432
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003433 if (acl_type == ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 count = le16_to_cpu(cifs_acl->access_entry_count);
3435 pACE = &cifs_acl->ace_array[0];
3436 size = sizeof(struct cifs_posix_acl);
3437 size += sizeof(struct cifs_posix_ace) * count;
3438 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003439 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003440 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3441 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442 return -EINVAL;
3443 }
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003444 } else if (acl_type == ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445 count = le16_to_cpu(cifs_acl->access_entry_count);
3446 size = sizeof(struct cifs_posix_acl);
3447 size += sizeof(struct cifs_posix_ace) * count;
3448/* skip past access ACEs to get to default ACEs */
3449 pACE = &cifs_acl->ace_array[count];
3450 count = le16_to_cpu(cifs_acl->default_entry_count);
3451 size += sizeof(struct cifs_posix_ace) * count;
3452 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003453 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 return -EINVAL;
3455 } else {
3456 /* illegal type */
3457 return -EINVAL;
3458 }
3459
3460 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003461 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003462 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003463 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 return -ERANGE;
3465 } else /* buffer big enough */ {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003466 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
3467
Steve Frenchff7feac2005-11-15 16:45:16 -08003468 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003469 for (i = 0; i < count ; i++) {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003470 cifs_convert_ace(&ace[i], pACE);
Steve French50c2f752007-07-13 00:33:32 +00003471 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472 }
3473 }
3474 return size;
3475}
3476
Steve French50c2f752007-07-13 00:33:32 +00003477static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003478 const struct posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479{
3480 __u16 rc = 0; /* 0 = ACL converted ok */
3481
Steve Frenchff7feac2005-11-15 16:45:16 -08003482 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3483 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003485 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486 /* Probably no need to le convert -1 on any arch but can not hurt */
3487 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003488 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003489 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003490/*
3491 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3492 ace->e_perm, ace->e_tag, ace->e_id);
3493*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494 return rc;
3495}
3496
3497/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003498static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3499 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500{
3501 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003502 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003503 struct posix_acl_xattr_header *local_acl = (void *)pACL;
Eryu Guanae9ebe72016-10-24 20:46:40 +08003504 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505 int count;
3506 int i;
3507
Steve French790fe572007-07-07 19:25:05 +00003508 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509 return 0;
3510
3511 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003512 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3513 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003514 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003515 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3516 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517 return 0;
3518 }
3519 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003520 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003521 cifs_acl->access_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003522 cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003523 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003524 cifs_acl->default_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003525 cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003526 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003527 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528 return 0;
3529 }
Steve French50c2f752007-07-13 00:33:32 +00003530 for (i = 0; i < count; i++) {
Eryu Guanae9ebe72016-10-24 20:46:40 +08003531 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
Steve French790fe572007-07-07 19:25:05 +00003532 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533 /* ACE not converted */
3534 break;
3535 }
3536 }
Steve French790fe572007-07-07 19:25:05 +00003537 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3539 rc += sizeof(struct cifs_posix_acl);
3540 /* BB add check to make sure ACL does not overflow SMB */
3541 }
3542 return rc;
3543}
3544
3545int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003546CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003547 const unsigned char *searchName,
3548 char *acl_inf, const int buflen, const int acl_type,
3549 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550{
3551/* SMB_QUERY_POSIX_ACL */
3552 TRANSACTION2_QPI_REQ *pSMB = NULL;
3553 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3554 int rc = 0;
3555 int bytes_returned;
3556 int name_len;
3557 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003558
Joe Perchesf96637b2013-05-04 22:12:25 -05003559 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560
3561queryAclRetry:
3562 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3563 (void **) &pSMBr);
3564 if (rc)
3565 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003566
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3568 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003569 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3570 searchName, PATH_MAX, nls_codepage,
3571 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572 name_len++; /* trailing null */
3573 name_len *= 2;
3574 pSMB->FileName[name_len] = 0;
3575 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003576 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 name_len = strnlen(searchName, PATH_MAX);
3578 name_len++; /* trailing null */
3579 strncpy(pSMB->FileName, searchName, name_len);
3580 }
3581
3582 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3583 pSMB->TotalDataCount = 0;
3584 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003585 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586 pSMB->MaxDataCount = cpu_to_le16(4000);
3587 pSMB->MaxSetupCount = 0;
3588 pSMB->Reserved = 0;
3589 pSMB->Flags = 0;
3590 pSMB->Timeout = 0;
3591 pSMB->Reserved2 = 0;
3592 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003593 offsetof(struct smb_com_transaction2_qpi_req,
3594 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003595 pSMB->DataCount = 0;
3596 pSMB->DataOffset = 0;
3597 pSMB->SetupCount = 1;
3598 pSMB->Reserved3 = 0;
3599 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3600 byte_count = params + 1 /* pad */ ;
3601 pSMB->TotalParameterCount = cpu_to_le16(params);
3602 pSMB->ParameterCount = pSMB->TotalParameterCount;
3603 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3604 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003605 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606 pSMB->ByteCount = cpu_to_le16(byte_count);
3607
3608 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3609 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003610 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003612 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 } else {
3614 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003615
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003618 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619 rc = -EIO; /* bad smb */
3620 else {
3621 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3622 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3623 rc = cifs_copy_posix_acl(acl_inf,
3624 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003625 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 }
3627 }
3628 cifs_buf_release(pSMB);
3629 if (rc == -EAGAIN)
3630 goto queryAclRetry;
3631 return rc;
3632}
3633
3634int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003635CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003636 const unsigned char *fileName,
3637 const char *local_acl, const int buflen,
3638 const int acl_type,
3639 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640{
3641 struct smb_com_transaction2_spi_req *pSMB = NULL;
3642 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3643 char *parm_data;
3644 int name_len;
3645 int rc = 0;
3646 int bytes_returned = 0;
3647 __u16 params, byte_count, data_count, param_offset, offset;
3648
Joe Perchesf96637b2013-05-04 22:12:25 -05003649 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650setAclRetry:
3651 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003652 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653 if (rc)
3654 return rc;
3655 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3656 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003657 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3658 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659 name_len++; /* trailing null */
3660 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003661 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662 name_len = strnlen(fileName, PATH_MAX);
3663 name_len++; /* trailing null */
3664 strncpy(pSMB->FileName, fileName, name_len);
3665 }
3666 params = 6 + name_len;
3667 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003668 /* BB find max SMB size from sess */
3669 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 pSMB->MaxSetupCount = 0;
3671 pSMB->Reserved = 0;
3672 pSMB->Flags = 0;
3673 pSMB->Timeout = 0;
3674 pSMB->Reserved2 = 0;
3675 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003676 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 offset = param_offset + params;
3678 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3679 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3680
3681 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003682 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683
Steve French790fe572007-07-07 19:25:05 +00003684 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685 rc = -EOPNOTSUPP;
3686 goto setACLerrorExit;
3687 }
3688 pSMB->DataOffset = cpu_to_le16(offset);
3689 pSMB->SetupCount = 1;
3690 pSMB->Reserved3 = 0;
3691 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3692 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3693 byte_count = 3 /* pad */ + params + data_count;
3694 pSMB->DataCount = cpu_to_le16(data_count);
3695 pSMB->TotalDataCount = pSMB->DataCount;
3696 pSMB->ParameterCount = cpu_to_le16(params);
3697 pSMB->TotalParameterCount = pSMB->ParameterCount;
3698 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003699 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 pSMB->ByteCount = cpu_to_le16(byte_count);
3701 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003702 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003703 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003704 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705
3706setACLerrorExit:
3707 cifs_buf_release(pSMB);
3708 if (rc == -EAGAIN)
3709 goto setAclRetry;
3710 return rc;
3711}
3712
Steve Frenchf654bac2005-04-28 22:41:04 -07003713/* BB fix tabs in this function FIXME BB */
3714int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003715CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003716 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003717{
Steve French50c2f752007-07-13 00:33:32 +00003718 int rc = 0;
3719 struct smb_t2_qfi_req *pSMB = NULL;
3720 struct smb_t2_qfi_rsp *pSMBr = NULL;
3721 int bytes_returned;
3722 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003723
Joe Perchesf96637b2013-05-04 22:12:25 -05003724 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003725 if (tcon == NULL)
3726 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003727
3728GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003729 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3730 (void **) &pSMBr);
3731 if (rc)
3732 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003733
Steve Frenchad7a2922008-02-07 23:25:02 +00003734 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003735 pSMB->t2.TotalDataCount = 0;
3736 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3737 /* BB find exact max data count below from sess structure BB */
3738 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3739 pSMB->t2.MaxSetupCount = 0;
3740 pSMB->t2.Reserved = 0;
3741 pSMB->t2.Flags = 0;
3742 pSMB->t2.Timeout = 0;
3743 pSMB->t2.Reserved2 = 0;
3744 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3745 Fid) - 4);
3746 pSMB->t2.DataCount = 0;
3747 pSMB->t2.DataOffset = 0;
3748 pSMB->t2.SetupCount = 1;
3749 pSMB->t2.Reserved3 = 0;
3750 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3751 byte_count = params + 1 /* pad */ ;
3752 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3753 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3754 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3755 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003756 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003757 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003758 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003759
Steve French790fe572007-07-07 19:25:05 +00003760 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3761 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3762 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003763 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003764 } else {
3765 /* decode response */
3766 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003767 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003768 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003769 /* If rc should we check for EOPNOSUPP and
3770 disable the srvino flag? or in caller? */
3771 rc = -EIO; /* bad smb */
3772 else {
3773 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3774 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3775 struct file_chattr_info *pfinfo;
3776 /* BB Do we need a cast or hash here ? */
3777 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003778 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003779 rc = -EIO;
3780 goto GetExtAttrOut;
3781 }
3782 pfinfo = (struct file_chattr_info *)
3783 (data_offset + (char *) &pSMBr->hdr.Protocol);
3784 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003785 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003786 }
3787 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003788GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003789 cifs_buf_release(pSMB);
3790 if (rc == -EAGAIN)
3791 goto GetExtAttrRetry;
3792 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003793}
3794
Steve Frenchf654bac2005-04-28 22:41:04 -07003795#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003796
Jeff Layton79df1ba2010-12-06 12:52:08 -05003797#ifdef CONFIG_CIFS_ACL
3798/*
3799 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3800 * all NT TRANSACTS that we init here have total parm and data under about 400
3801 * bytes (to fit in small cifs buffer size), which is the case so far, it
3802 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3803 * returned setup area) and MaxParameterCount (returned parms size) must be set
3804 * by caller
3805 */
3806static int
3807smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003808 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003809 void **ret_buf)
3810{
3811 int rc;
3812 __u32 temp_offset;
3813 struct smb_com_ntransact_req *pSMB;
3814
3815 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3816 (void **)&pSMB);
3817 if (rc)
3818 return rc;
3819 *ret_buf = (void *)pSMB;
3820 pSMB->Reserved = 0;
3821 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3822 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003823 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003824 pSMB->ParameterCount = pSMB->TotalParameterCount;
3825 pSMB->DataCount = pSMB->TotalDataCount;
3826 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3827 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3828 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3829 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3830 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3831 pSMB->SubCommand = cpu_to_le16(sub_command);
3832 return 0;
3833}
3834
3835static int
3836validate_ntransact(char *buf, char **ppparm, char **ppdata,
3837 __u32 *pparmlen, __u32 *pdatalen)
3838{
3839 char *end_of_smb;
3840 __u32 data_count, data_offset, parm_count, parm_offset;
3841 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003842 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003843
3844 *pdatalen = 0;
3845 *pparmlen = 0;
3846
3847 if (buf == NULL)
3848 return -EINVAL;
3849
3850 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3851
Jeff Layton820a8032011-05-04 08:05:26 -04003852 bcc = get_bcc(&pSMBr->hdr);
3853 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003854 (char *)&pSMBr->ByteCount;
3855
3856 data_offset = le32_to_cpu(pSMBr->DataOffset);
3857 data_count = le32_to_cpu(pSMBr->DataCount);
3858 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3859 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3860
3861 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3862 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3863
3864 /* should we also check that parm and data areas do not overlap? */
3865 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003866 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003867 return -EINVAL;
3868 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003869 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003870 return -EINVAL;
3871 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003872 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003873 return -EINVAL;
3874 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003875 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3876 *ppdata, data_count, (data_count + *ppdata),
3877 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003878 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003879 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003880 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003881 return -EINVAL;
3882 }
3883 *pdatalen = data_count;
3884 *pparmlen = parm_count;
3885 return 0;
3886}
3887
Steve French0a4b92c2006-01-12 15:44:21 -08003888/* Get Security Descriptor (by handle) from remote server for a file or dir */
3889int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003890CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003891 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003892{
3893 int rc = 0;
3894 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003895 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003896 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003897 struct kvec rsp_iov;
Steve French0a4b92c2006-01-12 15:44:21 -08003898
Joe Perchesf96637b2013-05-04 22:12:25 -05003899 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003900
Steve French630f3f0c2007-10-25 21:17:17 +00003901 *pbuflen = 0;
3902 *acl_inf = NULL;
3903
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003904 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003905 8 /* parm len */, tcon, (void **) &pSMB);
3906 if (rc)
3907 return rc;
3908
3909 pSMB->MaxParameterCount = cpu_to_le32(4);
3910 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3911 pSMB->MaxSetupCount = 0;
3912 pSMB->Fid = fid; /* file handle always le */
3913 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3914 CIFS_ACL_DACL);
3915 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003916 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003917 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003918 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003919
Steve Frencha761ac52007-10-18 21:45:27 +00003920 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003921 0, &rsp_iov);
3922 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003923 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003924 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003925 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003926 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003927 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003928 __u32 parm_len;
3929 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003930 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003931 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003932
3933/* validate_nttransact */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003934 rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003935 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003936 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003937 goto qsec_out;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003938 pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
Steve French0a4b92c2006-01-12 15:44:21 -08003939
Joe Perchesf96637b2013-05-04 22:12:25 -05003940 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3941 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003942
3943 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3944 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003945 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003946 goto qsec_out;
3947 }
3948
3949/* BB check that data area is minimum length and as big as acl_len */
3950
Steve Frenchaf6f4612007-10-16 18:40:37 +00003951 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003952 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003953 cifs_dbg(VFS, "acl length %d does not match %d\n",
3954 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003955 if (*pbuflen > acl_len)
3956 *pbuflen = acl_len;
3957 }
Steve French0a4b92c2006-01-12 15:44:21 -08003958
Steve French630f3f0c2007-10-25 21:17:17 +00003959 /* check if buffer is big enough for the acl
3960 header followed by the smallest SID */
3961 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3962 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003963 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003964 rc = -EINVAL;
3965 *pbuflen = 0;
3966 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003967 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003968 if (*acl_inf == NULL) {
3969 *pbuflen = 0;
3970 rc = -ENOMEM;
3971 }
Steve French630f3f0c2007-10-25 21:17:17 +00003972 }
Steve French0a4b92c2006-01-12 15:44:21 -08003973 }
3974qsec_out:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003975 free_rsp_buf(buf_type, rsp_iov.iov_base);
Steve French0a4b92c2006-01-12 15:44:21 -08003976 return rc;
3977}
Steve French97837582007-12-31 07:47:21 +00003978
3979int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003980CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003981 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003982{
3983 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3984 int rc = 0;
3985 int bytes_returned = 0;
3986 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003987 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003988
3989setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003990 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003991 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003992 return rc;
Steve French97837582007-12-31 07:47:21 +00003993
3994 pSMB->MaxSetupCount = 0;
3995 pSMB->Reserved = 0;
3996
3997 param_count = 8;
3998 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3999 data_count = acllen;
4000 data_offset = param_offset + param_count;
4001 byte_count = 3 /* pad */ + param_count;
4002
4003 pSMB->DataCount = cpu_to_le32(data_count);
4004 pSMB->TotalDataCount = pSMB->DataCount;
4005 pSMB->MaxParameterCount = cpu_to_le32(4);
4006 pSMB->MaxDataCount = cpu_to_le32(16384);
4007 pSMB->ParameterCount = cpu_to_le32(param_count);
4008 pSMB->ParameterOffset = cpu_to_le32(param_offset);
4009 pSMB->TotalParameterCount = pSMB->ParameterCount;
4010 pSMB->DataOffset = cpu_to_le32(data_offset);
4011 pSMB->SetupCount = 0;
4012 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
4013 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
4014
4015 pSMB->Fid = fid; /* file handle always le */
4016 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05004017 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00004018
4019 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04004020 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
4021 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004022 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00004023 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004024 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00004025
4026 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4027 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4028
Joe Perchesf96637b2013-05-04 22:12:25 -05004029 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
4030 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00004031 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004032 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00004033 cifs_buf_release(pSMB);
4034
4035 if (rc == -EAGAIN)
4036 goto setCifsAclRetry;
4037
4038 return (rc);
4039}
4040
Jeff Layton79df1ba2010-12-06 12:52:08 -05004041#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08004042
Steve French6b8edfe2005-08-23 20:26:03 -07004043/* Legacy Query Path Information call for lookup to old servers such
4044 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004045int
4046SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
4047 const char *search_name, FILE_ALL_INFO *data,
4048 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07004049{
Steve Frenchad7a2922008-02-07 23:25:02 +00004050 QUERY_INFORMATION_REQ *pSMB;
4051 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07004052 int rc = 0;
4053 int bytes_returned;
4054 int name_len;
4055
Joe Perchesf96637b2013-05-04 22:12:25 -05004056 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004057QInfRetry:
4058 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004059 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07004060 if (rc)
4061 return rc;
4062
4063 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4064 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004065 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004066 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004067 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07004068 name_len++; /* trailing null */
4069 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004070 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004071 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07004072 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004073 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004074 }
4075 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00004076 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004077 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004078 pSMB->ByteCount = cpu_to_le16(name_len);
4079
4080 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004081 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07004082 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004083 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004084 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00004085 struct timespec ts;
4086 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00004087
4088 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00004089 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004090 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00004091 ts.tv_nsec = 0;
4092 ts.tv_sec = time;
4093 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004094 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
4095 data->LastWriteTime = data->ChangeTime;
4096 data->LastAccessTime = 0;
4097 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07004098 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004099 data->EndOfFile = data->AllocationSize;
4100 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07004101 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07004102 } else
4103 rc = -EIO; /* bad buffer passed in */
4104
4105 cifs_buf_release(pSMB);
4106
4107 if (rc == -EAGAIN)
4108 goto QInfRetry;
4109
4110 return rc;
4111}
4112
Jeff Laytonbcd53572010-02-12 07:44:16 -05004113int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004114CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004115 u16 netfid, FILE_ALL_INFO *pFindData)
4116{
4117 struct smb_t2_qfi_req *pSMB = NULL;
4118 struct smb_t2_qfi_rsp *pSMBr = NULL;
4119 int rc = 0;
4120 int bytes_returned;
4121 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004122
Jeff Laytonbcd53572010-02-12 07:44:16 -05004123QFileInfoRetry:
4124 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4125 (void **) &pSMBr);
4126 if (rc)
4127 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004128
Jeff Laytonbcd53572010-02-12 07:44:16 -05004129 params = 2 /* level */ + 2 /* fid */;
4130 pSMB->t2.TotalDataCount = 0;
4131 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4132 /* BB find exact max data count below from sess structure BB */
4133 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4134 pSMB->t2.MaxSetupCount = 0;
4135 pSMB->t2.Reserved = 0;
4136 pSMB->t2.Flags = 0;
4137 pSMB->t2.Timeout = 0;
4138 pSMB->t2.Reserved2 = 0;
4139 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4140 Fid) - 4);
4141 pSMB->t2.DataCount = 0;
4142 pSMB->t2.DataOffset = 0;
4143 pSMB->t2.SetupCount = 1;
4144 pSMB->t2.Reserved3 = 0;
4145 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4146 byte_count = params + 1 /* pad */ ;
4147 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4148 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4149 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4150 pSMB->Pad = 0;
4151 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004152 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004153 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004154
4155 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4156 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4157 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004158 cifs_dbg(FYI, "Send error in QFileInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004159 } else { /* decode response */
4160 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4161
4162 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4163 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004164 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004165 rc = -EIO; /* bad smb */
4166 else if (pFindData) {
4167 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4168 memcpy((char *) pFindData,
4169 (char *) &pSMBr->hdr.Protocol +
4170 data_offset, sizeof(FILE_ALL_INFO));
4171 } else
4172 rc = -ENOMEM;
4173 }
4174 cifs_buf_release(pSMB);
4175 if (rc == -EAGAIN)
4176 goto QFileInfoRetry;
4177
4178 return rc;
4179}
Steve French6b8edfe2005-08-23 20:26:03 -07004180
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004182CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004183 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004184 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004185 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004187 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188 TRANSACTION2_QPI_REQ *pSMB = NULL;
4189 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4190 int rc = 0;
4191 int bytes_returned;
4192 int name_len;
4193 __u16 params, byte_count;
4194
Joe Perchesf96637b2013-05-04 22:12:25 -05004195 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196QPathInfoRetry:
4197 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4198 (void **) &pSMBr);
4199 if (rc)
4200 return rc;
4201
4202 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4203 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004204 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004205 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 name_len++; /* trailing null */
4207 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004208 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004209 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004211 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004212 }
4213
Steve French50c2f752007-07-13 00:33:32 +00004214 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215 pSMB->TotalDataCount = 0;
4216 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004217 /* BB find exact max SMB PDU from sess structure BB */
4218 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219 pSMB->MaxSetupCount = 0;
4220 pSMB->Reserved = 0;
4221 pSMB->Flags = 0;
4222 pSMB->Timeout = 0;
4223 pSMB->Reserved2 = 0;
4224 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004225 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226 pSMB->DataCount = 0;
4227 pSMB->DataOffset = 0;
4228 pSMB->SetupCount = 1;
4229 pSMB->Reserved3 = 0;
4230 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4231 byte_count = params + 1 /* pad */ ;
4232 pSMB->TotalParameterCount = cpu_to_le16(params);
4233 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004234 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004235 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4236 else
4237 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004239 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 pSMB->ByteCount = cpu_to_le16(byte_count);
4241
4242 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4243 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4244 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004245 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246 } else { /* decode response */
4247 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4248
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004249 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4250 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004251 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004253 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004254 rc = -EIO; /* 24 or 26 expected but we do not read
4255 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004256 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004257 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004259
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004260 /*
4261 * On legacy responses we do not read the last field,
4262 * EAsize, fortunately since it varies by subdialect and
4263 * also note it differs on Set vs Get, ie two bytes or 4
4264 * bytes depending but we don't care here.
4265 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004266 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004267 size = sizeof(FILE_INFO_STANDARD);
4268 else
4269 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004270 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004271 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004272 } else
4273 rc = -ENOMEM;
4274 }
4275 cifs_buf_release(pSMB);
4276 if (rc == -EAGAIN)
4277 goto QPathInfoRetry;
4278
4279 return rc;
4280}
4281
4282int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004283CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004284 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4285{
4286 struct smb_t2_qfi_req *pSMB = NULL;
4287 struct smb_t2_qfi_rsp *pSMBr = NULL;
4288 int rc = 0;
4289 int bytes_returned;
4290 __u16 params, byte_count;
4291
4292UnixQFileInfoRetry:
4293 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4294 (void **) &pSMBr);
4295 if (rc)
4296 return rc;
4297
4298 params = 2 /* level */ + 2 /* fid */;
4299 pSMB->t2.TotalDataCount = 0;
4300 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4301 /* BB find exact max data count below from sess structure BB */
4302 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4303 pSMB->t2.MaxSetupCount = 0;
4304 pSMB->t2.Reserved = 0;
4305 pSMB->t2.Flags = 0;
4306 pSMB->t2.Timeout = 0;
4307 pSMB->t2.Reserved2 = 0;
4308 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4309 Fid) - 4);
4310 pSMB->t2.DataCount = 0;
4311 pSMB->t2.DataOffset = 0;
4312 pSMB->t2.SetupCount = 1;
4313 pSMB->t2.Reserved3 = 0;
4314 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4315 byte_count = params + 1 /* pad */ ;
4316 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4317 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4318 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4319 pSMB->Pad = 0;
4320 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004321 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004322 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004323
4324 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4325 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4326 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004327 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004328 } else { /* decode response */
4329 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4330
Jeff Layton820a8032011-05-04 08:05:26 -04004331 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004332 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 -05004333 rc = -EIO; /* bad smb */
4334 } else {
4335 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4336 memcpy((char *) pFindData,
4337 (char *) &pSMBr->hdr.Protocol +
4338 data_offset,
4339 sizeof(FILE_UNIX_BASIC_INFO));
4340 }
4341 }
4342
4343 cifs_buf_release(pSMB);
4344 if (rc == -EAGAIN)
4345 goto UnixQFileInfoRetry;
4346
4347 return rc;
4348}
4349
4350int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004351CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004353 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004354 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355{
4356/* SMB_QUERY_FILE_UNIX_BASIC */
4357 TRANSACTION2_QPI_REQ *pSMB = NULL;
4358 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4359 int rc = 0;
4360 int bytes_returned = 0;
4361 int name_len;
4362 __u16 params, byte_count;
4363
Joe Perchesf96637b2013-05-04 22:12:25 -05004364 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365UnixQPathInfoRetry:
4366 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4367 (void **) &pSMBr);
4368 if (rc)
4369 return rc;
4370
4371 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4372 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004373 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4374 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375 name_len++; /* trailing null */
4376 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004377 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378 name_len = strnlen(searchName, PATH_MAX);
4379 name_len++; /* trailing null */
4380 strncpy(pSMB->FileName, searchName, name_len);
4381 }
4382
Steve French50c2f752007-07-13 00:33:32 +00004383 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384 pSMB->TotalDataCount = 0;
4385 pSMB->MaxParameterCount = cpu_to_le16(2);
4386 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004387 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388 pSMB->MaxSetupCount = 0;
4389 pSMB->Reserved = 0;
4390 pSMB->Flags = 0;
4391 pSMB->Timeout = 0;
4392 pSMB->Reserved2 = 0;
4393 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004394 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004395 pSMB->DataCount = 0;
4396 pSMB->DataOffset = 0;
4397 pSMB->SetupCount = 1;
4398 pSMB->Reserved3 = 0;
4399 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4400 byte_count = params + 1 /* pad */ ;
4401 pSMB->TotalParameterCount = cpu_to_le16(params);
4402 pSMB->ParameterCount = pSMB->TotalParameterCount;
4403 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4404 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004405 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406 pSMB->ByteCount = cpu_to_le16(byte_count);
4407
4408 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4409 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4410 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004411 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412 } else { /* decode response */
4413 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4414
Jeff Layton820a8032011-05-04 08:05:26 -04004415 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004416 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 -07004417 rc = -EIO; /* bad smb */
4418 } else {
4419 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4420 memcpy((char *) pFindData,
4421 (char *) &pSMBr->hdr.Protocol +
4422 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004423 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 }
4425 }
4426 cifs_buf_release(pSMB);
4427 if (rc == -EAGAIN)
4428 goto UnixQPathInfoRetry;
4429
4430 return rc;
4431}
4432
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433/* xid, tcon, searchName and codepage are input parms, rest are returned */
4434int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004435CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004436 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004437 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004438 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439{
4440/* level 257 SMB_ */
4441 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4442 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004443 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 int rc = 0;
4445 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004446 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004448 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449
Joe Perchesf96637b2013-05-04 22:12:25 -05004450 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451
4452findFirstRetry:
4453 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4454 (void **) &pSMBr);
4455 if (rc)
4456 return rc;
4457
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004458 nls_codepage = cifs_sb->local_nls;
Steve French2baa2682014-09-27 02:19:01 -05004459 remap = cifs_remap(cifs_sb);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004460
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4462 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004463 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4464 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004465 /* We can not add the asterik earlier in case
4466 it got remapped to 0xF03A as if it were part of the
4467 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004469 if (msearch) {
4470 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4471 pSMB->FileName[name_len+1] = 0;
4472 pSMB->FileName[name_len+2] = '*';
4473 pSMB->FileName[name_len+3] = 0;
4474 name_len += 4; /* now the trailing null */
4475 /* null terminate just in case */
4476 pSMB->FileName[name_len] = 0;
4477 pSMB->FileName[name_len+1] = 0;
4478 name_len += 2;
4479 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480 } else { /* BB add check for overrun of SMB buf BB */
4481 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004483 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484 free buffer exit; BB */
4485 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004486 if (msearch) {
4487 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4488 pSMB->FileName[name_len+1] = '*';
4489 pSMB->FileName[name_len+2] = 0;
4490 name_len += 3;
4491 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 }
4493
4494 params = 12 + name_len /* includes null */ ;
4495 pSMB->TotalDataCount = 0; /* no EAs */
4496 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004497 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498 pSMB->MaxSetupCount = 0;
4499 pSMB->Reserved = 0;
4500 pSMB->Flags = 0;
4501 pSMB->Timeout = 0;
4502 pSMB->Reserved2 = 0;
4503 byte_count = params + 1 /* pad */ ;
4504 pSMB->TotalParameterCount = cpu_to_le16(params);
4505 pSMB->ParameterCount = pSMB->TotalParameterCount;
4506 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004507 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4508 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509 pSMB->DataCount = 0;
4510 pSMB->DataOffset = 0;
4511 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4512 pSMB->Reserved3 = 0;
4513 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4514 pSMB->SearchAttributes =
4515 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4516 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004517 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004518 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4520
4521 /* BB what should we set StorageType to? Does it matter? BB */
4522 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004523 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524 pSMB->ByteCount = cpu_to_le16(byte_count);
4525
4526 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4527 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004528 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529
Steve French88274812006-03-09 22:21:45 +00004530 if (rc) {/* BB add logic to retry regular search if Unix search
4531 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004533 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004534
Steve French88274812006-03-09 22:21:45 +00004535 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536
4537 /* BB eventually could optimize out free and realloc of buf */
4538 /* for this case */
4539 if (rc == -EAGAIN)
4540 goto findFirstRetry;
4541 } else { /* decode response */
4542 /* BB remember to free buffer if error BB */
4543 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004544 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004545 unsigned int lnoff;
4546
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004548 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549 else
Steve French4b18f2a2008-04-29 00:06:05 +00004550 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551
4552 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004553 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004554 psrch_inf->srch_entries_start =
4555 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4558 le16_to_cpu(pSMBr->t2.ParameterOffset));
4559
Steve French790fe572007-07-07 19:25:05 +00004560 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004561 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562 else
Steve French4b18f2a2008-04-29 00:06:05 +00004563 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564
Steve French50c2f752007-07-13 00:33:32 +00004565 psrch_inf->entries_in_buffer =
4566 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004567 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004569 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004570 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004571 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004572 psrch_inf->last_entry = NULL;
4573 return rc;
4574 }
4575
Steve French0752f152008-10-07 20:03:33 +00004576 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004577 lnoff;
4578
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004579 if (pnetfid)
4580 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581 } else {
4582 cifs_buf_release(pSMB);
4583 }
4584 }
4585
4586 return rc;
4587}
4588
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004589int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4590 __u16 searchHandle, __u16 search_flags,
4591 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592{
4593 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4594 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004595 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596 char *response_data;
4597 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004598 int bytes_returned;
4599 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600 __u16 params, byte_count;
4601
Joe Perchesf96637b2013-05-04 22:12:25 -05004602 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603
Steve French4b18f2a2008-04-29 00:06:05 +00004604 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605 return -ENOENT;
4606
4607 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4608 (void **) &pSMBr);
4609 if (rc)
4610 return rc;
4611
Steve French50c2f752007-07-13 00:33:32 +00004612 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004613 byte_count = 0;
4614 pSMB->TotalDataCount = 0; /* no EAs */
4615 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004616 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004617 pSMB->MaxSetupCount = 0;
4618 pSMB->Reserved = 0;
4619 pSMB->Flags = 0;
4620 pSMB->Timeout = 0;
4621 pSMB->Reserved2 = 0;
4622 pSMB->ParameterOffset = cpu_to_le16(
4623 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4624 pSMB->DataCount = 0;
4625 pSMB->DataOffset = 0;
4626 pSMB->SetupCount = 1;
4627 pSMB->Reserved3 = 0;
4628 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4629 pSMB->SearchHandle = searchHandle; /* always kept as le */
4630 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004631 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4633 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004634 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635
4636 name_len = psrch_inf->resume_name_len;
4637 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004638 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4640 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004641 /* 14 byte parm len above enough for 2 byte null terminator */
4642 pSMB->ResumeFileName[name_len] = 0;
4643 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644 } else {
4645 rc = -EINVAL;
4646 goto FNext2_err_exit;
4647 }
4648 byte_count = params + 1 /* pad */ ;
4649 pSMB->TotalParameterCount = cpu_to_le16(params);
4650 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004651 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004652 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004653
Linus Torvalds1da177e2005-04-16 15:20:36 -07004654 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4655 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004656 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657 if (rc) {
4658 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004659 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004660 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004661 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004663 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004664 } else { /* decode response */
4665 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004666
Steve French790fe572007-07-07 19:25:05 +00004667 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004668 unsigned int lnoff;
4669
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670 /* BB fixme add lock for file (srch_info) struct here */
4671 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004672 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004673 else
Steve French4b18f2a2008-04-29 00:06:05 +00004674 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004675 response_data = (char *) &pSMBr->hdr.Protocol +
4676 le16_to_cpu(pSMBr->t2.ParameterOffset);
4677 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4678 response_data = (char *)&pSMBr->hdr.Protocol +
4679 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004680 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004681 cifs_small_buf_release(
4682 psrch_inf->ntwrk_buf_start);
4683 else
4684 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685 psrch_inf->srch_entries_start = response_data;
4686 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004687 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004688 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004689 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690 else
Steve French4b18f2a2008-04-29 00:06:05 +00004691 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004692 psrch_inf->entries_in_buffer =
4693 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694 psrch_inf->index_of_last_entry +=
4695 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004696 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004697 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004698 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004699 psrch_inf->last_entry = NULL;
4700 return rc;
4701 } else
4702 psrch_inf->last_entry =
4703 psrch_inf->srch_entries_start + lnoff;
4704
Joe Perchesf96637b2013-05-04 22:12:25 -05004705/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4706 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707
4708 /* BB fixme add unlock here */
4709 }
4710
4711 }
4712
4713 /* BB On error, should we leave previous search buf (and count and
4714 last entry fields) intact or free the previous one? */
4715
4716 /* Note: On -EAGAIN error only caller can retry on handle based calls
4717 since file handle passed in no longer valid */
4718FNext2_err_exit:
4719 if (rc != 0)
4720 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721 return rc;
4722}
4723
4724int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004725CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004726 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727{
4728 int rc = 0;
4729 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730
Joe Perchesf96637b2013-05-04 22:12:25 -05004731 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4733
4734 /* no sense returning error if session restarted
4735 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004736 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737 return 0;
4738 if (rc)
4739 return rc;
4740
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741 pSMB->FileID = searchHandle;
4742 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004743 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004744 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00004745 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004746 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004747
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004748 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004749
4750 /* Since session is dead, search handle closed on server already */
4751 if (rc == -EAGAIN)
4752 rc = 0;
4753
4754 return rc;
4755}
4756
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004758CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004759 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004760 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761{
4762 int rc = 0;
4763 TRANSACTION2_QPI_REQ *pSMB = NULL;
4764 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4765 int name_len, bytes_returned;
4766 __u16 params, byte_count;
4767
Joe Perchesf96637b2013-05-04 22:12:25 -05004768 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004769 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004770 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771
4772GetInodeNumberRetry:
4773 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004774 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775 if (rc)
4776 return rc;
4777
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4779 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004780 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004781 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004782 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004783 name_len++; /* trailing null */
4784 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004785 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004786 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004787 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004788 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789 }
4790
4791 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4792 pSMB->TotalDataCount = 0;
4793 pSMB->MaxParameterCount = cpu_to_le16(2);
4794 /* BB find exact max data count below from sess structure BB */
4795 pSMB->MaxDataCount = cpu_to_le16(4000);
4796 pSMB->MaxSetupCount = 0;
4797 pSMB->Reserved = 0;
4798 pSMB->Flags = 0;
4799 pSMB->Timeout = 0;
4800 pSMB->Reserved2 = 0;
4801 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004802 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803 pSMB->DataCount = 0;
4804 pSMB->DataOffset = 0;
4805 pSMB->SetupCount = 1;
4806 pSMB->Reserved3 = 0;
4807 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4808 byte_count = params + 1 /* pad */ ;
4809 pSMB->TotalParameterCount = cpu_to_le16(params);
4810 pSMB->ParameterCount = pSMB->TotalParameterCount;
4811 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4812 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004813 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814 pSMB->ByteCount = cpu_to_le16(byte_count);
4815
4816 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4817 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4818 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004819 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004820 } else {
4821 /* decode response */
4822 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004824 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004825 /* If rc should we check for EOPNOSUPP and
4826 disable the srvino flag? or in caller? */
4827 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004828 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4830 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004831 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004833 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004834 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835 rc = -EIO;
4836 goto GetInodeNumOut;
4837 }
4838 pfinfo = (struct file_internal_info *)
4839 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004840 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841 }
4842 }
4843GetInodeNumOut:
4844 cifs_buf_release(pSMB);
4845 if (rc == -EAGAIN)
4846 goto GetInodeNumberRetry;
4847 return rc;
4848}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849
4850int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004851CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004852 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004853 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004854 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855{
4856/* TRANS2_GET_DFS_REFERRAL */
4857 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4858 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859 int rc = 0;
4860 int bytes_returned;
4861 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004863 *num_of_nodes = 0;
4864 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865
Joe Perchesf96637b2013-05-04 22:12:25 -05004866 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004867 if (ses == NULL || ses->tcon_ipc == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868 return -ENODEV;
Aurelien Aptelb327a712018-01-24 13:46:10 +01004869
Linus Torvalds1da177e2005-04-16 15:20:36 -07004870getDFSRetry:
Aurelien Aptelb327a712018-01-24 13:46:10 +01004871 rc = smb_init(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872 (void **) &pSMBr);
4873 if (rc)
4874 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004875
4876 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004877 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004878 pSMB->hdr.Mid = get_next_mid(ses->server);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004879 pSMB->hdr.Tid = ses->tcon_ipc->tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004880 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004881 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004882 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004883 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004885
4886 if (ses->capabilities & CAP_UNICODE) {
4887 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4888 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004889 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004890 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004891 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892 name_len++; /* trailing null */
4893 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004894 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004895 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004897 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898 }
4899
Dan Carpenter65c3b202015-04-30 17:30:24 +03004900 if (ses->server->sign)
Jeff Layton38d77c52013-05-26 07:01:00 -04004901 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00004902
Steve French50c2f752007-07-13 00:33:32 +00004903 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004904
Linus Torvalds1da177e2005-04-16 15:20:36 -07004905 params = 2 /* level */ + name_len /*includes null */ ;
4906 pSMB->TotalDataCount = 0;
4907 pSMB->DataCount = 0;
4908 pSMB->DataOffset = 0;
4909 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004910 /* BB find exact max SMB PDU from sess structure BB */
4911 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912 pSMB->MaxSetupCount = 0;
4913 pSMB->Reserved = 0;
4914 pSMB->Flags = 0;
4915 pSMB->Timeout = 0;
4916 pSMB->Reserved2 = 0;
4917 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004918 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919 pSMB->SetupCount = 1;
4920 pSMB->Reserved3 = 0;
4921 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4922 byte_count = params + 3 /* pad */ ;
4923 pSMB->ParameterCount = cpu_to_le16(params);
4924 pSMB->TotalParameterCount = pSMB->ParameterCount;
4925 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004926 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004927 pSMB->ByteCount = cpu_to_le16(byte_count);
4928
4929 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4930 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4931 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004932 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004933 goto GetDFSRefExit;
4934 }
4935 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004937 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004938 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004939 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004940 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004942
Joe Perchesf96637b2013-05-04 22:12:25 -05004943 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4944 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004945
4946 /* parse returned result into more usable form */
Aurelien Aptel4ecce922017-02-13 16:03:47 +01004947 rc = parse_dfs_referrals(&pSMBr->dfs_data,
4948 le16_to_cpu(pSMBr->t2.DataCount),
4949 num_of_nodes, target_nodes, nls_codepage,
4950 remap, search_name,
Steve French284316d2017-03-02 15:42:48 -06004951 (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0);
Igor Mammedovfec45852008-05-16 13:06:30 +04004952
Linus Torvalds1da177e2005-04-16 15:20:36 -07004953GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004954 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004955
4956 if (rc == -EAGAIN)
4957 goto getDFSRetry;
4958
4959 return rc;
4960}
4961
Steve French20962432005-09-21 22:05:57 -07004962/* Query File System Info such as free space to old servers such as Win 9x */
4963int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004964SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4965 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004966{
4967/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4968 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4969 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4970 FILE_SYSTEM_ALLOC_INFO *response_data;
4971 int rc = 0;
4972 int bytes_returned = 0;
4973 __u16 params, byte_count;
4974
Joe Perchesf96637b2013-05-04 22:12:25 -05004975 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004976oldQFSInfoRetry:
4977 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4978 (void **) &pSMBr);
4979 if (rc)
4980 return rc;
Steve French20962432005-09-21 22:05:57 -07004981
4982 params = 2; /* level */
4983 pSMB->TotalDataCount = 0;
4984 pSMB->MaxParameterCount = cpu_to_le16(2);
4985 pSMB->MaxDataCount = cpu_to_le16(1000);
4986 pSMB->MaxSetupCount = 0;
4987 pSMB->Reserved = 0;
4988 pSMB->Flags = 0;
4989 pSMB->Timeout = 0;
4990 pSMB->Reserved2 = 0;
4991 byte_count = params + 1 /* pad */ ;
4992 pSMB->TotalParameterCount = cpu_to_le16(params);
4993 pSMB->ParameterCount = pSMB->TotalParameterCount;
4994 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4995 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4996 pSMB->DataCount = 0;
4997 pSMB->DataOffset = 0;
4998 pSMB->SetupCount = 1;
4999 pSMB->Reserved3 = 0;
5000 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5001 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005002 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07005003 pSMB->ByteCount = cpu_to_le16(byte_count);
5004
5005 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5006 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5007 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005008 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07005009 } else { /* decode response */
5010 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5011
Jeff Layton820a8032011-05-04 08:05:26 -04005012 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07005013 rc = -EIO; /* bad smb */
5014 else {
5015 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05005016 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04005017 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07005018
Steve French50c2f752007-07-13 00:33:32 +00005019 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07005020 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5021 FSData->f_bsize =
5022 le16_to_cpu(response_data->BytesPerSector) *
5023 le32_to_cpu(response_data->
5024 SectorsPerAllocationUnit);
5025 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00005026 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07005027 FSData->f_bfree = FSData->f_bavail =
5028 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005029 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5030 (unsigned long long)FSData->f_blocks,
5031 (unsigned long long)FSData->f_bfree,
5032 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07005033 }
5034 }
5035 cifs_buf_release(pSMB);
5036
5037 if (rc == -EAGAIN)
5038 goto oldQFSInfoRetry;
5039
5040 return rc;
5041}
5042
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005044CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5045 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005046{
5047/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5048 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5049 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5050 FILE_SYSTEM_INFO *response_data;
5051 int rc = 0;
5052 int bytes_returned = 0;
5053 __u16 params, byte_count;
5054
Joe Perchesf96637b2013-05-04 22:12:25 -05005055 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056QFSInfoRetry:
5057 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5058 (void **) &pSMBr);
5059 if (rc)
5060 return rc;
5061
5062 params = 2; /* level */
5063 pSMB->TotalDataCount = 0;
5064 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005065 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066 pSMB->MaxSetupCount = 0;
5067 pSMB->Reserved = 0;
5068 pSMB->Flags = 0;
5069 pSMB->Timeout = 0;
5070 pSMB->Reserved2 = 0;
5071 byte_count = params + 1 /* pad */ ;
5072 pSMB->TotalParameterCount = cpu_to_le16(params);
5073 pSMB->ParameterCount = pSMB->TotalParameterCount;
5074 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005075 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005076 pSMB->DataCount = 0;
5077 pSMB->DataOffset = 0;
5078 pSMB->SetupCount = 1;
5079 pSMB->Reserved3 = 0;
5080 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5081 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005082 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005083 pSMB->ByteCount = cpu_to_le16(byte_count);
5084
5085 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5086 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5087 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005088 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005089 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005090 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091
Jeff Layton820a8032011-05-04 08:05:26 -04005092 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005093 rc = -EIO; /* bad smb */
5094 else {
5095 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096
5097 response_data =
5098 (FILE_SYSTEM_INFO
5099 *) (((char *) &pSMBr->hdr.Protocol) +
5100 data_offset);
5101 FSData->f_bsize =
5102 le32_to_cpu(response_data->BytesPerSector) *
5103 le32_to_cpu(response_data->
5104 SectorsPerAllocationUnit);
5105 FSData->f_blocks =
5106 le64_to_cpu(response_data->TotalAllocationUnits);
5107 FSData->f_bfree = FSData->f_bavail =
5108 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005109 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5110 (unsigned long long)FSData->f_blocks,
5111 (unsigned long long)FSData->f_bfree,
5112 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005113 }
5114 }
5115 cifs_buf_release(pSMB);
5116
5117 if (rc == -EAGAIN)
5118 goto QFSInfoRetry;
5119
5120 return rc;
5121}
5122
5123int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005124CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005125{
5126/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5127 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5128 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5129 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5130 int rc = 0;
5131 int bytes_returned = 0;
5132 __u16 params, byte_count;
5133
Joe Perchesf96637b2013-05-04 22:12:25 -05005134 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005135QFSAttributeRetry:
5136 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5137 (void **) &pSMBr);
5138 if (rc)
5139 return rc;
5140
5141 params = 2; /* level */
5142 pSMB->TotalDataCount = 0;
5143 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005144 /* BB find exact max SMB PDU from sess structure BB */
5145 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146 pSMB->MaxSetupCount = 0;
5147 pSMB->Reserved = 0;
5148 pSMB->Flags = 0;
5149 pSMB->Timeout = 0;
5150 pSMB->Reserved2 = 0;
5151 byte_count = params + 1 /* pad */ ;
5152 pSMB->TotalParameterCount = cpu_to_le16(params);
5153 pSMB->ParameterCount = pSMB->TotalParameterCount;
5154 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005155 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156 pSMB->DataCount = 0;
5157 pSMB->DataOffset = 0;
5158 pSMB->SetupCount = 1;
5159 pSMB->Reserved3 = 0;
5160 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5161 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005162 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005163 pSMB->ByteCount = cpu_to_le16(byte_count);
5164
5165 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5166 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5167 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005168 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005169 } else { /* decode response */
5170 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5171
Jeff Layton820a8032011-05-04 08:05:26 -04005172 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005173 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005174 rc = -EIO; /* bad smb */
5175 } else {
5176 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5177 response_data =
5178 (FILE_SYSTEM_ATTRIBUTE_INFO
5179 *) (((char *) &pSMBr->hdr.Protocol) +
5180 data_offset);
5181 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005182 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183 }
5184 }
5185 cifs_buf_release(pSMB);
5186
5187 if (rc == -EAGAIN)
5188 goto QFSAttributeRetry;
5189
5190 return rc;
5191}
5192
5193int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005194CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195{
5196/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5197 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5198 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5199 FILE_SYSTEM_DEVICE_INFO *response_data;
5200 int rc = 0;
5201 int bytes_returned = 0;
5202 __u16 params, byte_count;
5203
Joe Perchesf96637b2013-05-04 22:12:25 -05005204 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005205QFSDeviceRetry:
5206 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5207 (void **) &pSMBr);
5208 if (rc)
5209 return rc;
5210
5211 params = 2; /* level */
5212 pSMB->TotalDataCount = 0;
5213 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005214 /* BB find exact max SMB PDU from sess structure BB */
5215 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005216 pSMB->MaxSetupCount = 0;
5217 pSMB->Reserved = 0;
5218 pSMB->Flags = 0;
5219 pSMB->Timeout = 0;
5220 pSMB->Reserved2 = 0;
5221 byte_count = params + 1 /* pad */ ;
5222 pSMB->TotalParameterCount = cpu_to_le16(params);
5223 pSMB->ParameterCount = pSMB->TotalParameterCount;
5224 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005225 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226
5227 pSMB->DataCount = 0;
5228 pSMB->DataOffset = 0;
5229 pSMB->SetupCount = 1;
5230 pSMB->Reserved3 = 0;
5231 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5232 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005233 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234 pSMB->ByteCount = cpu_to_le16(byte_count);
5235
5236 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5237 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5238 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005239 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240 } else { /* decode response */
5241 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5242
Jeff Layton820a8032011-05-04 08:05:26 -04005243 if (rc || get_bcc(&pSMBr->hdr) <
5244 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005245 rc = -EIO; /* bad smb */
5246 else {
5247 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5248 response_data =
Steve French737b7582005-04-28 22:41:06 -07005249 (FILE_SYSTEM_DEVICE_INFO *)
5250 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251 data_offset);
5252 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005253 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254 }
5255 }
5256 cifs_buf_release(pSMB);
5257
5258 if (rc == -EAGAIN)
5259 goto QFSDeviceRetry;
5260
5261 return rc;
5262}
5263
5264int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005265CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005266{
5267/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5268 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5269 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5270 FILE_SYSTEM_UNIX_INFO *response_data;
5271 int rc = 0;
5272 int bytes_returned = 0;
5273 __u16 params, byte_count;
5274
Joe Perchesf96637b2013-05-04 22:12:25 -05005275 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005276QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005277 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5278 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005279 if (rc)
5280 return rc;
5281
5282 params = 2; /* level */
5283 pSMB->TotalDataCount = 0;
5284 pSMB->DataCount = 0;
5285 pSMB->DataOffset = 0;
5286 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005287 /* BB find exact max SMB PDU from sess structure BB */
5288 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005289 pSMB->MaxSetupCount = 0;
5290 pSMB->Reserved = 0;
5291 pSMB->Flags = 0;
5292 pSMB->Timeout = 0;
5293 pSMB->Reserved2 = 0;
5294 byte_count = params + 1 /* pad */ ;
5295 pSMB->ParameterCount = cpu_to_le16(params);
5296 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005297 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5298 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005299 pSMB->SetupCount = 1;
5300 pSMB->Reserved3 = 0;
5301 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5302 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005303 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005304 pSMB->ByteCount = cpu_to_le16(byte_count);
5305
5306 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5307 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5308 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005309 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005310 } else { /* decode response */
5311 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5312
Jeff Layton820a8032011-05-04 08:05:26 -04005313 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005314 rc = -EIO; /* bad smb */
5315 } else {
5316 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5317 response_data =
5318 (FILE_SYSTEM_UNIX_INFO
5319 *) (((char *) &pSMBr->hdr.Protocol) +
5320 data_offset);
5321 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005322 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005323 }
5324 }
5325 cifs_buf_release(pSMB);
5326
5327 if (rc == -EAGAIN)
5328 goto QFSUnixRetry;
5329
5330
5331 return rc;
5332}
5333
Jeremy Allisonac670552005-06-22 17:26:35 -07005334int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005335CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005336{
5337/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5338 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5339 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5340 int rc = 0;
5341 int bytes_returned = 0;
5342 __u16 params, param_offset, offset, byte_count;
5343
Joe Perchesf96637b2013-05-04 22:12:25 -05005344 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005345SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005346 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005347 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5348 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005349 if (rc)
5350 return rc;
5351
5352 params = 4; /* 2 bytes zero followed by info level. */
5353 pSMB->MaxSetupCount = 0;
5354 pSMB->Reserved = 0;
5355 pSMB->Flags = 0;
5356 pSMB->Timeout = 0;
5357 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005358 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5359 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005360 offset = param_offset + params;
5361
5362 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005363 /* BB find exact max SMB PDU from sess structure BB */
5364 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005365 pSMB->SetupCount = 1;
5366 pSMB->Reserved3 = 0;
5367 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5368 byte_count = 1 /* pad */ + params + 12;
5369
5370 pSMB->DataCount = cpu_to_le16(12);
5371 pSMB->ParameterCount = cpu_to_le16(params);
5372 pSMB->TotalDataCount = pSMB->DataCount;
5373 pSMB->TotalParameterCount = pSMB->ParameterCount;
5374 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5375 pSMB->DataOffset = cpu_to_le16(offset);
5376
5377 /* Params. */
5378 pSMB->FileNum = 0;
5379 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5380
5381 /* Data. */
5382 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5383 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5384 pSMB->ClientUnixCap = cpu_to_le64(cap);
5385
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005386 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005387 pSMB->ByteCount = cpu_to_le16(byte_count);
5388
5389 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5390 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5391 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005392 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005393 } else { /* decode response */
5394 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005395 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005396 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005397 }
5398 cifs_buf_release(pSMB);
5399
5400 if (rc == -EAGAIN)
5401 goto SETFSUnixRetry;
5402
5403 return rc;
5404}
5405
5406
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407
5408int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005409CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005410 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005411{
5412/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5413 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5414 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5415 FILE_SYSTEM_POSIX_INFO *response_data;
5416 int rc = 0;
5417 int bytes_returned = 0;
5418 __u16 params, byte_count;
5419
Joe Perchesf96637b2013-05-04 22:12:25 -05005420 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005421QFSPosixRetry:
5422 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5423 (void **) &pSMBr);
5424 if (rc)
5425 return rc;
5426
5427 params = 2; /* level */
5428 pSMB->TotalDataCount = 0;
5429 pSMB->DataCount = 0;
5430 pSMB->DataOffset = 0;
5431 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005432 /* BB find exact max SMB PDU from sess structure BB */
5433 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434 pSMB->MaxSetupCount = 0;
5435 pSMB->Reserved = 0;
5436 pSMB->Flags = 0;
5437 pSMB->Timeout = 0;
5438 pSMB->Reserved2 = 0;
5439 byte_count = params + 1 /* pad */ ;
5440 pSMB->ParameterCount = cpu_to_le16(params);
5441 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005442 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5443 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005444 pSMB->SetupCount = 1;
5445 pSMB->Reserved3 = 0;
5446 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5447 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005448 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005449 pSMB->ByteCount = cpu_to_le16(byte_count);
5450
5451 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5452 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5453 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005454 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455 } else { /* decode response */
5456 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5457
Jeff Layton820a8032011-05-04 08:05:26 -04005458 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459 rc = -EIO; /* bad smb */
5460 } else {
5461 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5462 response_data =
5463 (FILE_SYSTEM_POSIX_INFO
5464 *) (((char *) &pSMBr->hdr.Protocol) +
5465 data_offset);
5466 FSData->f_bsize =
5467 le32_to_cpu(response_data->BlockSize);
5468 FSData->f_blocks =
5469 le64_to_cpu(response_data->TotalBlocks);
5470 FSData->f_bfree =
5471 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005472 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005473 FSData->f_bavail = FSData->f_bfree;
5474 } else {
5475 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005476 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005477 }
Steve French790fe572007-07-07 19:25:05 +00005478 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005480 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005481 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005483 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005484 }
5485 }
5486 cifs_buf_release(pSMB);
5487
5488 if (rc == -EAGAIN)
5489 goto QFSPosixRetry;
5490
5491 return rc;
5492}
5493
5494
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005495/*
5496 * We can not use write of zero bytes trick to set file size due to need for
5497 * large file support. Also note that this SetPathInfo is preferred to
5498 * SetFileInfo based method in next routine which is only needed to work around
5499 * a sharing violation bugin Samba which this routine can run into.
5500 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005502CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005503 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5504 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005505{
5506 struct smb_com_transaction2_spi_req *pSMB = NULL;
5507 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5508 struct file_end_of_file_info *parm_data;
5509 int name_len;
5510 int rc = 0;
5511 int bytes_returned = 0;
Steve French2baa2682014-09-27 02:19:01 -05005512 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005513
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514 __u16 params, byte_count, data_count, param_offset, offset;
5515
Joe Perchesf96637b2013-05-04 22:12:25 -05005516 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517SetEOFRetry:
5518 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5519 (void **) &pSMBr);
5520 if (rc)
5521 return rc;
5522
5523 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5524 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005525 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5526 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005527 name_len++; /* trailing null */
5528 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005529 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005530 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005531 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005532 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005533 }
5534 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005535 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005537 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005538 pSMB->MaxSetupCount = 0;
5539 pSMB->Reserved = 0;
5540 pSMB->Flags = 0;
5541 pSMB->Timeout = 0;
5542 pSMB->Reserved2 = 0;
5543 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005544 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005545 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005546 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005547 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5548 pSMB->InformationLevel =
5549 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5550 else
5551 pSMB->InformationLevel =
5552 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5553 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005554 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5555 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005556 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557 else
5558 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005559 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005560 }
5561
5562 parm_data =
5563 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5564 offset);
5565 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5566 pSMB->DataOffset = cpu_to_le16(offset);
5567 pSMB->SetupCount = 1;
5568 pSMB->Reserved3 = 0;
5569 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5570 byte_count = 3 /* pad */ + params + data_count;
5571 pSMB->DataCount = cpu_to_le16(data_count);
5572 pSMB->TotalDataCount = pSMB->DataCount;
5573 pSMB->ParameterCount = cpu_to_le16(params);
5574 pSMB->TotalParameterCount = pSMB->ParameterCount;
5575 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005576 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577 parm_data->FileSize = cpu_to_le64(size);
5578 pSMB->ByteCount = cpu_to_le16(byte_count);
5579 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5580 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005581 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005582 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583
5584 cifs_buf_release(pSMB);
5585
5586 if (rc == -EAGAIN)
5587 goto SetEOFRetry;
5588
5589 return rc;
5590}
5591
5592int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005593CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5594 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005595{
5596 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597 struct file_end_of_file_info *parm_data;
5598 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005599 __u16 params, param_offset, offset, byte_count, count;
5600
Joe Perchesf96637b2013-05-04 22:12:25 -05005601 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5602 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005603 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5604
Linus Torvalds1da177e2005-04-16 15:20:36 -07005605 if (rc)
5606 return rc;
5607
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005608 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5609 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005610
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611 params = 6;
5612 pSMB->MaxSetupCount = 0;
5613 pSMB->Reserved = 0;
5614 pSMB->Flags = 0;
5615 pSMB->Timeout = 0;
5616 pSMB->Reserved2 = 0;
5617 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5618 offset = param_offset + params;
5619
Linus Torvalds1da177e2005-04-16 15:20:36 -07005620 count = sizeof(struct file_end_of_file_info);
5621 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005622 /* BB find exact max SMB PDU from sess structure BB */
5623 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005624 pSMB->SetupCount = 1;
5625 pSMB->Reserved3 = 0;
5626 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5627 byte_count = 3 /* pad */ + params + count;
5628 pSMB->DataCount = cpu_to_le16(count);
5629 pSMB->ParameterCount = cpu_to_le16(params);
5630 pSMB->TotalDataCount = pSMB->DataCount;
5631 pSMB->TotalParameterCount = pSMB->ParameterCount;
5632 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5633 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005634 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5635 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005636 pSMB->DataOffset = cpu_to_le16(offset);
5637 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005638 pSMB->Fid = cfile->fid.netfid;
5639 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005640 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5641 pSMB->InformationLevel =
5642 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5643 else
5644 pSMB->InformationLevel =
5645 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005646 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005647 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5648 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005649 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650 else
5651 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005652 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005653 }
5654 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005655 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005657 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005658 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005659 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005660 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5661 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005662 }
5663
Steve French50c2f752007-07-13 00:33:32 +00005664 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005665 since file handle passed in no longer valid */
5666
5667 return rc;
5668}
5669
Steve French50c2f752007-07-13 00:33:32 +00005670/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005671 an open handle, rather than by pathname - this is awkward due to
5672 potential access conflicts on the open, but it is unavoidable for these
5673 old servers since the only other choice is to go from 100 nanosecond DCE
5674 time and resort to the original setpathinfo level which takes the ancient
5675 DOS time format with 2 second granularity */
5676int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005677CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005678 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005679{
5680 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005681 char *data_offset;
5682 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005683 __u16 params, param_offset, offset, byte_count, count;
5684
Joe Perchesf96637b2013-05-04 22:12:25 -05005685 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005686 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5687
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688 if (rc)
5689 return rc;
5690
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005691 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5692 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005693
Linus Torvalds1da177e2005-04-16 15:20:36 -07005694 params = 6;
5695 pSMB->MaxSetupCount = 0;
5696 pSMB->Reserved = 0;
5697 pSMB->Flags = 0;
5698 pSMB->Timeout = 0;
5699 pSMB->Reserved2 = 0;
5700 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5701 offset = param_offset + params;
5702
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005703 data_offset = (char *)pSMB +
5704 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005705
Steve French26f57362007-08-30 22:09:15 +00005706 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005707 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005708 /* BB find max SMB PDU from sess */
5709 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005710 pSMB->SetupCount = 1;
5711 pSMB->Reserved3 = 0;
5712 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5713 byte_count = 3 /* pad */ + params + count;
5714 pSMB->DataCount = cpu_to_le16(count);
5715 pSMB->ParameterCount = cpu_to_le16(params);
5716 pSMB->TotalDataCount = pSMB->DataCount;
5717 pSMB->TotalParameterCount = pSMB->ParameterCount;
5718 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5719 pSMB->DataOffset = cpu_to_le16(offset);
5720 pSMB->Fid = fid;
5721 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5722 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5723 else
5724 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5725 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005726 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005727 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005728 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005729 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005730 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00005731 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005732 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5733 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005734
Steve French50c2f752007-07-13 00:33:32 +00005735 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005736 since file handle passed in no longer valid */
5737
5738 return rc;
5739}
5740
Jeff Layton6d22f092008-09-23 11:48:35 -04005741int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005742CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005743 bool delete_file, __u16 fid, __u32 pid_of_opener)
5744{
5745 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5746 char *data_offset;
5747 int rc = 0;
5748 __u16 params, param_offset, offset, byte_count, count;
5749
Joe Perchesf96637b2013-05-04 22:12:25 -05005750 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005751 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5752
5753 if (rc)
5754 return rc;
5755
5756 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5757 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5758
5759 params = 6;
5760 pSMB->MaxSetupCount = 0;
5761 pSMB->Reserved = 0;
5762 pSMB->Flags = 0;
5763 pSMB->Timeout = 0;
5764 pSMB->Reserved2 = 0;
5765 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5766 offset = param_offset + params;
5767
5768 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5769
5770 count = 1;
5771 pSMB->MaxParameterCount = cpu_to_le16(2);
5772 /* BB find max SMB PDU from sess */
5773 pSMB->MaxDataCount = cpu_to_le16(1000);
5774 pSMB->SetupCount = 1;
5775 pSMB->Reserved3 = 0;
5776 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5777 byte_count = 3 /* pad */ + params + count;
5778 pSMB->DataCount = cpu_to_le16(count);
5779 pSMB->ParameterCount = cpu_to_le16(params);
5780 pSMB->TotalDataCount = pSMB->DataCount;
5781 pSMB->TotalParameterCount = pSMB->ParameterCount;
5782 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5783 pSMB->DataOffset = cpu_to_le16(offset);
5784 pSMB->Fid = fid;
5785 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5786 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005787 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005788 pSMB->ByteCount = cpu_to_le16(byte_count);
5789 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005790 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005791 cifs_small_buf_release(pSMB);
Jeff Layton6d22f092008-09-23 11:48:35 -04005792 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005793 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005794
5795 return rc;
5796}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005797
5798int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005799CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005800 const char *fileName, const FILE_BASIC_INFO *data,
5801 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005802{
5803 TRANSACTION2_SPI_REQ *pSMB = NULL;
5804 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5805 int name_len;
5806 int rc = 0;
5807 int bytes_returned = 0;
5808 char *data_offset;
5809 __u16 params, param_offset, offset, byte_count, count;
5810
Joe Perchesf96637b2013-05-04 22:12:25 -05005811 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005812
5813SetTimesRetry:
5814 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5815 (void **) &pSMBr);
5816 if (rc)
5817 return rc;
5818
5819 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5820 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005821 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5822 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005823 name_len++; /* trailing null */
5824 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005825 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005826 name_len = strnlen(fileName, PATH_MAX);
5827 name_len++; /* trailing null */
5828 strncpy(pSMB->FileName, fileName, name_len);
5829 }
5830
5831 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005832 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005833 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005834 /* BB find max SMB PDU from sess structure BB */
5835 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005836 pSMB->MaxSetupCount = 0;
5837 pSMB->Reserved = 0;
5838 pSMB->Flags = 0;
5839 pSMB->Timeout = 0;
5840 pSMB->Reserved2 = 0;
5841 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005842 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005843 offset = param_offset + params;
5844 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5845 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5846 pSMB->DataOffset = cpu_to_le16(offset);
5847 pSMB->SetupCount = 1;
5848 pSMB->Reserved3 = 0;
5849 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5850 byte_count = 3 /* pad */ + params + count;
5851
5852 pSMB->DataCount = cpu_to_le16(count);
5853 pSMB->ParameterCount = cpu_to_le16(params);
5854 pSMB->TotalDataCount = pSMB->DataCount;
5855 pSMB->TotalParameterCount = pSMB->ParameterCount;
5856 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5857 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5858 else
5859 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5860 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005861 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005862 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005863 pSMB->ByteCount = cpu_to_le16(byte_count);
5864 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5865 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005866 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005867 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005868
5869 cifs_buf_release(pSMB);
5870
5871 if (rc == -EAGAIN)
5872 goto SetTimesRetry;
5873
5874 return rc;
5875}
5876
5877/* Can not be used to set time stamps yet (due to old DOS time format) */
5878/* Can be used to set attributes */
5879#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5880 handling it anyway and NT4 was what we thought it would be needed for
5881 Do not delete it until we prove whether needed for Win9x though */
5882int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005883CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005884 __u16 dos_attrs, const struct nls_table *nls_codepage)
5885{
5886 SETATTR_REQ *pSMB = NULL;
5887 SETATTR_RSP *pSMBr = NULL;
5888 int rc = 0;
5889 int bytes_returned;
5890 int name_len;
5891
Joe Perchesf96637b2013-05-04 22:12:25 -05005892 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005893
5894SetAttrLgcyRetry:
5895 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5896 (void **) &pSMBr);
5897 if (rc)
5898 return rc;
5899
5900 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5901 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005902 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5903 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005904 name_len++; /* trailing null */
5905 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005906 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005907 name_len = strnlen(fileName, PATH_MAX);
5908 name_len++; /* trailing null */
5909 strncpy(pSMB->fileName, fileName, name_len);
5910 }
5911 pSMB->attr = cpu_to_le16(dos_attrs);
5912 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005913 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005914 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5915 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5916 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005917 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005918 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005919
5920 cifs_buf_release(pSMB);
5921
5922 if (rc == -EAGAIN)
5923 goto SetAttrLgcyRetry;
5924
5925 return rc;
5926}
5927#endif /* temporarily unneeded SetAttr legacy function */
5928
Jeff Layton654cf142009-07-09 20:02:49 -04005929static void
5930cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5931 const struct cifs_unix_set_info_args *args)
5932{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005933 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005934 u64 mode = args->mode;
5935
Eric W. Biederman49418b22013-02-06 00:57:56 -08005936 if (uid_valid(args->uid))
5937 uid = from_kuid(&init_user_ns, args->uid);
5938 if (gid_valid(args->gid))
5939 gid = from_kgid(&init_user_ns, args->gid);
5940
Jeff Layton654cf142009-07-09 20:02:49 -04005941 /*
5942 * Samba server ignores set of file size to zero due to bugs in some
5943 * older clients, but we should be precise - we use SetFileSize to
5944 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005945 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005946 * zero instead of -1 here
5947 */
5948 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5949 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5950 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5951 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5952 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005953 data_offset->Uid = cpu_to_le64(uid);
5954 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005955 /* better to leave device as zero when it is */
5956 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5957 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5958 data_offset->Permissions = cpu_to_le64(mode);
5959
5960 if (S_ISREG(mode))
5961 data_offset->Type = cpu_to_le32(UNIX_FILE);
5962 else if (S_ISDIR(mode))
5963 data_offset->Type = cpu_to_le32(UNIX_DIR);
5964 else if (S_ISLNK(mode))
5965 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5966 else if (S_ISCHR(mode))
5967 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5968 else if (S_ISBLK(mode))
5969 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5970 else if (S_ISFIFO(mode))
5971 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5972 else if (S_ISSOCK(mode))
5973 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5974}
5975
Linus Torvalds1da177e2005-04-16 15:20:36 -07005976int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005977CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005978 const struct cifs_unix_set_info_args *args,
5979 u16 fid, u32 pid_of_opener)
5980{
5981 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005982 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005983 int rc = 0;
5984 u16 params, param_offset, offset, byte_count, count;
5985
Joe Perchesf96637b2013-05-04 22:12:25 -05005986 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005987 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5988
5989 if (rc)
5990 return rc;
5991
5992 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5993 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5994
5995 params = 6;
5996 pSMB->MaxSetupCount = 0;
5997 pSMB->Reserved = 0;
5998 pSMB->Flags = 0;
5999 pSMB->Timeout = 0;
6000 pSMB->Reserved2 = 0;
6001 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
6002 offset = param_offset + params;
6003
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006004 data_offset = (char *)pSMB +
6005 offsetof(struct smb_hdr, Protocol) + offset;
6006
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006007 count = sizeof(FILE_UNIX_BASIC_INFO);
6008
6009 pSMB->MaxParameterCount = cpu_to_le16(2);
6010 /* BB find max SMB PDU from sess */
6011 pSMB->MaxDataCount = cpu_to_le16(1000);
6012 pSMB->SetupCount = 1;
6013 pSMB->Reserved3 = 0;
6014 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
6015 byte_count = 3 /* pad */ + params + count;
6016 pSMB->DataCount = cpu_to_le16(count);
6017 pSMB->ParameterCount = cpu_to_le16(params);
6018 pSMB->TotalDataCount = pSMB->DataCount;
6019 pSMB->TotalParameterCount = pSMB->ParameterCount;
6020 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6021 pSMB->DataOffset = cpu_to_le16(offset);
6022 pSMB->Fid = fid;
6023 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6024 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006025 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006026 pSMB->ByteCount = cpu_to_le16(byte_count);
6027
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006028 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006029
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04006030 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07006031 cifs_small_buf_release(pSMB);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006032 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006033 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
6034 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006035
6036 /* Note: On -EAGAIN error only caller can retry on handle based calls
6037 since file handle passed in no longer valid */
6038
6039 return rc;
6040}
6041
6042int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006043CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006044 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006045 const struct cifs_unix_set_info_args *args,
6046 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006047{
6048 TRANSACTION2_SPI_REQ *pSMB = NULL;
6049 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6050 int name_len;
6051 int rc = 0;
6052 int bytes_returned = 0;
6053 FILE_UNIX_BASIC_INFO *data_offset;
6054 __u16 params, param_offset, offset, count, byte_count;
6055
Joe Perchesf96637b2013-05-04 22:12:25 -05006056 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006057setPermsRetry:
6058 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6059 (void **) &pSMBr);
6060 if (rc)
6061 return rc;
6062
6063 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6064 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006065 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06006066 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006067 name_len++; /* trailing null */
6068 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07006069 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006070 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006071 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006072 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006073 }
6074
6075 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006076 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006077 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006078 /* BB find max SMB PDU from sess structure BB */
6079 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006080 pSMB->MaxSetupCount = 0;
6081 pSMB->Reserved = 0;
6082 pSMB->Flags = 0;
6083 pSMB->Timeout = 0;
6084 pSMB->Reserved2 = 0;
6085 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006086 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006087 offset = param_offset + params;
6088 data_offset =
6089 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6090 offset);
6091 memset(data_offset, 0, count);
6092 pSMB->DataOffset = cpu_to_le16(offset);
6093 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6094 pSMB->SetupCount = 1;
6095 pSMB->Reserved3 = 0;
6096 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6097 byte_count = 3 /* pad */ + params + count;
6098 pSMB->ParameterCount = cpu_to_le16(params);
6099 pSMB->DataCount = cpu_to_le16(count);
6100 pSMB->TotalParameterCount = pSMB->ParameterCount;
6101 pSMB->TotalDataCount = pSMB->DataCount;
6102 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6103 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006104 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006105
Jeff Layton654cf142009-07-09 20:02:49 -04006106 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006107
6108 pSMB->ByteCount = cpu_to_le16(byte_count);
6109 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6110 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006111 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006112 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006113
Steve French0d817bc2008-05-22 02:02:03 +00006114 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006115 if (rc == -EAGAIN)
6116 goto setPermsRetry;
6117 return rc;
6118}
6119
Linus Torvalds1da177e2005-04-16 15:20:36 -07006120#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006121/*
6122 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6123 * function used by listxattr and getxattr type calls. When ea_name is set,
6124 * it looks for that attribute name and stuffs that value into the EAData
6125 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6126 * buffer. In both cases, the return value is either the length of the
6127 * resulting data or a negative error code. If EAData is a NULL pointer then
6128 * the data isn't copied to it, but the length is returned.
6129 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006130ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006131CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006132 const unsigned char *searchName, const unsigned char *ea_name,
6133 char *EAData, size_t buf_size,
Steve French67b4c882017-05-12 20:59:10 -05006134 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006135{
6136 /* BB assumes one setup word */
6137 TRANSACTION2_QPI_REQ *pSMB = NULL;
6138 TRANSACTION2_QPI_RSP *pSMBr = NULL;
Steve French67b4c882017-05-12 20:59:10 -05006139 int remap = cifs_remap(cifs_sb);
6140 struct nls_table *nls_codepage = cifs_sb->local_nls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006141 int rc = 0;
6142 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006143 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006144 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006145 struct fea *temp_fea;
6146 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006147 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006148 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006149 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006150
Joe Perchesf96637b2013-05-04 22:12:25 -05006151 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006152QAllEAsRetry:
6153 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6154 (void **) &pSMBr);
6155 if (rc)
6156 return rc;
6157
6158 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006159 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006160 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6161 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006162 list_len++; /* trailing null */
6163 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006164 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006165 list_len = strnlen(searchName, PATH_MAX);
6166 list_len++; /* trailing null */
6167 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006168 }
6169
Jeff Layton6e462b92010-02-10 16:18:26 -05006170 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006171 pSMB->TotalDataCount = 0;
6172 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006173 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006174 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006175 pSMB->MaxSetupCount = 0;
6176 pSMB->Reserved = 0;
6177 pSMB->Flags = 0;
6178 pSMB->Timeout = 0;
6179 pSMB->Reserved2 = 0;
6180 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006181 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006182 pSMB->DataCount = 0;
6183 pSMB->DataOffset = 0;
6184 pSMB->SetupCount = 1;
6185 pSMB->Reserved3 = 0;
6186 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6187 byte_count = params + 1 /* pad */ ;
6188 pSMB->TotalParameterCount = cpu_to_le16(params);
6189 pSMB->ParameterCount = pSMB->TotalParameterCount;
6190 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6191 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006192 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006193 pSMB->ByteCount = cpu_to_le16(byte_count);
6194
6195 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6196 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6197 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006198 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006199 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006200 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006201
6202
6203 /* BB also check enough total bytes returned */
6204 /* BB we need to improve the validity checking
6205 of these trans2 responses */
6206
6207 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006208 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006209 rc = -EIO; /* bad smb */
6210 goto QAllEAsOut;
6211 }
6212
6213 /* check that length of list is not more than bcc */
6214 /* check that each entry does not go beyond length
6215 of list */
6216 /* check that each element of each entry does not
6217 go beyond end of list */
6218 /* validate_trans2_offsets() */
6219 /* BB check if start of smb + data_offset > &bcc+ bcc */
6220
6221 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6222 ea_response_data = (struct fealist *)
6223 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6224
Jeff Layton6e462b92010-02-10 16:18:26 -05006225 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006226 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006227 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006228 cifs_dbg(FYI, "empty EA list returned from server\n");
Steve French60977fc2014-03-25 19:46:36 -05006229 /* didn't find the named attribute */
6230 if (ea_name)
6231 rc = -ENODATA;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006232 goto QAllEAsOut;
6233 }
6234
Jeff Layton0cd126b2010-02-10 16:18:26 -05006235 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006236 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006237 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006238 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006239 rc = -EIO;
6240 goto QAllEAsOut;
6241 }
6242
Jeff Laytonf0d38682010-02-10 16:18:26 -05006243 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006244 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006245 temp_fea = ea_response_data->list;
6246 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006247 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006248 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006249 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006250
Jeff Layton6e462b92010-02-10 16:18:26 -05006251 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006252 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006253 /* make sure we can read name_len and value_len */
6254 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006255 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006256 rc = -EIO;
6257 goto QAllEAsOut;
6258 }
6259
6260 name_len = temp_fea->name_len;
6261 value_len = le16_to_cpu(temp_fea->value_len);
6262 list_len -= name_len + 1 + value_len;
6263 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006264 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006265 rc = -EIO;
6266 goto QAllEAsOut;
6267 }
6268
Jeff Layton31c05192010-02-10 16:18:26 -05006269 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006270 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006271 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006272 temp_ptr += name_len + 1;
6273 rc = value_len;
6274 if (buf_size == 0)
6275 goto QAllEAsOut;
6276 if ((size_t)value_len > buf_size) {
6277 rc = -ERANGE;
6278 goto QAllEAsOut;
6279 }
6280 memcpy(EAData, temp_ptr, value_len);
6281 goto QAllEAsOut;
6282 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006283 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006284 /* account for prefix user. and trailing null */
6285 rc += (5 + 1 + name_len);
6286 if (rc < (int) buf_size) {
6287 memcpy(EAData, "user.", 5);
6288 EAData += 5;
6289 memcpy(EAData, temp_ptr, name_len);
6290 EAData += name_len;
6291 /* null terminate name */
6292 *EAData = 0;
6293 ++EAData;
6294 } else if (buf_size == 0) {
6295 /* skip copy - calc size only */
6296 } else {
6297 /* stop before overrun buffer */
6298 rc = -ERANGE;
6299 break;
6300 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006301 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006302 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006303 temp_fea = (struct fea *)temp_ptr;
6304 }
6305
Jeff Layton31c05192010-02-10 16:18:26 -05006306 /* didn't find the named attribute */
6307 if (ea_name)
6308 rc = -ENODATA;
6309
Jeff Laytonf0d38682010-02-10 16:18:26 -05006310QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006311 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006312 if (rc == -EAGAIN)
6313 goto QAllEAsRetry;
6314
6315 return (ssize_t)rc;
6316}
6317
Linus Torvalds1da177e2005-04-16 15:20:36 -07006318int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006319CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6320 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006321 const __u16 ea_value_len, const struct nls_table *nls_codepage,
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006322 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006323{
6324 struct smb_com_transaction2_spi_req *pSMB = NULL;
6325 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6326 struct fealist *parm_data;
6327 int name_len;
6328 int rc = 0;
6329 int bytes_returned = 0;
6330 __u16 params, param_offset, byte_count, offset, count;
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006331 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006332
Joe Perchesf96637b2013-05-04 22:12:25 -05006333 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006334SetEARetry:
6335 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6336 (void **) &pSMBr);
6337 if (rc)
6338 return rc;
6339
6340 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6341 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006342 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6343 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006344 name_len++; /* trailing null */
6345 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006346 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006347 name_len = strnlen(fileName, PATH_MAX);
6348 name_len++; /* trailing null */
6349 strncpy(pSMB->FileName, fileName, name_len);
6350 }
6351
6352 params = 6 + name_len;
6353
6354 /* done calculating parms using name_len of file name,
6355 now use name_len to calculate length of ea name
6356 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006357 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006358 name_len = 0;
6359 else
Steve French50c2f752007-07-13 00:33:32 +00006360 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006361
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006362 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006363 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006364 /* BB find max SMB PDU from sess */
6365 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006366 pSMB->MaxSetupCount = 0;
6367 pSMB->Reserved = 0;
6368 pSMB->Flags = 0;
6369 pSMB->Timeout = 0;
6370 pSMB->Reserved2 = 0;
6371 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006372 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006373 offset = param_offset + params;
6374 pSMB->InformationLevel =
6375 cpu_to_le16(SMB_SET_FILE_EA);
6376
Arnd Bergmannade7db92018-02-02 16:48:47 +01006377 parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006378 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6379 pSMB->DataOffset = cpu_to_le16(offset);
6380 pSMB->SetupCount = 1;
6381 pSMB->Reserved3 = 0;
6382 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6383 byte_count = 3 /* pad */ + params + count;
6384 pSMB->DataCount = cpu_to_le16(count);
6385 parm_data->list_len = cpu_to_le32(count);
6386 parm_data->list[0].EA_flags = 0;
6387 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006388 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006389 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006390 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006391 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006392 parm_data->list[0].name[name_len] = 0;
6393 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6394 /* caller ensures that ea_value_len is less than 64K but
6395 we need to ensure that it fits within the smb */
6396
Steve French50c2f752007-07-13 00:33:32 +00006397 /*BB add length check to see if it would fit in
6398 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006399 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6400 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006401 memcpy(parm_data->list[0].name+name_len+1,
6402 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006403
6404 pSMB->TotalDataCount = pSMB->DataCount;
6405 pSMB->ParameterCount = cpu_to_le16(params);
6406 pSMB->TotalParameterCount = pSMB->ParameterCount;
6407 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006408 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006409 pSMB->ByteCount = cpu_to_le16(byte_count);
6410 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6411 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006412 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006413 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006414
6415 cifs_buf_release(pSMB);
6416
6417 if (rc == -EAGAIN)
6418 goto SetEARetry;
6419
6420 return rc;
6421}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006422#endif
Steve French0eff0e22011-02-24 05:39:23 +00006423
6424#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6425/*
6426 * Years ago the kernel added a "dnotify" function for Samba server,
6427 * to allow network clients (such as Windows) to display updated
6428 * lists of files in directory listings automatically when
6429 * files are added by one user when another user has the
6430 * same directory open on their desktop. The Linux cifs kernel
6431 * client hooked into the kernel side of this interface for
6432 * the same reason, but ironically when the VFS moved from
6433 * "dnotify" to "inotify" it became harder to plug in Linux
6434 * network file system clients (the most obvious use case
6435 * for notify interfaces is when multiple users can update
6436 * the contents of the same directory - exactly what network
6437 * file systems can do) although the server (Samba) could
6438 * still use it. For the short term we leave the worker
6439 * function ifdeffed out (below) until inotify is fixed
6440 * in the VFS to make it easier to plug in network file
6441 * system clients. If inotify turns out to be permanently
6442 * incompatible for network fs clients, we could instead simply
6443 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6444 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006445int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006446 const int notify_subdirs, const __u16 netfid,
6447 __u32 filter, struct file *pfile, int multishot,
6448 const struct nls_table *nls_codepage)
6449{
6450 int rc = 0;
6451 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6452 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6453 struct dir_notify_req *dnotify_req;
6454 int bytes_returned;
6455
Joe Perchesf96637b2013-05-04 22:12:25 -05006456 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006457 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6458 (void **) &pSMBr);
6459 if (rc)
6460 return rc;
6461
6462 pSMB->TotalParameterCount = 0 ;
6463 pSMB->TotalDataCount = 0;
6464 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006465 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006466 pSMB->MaxSetupCount = 4;
6467 pSMB->Reserved = 0;
6468 pSMB->ParameterOffset = 0;
6469 pSMB->DataCount = 0;
6470 pSMB->DataOffset = 0;
6471 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6472 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6473 pSMB->ParameterCount = pSMB->TotalParameterCount;
6474 if (notify_subdirs)
6475 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6476 pSMB->Reserved2 = 0;
6477 pSMB->CompletionFilter = cpu_to_le32(filter);
6478 pSMB->Fid = netfid; /* file handle always le */
6479 pSMB->ByteCount = 0;
6480
6481 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6482 (struct smb_hdr *)pSMBr, &bytes_returned,
6483 CIFS_ASYNC_OP);
6484 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006485 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006486 } else {
6487 /* Add file to outstanding requests */
6488 /* BB change to kmem cache alloc */
6489 dnotify_req = kmalloc(
6490 sizeof(struct dir_notify_req),
6491 GFP_KERNEL);
6492 if (dnotify_req) {
6493 dnotify_req->Pid = pSMB->hdr.Pid;
6494 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6495 dnotify_req->Mid = pSMB->hdr.Mid;
6496 dnotify_req->Tid = pSMB->hdr.Tid;
6497 dnotify_req->Uid = pSMB->hdr.Uid;
6498 dnotify_req->netfid = netfid;
6499 dnotify_req->pfile = pfile;
6500 dnotify_req->filter = filter;
6501 dnotify_req->multishot = multishot;
6502 spin_lock(&GlobalMid_Lock);
6503 list_add_tail(&dnotify_req->lhead,
6504 &GlobalDnotifyReqList);
6505 spin_unlock(&GlobalMid_Lock);
6506 } else
6507 rc = -ENOMEM;
6508 }
6509 cifs_buf_release(pSMB);
6510 return rc;
6511}
6512#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */