blob: c8e42785d261bf5ea3ed60974ea51b5ffbd52599 [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
110 mutex_lock(&tcon->prfid_mutex);
111 tcon->valid_root_fid = false;
112 memset(tcon->prfid, 0, sizeof(struct cifs_fid));
113 mutex_unlock(&tcon->prfid_mutex);
114
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) {
160 wait_event_interruptible_timeout(server->response_q,
Steve Frenchfd88ce92011-04-12 01:01:14 +0000161 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
Jeff Layton9162ab22009-09-03 12:07:17 -0400162
Steve Frenchfd88ce92011-04-12 01:01:14 +0000163 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400164 if (server->tcpStatus != CifsNeedReconnect)
165 break;
166
167 /*
168 * on "soft" mounts we wait once. Hard mounts keep
169 * retrying until process is killed or server comes
170 * back on-line
171 */
Jeff Laytond4025392011-02-07 08:54:35 -0500172 if (!tcon->retry) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500173 cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
Jeff Layton9162ab22009-09-03 12:07:17 -0400174 return -EHOSTDOWN;
175 }
176 }
177
178 if (!ses->need_reconnect && !tcon->need_reconnect)
179 return 0;
180
181 nls_codepage = load_nls_default();
182
183 /*
184 * need to prevent multiple threads trying to simultaneously
185 * reconnect the same SMB session
186 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000187 mutex_lock(&ses->session_mutex);
Samuel Cabrero76e75272017-07-11 12:44:39 +0200188
189 /*
190 * Recheck after acquire mutex. If another thread is negotiating
191 * and the server never sends an answer the socket will be closed
192 * and tcpStatus set to reconnect.
193 */
194 if (server->tcpStatus == CifsNeedReconnect) {
195 rc = -EHOSTDOWN;
196 mutex_unlock(&ses->session_mutex);
197 goto out;
198 }
199
Jeff Layton198b5682010-04-24 07:57:48 -0400200 rc = cifs_negotiate_protocol(0, ses);
201 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400202 rc = cifs_setup_session(0, ses, nls_codepage);
203
204 /* do we need to reconnect tcon? */
205 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000206 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400207 goto out;
208 }
209
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400210 cifs_mark_open_files_invalid(tcon);
Jeff Layton9162ab22009-09-03 12:07:17 -0400211 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000212 mutex_unlock(&ses->session_mutex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500213 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400214
Steve Frenchc318e6c2018-04-04 14:08:52 -0500215 if (rc) {
216 printk_once(KERN_WARNING "reconnect tcon failed rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400217 goto out;
Steve Frenchc318e6c2018-04-04 14:08:52 -0500218 }
Jeff Layton9162ab22009-09-03 12:07:17 -0400219
Jeff Layton9162ab22009-09-03 12:07:17 -0400220 atomic_inc(&tconInfoReconnectCount);
221
222 /* tell server Unix caps we support */
223 if (ses->capabilities & CAP_UNIX)
224 reset_cifs_unix_caps(0, tcon, NULL, NULL);
225
226 /*
227 * Removed call to reopen open files here. It is safer (and faster) to
228 * reopen files one at a time as needed in read and write.
229 *
230 * FIXME: what about file locks? don't we need to reclaim them ASAP?
231 */
232
233out:
234 /*
235 * Check if handle based operation so we know whether we can continue
236 * or not without returning to caller to reset file handle
237 */
238 switch (smb_command) {
239 case SMB_COM_READ_ANDX:
240 case SMB_COM_WRITE_ANDX:
241 case SMB_COM_CLOSE:
242 case SMB_COM_FIND_CLOSE2:
243 case SMB_COM_LOCKING_ANDX:
244 rc = -EAGAIN;
245 }
246
247 unload_nls(nls_codepage);
248 return rc;
249}
250
Steve Frenchad7a2922008-02-07 23:25:02 +0000251/* Allocate and return pointer to an SMB request buffer, and set basic
252 SMB information in the SMB header. If the return code is zero, this
253 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254static int
Steve French96daf2b2011-05-27 04:34:02 +0000255small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000256 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257{
Jeff Laytonf5695992010-09-29 15:27:08 -0400258 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
Jeff Layton9162ab22009-09-03 12:07:17 -0400260 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000261 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 return rc;
263
264 *request_buf = cifs_small_buf_get();
265 if (*request_buf == NULL) {
266 /* BB should we add a retry in here if not a writepage? */
267 return -ENOMEM;
268 }
269
Steve French63135e02007-07-17 17:34:02 +0000270 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000271 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
Steve French790fe572007-07-07 19:25:05 +0000273 if (tcon != NULL)
274 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700275
Jeff Laytonf5695992010-09-29 15:27:08 -0400276 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000277}
278
Steve French12b3b8f2006-02-09 21:12:47 +0000279int
Steve French50c2f752007-07-13 00:33:32 +0000280small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000281 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000282{
283 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000284 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000285
Steve French5815449d2006-02-14 01:36:20 +0000286 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000287 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000288 return rc;
289
Steve French04fdabe2006-02-10 05:52:50 +0000290 buffer = (struct smb_hdr *)*request_buf;
Pavel Shilovsky88257362012-05-23 14:01:59 +0400291 buffer->Mid = get_next_mid(ses->server);
Steve French12b3b8f2006-02-09 21:12:47 +0000292 if (ses->capabilities & CAP_UNICODE)
293 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000294 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000295 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
296
297 /* uid, tid can stay at zero as set in header assemble */
298
Steve French50c2f752007-07-13 00:33:32 +0000299 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000300 this function is used after 1st of session setup requests */
301
302 return rc;
303}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
305/* If the return code is zero, this function must fill in request_buf pointer */
306static int
Steve French96daf2b2011-05-27 04:34:02 +0000307__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400308 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 *request_buf = cifs_buf_get();
311 if (*request_buf == NULL) {
312 /* BB should we add a retry in here if not a writepage? */
313 return -ENOMEM;
314 }
315 /* Although the original thought was we needed the response buf for */
316 /* potential retries of smb operations it turns out we can determine */
317 /* from the mid flags when the request buffer can be resent without */
318 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000319 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000320 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
322 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000323 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
Steve French790fe572007-07-07 19:25:05 +0000325 if (tcon != NULL)
326 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700327
Jeff Laytonf5695992010-09-29 15:27:08 -0400328 return 0;
329}
330
331/* If the return code is zero, this function must fill in request_buf pointer */
332static int
Steve French96daf2b2011-05-27 04:34:02 +0000333smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400334 void **request_buf, void **response_buf)
335{
336 int rc;
337
338 rc = cifs_reconnect_tcon(tcon, smb_command);
339 if (rc)
340 return rc;
341
342 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
343}
344
345static int
Steve French96daf2b2011-05-27 04:34:02 +0000346smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400347 void **request_buf, void **response_buf)
348{
349 if (tcon->ses->need_reconnect || tcon->need_reconnect)
350 return -EHOSTDOWN;
351
352 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353}
354
Steve French50c2f752007-07-13 00:33:32 +0000355static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356{
Jeff Layton12df83c2011-01-20 13:36:51 -0500357 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
Jeff Layton12df83c2011-01-20 13:36:51 -0500359 /* check for plausible wct */
360 if (pSMB->hdr.WordCount < 10)
361 goto vt2_err;
362
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500364 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
365 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
366 goto vt2_err;
367
Jeff Layton12df83c2011-01-20 13:36:51 -0500368 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
369 if (total_size >= 512)
370 goto vt2_err;
371
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400372 /* check that bcc is at least as big as parms + data, and that it is
373 * less than negotiated smb buffer
374 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500375 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
376 if (total_size > get_bcc(&pSMB->hdr) ||
377 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
378 goto vt2_err;
379
380 return 0;
381vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000382 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500384 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385}
Jeff Layton690c5222011-01-20 13:36:51 -0500386
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400387static int
Jeff Layton3f618222013-06-12 19:52:14 -0500388decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400389{
390 int rc = 0;
391 u16 count;
392 char *guid = pSMBr->u.extended_response.GUID;
Jeff Layton3f618222013-06-12 19:52:14 -0500393 struct TCP_Server_Info *server = ses->server;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400394
395 count = get_bcc(&pSMBr->hdr);
396 if (count < SMB1_CLIENT_GUID_SIZE)
397 return -EIO;
398
399 spin_lock(&cifs_tcp_ses_lock);
400 if (server->srv_count > 1) {
401 spin_unlock(&cifs_tcp_ses_lock);
402 if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
403 cifs_dbg(FYI, "server UID changed\n");
404 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
405 }
406 } else {
407 spin_unlock(&cifs_tcp_ses_lock);
408 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
409 }
410
411 if (count == SMB1_CLIENT_GUID_SIZE) {
Jeff Layton3f618222013-06-12 19:52:14 -0500412 server->sec_ntlmssp = true;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400413 } else {
414 count -= SMB1_CLIENT_GUID_SIZE;
415 rc = decode_negTokenInit(
416 pSMBr->u.extended_response.SecurityBlob, count, server);
417 if (rc != 1)
418 return -EINVAL;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400419 }
420
421 return 0;
422}
423
Jeff Layton9ddec562013-05-26 07:00:58 -0400424int
Jeff Layton38d77c52013-05-26 07:01:00 -0400425cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
Jeff Layton9ddec562013-05-26 07:00:58 -0400426{
Jeff Layton50285882013-06-27 12:45:00 -0400427 bool srv_sign_required = server->sec_mode & server->vals->signing_required;
428 bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled;
Jeff Layton38d77c52013-05-26 07:01:00 -0400429 bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN;
430
431 /*
432 * Is signing required by mnt options? If not then check
433 * global_secflags to see if it is there.
434 */
435 if (!mnt_sign_required)
436 mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
437 CIFSSEC_MUST_SIGN);
438
439 /*
440 * If signing is required then it's automatically enabled too,
441 * otherwise, check to see if the secflags allow it.
442 */
443 mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
444 (global_secflags & CIFSSEC_MAY_SIGN);
445
446 /* If server requires signing, does client allow it? */
447 if (srv_sign_required) {
448 if (!mnt_sign_enabled) {
449 cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!");
450 return -ENOTSUPP;
Jeff Layton9ddec562013-05-26 07:00:58 -0400451 }
Jeff Layton38d77c52013-05-26 07:01:00 -0400452 server->sign = true;
453 }
454
455 /* If client requires signing, does server allow it? */
456 if (mnt_sign_required) {
457 if (!srv_sign_enabled) {
458 cifs_dbg(VFS, "Server does not support signing!");
459 return -ENOTSUPP;
460 }
461 server->sign = true;
Jeff Layton9ddec562013-05-26 07:00:58 -0400462 }
463
Long Libb4c0412018-04-17 12:17:08 -0700464 if (cifs_rdma_enabled(server) && server->sign)
465 cifs_dbg(VFS, "Signing is enabled, and RDMA read/write will be disabled");
466
Jeff Layton9ddec562013-05-26 07:00:58 -0400467 return 0;
468}
469
Jeff Layton2190eca2013-05-26 07:00:57 -0400470#ifdef CONFIG_CIFS_WEAK_PW_HASH
471static int
Jeff Layton3f618222013-06-12 19:52:14 -0500472decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400473{
474 __s16 tmp;
475 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
476
477 if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
478 return -EOPNOTSUPP;
479
Jeff Layton2190eca2013-05-26 07:00:57 -0400480 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
481 server->maxReq = min_t(unsigned int,
482 le16_to_cpu(rsp->MaxMpxCount),
483 cifs_max_pending);
484 set_credits(server, server->maxReq);
485 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Jeff Layton2190eca2013-05-26 07:00:57 -0400486 /* even though we do not use raw we might as well set this
487 accurately, in case we ever find a need for it */
488 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
489 server->max_rw = 0xFF00;
490 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
491 } else {
492 server->max_rw = 0;/* do not need to use raw anyway */
493 server->capabilities = CAP_MPX_MODE;
494 }
495 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
496 if (tmp == -1) {
497 /* OS/2 often does not set timezone therefore
498 * we must use server time to calc time zone.
499 * Could deviate slightly from the right zone.
500 * Smallest defined timezone difference is 15 minutes
501 * (i.e. Nepal). Rounding up/down is done to match
502 * this requirement.
503 */
504 int val, seconds, remain, result;
Deepa Dinamanie37fea52017-05-08 15:59:16 -0700505 struct timespec ts;
506 unsigned long utc = ktime_get_real_seconds();
Jeff Layton2190eca2013-05-26 07:00:57 -0400507 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
508 rsp->SrvTime.Time, 0);
509 cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
Deepa Dinamanie37fea52017-05-08 15:59:16 -0700510 (int)ts.tv_sec, (int)utc,
511 (int)(utc - ts.tv_sec));
512 val = (int)(utc - ts.tv_sec);
Jeff Layton2190eca2013-05-26 07:00:57 -0400513 seconds = abs(val);
514 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
515 remain = seconds % MIN_TZ_ADJ;
516 if (remain >= (MIN_TZ_ADJ / 2))
517 result += MIN_TZ_ADJ;
518 if (val < 0)
519 result = -result;
520 server->timeAdj = result;
521 } else {
522 server->timeAdj = (int)tmp;
523 server->timeAdj *= 60; /* also in seconds */
524 }
525 cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
526
527
528 /* BB get server time for time conversions and add
529 code to use it and timezone since this is not UTC */
530
531 if (rsp->EncryptionKeyLength ==
532 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
533 memcpy(server->cryptkey, rsp->EncryptionKey,
534 CIFS_CRYPTO_KEY_SIZE);
535 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
536 return -EIO; /* need cryptkey unless plain text */
537 }
538
539 cifs_dbg(FYI, "LANMAN negotiated\n");
540 return 0;
541}
542#else
543static inline int
Jeff Layton3f618222013-06-12 19:52:14 -0500544decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400545{
546 cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
547 return -EOPNOTSUPP;
548}
549#endif
550
Jeff Layton91934002013-05-26 07:00:58 -0400551static bool
Jeff Layton3f618222013-06-12 19:52:14 -0500552should_set_ext_sec_flag(enum securityEnum sectype)
Jeff Layton91934002013-05-26 07:00:58 -0400553{
Jeff Layton3f618222013-06-12 19:52:14 -0500554 switch (sectype) {
555 case RawNTLMSSP:
556 case Kerberos:
Jeff Layton91934002013-05-26 07:00:58 -0400557 return true;
Jeff Layton3f618222013-06-12 19:52:14 -0500558 case Unspecified:
559 if (global_secflags &
560 (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
561 return true;
562 /* Fallthrough */
563 default:
564 return false;
565 }
Jeff Layton91934002013-05-26 07:00:58 -0400566}
567
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400569CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570{
571 NEGOTIATE_REQ *pSMB;
572 NEGOTIATE_RSP *pSMBr;
573 int rc = 0;
574 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000575 int i;
Jeff Layton3534b852013-05-24 07:41:01 -0400576 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 u16 count;
578
Jeff Layton3534b852013-05-24 07:41:01 -0400579 if (!server) {
580 WARN(1, "%s: server is NULL!\n", __func__);
581 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 }
Jeff Layton3534b852013-05-24 07:41:01 -0400583
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
585 (void **) &pSMB, (void **) &pSMBr);
586 if (rc)
587 return rc;
Steve French750d1152006-06-27 06:28:30 +0000588
Pavel Shilovsky88257362012-05-23 14:01:59 +0400589 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000590 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000591
Jeff Layton3f618222013-06-12 19:52:14 -0500592 if (should_set_ext_sec_flag(ses->sectype)) {
Jeff Layton91934002013-05-26 07:00:58 -0400593 cifs_dbg(FYI, "Requesting extended security.");
Steve Frenchac683922009-05-06 04:16:04 +0000594 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
595 }
Steve French50c2f752007-07-13 00:33:32 +0000596
Steve French39798772006-05-31 22:40:51 +0000597 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000598 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000599 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
600 count += strlen(protocols[i].name) + 1;
601 /* null at end of source and target buffers anyway */
602 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000603 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 pSMB->ByteCount = cpu_to_le16(count);
605
606 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
607 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000608 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000609 goto neg_err_exit;
610
Jeff Layton9bf67e52010-04-24 07:57:46 -0400611 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500612 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000613 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400614 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000615 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000616 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000617 could not negotiate a common dialect */
618 rc = -EOPNOTSUPP;
619 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000620 } else if (pSMBr->hdr.WordCount == 13) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400621 server->negflavor = CIFS_NEGFLAVOR_LANMAN;
Jeff Layton3f618222013-06-12 19:52:14 -0500622 rc = decode_lanman_negprot_rsp(server, pSMBr);
Jeff Layton9ddec562013-05-26 07:00:58 -0400623 goto signing_check;
Steve French790fe572007-07-07 19:25:05 +0000624 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000625 /* unknown wct */
626 rc = -EOPNOTSUPP;
627 goto neg_err_exit;
628 }
Jeff Layton2190eca2013-05-26 07:00:57 -0400629 /* else wct == 17, NTLM or better */
630
Steve French96daf2b2011-05-27 04:34:02 +0000631 server->sec_mode = pSMBr->SecurityMode;
632 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500633 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000634
Steve French254e55e2006-06-04 05:53:15 +0000635 /* one byte, so no need to convert this or EncryptionKeyLen from
636 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300637 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
638 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400639 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000640 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400641 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000642 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500643 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000644 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000645 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
646 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400647
Jeff Laytone598d1d82013-05-26 07:00:59 -0400648 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
649 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500650 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000651 CIFS_CRYPTO_KEY_SIZE);
Noel Powerf2910952015-05-27 09:22:10 +0100652 } else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
653 server->capabilities & CAP_EXTENDED_SECURITY) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400654 server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
Jeff Layton3f618222013-06-12 19:52:14 -0500655 rc = decode_ext_sec_blob(ses, pSMBr);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400656 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000657 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Laytone598d1d82013-05-26 07:00:59 -0400658 } else {
659 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Steve French254e55e2006-06-04 05:53:15 +0000660 server->capabilities &= ~CAP_EXTENDED_SECURITY;
Jeff Laytone598d1d82013-05-26 07:00:59 -0400661 }
Steve French254e55e2006-06-04 05:53:15 +0000662
663signing_check:
Jeff Layton9ddec562013-05-26 07:00:58 -0400664 if (!rc)
Jeff Layton38d77c52013-05-26 07:01:00 -0400665 rc = cifs_enable_signing(server, ses->sign);
Steve French50c2f752007-07-13 00:33:32 +0000666neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700667 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000668
Joe Perchesf96637b2013-05-04 22:12:25 -0500669 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 return rc;
671}
672
673int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400674CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675{
676 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
Joe Perchesf96637b2013-05-04 22:12:25 -0500679 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500680
681 /* BB: do we need to check this? These should never be NULL. */
682 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
683 return -EIO;
684
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500686 * No need to return error on this operation if tid invalidated and
687 * closed on server already e.g. due to tcp session crashing. Also,
688 * the tcon is no longer on the list, so no need to take lock before
689 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 */
Steve French268875b2009-06-25 00:29:21 +0000691 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000692 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
Steve French50c2f752007-07-13 00:33:32 +0000694 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700695 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500696 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 return rc;
Steve French133672e2007-11-13 22:41:37 +0000698
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400699 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700700 cifs_small_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500702 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703
Steve French50c2f752007-07-13 00:33:32 +0000704 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500705 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 if (rc == -EAGAIN)
707 rc = 0;
708
709 return rc;
710}
711
Jeff Layton766fdbb2011-01-11 07:24:21 -0500712/*
713 * This is a no-op for now. We're not really interested in the reply, but
714 * rather in the fact that the server sent one and that server->lstrp
715 * gets updated.
716 *
717 * FIXME: maybe we should consider checking that the reply matches request?
718 */
719static void
720cifs_echo_callback(struct mid_q_entry *mid)
721{
722 struct TCP_Server_Info *server = mid->callback_data;
723
724 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400725 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500726}
727
728int
729CIFSSMBEcho(struct TCP_Server_Info *server)
730{
731 ECHO_REQ *smb;
732 int rc = 0;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800733 struct kvec iov[2];
734 struct smb_rqst rqst = { .rq_iov = iov,
735 .rq_nvec = 2 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500736
Joe Perchesf96637b2013-05-04 22:12:25 -0500737 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500738
739 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
740 if (rc)
741 return rc;
742
Steve French26c9cb62017-05-02 13:35:20 -0500743 if (server->capabilities & CAP_UNICODE)
744 smb->hdr.Flags2 |= SMBFLG2_UNICODE;
745
Jeff Layton766fdbb2011-01-11 07:24:21 -0500746 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000747 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500748 smb->hdr.WordCount = 1;
749 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400750 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500751 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000752 inc_rfc1001_len(smb, 3);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800753
754 iov[0].iov_len = 4;
755 iov[0].iov_base = smb;
756 iov[1].iov_len = get_rfc1002_length(smb);
757 iov[1].iov_base = (char *)smb + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500758
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -0800759 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400760 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500761 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500762 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500763
764 cifs_small_buf_release(smb);
765
766 return rc;
767}
768
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400770CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 LOGOFF_ANDX_REQ *pSMB;
773 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774
Joe Perchesf96637b2013-05-04 22:12:25 -0500775 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500776
777 /*
778 * BB: do we need to check validity of ses and server? They should
779 * always be valid since we have an active reference. If not, that
780 * should probably be a BUG()
781 */
782 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 return -EIO;
784
Steve Frenchd7b619c2010-02-25 05:36:46 +0000785 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000786 if (ses->need_reconnect)
787 goto session_already_dead; /* no need to send SMBlogoff if uid
788 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
790 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000791 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 return rc;
793 }
794
Pavel Shilovsky88257362012-05-23 14:01:59 +0400795 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700796
Jeff Layton38d77c52013-05-26 07:01:00 -0400797 if (ses->server->sign)
798 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799
800 pSMB->hdr.Uid = ses->Suid;
801
802 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400803 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700804 cifs_small_buf_release(pSMB);
Steve French3b795212008-11-13 19:45:32 +0000805session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000806 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807
808 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000809 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 error */
811 if (rc == -EAGAIN)
812 rc = 0;
813 return rc;
814}
815
816int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400817CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
818 const char *fileName, __u16 type,
819 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000820{
821 TRANSACTION2_SPI_REQ *pSMB = NULL;
822 TRANSACTION2_SPI_RSP *pSMBr = NULL;
823 struct unlink_psx_rq *pRqD;
824 int name_len;
825 int rc = 0;
826 int bytes_returned = 0;
827 __u16 params, param_offset, offset, byte_count;
828
Joe Perchesf96637b2013-05-04 22:12:25 -0500829 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000830PsxDelete:
831 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
832 (void **) &pSMBr);
833 if (rc)
834 return rc;
835
836 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
837 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600838 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
839 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000840 name_len++; /* trailing null */
841 name_len *= 2;
842 } else { /* BB add path length overrun check */
843 name_len = strnlen(fileName, PATH_MAX);
844 name_len++; /* trailing null */
845 strncpy(pSMB->FileName, fileName, name_len);
846 }
847
848 params = 6 + name_len;
849 pSMB->MaxParameterCount = cpu_to_le16(2);
850 pSMB->MaxDataCount = 0; /* BB double check this with jra */
851 pSMB->MaxSetupCount = 0;
852 pSMB->Reserved = 0;
853 pSMB->Flags = 0;
854 pSMB->Timeout = 0;
855 pSMB->Reserved2 = 0;
856 param_offset = offsetof(struct smb_com_transaction2_spi_req,
857 InformationLevel) - 4;
858 offset = param_offset + params;
859
860 /* Setup pointer to Request Data (inode type) */
861 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
862 pRqD->type = cpu_to_le16(type);
863 pSMB->ParameterOffset = cpu_to_le16(param_offset);
864 pSMB->DataOffset = cpu_to_le16(offset);
865 pSMB->SetupCount = 1;
866 pSMB->Reserved3 = 0;
867 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
868 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
869
870 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
871 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
872 pSMB->ParameterCount = cpu_to_le16(params);
873 pSMB->TotalParameterCount = pSMB->ParameterCount;
874 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
875 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000876 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000877 pSMB->ByteCount = cpu_to_le16(byte_count);
878 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
879 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000880 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500881 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000882 cifs_buf_release(pSMB);
883
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400884 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000885
886 if (rc == -EAGAIN)
887 goto PsxDelete;
888
889 return rc;
890}
891
892int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700893CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
894 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895{
896 DELETE_FILE_REQ *pSMB = NULL;
897 DELETE_FILE_RSP *pSMBr = NULL;
898 int rc = 0;
899 int bytes_returned;
900 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500901 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902
903DelFileRetry:
904 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
905 (void **) &pSMBr);
906 if (rc)
907 return rc;
908
909 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700910 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
911 PATH_MAX, cifs_sb->local_nls,
912 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 name_len++; /* trailing null */
914 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700915 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700916 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700918 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 }
920 pSMB->SearchAttributes =
921 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
922 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000923 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 pSMB->ByteCount = cpu_to_le16(name_len + 1);
925 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
926 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400927 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000928 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500929 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930
931 cifs_buf_release(pSMB);
932 if (rc == -EAGAIN)
933 goto DelFileRetry;
934
935 return rc;
936}
937
938int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400939CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
940 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941{
942 DELETE_DIRECTORY_REQ *pSMB = NULL;
943 DELETE_DIRECTORY_RSP *pSMBr = NULL;
944 int rc = 0;
945 int bytes_returned;
946 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500947 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
Joe Perchesf96637b2013-05-04 22:12:25 -0500949 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950RmDirRetry:
951 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
952 (void **) &pSMBr);
953 if (rc)
954 return rc;
955
956 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400957 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
958 PATH_MAX, cifs_sb->local_nls,
959 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 name_len++; /* trailing null */
961 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700962 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400963 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400965 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 }
967
968 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000969 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 pSMB->ByteCount = cpu_to_le16(name_len + 1);
971 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
972 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400973 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000974 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500975 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
977 cifs_buf_release(pSMB);
978 if (rc == -EAGAIN)
979 goto RmDirRetry;
980 return rc;
981}
982
983int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300984CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
985 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986{
987 int rc = 0;
988 CREATE_DIRECTORY_REQ *pSMB = NULL;
989 CREATE_DIRECTORY_RSP *pSMBr = NULL;
990 int bytes_returned;
991 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500992 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
Joe Perchesf96637b2013-05-04 22:12:25 -0500994 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995MkDirRetry:
996 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
997 (void **) &pSMBr);
998 if (rc)
999 return rc;
1000
1001 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06001002 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001003 PATH_MAX, cifs_sb->local_nls,
1004 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 name_len++; /* trailing null */
1006 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001007 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 name_len = strnlen(name, PATH_MAX);
1009 name_len++; /* trailing null */
1010 strncpy(pSMB->DirName, name, name_len);
1011 }
1012
1013 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001014 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1016 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1017 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001018 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001019 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001020 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001021
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 cifs_buf_release(pSMB);
1023 if (rc == -EAGAIN)
1024 goto MkDirRetry;
1025 return rc;
1026}
1027
Steve French2dd29d32007-04-23 22:07:35 +00001028int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001029CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1030 __u32 posix_flags, __u64 mode, __u16 *netfid,
1031 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1032 const char *name, const struct nls_table *nls_codepage,
1033 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001034{
1035 TRANSACTION2_SPI_REQ *pSMB = NULL;
1036 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1037 int name_len;
1038 int rc = 0;
1039 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001040 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001041 OPEN_PSX_REQ *pdata;
1042 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001043
Joe Perchesf96637b2013-05-04 22:12:25 -05001044 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001045PsxCreat:
1046 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1047 (void **) &pSMBr);
1048 if (rc)
1049 return rc;
1050
1051 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1052 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001053 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1054 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001055 name_len++; /* trailing null */
1056 name_len *= 2;
1057 } else { /* BB improve the check for buffer overruns BB */
1058 name_len = strnlen(name, PATH_MAX);
1059 name_len++; /* trailing null */
1060 strncpy(pSMB->FileName, name, name_len);
1061 }
1062
1063 params = 6 + name_len;
1064 count = sizeof(OPEN_PSX_REQ);
1065 pSMB->MaxParameterCount = cpu_to_le16(2);
1066 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1067 pSMB->MaxSetupCount = 0;
1068 pSMB->Reserved = 0;
1069 pSMB->Flags = 0;
1070 pSMB->Timeout = 0;
1071 pSMB->Reserved2 = 0;
1072 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001073 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001074 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001075 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001076 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001077 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001078 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001079 pdata->OpenFlags = cpu_to_le32(*pOplock);
1080 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1081 pSMB->DataOffset = cpu_to_le16(offset);
1082 pSMB->SetupCount = 1;
1083 pSMB->Reserved3 = 0;
1084 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1085 byte_count = 3 /* pad */ + params + count;
1086
1087 pSMB->DataCount = cpu_to_le16(count);
1088 pSMB->ParameterCount = cpu_to_le16(params);
1089 pSMB->TotalDataCount = pSMB->DataCount;
1090 pSMB->TotalParameterCount = pSMB->ParameterCount;
1091 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1092 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001093 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001094 pSMB->ByteCount = cpu_to_le16(byte_count);
1095 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1096 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1097 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001098 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001099 goto psx_create_err;
1100 }
1101
Joe Perchesf96637b2013-05-04 22:12:25 -05001102 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001103 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1104
Jeff Layton820a8032011-05-04 08:05:26 -04001105 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001106 rc = -EIO; /* bad smb */
1107 goto psx_create_err;
1108 }
1109
1110 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001111 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001112 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001113
Steve French2dd29d32007-04-23 22:07:35 +00001114 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001115 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001116 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1117 /* Let caller know file was created so we can set the mode. */
1118 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001119 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001120 *pOplock |= CIFS_CREATE_ACTION;
1121 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001122 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1123 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001124 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001125 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001126 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001127 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001128 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001129 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001130 goto psx_create_err;
1131 }
Steve French50c2f752007-07-13 00:33:32 +00001132 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001133 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001134 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001135 }
Steve French2dd29d32007-04-23 22:07:35 +00001136
1137psx_create_err:
1138 cifs_buf_release(pSMB);
1139
Steve French65bc98b2009-07-10 15:27:25 +00001140 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001141 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001142 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001143 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001144
1145 if (rc == -EAGAIN)
1146 goto PsxCreat;
1147
Steve French50c2f752007-07-13 00:33:32 +00001148 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001149}
1150
Steve Frencha9d02ad2005-08-24 23:06:05 -07001151static __u16 convert_disposition(int disposition)
1152{
1153 __u16 ofun = 0;
1154
1155 switch (disposition) {
1156 case FILE_SUPERSEDE:
1157 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1158 break;
1159 case FILE_OPEN:
1160 ofun = SMBOPEN_OAPPEND;
1161 break;
1162 case FILE_CREATE:
1163 ofun = SMBOPEN_OCREATE;
1164 break;
1165 case FILE_OPEN_IF:
1166 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1167 break;
1168 case FILE_OVERWRITE:
1169 ofun = SMBOPEN_OTRUNC;
1170 break;
1171 case FILE_OVERWRITE_IF:
1172 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1173 break;
1174 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001175 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001176 ofun = SMBOPEN_OAPPEND; /* regular open */
1177 }
1178 return ofun;
1179}
1180
Jeff Layton35fc37d2008-05-14 10:22:03 -07001181static int
1182access_flags_to_smbopen_mode(const int access_flags)
1183{
1184 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1185
1186 if (masked_flags == GENERIC_READ)
1187 return SMBOPEN_READ;
1188 else if (masked_flags == GENERIC_WRITE)
1189 return SMBOPEN_WRITE;
1190
1191 /* just go for read/write */
1192 return SMBOPEN_READWRITE;
1193}
1194
Steve Frencha9d02ad2005-08-24 23:06:05 -07001195int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001196SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001197 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001198 const int access_flags, const int create_options, __u16 *netfid,
1199 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001200 const struct nls_table *nls_codepage, int remap)
1201{
1202 int rc = -EACCES;
1203 OPENX_REQ *pSMB = NULL;
1204 OPENX_RSP *pSMBr = NULL;
1205 int bytes_returned;
1206 int name_len;
1207 __u16 count;
1208
1209OldOpenRetry:
1210 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1211 (void **) &pSMBr);
1212 if (rc)
1213 return rc;
1214
1215 pSMB->AndXCommand = 0xFF; /* none */
1216
1217 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1218 count = 1; /* account for one byte pad to word boundary */
1219 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001220 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1221 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001222 name_len++; /* trailing null */
1223 name_len *= 2;
1224 } else { /* BB improve check for buffer overruns BB */
1225 count = 0; /* no pad */
1226 name_len = strnlen(fileName, PATH_MAX);
1227 name_len++; /* trailing null */
1228 strncpy(pSMB->fileName, fileName, name_len);
1229 }
1230 if (*pOplock & REQ_OPLOCK)
1231 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001232 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001233 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001234
Steve Frencha9d02ad2005-08-24 23:06:05 -07001235 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001236 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001237 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1238 /* set file as system file if special file such
1239 as fifo and server expecting SFU style and
1240 no Unix extensions */
1241
Steve French790fe572007-07-07 19:25:05 +00001242 if (create_options & CREATE_OPTION_SPECIAL)
1243 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001244 else /* BB FIXME BB */
1245 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001246
Jeff Layton67750fb2008-05-09 22:28:02 +00001247 if (create_options & CREATE_OPTION_READONLY)
1248 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001249
1250 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001251/* pSMB->CreateOptions = cpu_to_le32(create_options &
1252 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001253 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001254
1255 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001256 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001257 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001258 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001259
1260 pSMB->ByteCount = cpu_to_le16(count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001261 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001262 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001263 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001264 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001265 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001266 } else {
1267 /* BB verify if wct == 15 */
1268
Steve French582d21e2008-05-13 04:54:12 +00001269/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001270
1271 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1272 /* Let caller know file was created so we can set the mode. */
1273 /* Do we care about the CreateAction in any other cases? */
1274 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001275/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001276 *pOplock |= CIFS_CREATE_ACTION; */
1277 /* BB FIXME END */
1278
Steve French790fe572007-07-07 19:25:05 +00001279 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001280 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1281 pfile_info->LastAccessTime = 0; /* BB fixme */
1282 pfile_info->LastWriteTime = 0; /* BB fixme */
1283 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001284 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001285 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001286 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001287 pfile_info->AllocationSize =
1288 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1289 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001290 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001291 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001292 }
1293 }
1294
1295 cifs_buf_release(pSMB);
1296 if (rc == -EAGAIN)
1297 goto OldOpenRetry;
1298 return rc;
1299}
1300
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301int
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001302CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
1303 FILE_ALL_INFO *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304{
1305 int rc = -EACCES;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001306 OPEN_REQ *req = NULL;
1307 OPEN_RSP *rsp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 int bytes_returned;
1309 int name_len;
1310 __u16 count;
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001311 struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
1312 struct cifs_tcon *tcon = oparms->tcon;
Steve French2baa2682014-09-27 02:19:01 -05001313 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001314 const struct nls_table *nls = cifs_sb->local_nls;
1315 int create_options = oparms->create_options;
1316 int desired_access = oparms->desired_access;
1317 int disposition = oparms->disposition;
1318 const char *path = oparms->path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319
1320openRetry:
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001321 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
1322 (void **)&rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 if (rc)
1324 return rc;
1325
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001326 /* no commands go after this */
1327 req->AndXCommand = 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001329 if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
1330 /* account for one byte pad to word boundary */
1331 count = 1;
1332 name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
1333 path, PATH_MAX, nls, remap);
1334 /* trailing null */
1335 name_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 name_len *= 2;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001337 req->NameLength = cpu_to_le16(name_len);
1338 } else {
1339 /* BB improve check for buffer overruns BB */
1340 /* no pad */
1341 count = 0;
1342 name_len = strnlen(path, PATH_MAX);
1343 /* trailing null */
1344 name_len++;
1345 req->NameLength = cpu_to_le16(name_len);
1346 strncpy(req->fileName, path, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 }
Jeff Layton67750fb2008-05-09 22:28:02 +00001348
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001349 if (*oplock & REQ_OPLOCK)
1350 req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1351 else if (*oplock & REQ_BATCHOPLOCK)
1352 req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1353
1354 req->DesiredAccess = cpu_to_le32(desired_access);
1355 req->AllocationSize = 0;
1356
1357 /*
1358 * Set file as system file if special file such as fifo and server
1359 * expecting SFU style and no Unix extensions.
1360 */
1361 if (create_options & CREATE_OPTION_SPECIAL)
1362 req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1363 else
1364 req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1365
1366 /*
1367 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
1368 * sensitive checks for other servers such as Samba.
1369 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 if (tcon->ses->capabilities & CAP_UNIX)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001371 req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372
Jeff Layton67750fb2008-05-09 22:28:02 +00001373 if (create_options & CREATE_OPTION_READONLY)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001374 req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
Jeff Layton67750fb2008-05-09 22:28:02 +00001375
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001376 req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1377 req->CreateDisposition = cpu_to_le32(disposition);
1378 req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1379
Steve French09d1db52005-04-28 22:41:08 -07001380 /* BB Expirement with various impersonation levels and verify */
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001381 req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1382 req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383
1384 count += name_len;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001385 inc_rfc1001_len(req, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001387 req->ByteCount = cpu_to_le16(count);
1388 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
1389 (struct smb_hdr *)rsp, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001390 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001392 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001393 cifs_buf_release(req);
1394 if (rc == -EAGAIN)
1395 goto openRetry;
1396 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001398
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001399 /* 1 byte no need to le_to_cpu */
1400 *oplock = rsp->OplockLevel;
1401 /* cifs fid stays in le */
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001402 oparms->fid->netfid = rsp->Fid;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001403
1404 /* Let caller know file was created so we can set the mode. */
1405 /* Do we care about the CreateAction in any other cases? */
1406 if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
1407 *oplock |= CIFS_CREATE_ACTION;
1408
1409 if (buf) {
1410 /* copy from CreationTime to Attributes */
1411 memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
1412 /* the file_info buf is endian converted by caller */
1413 buf->AllocationSize = rsp->AllocationSize;
1414 buf->EndOfFile = rsp->EndOfFile;
1415 buf->NumberOfLinks = cpu_to_le32(1);
1416 buf->DeletePending = 0;
1417 }
1418
1419 cifs_buf_release(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 return rc;
1421}
1422
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001423/*
1424 * Discard any remaining data in the current SMB. To do this, we borrow the
1425 * current bigbuf.
1426 */
Pavel Shilovskyc42a6ab2016-11-17 16:20:23 -08001427int
Pavel Shilovsky350be252017-04-10 10:31:33 -07001428cifs_discard_remaining_data(struct TCP_Server_Info *server)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001429{
Ronnie Sahlberg05432e22018-04-09 18:06:31 +10001430 unsigned int rfclen = server->pdu_size;
1431 int remaining = rfclen + server->vals->header_preamble_size -
1432 server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001433
1434 while (remaining > 0) {
1435 int length;
1436
1437 length = cifs_read_from_socket(server, server->bigbuf,
1438 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001439 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001440 if (length < 0)
1441 return length;
1442 server->total_read += length;
1443 remaining -= length;
1444 }
1445
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001446 return 0;
1447}
1448
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001449static int
1450cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1451{
1452 int length;
1453 struct cifs_readdata *rdata = mid->callback_data;
1454
Pavel Shilovsky350be252017-04-10 10:31:33 -07001455 length = cifs_discard_remaining_data(server);
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001456 dequeue_mid(mid, rdata->result);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001457 mid->resp_buf = server->smallbuf;
1458 server->smallbuf = NULL;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001459 return length;
1460}
1461
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001462int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001463cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1464{
1465 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001466 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001467 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001468 char *buf = server->smallbuf;
Ronnie Sahlberg2e964672018-04-09 18:06:26 +10001469 unsigned int buflen = server->pdu_size +
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +11001470 server->vals->header_preamble_size;
Long Li74dcf412017-11-22 17:38:46 -07001471 bool use_rdma_mr = false;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001472
Joe Perchesf96637b2013-05-04 22:12:25 -05001473 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1474 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001475
1476 /*
1477 * read the rest of READ_RSP header (sans Data array), or whatever we
1478 * can if there's not enough data. At this point, we've read down to
1479 * the Mid.
1480 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001481 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001482 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001483
Al Viroa6137302016-01-09 19:37:16 -05001484 length = cifs_read_from_socket(server,
1485 buf + HEADER_SIZE(server) - 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001486 if (length < 0)
1487 return length;
1488 server->total_read += length;
1489
Pavel Shilovsky511c54a2017-07-08 14:32:00 -07001490 if (server->ops->is_session_expired &&
1491 server->ops->is_session_expired(buf)) {
1492 cifs_reconnect(server);
1493 wake_up(&server->response_q);
1494 return -1;
1495 }
1496
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001497 if (server->ops->is_status_pending &&
1498 server->ops->is_status_pending(buf, server, 0)) {
Pavel Shilovsky350be252017-04-10 10:31:33 -07001499 cifs_discard_remaining_data(server);
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001500 return -1;
1501 }
1502
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001503 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001504 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001505 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001506 cifs_dbg(FYI, "%s: server returned error %d\n",
1507 __func__, rdata->result);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001508 return cifs_readv_discard(server, mid);
1509 }
1510
1511 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001512 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001513 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1514 __func__, server->total_read,
1515 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001516 rdata->result = -EIO;
1517 return cifs_readv_discard(server, mid);
1518 }
1519
Ronnie Sahlberg93012bf2018-03-31 11:45:31 +11001520 data_offset = server->ops->read_data_offset(buf) +
1521 server->vals->header_preamble_size;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001522 if (data_offset < server->total_read) {
1523 /*
1524 * win2k8 sometimes sends an offset of 0 when the read
1525 * is beyond the EOF. Treat it as if the data starts just after
1526 * the header.
1527 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001528 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1529 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001530 data_offset = server->total_read;
1531 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1532 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001533 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1534 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001535 rdata->result = -EIO;
1536 return cifs_readv_discard(server, mid);
1537 }
1538
Joe Perchesf96637b2013-05-04 22:12:25 -05001539 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1540 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001541
1542 len = data_offset - server->total_read;
1543 if (len > 0) {
1544 /* read any junk before data into the rest of smallbuf */
Al Viroa6137302016-01-09 19:37:16 -05001545 length = cifs_read_from_socket(server,
1546 buf + server->total_read, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001547 if (length < 0)
1548 return length;
1549 server->total_read += length;
1550 }
1551
1552 /* set up first iov for signature check */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001553 rdata->iov[0].iov_base = buf;
1554 rdata->iov[0].iov_len = 4;
1555 rdata->iov[1].iov_base = buf + 4;
1556 rdata->iov[1].iov_len = server->total_read - 4;
1557 cifs_dbg(FYI, "0: iov_base=%p iov_len=%u\n",
1558 rdata->iov[0].iov_base, server->total_read);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001559
1560 /* how much data is in the response? */
Long Li74dcf412017-11-22 17:38:46 -07001561#ifdef CONFIG_CIFS_SMB_DIRECT
1562 use_rdma_mr = rdata->mr;
1563#endif
1564 data_len = server->ops->read_data_length(buf, use_rdma_mr);
1565 if (!use_rdma_mr && (data_offset + data_len > buflen)) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001566 /* data_len is corrupt -- discard frame */
1567 rdata->result = -EIO;
1568 return cifs_readv_discard(server, mid);
1569 }
1570
Jeff Layton8321fec2012-09-19 06:22:32 -07001571 length = rdata->read_into_pages(server, rdata, data_len);
1572 if (length < 0)
1573 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001574
Jeff Layton8321fec2012-09-19 06:22:32 -07001575 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001576
Joe Perchesf96637b2013-05-04 22:12:25 -05001577 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1578 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001579
1580 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001581 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001582 return cifs_readv_discard(server, mid);
1583
1584 dequeue_mid(mid, false);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001585 mid->resp_buf = server->smallbuf;
1586 server->smallbuf = NULL;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001587 return length;
1588}
1589
1590static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001591cifs_readv_callback(struct mid_q_entry *mid)
1592{
1593 struct cifs_readdata *rdata = mid->callback_data;
1594 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1595 struct TCP_Server_Info *server = tcon->ses->server;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001596 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1597 .rq_nvec = 2,
Jeff Layton8321fec2012-09-19 06:22:32 -07001598 .rq_pages = rdata->pages,
1599 .rq_npages = rdata->nr_pages,
1600 .rq_pagesz = rdata->pagesz,
1601 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001602
Joe Perchesf96637b2013-05-04 22:12:25 -05001603 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1604 __func__, mid->mid, mid->mid_state, rdata->result,
1605 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001606
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001607 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001608 case MID_RESPONSE_RECEIVED:
1609 /* result already set, check signature */
Jeff Layton38d77c52013-05-26 07:01:00 -04001610 if (server->sign) {
Steve French985e4ff02012-08-03 09:42:45 -05001611 int rc = 0;
1612
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001613 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001614 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001615 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001616 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1617 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001618 }
1619 /* FIXME: should this be counted toward the initiating task? */
Pavel Shilovsky34a54d62014-07-10 10:03:29 +04001620 task_io_account_read(rdata->got_bytes);
1621 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001622 break;
1623 case MID_REQUEST_SUBMITTED:
1624 case MID_RETRY_NEEDED:
1625 rdata->result = -EAGAIN;
Pavel Shilovskyd913ed12014-07-10 11:31:48 +04001626 if (server->sign && rdata->got_bytes)
1627 /* reset bytes number since we can not check a sign */
1628 rdata->got_bytes = 0;
1629 /* FIXME: should this be counted toward the initiating task? */
1630 task_io_account_read(rdata->got_bytes);
1631 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001632 break;
1633 default:
1634 rdata->result = -EIO;
1635 }
1636
Jeff Laytonda472fc2012-03-23 14:40:53 -04001637 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001638 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001639 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001640}
1641
1642/* cifs_async_readv - send an async write, and set up mid to handle result */
1643int
1644cifs_async_readv(struct cifs_readdata *rdata)
1645{
1646 int rc;
1647 READ_REQ *smb = NULL;
1648 int wct;
1649 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001650 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1651 .rq_nvec = 2 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001652
Joe Perchesf96637b2013-05-04 22:12:25 -05001653 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1654 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001655
1656 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1657 wct = 12;
1658 else {
1659 wct = 10; /* old style read */
1660 if ((rdata->offset >> 32) > 0) {
1661 /* can not handle this big offset for old */
1662 return -EIO;
1663 }
1664 }
1665
1666 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1667 if (rc)
1668 return rc;
1669
1670 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1671 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1672
1673 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001674 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001675 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1676 if (wct == 12)
1677 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1678 smb->Remaining = 0;
1679 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1680 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1681 if (wct == 12)
1682 smb->ByteCount = 0;
1683 else {
1684 /* old style read */
1685 struct smb_com_readx_req *smbr =
1686 (struct smb_com_readx_req *)smb;
1687 smbr->ByteCount = 0;
1688 }
1689
1690 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001691 rdata->iov[0].iov_base = smb;
1692 rdata->iov[0].iov_len = 4;
1693 rdata->iov[1].iov_base = (char *)smb + 4;
1694 rdata->iov[1].iov_len = get_rfc1002_length(smb);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001695
Jeff Layton6993f742012-05-16 07:13:17 -04001696 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001697 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -08001698 cifs_readv_callback, NULL, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001699
1700 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001701 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001702 else
1703 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001704
1705 cifs_small_buf_release(smb);
1706 return rc;
1707}
1708
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001710CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1711 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712{
1713 int rc = -EACCES;
1714 READ_REQ *pSMB = NULL;
1715 READ_RSP *pSMBr = NULL;
1716 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001717 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001718 int resp_buf_type = 0;
1719 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001720 struct kvec rsp_iov;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001721 __u32 pid = io_parms->pid;
1722 __u16 netfid = io_parms->netfid;
1723 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001724 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001725 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726
Joe Perchesf96637b2013-05-04 22:12:25 -05001727 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001728 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001729 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001730 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001731 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001732 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001733 /* can not handle this big offset for old */
1734 return -EIO;
1735 }
1736 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737
1738 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001739 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 if (rc)
1741 return rc;
1742
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001743 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1744 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1745
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 /* tcon and ses pointer are checked in smb_init */
1747 if (tcon->ses->server == NULL)
1748 return -ECONNABORTED;
1749
Steve Frenchec637e32005-12-12 20:53:18 -08001750 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001752 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001753 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001754 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001755
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 pSMB->Remaining = 0;
1757 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1758 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001759 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001760 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1761 else {
1762 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001763 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001764 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001765 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001766 }
Steve Frenchec637e32005-12-12 20:53:18 -08001767
1768 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001769 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001770 rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
1771 CIFS_LOG_ERROR, &rsp_iov);
1772 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001773 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001774 pSMBr = (READ_RSP *)rsp_iov.iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001776 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 } else {
1778 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1779 data_length = data_length << 16;
1780 data_length += le16_to_cpu(pSMBr->DataLength);
1781 *nbytes = data_length;
1782
1783 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001784 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001786 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001787 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 rc = -EIO;
1789 *nbytes = 0;
1790 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001791 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001792 le16_to_cpu(pSMBr->DataOffset);
1793/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001794 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001795 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001796 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001797 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001798 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 }
1800 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801
Steve French790fe572007-07-07 19:25:05 +00001802 if (*buf) {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001803 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French790fe572007-07-07 19:25:05 +00001804 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001805 /* return buffer to caller to free */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001806 *buf = rsp_iov.iov_base;
Steve French790fe572007-07-07 19:25:05 +00001807 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001808 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001809 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001810 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001811 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001812
1813 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 since file handle passed in no longer valid */
1815 return rc;
1816}
1817
Steve Frenchec637e32005-12-12 20:53:18 -08001818
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001820CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Al Virodbbab322016-09-05 17:53:43 -04001821 unsigned int *nbytes, const char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822{
1823 int rc = -EACCES;
1824 WRITE_REQ *pSMB = NULL;
1825 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001826 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 __u32 bytes_sent;
1828 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001829 __u32 pid = io_parms->pid;
1830 __u16 netfid = io_parms->netfid;
1831 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001832 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001833 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834
Steve Frencha24e2d72010-04-03 17:20:21 +00001835 *nbytes = 0;
1836
Joe Perchesf96637b2013-05-04 22:12:25 -05001837 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001838 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001839 return -ECONNABORTED;
1840
Steve French790fe572007-07-07 19:25:05 +00001841 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001842 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001843 else {
Steve French1c955182005-08-30 20:58:07 -07001844 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001845 if ((offset >> 32) > 0) {
1846 /* can not handle big offset for old srv */
1847 return -EIO;
1848 }
1849 }
Steve French1c955182005-08-30 20:58:07 -07001850
1851 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 (void **) &pSMBr);
1853 if (rc)
1854 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001855
1856 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1857 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1858
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 /* tcon and ses pointer are checked in smb_init */
1860 if (tcon->ses->server == NULL)
1861 return -ECONNABORTED;
1862
1863 pSMB->AndXCommand = 0xFF; /* none */
1864 pSMB->Fid = netfid;
1865 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001866 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001867 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001868
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 pSMB->Reserved = 0xFFFFFFFF;
1870 pSMB->WriteMode = 0;
1871 pSMB->Remaining = 0;
1872
Steve French50c2f752007-07-13 00:33:32 +00001873 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 can send more if LARGE_WRITE_X capability returned by the server and if
1875 our buffer is big enough or if we convert to iovecs on socket writes
1876 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001877 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1879 } else {
1880 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1881 & ~0xFF;
1882 }
1883
1884 if (bytes_sent > count)
1885 bytes_sent = count;
1886 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001887 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001888 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001889 memcpy(pSMB->Data, buf, bytes_sent);
Al Virodbbab322016-09-05 17:53:43 -04001890 else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 /* No buffer */
1892 cifs_buf_release(pSMB);
1893 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001894 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001895 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001896 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001897 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001898 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001899
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1901 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001902 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001903
Steve French790fe572007-07-07 19:25:05 +00001904 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001905 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001906 else { /* old style write has byte count 4 bytes earlier
1907 so 4 bytes pad */
1908 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001909 (struct smb_com_writex_req *)pSMB;
1910 pSMBW->ByteCount = cpu_to_le16(byte_count);
1911 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912
1913 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Al Virodbbab322016-09-05 17:53:43 -04001914 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001915 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001917 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 } else {
1919 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1920 *nbytes = (*nbytes) << 16;
1921 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301922
1923 /*
1924 * Mask off high 16 bits when bytes written as returned by the
1925 * server is greater than bytes requested by the client. Some
1926 * OS/2 servers are known to set incorrect CountHigh values.
1927 */
1928 if (*nbytes > count)
1929 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 }
1931
1932 cifs_buf_release(pSMB);
1933
Steve French50c2f752007-07-13 00:33:32 +00001934 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 since file handle passed in no longer valid */
1936
1937 return rc;
1938}
1939
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001940void
1941cifs_writedata_release(struct kref *refcount)
1942{
1943 struct cifs_writedata *wdata = container_of(refcount,
1944 struct cifs_writedata, refcount);
Long Lidb223a52017-11-22 17:38:45 -07001945#ifdef CONFIG_CIFS_SMB_DIRECT
1946 if (wdata->mr) {
1947 smbd_deregister_mr(wdata->mr);
1948 wdata->mr = NULL;
1949 }
1950#endif
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001951
1952 if (wdata->cfile)
1953 cifsFileInfo_put(wdata->cfile);
1954
1955 kfree(wdata);
1956}
1957
1958/*
1959 * Write failed with a retryable error. Resend the write request. It's also
1960 * possible that the page was redirtied so re-clean the page.
1961 */
1962static void
1963cifs_writev_requeue(struct cifs_writedata *wdata)
1964{
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001965 int i, rc = 0;
David Howells2b0143b2015-03-17 22:25:59 +00001966 struct inode *inode = d_inode(wdata->cfile->dentry);
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001967 struct TCP_Server_Info *server;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001968 unsigned int rest_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001969
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001970 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1971 i = 0;
1972 rest_len = wdata->bytes;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001973 do {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001974 struct cifs_writedata *wdata2;
1975 unsigned int j, nr_pages, wsize, tailsz, cur_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001976
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001977 wsize = server->ops->wp_retry_size(inode);
1978 if (wsize < rest_len) {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001979 nr_pages = wsize / PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001980 if (!nr_pages) {
1981 rc = -ENOTSUPP;
1982 break;
1983 }
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001984 cur_len = nr_pages * PAGE_SIZE;
1985 tailsz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001986 } else {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001987 nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001988 cur_len = rest_len;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001989 tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE;
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001990 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001991
1992 wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
1993 if (!wdata2) {
1994 rc = -ENOMEM;
1995 break;
1996 }
1997
1998 for (j = 0; j < nr_pages; j++) {
1999 wdata2->pages[j] = wdata->pages[i + j];
2000 lock_page(wdata2->pages[j]);
2001 clear_page_dirty_for_io(wdata2->pages[j]);
2002 }
2003
2004 wdata2->sync_mode = wdata->sync_mode;
2005 wdata2->nr_pages = nr_pages;
2006 wdata2->offset = page_offset(wdata2->pages[0]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002007 wdata2->pagesz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002008 wdata2->tailsz = tailsz;
2009 wdata2->bytes = cur_len;
2010
2011 wdata2->cfile = find_writable_file(CIFS_I(inode), false);
2012 if (!wdata2->cfile) {
2013 cifs_dbg(VFS, "No writable handles for inode\n");
2014 rc = -EBADF;
2015 break;
2016 }
2017 wdata2->pid = wdata2->cfile->pid;
2018 rc = server->ops->async_writev(wdata2, cifs_writedata_release);
2019
2020 for (j = 0; j < nr_pages; j++) {
2021 unlock_page(wdata2->pages[j]);
2022 if (rc != 0 && rc != -EAGAIN) {
2023 SetPageError(wdata2->pages[j]);
2024 end_page_writeback(wdata2->pages[j]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002025 put_page(wdata2->pages[j]);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002026 }
2027 }
2028
2029 if (rc) {
2030 kref_put(&wdata2->refcount, cifs_writedata_release);
2031 if (rc == -EAGAIN)
2032 continue;
2033 break;
2034 }
2035
2036 rest_len -= cur_len;
2037 i += nr_pages;
2038 } while (i < wdata->nr_pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002039
2040 mapping_set_error(inode->i_mapping, rc);
2041 kref_put(&wdata->refcount, cifs_writedata_release);
2042}
2043
Jeff Laytonc2e87642012-03-23 14:40:55 -04002044void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002045cifs_writev_complete(struct work_struct *work)
2046{
2047 struct cifs_writedata *wdata = container_of(work,
2048 struct cifs_writedata, work);
David Howells2b0143b2015-03-17 22:25:59 +00002049 struct inode *inode = d_inode(wdata->cfile->dentry);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002050 int i = 0;
2051
2052 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04002053 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002054 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04002055 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002056 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2057 wdata->bytes);
2058 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2059 return cifs_writev_requeue(wdata);
2060
2061 for (i = 0; i < wdata->nr_pages; i++) {
2062 struct page *page = wdata->pages[i];
2063 if (wdata->result == -EAGAIN)
2064 __set_page_dirty_nobuffers(page);
2065 else if (wdata->result < 0)
2066 SetPageError(page);
2067 end_page_writeback(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002068 put_page(page);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002069 }
2070 if (wdata->result != -EAGAIN)
2071 mapping_set_error(inode->i_mapping, wdata->result);
2072 kref_put(&wdata->refcount, cifs_writedata_release);
2073}
2074
2075struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04002076cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002077{
2078 struct cifs_writedata *wdata;
2079
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002080 /* writedata + number of page pointers */
2081 wdata = kzalloc(sizeof(*wdata) +
Jeff Layton26c8f0d2014-02-07 11:04:04 -05002082 sizeof(struct page *) * nr_pages, GFP_NOFS);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002083 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002084 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04002085 INIT_LIST_HEAD(&wdata->list);
2086 init_completion(&wdata->done);
2087 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002088 }
2089 return wdata;
2090}
2091
2092/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002093 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002094 * workqueue completion task.
2095 */
2096static void
2097cifs_writev_callback(struct mid_q_entry *mid)
2098{
2099 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002100 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002101 unsigned int written;
2102 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2103
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002104 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002105 case MID_RESPONSE_RECEIVED:
2106 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2107 if (wdata->result != 0)
2108 break;
2109
2110 written = le16_to_cpu(smb->CountHigh);
2111 written <<= 16;
2112 written += le16_to_cpu(smb->Count);
2113 /*
2114 * Mask off high 16 bits when bytes written as returned
2115 * by the server is greater than bytes requested by the
2116 * client. OS/2 servers are known to set incorrect
2117 * CountHigh values.
2118 */
2119 if (written > wdata->bytes)
2120 written &= 0xFFFF;
2121
2122 if (written < wdata->bytes)
2123 wdata->result = -ENOSPC;
2124 else
2125 wdata->bytes = written;
2126 break;
2127 case MID_REQUEST_SUBMITTED:
2128 case MID_RETRY_NEEDED:
2129 wdata->result = -EAGAIN;
2130 break;
2131 default:
2132 wdata->result = -EIO;
2133 break;
2134 }
2135
Jeff Laytonda472fc2012-03-23 14:40:53 -04002136 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002137 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002138 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002139}
2140
2141/* cifs_async_writev - send an async write, and set up mid to handle result */
2142int
Steve French4a5c80d2014-02-07 20:45:12 -06002143cifs_async_writev(struct cifs_writedata *wdata,
2144 void (*release)(struct kref *kref))
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002145{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002146 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002147 WRITE_REQ *smb = NULL;
2148 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002149 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002150 struct kvec iov[2];
Jeff Laytonfec344e2012-09-18 16:20:35 -07002151 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002152
2153 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2154 wct = 14;
2155 } else {
2156 wct = 12;
2157 if (wdata->offset >> 32 > 0) {
2158 /* can not handle big offset for old srv */
2159 return -EIO;
2160 }
2161 }
2162
2163 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2164 if (rc)
2165 goto async_writev_out;
2166
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002167 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2168 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002169
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002170 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002171 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002172 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2173 if (wct == 14)
2174 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2175 smb->Reserved = 0xFFFFFFFF;
2176 smb->WriteMode = 0;
2177 smb->Remaining = 0;
2178
2179 smb->DataOffset =
2180 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2181
2182 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002183 iov[0].iov_len = 4;
2184 iov[0].iov_base = smb;
2185 iov[1].iov_len = get_rfc1002_length(smb) + 1;
2186 iov[1].iov_base = (char *)smb + 4;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002187
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002188 rqst.rq_iov = iov;
2189 rqst.rq_nvec = 2;
Jeff Laytoneddb0792012-09-18 16:20:35 -07002190 rqst.rq_pages = wdata->pages;
2191 rqst.rq_npages = wdata->nr_pages;
2192 rqst.rq_pagesz = wdata->pagesz;
2193 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002194
Joe Perchesf96637b2013-05-04 22:12:25 -05002195 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2196 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002197
2198 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2199 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2200
2201 if (wct == 14) {
2202 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2203 put_bcc(wdata->bytes + 1, &smb->hdr);
2204 } else {
2205 /* wct == 12 */
2206 struct smb_com_writex_req *smbw =
2207 (struct smb_com_writex_req *)smb;
2208 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2209 put_bcc(wdata->bytes + 5, &smbw->hdr);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002210 iov[1].iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002211 }
2212
2213 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002214 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -08002215 cifs_writev_callback, NULL, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002216
2217 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002218 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002219 else
Steve French4a5c80d2014-02-07 20:45:12 -06002220 kref_put(&wdata->refcount, release);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002221
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002222async_writev_out:
2223 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002224 return rc;
2225}
2226
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002227int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002228CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002229 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230{
2231 int rc = -EACCES;
2232 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002233 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002234 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002235 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002236 __u32 pid = io_parms->pid;
2237 __u16 netfid = io_parms->netfid;
2238 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002239 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002240 unsigned int count = io_parms->length;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002241 struct kvec rsp_iov;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002243 *nbytes = 0;
2244
Joe Perchesf96637b2013-05-04 22:12:25 -05002245 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002246
Steve French4c3130e2008-12-09 00:28:16 +00002247 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002248 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002249 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002250 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002251 if ((offset >> 32) > 0) {
2252 /* can not handle big offset for old srv */
2253 return -EIO;
2254 }
2255 }
Steve French8cc64c62005-10-03 13:49:43 -07002256 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 if (rc)
2258 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002259
2260 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2261 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2262
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 /* tcon and ses pointer are checked in smb_init */
2264 if (tcon->ses->server == NULL)
2265 return -ECONNABORTED;
2266
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002267 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 pSMB->Fid = netfid;
2269 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002270 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002271 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 pSMB->Reserved = 0xFFFFFFFF;
2273 pSMB->WriteMode = 0;
2274 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002275
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002277 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278
Steve French3e844692005-10-03 13:37:24 -07002279 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2280 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002281 /* header + 1 byte pad */
2282 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002283 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002284 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002285 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002286 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002287 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002288 pSMB->ByteCount = cpu_to_le16(count + 1);
2289 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002290 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002291 (struct smb_com_writex_req *)pSMB;
2292 pSMBW->ByteCount = cpu_to_le16(count + 5);
2293 }
Steve French3e844692005-10-03 13:37:24 -07002294 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002295 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002296 iov[0].iov_len = smb_hdr_len + 4;
2297 else /* wct == 12 pad bigger by four bytes */
2298 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002299
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002300 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
2301 &rsp_iov);
2302 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002303 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002305 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002306 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002307 /* presumably this can not happen, but best to be safe */
2308 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002309 } else {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002310 WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002311 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2312 *nbytes = (*nbytes) << 16;
2313 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302314
2315 /*
2316 * Mask off high 16 bits when bytes written as returned by the
2317 * server is greater than bytes requested by the client. OS/2
2318 * servers are known to set incorrect CountHigh values.
2319 */
2320 if (*nbytes > count)
2321 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002322 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002324 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325
Steve French50c2f752007-07-13 00:33:32 +00002326 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 since file handle passed in no longer valid */
2328
2329 return rc;
2330}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002331
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002332int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2333 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002334 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2335{
2336 int rc = 0;
2337 LOCK_REQ *pSMB = NULL;
2338 struct kvec iov[2];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002339 struct kvec rsp_iov;
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002340 int resp_buf_type;
2341 __u16 count;
2342
Joe Perchesf96637b2013-05-04 22:12:25 -05002343 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2344 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002345
2346 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2347 if (rc)
2348 return rc;
2349
2350 pSMB->Timeout = 0;
2351 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2352 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2353 pSMB->LockType = lock_type;
2354 pSMB->AndXCommand = 0xFF; /* none */
2355 pSMB->Fid = netfid; /* netfid stays le */
2356
2357 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2358 inc_rfc1001_len(pSMB, count);
2359 pSMB->ByteCount = cpu_to_le16(count);
2360
2361 iov[0].iov_base = (char *)pSMB;
2362 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2363 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2364 iov[1].iov_base = (char *)buf;
2365 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2366
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002367 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002368 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP,
2369 &rsp_iov);
2370 cifs_small_buf_release(pSMB);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002371 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002372 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002373
2374 return rc;
2375}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002376
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002378CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002379 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002381 const __u32 numLock, const __u8 lockType,
2382 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383{
2384 int rc = 0;
2385 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002386/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002388 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 __u16 count;
2390
Joe Perchesf96637b2013-05-04 22:12:25 -05002391 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2392 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002393 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2394
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 if (rc)
2396 return rc;
2397
Steve French790fe572007-07-07 19:25:05 +00002398 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002399 /* no response expected */
2400 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002402 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002403 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2405 } else {
2406 pSMB->Timeout = 0;
2407 }
2408
2409 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2410 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2411 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002412 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 pSMB->AndXCommand = 0xFF; /* none */
2414 pSMB->Fid = smb_file_id; /* netfid stays le */
2415
Steve French790fe572007-07-07 19:25:05 +00002416 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002417 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 /* BB where to store pid high? */
2419 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2420 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2421 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2422 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2423 count = sizeof(LOCKING_ANDX_RANGE);
2424 } else {
2425 /* oplock break */
2426 count = 0;
2427 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002428 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 pSMB->ByteCount = cpu_to_le16(count);
2430
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002431 if (waitFlag)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002432 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002433 (struct smb_hdr *) pSMB, &bytes_returned);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002434 else
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002435 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002436 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002437 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002438 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002439 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440
Steve French50c2f752007-07-13 00:33:32 +00002441 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 since file handle passed in no longer valid */
2443 return rc;
2444}
2445
2446int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002447CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002448 const __u16 smb_file_id, const __u32 netpid,
2449 const loff_t start_offset, const __u64 len,
2450 struct file_lock *pLockData, const __u16 lock_type,
2451 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002452{
2453 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2454 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002455 struct cifs_posix_lock *parm_data;
2456 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002457 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002458 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002459 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002460 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002461 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002462 struct kvec rsp_iov;
Steve French08547b02006-02-28 22:39:25 +00002463
Joe Perchesf96637b2013-05-04 22:12:25 -05002464 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002465
Steve French08547b02006-02-28 22:39:25 +00002466 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2467
2468 if (rc)
2469 return rc;
2470
2471 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2472
Steve French50c2f752007-07-13 00:33:32 +00002473 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002474 pSMB->MaxSetupCount = 0;
2475 pSMB->Reserved = 0;
2476 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002477 pSMB->Reserved2 = 0;
2478 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2479 offset = param_offset + params;
2480
Steve French08547b02006-02-28 22:39:25 +00002481 count = sizeof(struct cifs_posix_lock);
2482 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002483 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002484 pSMB->SetupCount = 1;
2485 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002486 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002487 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2488 else
2489 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2490 byte_count = 3 /* pad */ + params + count;
2491 pSMB->DataCount = cpu_to_le16(count);
2492 pSMB->ParameterCount = cpu_to_le16(params);
2493 pSMB->TotalDataCount = pSMB->DataCount;
2494 pSMB->TotalParameterCount = pSMB->ParameterCount;
2495 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002496 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002497 (((char *) &pSMB->hdr.Protocol) + offset);
2498
2499 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002500 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002501 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002502 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002503 pSMB->Timeout = cpu_to_le32(-1);
2504 } else
2505 pSMB->Timeout = 0;
2506
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002507 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002508 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002509 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002510
2511 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002512 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002513 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2514 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002515 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002516 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002517 if (waitFlag) {
2518 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2519 (struct smb_hdr *) pSMBr, &bytes_returned);
2520 } else {
Steve French133672e2007-11-13 22:41:37 +00002521 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002522 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002523 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002524 &resp_buf_type, timeout, &rsp_iov);
2525 pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002526 }
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002527 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002528
Steve French08547b02006-02-28 22:39:25 +00002529 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002530 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002531 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002532 /* lock structure can be returned on get */
2533 __u16 data_offset;
2534 __u16 data_count;
2535 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002536
Jeff Layton820a8032011-05-04 08:05:26 -04002537 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002538 rc = -EIO; /* bad smb */
2539 goto plk_err_exit;
2540 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002541 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2542 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002543 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002544 rc = -EIO;
2545 goto plk_err_exit;
2546 }
2547 parm_data = (struct cifs_posix_lock *)
2548 ((char *)&pSMBr->hdr.Protocol + data_offset);
Fabian Frederickbc09d142014-12-10 15:41:15 -08002549 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002550 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002551 else {
2552 if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002553 cpu_to_le16(CIFS_RDLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002554 pLockData->fl_type = F_RDLCK;
2555 else if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002556 cpu_to_le16(CIFS_WRLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002557 pLockData->fl_type = F_WRLCK;
2558
Steve French5443d132011-03-13 05:08:25 +00002559 pLockData->fl_start = le64_to_cpu(parm_data->start);
2560 pLockData->fl_end = pLockData->fl_start +
2561 le64_to_cpu(parm_data->length) - 1;
Benjamin Coddington9d5b86a2017-07-16 10:28:22 -04002562 pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002563 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002564 }
Steve French50c2f752007-07-13 00:33:32 +00002565
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002566plk_err_exit:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002567 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French133672e2007-11-13 22:41:37 +00002568
Steve French08547b02006-02-28 22:39:25 +00002569 /* Note: On -EAGAIN error only caller can retry on handle based calls
2570 since file handle passed in no longer valid */
2571
2572 return rc;
2573}
2574
2575
2576int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002577CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578{
2579 int rc = 0;
2580 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002581 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582
2583/* do not retry on dead session on close */
2584 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002585 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 return 0;
2587 if (rc)
2588 return rc;
2589
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002591 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002593 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002594 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002595 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002597 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002599 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 }
2601 }
2602
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002604 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 rc = 0;
2606
2607 return rc;
2608}
2609
2610int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002611CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002612{
2613 int rc = 0;
2614 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002615 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002616
2617 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2618 if (rc)
2619 return rc;
2620
2621 pSMB->FileID = (__u16) smb_file_id;
2622 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002623 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002624 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002625 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002626 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002627 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002628
2629 return rc;
2630}
2631
2632int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002633CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002634 const char *from_name, const char *to_name,
2635 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636{
2637 int rc = 0;
2638 RENAME_REQ *pSMB = NULL;
2639 RENAME_RSP *pSMBr = NULL;
2640 int bytes_returned;
2641 int name_len, name_len2;
2642 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002643 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644
Joe Perchesf96637b2013-05-04 22:12:25 -05002645 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646renameRetry:
2647 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2648 (void **) &pSMBr);
2649 if (rc)
2650 return rc;
2651
2652 pSMB->BufferFormat = 0x04;
2653 pSMB->SearchAttributes =
2654 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2655 ATTR_DIRECTORY);
2656
2657 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002658 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2659 from_name, PATH_MAX,
2660 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 name_len++; /* trailing null */
2662 name_len *= 2;
2663 pSMB->OldFileName[name_len] = 0x04; /* pad */
2664 /* protocol requires ASCII signature byte on Unicode string */
2665 pSMB->OldFileName[name_len + 1] = 0x00;
2666 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002667 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002668 to_name, PATH_MAX, cifs_sb->local_nls,
2669 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2671 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002672 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002673 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002675 strncpy(pSMB->OldFileName, from_name, name_len);
2676 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 name_len2++; /* trailing null */
2678 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002679 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 name_len2++; /* trailing null */
2681 name_len2++; /* signature byte */
2682 }
2683
2684 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002685 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 pSMB->ByteCount = cpu_to_le16(count);
2687
2688 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2689 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002690 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002691 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002692 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 cifs_buf_release(pSMB);
2695
2696 if (rc == -EAGAIN)
2697 goto renameRetry;
2698
2699 return rc;
2700}
2701
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002702int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002703 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002704 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705{
2706 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2707 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002708 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 char *data_offset;
2710 char dummy_string[30];
2711 int rc = 0;
2712 int bytes_returned = 0;
2713 int len_of_str;
2714 __u16 params, param_offset, offset, count, byte_count;
2715
Joe Perchesf96637b2013-05-04 22:12:25 -05002716 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2718 (void **) &pSMBr);
2719 if (rc)
2720 return rc;
2721
2722 params = 6;
2723 pSMB->MaxSetupCount = 0;
2724 pSMB->Reserved = 0;
2725 pSMB->Flags = 0;
2726 pSMB->Timeout = 0;
2727 pSMB->Reserved2 = 0;
2728 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2729 offset = param_offset + params;
2730
2731 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2732 rename_info = (struct set_file_rename *) data_offset;
2733 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002734 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 pSMB->SetupCount = 1;
2736 pSMB->Reserved3 = 0;
2737 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2738 byte_count = 3 /* pad */ + params;
2739 pSMB->ParameterCount = cpu_to_le16(params);
2740 pSMB->TotalParameterCount = pSMB->ParameterCount;
2741 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2742 pSMB->DataOffset = cpu_to_le16(offset);
2743 /* construct random name ".cifs_tmp<inodenum><mid>" */
2744 rename_info->overwrite = cpu_to_le32(1);
2745 rename_info->root_fid = 0;
2746 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002747 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002748 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002749 len_of_str =
2750 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002751 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002753 len_of_str =
2754 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002755 target_name, PATH_MAX, nls_codepage,
2756 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 }
2758 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002759 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 byte_count += count;
2761 pSMB->DataCount = cpu_to_le16(count);
2762 pSMB->TotalDataCount = pSMB->DataCount;
2763 pSMB->Fid = netfid;
2764 pSMB->InformationLevel =
2765 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2766 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002767 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 pSMB->ByteCount = cpu_to_le16(byte_count);
2769 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002770 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002771 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002772 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002773 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2774 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002775
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 cifs_buf_release(pSMB);
2777
2778 /* Note: On -EAGAIN error only caller can retry on handle based calls
2779 since file handle passed in no longer valid */
2780
2781 return rc;
2782}
2783
2784int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002785CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2786 const char *fromName, const __u16 target_tid, const char *toName,
2787 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788{
2789 int rc = 0;
2790 COPY_REQ *pSMB = NULL;
2791 COPY_RSP *pSMBr = NULL;
2792 int bytes_returned;
2793 int name_len, name_len2;
2794 __u16 count;
2795
Joe Perchesf96637b2013-05-04 22:12:25 -05002796 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797copyRetry:
2798 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2799 (void **) &pSMBr);
2800 if (rc)
2801 return rc;
2802
2803 pSMB->BufferFormat = 0x04;
2804 pSMB->Tid2 = target_tid;
2805
2806 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2807
2808 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002809 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2810 fromName, PATH_MAX, nls_codepage,
2811 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812 name_len++; /* trailing null */
2813 name_len *= 2;
2814 pSMB->OldFileName[name_len] = 0x04; /* pad */
2815 /* protocol requires ASCII signature byte on Unicode string */
2816 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002817 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002818 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2819 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2821 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002822 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 name_len = strnlen(fromName, PATH_MAX);
2824 name_len++; /* trailing null */
2825 strncpy(pSMB->OldFileName, fromName, name_len);
2826 name_len2 = strnlen(toName, PATH_MAX);
2827 name_len2++; /* trailing null */
2828 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2829 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2830 name_len2++; /* trailing null */
2831 name_len2++; /* signature byte */
2832 }
2833
2834 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002835 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836 pSMB->ByteCount = cpu_to_le16(count);
2837
2838 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2839 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2840 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002841 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2842 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 }
Steve French0d817bc2008-05-22 02:02:03 +00002844 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845
2846 if (rc == -EAGAIN)
2847 goto copyRetry;
2848
2849 return rc;
2850}
2851
2852int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002853CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 const char *fromName, const char *toName,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002855 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856{
2857 TRANSACTION2_SPI_REQ *pSMB = NULL;
2858 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2859 char *data_offset;
2860 int name_len;
2861 int name_len_target;
2862 int rc = 0;
2863 int bytes_returned = 0;
2864 __u16 params, param_offset, offset, byte_count;
2865
Joe Perchesf96637b2013-05-04 22:12:25 -05002866 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867createSymLinkRetry:
2868 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2869 (void **) &pSMBr);
2870 if (rc)
2871 return rc;
2872
2873 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2874 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002875 cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
2876 /* find define for this maxpathcomponent */
2877 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 name_len++; /* trailing null */
2879 name_len *= 2;
2880
Steve French50c2f752007-07-13 00:33:32 +00002881 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 name_len = strnlen(fromName, PATH_MAX);
2883 name_len++; /* trailing null */
2884 strncpy(pSMB->FileName, fromName, name_len);
2885 }
2886 params = 6 + name_len;
2887 pSMB->MaxSetupCount = 0;
2888 pSMB->Reserved = 0;
2889 pSMB->Flags = 0;
2890 pSMB->Timeout = 0;
2891 pSMB->Reserved2 = 0;
2892 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002893 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 offset = param_offset + params;
2895
2896 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2897 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2898 name_len_target =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002899 cifsConvertToUTF16((__le16 *) data_offset, toName,
2900 /* find define for this maxpathcomponent */
2901 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 name_len_target++; /* trailing null */
2903 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002904 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 name_len_target = strnlen(toName, PATH_MAX);
2906 name_len_target++; /* trailing null */
2907 strncpy(data_offset, toName, name_len_target);
2908 }
2909
2910 pSMB->MaxParameterCount = cpu_to_le16(2);
2911 /* BB find exact max on data count below from sess */
2912 pSMB->MaxDataCount = cpu_to_le16(1000);
2913 pSMB->SetupCount = 1;
2914 pSMB->Reserved3 = 0;
2915 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2916 byte_count = 3 /* pad */ + params + name_len_target;
2917 pSMB->DataCount = cpu_to_le16(name_len_target);
2918 pSMB->ParameterCount = cpu_to_le16(params);
2919 pSMB->TotalDataCount = pSMB->DataCount;
2920 pSMB->TotalParameterCount = pSMB->ParameterCount;
2921 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2922 pSMB->DataOffset = cpu_to_le16(offset);
2923 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2924 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002925 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 pSMB->ByteCount = cpu_to_le16(byte_count);
2927 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2928 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002929 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002930 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002931 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2932 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933
Steve French0d817bc2008-05-22 02:02:03 +00002934 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935
2936 if (rc == -EAGAIN)
2937 goto createSymLinkRetry;
2938
2939 return rc;
2940}
2941
2942int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002943CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002945 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946{
2947 TRANSACTION2_SPI_REQ *pSMB = NULL;
2948 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2949 char *data_offset;
2950 int name_len;
2951 int name_len_target;
2952 int rc = 0;
2953 int bytes_returned = 0;
2954 __u16 params, param_offset, offset, byte_count;
2955
Joe Perchesf96637b2013-05-04 22:12:25 -05002956 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957createHardLinkRetry:
2958 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2959 (void **) &pSMBr);
2960 if (rc)
2961 return rc;
2962
2963 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002964 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2965 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966 name_len++; /* trailing null */
2967 name_len *= 2;
2968
Steve French50c2f752007-07-13 00:33:32 +00002969 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 name_len = strnlen(toName, PATH_MAX);
2971 name_len++; /* trailing null */
2972 strncpy(pSMB->FileName, toName, name_len);
2973 }
2974 params = 6 + name_len;
2975 pSMB->MaxSetupCount = 0;
2976 pSMB->Reserved = 0;
2977 pSMB->Flags = 0;
2978 pSMB->Timeout = 0;
2979 pSMB->Reserved2 = 0;
2980 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002981 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 offset = param_offset + params;
2983
2984 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2985 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2986 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002987 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2988 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 name_len_target++; /* trailing null */
2990 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002991 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 name_len_target = strnlen(fromName, PATH_MAX);
2993 name_len_target++; /* trailing null */
2994 strncpy(data_offset, fromName, name_len_target);
2995 }
2996
2997 pSMB->MaxParameterCount = cpu_to_le16(2);
2998 /* BB find exact max on data count below from sess*/
2999 pSMB->MaxDataCount = cpu_to_le16(1000);
3000 pSMB->SetupCount = 1;
3001 pSMB->Reserved3 = 0;
3002 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3003 byte_count = 3 /* pad */ + params + name_len_target;
3004 pSMB->ParameterCount = cpu_to_le16(params);
3005 pSMB->TotalParameterCount = pSMB->ParameterCount;
3006 pSMB->DataCount = cpu_to_le16(name_len_target);
3007 pSMB->TotalDataCount = pSMB->DataCount;
3008 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3009 pSMB->DataOffset = cpu_to_le16(offset);
3010 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
3011 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003012 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 pSMB->ByteCount = cpu_to_le16(byte_count);
3014 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3015 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003016 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003017 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003018 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
3019 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020
3021 cifs_buf_release(pSMB);
3022 if (rc == -EAGAIN)
3023 goto createHardLinkRetry;
3024
3025 return rc;
3026}
3027
3028int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003029CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07003030 const char *from_name, const char *to_name,
3031 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032{
3033 int rc = 0;
3034 NT_RENAME_REQ *pSMB = NULL;
3035 RENAME_RSP *pSMBr = NULL;
3036 int bytes_returned;
3037 int name_len, name_len2;
3038 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05003039 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040
Joe Perchesf96637b2013-05-04 22:12:25 -05003041 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042winCreateHardLinkRetry:
3043
3044 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
3045 (void **) &pSMBr);
3046 if (rc)
3047 return rc;
3048
3049 pSMB->SearchAttributes =
3050 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3051 ATTR_DIRECTORY);
3052 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3053 pSMB->ClusterCount = 0;
3054
3055 pSMB->BufferFormat = 0x04;
3056
3057 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3058 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07003059 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
3060 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 name_len++; /* trailing null */
3062 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05003063
3064 /* protocol specifies ASCII buffer format (0x04) for unicode */
3065 pSMB->OldFileName[name_len] = 0x04;
3066 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06003068 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07003069 to_name, PATH_MAX, cifs_sb->local_nls,
3070 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3072 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00003073 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003074 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003076 strncpy(pSMB->OldFileName, from_name, name_len);
3077 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 name_len2++; /* trailing null */
3079 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003080 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 name_len2++; /* trailing null */
3082 name_len2++; /* signature byte */
3083 }
3084
3085 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003086 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 pSMB->ByteCount = cpu_to_le16(count);
3088
3089 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3090 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003091 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003092 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003093 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003094
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 cifs_buf_release(pSMB);
3096 if (rc == -EAGAIN)
3097 goto winCreateHardLinkRetry;
3098
3099 return rc;
3100}
3101
3102int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003103CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003104 const unsigned char *searchName, char **symlinkinfo,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003105 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106{
3107/* SMB_QUERY_FILE_UNIX_LINK */
3108 TRANSACTION2_QPI_REQ *pSMB = NULL;
3109 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3110 int rc = 0;
3111 int bytes_returned;
3112 int name_len;
3113 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003114 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115
Joe Perchesf96637b2013-05-04 22:12:25 -05003116 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117
3118querySymLinkRetry:
3119 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3120 (void **) &pSMBr);
3121 if (rc)
3122 return rc;
3123
3124 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3125 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003126 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3127 searchName, PATH_MAX, nls_codepage,
3128 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 name_len++; /* trailing null */
3130 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003131 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 name_len = strnlen(searchName, PATH_MAX);
3133 name_len++; /* trailing null */
3134 strncpy(pSMB->FileName, searchName, name_len);
3135 }
3136
3137 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3138 pSMB->TotalDataCount = 0;
3139 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003140 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141 pSMB->MaxSetupCount = 0;
3142 pSMB->Reserved = 0;
3143 pSMB->Flags = 0;
3144 pSMB->Timeout = 0;
3145 pSMB->Reserved2 = 0;
3146 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003147 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148 pSMB->DataCount = 0;
3149 pSMB->DataOffset = 0;
3150 pSMB->SetupCount = 1;
3151 pSMB->Reserved3 = 0;
3152 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3153 byte_count = params + 1 /* pad */ ;
3154 pSMB->TotalParameterCount = cpu_to_le16(params);
3155 pSMB->ParameterCount = pSMB->TotalParameterCount;
3156 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3157 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003158 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159 pSMB->ByteCount = cpu_to_le16(byte_count);
3160
3161 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3162 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3163 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003164 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 } else {
3166 /* decode response */
3167
3168 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003170 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003171 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003173 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003174 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175
Jeff Layton460b9692009-04-30 07:17:56 -04003176 data_start = ((char *) &pSMBr->hdr.Protocol) +
3177 le16_to_cpu(pSMBr->t2.DataOffset);
3178
Steve French0e0d2cf2009-05-01 05:27:32 +00003179 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3180 is_unicode = true;
3181 else
3182 is_unicode = false;
3183
Steve French737b7582005-04-28 22:41:06 -07003184 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003185 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3186 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003187 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003188 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189 }
3190 }
3191 cifs_buf_release(pSMB);
3192 if (rc == -EAGAIN)
3193 goto querySymLinkRetry;
3194 return rc;
3195}
3196
Steve Frenchc52a9552011-02-24 06:16:22 +00003197/*
3198 * Recent Windows versions now create symlinks more frequently
3199 * and they use the "reparse point" mechanism below. We can of course
3200 * do symlinks nicely to Samba and other servers which support the
3201 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3202 * "MF" symlinks optionally, but for recent Windows we really need to
3203 * reenable the code below and fix the cifs_symlink callers to handle this.
3204 * In the interim this code has been moved to its own config option so
3205 * it is not compiled in by default until callers fixed up and more tested.
3206 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003208CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3209 __u16 fid, char **symlinkinfo,
3210 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211{
3212 int rc = 0;
3213 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003214 struct smb_com_transaction_ioctl_req *pSMB;
3215 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003216 bool is_unicode;
3217 unsigned int sub_len;
3218 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003219 struct reparse_symlink_data *reparse_buf;
3220 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003221 __u32 data_offset, data_count;
3222 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003224 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3226 (void **) &pSMBr);
3227 if (rc)
3228 return rc;
3229
3230 pSMB->TotalParameterCount = 0 ;
3231 pSMB->TotalDataCount = 0;
3232 pSMB->MaxParameterCount = cpu_to_le32(2);
3233 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003234 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235 pSMB->MaxSetupCount = 4;
3236 pSMB->Reserved = 0;
3237 pSMB->ParameterOffset = 0;
3238 pSMB->DataCount = 0;
3239 pSMB->DataOffset = 0;
3240 pSMB->SetupCount = 4;
3241 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3242 pSMB->ParameterCount = pSMB->TotalParameterCount;
3243 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3244 pSMB->IsFsctl = 1; /* FSCTL */
3245 pSMB->IsRootFlag = 0;
3246 pSMB->Fid = fid; /* file handle always le */
3247 pSMB->ByteCount = 0;
3248
3249 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3250 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3251 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003252 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003253 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254 }
Steve French989c7e52009-05-02 05:32:20 +00003255
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003256 data_offset = le32_to_cpu(pSMBr->DataOffset);
3257 data_count = le32_to_cpu(pSMBr->DataCount);
3258 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3259 /* BB also check enough total bytes returned */
3260 rc = -EIO; /* bad smb */
3261 goto qreparse_out;
3262 }
3263 if (!data_count || (data_count > 2048)) {
3264 rc = -EIO;
3265 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3266 goto qreparse_out;
3267 }
3268 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003269 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003270 ((char *)&pSMBr->hdr.Protocol + data_offset);
3271 if ((char *)reparse_buf >= end_of_smb) {
3272 rc = -EIO;
3273 goto qreparse_out;
3274 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003275 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3276 cifs_dbg(FYI, "NFS style reparse tag\n");
3277 posix_buf = (struct reparse_posix_data *)reparse_buf;
3278
3279 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3280 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3281 le64_to_cpu(posix_buf->InodeType));
3282 rc = -EOPNOTSUPP;
3283 goto qreparse_out;
3284 }
3285 is_unicode = true;
3286 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3287 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3288 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3289 rc = -EIO;
3290 goto qreparse_out;
3291 }
3292 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3293 sub_len, is_unicode, nls_codepage);
3294 goto qreparse_out;
3295 } else if (reparse_buf->ReparseTag !=
3296 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3297 rc = -EOPNOTSUPP;
3298 goto qreparse_out;
3299 }
3300
3301 /* Reparse tag is NTFS symlink */
3302 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3303 reparse_buf->PathBuffer;
3304 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3305 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003306 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3307 rc = -EIO;
3308 goto qreparse_out;
3309 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003310 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3311 is_unicode = true;
3312 else
3313 is_unicode = false;
3314
3315 /* BB FIXME investigate remapping reserved chars here */
3316 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3317 nls_codepage);
3318 if (!*symlinkinfo)
3319 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003320qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003321 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003323 /*
3324 * Note: On -EAGAIN error only caller can retry on handle based calls
3325 * since file handle passed in no longer valid.
3326 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327 return rc;
3328}
3329
Steve Frenchc7f508a2013-10-14 15:27:32 -05003330int
3331CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3332 __u16 fid)
3333{
3334 int rc = 0;
3335 int bytes_returned;
3336 struct smb_com_transaction_compr_ioctl_req *pSMB;
3337 struct smb_com_transaction_ioctl_rsp *pSMBr;
3338
3339 cifs_dbg(FYI, "Set compression for %u\n", fid);
3340 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3341 (void **) &pSMBr);
3342 if (rc)
3343 return rc;
3344
3345 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3346
3347 pSMB->TotalParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003348 pSMB->TotalDataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003349 pSMB->MaxParameterCount = 0;
3350 pSMB->MaxDataCount = 0;
3351 pSMB->MaxSetupCount = 4;
3352 pSMB->Reserved = 0;
3353 pSMB->ParameterOffset = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003354 pSMB->DataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003355 pSMB->DataOffset =
3356 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3357 compression_state) - 4); /* 84 */
3358 pSMB->SetupCount = 4;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003359 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003360 pSMB->ParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003361 pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003362 pSMB->IsFsctl = 1; /* FSCTL */
3363 pSMB->IsRootFlag = 0;
3364 pSMB->Fid = fid; /* file handle always le */
3365 /* 3 byte pad, followed by 2 byte compress state */
Fabian Frederickbc09d142014-12-10 15:41:15 -08003366 pSMB->ByteCount = cpu_to_le16(5);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003367 inc_rfc1001_len(pSMB, 5);
3368
3369 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3370 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3371 if (rc)
3372 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3373
3374 cifs_buf_release(pSMB);
3375
3376 /*
3377 * Note: On -EAGAIN error only caller can retry on handle based calls
3378 * since file handle passed in no longer valid.
3379 */
3380 return rc;
3381}
3382
3383
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384#ifdef CONFIG_CIFS_POSIX
3385
3386/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003387static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
Steve French50c2f752007-07-13 00:33:32 +00003388 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389{
3390 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003391 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3392 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3393 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003394/*
3395 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3396 ace->e_perm, ace->e_tag, ace->e_id);
3397*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398
3399 return;
3400}
3401
3402/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003403static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3404 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405{
3406 int size = 0;
3407 int i;
3408 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003409 struct cifs_posix_ace *pACE;
3410 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003411 struct posix_acl_xattr_header *local_acl = (void *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412
3413 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3414 return -EOPNOTSUPP;
3415
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003416 if (acl_type == ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417 count = le16_to_cpu(cifs_acl->access_entry_count);
3418 pACE = &cifs_acl->ace_array[0];
3419 size = sizeof(struct cifs_posix_acl);
3420 size += sizeof(struct cifs_posix_ace) * count;
3421 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003422 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003423 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3424 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425 return -EINVAL;
3426 }
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003427 } else if (acl_type == ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 count = le16_to_cpu(cifs_acl->access_entry_count);
3429 size = sizeof(struct cifs_posix_acl);
3430 size += sizeof(struct cifs_posix_ace) * count;
3431/* skip past access ACEs to get to default ACEs */
3432 pACE = &cifs_acl->ace_array[count];
3433 count = le16_to_cpu(cifs_acl->default_entry_count);
3434 size += sizeof(struct cifs_posix_ace) * count;
3435 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003436 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 return -EINVAL;
3438 } else {
3439 /* illegal type */
3440 return -EINVAL;
3441 }
3442
3443 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003444 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003445 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003446 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447 return -ERANGE;
3448 } else /* buffer big enough */ {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003449 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
3450
Steve Frenchff7feac2005-11-15 16:45:16 -08003451 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003452 for (i = 0; i < count ; i++) {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003453 cifs_convert_ace(&ace[i], pACE);
Steve French50c2f752007-07-13 00:33:32 +00003454 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455 }
3456 }
3457 return size;
3458}
3459
Steve French50c2f752007-07-13 00:33:32 +00003460static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003461 const struct posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462{
3463 __u16 rc = 0; /* 0 = ACL converted ok */
3464
Steve Frenchff7feac2005-11-15 16:45:16 -08003465 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3466 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003468 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 /* Probably no need to le convert -1 on any arch but can not hurt */
3470 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003471 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003472 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003473/*
3474 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3475 ace->e_perm, ace->e_tag, ace->e_id);
3476*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 return rc;
3478}
3479
3480/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003481static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3482 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483{
3484 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003485 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003486 struct posix_acl_xattr_header *local_acl = (void *)pACL;
Eryu Guanae9ebe72016-10-24 20:46:40 +08003487 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488 int count;
3489 int i;
3490
Steve French790fe572007-07-07 19:25:05 +00003491 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492 return 0;
3493
3494 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003495 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3496 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003497 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003498 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3499 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500 return 0;
3501 }
3502 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003503 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003504 cifs_acl->access_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003505 cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003506 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003507 cifs_acl->default_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003508 cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003509 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003510 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511 return 0;
3512 }
Steve French50c2f752007-07-13 00:33:32 +00003513 for (i = 0; i < count; i++) {
Eryu Guanae9ebe72016-10-24 20:46:40 +08003514 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
Steve French790fe572007-07-07 19:25:05 +00003515 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 /* ACE not converted */
3517 break;
3518 }
3519 }
Steve French790fe572007-07-07 19:25:05 +00003520 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3522 rc += sizeof(struct cifs_posix_acl);
3523 /* BB add check to make sure ACL does not overflow SMB */
3524 }
3525 return rc;
3526}
3527
3528int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003529CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003530 const unsigned char *searchName,
3531 char *acl_inf, const int buflen, const int acl_type,
3532 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533{
3534/* SMB_QUERY_POSIX_ACL */
3535 TRANSACTION2_QPI_REQ *pSMB = NULL;
3536 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3537 int rc = 0;
3538 int bytes_returned;
3539 int name_len;
3540 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003541
Joe Perchesf96637b2013-05-04 22:12:25 -05003542 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543
3544queryAclRetry:
3545 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3546 (void **) &pSMBr);
3547 if (rc)
3548 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003549
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3551 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003552 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3553 searchName, PATH_MAX, nls_codepage,
3554 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555 name_len++; /* trailing null */
3556 name_len *= 2;
3557 pSMB->FileName[name_len] = 0;
3558 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003559 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560 name_len = strnlen(searchName, PATH_MAX);
3561 name_len++; /* trailing null */
3562 strncpy(pSMB->FileName, searchName, name_len);
3563 }
3564
3565 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3566 pSMB->TotalDataCount = 0;
3567 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003568 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569 pSMB->MaxDataCount = cpu_to_le16(4000);
3570 pSMB->MaxSetupCount = 0;
3571 pSMB->Reserved = 0;
3572 pSMB->Flags = 0;
3573 pSMB->Timeout = 0;
3574 pSMB->Reserved2 = 0;
3575 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003576 offsetof(struct smb_com_transaction2_qpi_req,
3577 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578 pSMB->DataCount = 0;
3579 pSMB->DataOffset = 0;
3580 pSMB->SetupCount = 1;
3581 pSMB->Reserved3 = 0;
3582 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3583 byte_count = params + 1 /* pad */ ;
3584 pSMB->TotalParameterCount = cpu_to_le16(params);
3585 pSMB->ParameterCount = pSMB->TotalParameterCount;
3586 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3587 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003588 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 pSMB->ByteCount = cpu_to_le16(byte_count);
3590
3591 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3592 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003593 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003595 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596 } else {
3597 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003598
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003601 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 rc = -EIO; /* bad smb */
3603 else {
3604 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3605 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3606 rc = cifs_copy_posix_acl(acl_inf,
3607 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003608 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 }
3610 }
3611 cifs_buf_release(pSMB);
3612 if (rc == -EAGAIN)
3613 goto queryAclRetry;
3614 return rc;
3615}
3616
3617int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003618CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003619 const unsigned char *fileName,
3620 const char *local_acl, const int buflen,
3621 const int acl_type,
3622 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623{
3624 struct smb_com_transaction2_spi_req *pSMB = NULL;
3625 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3626 char *parm_data;
3627 int name_len;
3628 int rc = 0;
3629 int bytes_returned = 0;
3630 __u16 params, byte_count, data_count, param_offset, offset;
3631
Joe Perchesf96637b2013-05-04 22:12:25 -05003632 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633setAclRetry:
3634 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003635 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 if (rc)
3637 return rc;
3638 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3639 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003640 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3641 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 name_len++; /* trailing null */
3643 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003644 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645 name_len = strnlen(fileName, PATH_MAX);
3646 name_len++; /* trailing null */
3647 strncpy(pSMB->FileName, fileName, name_len);
3648 }
3649 params = 6 + name_len;
3650 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003651 /* BB find max SMB size from sess */
3652 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653 pSMB->MaxSetupCount = 0;
3654 pSMB->Reserved = 0;
3655 pSMB->Flags = 0;
3656 pSMB->Timeout = 0;
3657 pSMB->Reserved2 = 0;
3658 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003659 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660 offset = param_offset + params;
3661 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3662 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3663
3664 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003665 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666
Steve French790fe572007-07-07 19:25:05 +00003667 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 rc = -EOPNOTSUPP;
3669 goto setACLerrorExit;
3670 }
3671 pSMB->DataOffset = cpu_to_le16(offset);
3672 pSMB->SetupCount = 1;
3673 pSMB->Reserved3 = 0;
3674 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3675 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3676 byte_count = 3 /* pad */ + params + data_count;
3677 pSMB->DataCount = cpu_to_le16(data_count);
3678 pSMB->TotalDataCount = pSMB->DataCount;
3679 pSMB->ParameterCount = cpu_to_le16(params);
3680 pSMB->TotalParameterCount = pSMB->ParameterCount;
3681 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003682 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 pSMB->ByteCount = cpu_to_le16(byte_count);
3684 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003685 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003686 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003687 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688
3689setACLerrorExit:
3690 cifs_buf_release(pSMB);
3691 if (rc == -EAGAIN)
3692 goto setAclRetry;
3693 return rc;
3694}
3695
Steve Frenchf654bac2005-04-28 22:41:04 -07003696/* BB fix tabs in this function FIXME BB */
3697int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003698CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003699 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003700{
Steve French50c2f752007-07-13 00:33:32 +00003701 int rc = 0;
3702 struct smb_t2_qfi_req *pSMB = NULL;
3703 struct smb_t2_qfi_rsp *pSMBr = NULL;
3704 int bytes_returned;
3705 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003706
Joe Perchesf96637b2013-05-04 22:12:25 -05003707 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003708 if (tcon == NULL)
3709 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003710
3711GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003712 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3713 (void **) &pSMBr);
3714 if (rc)
3715 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003716
Steve Frenchad7a2922008-02-07 23:25:02 +00003717 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003718 pSMB->t2.TotalDataCount = 0;
3719 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3720 /* BB find exact max data count below from sess structure BB */
3721 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3722 pSMB->t2.MaxSetupCount = 0;
3723 pSMB->t2.Reserved = 0;
3724 pSMB->t2.Flags = 0;
3725 pSMB->t2.Timeout = 0;
3726 pSMB->t2.Reserved2 = 0;
3727 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3728 Fid) - 4);
3729 pSMB->t2.DataCount = 0;
3730 pSMB->t2.DataOffset = 0;
3731 pSMB->t2.SetupCount = 1;
3732 pSMB->t2.Reserved3 = 0;
3733 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3734 byte_count = params + 1 /* pad */ ;
3735 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3736 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3737 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3738 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003739 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003740 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003741 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003742
Steve French790fe572007-07-07 19:25:05 +00003743 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3744 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3745 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003746 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003747 } else {
3748 /* decode response */
3749 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003750 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003751 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003752 /* If rc should we check for EOPNOSUPP and
3753 disable the srvino flag? or in caller? */
3754 rc = -EIO; /* bad smb */
3755 else {
3756 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3757 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3758 struct file_chattr_info *pfinfo;
3759 /* BB Do we need a cast or hash here ? */
3760 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003761 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003762 rc = -EIO;
3763 goto GetExtAttrOut;
3764 }
3765 pfinfo = (struct file_chattr_info *)
3766 (data_offset + (char *) &pSMBr->hdr.Protocol);
3767 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003768 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003769 }
3770 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003771GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003772 cifs_buf_release(pSMB);
3773 if (rc == -EAGAIN)
3774 goto GetExtAttrRetry;
3775 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003776}
3777
Steve Frenchf654bac2005-04-28 22:41:04 -07003778#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779
Jeff Layton79df1ba2010-12-06 12:52:08 -05003780#ifdef CONFIG_CIFS_ACL
3781/*
3782 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3783 * all NT TRANSACTS that we init here have total parm and data under about 400
3784 * bytes (to fit in small cifs buffer size), which is the case so far, it
3785 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3786 * returned setup area) and MaxParameterCount (returned parms size) must be set
3787 * by caller
3788 */
3789static int
3790smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003791 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003792 void **ret_buf)
3793{
3794 int rc;
3795 __u32 temp_offset;
3796 struct smb_com_ntransact_req *pSMB;
3797
3798 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3799 (void **)&pSMB);
3800 if (rc)
3801 return rc;
3802 *ret_buf = (void *)pSMB;
3803 pSMB->Reserved = 0;
3804 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3805 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003806 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003807 pSMB->ParameterCount = pSMB->TotalParameterCount;
3808 pSMB->DataCount = pSMB->TotalDataCount;
3809 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3810 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3811 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3812 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3813 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3814 pSMB->SubCommand = cpu_to_le16(sub_command);
3815 return 0;
3816}
3817
3818static int
3819validate_ntransact(char *buf, char **ppparm, char **ppdata,
3820 __u32 *pparmlen, __u32 *pdatalen)
3821{
3822 char *end_of_smb;
3823 __u32 data_count, data_offset, parm_count, parm_offset;
3824 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003825 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003826
3827 *pdatalen = 0;
3828 *pparmlen = 0;
3829
3830 if (buf == NULL)
3831 return -EINVAL;
3832
3833 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3834
Jeff Layton820a8032011-05-04 08:05:26 -04003835 bcc = get_bcc(&pSMBr->hdr);
3836 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003837 (char *)&pSMBr->ByteCount;
3838
3839 data_offset = le32_to_cpu(pSMBr->DataOffset);
3840 data_count = le32_to_cpu(pSMBr->DataCount);
3841 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3842 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3843
3844 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3845 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3846
3847 /* should we also check that parm and data areas do not overlap? */
3848 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003849 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003850 return -EINVAL;
3851 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003852 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003853 return -EINVAL;
3854 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003855 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003856 return -EINVAL;
3857 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003858 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3859 *ppdata, data_count, (data_count + *ppdata),
3860 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003861 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003862 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003863 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003864 return -EINVAL;
3865 }
3866 *pdatalen = data_count;
3867 *pparmlen = parm_count;
3868 return 0;
3869}
3870
Steve French0a4b92c2006-01-12 15:44:21 -08003871/* Get Security Descriptor (by handle) from remote server for a file or dir */
3872int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003873CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003874 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003875{
3876 int rc = 0;
3877 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003878 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003879 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003880 struct kvec rsp_iov;
Steve French0a4b92c2006-01-12 15:44:21 -08003881
Joe Perchesf96637b2013-05-04 22:12:25 -05003882 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003883
Steve French630f3f0c2007-10-25 21:17:17 +00003884 *pbuflen = 0;
3885 *acl_inf = NULL;
3886
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003887 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003888 8 /* parm len */, tcon, (void **) &pSMB);
3889 if (rc)
3890 return rc;
3891
3892 pSMB->MaxParameterCount = cpu_to_le32(4);
3893 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3894 pSMB->MaxSetupCount = 0;
3895 pSMB->Fid = fid; /* file handle always le */
3896 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3897 CIFS_ACL_DACL);
3898 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003899 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003900 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003901 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003902
Steve Frencha761ac52007-10-18 21:45:27 +00003903 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003904 0, &rsp_iov);
3905 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003906 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003907 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003908 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003909 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003910 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003911 __u32 parm_len;
3912 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003913 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003914 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003915
3916/* validate_nttransact */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003917 rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003918 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003919 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003920 goto qsec_out;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003921 pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
Steve French0a4b92c2006-01-12 15:44:21 -08003922
Joe Perchesf96637b2013-05-04 22:12:25 -05003923 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3924 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003925
3926 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3927 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003928 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003929 goto qsec_out;
3930 }
3931
3932/* BB check that data area is minimum length and as big as acl_len */
3933
Steve Frenchaf6f4612007-10-16 18:40:37 +00003934 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003935 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003936 cifs_dbg(VFS, "acl length %d does not match %d\n",
3937 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003938 if (*pbuflen > acl_len)
3939 *pbuflen = acl_len;
3940 }
Steve French0a4b92c2006-01-12 15:44:21 -08003941
Steve French630f3f0c2007-10-25 21:17:17 +00003942 /* check if buffer is big enough for the acl
3943 header followed by the smallest SID */
3944 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3945 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003946 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003947 rc = -EINVAL;
3948 *pbuflen = 0;
3949 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003950 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003951 if (*acl_inf == NULL) {
3952 *pbuflen = 0;
3953 rc = -ENOMEM;
3954 }
Steve French630f3f0c2007-10-25 21:17:17 +00003955 }
Steve French0a4b92c2006-01-12 15:44:21 -08003956 }
3957qsec_out:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003958 free_rsp_buf(buf_type, rsp_iov.iov_base);
Steve French0a4b92c2006-01-12 15:44:21 -08003959 return rc;
3960}
Steve French97837582007-12-31 07:47:21 +00003961
3962int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003963CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003964 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003965{
3966 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3967 int rc = 0;
3968 int bytes_returned = 0;
3969 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003970 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003971
3972setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003973 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003974 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003975 return rc;
Steve French97837582007-12-31 07:47:21 +00003976
3977 pSMB->MaxSetupCount = 0;
3978 pSMB->Reserved = 0;
3979
3980 param_count = 8;
3981 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3982 data_count = acllen;
3983 data_offset = param_offset + param_count;
3984 byte_count = 3 /* pad */ + param_count;
3985
3986 pSMB->DataCount = cpu_to_le32(data_count);
3987 pSMB->TotalDataCount = pSMB->DataCount;
3988 pSMB->MaxParameterCount = cpu_to_le32(4);
3989 pSMB->MaxDataCount = cpu_to_le32(16384);
3990 pSMB->ParameterCount = cpu_to_le32(param_count);
3991 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3992 pSMB->TotalParameterCount = pSMB->ParameterCount;
3993 pSMB->DataOffset = cpu_to_le32(data_offset);
3994 pSMB->SetupCount = 0;
3995 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3996 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3997
3998 pSMB->Fid = fid; /* file handle always le */
3999 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05004000 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00004001
4002 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04004003 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
4004 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004005 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00004006 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004007 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00004008
4009 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4010 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4011
Joe Perchesf96637b2013-05-04 22:12:25 -05004012 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
4013 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00004014 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004015 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00004016 cifs_buf_release(pSMB);
4017
4018 if (rc == -EAGAIN)
4019 goto setCifsAclRetry;
4020
4021 return (rc);
4022}
4023
Jeff Layton79df1ba2010-12-06 12:52:08 -05004024#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08004025
Steve French6b8edfe2005-08-23 20:26:03 -07004026/* Legacy Query Path Information call for lookup to old servers such
4027 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004028int
4029SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
4030 const char *search_name, FILE_ALL_INFO *data,
4031 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07004032{
Steve Frenchad7a2922008-02-07 23:25:02 +00004033 QUERY_INFORMATION_REQ *pSMB;
4034 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07004035 int rc = 0;
4036 int bytes_returned;
4037 int name_len;
4038
Joe Perchesf96637b2013-05-04 22:12:25 -05004039 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004040QInfRetry:
4041 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004042 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07004043 if (rc)
4044 return rc;
4045
4046 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4047 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004048 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004049 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004050 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07004051 name_len++; /* trailing null */
4052 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004053 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004054 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07004055 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004056 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004057 }
4058 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00004059 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004060 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004061 pSMB->ByteCount = cpu_to_le16(name_len);
4062
4063 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004064 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07004065 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004066 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004067 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00004068 struct timespec ts;
4069 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00004070
4071 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00004072 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004073 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00004074 ts.tv_nsec = 0;
4075 ts.tv_sec = time;
4076 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004077 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
4078 data->LastWriteTime = data->ChangeTime;
4079 data->LastAccessTime = 0;
4080 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07004081 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004082 data->EndOfFile = data->AllocationSize;
4083 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07004084 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07004085 } else
4086 rc = -EIO; /* bad buffer passed in */
4087
4088 cifs_buf_release(pSMB);
4089
4090 if (rc == -EAGAIN)
4091 goto QInfRetry;
4092
4093 return rc;
4094}
4095
Jeff Laytonbcd53572010-02-12 07:44:16 -05004096int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004097CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004098 u16 netfid, FILE_ALL_INFO *pFindData)
4099{
4100 struct smb_t2_qfi_req *pSMB = NULL;
4101 struct smb_t2_qfi_rsp *pSMBr = NULL;
4102 int rc = 0;
4103 int bytes_returned;
4104 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004105
Jeff Laytonbcd53572010-02-12 07:44:16 -05004106QFileInfoRetry:
4107 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4108 (void **) &pSMBr);
4109 if (rc)
4110 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004111
Jeff Laytonbcd53572010-02-12 07:44:16 -05004112 params = 2 /* level */ + 2 /* fid */;
4113 pSMB->t2.TotalDataCount = 0;
4114 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4115 /* BB find exact max data count below from sess structure BB */
4116 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4117 pSMB->t2.MaxSetupCount = 0;
4118 pSMB->t2.Reserved = 0;
4119 pSMB->t2.Flags = 0;
4120 pSMB->t2.Timeout = 0;
4121 pSMB->t2.Reserved2 = 0;
4122 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4123 Fid) - 4);
4124 pSMB->t2.DataCount = 0;
4125 pSMB->t2.DataOffset = 0;
4126 pSMB->t2.SetupCount = 1;
4127 pSMB->t2.Reserved3 = 0;
4128 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4129 byte_count = params + 1 /* pad */ ;
4130 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4131 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4132 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4133 pSMB->Pad = 0;
4134 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004135 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004136 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004137
4138 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4139 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4140 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004141 cifs_dbg(FYI, "Send error in QFileInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004142 } else { /* decode response */
4143 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4144
4145 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4146 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004147 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004148 rc = -EIO; /* bad smb */
4149 else if (pFindData) {
4150 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4151 memcpy((char *) pFindData,
4152 (char *) &pSMBr->hdr.Protocol +
4153 data_offset, sizeof(FILE_ALL_INFO));
4154 } else
4155 rc = -ENOMEM;
4156 }
4157 cifs_buf_release(pSMB);
4158 if (rc == -EAGAIN)
4159 goto QFileInfoRetry;
4160
4161 return rc;
4162}
Steve French6b8edfe2005-08-23 20:26:03 -07004163
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004165CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004166 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004167 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004168 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004170 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171 TRANSACTION2_QPI_REQ *pSMB = NULL;
4172 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4173 int rc = 0;
4174 int bytes_returned;
4175 int name_len;
4176 __u16 params, byte_count;
4177
Joe Perchesf96637b2013-05-04 22:12:25 -05004178 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179QPathInfoRetry:
4180 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4181 (void **) &pSMBr);
4182 if (rc)
4183 return rc;
4184
4185 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4186 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004187 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004188 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189 name_len++; /* trailing null */
4190 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004191 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004192 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004194 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195 }
4196
Steve French50c2f752007-07-13 00:33:32 +00004197 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198 pSMB->TotalDataCount = 0;
4199 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004200 /* BB find exact max SMB PDU from sess structure BB */
4201 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004202 pSMB->MaxSetupCount = 0;
4203 pSMB->Reserved = 0;
4204 pSMB->Flags = 0;
4205 pSMB->Timeout = 0;
4206 pSMB->Reserved2 = 0;
4207 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004208 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209 pSMB->DataCount = 0;
4210 pSMB->DataOffset = 0;
4211 pSMB->SetupCount = 1;
4212 pSMB->Reserved3 = 0;
4213 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4214 byte_count = params + 1 /* pad */ ;
4215 pSMB->TotalParameterCount = cpu_to_le16(params);
4216 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004217 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004218 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4219 else
4220 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004221 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004222 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223 pSMB->ByteCount = cpu_to_le16(byte_count);
4224
4225 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4226 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4227 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004228 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229 } else { /* decode response */
4230 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4231
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004232 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4233 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004234 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004236 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004237 rc = -EIO; /* 24 or 26 expected but we do not read
4238 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004239 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004240 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004242
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004243 /*
4244 * On legacy responses we do not read the last field,
4245 * EAsize, fortunately since it varies by subdialect and
4246 * also note it differs on Set vs Get, ie two bytes or 4
4247 * bytes depending but we don't care here.
4248 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004249 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004250 size = sizeof(FILE_INFO_STANDARD);
4251 else
4252 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004253 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004254 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255 } else
4256 rc = -ENOMEM;
4257 }
4258 cifs_buf_release(pSMB);
4259 if (rc == -EAGAIN)
4260 goto QPathInfoRetry;
4261
4262 return rc;
4263}
4264
4265int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004266CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004267 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4268{
4269 struct smb_t2_qfi_req *pSMB = NULL;
4270 struct smb_t2_qfi_rsp *pSMBr = NULL;
4271 int rc = 0;
4272 int bytes_returned;
4273 __u16 params, byte_count;
4274
4275UnixQFileInfoRetry:
4276 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4277 (void **) &pSMBr);
4278 if (rc)
4279 return rc;
4280
4281 params = 2 /* level */ + 2 /* fid */;
4282 pSMB->t2.TotalDataCount = 0;
4283 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4284 /* BB find exact max data count below from sess structure BB */
4285 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4286 pSMB->t2.MaxSetupCount = 0;
4287 pSMB->t2.Reserved = 0;
4288 pSMB->t2.Flags = 0;
4289 pSMB->t2.Timeout = 0;
4290 pSMB->t2.Reserved2 = 0;
4291 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4292 Fid) - 4);
4293 pSMB->t2.DataCount = 0;
4294 pSMB->t2.DataOffset = 0;
4295 pSMB->t2.SetupCount = 1;
4296 pSMB->t2.Reserved3 = 0;
4297 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4298 byte_count = params + 1 /* pad */ ;
4299 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4300 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4301 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4302 pSMB->Pad = 0;
4303 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004304 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004305 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004306
4307 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4308 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4309 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004310 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004311 } else { /* decode response */
4312 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4313
Jeff Layton820a8032011-05-04 08:05:26 -04004314 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004315 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 -05004316 rc = -EIO; /* bad smb */
4317 } else {
4318 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4319 memcpy((char *) pFindData,
4320 (char *) &pSMBr->hdr.Protocol +
4321 data_offset,
4322 sizeof(FILE_UNIX_BASIC_INFO));
4323 }
4324 }
4325
4326 cifs_buf_release(pSMB);
4327 if (rc == -EAGAIN)
4328 goto UnixQFileInfoRetry;
4329
4330 return rc;
4331}
4332
4333int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004334CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004336 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004337 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338{
4339/* SMB_QUERY_FILE_UNIX_BASIC */
4340 TRANSACTION2_QPI_REQ *pSMB = NULL;
4341 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4342 int rc = 0;
4343 int bytes_returned = 0;
4344 int name_len;
4345 __u16 params, byte_count;
4346
Joe Perchesf96637b2013-05-04 22:12:25 -05004347 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348UnixQPathInfoRetry:
4349 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4350 (void **) &pSMBr);
4351 if (rc)
4352 return rc;
4353
4354 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4355 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004356 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4357 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358 name_len++; /* trailing null */
4359 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004360 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 name_len = strnlen(searchName, PATH_MAX);
4362 name_len++; /* trailing null */
4363 strncpy(pSMB->FileName, searchName, name_len);
4364 }
4365
Steve French50c2f752007-07-13 00:33:32 +00004366 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367 pSMB->TotalDataCount = 0;
4368 pSMB->MaxParameterCount = cpu_to_le16(2);
4369 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004370 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371 pSMB->MaxSetupCount = 0;
4372 pSMB->Reserved = 0;
4373 pSMB->Flags = 0;
4374 pSMB->Timeout = 0;
4375 pSMB->Reserved2 = 0;
4376 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004377 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378 pSMB->DataCount = 0;
4379 pSMB->DataOffset = 0;
4380 pSMB->SetupCount = 1;
4381 pSMB->Reserved3 = 0;
4382 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4383 byte_count = params + 1 /* pad */ ;
4384 pSMB->TotalParameterCount = cpu_to_le16(params);
4385 pSMB->ParameterCount = pSMB->TotalParameterCount;
4386 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4387 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004388 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389 pSMB->ByteCount = cpu_to_le16(byte_count);
4390
4391 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4392 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4393 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004394 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004395 } else { /* decode response */
4396 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4397
Jeff Layton820a8032011-05-04 08:05:26 -04004398 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004399 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 -07004400 rc = -EIO; /* bad smb */
4401 } else {
4402 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4403 memcpy((char *) pFindData,
4404 (char *) &pSMBr->hdr.Protocol +
4405 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004406 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407 }
4408 }
4409 cifs_buf_release(pSMB);
4410 if (rc == -EAGAIN)
4411 goto UnixQPathInfoRetry;
4412
4413 return rc;
4414}
4415
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416/* xid, tcon, searchName and codepage are input parms, rest are returned */
4417int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004418CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004419 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004420 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004421 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422{
4423/* level 257 SMB_ */
4424 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4425 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004426 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427 int rc = 0;
4428 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004429 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004431 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432
Joe Perchesf96637b2013-05-04 22:12:25 -05004433 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434
4435findFirstRetry:
4436 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4437 (void **) &pSMBr);
4438 if (rc)
4439 return rc;
4440
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004441 nls_codepage = cifs_sb->local_nls;
Steve French2baa2682014-09-27 02:19:01 -05004442 remap = cifs_remap(cifs_sb);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004443
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4445 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004446 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4447 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004448 /* We can not add the asterik earlier in case
4449 it got remapped to 0xF03A as if it were part of the
4450 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004452 if (msearch) {
4453 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4454 pSMB->FileName[name_len+1] = 0;
4455 pSMB->FileName[name_len+2] = '*';
4456 pSMB->FileName[name_len+3] = 0;
4457 name_len += 4; /* now the trailing null */
4458 /* null terminate just in case */
4459 pSMB->FileName[name_len] = 0;
4460 pSMB->FileName[name_len+1] = 0;
4461 name_len += 2;
4462 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 } else { /* BB add check for overrun of SMB buf BB */
4464 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004466 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467 free buffer exit; BB */
4468 strncpy(pSMB->FileName, searchName, name_len);
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] = '*';
4472 pSMB->FileName[name_len+2] = 0;
4473 name_len += 3;
4474 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 }
4476
4477 params = 12 + name_len /* includes null */ ;
4478 pSMB->TotalDataCount = 0; /* no EAs */
4479 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004480 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 pSMB->MaxSetupCount = 0;
4482 pSMB->Reserved = 0;
4483 pSMB->Flags = 0;
4484 pSMB->Timeout = 0;
4485 pSMB->Reserved2 = 0;
4486 byte_count = params + 1 /* pad */ ;
4487 pSMB->TotalParameterCount = cpu_to_le16(params);
4488 pSMB->ParameterCount = pSMB->TotalParameterCount;
4489 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004490 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4491 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 pSMB->DataCount = 0;
4493 pSMB->DataOffset = 0;
4494 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4495 pSMB->Reserved3 = 0;
4496 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4497 pSMB->SearchAttributes =
4498 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4499 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004500 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004501 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4503
4504 /* BB what should we set StorageType to? Does it matter? BB */
4505 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004506 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507 pSMB->ByteCount = cpu_to_le16(byte_count);
4508
4509 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4510 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004511 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512
Steve French88274812006-03-09 22:21:45 +00004513 if (rc) {/* BB add logic to retry regular search if Unix search
4514 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004516 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004517
Steve French88274812006-03-09 22:21:45 +00004518 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519
4520 /* BB eventually could optimize out free and realloc of buf */
4521 /* for this case */
4522 if (rc == -EAGAIN)
4523 goto findFirstRetry;
4524 } else { /* decode response */
4525 /* BB remember to free buffer if error BB */
4526 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004527 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004528 unsigned int lnoff;
4529
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004531 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532 else
Steve French4b18f2a2008-04-29 00:06:05 +00004533 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534
4535 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004536 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004537 psrch_inf->srch_entries_start =
4538 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4541 le16_to_cpu(pSMBr->t2.ParameterOffset));
4542
Steve French790fe572007-07-07 19:25:05 +00004543 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004544 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545 else
Steve French4b18f2a2008-04-29 00:06:05 +00004546 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547
Steve French50c2f752007-07-13 00:33:32 +00004548 psrch_inf->entries_in_buffer =
4549 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004550 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004552 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004553 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004554 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004555 psrch_inf->last_entry = NULL;
4556 return rc;
4557 }
4558
Steve French0752f152008-10-07 20:03:33 +00004559 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004560 lnoff;
4561
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004562 if (pnetfid)
4563 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564 } else {
4565 cifs_buf_release(pSMB);
4566 }
4567 }
4568
4569 return rc;
4570}
4571
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004572int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4573 __u16 searchHandle, __u16 search_flags,
4574 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575{
4576 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4577 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004578 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004579 char *response_data;
4580 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004581 int bytes_returned;
4582 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004583 __u16 params, byte_count;
4584
Joe Perchesf96637b2013-05-04 22:12:25 -05004585 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586
Steve French4b18f2a2008-04-29 00:06:05 +00004587 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588 return -ENOENT;
4589
4590 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4591 (void **) &pSMBr);
4592 if (rc)
4593 return rc;
4594
Steve French50c2f752007-07-13 00:33:32 +00004595 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596 byte_count = 0;
4597 pSMB->TotalDataCount = 0; /* no EAs */
4598 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004599 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600 pSMB->MaxSetupCount = 0;
4601 pSMB->Reserved = 0;
4602 pSMB->Flags = 0;
4603 pSMB->Timeout = 0;
4604 pSMB->Reserved2 = 0;
4605 pSMB->ParameterOffset = cpu_to_le16(
4606 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4607 pSMB->DataCount = 0;
4608 pSMB->DataOffset = 0;
4609 pSMB->SetupCount = 1;
4610 pSMB->Reserved3 = 0;
4611 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4612 pSMB->SearchHandle = searchHandle; /* always kept as le */
4613 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004614 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4616 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004617 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618
4619 name_len = psrch_inf->resume_name_len;
4620 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004621 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004622 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4623 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004624 /* 14 byte parm len above enough for 2 byte null terminator */
4625 pSMB->ResumeFileName[name_len] = 0;
4626 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627 } else {
4628 rc = -EINVAL;
4629 goto FNext2_err_exit;
4630 }
4631 byte_count = params + 1 /* pad */ ;
4632 pSMB->TotalParameterCount = cpu_to_le16(params);
4633 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004634 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004636
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4638 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004639 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640 if (rc) {
4641 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004642 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004643 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004644 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004646 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647 } else { /* decode response */
4648 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004649
Steve French790fe572007-07-07 19:25:05 +00004650 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004651 unsigned int lnoff;
4652
Linus Torvalds1da177e2005-04-16 15:20:36 -07004653 /* BB fixme add lock for file (srch_info) struct here */
4654 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004655 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004656 else
Steve French4b18f2a2008-04-29 00:06:05 +00004657 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004658 response_data = (char *) &pSMBr->hdr.Protocol +
4659 le16_to_cpu(pSMBr->t2.ParameterOffset);
4660 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4661 response_data = (char *)&pSMBr->hdr.Protocol +
4662 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004663 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004664 cifs_small_buf_release(
4665 psrch_inf->ntwrk_buf_start);
4666 else
4667 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668 psrch_inf->srch_entries_start = response_data;
4669 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004670 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004671 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004672 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004673 else
Steve French4b18f2a2008-04-29 00:06:05 +00004674 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004675 psrch_inf->entries_in_buffer =
4676 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677 psrch_inf->index_of_last_entry +=
4678 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004679 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004680 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004681 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004682 psrch_inf->last_entry = NULL;
4683 return rc;
4684 } else
4685 psrch_inf->last_entry =
4686 psrch_inf->srch_entries_start + lnoff;
4687
Joe Perchesf96637b2013-05-04 22:12:25 -05004688/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4689 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690
4691 /* BB fixme add unlock here */
4692 }
4693
4694 }
4695
4696 /* BB On error, should we leave previous search buf (and count and
4697 last entry fields) intact or free the previous one? */
4698
4699 /* Note: On -EAGAIN error only caller can retry on handle based calls
4700 since file handle passed in no longer valid */
4701FNext2_err_exit:
4702 if (rc != 0)
4703 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004704 return rc;
4705}
4706
4707int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004708CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004709 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004710{
4711 int rc = 0;
4712 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713
Joe Perchesf96637b2013-05-04 22:12:25 -05004714 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4716
4717 /* no sense returning error if session restarted
4718 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004719 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720 return 0;
4721 if (rc)
4722 return rc;
4723
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724 pSMB->FileID = searchHandle;
4725 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004726 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004727 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00004728 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004729 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004730
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004731 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732
4733 /* Since session is dead, search handle closed on server already */
4734 if (rc == -EAGAIN)
4735 rc = 0;
4736
4737 return rc;
4738}
4739
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004741CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004742 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004743 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744{
4745 int rc = 0;
4746 TRANSACTION2_QPI_REQ *pSMB = NULL;
4747 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4748 int name_len, bytes_returned;
4749 __u16 params, byte_count;
4750
Joe Perchesf96637b2013-05-04 22:12:25 -05004751 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004752 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004753 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754
4755GetInodeNumberRetry:
4756 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004757 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758 if (rc)
4759 return rc;
4760
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4762 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004763 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004764 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004765 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766 name_len++; /* trailing null */
4767 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004768 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004769 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004771 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772 }
4773
4774 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4775 pSMB->TotalDataCount = 0;
4776 pSMB->MaxParameterCount = cpu_to_le16(2);
4777 /* BB find exact max data count below from sess structure BB */
4778 pSMB->MaxDataCount = cpu_to_le16(4000);
4779 pSMB->MaxSetupCount = 0;
4780 pSMB->Reserved = 0;
4781 pSMB->Flags = 0;
4782 pSMB->Timeout = 0;
4783 pSMB->Reserved2 = 0;
4784 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004785 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786 pSMB->DataCount = 0;
4787 pSMB->DataOffset = 0;
4788 pSMB->SetupCount = 1;
4789 pSMB->Reserved3 = 0;
4790 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4791 byte_count = params + 1 /* pad */ ;
4792 pSMB->TotalParameterCount = cpu_to_le16(params);
4793 pSMB->ParameterCount = pSMB->TotalParameterCount;
4794 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4795 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004796 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 pSMB->ByteCount = cpu_to_le16(byte_count);
4798
4799 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4800 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4801 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004802 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803 } else {
4804 /* decode response */
4805 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004807 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808 /* If rc should we check for EOPNOSUPP and
4809 disable the srvino flag? or in caller? */
4810 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004811 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4813 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004814 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004816 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004817 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818 rc = -EIO;
4819 goto GetInodeNumOut;
4820 }
4821 pfinfo = (struct file_internal_info *)
4822 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004823 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824 }
4825 }
4826GetInodeNumOut:
4827 cifs_buf_release(pSMB);
4828 if (rc == -EAGAIN)
4829 goto GetInodeNumberRetry;
4830 return rc;
4831}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832
4833int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004834CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004835 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004836 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004837 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838{
4839/* TRANS2_GET_DFS_REFERRAL */
4840 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4841 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004842 int rc = 0;
4843 int bytes_returned;
4844 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004846 *num_of_nodes = 0;
4847 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004848
Joe Perchesf96637b2013-05-04 22:12:25 -05004849 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004850 if (ses == NULL || ses->tcon_ipc == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004851 return -ENODEV;
Aurelien Aptelb327a712018-01-24 13:46:10 +01004852
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853getDFSRetry:
Aurelien Aptelb327a712018-01-24 13:46:10 +01004854 rc = smb_init(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855 (void **) &pSMBr);
4856 if (rc)
4857 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004858
4859 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004860 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004861 pSMB->hdr.Mid = get_next_mid(ses->server);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004862 pSMB->hdr.Tid = ses->tcon_ipc->tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004864 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004866 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004867 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868
4869 if (ses->capabilities & CAP_UNICODE) {
4870 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4871 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004872 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004873 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004874 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875 name_len++; /* trailing null */
4876 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004877 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004878 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004880 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881 }
4882
Dan Carpenter65c3b202015-04-30 17:30:24 +03004883 if (ses->server->sign)
Jeff Layton38d77c52013-05-26 07:01:00 -04004884 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00004885
Steve French50c2f752007-07-13 00:33:32 +00004886 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004887
Linus Torvalds1da177e2005-04-16 15:20:36 -07004888 params = 2 /* level */ + name_len /*includes null */ ;
4889 pSMB->TotalDataCount = 0;
4890 pSMB->DataCount = 0;
4891 pSMB->DataOffset = 0;
4892 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004893 /* BB find exact max SMB PDU from sess structure BB */
4894 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004895 pSMB->MaxSetupCount = 0;
4896 pSMB->Reserved = 0;
4897 pSMB->Flags = 0;
4898 pSMB->Timeout = 0;
4899 pSMB->Reserved2 = 0;
4900 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004901 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004902 pSMB->SetupCount = 1;
4903 pSMB->Reserved3 = 0;
4904 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4905 byte_count = params + 3 /* pad */ ;
4906 pSMB->ParameterCount = cpu_to_le16(params);
4907 pSMB->TotalParameterCount = pSMB->ParameterCount;
4908 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004909 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910 pSMB->ByteCount = cpu_to_le16(byte_count);
4911
4912 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4913 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4914 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004915 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004916 goto GetDFSRefExit;
4917 }
4918 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004920 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004921 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004922 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004923 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004924 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004925
Joe Perchesf96637b2013-05-04 22:12:25 -05004926 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4927 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004928
4929 /* parse returned result into more usable form */
Aurelien Aptel4ecce922017-02-13 16:03:47 +01004930 rc = parse_dfs_referrals(&pSMBr->dfs_data,
4931 le16_to_cpu(pSMBr->t2.DataCount),
4932 num_of_nodes, target_nodes, nls_codepage,
4933 remap, search_name,
Steve French284316d2017-03-02 15:42:48 -06004934 (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0);
Igor Mammedovfec45852008-05-16 13:06:30 +04004935
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004937 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004938
4939 if (rc == -EAGAIN)
4940 goto getDFSRetry;
4941
4942 return rc;
4943}
4944
Steve French20962432005-09-21 22:05:57 -07004945/* Query File System Info such as free space to old servers such as Win 9x */
4946int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004947SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4948 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004949{
4950/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4951 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4952 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4953 FILE_SYSTEM_ALLOC_INFO *response_data;
4954 int rc = 0;
4955 int bytes_returned = 0;
4956 __u16 params, byte_count;
4957
Joe Perchesf96637b2013-05-04 22:12:25 -05004958 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004959oldQFSInfoRetry:
4960 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4961 (void **) &pSMBr);
4962 if (rc)
4963 return rc;
Steve French20962432005-09-21 22:05:57 -07004964
4965 params = 2; /* level */
4966 pSMB->TotalDataCount = 0;
4967 pSMB->MaxParameterCount = cpu_to_le16(2);
4968 pSMB->MaxDataCount = cpu_to_le16(1000);
4969 pSMB->MaxSetupCount = 0;
4970 pSMB->Reserved = 0;
4971 pSMB->Flags = 0;
4972 pSMB->Timeout = 0;
4973 pSMB->Reserved2 = 0;
4974 byte_count = params + 1 /* pad */ ;
4975 pSMB->TotalParameterCount = cpu_to_le16(params);
4976 pSMB->ParameterCount = pSMB->TotalParameterCount;
4977 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4978 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4979 pSMB->DataCount = 0;
4980 pSMB->DataOffset = 0;
4981 pSMB->SetupCount = 1;
4982 pSMB->Reserved3 = 0;
4983 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4984 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004985 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004986 pSMB->ByteCount = cpu_to_le16(byte_count);
4987
4988 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4989 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4990 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004991 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07004992 } else { /* decode response */
4993 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4994
Jeff Layton820a8032011-05-04 08:05:26 -04004995 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004996 rc = -EIO; /* bad smb */
4997 else {
4998 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05004999 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04005000 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07005001
Steve French50c2f752007-07-13 00:33:32 +00005002 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07005003 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5004 FSData->f_bsize =
5005 le16_to_cpu(response_data->BytesPerSector) *
5006 le32_to_cpu(response_data->
5007 SectorsPerAllocationUnit);
5008 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00005009 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07005010 FSData->f_bfree = FSData->f_bavail =
5011 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005012 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5013 (unsigned long long)FSData->f_blocks,
5014 (unsigned long long)FSData->f_bfree,
5015 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07005016 }
5017 }
5018 cifs_buf_release(pSMB);
5019
5020 if (rc == -EAGAIN)
5021 goto oldQFSInfoRetry;
5022
5023 return rc;
5024}
5025
Linus Torvalds1da177e2005-04-16 15:20:36 -07005026int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005027CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5028 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005029{
5030/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5031 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5032 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5033 FILE_SYSTEM_INFO *response_data;
5034 int rc = 0;
5035 int bytes_returned = 0;
5036 __u16 params, byte_count;
5037
Joe Perchesf96637b2013-05-04 22:12:25 -05005038 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005039QFSInfoRetry:
5040 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5041 (void **) &pSMBr);
5042 if (rc)
5043 return rc;
5044
5045 params = 2; /* level */
5046 pSMB->TotalDataCount = 0;
5047 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005048 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005049 pSMB->MaxSetupCount = 0;
5050 pSMB->Reserved = 0;
5051 pSMB->Flags = 0;
5052 pSMB->Timeout = 0;
5053 pSMB->Reserved2 = 0;
5054 byte_count = params + 1 /* pad */ ;
5055 pSMB->TotalParameterCount = cpu_to_le16(params);
5056 pSMB->ParameterCount = pSMB->TotalParameterCount;
5057 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005058 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059 pSMB->DataCount = 0;
5060 pSMB->DataOffset = 0;
5061 pSMB->SetupCount = 1;
5062 pSMB->Reserved3 = 0;
5063 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5064 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005065 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066 pSMB->ByteCount = cpu_to_le16(byte_count);
5067
5068 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5069 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5070 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005071 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005073 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005074
Jeff Layton820a8032011-05-04 08:05:26 -04005075 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005076 rc = -EIO; /* bad smb */
5077 else {
5078 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005079
5080 response_data =
5081 (FILE_SYSTEM_INFO
5082 *) (((char *) &pSMBr->hdr.Protocol) +
5083 data_offset);
5084 FSData->f_bsize =
5085 le32_to_cpu(response_data->BytesPerSector) *
5086 le32_to_cpu(response_data->
5087 SectorsPerAllocationUnit);
5088 FSData->f_blocks =
5089 le64_to_cpu(response_data->TotalAllocationUnits);
5090 FSData->f_bfree = FSData->f_bavail =
5091 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005092 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5093 (unsigned long long)FSData->f_blocks,
5094 (unsigned long long)FSData->f_bfree,
5095 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096 }
5097 }
5098 cifs_buf_release(pSMB);
5099
5100 if (rc == -EAGAIN)
5101 goto QFSInfoRetry;
5102
5103 return rc;
5104}
5105
5106int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005107CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108{
5109/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5110 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5111 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5112 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5113 int rc = 0;
5114 int bytes_returned = 0;
5115 __u16 params, byte_count;
5116
Joe Perchesf96637b2013-05-04 22:12:25 -05005117 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005118QFSAttributeRetry:
5119 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5120 (void **) &pSMBr);
5121 if (rc)
5122 return rc;
5123
5124 params = 2; /* level */
5125 pSMB->TotalDataCount = 0;
5126 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005127 /* BB find exact max SMB PDU from sess structure BB */
5128 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129 pSMB->MaxSetupCount = 0;
5130 pSMB->Reserved = 0;
5131 pSMB->Flags = 0;
5132 pSMB->Timeout = 0;
5133 pSMB->Reserved2 = 0;
5134 byte_count = params + 1 /* pad */ ;
5135 pSMB->TotalParameterCount = cpu_to_le16(params);
5136 pSMB->ParameterCount = pSMB->TotalParameterCount;
5137 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005138 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005139 pSMB->DataCount = 0;
5140 pSMB->DataOffset = 0;
5141 pSMB->SetupCount = 1;
5142 pSMB->Reserved3 = 0;
5143 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5144 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005145 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146 pSMB->ByteCount = cpu_to_le16(byte_count);
5147
5148 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5149 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5150 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005151 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152 } else { /* decode response */
5153 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5154
Jeff Layton820a8032011-05-04 08:05:26 -04005155 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005156 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157 rc = -EIO; /* bad smb */
5158 } else {
5159 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5160 response_data =
5161 (FILE_SYSTEM_ATTRIBUTE_INFO
5162 *) (((char *) &pSMBr->hdr.Protocol) +
5163 data_offset);
5164 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005165 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005166 }
5167 }
5168 cifs_buf_release(pSMB);
5169
5170 if (rc == -EAGAIN)
5171 goto QFSAttributeRetry;
5172
5173 return rc;
5174}
5175
5176int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005177CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178{
5179/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5180 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5181 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5182 FILE_SYSTEM_DEVICE_INFO *response_data;
5183 int rc = 0;
5184 int bytes_returned = 0;
5185 __u16 params, byte_count;
5186
Joe Perchesf96637b2013-05-04 22:12:25 -05005187 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005188QFSDeviceRetry:
5189 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5190 (void **) &pSMBr);
5191 if (rc)
5192 return rc;
5193
5194 params = 2; /* level */
5195 pSMB->TotalDataCount = 0;
5196 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005197 /* BB find exact max SMB PDU from sess structure BB */
5198 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 pSMB->MaxSetupCount = 0;
5200 pSMB->Reserved = 0;
5201 pSMB->Flags = 0;
5202 pSMB->Timeout = 0;
5203 pSMB->Reserved2 = 0;
5204 byte_count = params + 1 /* pad */ ;
5205 pSMB->TotalParameterCount = cpu_to_le16(params);
5206 pSMB->ParameterCount = pSMB->TotalParameterCount;
5207 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005208 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005209
5210 pSMB->DataCount = 0;
5211 pSMB->DataOffset = 0;
5212 pSMB->SetupCount = 1;
5213 pSMB->Reserved3 = 0;
5214 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5215 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005216 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217 pSMB->ByteCount = cpu_to_le16(byte_count);
5218
5219 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5220 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5221 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005222 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223 } else { /* decode response */
5224 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5225
Jeff Layton820a8032011-05-04 08:05:26 -04005226 if (rc || get_bcc(&pSMBr->hdr) <
5227 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228 rc = -EIO; /* bad smb */
5229 else {
5230 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5231 response_data =
Steve French737b7582005-04-28 22:41:06 -07005232 (FILE_SYSTEM_DEVICE_INFO *)
5233 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234 data_offset);
5235 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005236 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237 }
5238 }
5239 cifs_buf_release(pSMB);
5240
5241 if (rc == -EAGAIN)
5242 goto QFSDeviceRetry;
5243
5244 return rc;
5245}
5246
5247int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005248CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005249{
5250/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5251 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5252 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5253 FILE_SYSTEM_UNIX_INFO *response_data;
5254 int rc = 0;
5255 int bytes_returned = 0;
5256 __u16 params, byte_count;
5257
Joe Perchesf96637b2013-05-04 22:12:25 -05005258 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005259QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005260 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5261 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005262 if (rc)
5263 return rc;
5264
5265 params = 2; /* level */
5266 pSMB->TotalDataCount = 0;
5267 pSMB->DataCount = 0;
5268 pSMB->DataOffset = 0;
5269 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005270 /* BB find exact max SMB PDU from sess structure BB */
5271 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005272 pSMB->MaxSetupCount = 0;
5273 pSMB->Reserved = 0;
5274 pSMB->Flags = 0;
5275 pSMB->Timeout = 0;
5276 pSMB->Reserved2 = 0;
5277 byte_count = params + 1 /* pad */ ;
5278 pSMB->ParameterCount = cpu_to_le16(params);
5279 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005280 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5281 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005282 pSMB->SetupCount = 1;
5283 pSMB->Reserved3 = 0;
5284 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5285 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005286 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005287 pSMB->ByteCount = cpu_to_le16(byte_count);
5288
5289 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5290 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5291 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005292 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005293 } else { /* decode response */
5294 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5295
Jeff Layton820a8032011-05-04 08:05:26 -04005296 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005297 rc = -EIO; /* bad smb */
5298 } else {
5299 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5300 response_data =
5301 (FILE_SYSTEM_UNIX_INFO
5302 *) (((char *) &pSMBr->hdr.Protocol) +
5303 data_offset);
5304 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005305 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005306 }
5307 }
5308 cifs_buf_release(pSMB);
5309
5310 if (rc == -EAGAIN)
5311 goto QFSUnixRetry;
5312
5313
5314 return rc;
5315}
5316
Jeremy Allisonac670552005-06-22 17:26:35 -07005317int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005318CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005319{
5320/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5321 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5322 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5323 int rc = 0;
5324 int bytes_returned = 0;
5325 __u16 params, param_offset, offset, byte_count;
5326
Joe Perchesf96637b2013-05-04 22:12:25 -05005327 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005328SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005329 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005330 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5331 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005332 if (rc)
5333 return rc;
5334
5335 params = 4; /* 2 bytes zero followed by info level. */
5336 pSMB->MaxSetupCount = 0;
5337 pSMB->Reserved = 0;
5338 pSMB->Flags = 0;
5339 pSMB->Timeout = 0;
5340 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005341 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5342 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005343 offset = param_offset + params;
5344
5345 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005346 /* BB find exact max SMB PDU from sess structure BB */
5347 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005348 pSMB->SetupCount = 1;
5349 pSMB->Reserved3 = 0;
5350 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5351 byte_count = 1 /* pad */ + params + 12;
5352
5353 pSMB->DataCount = cpu_to_le16(12);
5354 pSMB->ParameterCount = cpu_to_le16(params);
5355 pSMB->TotalDataCount = pSMB->DataCount;
5356 pSMB->TotalParameterCount = pSMB->ParameterCount;
5357 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5358 pSMB->DataOffset = cpu_to_le16(offset);
5359
5360 /* Params. */
5361 pSMB->FileNum = 0;
5362 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5363
5364 /* Data. */
5365 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5366 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5367 pSMB->ClientUnixCap = cpu_to_le64(cap);
5368
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005369 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005370 pSMB->ByteCount = cpu_to_le16(byte_count);
5371
5372 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5373 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5374 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005375 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005376 } else { /* decode response */
5377 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005378 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005379 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005380 }
5381 cifs_buf_release(pSMB);
5382
5383 if (rc == -EAGAIN)
5384 goto SETFSUnixRetry;
5385
5386 return rc;
5387}
5388
5389
Linus Torvalds1da177e2005-04-16 15:20:36 -07005390
5391int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005392CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005393 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005394{
5395/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5396 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5397 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5398 FILE_SYSTEM_POSIX_INFO *response_data;
5399 int rc = 0;
5400 int bytes_returned = 0;
5401 __u16 params, byte_count;
5402
Joe Perchesf96637b2013-05-04 22:12:25 -05005403 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404QFSPosixRetry:
5405 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5406 (void **) &pSMBr);
5407 if (rc)
5408 return rc;
5409
5410 params = 2; /* level */
5411 pSMB->TotalDataCount = 0;
5412 pSMB->DataCount = 0;
5413 pSMB->DataOffset = 0;
5414 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005415 /* BB find exact max SMB PDU from sess structure BB */
5416 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005417 pSMB->MaxSetupCount = 0;
5418 pSMB->Reserved = 0;
5419 pSMB->Flags = 0;
5420 pSMB->Timeout = 0;
5421 pSMB->Reserved2 = 0;
5422 byte_count = params + 1 /* pad */ ;
5423 pSMB->ParameterCount = cpu_to_le16(params);
5424 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005425 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5426 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005427 pSMB->SetupCount = 1;
5428 pSMB->Reserved3 = 0;
5429 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5430 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005431 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432 pSMB->ByteCount = cpu_to_le16(byte_count);
5433
5434 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5435 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5436 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005437 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438 } else { /* decode response */
5439 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5440
Jeff Layton820a8032011-05-04 08:05:26 -04005441 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005442 rc = -EIO; /* bad smb */
5443 } else {
5444 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5445 response_data =
5446 (FILE_SYSTEM_POSIX_INFO
5447 *) (((char *) &pSMBr->hdr.Protocol) +
5448 data_offset);
5449 FSData->f_bsize =
5450 le32_to_cpu(response_data->BlockSize);
5451 FSData->f_blocks =
5452 le64_to_cpu(response_data->TotalBlocks);
5453 FSData->f_bfree =
5454 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005455 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456 FSData->f_bavail = FSData->f_bfree;
5457 } else {
5458 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005459 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005460 }
Steve French790fe572007-07-07 19:25:05 +00005461 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005462 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005463 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005464 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005465 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005466 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467 }
5468 }
5469 cifs_buf_release(pSMB);
5470
5471 if (rc == -EAGAIN)
5472 goto QFSPosixRetry;
5473
5474 return rc;
5475}
5476
5477
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005478/*
5479 * We can not use write of zero bytes trick to set file size due to need for
5480 * large file support. Also note that this SetPathInfo is preferred to
5481 * SetFileInfo based method in next routine which is only needed to work around
5482 * a sharing violation bugin Samba which this routine can run into.
5483 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005484int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005485CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005486 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5487 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488{
5489 struct smb_com_transaction2_spi_req *pSMB = NULL;
5490 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5491 struct file_end_of_file_info *parm_data;
5492 int name_len;
5493 int rc = 0;
5494 int bytes_returned = 0;
Steve French2baa2682014-09-27 02:19:01 -05005495 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005496
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497 __u16 params, byte_count, data_count, param_offset, offset;
5498
Joe Perchesf96637b2013-05-04 22:12:25 -05005499 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500SetEOFRetry:
5501 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5502 (void **) &pSMBr);
5503 if (rc)
5504 return rc;
5505
5506 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5507 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005508 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5509 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005510 name_len++; /* trailing null */
5511 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005512 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005513 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005515 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516 }
5517 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005518 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005519 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005520 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005521 pSMB->MaxSetupCount = 0;
5522 pSMB->Reserved = 0;
5523 pSMB->Flags = 0;
5524 pSMB->Timeout = 0;
5525 pSMB->Reserved2 = 0;
5526 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005527 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005529 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005530 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5531 pSMB->InformationLevel =
5532 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5533 else
5534 pSMB->InformationLevel =
5535 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5536 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005537 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5538 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005539 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005540 else
5541 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005542 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005543 }
5544
5545 parm_data =
5546 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5547 offset);
5548 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5549 pSMB->DataOffset = cpu_to_le16(offset);
5550 pSMB->SetupCount = 1;
5551 pSMB->Reserved3 = 0;
5552 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5553 byte_count = 3 /* pad */ + params + data_count;
5554 pSMB->DataCount = cpu_to_le16(data_count);
5555 pSMB->TotalDataCount = pSMB->DataCount;
5556 pSMB->ParameterCount = cpu_to_le16(params);
5557 pSMB->TotalParameterCount = pSMB->ParameterCount;
5558 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005559 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005560 parm_data->FileSize = cpu_to_le64(size);
5561 pSMB->ByteCount = cpu_to_le16(byte_count);
5562 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5563 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005564 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005565 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566
5567 cifs_buf_release(pSMB);
5568
5569 if (rc == -EAGAIN)
5570 goto SetEOFRetry;
5571
5572 return rc;
5573}
5574
5575int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005576CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5577 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578{
5579 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005580 struct file_end_of_file_info *parm_data;
5581 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582 __u16 params, param_offset, offset, byte_count, count;
5583
Joe Perchesf96637b2013-05-04 22:12:25 -05005584 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5585 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005586 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5587
Linus Torvalds1da177e2005-04-16 15:20:36 -07005588 if (rc)
5589 return rc;
5590
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005591 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5592 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005593
Linus Torvalds1da177e2005-04-16 15:20:36 -07005594 params = 6;
5595 pSMB->MaxSetupCount = 0;
5596 pSMB->Reserved = 0;
5597 pSMB->Flags = 0;
5598 pSMB->Timeout = 0;
5599 pSMB->Reserved2 = 0;
5600 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5601 offset = param_offset + params;
5602
Linus Torvalds1da177e2005-04-16 15:20:36 -07005603 count = sizeof(struct file_end_of_file_info);
5604 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005605 /* BB find exact max SMB PDU from sess structure BB */
5606 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005607 pSMB->SetupCount = 1;
5608 pSMB->Reserved3 = 0;
5609 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5610 byte_count = 3 /* pad */ + params + count;
5611 pSMB->DataCount = cpu_to_le16(count);
5612 pSMB->ParameterCount = cpu_to_le16(params);
5613 pSMB->TotalDataCount = pSMB->DataCount;
5614 pSMB->TotalParameterCount = pSMB->ParameterCount;
5615 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5616 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005617 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5618 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005619 pSMB->DataOffset = cpu_to_le16(offset);
5620 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005621 pSMB->Fid = cfile->fid.netfid;
5622 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5624 pSMB->InformationLevel =
5625 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5626 else
5627 pSMB->InformationLevel =
5628 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005629 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005630 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5631 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005632 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633 else
5634 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005635 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005636 }
5637 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005638 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005639 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005640 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005641 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005642 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005643 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5644 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645 }
5646
Steve French50c2f752007-07-13 00:33:32 +00005647 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005648 since file handle passed in no longer valid */
5649
5650 return rc;
5651}
5652
Steve French50c2f752007-07-13 00:33:32 +00005653/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005654 an open handle, rather than by pathname - this is awkward due to
5655 potential access conflicts on the open, but it is unavoidable for these
5656 old servers since the only other choice is to go from 100 nanosecond DCE
5657 time and resort to the original setpathinfo level which takes the ancient
5658 DOS time format with 2 second granularity */
5659int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005660CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005661 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005662{
5663 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005664 char *data_offset;
5665 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005666 __u16 params, param_offset, offset, byte_count, count;
5667
Joe Perchesf96637b2013-05-04 22:12:25 -05005668 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005669 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5670
Linus Torvalds1da177e2005-04-16 15:20:36 -07005671 if (rc)
5672 return rc;
5673
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005674 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5675 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005676
Linus Torvalds1da177e2005-04-16 15:20:36 -07005677 params = 6;
5678 pSMB->MaxSetupCount = 0;
5679 pSMB->Reserved = 0;
5680 pSMB->Flags = 0;
5681 pSMB->Timeout = 0;
5682 pSMB->Reserved2 = 0;
5683 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5684 offset = param_offset + params;
5685
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005686 data_offset = (char *)pSMB +
5687 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688
Steve French26f57362007-08-30 22:09:15 +00005689 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005690 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005691 /* BB find max SMB PDU from sess */
5692 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005693 pSMB->SetupCount = 1;
5694 pSMB->Reserved3 = 0;
5695 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5696 byte_count = 3 /* pad */ + params + count;
5697 pSMB->DataCount = cpu_to_le16(count);
5698 pSMB->ParameterCount = cpu_to_le16(params);
5699 pSMB->TotalDataCount = pSMB->DataCount;
5700 pSMB->TotalParameterCount = pSMB->ParameterCount;
5701 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5702 pSMB->DataOffset = cpu_to_le16(offset);
5703 pSMB->Fid = fid;
5704 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5705 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5706 else
5707 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5708 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005709 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005710 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005711 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005712 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005713 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00005714 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005715 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5716 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005717
Steve French50c2f752007-07-13 00:33:32 +00005718 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005719 since file handle passed in no longer valid */
5720
5721 return rc;
5722}
5723
Jeff Layton6d22f092008-09-23 11:48:35 -04005724int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005725CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005726 bool delete_file, __u16 fid, __u32 pid_of_opener)
5727{
5728 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5729 char *data_offset;
5730 int rc = 0;
5731 __u16 params, param_offset, offset, byte_count, count;
5732
Joe Perchesf96637b2013-05-04 22:12:25 -05005733 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005734 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5735
5736 if (rc)
5737 return rc;
5738
5739 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5740 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5741
5742 params = 6;
5743 pSMB->MaxSetupCount = 0;
5744 pSMB->Reserved = 0;
5745 pSMB->Flags = 0;
5746 pSMB->Timeout = 0;
5747 pSMB->Reserved2 = 0;
5748 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5749 offset = param_offset + params;
5750
5751 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5752
5753 count = 1;
5754 pSMB->MaxParameterCount = cpu_to_le16(2);
5755 /* BB find max SMB PDU from sess */
5756 pSMB->MaxDataCount = cpu_to_le16(1000);
5757 pSMB->SetupCount = 1;
5758 pSMB->Reserved3 = 0;
5759 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5760 byte_count = 3 /* pad */ + params + count;
5761 pSMB->DataCount = cpu_to_le16(count);
5762 pSMB->ParameterCount = cpu_to_le16(params);
5763 pSMB->TotalDataCount = pSMB->DataCount;
5764 pSMB->TotalParameterCount = pSMB->ParameterCount;
5765 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5766 pSMB->DataOffset = cpu_to_le16(offset);
5767 pSMB->Fid = fid;
5768 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5769 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005770 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005771 pSMB->ByteCount = cpu_to_le16(byte_count);
5772 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005773 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005774 cifs_small_buf_release(pSMB);
Jeff Layton6d22f092008-09-23 11:48:35 -04005775 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005776 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005777
5778 return rc;
5779}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005780
5781int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005782CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005783 const char *fileName, const FILE_BASIC_INFO *data,
5784 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005785{
5786 TRANSACTION2_SPI_REQ *pSMB = NULL;
5787 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5788 int name_len;
5789 int rc = 0;
5790 int bytes_returned = 0;
5791 char *data_offset;
5792 __u16 params, param_offset, offset, byte_count, count;
5793
Joe Perchesf96637b2013-05-04 22:12:25 -05005794 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005795
5796SetTimesRetry:
5797 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5798 (void **) &pSMBr);
5799 if (rc)
5800 return rc;
5801
5802 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5803 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005804 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5805 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005806 name_len++; /* trailing null */
5807 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005808 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005809 name_len = strnlen(fileName, PATH_MAX);
5810 name_len++; /* trailing null */
5811 strncpy(pSMB->FileName, fileName, name_len);
5812 }
5813
5814 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005815 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005816 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005817 /* BB find max SMB PDU from sess structure BB */
5818 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005819 pSMB->MaxSetupCount = 0;
5820 pSMB->Reserved = 0;
5821 pSMB->Flags = 0;
5822 pSMB->Timeout = 0;
5823 pSMB->Reserved2 = 0;
5824 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005825 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005826 offset = param_offset + params;
5827 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5828 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5829 pSMB->DataOffset = cpu_to_le16(offset);
5830 pSMB->SetupCount = 1;
5831 pSMB->Reserved3 = 0;
5832 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5833 byte_count = 3 /* pad */ + params + count;
5834
5835 pSMB->DataCount = cpu_to_le16(count);
5836 pSMB->ParameterCount = cpu_to_le16(params);
5837 pSMB->TotalDataCount = pSMB->DataCount;
5838 pSMB->TotalParameterCount = pSMB->ParameterCount;
5839 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5840 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5841 else
5842 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5843 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005844 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005845 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005846 pSMB->ByteCount = cpu_to_le16(byte_count);
5847 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5848 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005849 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005850 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851
5852 cifs_buf_release(pSMB);
5853
5854 if (rc == -EAGAIN)
5855 goto SetTimesRetry;
5856
5857 return rc;
5858}
5859
5860/* Can not be used to set time stamps yet (due to old DOS time format) */
5861/* Can be used to set attributes */
5862#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5863 handling it anyway and NT4 was what we thought it would be needed for
5864 Do not delete it until we prove whether needed for Win9x though */
5865int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005866CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005867 __u16 dos_attrs, const struct nls_table *nls_codepage)
5868{
5869 SETATTR_REQ *pSMB = NULL;
5870 SETATTR_RSP *pSMBr = NULL;
5871 int rc = 0;
5872 int bytes_returned;
5873 int name_len;
5874
Joe Perchesf96637b2013-05-04 22:12:25 -05005875 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005876
5877SetAttrLgcyRetry:
5878 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5879 (void **) &pSMBr);
5880 if (rc)
5881 return rc;
5882
5883 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5884 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005885 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5886 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005887 name_len++; /* trailing null */
5888 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005889 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005890 name_len = strnlen(fileName, PATH_MAX);
5891 name_len++; /* trailing null */
5892 strncpy(pSMB->fileName, fileName, name_len);
5893 }
5894 pSMB->attr = cpu_to_le16(dos_attrs);
5895 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005896 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005897 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5898 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5899 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005900 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005901 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005902
5903 cifs_buf_release(pSMB);
5904
5905 if (rc == -EAGAIN)
5906 goto SetAttrLgcyRetry;
5907
5908 return rc;
5909}
5910#endif /* temporarily unneeded SetAttr legacy function */
5911
Jeff Layton654cf142009-07-09 20:02:49 -04005912static void
5913cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5914 const struct cifs_unix_set_info_args *args)
5915{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005916 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005917 u64 mode = args->mode;
5918
Eric W. Biederman49418b22013-02-06 00:57:56 -08005919 if (uid_valid(args->uid))
5920 uid = from_kuid(&init_user_ns, args->uid);
5921 if (gid_valid(args->gid))
5922 gid = from_kgid(&init_user_ns, args->gid);
5923
Jeff Layton654cf142009-07-09 20:02:49 -04005924 /*
5925 * Samba server ignores set of file size to zero due to bugs in some
5926 * older clients, but we should be precise - we use SetFileSize to
5927 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005928 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005929 * zero instead of -1 here
5930 */
5931 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5932 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5933 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5934 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5935 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005936 data_offset->Uid = cpu_to_le64(uid);
5937 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005938 /* better to leave device as zero when it is */
5939 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5940 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5941 data_offset->Permissions = cpu_to_le64(mode);
5942
5943 if (S_ISREG(mode))
5944 data_offset->Type = cpu_to_le32(UNIX_FILE);
5945 else if (S_ISDIR(mode))
5946 data_offset->Type = cpu_to_le32(UNIX_DIR);
5947 else if (S_ISLNK(mode))
5948 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5949 else if (S_ISCHR(mode))
5950 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5951 else if (S_ISBLK(mode))
5952 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5953 else if (S_ISFIFO(mode))
5954 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5955 else if (S_ISSOCK(mode))
5956 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5957}
5958
Linus Torvalds1da177e2005-04-16 15:20:36 -07005959int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005960CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005961 const struct cifs_unix_set_info_args *args,
5962 u16 fid, u32 pid_of_opener)
5963{
5964 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005965 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005966 int rc = 0;
5967 u16 params, param_offset, offset, byte_count, count;
5968
Joe Perchesf96637b2013-05-04 22:12:25 -05005969 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005970 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5971
5972 if (rc)
5973 return rc;
5974
5975 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5976 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5977
5978 params = 6;
5979 pSMB->MaxSetupCount = 0;
5980 pSMB->Reserved = 0;
5981 pSMB->Flags = 0;
5982 pSMB->Timeout = 0;
5983 pSMB->Reserved2 = 0;
5984 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5985 offset = param_offset + params;
5986
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005987 data_offset = (char *)pSMB +
5988 offsetof(struct smb_hdr, Protocol) + offset;
5989
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005990 count = sizeof(FILE_UNIX_BASIC_INFO);
5991
5992 pSMB->MaxParameterCount = cpu_to_le16(2);
5993 /* BB find max SMB PDU from sess */
5994 pSMB->MaxDataCount = cpu_to_le16(1000);
5995 pSMB->SetupCount = 1;
5996 pSMB->Reserved3 = 0;
5997 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5998 byte_count = 3 /* pad */ + params + count;
5999 pSMB->DataCount = cpu_to_le16(count);
6000 pSMB->ParameterCount = cpu_to_le16(params);
6001 pSMB->TotalDataCount = pSMB->DataCount;
6002 pSMB->TotalParameterCount = pSMB->ParameterCount;
6003 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6004 pSMB->DataOffset = cpu_to_le16(offset);
6005 pSMB->Fid = fid;
6006 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6007 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006008 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006009 pSMB->ByteCount = cpu_to_le16(byte_count);
6010
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006011 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006012
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04006013 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07006014 cifs_small_buf_release(pSMB);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006015 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006016 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
6017 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006018
6019 /* Note: On -EAGAIN error only caller can retry on handle based calls
6020 since file handle passed in no longer valid */
6021
6022 return rc;
6023}
6024
6025int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006026CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006027 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006028 const struct cifs_unix_set_info_args *args,
6029 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006030{
6031 TRANSACTION2_SPI_REQ *pSMB = NULL;
6032 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6033 int name_len;
6034 int rc = 0;
6035 int bytes_returned = 0;
6036 FILE_UNIX_BASIC_INFO *data_offset;
6037 __u16 params, param_offset, offset, count, byte_count;
6038
Joe Perchesf96637b2013-05-04 22:12:25 -05006039 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006040setPermsRetry:
6041 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6042 (void **) &pSMBr);
6043 if (rc)
6044 return rc;
6045
6046 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6047 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006048 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06006049 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006050 name_len++; /* trailing null */
6051 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07006052 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006053 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006054 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006055 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006056 }
6057
6058 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006059 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006060 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006061 /* BB find max SMB PDU from sess structure BB */
6062 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006063 pSMB->MaxSetupCount = 0;
6064 pSMB->Reserved = 0;
6065 pSMB->Flags = 0;
6066 pSMB->Timeout = 0;
6067 pSMB->Reserved2 = 0;
6068 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006069 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070 offset = param_offset + params;
6071 data_offset =
6072 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6073 offset);
6074 memset(data_offset, 0, count);
6075 pSMB->DataOffset = cpu_to_le16(offset);
6076 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6077 pSMB->SetupCount = 1;
6078 pSMB->Reserved3 = 0;
6079 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6080 byte_count = 3 /* pad */ + params + count;
6081 pSMB->ParameterCount = cpu_to_le16(params);
6082 pSMB->DataCount = cpu_to_le16(count);
6083 pSMB->TotalParameterCount = pSMB->ParameterCount;
6084 pSMB->TotalDataCount = pSMB->DataCount;
6085 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6086 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006087 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006088
Jeff Layton654cf142009-07-09 20:02:49 -04006089 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006090
6091 pSMB->ByteCount = cpu_to_le16(byte_count);
6092 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6093 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006094 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006095 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006096
Steve French0d817bc2008-05-22 02:02:03 +00006097 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006098 if (rc == -EAGAIN)
6099 goto setPermsRetry;
6100 return rc;
6101}
6102
Linus Torvalds1da177e2005-04-16 15:20:36 -07006103#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006104/*
6105 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6106 * function used by listxattr and getxattr type calls. When ea_name is set,
6107 * it looks for that attribute name and stuffs that value into the EAData
6108 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6109 * buffer. In both cases, the return value is either the length of the
6110 * resulting data or a negative error code. If EAData is a NULL pointer then
6111 * the data isn't copied to it, but the length is returned.
6112 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006113ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006114CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006115 const unsigned char *searchName, const unsigned char *ea_name,
6116 char *EAData, size_t buf_size,
Steve French67b4c882017-05-12 20:59:10 -05006117 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006118{
6119 /* BB assumes one setup word */
6120 TRANSACTION2_QPI_REQ *pSMB = NULL;
6121 TRANSACTION2_QPI_RSP *pSMBr = NULL;
Steve French67b4c882017-05-12 20:59:10 -05006122 int remap = cifs_remap(cifs_sb);
6123 struct nls_table *nls_codepage = cifs_sb->local_nls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006124 int rc = 0;
6125 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006126 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006127 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006128 struct fea *temp_fea;
6129 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006130 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006131 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006132 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006133
Joe Perchesf96637b2013-05-04 22:12:25 -05006134 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006135QAllEAsRetry:
6136 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6137 (void **) &pSMBr);
6138 if (rc)
6139 return rc;
6140
6141 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006142 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006143 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6144 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006145 list_len++; /* trailing null */
6146 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006147 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006148 list_len = strnlen(searchName, PATH_MAX);
6149 list_len++; /* trailing null */
6150 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006151 }
6152
Jeff Layton6e462b92010-02-10 16:18:26 -05006153 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006154 pSMB->TotalDataCount = 0;
6155 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006156 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006157 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006158 pSMB->MaxSetupCount = 0;
6159 pSMB->Reserved = 0;
6160 pSMB->Flags = 0;
6161 pSMB->Timeout = 0;
6162 pSMB->Reserved2 = 0;
6163 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006164 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006165 pSMB->DataCount = 0;
6166 pSMB->DataOffset = 0;
6167 pSMB->SetupCount = 1;
6168 pSMB->Reserved3 = 0;
6169 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6170 byte_count = params + 1 /* pad */ ;
6171 pSMB->TotalParameterCount = cpu_to_le16(params);
6172 pSMB->ParameterCount = pSMB->TotalParameterCount;
6173 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6174 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006175 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006176 pSMB->ByteCount = cpu_to_le16(byte_count);
6177
6178 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6179 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6180 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006181 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006182 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006183 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006184
6185
6186 /* BB also check enough total bytes returned */
6187 /* BB we need to improve the validity checking
6188 of these trans2 responses */
6189
6190 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006191 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006192 rc = -EIO; /* bad smb */
6193 goto QAllEAsOut;
6194 }
6195
6196 /* check that length of list is not more than bcc */
6197 /* check that each entry does not go beyond length
6198 of list */
6199 /* check that each element of each entry does not
6200 go beyond end of list */
6201 /* validate_trans2_offsets() */
6202 /* BB check if start of smb + data_offset > &bcc+ bcc */
6203
6204 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6205 ea_response_data = (struct fealist *)
6206 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6207
Jeff Layton6e462b92010-02-10 16:18:26 -05006208 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006209 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006210 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006211 cifs_dbg(FYI, "empty EA list returned from server\n");
Steve French60977fc2014-03-25 19:46:36 -05006212 /* didn't find the named attribute */
6213 if (ea_name)
6214 rc = -ENODATA;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006215 goto QAllEAsOut;
6216 }
6217
Jeff Layton0cd126b2010-02-10 16:18:26 -05006218 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006219 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006220 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006221 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006222 rc = -EIO;
6223 goto QAllEAsOut;
6224 }
6225
Jeff Laytonf0d38682010-02-10 16:18:26 -05006226 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006227 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006228 temp_fea = ea_response_data->list;
6229 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006230 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006231 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006232 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006233
Jeff Layton6e462b92010-02-10 16:18:26 -05006234 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006235 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006236 /* make sure we can read name_len and value_len */
6237 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006238 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006239 rc = -EIO;
6240 goto QAllEAsOut;
6241 }
6242
6243 name_len = temp_fea->name_len;
6244 value_len = le16_to_cpu(temp_fea->value_len);
6245 list_len -= name_len + 1 + value_len;
6246 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006247 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006248 rc = -EIO;
6249 goto QAllEAsOut;
6250 }
6251
Jeff Layton31c05192010-02-10 16:18:26 -05006252 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006253 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006254 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006255 temp_ptr += name_len + 1;
6256 rc = value_len;
6257 if (buf_size == 0)
6258 goto QAllEAsOut;
6259 if ((size_t)value_len > buf_size) {
6260 rc = -ERANGE;
6261 goto QAllEAsOut;
6262 }
6263 memcpy(EAData, temp_ptr, value_len);
6264 goto QAllEAsOut;
6265 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006266 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006267 /* account for prefix user. and trailing null */
6268 rc += (5 + 1 + name_len);
6269 if (rc < (int) buf_size) {
6270 memcpy(EAData, "user.", 5);
6271 EAData += 5;
6272 memcpy(EAData, temp_ptr, name_len);
6273 EAData += name_len;
6274 /* null terminate name */
6275 *EAData = 0;
6276 ++EAData;
6277 } else if (buf_size == 0) {
6278 /* skip copy - calc size only */
6279 } else {
6280 /* stop before overrun buffer */
6281 rc = -ERANGE;
6282 break;
6283 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006284 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006285 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006286 temp_fea = (struct fea *)temp_ptr;
6287 }
6288
Jeff Layton31c05192010-02-10 16:18:26 -05006289 /* didn't find the named attribute */
6290 if (ea_name)
6291 rc = -ENODATA;
6292
Jeff Laytonf0d38682010-02-10 16:18:26 -05006293QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006294 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006295 if (rc == -EAGAIN)
6296 goto QAllEAsRetry;
6297
6298 return (ssize_t)rc;
6299}
6300
Linus Torvalds1da177e2005-04-16 15:20:36 -07006301int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006302CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6303 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006304 const __u16 ea_value_len, const struct nls_table *nls_codepage,
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006305 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006306{
6307 struct smb_com_transaction2_spi_req *pSMB = NULL;
6308 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6309 struct fealist *parm_data;
6310 int name_len;
6311 int rc = 0;
6312 int bytes_returned = 0;
6313 __u16 params, param_offset, byte_count, offset, count;
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006314 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006315
Joe Perchesf96637b2013-05-04 22:12:25 -05006316 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006317SetEARetry:
6318 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6319 (void **) &pSMBr);
6320 if (rc)
6321 return rc;
6322
6323 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6324 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006325 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6326 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006327 name_len++; /* trailing null */
6328 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006329 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006330 name_len = strnlen(fileName, PATH_MAX);
6331 name_len++; /* trailing null */
6332 strncpy(pSMB->FileName, fileName, name_len);
6333 }
6334
6335 params = 6 + name_len;
6336
6337 /* done calculating parms using name_len of file name,
6338 now use name_len to calculate length of ea name
6339 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006340 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006341 name_len = 0;
6342 else
Steve French50c2f752007-07-13 00:33:32 +00006343 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006344
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006345 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006346 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006347 /* BB find max SMB PDU from sess */
6348 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006349 pSMB->MaxSetupCount = 0;
6350 pSMB->Reserved = 0;
6351 pSMB->Flags = 0;
6352 pSMB->Timeout = 0;
6353 pSMB->Reserved2 = 0;
6354 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006355 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006356 offset = param_offset + params;
6357 pSMB->InformationLevel =
6358 cpu_to_le16(SMB_SET_FILE_EA);
6359
Arnd Bergmannade7db92018-02-02 16:48:47 +01006360 parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006361 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6362 pSMB->DataOffset = cpu_to_le16(offset);
6363 pSMB->SetupCount = 1;
6364 pSMB->Reserved3 = 0;
6365 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6366 byte_count = 3 /* pad */ + params + count;
6367 pSMB->DataCount = cpu_to_le16(count);
6368 parm_data->list_len = cpu_to_le32(count);
6369 parm_data->list[0].EA_flags = 0;
6370 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006371 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006372 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006373 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006374 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006375 parm_data->list[0].name[name_len] = 0;
6376 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6377 /* caller ensures that ea_value_len is less than 64K but
6378 we need to ensure that it fits within the smb */
6379
Steve French50c2f752007-07-13 00:33:32 +00006380 /*BB add length check to see if it would fit in
6381 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006382 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6383 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006384 memcpy(parm_data->list[0].name+name_len+1,
6385 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006386
6387 pSMB->TotalDataCount = pSMB->DataCount;
6388 pSMB->ParameterCount = cpu_to_le16(params);
6389 pSMB->TotalParameterCount = pSMB->ParameterCount;
6390 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006391 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006392 pSMB->ByteCount = cpu_to_le16(byte_count);
6393 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6394 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006395 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006396 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006397
6398 cifs_buf_release(pSMB);
6399
6400 if (rc == -EAGAIN)
6401 goto SetEARetry;
6402
6403 return rc;
6404}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006405#endif
Steve French0eff0e22011-02-24 05:39:23 +00006406
6407#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6408/*
6409 * Years ago the kernel added a "dnotify" function for Samba server,
6410 * to allow network clients (such as Windows) to display updated
6411 * lists of files in directory listings automatically when
6412 * files are added by one user when another user has the
6413 * same directory open on their desktop. The Linux cifs kernel
6414 * client hooked into the kernel side of this interface for
6415 * the same reason, but ironically when the VFS moved from
6416 * "dnotify" to "inotify" it became harder to plug in Linux
6417 * network file system clients (the most obvious use case
6418 * for notify interfaces is when multiple users can update
6419 * the contents of the same directory - exactly what network
6420 * file systems can do) although the server (Samba) could
6421 * still use it. For the short term we leave the worker
6422 * function ifdeffed out (below) until inotify is fixed
6423 * in the VFS to make it easier to plug in network file
6424 * system clients. If inotify turns out to be permanently
6425 * incompatible for network fs clients, we could instead simply
6426 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6427 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006428int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006429 const int notify_subdirs, const __u16 netfid,
6430 __u32 filter, struct file *pfile, int multishot,
6431 const struct nls_table *nls_codepage)
6432{
6433 int rc = 0;
6434 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6435 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6436 struct dir_notify_req *dnotify_req;
6437 int bytes_returned;
6438
Joe Perchesf96637b2013-05-04 22:12:25 -05006439 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006440 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6441 (void **) &pSMBr);
6442 if (rc)
6443 return rc;
6444
6445 pSMB->TotalParameterCount = 0 ;
6446 pSMB->TotalDataCount = 0;
6447 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006448 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006449 pSMB->MaxSetupCount = 4;
6450 pSMB->Reserved = 0;
6451 pSMB->ParameterOffset = 0;
6452 pSMB->DataCount = 0;
6453 pSMB->DataOffset = 0;
6454 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6455 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6456 pSMB->ParameterCount = pSMB->TotalParameterCount;
6457 if (notify_subdirs)
6458 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6459 pSMB->Reserved2 = 0;
6460 pSMB->CompletionFilter = cpu_to_le32(filter);
6461 pSMB->Fid = netfid; /* file handle always le */
6462 pSMB->ByteCount = 0;
6463
6464 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6465 (struct smb_hdr *)pSMBr, &bytes_returned,
6466 CIFS_ASYNC_OP);
6467 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006468 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006469 } else {
6470 /* Add file to outstanding requests */
6471 /* BB change to kmem cache alloc */
6472 dnotify_req = kmalloc(
6473 sizeof(struct dir_notify_req),
6474 GFP_KERNEL);
6475 if (dnotify_req) {
6476 dnotify_req->Pid = pSMB->hdr.Pid;
6477 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6478 dnotify_req->Mid = pSMB->hdr.Mid;
6479 dnotify_req->Tid = pSMB->hdr.Tid;
6480 dnotify_req->Uid = pSMB->hdr.Uid;
6481 dnotify_req->netfid = netfid;
6482 dnotify_req->pfile = pfile;
6483 dnotify_req->filter = filter;
6484 dnotify_req->multishot = multishot;
6485 spin_lock(&GlobalMid_Lock);
6486 list_add_tail(&dnotify_req->lhead,
6487 &GlobalDnotifyReqList);
6488 spin_unlock(&GlobalMid_Lock);
6489 } else
6490 rc = -ENOMEM;
6491 }
6492 cifs_buf_release(pSMB);
6493 return rc;
6494}
6495#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */