blob: 5aca336642c0acd7cafa9d6a7ef3f80b6cfb0ab9 [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
Long Li8e7360f2018-05-30 12:47:56 -07001955 kvfree(wdata->pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001956 kfree(wdata);
1957}
1958
1959/*
1960 * Write failed with a retryable error. Resend the write request. It's also
1961 * possible that the page was redirtied so re-clean the page.
1962 */
1963static void
1964cifs_writev_requeue(struct cifs_writedata *wdata)
1965{
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001966 int i, rc = 0;
David Howells2b0143b2015-03-17 22:25:59 +00001967 struct inode *inode = d_inode(wdata->cfile->dentry);
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001968 struct TCP_Server_Info *server;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001969 unsigned int rest_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001970
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001971 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1972 i = 0;
1973 rest_len = wdata->bytes;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001974 do {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001975 struct cifs_writedata *wdata2;
1976 unsigned int j, nr_pages, wsize, tailsz, cur_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001977
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001978 wsize = server->ops->wp_retry_size(inode);
1979 if (wsize < rest_len) {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001980 nr_pages = wsize / PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001981 if (!nr_pages) {
1982 rc = -ENOTSUPP;
1983 break;
1984 }
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001985 cur_len = nr_pages * PAGE_SIZE;
1986 tailsz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001987 } else {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001988 nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001989 cur_len = rest_len;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001990 tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE;
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001991 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001992
1993 wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
1994 if (!wdata2) {
1995 rc = -ENOMEM;
1996 break;
1997 }
1998
1999 for (j = 0; j < nr_pages; j++) {
2000 wdata2->pages[j] = wdata->pages[i + j];
2001 lock_page(wdata2->pages[j]);
2002 clear_page_dirty_for_io(wdata2->pages[j]);
2003 }
2004
2005 wdata2->sync_mode = wdata->sync_mode;
2006 wdata2->nr_pages = nr_pages;
2007 wdata2->offset = page_offset(wdata2->pages[0]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002008 wdata2->pagesz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002009 wdata2->tailsz = tailsz;
2010 wdata2->bytes = cur_len;
2011
2012 wdata2->cfile = find_writable_file(CIFS_I(inode), false);
2013 if (!wdata2->cfile) {
2014 cifs_dbg(VFS, "No writable handles for inode\n");
2015 rc = -EBADF;
2016 break;
2017 }
2018 wdata2->pid = wdata2->cfile->pid;
2019 rc = server->ops->async_writev(wdata2, cifs_writedata_release);
2020
2021 for (j = 0; j < nr_pages; j++) {
2022 unlock_page(wdata2->pages[j]);
2023 if (rc != 0 && rc != -EAGAIN) {
2024 SetPageError(wdata2->pages[j]);
2025 end_page_writeback(wdata2->pages[j]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002026 put_page(wdata2->pages[j]);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002027 }
2028 }
2029
2030 if (rc) {
2031 kref_put(&wdata2->refcount, cifs_writedata_release);
2032 if (rc == -EAGAIN)
2033 continue;
2034 break;
2035 }
2036
2037 rest_len -= cur_len;
2038 i += nr_pages;
2039 } while (i < wdata->nr_pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002040
2041 mapping_set_error(inode->i_mapping, rc);
2042 kref_put(&wdata->refcount, cifs_writedata_release);
2043}
2044
Jeff Laytonc2e87642012-03-23 14:40:55 -04002045void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002046cifs_writev_complete(struct work_struct *work)
2047{
2048 struct cifs_writedata *wdata = container_of(work,
2049 struct cifs_writedata, work);
David Howells2b0143b2015-03-17 22:25:59 +00002050 struct inode *inode = d_inode(wdata->cfile->dentry);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002051 int i = 0;
2052
2053 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04002054 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002055 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04002056 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002057 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2058 wdata->bytes);
2059 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2060 return cifs_writev_requeue(wdata);
2061
2062 for (i = 0; i < wdata->nr_pages; i++) {
2063 struct page *page = wdata->pages[i];
2064 if (wdata->result == -EAGAIN)
2065 __set_page_dirty_nobuffers(page);
2066 else if (wdata->result < 0)
2067 SetPageError(page);
2068 end_page_writeback(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002069 put_page(page);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002070 }
2071 if (wdata->result != -EAGAIN)
2072 mapping_set_error(inode->i_mapping, wdata->result);
2073 kref_put(&wdata->refcount, cifs_writedata_release);
2074}
2075
2076struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04002077cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002078{
Long Li8e7360f2018-05-30 12:47:56 -07002079 struct page **pages =
2080 kzalloc(sizeof(struct page *) * nr_pages, GFP_NOFS);
2081 if (pages)
2082 return cifs_writedata_direct_alloc(pages, complete);
2083
2084 return NULL;
2085}
2086
2087struct cifs_writedata *
2088cifs_writedata_direct_alloc(struct page **pages, work_func_t complete)
2089{
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002090 struct cifs_writedata *wdata;
2091
Long Li8e7360f2018-05-30 12:47:56 -07002092 wdata = kzalloc(sizeof(*wdata), GFP_NOFS);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002093 if (wdata != NULL) {
Long Li8e7360f2018-05-30 12:47:56 -07002094 wdata->pages = pages;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002095 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04002096 INIT_LIST_HEAD(&wdata->list);
2097 init_completion(&wdata->done);
2098 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002099 }
2100 return wdata;
2101}
2102
2103/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002104 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002105 * workqueue completion task.
2106 */
2107static void
2108cifs_writev_callback(struct mid_q_entry *mid)
2109{
2110 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002111 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002112 unsigned int written;
2113 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2114
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002115 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002116 case MID_RESPONSE_RECEIVED:
2117 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2118 if (wdata->result != 0)
2119 break;
2120
2121 written = le16_to_cpu(smb->CountHigh);
2122 written <<= 16;
2123 written += le16_to_cpu(smb->Count);
2124 /*
2125 * Mask off high 16 bits when bytes written as returned
2126 * by the server is greater than bytes requested by the
2127 * client. OS/2 servers are known to set incorrect
2128 * CountHigh values.
2129 */
2130 if (written > wdata->bytes)
2131 written &= 0xFFFF;
2132
2133 if (written < wdata->bytes)
2134 wdata->result = -ENOSPC;
2135 else
2136 wdata->bytes = written;
2137 break;
2138 case MID_REQUEST_SUBMITTED:
2139 case MID_RETRY_NEEDED:
2140 wdata->result = -EAGAIN;
2141 break;
2142 default:
2143 wdata->result = -EIO;
2144 break;
2145 }
2146
Jeff Laytonda472fc2012-03-23 14:40:53 -04002147 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002148 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002149 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002150}
2151
2152/* cifs_async_writev - send an async write, and set up mid to handle result */
2153int
Steve French4a5c80d2014-02-07 20:45:12 -06002154cifs_async_writev(struct cifs_writedata *wdata,
2155 void (*release)(struct kref *kref))
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002156{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002157 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002158 WRITE_REQ *smb = NULL;
2159 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002160 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002161 struct kvec iov[2];
Jeff Laytonfec344e2012-09-18 16:20:35 -07002162 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002163
2164 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2165 wct = 14;
2166 } else {
2167 wct = 12;
2168 if (wdata->offset >> 32 > 0) {
2169 /* can not handle big offset for old srv */
2170 return -EIO;
2171 }
2172 }
2173
2174 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2175 if (rc)
2176 goto async_writev_out;
2177
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002178 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2179 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002180
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002181 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002182 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002183 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2184 if (wct == 14)
2185 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2186 smb->Reserved = 0xFFFFFFFF;
2187 smb->WriteMode = 0;
2188 smb->Remaining = 0;
2189
2190 smb->DataOffset =
2191 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2192
2193 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002194 iov[0].iov_len = 4;
2195 iov[0].iov_base = smb;
2196 iov[1].iov_len = get_rfc1002_length(smb) + 1;
2197 iov[1].iov_base = (char *)smb + 4;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002198
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002199 rqst.rq_iov = iov;
2200 rqst.rq_nvec = 2;
Jeff Laytoneddb0792012-09-18 16:20:35 -07002201 rqst.rq_pages = wdata->pages;
2202 rqst.rq_npages = wdata->nr_pages;
2203 rqst.rq_pagesz = wdata->pagesz;
2204 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002205
Joe Perchesf96637b2013-05-04 22:12:25 -05002206 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2207 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002208
2209 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2210 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2211
2212 if (wct == 14) {
2213 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2214 put_bcc(wdata->bytes + 1, &smb->hdr);
2215 } else {
2216 /* wct == 12 */
2217 struct smb_com_writex_req *smbw =
2218 (struct smb_com_writex_req *)smb;
2219 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2220 put_bcc(wdata->bytes + 5, &smbw->hdr);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002221 iov[1].iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002222 }
2223
2224 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002225 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -08002226 cifs_writev_callback, NULL, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002227
2228 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002229 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002230 else
Steve French4a5c80d2014-02-07 20:45:12 -06002231 kref_put(&wdata->refcount, release);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002232
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002233async_writev_out:
2234 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002235 return rc;
2236}
2237
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002238int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002239CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002240 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241{
2242 int rc = -EACCES;
2243 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002244 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002245 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002246 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002247 __u32 pid = io_parms->pid;
2248 __u16 netfid = io_parms->netfid;
2249 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002250 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002251 unsigned int count = io_parms->length;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002252 struct kvec rsp_iov;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002254 *nbytes = 0;
2255
Joe Perchesf96637b2013-05-04 22:12:25 -05002256 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002257
Steve French4c3130e2008-12-09 00:28:16 +00002258 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002259 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002260 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002261 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002262 if ((offset >> 32) > 0) {
2263 /* can not handle big offset for old srv */
2264 return -EIO;
2265 }
2266 }
Steve French8cc64c62005-10-03 13:49:43 -07002267 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 if (rc)
2269 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002270
2271 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2272 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2273
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 /* tcon and ses pointer are checked in smb_init */
2275 if (tcon->ses->server == NULL)
2276 return -ECONNABORTED;
2277
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002278 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 pSMB->Fid = netfid;
2280 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002281 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002282 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 pSMB->Reserved = 0xFFFFFFFF;
2284 pSMB->WriteMode = 0;
2285 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002286
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002288 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289
Steve French3e844692005-10-03 13:37:24 -07002290 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2291 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002292 /* header + 1 byte pad */
2293 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002294 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002295 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002296 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002297 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002298 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002299 pSMB->ByteCount = cpu_to_le16(count + 1);
2300 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002301 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002302 (struct smb_com_writex_req *)pSMB;
2303 pSMBW->ByteCount = cpu_to_le16(count + 5);
2304 }
Steve French3e844692005-10-03 13:37:24 -07002305 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002306 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002307 iov[0].iov_len = smb_hdr_len + 4;
2308 else /* wct == 12 pad bigger by four bytes */
2309 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002310
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002311 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
2312 &rsp_iov);
2313 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002314 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002316 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002317 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002318 /* presumably this can not happen, but best to be safe */
2319 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002320 } else {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002321 WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002322 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2323 *nbytes = (*nbytes) << 16;
2324 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302325
2326 /*
2327 * Mask off high 16 bits when bytes written as returned by the
2328 * server is greater than bytes requested by the client. OS/2
2329 * servers are known to set incorrect CountHigh values.
2330 */
2331 if (*nbytes > count)
2332 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002333 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002335 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336
Steve French50c2f752007-07-13 00:33:32 +00002337 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 since file handle passed in no longer valid */
2339
2340 return rc;
2341}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002342
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002343int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2344 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002345 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2346{
2347 int rc = 0;
2348 LOCK_REQ *pSMB = NULL;
2349 struct kvec iov[2];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002350 struct kvec rsp_iov;
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002351 int resp_buf_type;
2352 __u16 count;
2353
Joe Perchesf96637b2013-05-04 22:12:25 -05002354 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2355 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002356
2357 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2358 if (rc)
2359 return rc;
2360
2361 pSMB->Timeout = 0;
2362 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2363 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2364 pSMB->LockType = lock_type;
2365 pSMB->AndXCommand = 0xFF; /* none */
2366 pSMB->Fid = netfid; /* netfid stays le */
2367
2368 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2369 inc_rfc1001_len(pSMB, count);
2370 pSMB->ByteCount = cpu_to_le16(count);
2371
2372 iov[0].iov_base = (char *)pSMB;
2373 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2374 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2375 iov[1].iov_base = (char *)buf;
2376 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2377
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002378 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002379 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP,
2380 &rsp_iov);
2381 cifs_small_buf_release(pSMB);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002382 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002383 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002384
2385 return rc;
2386}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002387
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002389CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002390 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002392 const __u32 numLock, const __u8 lockType,
2393 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394{
2395 int rc = 0;
2396 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002397/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002399 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 __u16 count;
2401
Joe Perchesf96637b2013-05-04 22:12:25 -05002402 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2403 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002404 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2405
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 if (rc)
2407 return rc;
2408
Steve French790fe572007-07-07 19:25:05 +00002409 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002410 /* no response expected */
2411 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002413 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002414 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2416 } else {
2417 pSMB->Timeout = 0;
2418 }
2419
2420 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2421 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2422 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002423 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 pSMB->AndXCommand = 0xFF; /* none */
2425 pSMB->Fid = smb_file_id; /* netfid stays le */
2426
Steve French790fe572007-07-07 19:25:05 +00002427 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002428 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 /* BB where to store pid high? */
2430 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2431 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2432 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2433 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2434 count = sizeof(LOCKING_ANDX_RANGE);
2435 } else {
2436 /* oplock break */
2437 count = 0;
2438 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002439 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 pSMB->ByteCount = cpu_to_le16(count);
2441
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002442 if (waitFlag)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002443 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002444 (struct smb_hdr *) pSMB, &bytes_returned);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002445 else
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002446 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002447 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002448 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002449 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002450 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451
Steve French50c2f752007-07-13 00:33:32 +00002452 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 since file handle passed in no longer valid */
2454 return rc;
2455}
2456
2457int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002458CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002459 const __u16 smb_file_id, const __u32 netpid,
2460 const loff_t start_offset, const __u64 len,
2461 struct file_lock *pLockData, const __u16 lock_type,
2462 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002463{
2464 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2465 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002466 struct cifs_posix_lock *parm_data;
2467 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002468 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002469 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002470 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002471 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002472 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002473 struct kvec rsp_iov;
Steve French08547b02006-02-28 22:39:25 +00002474
Joe Perchesf96637b2013-05-04 22:12:25 -05002475 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002476
Steve French08547b02006-02-28 22:39:25 +00002477 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2478
2479 if (rc)
2480 return rc;
2481
2482 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2483
Steve French50c2f752007-07-13 00:33:32 +00002484 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002485 pSMB->MaxSetupCount = 0;
2486 pSMB->Reserved = 0;
2487 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002488 pSMB->Reserved2 = 0;
2489 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2490 offset = param_offset + params;
2491
Steve French08547b02006-02-28 22:39:25 +00002492 count = sizeof(struct cifs_posix_lock);
2493 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002494 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002495 pSMB->SetupCount = 1;
2496 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002497 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002498 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2499 else
2500 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2501 byte_count = 3 /* pad */ + params + count;
2502 pSMB->DataCount = cpu_to_le16(count);
2503 pSMB->ParameterCount = cpu_to_le16(params);
2504 pSMB->TotalDataCount = pSMB->DataCount;
2505 pSMB->TotalParameterCount = pSMB->ParameterCount;
2506 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002507 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002508 (((char *) &pSMB->hdr.Protocol) + offset);
2509
2510 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002511 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002512 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002513 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002514 pSMB->Timeout = cpu_to_le32(-1);
2515 } else
2516 pSMB->Timeout = 0;
2517
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002518 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002519 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002520 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002521
2522 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002523 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002524 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2525 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002526 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002527 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002528 if (waitFlag) {
2529 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2530 (struct smb_hdr *) pSMBr, &bytes_returned);
2531 } else {
Steve French133672e2007-11-13 22:41:37 +00002532 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002533 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002534 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002535 &resp_buf_type, timeout, &rsp_iov);
2536 pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002537 }
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002538 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002539
Steve French08547b02006-02-28 22:39:25 +00002540 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002541 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002542 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002543 /* lock structure can be returned on get */
2544 __u16 data_offset;
2545 __u16 data_count;
2546 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002547
Jeff Layton820a8032011-05-04 08:05:26 -04002548 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002549 rc = -EIO; /* bad smb */
2550 goto plk_err_exit;
2551 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002552 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2553 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002554 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002555 rc = -EIO;
2556 goto plk_err_exit;
2557 }
2558 parm_data = (struct cifs_posix_lock *)
2559 ((char *)&pSMBr->hdr.Protocol + data_offset);
Fabian Frederickbc09d142014-12-10 15:41:15 -08002560 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002561 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002562 else {
2563 if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002564 cpu_to_le16(CIFS_RDLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002565 pLockData->fl_type = F_RDLCK;
2566 else if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002567 cpu_to_le16(CIFS_WRLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002568 pLockData->fl_type = F_WRLCK;
2569
Steve French5443d132011-03-13 05:08:25 +00002570 pLockData->fl_start = le64_to_cpu(parm_data->start);
2571 pLockData->fl_end = pLockData->fl_start +
2572 le64_to_cpu(parm_data->length) - 1;
Benjamin Coddington9d5b86a2017-07-16 10:28:22 -04002573 pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002574 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002575 }
Steve French50c2f752007-07-13 00:33:32 +00002576
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002577plk_err_exit:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002578 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French133672e2007-11-13 22:41:37 +00002579
Steve French08547b02006-02-28 22:39:25 +00002580 /* Note: On -EAGAIN error only caller can retry on handle based calls
2581 since file handle passed in no longer valid */
2582
2583 return rc;
2584}
2585
2586
2587int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002588CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589{
2590 int rc = 0;
2591 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002592 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593
2594/* do not retry on dead session on close */
2595 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002596 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 return 0;
2598 if (rc)
2599 return rc;
2600
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002602 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002604 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002605 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002606 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002608 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002610 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 }
2612 }
2613
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002615 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 rc = 0;
2617
2618 return rc;
2619}
2620
2621int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002622CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002623{
2624 int rc = 0;
2625 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002626 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002627
2628 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2629 if (rc)
2630 return rc;
2631
2632 pSMB->FileID = (__u16) smb_file_id;
2633 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002634 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002635 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002636 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002637 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002638 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002639
2640 return rc;
2641}
2642
2643int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002644CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002645 const char *from_name, const char *to_name,
2646 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647{
2648 int rc = 0;
2649 RENAME_REQ *pSMB = NULL;
2650 RENAME_RSP *pSMBr = NULL;
2651 int bytes_returned;
2652 int name_len, name_len2;
2653 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002654 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655
Joe Perchesf96637b2013-05-04 22:12:25 -05002656 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657renameRetry:
2658 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2659 (void **) &pSMBr);
2660 if (rc)
2661 return rc;
2662
2663 pSMB->BufferFormat = 0x04;
2664 pSMB->SearchAttributes =
2665 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2666 ATTR_DIRECTORY);
2667
2668 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002669 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2670 from_name, PATH_MAX,
2671 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 name_len++; /* trailing null */
2673 name_len *= 2;
2674 pSMB->OldFileName[name_len] = 0x04; /* pad */
2675 /* protocol requires ASCII signature byte on Unicode string */
2676 pSMB->OldFileName[name_len + 1] = 0x00;
2677 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002678 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002679 to_name, PATH_MAX, cifs_sb->local_nls,
2680 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2682 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002683 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002684 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002686 strncpy(pSMB->OldFileName, from_name, name_len);
2687 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 name_len2++; /* trailing null */
2689 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002690 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 name_len2++; /* trailing null */
2692 name_len2++; /* signature byte */
2693 }
2694
2695 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002696 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 pSMB->ByteCount = cpu_to_le16(count);
2698
2699 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2700 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002701 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002702 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002703 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 cifs_buf_release(pSMB);
2706
2707 if (rc == -EAGAIN)
2708 goto renameRetry;
2709
2710 return rc;
2711}
2712
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002713int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002714 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002715 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716{
2717 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2718 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002719 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 char *data_offset;
2721 char dummy_string[30];
2722 int rc = 0;
2723 int bytes_returned = 0;
2724 int len_of_str;
2725 __u16 params, param_offset, offset, count, byte_count;
2726
Joe Perchesf96637b2013-05-04 22:12:25 -05002727 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2729 (void **) &pSMBr);
2730 if (rc)
2731 return rc;
2732
2733 params = 6;
2734 pSMB->MaxSetupCount = 0;
2735 pSMB->Reserved = 0;
2736 pSMB->Flags = 0;
2737 pSMB->Timeout = 0;
2738 pSMB->Reserved2 = 0;
2739 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2740 offset = param_offset + params;
2741
2742 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2743 rename_info = (struct set_file_rename *) data_offset;
2744 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002745 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 pSMB->SetupCount = 1;
2747 pSMB->Reserved3 = 0;
2748 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2749 byte_count = 3 /* pad */ + params;
2750 pSMB->ParameterCount = cpu_to_le16(params);
2751 pSMB->TotalParameterCount = pSMB->ParameterCount;
2752 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2753 pSMB->DataOffset = cpu_to_le16(offset);
2754 /* construct random name ".cifs_tmp<inodenum><mid>" */
2755 rename_info->overwrite = cpu_to_le32(1);
2756 rename_info->root_fid = 0;
2757 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002758 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002759 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002760 len_of_str =
2761 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002762 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002764 len_of_str =
2765 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002766 target_name, PATH_MAX, nls_codepage,
2767 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 }
2769 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002770 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 byte_count += count;
2772 pSMB->DataCount = cpu_to_le16(count);
2773 pSMB->TotalDataCount = pSMB->DataCount;
2774 pSMB->Fid = netfid;
2775 pSMB->InformationLevel =
2776 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2777 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002778 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 pSMB->ByteCount = cpu_to_le16(byte_count);
2780 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002781 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002782 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002783 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002784 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2785 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002786
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 cifs_buf_release(pSMB);
2788
2789 /* Note: On -EAGAIN error only caller can retry on handle based calls
2790 since file handle passed in no longer valid */
2791
2792 return rc;
2793}
2794
2795int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002796CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2797 const char *fromName, const __u16 target_tid, const char *toName,
2798 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799{
2800 int rc = 0;
2801 COPY_REQ *pSMB = NULL;
2802 COPY_RSP *pSMBr = NULL;
2803 int bytes_returned;
2804 int name_len, name_len2;
2805 __u16 count;
2806
Joe Perchesf96637b2013-05-04 22:12:25 -05002807 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808copyRetry:
2809 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2810 (void **) &pSMBr);
2811 if (rc)
2812 return rc;
2813
2814 pSMB->BufferFormat = 0x04;
2815 pSMB->Tid2 = target_tid;
2816
2817 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2818
2819 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002820 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2821 fromName, PATH_MAX, nls_codepage,
2822 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 name_len++; /* trailing null */
2824 name_len *= 2;
2825 pSMB->OldFileName[name_len] = 0x04; /* pad */
2826 /* protocol requires ASCII signature byte on Unicode string */
2827 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002828 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002829 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2830 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2832 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002833 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 name_len = strnlen(fromName, PATH_MAX);
2835 name_len++; /* trailing null */
2836 strncpy(pSMB->OldFileName, fromName, name_len);
2837 name_len2 = strnlen(toName, PATH_MAX);
2838 name_len2++; /* trailing null */
2839 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2840 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2841 name_len2++; /* trailing null */
2842 name_len2++; /* signature byte */
2843 }
2844
2845 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002846 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 pSMB->ByteCount = cpu_to_le16(count);
2848
2849 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2850 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2851 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002852 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2853 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 }
Steve French0d817bc2008-05-22 02:02:03 +00002855 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856
2857 if (rc == -EAGAIN)
2858 goto copyRetry;
2859
2860 return rc;
2861}
2862
2863int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002864CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 const char *fromName, const char *toName,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002866 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867{
2868 TRANSACTION2_SPI_REQ *pSMB = NULL;
2869 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2870 char *data_offset;
2871 int name_len;
2872 int name_len_target;
2873 int rc = 0;
2874 int bytes_returned = 0;
2875 __u16 params, param_offset, offset, byte_count;
2876
Joe Perchesf96637b2013-05-04 22:12:25 -05002877 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878createSymLinkRetry:
2879 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2880 (void **) &pSMBr);
2881 if (rc)
2882 return rc;
2883
2884 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2885 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002886 cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
2887 /* find define for this maxpathcomponent */
2888 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889 name_len++; /* trailing null */
2890 name_len *= 2;
2891
Steve French50c2f752007-07-13 00:33:32 +00002892 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 name_len = strnlen(fromName, PATH_MAX);
2894 name_len++; /* trailing null */
2895 strncpy(pSMB->FileName, fromName, name_len);
2896 }
2897 params = 6 + name_len;
2898 pSMB->MaxSetupCount = 0;
2899 pSMB->Reserved = 0;
2900 pSMB->Flags = 0;
2901 pSMB->Timeout = 0;
2902 pSMB->Reserved2 = 0;
2903 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002904 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 offset = param_offset + params;
2906
2907 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2908 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2909 name_len_target =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002910 cifsConvertToUTF16((__le16 *) data_offset, toName,
2911 /* find define for this maxpathcomponent */
2912 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 name_len_target++; /* trailing null */
2914 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002915 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 name_len_target = strnlen(toName, PATH_MAX);
2917 name_len_target++; /* trailing null */
2918 strncpy(data_offset, toName, name_len_target);
2919 }
2920
2921 pSMB->MaxParameterCount = cpu_to_le16(2);
2922 /* BB find exact max on data count below from sess */
2923 pSMB->MaxDataCount = cpu_to_le16(1000);
2924 pSMB->SetupCount = 1;
2925 pSMB->Reserved3 = 0;
2926 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2927 byte_count = 3 /* pad */ + params + name_len_target;
2928 pSMB->DataCount = cpu_to_le16(name_len_target);
2929 pSMB->ParameterCount = cpu_to_le16(params);
2930 pSMB->TotalDataCount = pSMB->DataCount;
2931 pSMB->TotalParameterCount = pSMB->ParameterCount;
2932 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2933 pSMB->DataOffset = cpu_to_le16(offset);
2934 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2935 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002936 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 pSMB->ByteCount = cpu_to_le16(byte_count);
2938 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2939 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002940 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002941 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002942 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2943 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944
Steve French0d817bc2008-05-22 02:02:03 +00002945 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946
2947 if (rc == -EAGAIN)
2948 goto createSymLinkRetry;
2949
2950 return rc;
2951}
2952
2953int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002954CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002956 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957{
2958 TRANSACTION2_SPI_REQ *pSMB = NULL;
2959 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2960 char *data_offset;
2961 int name_len;
2962 int name_len_target;
2963 int rc = 0;
2964 int bytes_returned = 0;
2965 __u16 params, param_offset, offset, byte_count;
2966
Joe Perchesf96637b2013-05-04 22:12:25 -05002967 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968createHardLinkRetry:
2969 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2970 (void **) &pSMBr);
2971 if (rc)
2972 return rc;
2973
2974 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002975 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2976 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 name_len++; /* trailing null */
2978 name_len *= 2;
2979
Steve French50c2f752007-07-13 00:33:32 +00002980 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 name_len = strnlen(toName, PATH_MAX);
2982 name_len++; /* trailing null */
2983 strncpy(pSMB->FileName, toName, name_len);
2984 }
2985 params = 6 + name_len;
2986 pSMB->MaxSetupCount = 0;
2987 pSMB->Reserved = 0;
2988 pSMB->Flags = 0;
2989 pSMB->Timeout = 0;
2990 pSMB->Reserved2 = 0;
2991 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002992 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 offset = param_offset + params;
2994
2995 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2996 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2997 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002998 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2999 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 name_len_target++; /* trailing null */
3001 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003002 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 name_len_target = strnlen(fromName, PATH_MAX);
3004 name_len_target++; /* trailing null */
3005 strncpy(data_offset, fromName, name_len_target);
3006 }
3007
3008 pSMB->MaxParameterCount = cpu_to_le16(2);
3009 /* BB find exact max on data count below from sess*/
3010 pSMB->MaxDataCount = cpu_to_le16(1000);
3011 pSMB->SetupCount = 1;
3012 pSMB->Reserved3 = 0;
3013 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3014 byte_count = 3 /* pad */ + params + name_len_target;
3015 pSMB->ParameterCount = cpu_to_le16(params);
3016 pSMB->TotalParameterCount = pSMB->ParameterCount;
3017 pSMB->DataCount = cpu_to_le16(name_len_target);
3018 pSMB->TotalDataCount = pSMB->DataCount;
3019 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3020 pSMB->DataOffset = cpu_to_le16(offset);
3021 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
3022 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003023 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 pSMB->ByteCount = cpu_to_le16(byte_count);
3025 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3026 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003027 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003028 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003029 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
3030 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031
3032 cifs_buf_release(pSMB);
3033 if (rc == -EAGAIN)
3034 goto createHardLinkRetry;
3035
3036 return rc;
3037}
3038
3039int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003040CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07003041 const char *from_name, const char *to_name,
3042 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043{
3044 int rc = 0;
3045 NT_RENAME_REQ *pSMB = NULL;
3046 RENAME_RSP *pSMBr = NULL;
3047 int bytes_returned;
3048 int name_len, name_len2;
3049 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05003050 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051
Joe Perchesf96637b2013-05-04 22:12:25 -05003052 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053winCreateHardLinkRetry:
3054
3055 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
3056 (void **) &pSMBr);
3057 if (rc)
3058 return rc;
3059
3060 pSMB->SearchAttributes =
3061 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3062 ATTR_DIRECTORY);
3063 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3064 pSMB->ClusterCount = 0;
3065
3066 pSMB->BufferFormat = 0x04;
3067
3068 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3069 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07003070 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
3071 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 name_len++; /* trailing null */
3073 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05003074
3075 /* protocol specifies ASCII buffer format (0x04) for unicode */
3076 pSMB->OldFileName[name_len] = 0x04;
3077 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06003079 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07003080 to_name, PATH_MAX, cifs_sb->local_nls,
3081 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3083 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00003084 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003085 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003087 strncpy(pSMB->OldFileName, from_name, name_len);
3088 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 name_len2++; /* trailing null */
3090 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003091 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092 name_len2++; /* trailing null */
3093 name_len2++; /* signature byte */
3094 }
3095
3096 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003097 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098 pSMB->ByteCount = cpu_to_le16(count);
3099
3100 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3101 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003102 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003103 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003104 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003105
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106 cifs_buf_release(pSMB);
3107 if (rc == -EAGAIN)
3108 goto winCreateHardLinkRetry;
3109
3110 return rc;
3111}
3112
3113int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003114CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003115 const unsigned char *searchName, char **symlinkinfo,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003116 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117{
3118/* SMB_QUERY_FILE_UNIX_LINK */
3119 TRANSACTION2_QPI_REQ *pSMB = NULL;
3120 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3121 int rc = 0;
3122 int bytes_returned;
3123 int name_len;
3124 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003125 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126
Joe Perchesf96637b2013-05-04 22:12:25 -05003127 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128
3129querySymLinkRetry:
3130 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3131 (void **) &pSMBr);
3132 if (rc)
3133 return rc;
3134
3135 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3136 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003137 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3138 searchName, PATH_MAX, nls_codepage,
3139 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 name_len++; /* trailing null */
3141 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003142 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 name_len = strnlen(searchName, PATH_MAX);
3144 name_len++; /* trailing null */
3145 strncpy(pSMB->FileName, searchName, name_len);
3146 }
3147
3148 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3149 pSMB->TotalDataCount = 0;
3150 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003151 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152 pSMB->MaxSetupCount = 0;
3153 pSMB->Reserved = 0;
3154 pSMB->Flags = 0;
3155 pSMB->Timeout = 0;
3156 pSMB->Reserved2 = 0;
3157 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003158 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159 pSMB->DataCount = 0;
3160 pSMB->DataOffset = 0;
3161 pSMB->SetupCount = 1;
3162 pSMB->Reserved3 = 0;
3163 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3164 byte_count = params + 1 /* pad */ ;
3165 pSMB->TotalParameterCount = cpu_to_le16(params);
3166 pSMB->ParameterCount = pSMB->TotalParameterCount;
3167 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3168 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003169 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170 pSMB->ByteCount = cpu_to_le16(byte_count);
3171
3172 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3173 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3174 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003175 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 } else {
3177 /* decode response */
3178
3179 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003181 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003182 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003184 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003185 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186
Jeff Layton460b9692009-04-30 07:17:56 -04003187 data_start = ((char *) &pSMBr->hdr.Protocol) +
3188 le16_to_cpu(pSMBr->t2.DataOffset);
3189
Steve French0e0d2cf2009-05-01 05:27:32 +00003190 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3191 is_unicode = true;
3192 else
3193 is_unicode = false;
3194
Steve French737b7582005-04-28 22:41:06 -07003195 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003196 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3197 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003198 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003199 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200 }
3201 }
3202 cifs_buf_release(pSMB);
3203 if (rc == -EAGAIN)
3204 goto querySymLinkRetry;
3205 return rc;
3206}
3207
Steve Frenchc52a9552011-02-24 06:16:22 +00003208/*
3209 * Recent Windows versions now create symlinks more frequently
3210 * and they use the "reparse point" mechanism below. We can of course
3211 * do symlinks nicely to Samba and other servers which support the
3212 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3213 * "MF" symlinks optionally, but for recent Windows we really need to
3214 * reenable the code below and fix the cifs_symlink callers to handle this.
3215 * In the interim this code has been moved to its own config option so
3216 * it is not compiled in by default until callers fixed up and more tested.
3217 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003219CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3220 __u16 fid, char **symlinkinfo,
3221 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222{
3223 int rc = 0;
3224 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003225 struct smb_com_transaction_ioctl_req *pSMB;
3226 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003227 bool is_unicode;
3228 unsigned int sub_len;
3229 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003230 struct reparse_symlink_data *reparse_buf;
3231 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003232 __u32 data_offset, data_count;
3233 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003235 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3237 (void **) &pSMBr);
3238 if (rc)
3239 return rc;
3240
3241 pSMB->TotalParameterCount = 0 ;
3242 pSMB->TotalDataCount = 0;
3243 pSMB->MaxParameterCount = cpu_to_le32(2);
3244 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003245 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 pSMB->MaxSetupCount = 4;
3247 pSMB->Reserved = 0;
3248 pSMB->ParameterOffset = 0;
3249 pSMB->DataCount = 0;
3250 pSMB->DataOffset = 0;
3251 pSMB->SetupCount = 4;
3252 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3253 pSMB->ParameterCount = pSMB->TotalParameterCount;
3254 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3255 pSMB->IsFsctl = 1; /* FSCTL */
3256 pSMB->IsRootFlag = 0;
3257 pSMB->Fid = fid; /* file handle always le */
3258 pSMB->ByteCount = 0;
3259
3260 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3261 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3262 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003263 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003264 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265 }
Steve French989c7e52009-05-02 05:32:20 +00003266
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003267 data_offset = le32_to_cpu(pSMBr->DataOffset);
3268 data_count = le32_to_cpu(pSMBr->DataCount);
3269 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3270 /* BB also check enough total bytes returned */
3271 rc = -EIO; /* bad smb */
3272 goto qreparse_out;
3273 }
3274 if (!data_count || (data_count > 2048)) {
3275 rc = -EIO;
3276 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3277 goto qreparse_out;
3278 }
3279 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003280 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003281 ((char *)&pSMBr->hdr.Protocol + data_offset);
3282 if ((char *)reparse_buf >= end_of_smb) {
3283 rc = -EIO;
3284 goto qreparse_out;
3285 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003286 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3287 cifs_dbg(FYI, "NFS style reparse tag\n");
3288 posix_buf = (struct reparse_posix_data *)reparse_buf;
3289
3290 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3291 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3292 le64_to_cpu(posix_buf->InodeType));
3293 rc = -EOPNOTSUPP;
3294 goto qreparse_out;
3295 }
3296 is_unicode = true;
3297 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3298 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3299 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3300 rc = -EIO;
3301 goto qreparse_out;
3302 }
3303 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3304 sub_len, is_unicode, nls_codepage);
3305 goto qreparse_out;
3306 } else if (reparse_buf->ReparseTag !=
3307 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3308 rc = -EOPNOTSUPP;
3309 goto qreparse_out;
3310 }
3311
3312 /* Reparse tag is NTFS symlink */
3313 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3314 reparse_buf->PathBuffer;
3315 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3316 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003317 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3318 rc = -EIO;
3319 goto qreparse_out;
3320 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003321 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3322 is_unicode = true;
3323 else
3324 is_unicode = false;
3325
3326 /* BB FIXME investigate remapping reserved chars here */
3327 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3328 nls_codepage);
3329 if (!*symlinkinfo)
3330 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003332 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003334 /*
3335 * Note: On -EAGAIN error only caller can retry on handle based calls
3336 * since file handle passed in no longer valid.
3337 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338 return rc;
3339}
3340
Steve Frenchc7f508a2013-10-14 15:27:32 -05003341int
3342CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3343 __u16 fid)
3344{
3345 int rc = 0;
3346 int bytes_returned;
3347 struct smb_com_transaction_compr_ioctl_req *pSMB;
3348 struct smb_com_transaction_ioctl_rsp *pSMBr;
3349
3350 cifs_dbg(FYI, "Set compression for %u\n", fid);
3351 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3352 (void **) &pSMBr);
3353 if (rc)
3354 return rc;
3355
3356 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3357
3358 pSMB->TotalParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003359 pSMB->TotalDataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003360 pSMB->MaxParameterCount = 0;
3361 pSMB->MaxDataCount = 0;
3362 pSMB->MaxSetupCount = 4;
3363 pSMB->Reserved = 0;
3364 pSMB->ParameterOffset = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003365 pSMB->DataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003366 pSMB->DataOffset =
3367 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3368 compression_state) - 4); /* 84 */
3369 pSMB->SetupCount = 4;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003370 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003371 pSMB->ParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003372 pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003373 pSMB->IsFsctl = 1; /* FSCTL */
3374 pSMB->IsRootFlag = 0;
3375 pSMB->Fid = fid; /* file handle always le */
3376 /* 3 byte pad, followed by 2 byte compress state */
Fabian Frederickbc09d142014-12-10 15:41:15 -08003377 pSMB->ByteCount = cpu_to_le16(5);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003378 inc_rfc1001_len(pSMB, 5);
3379
3380 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3381 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3382 if (rc)
3383 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3384
3385 cifs_buf_release(pSMB);
3386
3387 /*
3388 * Note: On -EAGAIN error only caller can retry on handle based calls
3389 * since file handle passed in no longer valid.
3390 */
3391 return rc;
3392}
3393
3394
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395#ifdef CONFIG_CIFS_POSIX
3396
3397/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003398static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
Steve French50c2f752007-07-13 00:33:32 +00003399 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400{
3401 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003402 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3403 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3404 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003405/*
3406 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3407 ace->e_perm, ace->e_tag, ace->e_id);
3408*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409
3410 return;
3411}
3412
3413/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003414static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3415 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416{
3417 int size = 0;
3418 int i;
3419 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003420 struct cifs_posix_ace *pACE;
3421 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003422 struct posix_acl_xattr_header *local_acl = (void *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423
3424 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3425 return -EOPNOTSUPP;
3426
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003427 if (acl_type == ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 count = le16_to_cpu(cifs_acl->access_entry_count);
3429 pACE = &cifs_acl->ace_array[0];
3430 size = sizeof(struct cifs_posix_acl);
3431 size += sizeof(struct cifs_posix_ace) * count;
3432 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003433 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003434 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3435 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436 return -EINVAL;
3437 }
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003438 } else if (acl_type == ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 count = le16_to_cpu(cifs_acl->access_entry_count);
3440 size = sizeof(struct cifs_posix_acl);
3441 size += sizeof(struct cifs_posix_ace) * count;
3442/* skip past access ACEs to get to default ACEs */
3443 pACE = &cifs_acl->ace_array[count];
3444 count = le16_to_cpu(cifs_acl->default_entry_count);
3445 size += sizeof(struct cifs_posix_ace) * count;
3446 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003447 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 return -EINVAL;
3449 } else {
3450 /* illegal type */
3451 return -EINVAL;
3452 }
3453
3454 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003455 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003456 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003457 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458 return -ERANGE;
3459 } else /* buffer big enough */ {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003460 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
3461
Steve Frenchff7feac2005-11-15 16:45:16 -08003462 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003463 for (i = 0; i < count ; i++) {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003464 cifs_convert_ace(&ace[i], pACE);
Steve French50c2f752007-07-13 00:33:32 +00003465 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 }
3467 }
3468 return size;
3469}
3470
Steve French50c2f752007-07-13 00:33:32 +00003471static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003472 const struct posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473{
3474 __u16 rc = 0; /* 0 = ACL converted ok */
3475
Steve Frenchff7feac2005-11-15 16:45:16 -08003476 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3477 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003479 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480 /* Probably no need to le convert -1 on any arch but can not hurt */
3481 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003482 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003483 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003484/*
3485 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3486 ace->e_perm, ace->e_tag, ace->e_id);
3487*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488 return rc;
3489}
3490
3491/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003492static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3493 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494{
3495 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003496 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003497 struct posix_acl_xattr_header *local_acl = (void *)pACL;
Eryu Guanae9ebe72016-10-24 20:46:40 +08003498 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499 int count;
3500 int i;
3501
Steve French790fe572007-07-07 19:25:05 +00003502 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 return 0;
3504
3505 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003506 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3507 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003508 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003509 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3510 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511 return 0;
3512 }
3513 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003514 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003515 cifs_acl->access_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003516 cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003517 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003518 cifs_acl->default_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003519 cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003520 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003521 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 return 0;
3523 }
Steve French50c2f752007-07-13 00:33:32 +00003524 for (i = 0; i < count; i++) {
Eryu Guanae9ebe72016-10-24 20:46:40 +08003525 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
Steve French790fe572007-07-07 19:25:05 +00003526 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527 /* ACE not converted */
3528 break;
3529 }
3530 }
Steve French790fe572007-07-07 19:25:05 +00003531 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3533 rc += sizeof(struct cifs_posix_acl);
3534 /* BB add check to make sure ACL does not overflow SMB */
3535 }
3536 return rc;
3537}
3538
3539int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003540CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003541 const unsigned char *searchName,
3542 char *acl_inf, const int buflen, const int acl_type,
3543 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544{
3545/* SMB_QUERY_POSIX_ACL */
3546 TRANSACTION2_QPI_REQ *pSMB = NULL;
3547 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3548 int rc = 0;
3549 int bytes_returned;
3550 int name_len;
3551 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003552
Joe Perchesf96637b2013-05-04 22:12:25 -05003553 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554
3555queryAclRetry:
3556 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3557 (void **) &pSMBr);
3558 if (rc)
3559 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003560
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3562 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003563 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3564 searchName, PATH_MAX, nls_codepage,
3565 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566 name_len++; /* trailing null */
3567 name_len *= 2;
3568 pSMB->FileName[name_len] = 0;
3569 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003570 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571 name_len = strnlen(searchName, PATH_MAX);
3572 name_len++; /* trailing null */
3573 strncpy(pSMB->FileName, searchName, name_len);
3574 }
3575
3576 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3577 pSMB->TotalDataCount = 0;
3578 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003579 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580 pSMB->MaxDataCount = cpu_to_le16(4000);
3581 pSMB->MaxSetupCount = 0;
3582 pSMB->Reserved = 0;
3583 pSMB->Flags = 0;
3584 pSMB->Timeout = 0;
3585 pSMB->Reserved2 = 0;
3586 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003587 offsetof(struct smb_com_transaction2_qpi_req,
3588 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 pSMB->DataCount = 0;
3590 pSMB->DataOffset = 0;
3591 pSMB->SetupCount = 1;
3592 pSMB->Reserved3 = 0;
3593 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3594 byte_count = params + 1 /* pad */ ;
3595 pSMB->TotalParameterCount = cpu_to_le16(params);
3596 pSMB->ParameterCount = pSMB->TotalParameterCount;
3597 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3598 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003599 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 pSMB->ByteCount = cpu_to_le16(byte_count);
3601
3602 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3603 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003604 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003606 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 } else {
3608 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003609
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003612 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 rc = -EIO; /* bad smb */
3614 else {
3615 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3616 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3617 rc = cifs_copy_posix_acl(acl_inf,
3618 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003619 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 }
3621 }
3622 cifs_buf_release(pSMB);
3623 if (rc == -EAGAIN)
3624 goto queryAclRetry;
3625 return rc;
3626}
3627
3628int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003629CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003630 const unsigned char *fileName,
3631 const char *local_acl, const int buflen,
3632 const int acl_type,
3633 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634{
3635 struct smb_com_transaction2_spi_req *pSMB = NULL;
3636 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3637 char *parm_data;
3638 int name_len;
3639 int rc = 0;
3640 int bytes_returned = 0;
3641 __u16 params, byte_count, data_count, param_offset, offset;
3642
Joe Perchesf96637b2013-05-04 22:12:25 -05003643 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644setAclRetry:
3645 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003646 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647 if (rc)
3648 return rc;
3649 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3650 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003651 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3652 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653 name_len++; /* trailing null */
3654 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003655 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003656 name_len = strnlen(fileName, PATH_MAX);
3657 name_len++; /* trailing null */
3658 strncpy(pSMB->FileName, fileName, name_len);
3659 }
3660 params = 6 + name_len;
3661 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003662 /* BB find max SMB size from sess */
3663 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 pSMB->MaxSetupCount = 0;
3665 pSMB->Reserved = 0;
3666 pSMB->Flags = 0;
3667 pSMB->Timeout = 0;
3668 pSMB->Reserved2 = 0;
3669 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003670 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671 offset = param_offset + params;
3672 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3673 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3674
3675 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003676 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677
Steve French790fe572007-07-07 19:25:05 +00003678 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679 rc = -EOPNOTSUPP;
3680 goto setACLerrorExit;
3681 }
3682 pSMB->DataOffset = cpu_to_le16(offset);
3683 pSMB->SetupCount = 1;
3684 pSMB->Reserved3 = 0;
3685 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3686 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3687 byte_count = 3 /* pad */ + params + data_count;
3688 pSMB->DataCount = cpu_to_le16(data_count);
3689 pSMB->TotalDataCount = pSMB->DataCount;
3690 pSMB->ParameterCount = cpu_to_le16(params);
3691 pSMB->TotalParameterCount = pSMB->ParameterCount;
3692 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003693 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694 pSMB->ByteCount = cpu_to_le16(byte_count);
3695 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003696 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003697 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003698 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699
3700setACLerrorExit:
3701 cifs_buf_release(pSMB);
3702 if (rc == -EAGAIN)
3703 goto setAclRetry;
3704 return rc;
3705}
3706
Steve Frenchf654bac2005-04-28 22:41:04 -07003707/* BB fix tabs in this function FIXME BB */
3708int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003709CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003710 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003711{
Steve French50c2f752007-07-13 00:33:32 +00003712 int rc = 0;
3713 struct smb_t2_qfi_req *pSMB = NULL;
3714 struct smb_t2_qfi_rsp *pSMBr = NULL;
3715 int bytes_returned;
3716 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003717
Joe Perchesf96637b2013-05-04 22:12:25 -05003718 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003719 if (tcon == NULL)
3720 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003721
3722GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003723 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3724 (void **) &pSMBr);
3725 if (rc)
3726 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003727
Steve Frenchad7a2922008-02-07 23:25:02 +00003728 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003729 pSMB->t2.TotalDataCount = 0;
3730 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3731 /* BB find exact max data count below from sess structure BB */
3732 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3733 pSMB->t2.MaxSetupCount = 0;
3734 pSMB->t2.Reserved = 0;
3735 pSMB->t2.Flags = 0;
3736 pSMB->t2.Timeout = 0;
3737 pSMB->t2.Reserved2 = 0;
3738 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3739 Fid) - 4);
3740 pSMB->t2.DataCount = 0;
3741 pSMB->t2.DataOffset = 0;
3742 pSMB->t2.SetupCount = 1;
3743 pSMB->t2.Reserved3 = 0;
3744 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3745 byte_count = params + 1 /* pad */ ;
3746 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3747 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3748 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3749 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003750 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003751 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003752 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003753
Steve French790fe572007-07-07 19:25:05 +00003754 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3755 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3756 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003757 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003758 } else {
3759 /* decode response */
3760 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003761 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003762 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003763 /* If rc should we check for EOPNOSUPP and
3764 disable the srvino flag? or in caller? */
3765 rc = -EIO; /* bad smb */
3766 else {
3767 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3768 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3769 struct file_chattr_info *pfinfo;
3770 /* BB Do we need a cast or hash here ? */
3771 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003772 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003773 rc = -EIO;
3774 goto GetExtAttrOut;
3775 }
3776 pfinfo = (struct file_chattr_info *)
3777 (data_offset + (char *) &pSMBr->hdr.Protocol);
3778 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003779 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003780 }
3781 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003782GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003783 cifs_buf_release(pSMB);
3784 if (rc == -EAGAIN)
3785 goto GetExtAttrRetry;
3786 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003787}
3788
Steve Frenchf654bac2005-04-28 22:41:04 -07003789#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790
Jeff Layton79df1ba2010-12-06 12:52:08 -05003791#ifdef CONFIG_CIFS_ACL
3792/*
3793 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3794 * all NT TRANSACTS that we init here have total parm and data under about 400
3795 * bytes (to fit in small cifs buffer size), which is the case so far, it
3796 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3797 * returned setup area) and MaxParameterCount (returned parms size) must be set
3798 * by caller
3799 */
3800static int
3801smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003802 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003803 void **ret_buf)
3804{
3805 int rc;
3806 __u32 temp_offset;
3807 struct smb_com_ntransact_req *pSMB;
3808
3809 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3810 (void **)&pSMB);
3811 if (rc)
3812 return rc;
3813 *ret_buf = (void *)pSMB;
3814 pSMB->Reserved = 0;
3815 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3816 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003817 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003818 pSMB->ParameterCount = pSMB->TotalParameterCount;
3819 pSMB->DataCount = pSMB->TotalDataCount;
3820 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3821 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3822 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3823 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3824 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3825 pSMB->SubCommand = cpu_to_le16(sub_command);
3826 return 0;
3827}
3828
3829static int
3830validate_ntransact(char *buf, char **ppparm, char **ppdata,
3831 __u32 *pparmlen, __u32 *pdatalen)
3832{
3833 char *end_of_smb;
3834 __u32 data_count, data_offset, parm_count, parm_offset;
3835 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003836 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003837
3838 *pdatalen = 0;
3839 *pparmlen = 0;
3840
3841 if (buf == NULL)
3842 return -EINVAL;
3843
3844 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3845
Jeff Layton820a8032011-05-04 08:05:26 -04003846 bcc = get_bcc(&pSMBr->hdr);
3847 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003848 (char *)&pSMBr->ByteCount;
3849
3850 data_offset = le32_to_cpu(pSMBr->DataOffset);
3851 data_count = le32_to_cpu(pSMBr->DataCount);
3852 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3853 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3854
3855 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3856 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3857
3858 /* should we also check that parm and data areas do not overlap? */
3859 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003860 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003861 return -EINVAL;
3862 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003863 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003864 return -EINVAL;
3865 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003866 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003867 return -EINVAL;
3868 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003869 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3870 *ppdata, data_count, (data_count + *ppdata),
3871 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003872 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003873 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003874 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003875 return -EINVAL;
3876 }
3877 *pdatalen = data_count;
3878 *pparmlen = parm_count;
3879 return 0;
3880}
3881
Steve French0a4b92c2006-01-12 15:44:21 -08003882/* Get Security Descriptor (by handle) from remote server for a file or dir */
3883int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003884CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003885 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003886{
3887 int rc = 0;
3888 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003889 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003890 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003891 struct kvec rsp_iov;
Steve French0a4b92c2006-01-12 15:44:21 -08003892
Joe Perchesf96637b2013-05-04 22:12:25 -05003893 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003894
Steve French630f3f0c2007-10-25 21:17:17 +00003895 *pbuflen = 0;
3896 *acl_inf = NULL;
3897
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003898 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003899 8 /* parm len */, tcon, (void **) &pSMB);
3900 if (rc)
3901 return rc;
3902
3903 pSMB->MaxParameterCount = cpu_to_le32(4);
3904 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3905 pSMB->MaxSetupCount = 0;
3906 pSMB->Fid = fid; /* file handle always le */
3907 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3908 CIFS_ACL_DACL);
3909 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003910 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003911 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003912 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003913
Steve Frencha761ac52007-10-18 21:45:27 +00003914 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003915 0, &rsp_iov);
3916 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003917 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003918 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003919 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003920 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003921 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003922 __u32 parm_len;
3923 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003924 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003925 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003926
3927/* validate_nttransact */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003928 rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003929 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003930 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003931 goto qsec_out;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003932 pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
Steve French0a4b92c2006-01-12 15:44:21 -08003933
Joe Perchesf96637b2013-05-04 22:12:25 -05003934 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3935 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003936
3937 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3938 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003939 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003940 goto qsec_out;
3941 }
3942
3943/* BB check that data area is minimum length and as big as acl_len */
3944
Steve Frenchaf6f4612007-10-16 18:40:37 +00003945 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003946 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003947 cifs_dbg(VFS, "acl length %d does not match %d\n",
3948 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003949 if (*pbuflen > acl_len)
3950 *pbuflen = acl_len;
3951 }
Steve French0a4b92c2006-01-12 15:44:21 -08003952
Steve French630f3f0c2007-10-25 21:17:17 +00003953 /* check if buffer is big enough for the acl
3954 header followed by the smallest SID */
3955 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3956 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003957 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003958 rc = -EINVAL;
3959 *pbuflen = 0;
3960 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003961 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003962 if (*acl_inf == NULL) {
3963 *pbuflen = 0;
3964 rc = -ENOMEM;
3965 }
Steve French630f3f0c2007-10-25 21:17:17 +00003966 }
Steve French0a4b92c2006-01-12 15:44:21 -08003967 }
3968qsec_out:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003969 free_rsp_buf(buf_type, rsp_iov.iov_base);
Steve French0a4b92c2006-01-12 15:44:21 -08003970 return rc;
3971}
Steve French97837582007-12-31 07:47:21 +00003972
3973int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003974CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003975 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003976{
3977 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3978 int rc = 0;
3979 int bytes_returned = 0;
3980 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003981 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003982
3983setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003984 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003985 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003986 return rc;
Steve French97837582007-12-31 07:47:21 +00003987
3988 pSMB->MaxSetupCount = 0;
3989 pSMB->Reserved = 0;
3990
3991 param_count = 8;
3992 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3993 data_count = acllen;
3994 data_offset = param_offset + param_count;
3995 byte_count = 3 /* pad */ + param_count;
3996
3997 pSMB->DataCount = cpu_to_le32(data_count);
3998 pSMB->TotalDataCount = pSMB->DataCount;
3999 pSMB->MaxParameterCount = cpu_to_le32(4);
4000 pSMB->MaxDataCount = cpu_to_le32(16384);
4001 pSMB->ParameterCount = cpu_to_le32(param_count);
4002 pSMB->ParameterOffset = cpu_to_le32(param_offset);
4003 pSMB->TotalParameterCount = pSMB->ParameterCount;
4004 pSMB->DataOffset = cpu_to_le32(data_offset);
4005 pSMB->SetupCount = 0;
4006 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
4007 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
4008
4009 pSMB->Fid = fid; /* file handle always le */
4010 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05004011 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00004012
4013 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04004014 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
4015 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004016 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00004017 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004018 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00004019
4020 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4021 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4022
Joe Perchesf96637b2013-05-04 22:12:25 -05004023 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
4024 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00004025 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004026 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00004027 cifs_buf_release(pSMB);
4028
4029 if (rc == -EAGAIN)
4030 goto setCifsAclRetry;
4031
4032 return (rc);
4033}
4034
Jeff Layton79df1ba2010-12-06 12:52:08 -05004035#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08004036
Steve French6b8edfe2005-08-23 20:26:03 -07004037/* Legacy Query Path Information call for lookup to old servers such
4038 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004039int
4040SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
4041 const char *search_name, FILE_ALL_INFO *data,
4042 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07004043{
Steve Frenchad7a2922008-02-07 23:25:02 +00004044 QUERY_INFORMATION_REQ *pSMB;
4045 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07004046 int rc = 0;
4047 int bytes_returned;
4048 int name_len;
4049
Joe Perchesf96637b2013-05-04 22:12:25 -05004050 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004051QInfRetry:
4052 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004053 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07004054 if (rc)
4055 return rc;
4056
4057 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4058 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004059 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004060 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004061 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07004062 name_len++; /* trailing null */
4063 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004064 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004065 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07004066 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004067 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004068 }
4069 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00004070 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004071 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004072 pSMB->ByteCount = cpu_to_le16(name_len);
4073
4074 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004075 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07004076 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004077 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004078 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00004079 struct timespec ts;
4080 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00004081
4082 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00004083 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004084 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00004085 ts.tv_nsec = 0;
4086 ts.tv_sec = time;
4087 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004088 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
4089 data->LastWriteTime = data->ChangeTime;
4090 data->LastAccessTime = 0;
4091 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07004092 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004093 data->EndOfFile = data->AllocationSize;
4094 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07004095 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07004096 } else
4097 rc = -EIO; /* bad buffer passed in */
4098
4099 cifs_buf_release(pSMB);
4100
4101 if (rc == -EAGAIN)
4102 goto QInfRetry;
4103
4104 return rc;
4105}
4106
Jeff Laytonbcd53572010-02-12 07:44:16 -05004107int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004108CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004109 u16 netfid, FILE_ALL_INFO *pFindData)
4110{
4111 struct smb_t2_qfi_req *pSMB = NULL;
4112 struct smb_t2_qfi_rsp *pSMBr = NULL;
4113 int rc = 0;
4114 int bytes_returned;
4115 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004116
Jeff Laytonbcd53572010-02-12 07:44:16 -05004117QFileInfoRetry:
4118 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4119 (void **) &pSMBr);
4120 if (rc)
4121 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004122
Jeff Laytonbcd53572010-02-12 07:44:16 -05004123 params = 2 /* level */ + 2 /* fid */;
4124 pSMB->t2.TotalDataCount = 0;
4125 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4126 /* BB find exact max data count below from sess structure BB */
4127 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4128 pSMB->t2.MaxSetupCount = 0;
4129 pSMB->t2.Reserved = 0;
4130 pSMB->t2.Flags = 0;
4131 pSMB->t2.Timeout = 0;
4132 pSMB->t2.Reserved2 = 0;
4133 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4134 Fid) - 4);
4135 pSMB->t2.DataCount = 0;
4136 pSMB->t2.DataOffset = 0;
4137 pSMB->t2.SetupCount = 1;
4138 pSMB->t2.Reserved3 = 0;
4139 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4140 byte_count = params + 1 /* pad */ ;
4141 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4142 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4143 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4144 pSMB->Pad = 0;
4145 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004146 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004147 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004148
4149 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4150 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4151 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004152 cifs_dbg(FYI, "Send error in QFileInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004153 } else { /* decode response */
4154 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4155
4156 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4157 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004158 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004159 rc = -EIO; /* bad smb */
4160 else if (pFindData) {
4161 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4162 memcpy((char *) pFindData,
4163 (char *) &pSMBr->hdr.Protocol +
4164 data_offset, sizeof(FILE_ALL_INFO));
4165 } else
4166 rc = -ENOMEM;
4167 }
4168 cifs_buf_release(pSMB);
4169 if (rc == -EAGAIN)
4170 goto QFileInfoRetry;
4171
4172 return rc;
4173}
Steve French6b8edfe2005-08-23 20:26:03 -07004174
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004176CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004177 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004178 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004179 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004181 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182 TRANSACTION2_QPI_REQ *pSMB = NULL;
4183 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4184 int rc = 0;
4185 int bytes_returned;
4186 int name_len;
4187 __u16 params, byte_count;
4188
Joe Perchesf96637b2013-05-04 22:12:25 -05004189 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190QPathInfoRetry:
4191 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4192 (void **) &pSMBr);
4193 if (rc)
4194 return rc;
4195
4196 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4197 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004198 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004199 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004200 name_len++; /* trailing null */
4201 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004202 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004203 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004205 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 }
4207
Steve French50c2f752007-07-13 00:33:32 +00004208 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209 pSMB->TotalDataCount = 0;
4210 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004211 /* BB find exact max SMB PDU from sess structure BB */
4212 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213 pSMB->MaxSetupCount = 0;
4214 pSMB->Reserved = 0;
4215 pSMB->Flags = 0;
4216 pSMB->Timeout = 0;
4217 pSMB->Reserved2 = 0;
4218 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004219 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220 pSMB->DataCount = 0;
4221 pSMB->DataOffset = 0;
4222 pSMB->SetupCount = 1;
4223 pSMB->Reserved3 = 0;
4224 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4225 byte_count = params + 1 /* pad */ ;
4226 pSMB->TotalParameterCount = cpu_to_le16(params);
4227 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004228 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004229 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4230 else
4231 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004233 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 pSMB->ByteCount = cpu_to_le16(byte_count);
4235
4236 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4237 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4238 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004239 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 } else { /* decode response */
4241 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4242
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004243 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4244 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004245 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004247 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004248 rc = -EIO; /* 24 or 26 expected but we do not read
4249 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004250 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004251 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004253
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004254 /*
4255 * On legacy responses we do not read the last field,
4256 * EAsize, fortunately since it varies by subdialect and
4257 * also note it differs on Set vs Get, ie two bytes or 4
4258 * bytes depending but we don't care here.
4259 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004260 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004261 size = sizeof(FILE_INFO_STANDARD);
4262 else
4263 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004264 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004265 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266 } else
4267 rc = -ENOMEM;
4268 }
4269 cifs_buf_release(pSMB);
4270 if (rc == -EAGAIN)
4271 goto QPathInfoRetry;
4272
4273 return rc;
4274}
4275
4276int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004277CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004278 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4279{
4280 struct smb_t2_qfi_req *pSMB = NULL;
4281 struct smb_t2_qfi_rsp *pSMBr = NULL;
4282 int rc = 0;
4283 int bytes_returned;
4284 __u16 params, byte_count;
4285
4286UnixQFileInfoRetry:
4287 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4288 (void **) &pSMBr);
4289 if (rc)
4290 return rc;
4291
4292 params = 2 /* level */ + 2 /* fid */;
4293 pSMB->t2.TotalDataCount = 0;
4294 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4295 /* BB find exact max data count below from sess structure BB */
4296 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4297 pSMB->t2.MaxSetupCount = 0;
4298 pSMB->t2.Reserved = 0;
4299 pSMB->t2.Flags = 0;
4300 pSMB->t2.Timeout = 0;
4301 pSMB->t2.Reserved2 = 0;
4302 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4303 Fid) - 4);
4304 pSMB->t2.DataCount = 0;
4305 pSMB->t2.DataOffset = 0;
4306 pSMB->t2.SetupCount = 1;
4307 pSMB->t2.Reserved3 = 0;
4308 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4309 byte_count = params + 1 /* pad */ ;
4310 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4311 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4312 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4313 pSMB->Pad = 0;
4314 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004315 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004316 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004317
4318 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4319 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4320 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004321 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004322 } else { /* decode response */
4323 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4324
Jeff Layton820a8032011-05-04 08:05:26 -04004325 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004326 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 -05004327 rc = -EIO; /* bad smb */
4328 } else {
4329 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4330 memcpy((char *) pFindData,
4331 (char *) &pSMBr->hdr.Protocol +
4332 data_offset,
4333 sizeof(FILE_UNIX_BASIC_INFO));
4334 }
4335 }
4336
4337 cifs_buf_release(pSMB);
4338 if (rc == -EAGAIN)
4339 goto UnixQFileInfoRetry;
4340
4341 return rc;
4342}
4343
4344int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004345CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004347 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004348 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349{
4350/* SMB_QUERY_FILE_UNIX_BASIC */
4351 TRANSACTION2_QPI_REQ *pSMB = NULL;
4352 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4353 int rc = 0;
4354 int bytes_returned = 0;
4355 int name_len;
4356 __u16 params, byte_count;
4357
Joe Perchesf96637b2013-05-04 22:12:25 -05004358 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359UnixQPathInfoRetry:
4360 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4361 (void **) &pSMBr);
4362 if (rc)
4363 return rc;
4364
4365 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4366 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004367 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4368 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369 name_len++; /* trailing null */
4370 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004371 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372 name_len = strnlen(searchName, PATH_MAX);
4373 name_len++; /* trailing null */
4374 strncpy(pSMB->FileName, searchName, name_len);
4375 }
4376
Steve French50c2f752007-07-13 00:33:32 +00004377 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378 pSMB->TotalDataCount = 0;
4379 pSMB->MaxParameterCount = cpu_to_le16(2);
4380 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004381 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382 pSMB->MaxSetupCount = 0;
4383 pSMB->Reserved = 0;
4384 pSMB->Flags = 0;
4385 pSMB->Timeout = 0;
4386 pSMB->Reserved2 = 0;
4387 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004388 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389 pSMB->DataCount = 0;
4390 pSMB->DataOffset = 0;
4391 pSMB->SetupCount = 1;
4392 pSMB->Reserved3 = 0;
4393 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4394 byte_count = params + 1 /* pad */ ;
4395 pSMB->TotalParameterCount = cpu_to_le16(params);
4396 pSMB->ParameterCount = pSMB->TotalParameterCount;
4397 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4398 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004399 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004400 pSMB->ByteCount = cpu_to_le16(byte_count);
4401
4402 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4403 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4404 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004405 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406 } else { /* decode response */
4407 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4408
Jeff Layton820a8032011-05-04 08:05:26 -04004409 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004410 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 -07004411 rc = -EIO; /* bad smb */
4412 } else {
4413 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4414 memcpy((char *) pFindData,
4415 (char *) &pSMBr->hdr.Protocol +
4416 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004417 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418 }
4419 }
4420 cifs_buf_release(pSMB);
4421 if (rc == -EAGAIN)
4422 goto UnixQPathInfoRetry;
4423
4424 return rc;
4425}
4426
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427/* xid, tcon, searchName and codepage are input parms, rest are returned */
4428int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004429CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004430 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004431 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004432 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433{
4434/* level 257 SMB_ */
4435 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4436 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004437 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 int rc = 0;
4439 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004440 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004442 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443
Joe Perchesf96637b2013-05-04 22:12:25 -05004444 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445
4446findFirstRetry:
4447 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4448 (void **) &pSMBr);
4449 if (rc)
4450 return rc;
4451
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004452 nls_codepage = cifs_sb->local_nls;
Steve French2baa2682014-09-27 02:19:01 -05004453 remap = cifs_remap(cifs_sb);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004454
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4456 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004457 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4458 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004459 /* We can not add the asterik earlier in case
4460 it got remapped to 0xF03A as if it were part of the
4461 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004463 if (msearch) {
4464 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4465 pSMB->FileName[name_len+1] = 0;
4466 pSMB->FileName[name_len+2] = '*';
4467 pSMB->FileName[name_len+3] = 0;
4468 name_len += 4; /* now the trailing null */
4469 /* null terminate just in case */
4470 pSMB->FileName[name_len] = 0;
4471 pSMB->FileName[name_len+1] = 0;
4472 name_len += 2;
4473 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474 } else { /* BB add check for overrun of SMB buf BB */
4475 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004477 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 free buffer exit; BB */
4479 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004480 if (msearch) {
4481 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4482 pSMB->FileName[name_len+1] = '*';
4483 pSMB->FileName[name_len+2] = 0;
4484 name_len += 3;
4485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486 }
4487
4488 params = 12 + name_len /* includes null */ ;
4489 pSMB->TotalDataCount = 0; /* no EAs */
4490 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004491 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 pSMB->MaxSetupCount = 0;
4493 pSMB->Reserved = 0;
4494 pSMB->Flags = 0;
4495 pSMB->Timeout = 0;
4496 pSMB->Reserved2 = 0;
4497 byte_count = params + 1 /* pad */ ;
4498 pSMB->TotalParameterCount = cpu_to_le16(params);
4499 pSMB->ParameterCount = pSMB->TotalParameterCount;
4500 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004501 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4502 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503 pSMB->DataCount = 0;
4504 pSMB->DataOffset = 0;
4505 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4506 pSMB->Reserved3 = 0;
4507 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4508 pSMB->SearchAttributes =
4509 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4510 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004511 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004512 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4514
4515 /* BB what should we set StorageType to? Does it matter? BB */
4516 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004517 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518 pSMB->ByteCount = cpu_to_le16(byte_count);
4519
4520 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4521 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004522 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004523
Steve French88274812006-03-09 22:21:45 +00004524 if (rc) {/* BB add logic to retry regular search if Unix search
4525 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004527 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004528
Steve French88274812006-03-09 22:21:45 +00004529 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530
4531 /* BB eventually could optimize out free and realloc of buf */
4532 /* for this case */
4533 if (rc == -EAGAIN)
4534 goto findFirstRetry;
4535 } else { /* decode response */
4536 /* BB remember to free buffer if error BB */
4537 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004538 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004539 unsigned int lnoff;
4540
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004542 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543 else
Steve French4b18f2a2008-04-29 00:06:05 +00004544 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545
4546 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004547 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004548 psrch_inf->srch_entries_start =
4549 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4552 le16_to_cpu(pSMBr->t2.ParameterOffset));
4553
Steve French790fe572007-07-07 19:25:05 +00004554 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004555 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556 else
Steve French4b18f2a2008-04-29 00:06:05 +00004557 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558
Steve French50c2f752007-07-13 00:33:32 +00004559 psrch_inf->entries_in_buffer =
4560 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004561 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004563 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004564 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004565 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004566 psrch_inf->last_entry = NULL;
4567 return rc;
4568 }
4569
Steve French0752f152008-10-07 20:03:33 +00004570 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004571 lnoff;
4572
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004573 if (pnetfid)
4574 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575 } else {
4576 cifs_buf_release(pSMB);
4577 }
4578 }
4579
4580 return rc;
4581}
4582
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004583int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4584 __u16 searchHandle, __u16 search_flags,
4585 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586{
4587 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4588 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004589 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590 char *response_data;
4591 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004592 int bytes_returned;
4593 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594 __u16 params, byte_count;
4595
Joe Perchesf96637b2013-05-04 22:12:25 -05004596 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597
Steve French4b18f2a2008-04-29 00:06:05 +00004598 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599 return -ENOENT;
4600
4601 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4602 (void **) &pSMBr);
4603 if (rc)
4604 return rc;
4605
Steve French50c2f752007-07-13 00:33:32 +00004606 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607 byte_count = 0;
4608 pSMB->TotalDataCount = 0; /* no EAs */
4609 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004610 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611 pSMB->MaxSetupCount = 0;
4612 pSMB->Reserved = 0;
4613 pSMB->Flags = 0;
4614 pSMB->Timeout = 0;
4615 pSMB->Reserved2 = 0;
4616 pSMB->ParameterOffset = cpu_to_le16(
4617 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4618 pSMB->DataCount = 0;
4619 pSMB->DataOffset = 0;
4620 pSMB->SetupCount = 1;
4621 pSMB->Reserved3 = 0;
4622 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4623 pSMB->SearchHandle = searchHandle; /* always kept as le */
4624 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004625 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4627 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004628 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629
4630 name_len = psrch_inf->resume_name_len;
4631 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004632 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4634 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004635 /* 14 byte parm len above enough for 2 byte null terminator */
4636 pSMB->ResumeFileName[name_len] = 0;
4637 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638 } else {
4639 rc = -EINVAL;
4640 goto FNext2_err_exit;
4641 }
4642 byte_count = params + 1 /* pad */ ;
4643 pSMB->TotalParameterCount = cpu_to_le16(params);
4644 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004645 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004646 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004647
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4649 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004650 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651 if (rc) {
4652 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004653 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004654 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004655 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004656 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004657 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004658 } else { /* decode response */
4659 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004660
Steve French790fe572007-07-07 19:25:05 +00004661 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004662 unsigned int lnoff;
4663
Linus Torvalds1da177e2005-04-16 15:20:36 -07004664 /* BB fixme add lock for file (srch_info) struct here */
4665 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004666 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004667 else
Steve French4b18f2a2008-04-29 00:06:05 +00004668 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669 response_data = (char *) &pSMBr->hdr.Protocol +
4670 le16_to_cpu(pSMBr->t2.ParameterOffset);
4671 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4672 response_data = (char *)&pSMBr->hdr.Protocol +
4673 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004674 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004675 cifs_small_buf_release(
4676 psrch_inf->ntwrk_buf_start);
4677 else
4678 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679 psrch_inf->srch_entries_start = response_data;
4680 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004681 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004682 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004683 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004684 else
Steve French4b18f2a2008-04-29 00:06:05 +00004685 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004686 psrch_inf->entries_in_buffer =
4687 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004688 psrch_inf->index_of_last_entry +=
4689 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004690 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004691 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004692 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004693 psrch_inf->last_entry = NULL;
4694 return rc;
4695 } else
4696 psrch_inf->last_entry =
4697 psrch_inf->srch_entries_start + lnoff;
4698
Joe Perchesf96637b2013-05-04 22:12:25 -05004699/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4700 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701
4702 /* BB fixme add unlock here */
4703 }
4704
4705 }
4706
4707 /* BB On error, should we leave previous search buf (and count and
4708 last entry fields) intact or free the previous one? */
4709
4710 /* Note: On -EAGAIN error only caller can retry on handle based calls
4711 since file handle passed in no longer valid */
4712FNext2_err_exit:
4713 if (rc != 0)
4714 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715 return rc;
4716}
4717
4718int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004719CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004720 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721{
4722 int rc = 0;
4723 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724
Joe Perchesf96637b2013-05-04 22:12:25 -05004725 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4727
4728 /* no sense returning error if session restarted
4729 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004730 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731 return 0;
4732 if (rc)
4733 return rc;
4734
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735 pSMB->FileID = searchHandle;
4736 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004737 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004738 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00004739 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004740 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004741
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004742 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004743
4744 /* Since session is dead, search handle closed on server already */
4745 if (rc == -EAGAIN)
4746 rc = 0;
4747
4748 return rc;
4749}
4750
Linus Torvalds1da177e2005-04-16 15:20:36 -07004751int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004752CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004753 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004754 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755{
4756 int rc = 0;
4757 TRANSACTION2_QPI_REQ *pSMB = NULL;
4758 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4759 int name_len, bytes_returned;
4760 __u16 params, byte_count;
4761
Joe Perchesf96637b2013-05-04 22:12:25 -05004762 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004763 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004764 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765
4766GetInodeNumberRetry:
4767 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004768 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 if (rc)
4770 return rc;
4771
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4773 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004774 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004775 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004776 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004777 name_len++; /* trailing null */
4778 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004779 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004780 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004782 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004783 }
4784
4785 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4786 pSMB->TotalDataCount = 0;
4787 pSMB->MaxParameterCount = cpu_to_le16(2);
4788 /* BB find exact max data count below from sess structure BB */
4789 pSMB->MaxDataCount = cpu_to_le16(4000);
4790 pSMB->MaxSetupCount = 0;
4791 pSMB->Reserved = 0;
4792 pSMB->Flags = 0;
4793 pSMB->Timeout = 0;
4794 pSMB->Reserved2 = 0;
4795 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004796 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 pSMB->DataCount = 0;
4798 pSMB->DataOffset = 0;
4799 pSMB->SetupCount = 1;
4800 pSMB->Reserved3 = 0;
4801 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4802 byte_count = params + 1 /* pad */ ;
4803 pSMB->TotalParameterCount = cpu_to_le16(params);
4804 pSMB->ParameterCount = pSMB->TotalParameterCount;
4805 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4806 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004807 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808 pSMB->ByteCount = cpu_to_le16(byte_count);
4809
4810 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4811 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4812 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004813 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814 } else {
4815 /* decode response */
4816 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004818 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819 /* If rc should we check for EOPNOSUPP and
4820 disable the srvino flag? or in caller? */
4821 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004822 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4824 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004825 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004827 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004828 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829 rc = -EIO;
4830 goto GetInodeNumOut;
4831 }
4832 pfinfo = (struct file_internal_info *)
4833 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004834 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835 }
4836 }
4837GetInodeNumOut:
4838 cifs_buf_release(pSMB);
4839 if (rc == -EAGAIN)
4840 goto GetInodeNumberRetry;
4841 return rc;
4842}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843
4844int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004845CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004846 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004847 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004848 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849{
4850/* TRANS2_GET_DFS_REFERRAL */
4851 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4852 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853 int rc = 0;
4854 int bytes_returned;
4855 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004856 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004857 *num_of_nodes = 0;
4858 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859
Joe Perchesf96637b2013-05-04 22:12:25 -05004860 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004861 if (ses == NULL || ses->tcon_ipc == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 return -ENODEV;
Aurelien Aptelb327a712018-01-24 13:46:10 +01004863
Linus Torvalds1da177e2005-04-16 15:20:36 -07004864getDFSRetry:
Aurelien Aptelb327a712018-01-24 13:46:10 +01004865 rc = smb_init(SMB_COM_TRANSACTION2, 15, ses->tcon_ipc, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866 (void **) &pSMBr);
4867 if (rc)
4868 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004869
4870 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004871 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004872 pSMB->hdr.Mid = get_next_mid(ses->server);
Aurelien Aptelb327a712018-01-24 13:46:10 +01004873 pSMB->hdr.Tid = ses->tcon_ipc->tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004874 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004875 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004877 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879
4880 if (ses->capabilities & CAP_UNICODE) {
4881 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4882 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004883 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004884 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004885 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004886 name_len++; /* trailing null */
4887 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004888 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004889 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004890 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004891 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892 }
4893
Dan Carpenter65c3b202015-04-30 17:30:24 +03004894 if (ses->server->sign)
Jeff Layton38d77c52013-05-26 07:01:00 -04004895 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00004896
Steve French50c2f752007-07-13 00:33:32 +00004897 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004898
Linus Torvalds1da177e2005-04-16 15:20:36 -07004899 params = 2 /* level */ + name_len /*includes null */ ;
4900 pSMB->TotalDataCount = 0;
4901 pSMB->DataCount = 0;
4902 pSMB->DataOffset = 0;
4903 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004904 /* BB find exact max SMB PDU from sess structure BB */
4905 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004906 pSMB->MaxSetupCount = 0;
4907 pSMB->Reserved = 0;
4908 pSMB->Flags = 0;
4909 pSMB->Timeout = 0;
4910 pSMB->Reserved2 = 0;
4911 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004912 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004913 pSMB->SetupCount = 1;
4914 pSMB->Reserved3 = 0;
4915 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4916 byte_count = params + 3 /* pad */ ;
4917 pSMB->ParameterCount = cpu_to_le16(params);
4918 pSMB->TotalParameterCount = pSMB->ParameterCount;
4919 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004920 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004921 pSMB->ByteCount = cpu_to_le16(byte_count);
4922
4923 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4924 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4925 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004926 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004927 goto GetDFSRefExit;
4928 }
4929 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004930
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004931 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004932 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004933 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004934 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004935 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004936
Joe Perchesf96637b2013-05-04 22:12:25 -05004937 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4938 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004939
4940 /* parse returned result into more usable form */
Aurelien Aptel4ecce922017-02-13 16:03:47 +01004941 rc = parse_dfs_referrals(&pSMBr->dfs_data,
4942 le16_to_cpu(pSMBr->t2.DataCount),
4943 num_of_nodes, target_nodes, nls_codepage,
4944 remap, search_name,
Steve French284316d2017-03-02 15:42:48 -06004945 (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0);
Igor Mammedovfec45852008-05-16 13:06:30 +04004946
Linus Torvalds1da177e2005-04-16 15:20:36 -07004947GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004948 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004949
4950 if (rc == -EAGAIN)
4951 goto getDFSRetry;
4952
4953 return rc;
4954}
4955
Steve French20962432005-09-21 22:05:57 -07004956/* Query File System Info such as free space to old servers such as Win 9x */
4957int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004958SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4959 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004960{
4961/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4962 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4963 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4964 FILE_SYSTEM_ALLOC_INFO *response_data;
4965 int rc = 0;
4966 int bytes_returned = 0;
4967 __u16 params, byte_count;
4968
Joe Perchesf96637b2013-05-04 22:12:25 -05004969 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004970oldQFSInfoRetry:
4971 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4972 (void **) &pSMBr);
4973 if (rc)
4974 return rc;
Steve French20962432005-09-21 22:05:57 -07004975
4976 params = 2; /* level */
4977 pSMB->TotalDataCount = 0;
4978 pSMB->MaxParameterCount = cpu_to_le16(2);
4979 pSMB->MaxDataCount = cpu_to_le16(1000);
4980 pSMB->MaxSetupCount = 0;
4981 pSMB->Reserved = 0;
4982 pSMB->Flags = 0;
4983 pSMB->Timeout = 0;
4984 pSMB->Reserved2 = 0;
4985 byte_count = params + 1 /* pad */ ;
4986 pSMB->TotalParameterCount = cpu_to_le16(params);
4987 pSMB->ParameterCount = pSMB->TotalParameterCount;
4988 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4989 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4990 pSMB->DataCount = 0;
4991 pSMB->DataOffset = 0;
4992 pSMB->SetupCount = 1;
4993 pSMB->Reserved3 = 0;
4994 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4995 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004996 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004997 pSMB->ByteCount = cpu_to_le16(byte_count);
4998
4999 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5000 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5001 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005002 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07005003 } else { /* decode response */
5004 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5005
Jeff Layton820a8032011-05-04 08:05:26 -04005006 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07005007 rc = -EIO; /* bad smb */
5008 else {
5009 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05005010 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04005011 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07005012
Steve French50c2f752007-07-13 00:33:32 +00005013 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07005014 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5015 FSData->f_bsize =
5016 le16_to_cpu(response_data->BytesPerSector) *
5017 le32_to_cpu(response_data->
5018 SectorsPerAllocationUnit);
5019 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00005020 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07005021 FSData->f_bfree = FSData->f_bavail =
5022 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005023 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5024 (unsigned long long)FSData->f_blocks,
5025 (unsigned long long)FSData->f_bfree,
5026 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07005027 }
5028 }
5029 cifs_buf_release(pSMB);
5030
5031 if (rc == -EAGAIN)
5032 goto oldQFSInfoRetry;
5033
5034 return rc;
5035}
5036
Linus Torvalds1da177e2005-04-16 15:20:36 -07005037int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005038CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5039 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005040{
5041/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5042 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5043 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5044 FILE_SYSTEM_INFO *response_data;
5045 int rc = 0;
5046 int bytes_returned = 0;
5047 __u16 params, byte_count;
5048
Joe Perchesf96637b2013-05-04 22:12:25 -05005049 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005050QFSInfoRetry:
5051 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5052 (void **) &pSMBr);
5053 if (rc)
5054 return rc;
5055
5056 params = 2; /* level */
5057 pSMB->TotalDataCount = 0;
5058 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005059 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005060 pSMB->MaxSetupCount = 0;
5061 pSMB->Reserved = 0;
5062 pSMB->Flags = 0;
5063 pSMB->Timeout = 0;
5064 pSMB->Reserved2 = 0;
5065 byte_count = params + 1 /* pad */ ;
5066 pSMB->TotalParameterCount = cpu_to_le16(params);
5067 pSMB->ParameterCount = pSMB->TotalParameterCount;
5068 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005069 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070 pSMB->DataCount = 0;
5071 pSMB->DataOffset = 0;
5072 pSMB->SetupCount = 1;
5073 pSMB->Reserved3 = 0;
5074 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5075 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005076 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077 pSMB->ByteCount = cpu_to_le16(byte_count);
5078
5079 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5080 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5081 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005082 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005083 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005084 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005085
Jeff Layton820a8032011-05-04 08:05:26 -04005086 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005087 rc = -EIO; /* bad smb */
5088 else {
5089 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090
5091 response_data =
5092 (FILE_SYSTEM_INFO
5093 *) (((char *) &pSMBr->hdr.Protocol) +
5094 data_offset);
5095 FSData->f_bsize =
5096 le32_to_cpu(response_data->BytesPerSector) *
5097 le32_to_cpu(response_data->
5098 SectorsPerAllocationUnit);
5099 FSData->f_blocks =
5100 le64_to_cpu(response_data->TotalAllocationUnits);
5101 FSData->f_bfree = FSData->f_bavail =
5102 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005103 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5104 (unsigned long long)FSData->f_blocks,
5105 (unsigned long long)FSData->f_bfree,
5106 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005107 }
5108 }
5109 cifs_buf_release(pSMB);
5110
5111 if (rc == -EAGAIN)
5112 goto QFSInfoRetry;
5113
5114 return rc;
5115}
5116
5117int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005118CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119{
5120/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5121 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5122 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5123 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5124 int rc = 0;
5125 int bytes_returned = 0;
5126 __u16 params, byte_count;
5127
Joe Perchesf96637b2013-05-04 22:12:25 -05005128 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129QFSAttributeRetry:
5130 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5131 (void **) &pSMBr);
5132 if (rc)
5133 return rc;
5134
5135 params = 2; /* level */
5136 pSMB->TotalDataCount = 0;
5137 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005138 /* BB find exact max SMB PDU from sess structure BB */
5139 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005140 pSMB->MaxSetupCount = 0;
5141 pSMB->Reserved = 0;
5142 pSMB->Flags = 0;
5143 pSMB->Timeout = 0;
5144 pSMB->Reserved2 = 0;
5145 byte_count = params + 1 /* pad */ ;
5146 pSMB->TotalParameterCount = cpu_to_le16(params);
5147 pSMB->ParameterCount = pSMB->TotalParameterCount;
5148 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005149 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150 pSMB->DataCount = 0;
5151 pSMB->DataOffset = 0;
5152 pSMB->SetupCount = 1;
5153 pSMB->Reserved3 = 0;
5154 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5155 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005156 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157 pSMB->ByteCount = cpu_to_le16(byte_count);
5158
5159 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5160 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5161 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005162 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005163 } else { /* decode response */
5164 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5165
Jeff Layton820a8032011-05-04 08:05:26 -04005166 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005167 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005168 rc = -EIO; /* bad smb */
5169 } else {
5170 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5171 response_data =
5172 (FILE_SYSTEM_ATTRIBUTE_INFO
5173 *) (((char *) &pSMBr->hdr.Protocol) +
5174 data_offset);
5175 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005176 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005177 }
5178 }
5179 cifs_buf_release(pSMB);
5180
5181 if (rc == -EAGAIN)
5182 goto QFSAttributeRetry;
5183
5184 return rc;
5185}
5186
5187int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005188CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005189{
5190/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5191 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5192 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5193 FILE_SYSTEM_DEVICE_INFO *response_data;
5194 int rc = 0;
5195 int bytes_returned = 0;
5196 __u16 params, byte_count;
5197
Joe Perchesf96637b2013-05-04 22:12:25 -05005198 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199QFSDeviceRetry:
5200 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5201 (void **) &pSMBr);
5202 if (rc)
5203 return rc;
5204
5205 params = 2; /* level */
5206 pSMB->TotalDataCount = 0;
5207 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005208 /* BB find exact max SMB PDU from sess structure BB */
5209 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005210 pSMB->MaxSetupCount = 0;
5211 pSMB->Reserved = 0;
5212 pSMB->Flags = 0;
5213 pSMB->Timeout = 0;
5214 pSMB->Reserved2 = 0;
5215 byte_count = params + 1 /* pad */ ;
5216 pSMB->TotalParameterCount = cpu_to_le16(params);
5217 pSMB->ParameterCount = pSMB->TotalParameterCount;
5218 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005219 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220
5221 pSMB->DataCount = 0;
5222 pSMB->DataOffset = 0;
5223 pSMB->SetupCount = 1;
5224 pSMB->Reserved3 = 0;
5225 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5226 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005227 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228 pSMB->ByteCount = cpu_to_le16(byte_count);
5229
5230 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5231 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5232 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005233 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234 } else { /* decode response */
5235 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5236
Jeff Layton820a8032011-05-04 08:05:26 -04005237 if (rc || get_bcc(&pSMBr->hdr) <
5238 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005239 rc = -EIO; /* bad smb */
5240 else {
5241 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5242 response_data =
Steve French737b7582005-04-28 22:41:06 -07005243 (FILE_SYSTEM_DEVICE_INFO *)
5244 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005245 data_offset);
5246 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005247 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248 }
5249 }
5250 cifs_buf_release(pSMB);
5251
5252 if (rc == -EAGAIN)
5253 goto QFSDeviceRetry;
5254
5255 return rc;
5256}
5257
5258int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005259CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005260{
5261/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5262 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5263 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5264 FILE_SYSTEM_UNIX_INFO *response_data;
5265 int rc = 0;
5266 int bytes_returned = 0;
5267 __u16 params, byte_count;
5268
Joe Perchesf96637b2013-05-04 22:12:25 -05005269 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005270QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005271 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5272 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005273 if (rc)
5274 return rc;
5275
5276 params = 2; /* level */
5277 pSMB->TotalDataCount = 0;
5278 pSMB->DataCount = 0;
5279 pSMB->DataOffset = 0;
5280 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005281 /* BB find exact max SMB PDU from sess structure BB */
5282 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005283 pSMB->MaxSetupCount = 0;
5284 pSMB->Reserved = 0;
5285 pSMB->Flags = 0;
5286 pSMB->Timeout = 0;
5287 pSMB->Reserved2 = 0;
5288 byte_count = params + 1 /* pad */ ;
5289 pSMB->ParameterCount = cpu_to_le16(params);
5290 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005291 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5292 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005293 pSMB->SetupCount = 1;
5294 pSMB->Reserved3 = 0;
5295 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5296 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005297 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005298 pSMB->ByteCount = cpu_to_le16(byte_count);
5299
5300 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5301 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5302 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005303 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005304 } else { /* decode response */
5305 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5306
Jeff Layton820a8032011-05-04 08:05:26 -04005307 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308 rc = -EIO; /* bad smb */
5309 } else {
5310 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5311 response_data =
5312 (FILE_SYSTEM_UNIX_INFO
5313 *) (((char *) &pSMBr->hdr.Protocol) +
5314 data_offset);
5315 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005316 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005317 }
5318 }
5319 cifs_buf_release(pSMB);
5320
5321 if (rc == -EAGAIN)
5322 goto QFSUnixRetry;
5323
5324
5325 return rc;
5326}
5327
Jeremy Allisonac670552005-06-22 17:26:35 -07005328int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005329CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005330{
5331/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5332 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5333 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5334 int rc = 0;
5335 int bytes_returned = 0;
5336 __u16 params, param_offset, offset, byte_count;
5337
Joe Perchesf96637b2013-05-04 22:12:25 -05005338 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005339SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005340 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005341 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5342 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005343 if (rc)
5344 return rc;
5345
5346 params = 4; /* 2 bytes zero followed by info level. */
5347 pSMB->MaxSetupCount = 0;
5348 pSMB->Reserved = 0;
5349 pSMB->Flags = 0;
5350 pSMB->Timeout = 0;
5351 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005352 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5353 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005354 offset = param_offset + params;
5355
5356 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005357 /* BB find exact max SMB PDU from sess structure BB */
5358 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005359 pSMB->SetupCount = 1;
5360 pSMB->Reserved3 = 0;
5361 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5362 byte_count = 1 /* pad */ + params + 12;
5363
5364 pSMB->DataCount = cpu_to_le16(12);
5365 pSMB->ParameterCount = cpu_to_le16(params);
5366 pSMB->TotalDataCount = pSMB->DataCount;
5367 pSMB->TotalParameterCount = pSMB->ParameterCount;
5368 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5369 pSMB->DataOffset = cpu_to_le16(offset);
5370
5371 /* Params. */
5372 pSMB->FileNum = 0;
5373 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5374
5375 /* Data. */
5376 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5377 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5378 pSMB->ClientUnixCap = cpu_to_le64(cap);
5379
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005380 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005381 pSMB->ByteCount = cpu_to_le16(byte_count);
5382
5383 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5384 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5385 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005386 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005387 } else { /* decode response */
5388 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005389 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005390 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005391 }
5392 cifs_buf_release(pSMB);
5393
5394 if (rc == -EAGAIN)
5395 goto SETFSUnixRetry;
5396
5397 return rc;
5398}
5399
5400
Linus Torvalds1da177e2005-04-16 15:20:36 -07005401
5402int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005403CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005404 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005405{
5406/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5407 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5408 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5409 FILE_SYSTEM_POSIX_INFO *response_data;
5410 int rc = 0;
5411 int bytes_returned = 0;
5412 __u16 params, byte_count;
5413
Joe Perchesf96637b2013-05-04 22:12:25 -05005414 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005415QFSPosixRetry:
5416 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5417 (void **) &pSMBr);
5418 if (rc)
5419 return rc;
5420
5421 params = 2; /* level */
5422 pSMB->TotalDataCount = 0;
5423 pSMB->DataCount = 0;
5424 pSMB->DataOffset = 0;
5425 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005426 /* BB find exact max SMB PDU from sess structure BB */
5427 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005428 pSMB->MaxSetupCount = 0;
5429 pSMB->Reserved = 0;
5430 pSMB->Flags = 0;
5431 pSMB->Timeout = 0;
5432 pSMB->Reserved2 = 0;
5433 byte_count = params + 1 /* pad */ ;
5434 pSMB->ParameterCount = cpu_to_le16(params);
5435 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005436 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5437 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438 pSMB->SetupCount = 1;
5439 pSMB->Reserved3 = 0;
5440 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5441 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005442 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443 pSMB->ByteCount = cpu_to_le16(byte_count);
5444
5445 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5446 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5447 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005448 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005449 } else { /* decode response */
5450 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5451
Jeff Layton820a8032011-05-04 08:05:26 -04005452 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453 rc = -EIO; /* bad smb */
5454 } else {
5455 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5456 response_data =
5457 (FILE_SYSTEM_POSIX_INFO
5458 *) (((char *) &pSMBr->hdr.Protocol) +
5459 data_offset);
5460 FSData->f_bsize =
5461 le32_to_cpu(response_data->BlockSize);
5462 FSData->f_blocks =
5463 le64_to_cpu(response_data->TotalBlocks);
5464 FSData->f_bfree =
5465 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005466 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467 FSData->f_bavail = FSData->f_bfree;
5468 } else {
5469 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005470 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005471 }
Steve French790fe572007-07-07 19:25:05 +00005472 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005473 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005474 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005475 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005477 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478 }
5479 }
5480 cifs_buf_release(pSMB);
5481
5482 if (rc == -EAGAIN)
5483 goto QFSPosixRetry;
5484
5485 return rc;
5486}
5487
5488
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005489/*
5490 * We can not use write of zero bytes trick to set file size due to need for
5491 * large file support. Also note that this SetPathInfo is preferred to
5492 * SetFileInfo based method in next routine which is only needed to work around
5493 * a sharing violation bugin Samba which this routine can run into.
5494 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005496CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005497 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5498 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005499{
5500 struct smb_com_transaction2_spi_req *pSMB = NULL;
5501 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5502 struct file_end_of_file_info *parm_data;
5503 int name_len;
5504 int rc = 0;
5505 int bytes_returned = 0;
Steve French2baa2682014-09-27 02:19:01 -05005506 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005507
Linus Torvalds1da177e2005-04-16 15:20:36 -07005508 __u16 params, byte_count, data_count, param_offset, offset;
5509
Joe Perchesf96637b2013-05-04 22:12:25 -05005510 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005511SetEOFRetry:
5512 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5513 (void **) &pSMBr);
5514 if (rc)
5515 return rc;
5516
5517 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5518 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005519 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5520 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005521 name_len++; /* trailing null */
5522 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005523 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005524 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005526 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005527 }
5528 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005529 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005530 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005531 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005532 pSMB->MaxSetupCount = 0;
5533 pSMB->Reserved = 0;
5534 pSMB->Flags = 0;
5535 pSMB->Timeout = 0;
5536 pSMB->Reserved2 = 0;
5537 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005538 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005539 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005540 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005541 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5542 pSMB->InformationLevel =
5543 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5544 else
5545 pSMB->InformationLevel =
5546 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5547 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005548 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5549 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005550 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005551 else
5552 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005553 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005554 }
5555
5556 parm_data =
5557 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5558 offset);
5559 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5560 pSMB->DataOffset = cpu_to_le16(offset);
5561 pSMB->SetupCount = 1;
5562 pSMB->Reserved3 = 0;
5563 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5564 byte_count = 3 /* pad */ + params + data_count;
5565 pSMB->DataCount = cpu_to_le16(data_count);
5566 pSMB->TotalDataCount = pSMB->DataCount;
5567 pSMB->ParameterCount = cpu_to_le16(params);
5568 pSMB->TotalParameterCount = pSMB->ParameterCount;
5569 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005570 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005571 parm_data->FileSize = cpu_to_le64(size);
5572 pSMB->ByteCount = cpu_to_le16(byte_count);
5573 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5574 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005575 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005576 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577
5578 cifs_buf_release(pSMB);
5579
5580 if (rc == -EAGAIN)
5581 goto SetEOFRetry;
5582
5583 return rc;
5584}
5585
5586int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005587CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5588 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005589{
5590 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005591 struct file_end_of_file_info *parm_data;
5592 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005593 __u16 params, param_offset, offset, byte_count, count;
5594
Joe Perchesf96637b2013-05-04 22:12:25 -05005595 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5596 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005597 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5598
Linus Torvalds1da177e2005-04-16 15:20:36 -07005599 if (rc)
5600 return rc;
5601
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005602 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5603 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005604
Linus Torvalds1da177e2005-04-16 15:20:36 -07005605 params = 6;
5606 pSMB->MaxSetupCount = 0;
5607 pSMB->Reserved = 0;
5608 pSMB->Flags = 0;
5609 pSMB->Timeout = 0;
5610 pSMB->Reserved2 = 0;
5611 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5612 offset = param_offset + params;
5613
Linus Torvalds1da177e2005-04-16 15:20:36 -07005614 count = sizeof(struct file_end_of_file_info);
5615 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005616 /* BB find exact max SMB PDU from sess structure BB */
5617 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005618 pSMB->SetupCount = 1;
5619 pSMB->Reserved3 = 0;
5620 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5621 byte_count = 3 /* pad */ + params + count;
5622 pSMB->DataCount = cpu_to_le16(count);
5623 pSMB->ParameterCount = cpu_to_le16(params);
5624 pSMB->TotalDataCount = pSMB->DataCount;
5625 pSMB->TotalParameterCount = pSMB->ParameterCount;
5626 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5627 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005628 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5629 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005630 pSMB->DataOffset = cpu_to_le16(offset);
5631 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005632 pSMB->Fid = cfile->fid.netfid;
5633 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005634 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5635 pSMB->InformationLevel =
5636 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5637 else
5638 pSMB->InformationLevel =
5639 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005640 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005641 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5642 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005643 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005644 else
5645 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005646 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005647 }
5648 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005649 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005651 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005652 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005653 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005654 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5655 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656 }
5657
Steve French50c2f752007-07-13 00:33:32 +00005658 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005659 since file handle passed in no longer valid */
5660
5661 return rc;
5662}
5663
Steve French50c2f752007-07-13 00:33:32 +00005664/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005665 an open handle, rather than by pathname - this is awkward due to
5666 potential access conflicts on the open, but it is unavoidable for these
5667 old servers since the only other choice is to go from 100 nanosecond DCE
5668 time and resort to the original setpathinfo level which takes the ancient
5669 DOS time format with 2 second granularity */
5670int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005671CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005672 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005673{
5674 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675 char *data_offset;
5676 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005677 __u16 params, param_offset, offset, byte_count, count;
5678
Joe Perchesf96637b2013-05-04 22:12:25 -05005679 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005680 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5681
Linus Torvalds1da177e2005-04-16 15:20:36 -07005682 if (rc)
5683 return rc;
5684
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005685 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5686 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005687
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688 params = 6;
5689 pSMB->MaxSetupCount = 0;
5690 pSMB->Reserved = 0;
5691 pSMB->Flags = 0;
5692 pSMB->Timeout = 0;
5693 pSMB->Reserved2 = 0;
5694 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5695 offset = param_offset + params;
5696
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005697 data_offset = (char *)pSMB +
5698 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005699
Steve French26f57362007-08-30 22:09:15 +00005700 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005701 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005702 /* BB find max SMB PDU from sess */
5703 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005704 pSMB->SetupCount = 1;
5705 pSMB->Reserved3 = 0;
5706 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5707 byte_count = 3 /* pad */ + params + count;
5708 pSMB->DataCount = cpu_to_le16(count);
5709 pSMB->ParameterCount = cpu_to_le16(params);
5710 pSMB->TotalDataCount = pSMB->DataCount;
5711 pSMB->TotalParameterCount = pSMB->ParameterCount;
5712 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5713 pSMB->DataOffset = cpu_to_le16(offset);
5714 pSMB->Fid = fid;
5715 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5716 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5717 else
5718 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5719 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005720 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005721 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005722 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005723 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005724 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00005725 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005726 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5727 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005728
Steve French50c2f752007-07-13 00:33:32 +00005729 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005730 since file handle passed in no longer valid */
5731
5732 return rc;
5733}
5734
Jeff Layton6d22f092008-09-23 11:48:35 -04005735int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005736CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005737 bool delete_file, __u16 fid, __u32 pid_of_opener)
5738{
5739 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5740 char *data_offset;
5741 int rc = 0;
5742 __u16 params, param_offset, offset, byte_count, count;
5743
Joe Perchesf96637b2013-05-04 22:12:25 -05005744 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005745 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5746
5747 if (rc)
5748 return rc;
5749
5750 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5751 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5752
5753 params = 6;
5754 pSMB->MaxSetupCount = 0;
5755 pSMB->Reserved = 0;
5756 pSMB->Flags = 0;
5757 pSMB->Timeout = 0;
5758 pSMB->Reserved2 = 0;
5759 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5760 offset = param_offset + params;
5761
5762 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5763
5764 count = 1;
5765 pSMB->MaxParameterCount = cpu_to_le16(2);
5766 /* BB find max SMB PDU from sess */
5767 pSMB->MaxDataCount = cpu_to_le16(1000);
5768 pSMB->SetupCount = 1;
5769 pSMB->Reserved3 = 0;
5770 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5771 byte_count = 3 /* pad */ + params + count;
5772 pSMB->DataCount = cpu_to_le16(count);
5773 pSMB->ParameterCount = cpu_to_le16(params);
5774 pSMB->TotalDataCount = pSMB->DataCount;
5775 pSMB->TotalParameterCount = pSMB->ParameterCount;
5776 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5777 pSMB->DataOffset = cpu_to_le16(offset);
5778 pSMB->Fid = fid;
5779 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5780 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005781 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005782 pSMB->ByteCount = cpu_to_le16(byte_count);
5783 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005784 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005785 cifs_small_buf_release(pSMB);
Jeff Layton6d22f092008-09-23 11:48:35 -04005786 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005787 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005788
5789 return rc;
5790}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791
5792int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005793CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005794 const char *fileName, const FILE_BASIC_INFO *data,
5795 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005796{
5797 TRANSACTION2_SPI_REQ *pSMB = NULL;
5798 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5799 int name_len;
5800 int rc = 0;
5801 int bytes_returned = 0;
5802 char *data_offset;
5803 __u16 params, param_offset, offset, byte_count, count;
5804
Joe Perchesf96637b2013-05-04 22:12:25 -05005805 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005806
5807SetTimesRetry:
5808 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5809 (void **) &pSMBr);
5810 if (rc)
5811 return rc;
5812
5813 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5814 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005815 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5816 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005817 name_len++; /* trailing null */
5818 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005819 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005820 name_len = strnlen(fileName, PATH_MAX);
5821 name_len++; /* trailing null */
5822 strncpy(pSMB->FileName, fileName, name_len);
5823 }
5824
5825 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005826 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005827 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005828 /* BB find max SMB PDU from sess structure BB */
5829 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005830 pSMB->MaxSetupCount = 0;
5831 pSMB->Reserved = 0;
5832 pSMB->Flags = 0;
5833 pSMB->Timeout = 0;
5834 pSMB->Reserved2 = 0;
5835 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005836 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005837 offset = param_offset + params;
5838 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5839 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5840 pSMB->DataOffset = cpu_to_le16(offset);
5841 pSMB->SetupCount = 1;
5842 pSMB->Reserved3 = 0;
5843 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5844 byte_count = 3 /* pad */ + params + count;
5845
5846 pSMB->DataCount = cpu_to_le16(count);
5847 pSMB->ParameterCount = cpu_to_le16(params);
5848 pSMB->TotalDataCount = pSMB->DataCount;
5849 pSMB->TotalParameterCount = pSMB->ParameterCount;
5850 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5851 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5852 else
5853 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5854 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005855 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005856 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005857 pSMB->ByteCount = cpu_to_le16(byte_count);
5858 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5859 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005860 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005861 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005862
5863 cifs_buf_release(pSMB);
5864
5865 if (rc == -EAGAIN)
5866 goto SetTimesRetry;
5867
5868 return rc;
5869}
5870
5871/* Can not be used to set time stamps yet (due to old DOS time format) */
5872/* Can be used to set attributes */
5873#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5874 handling it anyway and NT4 was what we thought it would be needed for
5875 Do not delete it until we prove whether needed for Win9x though */
5876int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005877CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005878 __u16 dos_attrs, const struct nls_table *nls_codepage)
5879{
5880 SETATTR_REQ *pSMB = NULL;
5881 SETATTR_RSP *pSMBr = NULL;
5882 int rc = 0;
5883 int bytes_returned;
5884 int name_len;
5885
Joe Perchesf96637b2013-05-04 22:12:25 -05005886 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005887
5888SetAttrLgcyRetry:
5889 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5890 (void **) &pSMBr);
5891 if (rc)
5892 return rc;
5893
5894 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5895 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005896 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5897 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005898 name_len++; /* trailing null */
5899 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005900 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005901 name_len = strnlen(fileName, PATH_MAX);
5902 name_len++; /* trailing null */
5903 strncpy(pSMB->fileName, fileName, name_len);
5904 }
5905 pSMB->attr = cpu_to_le16(dos_attrs);
5906 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005907 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005908 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5909 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5910 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005911 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005912 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005913
5914 cifs_buf_release(pSMB);
5915
5916 if (rc == -EAGAIN)
5917 goto SetAttrLgcyRetry;
5918
5919 return rc;
5920}
5921#endif /* temporarily unneeded SetAttr legacy function */
5922
Jeff Layton654cf142009-07-09 20:02:49 -04005923static void
5924cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5925 const struct cifs_unix_set_info_args *args)
5926{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005927 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005928 u64 mode = args->mode;
5929
Eric W. Biederman49418b22013-02-06 00:57:56 -08005930 if (uid_valid(args->uid))
5931 uid = from_kuid(&init_user_ns, args->uid);
5932 if (gid_valid(args->gid))
5933 gid = from_kgid(&init_user_ns, args->gid);
5934
Jeff Layton654cf142009-07-09 20:02:49 -04005935 /*
5936 * Samba server ignores set of file size to zero due to bugs in some
5937 * older clients, but we should be precise - we use SetFileSize to
5938 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005939 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005940 * zero instead of -1 here
5941 */
5942 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5943 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5944 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5945 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5946 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005947 data_offset->Uid = cpu_to_le64(uid);
5948 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005949 /* better to leave device as zero when it is */
5950 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5951 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5952 data_offset->Permissions = cpu_to_le64(mode);
5953
5954 if (S_ISREG(mode))
5955 data_offset->Type = cpu_to_le32(UNIX_FILE);
5956 else if (S_ISDIR(mode))
5957 data_offset->Type = cpu_to_le32(UNIX_DIR);
5958 else if (S_ISLNK(mode))
5959 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5960 else if (S_ISCHR(mode))
5961 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5962 else if (S_ISBLK(mode))
5963 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5964 else if (S_ISFIFO(mode))
5965 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5966 else if (S_ISSOCK(mode))
5967 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5968}
5969
Linus Torvalds1da177e2005-04-16 15:20:36 -07005970int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005971CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005972 const struct cifs_unix_set_info_args *args,
5973 u16 fid, u32 pid_of_opener)
5974{
5975 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005976 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005977 int rc = 0;
5978 u16 params, param_offset, offset, byte_count, count;
5979
Joe Perchesf96637b2013-05-04 22:12:25 -05005980 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005981 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5982
5983 if (rc)
5984 return rc;
5985
5986 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5987 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5988
5989 params = 6;
5990 pSMB->MaxSetupCount = 0;
5991 pSMB->Reserved = 0;
5992 pSMB->Flags = 0;
5993 pSMB->Timeout = 0;
5994 pSMB->Reserved2 = 0;
5995 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5996 offset = param_offset + params;
5997
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005998 data_offset = (char *)pSMB +
5999 offsetof(struct smb_hdr, Protocol) + offset;
6000
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006001 count = sizeof(FILE_UNIX_BASIC_INFO);
6002
6003 pSMB->MaxParameterCount = cpu_to_le16(2);
6004 /* BB find max SMB PDU from sess */
6005 pSMB->MaxDataCount = cpu_to_le16(1000);
6006 pSMB->SetupCount = 1;
6007 pSMB->Reserved3 = 0;
6008 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
6009 byte_count = 3 /* pad */ + params + count;
6010 pSMB->DataCount = cpu_to_le16(count);
6011 pSMB->ParameterCount = cpu_to_le16(params);
6012 pSMB->TotalDataCount = pSMB->DataCount;
6013 pSMB->TotalParameterCount = pSMB->ParameterCount;
6014 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6015 pSMB->DataOffset = cpu_to_le16(offset);
6016 pSMB->Fid = fid;
6017 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6018 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006019 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006020 pSMB->ByteCount = cpu_to_le16(byte_count);
6021
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006022 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006023
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04006024 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07006025 cifs_small_buf_release(pSMB);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006026 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006027 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
6028 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006029
6030 /* Note: On -EAGAIN error only caller can retry on handle based calls
6031 since file handle passed in no longer valid */
6032
6033 return rc;
6034}
6035
6036int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006037CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006038 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006039 const struct cifs_unix_set_info_args *args,
6040 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006041{
6042 TRANSACTION2_SPI_REQ *pSMB = NULL;
6043 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6044 int name_len;
6045 int rc = 0;
6046 int bytes_returned = 0;
6047 FILE_UNIX_BASIC_INFO *data_offset;
6048 __u16 params, param_offset, offset, count, byte_count;
6049
Joe Perchesf96637b2013-05-04 22:12:25 -05006050 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006051setPermsRetry:
6052 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6053 (void **) &pSMBr);
6054 if (rc)
6055 return rc;
6056
6057 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6058 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006059 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06006060 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006061 name_len++; /* trailing null */
6062 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07006063 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006064 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006065 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006066 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006067 }
6068
6069 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006070 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006071 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006072 /* BB find max SMB PDU from sess structure BB */
6073 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006074 pSMB->MaxSetupCount = 0;
6075 pSMB->Reserved = 0;
6076 pSMB->Flags = 0;
6077 pSMB->Timeout = 0;
6078 pSMB->Reserved2 = 0;
6079 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006080 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006081 offset = param_offset + params;
6082 data_offset =
6083 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6084 offset);
6085 memset(data_offset, 0, count);
6086 pSMB->DataOffset = cpu_to_le16(offset);
6087 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6088 pSMB->SetupCount = 1;
6089 pSMB->Reserved3 = 0;
6090 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6091 byte_count = 3 /* pad */ + params + count;
6092 pSMB->ParameterCount = cpu_to_le16(params);
6093 pSMB->DataCount = cpu_to_le16(count);
6094 pSMB->TotalParameterCount = pSMB->ParameterCount;
6095 pSMB->TotalDataCount = pSMB->DataCount;
6096 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6097 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006098 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006099
Jeff Layton654cf142009-07-09 20:02:49 -04006100 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006101
6102 pSMB->ByteCount = cpu_to_le16(byte_count);
6103 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6104 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006105 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006106 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006107
Steve French0d817bc2008-05-22 02:02:03 +00006108 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006109 if (rc == -EAGAIN)
6110 goto setPermsRetry;
6111 return rc;
6112}
6113
Linus Torvalds1da177e2005-04-16 15:20:36 -07006114#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006115/*
6116 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6117 * function used by listxattr and getxattr type calls. When ea_name is set,
6118 * it looks for that attribute name and stuffs that value into the EAData
6119 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6120 * buffer. In both cases, the return value is either the length of the
6121 * resulting data or a negative error code. If EAData is a NULL pointer then
6122 * the data isn't copied to it, but the length is returned.
6123 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006124ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006125CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006126 const unsigned char *searchName, const unsigned char *ea_name,
6127 char *EAData, size_t buf_size,
Steve French67b4c882017-05-12 20:59:10 -05006128 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006129{
6130 /* BB assumes one setup word */
6131 TRANSACTION2_QPI_REQ *pSMB = NULL;
6132 TRANSACTION2_QPI_RSP *pSMBr = NULL;
Steve French67b4c882017-05-12 20:59:10 -05006133 int remap = cifs_remap(cifs_sb);
6134 struct nls_table *nls_codepage = cifs_sb->local_nls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006135 int rc = 0;
6136 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006137 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006138 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006139 struct fea *temp_fea;
6140 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006141 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006142 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006143 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006144
Joe Perchesf96637b2013-05-04 22:12:25 -05006145 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006146QAllEAsRetry:
6147 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6148 (void **) &pSMBr);
6149 if (rc)
6150 return rc;
6151
6152 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006153 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006154 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6155 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006156 list_len++; /* trailing null */
6157 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006158 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006159 list_len = strnlen(searchName, PATH_MAX);
6160 list_len++; /* trailing null */
6161 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006162 }
6163
Jeff Layton6e462b92010-02-10 16:18:26 -05006164 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006165 pSMB->TotalDataCount = 0;
6166 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006167 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006168 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006169 pSMB->MaxSetupCount = 0;
6170 pSMB->Reserved = 0;
6171 pSMB->Flags = 0;
6172 pSMB->Timeout = 0;
6173 pSMB->Reserved2 = 0;
6174 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006175 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006176 pSMB->DataCount = 0;
6177 pSMB->DataOffset = 0;
6178 pSMB->SetupCount = 1;
6179 pSMB->Reserved3 = 0;
6180 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6181 byte_count = params + 1 /* pad */ ;
6182 pSMB->TotalParameterCount = cpu_to_le16(params);
6183 pSMB->ParameterCount = pSMB->TotalParameterCount;
6184 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6185 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006186 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006187 pSMB->ByteCount = cpu_to_le16(byte_count);
6188
6189 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6190 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6191 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006192 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006193 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006194 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006195
6196
6197 /* BB also check enough total bytes returned */
6198 /* BB we need to improve the validity checking
6199 of these trans2 responses */
6200
6201 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006202 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006203 rc = -EIO; /* bad smb */
6204 goto QAllEAsOut;
6205 }
6206
6207 /* check that length of list is not more than bcc */
6208 /* check that each entry does not go beyond length
6209 of list */
6210 /* check that each element of each entry does not
6211 go beyond end of list */
6212 /* validate_trans2_offsets() */
6213 /* BB check if start of smb + data_offset > &bcc+ bcc */
6214
6215 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6216 ea_response_data = (struct fealist *)
6217 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6218
Jeff Layton6e462b92010-02-10 16:18:26 -05006219 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006220 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006221 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006222 cifs_dbg(FYI, "empty EA list returned from server\n");
Steve French60977fc2014-03-25 19:46:36 -05006223 /* didn't find the named attribute */
6224 if (ea_name)
6225 rc = -ENODATA;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006226 goto QAllEAsOut;
6227 }
6228
Jeff Layton0cd126b2010-02-10 16:18:26 -05006229 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006230 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006231 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006232 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006233 rc = -EIO;
6234 goto QAllEAsOut;
6235 }
6236
Jeff Laytonf0d38682010-02-10 16:18:26 -05006237 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006238 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006239 temp_fea = ea_response_data->list;
6240 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006241 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006242 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006243 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006244
Jeff Layton6e462b92010-02-10 16:18:26 -05006245 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006246 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006247 /* make sure we can read name_len and value_len */
6248 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006249 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006250 rc = -EIO;
6251 goto QAllEAsOut;
6252 }
6253
6254 name_len = temp_fea->name_len;
6255 value_len = le16_to_cpu(temp_fea->value_len);
6256 list_len -= name_len + 1 + value_len;
6257 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006258 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006259 rc = -EIO;
6260 goto QAllEAsOut;
6261 }
6262
Jeff Layton31c05192010-02-10 16:18:26 -05006263 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006264 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006265 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006266 temp_ptr += name_len + 1;
6267 rc = value_len;
6268 if (buf_size == 0)
6269 goto QAllEAsOut;
6270 if ((size_t)value_len > buf_size) {
6271 rc = -ERANGE;
6272 goto QAllEAsOut;
6273 }
6274 memcpy(EAData, temp_ptr, value_len);
6275 goto QAllEAsOut;
6276 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006277 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006278 /* account for prefix user. and trailing null */
6279 rc += (5 + 1 + name_len);
6280 if (rc < (int) buf_size) {
6281 memcpy(EAData, "user.", 5);
6282 EAData += 5;
6283 memcpy(EAData, temp_ptr, name_len);
6284 EAData += name_len;
6285 /* null terminate name */
6286 *EAData = 0;
6287 ++EAData;
6288 } else if (buf_size == 0) {
6289 /* skip copy - calc size only */
6290 } else {
6291 /* stop before overrun buffer */
6292 rc = -ERANGE;
6293 break;
6294 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006295 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006296 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006297 temp_fea = (struct fea *)temp_ptr;
6298 }
6299
Jeff Layton31c05192010-02-10 16:18:26 -05006300 /* didn't find the named attribute */
6301 if (ea_name)
6302 rc = -ENODATA;
6303
Jeff Laytonf0d38682010-02-10 16:18:26 -05006304QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006305 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006306 if (rc == -EAGAIN)
6307 goto QAllEAsRetry;
6308
6309 return (ssize_t)rc;
6310}
6311
Linus Torvalds1da177e2005-04-16 15:20:36 -07006312int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006313CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6314 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006315 const __u16 ea_value_len, const struct nls_table *nls_codepage,
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006316 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006317{
6318 struct smb_com_transaction2_spi_req *pSMB = NULL;
6319 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6320 struct fealist *parm_data;
6321 int name_len;
6322 int rc = 0;
6323 int bytes_returned = 0;
6324 __u16 params, param_offset, byte_count, offset, count;
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006325 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006326
Joe Perchesf96637b2013-05-04 22:12:25 -05006327 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006328SetEARetry:
6329 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6330 (void **) &pSMBr);
6331 if (rc)
6332 return rc;
6333
6334 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6335 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006336 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6337 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006338 name_len++; /* trailing null */
6339 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006340 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006341 name_len = strnlen(fileName, PATH_MAX);
6342 name_len++; /* trailing null */
6343 strncpy(pSMB->FileName, fileName, name_len);
6344 }
6345
6346 params = 6 + name_len;
6347
6348 /* done calculating parms using name_len of file name,
6349 now use name_len to calculate length of ea name
6350 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006351 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006352 name_len = 0;
6353 else
Steve French50c2f752007-07-13 00:33:32 +00006354 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006355
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006356 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006357 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006358 /* BB find max SMB PDU from sess */
6359 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006360 pSMB->MaxSetupCount = 0;
6361 pSMB->Reserved = 0;
6362 pSMB->Flags = 0;
6363 pSMB->Timeout = 0;
6364 pSMB->Reserved2 = 0;
6365 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006366 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006367 offset = param_offset + params;
6368 pSMB->InformationLevel =
6369 cpu_to_le16(SMB_SET_FILE_EA);
6370
Arnd Bergmannade7db92018-02-02 16:48:47 +01006371 parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006372 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6373 pSMB->DataOffset = cpu_to_le16(offset);
6374 pSMB->SetupCount = 1;
6375 pSMB->Reserved3 = 0;
6376 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6377 byte_count = 3 /* pad */ + params + count;
6378 pSMB->DataCount = cpu_to_le16(count);
6379 parm_data->list_len = cpu_to_le32(count);
6380 parm_data->list[0].EA_flags = 0;
6381 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006382 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006383 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006384 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006385 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006386 parm_data->list[0].name[name_len] = 0;
6387 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6388 /* caller ensures that ea_value_len is less than 64K but
6389 we need to ensure that it fits within the smb */
6390
Steve French50c2f752007-07-13 00:33:32 +00006391 /*BB add length check to see if it would fit in
6392 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006393 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6394 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006395 memcpy(parm_data->list[0].name+name_len+1,
6396 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006397
6398 pSMB->TotalDataCount = pSMB->DataCount;
6399 pSMB->ParameterCount = cpu_to_le16(params);
6400 pSMB->TotalParameterCount = pSMB->ParameterCount;
6401 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006402 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006403 pSMB->ByteCount = cpu_to_le16(byte_count);
6404 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6405 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006406 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006407 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006408
6409 cifs_buf_release(pSMB);
6410
6411 if (rc == -EAGAIN)
6412 goto SetEARetry;
6413
6414 return rc;
6415}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006416#endif
Steve French0eff0e22011-02-24 05:39:23 +00006417
6418#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6419/*
6420 * Years ago the kernel added a "dnotify" function for Samba server,
6421 * to allow network clients (such as Windows) to display updated
6422 * lists of files in directory listings automatically when
6423 * files are added by one user when another user has the
6424 * same directory open on their desktop. The Linux cifs kernel
6425 * client hooked into the kernel side of this interface for
6426 * the same reason, but ironically when the VFS moved from
6427 * "dnotify" to "inotify" it became harder to plug in Linux
6428 * network file system clients (the most obvious use case
6429 * for notify interfaces is when multiple users can update
6430 * the contents of the same directory - exactly what network
6431 * file systems can do) although the server (Samba) could
6432 * still use it. For the short term we leave the worker
6433 * function ifdeffed out (below) until inotify is fixed
6434 * in the VFS to make it easier to plug in network file
6435 * system clients. If inotify turns out to be permanently
6436 * incompatible for network fs clients, we could instead simply
6437 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6438 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006439int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006440 const int notify_subdirs, const __u16 netfid,
6441 __u32 filter, struct file *pfile, int multishot,
6442 const struct nls_table *nls_codepage)
6443{
6444 int rc = 0;
6445 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6446 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6447 struct dir_notify_req *dnotify_req;
6448 int bytes_returned;
6449
Joe Perchesf96637b2013-05-04 22:12:25 -05006450 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006451 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6452 (void **) &pSMBr);
6453 if (rc)
6454 return rc;
6455
6456 pSMB->TotalParameterCount = 0 ;
6457 pSMB->TotalDataCount = 0;
6458 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006459 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006460 pSMB->MaxSetupCount = 4;
6461 pSMB->Reserved = 0;
6462 pSMB->ParameterOffset = 0;
6463 pSMB->DataCount = 0;
6464 pSMB->DataOffset = 0;
6465 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6466 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6467 pSMB->ParameterCount = pSMB->TotalParameterCount;
6468 if (notify_subdirs)
6469 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6470 pSMB->Reserved2 = 0;
6471 pSMB->CompletionFilter = cpu_to_le32(filter);
6472 pSMB->Fid = netfid; /* file handle always le */
6473 pSMB->ByteCount = 0;
6474
6475 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6476 (struct smb_hdr *)pSMBr, &bytes_returned,
6477 CIFS_ASYNC_OP);
6478 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006479 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006480 } else {
6481 /* Add file to outstanding requests */
6482 /* BB change to kmem cache alloc */
6483 dnotify_req = kmalloc(
6484 sizeof(struct dir_notify_req),
6485 GFP_KERNEL);
6486 if (dnotify_req) {
6487 dnotify_req->Pid = pSMB->hdr.Pid;
6488 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6489 dnotify_req->Mid = pSMB->hdr.Mid;
6490 dnotify_req->Tid = pSMB->hdr.Tid;
6491 dnotify_req->Uid = pSMB->hdr.Uid;
6492 dnotify_req->netfid = netfid;
6493 dnotify_req->pfile = pfile;
6494 dnotify_req->filter = filter;
6495 dnotify_req->multishot = multishot;
6496 spin_lock(&GlobalMid_Lock);
6497 list_add_tail(&dnotify_req->lhead,
6498 &GlobalDnotifyReqList);
6499 spin_unlock(&GlobalMid_Lock);
6500 } else
6501 rc = -ENOMEM;
6502 }
6503 cifs_buf_release(pSMB);
6504 return rc;
6505}
6506#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */