blob: 905d0fa1a1cca2247695885a64c5d2401e672a50 [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"
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
47#ifdef CONFIG_CIFS_POSIX
48static struct {
49 int index;
50 char *name;
51} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000052#ifdef CONFIG_CIFS_WEAK_PW_HASH
53 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000054 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000055#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000056 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000057 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 {BAD_PROT, "\2"}
59};
60#else
61static struct {
62 int index;
63 char *name;
64} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000065#ifdef CONFIG_CIFS_WEAK_PW_HASH
66 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000067 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000068#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000069 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 {BAD_PROT, "\2"}
71};
72#endif
73
Steve French39798772006-05-31 22:40:51 +000074/* define the number of elements in the cifs dialect array */
75#ifdef CONFIG_CIFS_POSIX
76#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000077#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000078#else
79#define CIFS_NUM_PROT 2
80#endif /* CIFS_WEAK_PW_HASH */
81#else /* not posix */
82#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000083#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000084#else
85#define CIFS_NUM_PROT 1
86#endif /* CONFIG_CIFS_WEAK_PW_HASH */
87#endif /* CIFS_POSIX */
88
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +040089/*
90 * Mark as invalid, all open files on tree connections since they
91 * were closed when session to server was lost.
92 */
93void
94cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070095{
96 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000097 struct list_head *tmp;
98 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400100 /* list all files open on tree connection and mark them invalid */
Steve French3afca262016-09-22 18:58:16 -0500101 spin_lock(&tcon->open_file_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400102 list_for_each_safe(tmp, tmp1, &tcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +0000103 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000104 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -0400105 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 }
Steve French3afca262016-09-22 18:58:16 -0500107 spin_unlock(&tcon->open_file_lock);
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400108 /*
109 * BB Add call to invalidate_inodes(sb) for all superblocks mounted
110 * to this tcon.
111 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112}
113
Jeff Layton9162ab22009-09-03 12:07:17 -0400114/* reconnect the socket, tcon, and smb session if needed */
115static int
Steve French96daf2b2011-05-27 04:34:02 +0000116cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400117{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400118 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000119 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400120 struct TCP_Server_Info *server;
121 struct nls_table *nls_codepage;
122
123 /*
124 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
125 * tcp and smb session status done differently for those three - in the
126 * calling routine
127 */
128 if (!tcon)
129 return 0;
130
131 ses = tcon->ses;
132 server = ses->server;
133
134 /*
135 * only tree disconnect, open, and write, (and ulogoff which does not
136 * have tcon) are allowed as we start force umount
137 */
138 if (tcon->tidStatus == CifsExiting) {
139 if (smb_command != SMB_COM_WRITE_ANDX &&
140 smb_command != SMB_COM_OPEN_ANDX &&
141 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500142 cifs_dbg(FYI, "can not send cmd %d while umounting\n",
143 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400144 return -ENODEV;
145 }
146 }
147
Jeff Layton9162ab22009-09-03 12:07:17 -0400148 /*
149 * Give demultiplex thread up to 10 seconds to reconnect, should be
150 * greater than cifs socket timeout which is 7 seconds
151 */
152 while (server->tcpStatus == CifsNeedReconnect) {
Paulo Alcantara28cada92018-07-05 13:46:34 -0300153 rc = wait_event_interruptible_timeout(server->response_q,
154 (server->tcpStatus != CifsNeedReconnect),
155 10 * HZ);
156 if (rc < 0) {
157 cifs_dbg(FYI, "%s: aborting reconnect due to a received"
158 " signal by the process\n", __func__);
159 return -ERESTARTSYS;
160 }
Jeff Layton9162ab22009-09-03 12:07:17 -0400161
Steve Frenchfd88ce92011-04-12 01:01:14 +0000162 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400163 if (server->tcpStatus != CifsNeedReconnect)
164 break;
165
166 /*
167 * on "soft" mounts we wait once. Hard mounts keep
168 * retrying until process is killed or server comes
169 * back on-line
170 */
Jeff Laytond4025392011-02-07 08:54:35 -0500171 if (!tcon->retry) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500172 cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
Jeff Layton9162ab22009-09-03 12:07:17 -0400173 return -EHOSTDOWN;
174 }
175 }
176
177 if (!ses->need_reconnect && !tcon->need_reconnect)
178 return 0;
179
180 nls_codepage = load_nls_default();
181
182 /*
183 * need to prevent multiple threads trying to simultaneously
184 * reconnect the same SMB session
185 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000186 mutex_lock(&ses->session_mutex);
Samuel Cabrero76e75272017-07-11 12:44:39 +0200187
188 /*
189 * Recheck after acquire mutex. If another thread is negotiating
190 * and the server never sends an answer the socket will be closed
191 * and tcpStatus set to reconnect.
192 */
193 if (server->tcpStatus == CifsNeedReconnect) {
194 rc = -EHOSTDOWN;
195 mutex_unlock(&ses->session_mutex);
196 goto out;
197 }
198
Jeff Layton198b5682010-04-24 07:57:48 -0400199 rc = cifs_negotiate_protocol(0, ses);
200 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400201 rc = cifs_setup_session(0, ses, nls_codepage);
202
203 /* do we need to reconnect tcon? */
204 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000205 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400206 goto out;
207 }
208
Pavel Shilovskyaa24d1e2011-12-27 16:23:34 +0400209 cifs_mark_open_files_invalid(tcon);
Jeff Layton9162ab22009-09-03 12:07:17 -0400210 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000211 mutex_unlock(&ses->session_mutex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500212 cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400213
214 if (rc)
215 goto out;
216
Jeff Layton9162ab22009-09-03 12:07:17 -0400217 atomic_inc(&tconInfoReconnectCount);
218
219 /* tell server Unix caps we support */
220 if (ses->capabilities & CAP_UNIX)
221 reset_cifs_unix_caps(0, tcon, NULL, NULL);
222
223 /*
224 * Removed call to reopen open files here. It is safer (and faster) to
225 * reopen files one at a time as needed in read and write.
226 *
227 * FIXME: what about file locks? don't we need to reclaim them ASAP?
228 */
229
230out:
231 /*
232 * Check if handle based operation so we know whether we can continue
233 * or not without returning to caller to reset file handle
234 */
235 switch (smb_command) {
236 case SMB_COM_READ_ANDX:
237 case SMB_COM_WRITE_ANDX:
238 case SMB_COM_CLOSE:
239 case SMB_COM_FIND_CLOSE2:
240 case SMB_COM_LOCKING_ANDX:
241 rc = -EAGAIN;
242 }
243
244 unload_nls(nls_codepage);
245 return rc;
246}
247
Steve Frenchad7a2922008-02-07 23:25:02 +0000248/* Allocate and return pointer to an SMB request buffer, and set basic
249 SMB information in the SMB header. If the return code is zero, this
250 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251static int
Steve French96daf2b2011-05-27 04:34:02 +0000252small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000253 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254{
Jeff Laytonf5695992010-09-29 15:27:08 -0400255 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256
Jeff Layton9162ab22009-09-03 12:07:17 -0400257 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000258 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 return rc;
260
261 *request_buf = cifs_small_buf_get();
262 if (*request_buf == NULL) {
263 /* BB should we add a retry in here if not a writepage? */
264 return -ENOMEM;
265 }
266
Steve French63135e02007-07-17 17:34:02 +0000267 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000268 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269
Steve French790fe572007-07-07 19:25:05 +0000270 if (tcon != NULL)
271 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700272
Jeff Laytonf5695992010-09-29 15:27:08 -0400273 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000274}
275
Steve French12b3b8f2006-02-09 21:12:47 +0000276int
Steve French50c2f752007-07-13 00:33:32 +0000277small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000278 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000279{
280 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000281 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000282
Steve French5815449d2006-02-14 01:36:20 +0000283 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000284 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000285 return rc;
286
Steve French04fdabe2006-02-10 05:52:50 +0000287 buffer = (struct smb_hdr *)*request_buf;
Pavel Shilovsky88257362012-05-23 14:01:59 +0400288 buffer->Mid = get_next_mid(ses->server);
Steve French12b3b8f2006-02-09 21:12:47 +0000289 if (ses->capabilities & CAP_UNICODE)
290 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000291 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000292 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
293
294 /* uid, tid can stay at zero as set in header assemble */
295
Steve French50c2f752007-07-13 00:33:32 +0000296 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000297 this function is used after 1st of session setup requests */
298
299 return rc;
300}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301
302/* If the return code is zero, this function must fill in request_buf pointer */
303static int
Steve French96daf2b2011-05-27 04:34:02 +0000304__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400305 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 *request_buf = cifs_buf_get();
308 if (*request_buf == NULL) {
309 /* BB should we add a retry in here if not a writepage? */
310 return -ENOMEM;
311 }
312 /* Although the original thought was we needed the response buf for */
313 /* potential retries of smb operations it turns out we can determine */
314 /* from the mid flags when the request buffer can be resent without */
315 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000316 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000317 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
319 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000320 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
Steve French790fe572007-07-07 19:25:05 +0000322 if (tcon != NULL)
323 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700324
Jeff Laytonf5695992010-09-29 15:27:08 -0400325 return 0;
326}
327
328/* If the return code is zero, this function must fill in request_buf pointer */
329static int
Steve French96daf2b2011-05-27 04:34:02 +0000330smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400331 void **request_buf, void **response_buf)
332{
333 int rc;
334
335 rc = cifs_reconnect_tcon(tcon, smb_command);
336 if (rc)
337 return rc;
338
339 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
340}
341
342static int
Steve French96daf2b2011-05-27 04:34:02 +0000343smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400344 void **request_buf, void **response_buf)
345{
346 if (tcon->ses->need_reconnect || tcon->need_reconnect)
347 return -EHOSTDOWN;
348
349 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350}
351
Steve French50c2f752007-07-13 00:33:32 +0000352static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353{
Jeff Layton12df83c2011-01-20 13:36:51 -0500354 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355
Jeff Layton12df83c2011-01-20 13:36:51 -0500356 /* check for plausible wct */
357 if (pSMB->hdr.WordCount < 10)
358 goto vt2_err;
359
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500361 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
362 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
363 goto vt2_err;
364
Jeff Layton12df83c2011-01-20 13:36:51 -0500365 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
366 if (total_size >= 512)
367 goto vt2_err;
368
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400369 /* check that bcc is at least as big as parms + data, and that it is
370 * less than negotiated smb buffer
371 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500372 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
373 if (total_size > get_bcc(&pSMB->hdr) ||
374 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
375 goto vt2_err;
376
377 return 0;
378vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000379 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500381 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382}
Jeff Layton690c5222011-01-20 13:36:51 -0500383
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400384static int
Jeff Layton3f618222013-06-12 19:52:14 -0500385decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400386{
387 int rc = 0;
388 u16 count;
389 char *guid = pSMBr->u.extended_response.GUID;
Jeff Layton3f618222013-06-12 19:52:14 -0500390 struct TCP_Server_Info *server = ses->server;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400391
392 count = get_bcc(&pSMBr->hdr);
393 if (count < SMB1_CLIENT_GUID_SIZE)
394 return -EIO;
395
396 spin_lock(&cifs_tcp_ses_lock);
397 if (server->srv_count > 1) {
398 spin_unlock(&cifs_tcp_ses_lock);
399 if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
400 cifs_dbg(FYI, "server UID changed\n");
401 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
402 }
403 } else {
404 spin_unlock(&cifs_tcp_ses_lock);
405 memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
406 }
407
408 if (count == SMB1_CLIENT_GUID_SIZE) {
Jeff Layton3f618222013-06-12 19:52:14 -0500409 server->sec_ntlmssp = true;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400410 } else {
411 count -= SMB1_CLIENT_GUID_SIZE;
412 rc = decode_negTokenInit(
413 pSMBr->u.extended_response.SecurityBlob, count, server);
414 if (rc != 1)
415 return -EINVAL;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400416 }
417
418 return 0;
419}
420
Jeff Layton9ddec562013-05-26 07:00:58 -0400421int
Jeff Layton38d77c52013-05-26 07:01:00 -0400422cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
Jeff Layton9ddec562013-05-26 07:00:58 -0400423{
Jeff Layton50285882013-06-27 12:45:00 -0400424 bool srv_sign_required = server->sec_mode & server->vals->signing_required;
425 bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled;
Jeff Layton38d77c52013-05-26 07:01:00 -0400426 bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN;
427
428 /*
429 * Is signing required by mnt options? If not then check
430 * global_secflags to see if it is there.
431 */
432 if (!mnt_sign_required)
433 mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
434 CIFSSEC_MUST_SIGN);
435
436 /*
437 * If signing is required then it's automatically enabled too,
438 * otherwise, check to see if the secflags allow it.
439 */
440 mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
441 (global_secflags & CIFSSEC_MAY_SIGN);
442
443 /* If server requires signing, does client allow it? */
444 if (srv_sign_required) {
445 if (!mnt_sign_enabled) {
446 cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!");
447 return -ENOTSUPP;
Jeff Layton9ddec562013-05-26 07:00:58 -0400448 }
Jeff Layton38d77c52013-05-26 07:01:00 -0400449 server->sign = true;
450 }
451
452 /* If client requires signing, does server allow it? */
453 if (mnt_sign_required) {
454 if (!srv_sign_enabled) {
455 cifs_dbg(VFS, "Server does not support signing!");
456 return -ENOTSUPP;
457 }
458 server->sign = true;
Jeff Layton9ddec562013-05-26 07:00:58 -0400459 }
460
461 return 0;
462}
463
Jeff Layton2190eca2013-05-26 07:00:57 -0400464#ifdef CONFIG_CIFS_WEAK_PW_HASH
465static int
Jeff Layton3f618222013-06-12 19:52:14 -0500466decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400467{
468 __s16 tmp;
469 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
470
471 if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
472 return -EOPNOTSUPP;
473
Jeff Layton2190eca2013-05-26 07:00:57 -0400474 server->sec_mode = le16_to_cpu(rsp->SecurityMode);
475 server->maxReq = min_t(unsigned int,
476 le16_to_cpu(rsp->MaxMpxCount),
477 cifs_max_pending);
478 set_credits(server, server->maxReq);
479 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Jeff Layton2190eca2013-05-26 07:00:57 -0400480 /* even though we do not use raw we might as well set this
481 accurately, in case we ever find a need for it */
482 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
483 server->max_rw = 0xFF00;
484 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
485 } else {
486 server->max_rw = 0;/* do not need to use raw anyway */
487 server->capabilities = CAP_MPX_MODE;
488 }
489 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
490 if (tmp == -1) {
491 /* OS/2 often does not set timezone therefore
492 * we must use server time to calc time zone.
493 * Could deviate slightly from the right zone.
494 * Smallest defined timezone difference is 15 minutes
495 * (i.e. Nepal). Rounding up/down is done to match
496 * this requirement.
497 */
498 int val, seconds, remain, result;
Deepa Dinamanie37fea52017-05-08 15:59:16 -0700499 struct timespec ts;
500 unsigned long utc = ktime_get_real_seconds();
Jeff Layton2190eca2013-05-26 07:00:57 -0400501 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
502 rsp->SrvTime.Time, 0);
503 cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
Deepa Dinamanie37fea52017-05-08 15:59:16 -0700504 (int)ts.tv_sec, (int)utc,
505 (int)(utc - ts.tv_sec));
506 val = (int)(utc - ts.tv_sec);
Jeff Layton2190eca2013-05-26 07:00:57 -0400507 seconds = abs(val);
508 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
509 remain = seconds % MIN_TZ_ADJ;
510 if (remain >= (MIN_TZ_ADJ / 2))
511 result += MIN_TZ_ADJ;
512 if (val < 0)
513 result = -result;
514 server->timeAdj = result;
515 } else {
516 server->timeAdj = (int)tmp;
517 server->timeAdj *= 60; /* also in seconds */
518 }
519 cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
520
521
522 /* BB get server time for time conversions and add
523 code to use it and timezone since this is not UTC */
524
525 if (rsp->EncryptionKeyLength ==
526 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
527 memcpy(server->cryptkey, rsp->EncryptionKey,
528 CIFS_CRYPTO_KEY_SIZE);
529 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
530 return -EIO; /* need cryptkey unless plain text */
531 }
532
533 cifs_dbg(FYI, "LANMAN negotiated\n");
534 return 0;
535}
536#else
537static inline int
Jeff Layton3f618222013-06-12 19:52:14 -0500538decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
Jeff Layton2190eca2013-05-26 07:00:57 -0400539{
540 cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
541 return -EOPNOTSUPP;
542}
543#endif
544
Jeff Layton91934002013-05-26 07:00:58 -0400545static bool
Jeff Layton3f618222013-06-12 19:52:14 -0500546should_set_ext_sec_flag(enum securityEnum sectype)
Jeff Layton91934002013-05-26 07:00:58 -0400547{
Jeff Layton3f618222013-06-12 19:52:14 -0500548 switch (sectype) {
549 case RawNTLMSSP:
550 case Kerberos:
Jeff Layton91934002013-05-26 07:00:58 -0400551 return true;
Jeff Layton3f618222013-06-12 19:52:14 -0500552 case Unspecified:
553 if (global_secflags &
554 (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
555 return true;
556 /* Fallthrough */
557 default:
558 return false;
559 }
Jeff Layton91934002013-05-26 07:00:58 -0400560}
561
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562int
Pavel Shilovsky286170a2012-05-25 10:43:58 +0400563CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564{
565 NEGOTIATE_REQ *pSMB;
566 NEGOTIATE_RSP *pSMBr;
567 int rc = 0;
568 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000569 int i;
Jeff Layton3534b852013-05-24 07:41:01 -0400570 struct TCP_Server_Info *server = ses->server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 u16 count;
572
Jeff Layton3534b852013-05-24 07:41:01 -0400573 if (!server) {
574 WARN(1, "%s: server is NULL!\n", __func__);
575 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 }
Jeff Layton3534b852013-05-24 07:41:01 -0400577
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
579 (void **) &pSMB, (void **) &pSMBr);
580 if (rc)
581 return rc;
Steve French750d1152006-06-27 06:28:30 +0000582
Pavel Shilovsky88257362012-05-23 14:01:59 +0400583 pSMB->hdr.Mid = get_next_mid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000584 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000585
Jeff Layton3f618222013-06-12 19:52:14 -0500586 if (should_set_ext_sec_flag(ses->sectype)) {
Jeff Layton91934002013-05-26 07:00:58 -0400587 cifs_dbg(FYI, "Requesting extended security.");
Steve Frenchac683922009-05-06 04:16:04 +0000588 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
589 }
Steve French50c2f752007-07-13 00:33:32 +0000590
Steve French39798772006-05-31 22:40:51 +0000591 count = 0;
Stephen Rothwella5bdc722018-09-03 13:15:58 +1000592 /*
593 * We know that all the name entries in the protocols array
594 * are short (< 16 bytes anyway) and are NUL terminated.
595 */
Steve French50c2f752007-07-13 00:33:32 +0000596 for (i = 0; i < CIFS_NUM_PROT; i++) {
Stephen Rothwella5bdc722018-09-03 13:15:58 +1000597 size_t len = strlen(protocols[i].name) + 1;
598
599 memcpy(pSMB->DialectsArray+count, protocols[i].name, len);
600 count += len;
Steve French39798772006-05-31 22:40:51 +0000601 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000602 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 pSMB->ByteCount = cpu_to_le16(count);
604
605 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
606 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000607 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000608 goto neg_err_exit;
609
Jeff Layton9bf67e52010-04-24 07:57:46 -0400610 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
Joe Perchesf96637b2013-05-04 22:12:25 -0500611 cifs_dbg(FYI, "Dialect: %d\n", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000612 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400613 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000614 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000615 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000616 could not negotiate a common dialect */
617 rc = -EOPNOTSUPP;
618 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000619 } else if (pSMBr->hdr.WordCount == 13) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400620 server->negflavor = CIFS_NEGFLAVOR_LANMAN;
Jeff Layton3f618222013-06-12 19:52:14 -0500621 rc = decode_lanman_negprot_rsp(server, pSMBr);
Jeff Layton9ddec562013-05-26 07:00:58 -0400622 goto signing_check;
Steve French790fe572007-07-07 19:25:05 +0000623 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000624 /* unknown wct */
625 rc = -EOPNOTSUPP;
626 goto neg_err_exit;
627 }
Jeff Layton2190eca2013-05-26 07:00:57 -0400628 /* else wct == 17, NTLM or better */
629
Steve French96daf2b2011-05-27 04:34:02 +0000630 server->sec_mode = pSMBr->SecurityMode;
631 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesf96637b2013-05-04 22:12:25 -0500632 cifs_dbg(FYI, "share mode security\n");
Steve French39798772006-05-31 22:40:51 +0000633
Steve French254e55e2006-06-04 05:53:15 +0000634 /* one byte, so no need to convert this or EncryptionKeyLen from
635 little endian */
Pavel Shilovsky10b9b982012-03-20 12:55:09 +0300636 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
637 cifs_max_pending);
Pavel Shilovsky45275782012-05-17 17:53:29 +0400638 set_credits(server, server->maxReq);
Steve French254e55e2006-06-04 05:53:15 +0000639 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400640 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000641 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesf96637b2013-05-04 22:12:25 -0500642 cifs_dbg(NOISY, "Max buf = %d\n", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000643 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000644 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
645 server->timeAdj *= 60;
Jeff Layton31d9e2b2013-05-26 07:00:57 -0400646
Jeff Laytone598d1d82013-05-26 07:00:59 -0400647 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
648 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500649 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000650 CIFS_CRYPTO_KEY_SIZE);
Noel Powerf2910952015-05-27 09:22:10 +0100651 } else if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
652 server->capabilities & CAP_EXTENDED_SECURITY) {
Jeff Laytone598d1d82013-05-26 07:00:59 -0400653 server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
Jeff Layton3f618222013-06-12 19:52:14 -0500654 rc = decode_ext_sec_blob(ses, pSMBr);
Jeff Laytone598d1d82013-05-26 07:00:59 -0400655 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000656 rc = -EIO; /* no crypt key only if plain text pwd */
Jeff Laytone598d1d82013-05-26 07:00:59 -0400657 } else {
658 server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
Steve French254e55e2006-06-04 05:53:15 +0000659 server->capabilities &= ~CAP_EXTENDED_SECURITY;
Jeff Laytone598d1d82013-05-26 07:00:59 -0400660 }
Steve French254e55e2006-06-04 05:53:15 +0000661
662signing_check:
Jeff Layton9ddec562013-05-26 07:00:58 -0400663 if (!rc)
Jeff Layton38d77c52013-05-26 07:01:00 -0400664 rc = cifs_enable_signing(server, ses->sign);
Steve French50c2f752007-07-13 00:33:32 +0000665neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700666 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000667
Joe Perchesf96637b2013-05-04 22:12:25 -0500668 cifs_dbg(FYI, "negprot rc %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 return rc;
670}
671
672int
Pavel Shilovsky2e6e02a2012-05-25 11:11:39 +0400673CIFSSMBTDis(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674{
675 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
Joe Perchesf96637b2013-05-04 22:12:25 -0500678 cifs_dbg(FYI, "In tree disconnect\n");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500679
680 /* BB: do we need to check this? These should never be NULL. */
681 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
682 return -EIO;
683
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500685 * No need to return error on this operation if tid invalidated and
686 * closed on server already e.g. due to tcp session crashing. Also,
687 * the tcon is no longer on the list, so no need to take lock before
688 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 */
Steve French268875b2009-06-25 00:29:21 +0000690 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000691 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
Steve French50c2f752007-07-13 00:33:32 +0000693 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700694 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500695 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 return rc;
Steve French133672e2007-11-13 22:41:37 +0000697
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400698 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700699 cifs_small_buf_release(smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500701 cifs_dbg(FYI, "Tree disconnect failed %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
Steve French50c2f752007-07-13 00:33:32 +0000703 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500704 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 if (rc == -EAGAIN)
706 rc = 0;
707
708 return rc;
709}
710
Jeff Layton766fdbb2011-01-11 07:24:21 -0500711/*
712 * This is a no-op for now. We're not really interested in the reply, but
713 * rather in the fact that the server sent one and that server->lstrp
714 * gets updated.
715 *
716 * FIXME: maybe we should consider checking that the reply matches request?
717 */
718static void
719cifs_echo_callback(struct mid_q_entry *mid)
720{
721 struct TCP_Server_Info *server = mid->callback_data;
722
723 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400724 add_credits(server, 1, CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500725}
726
727int
728CIFSSMBEcho(struct TCP_Server_Info *server)
729{
730 ECHO_REQ *smb;
731 int rc = 0;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800732 struct kvec iov[2];
733 struct smb_rqst rqst = { .rq_iov = iov,
734 .rq_nvec = 2 };
Jeff Layton766fdbb2011-01-11 07:24:21 -0500735
Joe Perchesf96637b2013-05-04 22:12:25 -0500736 cifs_dbg(FYI, "In echo request\n");
Jeff Layton766fdbb2011-01-11 07:24:21 -0500737
738 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
739 if (rc)
740 return rc;
741
Steve French26c9cb62017-05-02 13:35:20 -0500742 if (server->capabilities & CAP_UNICODE)
743 smb->hdr.Flags2 |= SMBFLG2_UNICODE;
744
Jeff Layton766fdbb2011-01-11 07:24:21 -0500745 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000746 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c82011-01-20 21:19:25 -0500747 smb->hdr.WordCount = 1;
748 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400749 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500750 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000751 inc_rfc1001_len(smb, 3);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -0800752
753 iov[0].iov_len = 4;
754 iov[0].iov_base = smb;
755 iov[1].iov_len = get_rfc1002_length(smb);
756 iov[1].iov_base = (char *)smb + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500757
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -0800758 rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL,
Pavel Shilovskya891f0f2012-05-23 16:14:34 +0400759 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500760 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500761 cifs_dbg(FYI, "Echo request failed: %d\n", rc);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500762
763 cifs_small_buf_release(smb);
764
765 return rc;
766}
767
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768int
Pavel Shilovsky58c45c52012-05-25 10:54:49 +0400769CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 LOGOFF_ANDX_REQ *pSMB;
772 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773
Joe Perchesf96637b2013-05-04 22:12:25 -0500774 cifs_dbg(FYI, "In SMBLogoff for session disconnect\n");
Jeff Layton14fbf502008-11-14 13:53:46 -0500775
776 /*
777 * BB: do we need to check validity of ses and server? They should
778 * always be valid since we have an active reference. If not, that
779 * should probably be a BUG()
780 */
781 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 return -EIO;
783
Steve Frenchd7b619c2010-02-25 05:36:46 +0000784 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000785 if (ses->need_reconnect)
786 goto session_already_dead; /* no need to send SMBlogoff if uid
787 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
789 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000790 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 return rc;
792 }
793
Pavel Shilovsky88257362012-05-23 14:01:59 +0400794 pSMB->hdr.Mid = get_next_mid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700795
Jeff Layton38d77c52013-05-26 07:01:00 -0400796 if (ses->server->sign)
797 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798
799 pSMB->hdr.Uid = ses->Suid;
800
801 pSMB->AndXCommand = 0xFF;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -0400802 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -0700803 cifs_small_buf_release(pSMB);
Steve French3b795212008-11-13 19:45:32 +0000804session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000805 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806
807 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000808 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 error */
810 if (rc == -EAGAIN)
811 rc = 0;
812 return rc;
813}
814
815int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400816CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
817 const char *fileName, __u16 type,
818 const struct nls_table *nls_codepage, int remap)
Steve French2d785a52007-07-15 01:48:57 +0000819{
820 TRANSACTION2_SPI_REQ *pSMB = NULL;
821 TRANSACTION2_SPI_RSP *pSMBr = NULL;
822 struct unlink_psx_rq *pRqD;
823 int name_len;
824 int rc = 0;
825 int bytes_returned = 0;
826 __u16 params, param_offset, offset, byte_count;
827
Joe Perchesf96637b2013-05-04 22:12:25 -0500828 cifs_dbg(FYI, "In POSIX delete\n");
Steve French2d785a52007-07-15 01:48:57 +0000829PsxDelete:
830 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
831 (void **) &pSMBr);
832 if (rc)
833 return rc;
834
835 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
836 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -0600837 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
838 PATH_MAX, nls_codepage, remap);
Steve French2d785a52007-07-15 01:48:57 +0000839 name_len++; /* trailing null */
840 name_len *= 2;
841 } else { /* BB add path length overrun check */
842 name_len = strnlen(fileName, PATH_MAX);
843 name_len++; /* trailing null */
844 strncpy(pSMB->FileName, fileName, name_len);
845 }
846
847 params = 6 + name_len;
848 pSMB->MaxParameterCount = cpu_to_le16(2);
849 pSMB->MaxDataCount = 0; /* BB double check this with jra */
850 pSMB->MaxSetupCount = 0;
851 pSMB->Reserved = 0;
852 pSMB->Flags = 0;
853 pSMB->Timeout = 0;
854 pSMB->Reserved2 = 0;
855 param_offset = offsetof(struct smb_com_transaction2_spi_req,
856 InformationLevel) - 4;
857 offset = param_offset + params;
858
859 /* Setup pointer to Request Data (inode type) */
860 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
861 pRqD->type = cpu_to_le16(type);
862 pSMB->ParameterOffset = cpu_to_le16(param_offset);
863 pSMB->DataOffset = cpu_to_le16(offset);
864 pSMB->SetupCount = 1;
865 pSMB->Reserved3 = 0;
866 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
867 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
868
869 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
870 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
871 pSMB->ParameterCount = cpu_to_le16(params);
872 pSMB->TotalParameterCount = pSMB->ParameterCount;
873 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
874 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000875 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000876 pSMB->ByteCount = cpu_to_le16(byte_count);
877 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
878 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000879 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500880 cifs_dbg(FYI, "Posix delete returned %d\n", rc);
Steve French2d785a52007-07-15 01:48:57 +0000881 cifs_buf_release(pSMB);
882
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400883 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve French2d785a52007-07-15 01:48:57 +0000884
885 if (rc == -EAGAIN)
886 goto PsxDelete;
887
888 return rc;
889}
890
891int
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700892CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
893 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894{
895 DELETE_FILE_REQ *pSMB = NULL;
896 DELETE_FILE_RSP *pSMBr = NULL;
897 int rc = 0;
898 int bytes_returned;
899 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500900 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901
902DelFileRetry:
903 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
904 (void **) &pSMBr);
905 if (rc)
906 return rc;
907
908 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700909 name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
910 PATH_MAX, cifs_sb->local_nls,
911 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 name_len++; /* trailing null */
913 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700914 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700915 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 name_len++; /* trailing null */
Pavel Shilovskyed6875e2012-09-18 16:20:25 -0700917 strncpy(pSMB->fileName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 }
919 pSMB->SearchAttributes =
920 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
921 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000922 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 pSMB->ByteCount = cpu_to_le16(name_len + 1);
924 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
925 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400926 cifs_stats_inc(&tcon->stats.cifs_stats.num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000927 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500928 cifs_dbg(FYI, "Error in RMFile = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929
930 cifs_buf_release(pSMB);
931 if (rc == -EAGAIN)
932 goto DelFileRetry;
933
934 return rc;
935}
936
937int
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400938CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
939 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940{
941 DELETE_DIRECTORY_REQ *pSMB = NULL;
942 DELETE_DIRECTORY_RSP *pSMBr = NULL;
943 int rc = 0;
944 int bytes_returned;
945 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500946 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
Joe Perchesf96637b2013-05-04 22:12:25 -0500948 cifs_dbg(FYI, "In CIFSSMBRmDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949RmDirRetry:
950 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
951 (void **) &pSMBr);
952 if (rc)
953 return rc;
954
955 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400956 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
957 PATH_MAX, cifs_sb->local_nls,
958 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 name_len++; /* trailing null */
960 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700961 } else { /* BB improve check for buffer overruns BB */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400962 name_len = strnlen(name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 name_len++; /* trailing null */
Pavel Shilovskyf958ca52012-07-10 16:14:18 +0400964 strncpy(pSMB->DirName, name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 }
966
967 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000968 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 pSMB->ByteCount = cpu_to_le16(name_len + 1);
970 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
971 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +0400972 cifs_stats_inc(&tcon->stats.cifs_stats.num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000973 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -0500974 cifs_dbg(FYI, "Error in RMDir = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975
976 cifs_buf_release(pSMB);
977 if (rc == -EAGAIN)
978 goto RmDirRetry;
979 return rc;
980}
981
982int
Pavel Shilovskyf4367202012-03-17 11:41:12 +0300983CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
984 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985{
986 int rc = 0;
987 CREATE_DIRECTORY_REQ *pSMB = NULL;
988 CREATE_DIRECTORY_RSP *pSMBr = NULL;
989 int bytes_returned;
990 int name_len;
Steve French2baa2682014-09-27 02:19:01 -0500991 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
Joe Perchesf96637b2013-05-04 22:12:25 -0500993 cifs_dbg(FYI, "In CIFSSMBMkDir\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994MkDirRetry:
995 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
996 (void **) &pSMBr);
997 if (rc)
998 return rc;
999
1000 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06001001 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
Pavel Shilovskyf4367202012-03-17 11:41:12 +03001002 PATH_MAX, cifs_sb->local_nls,
1003 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 name_len++; /* trailing null */
1005 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001006 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 name_len = strnlen(name, PATH_MAX);
1008 name_len++; /* trailing null */
1009 strncpy(pSMB->DirName, name, name_len);
1010 }
1011
1012 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001013 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1015 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1016 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001017 cifs_stats_inc(&tcon->stats.cifs_stats.num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001018 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001019 cifs_dbg(FYI, "Error in Mkdir = %d\n", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001020
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 cifs_buf_release(pSMB);
1022 if (rc == -EAGAIN)
1023 goto MkDirRetry;
1024 return rc;
1025}
1026
Steve French2dd29d32007-04-23 22:07:35 +00001027int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001028CIFSPOSIXCreate(const unsigned int xid, struct cifs_tcon *tcon,
1029 __u32 posix_flags, __u64 mode, __u16 *netfid,
1030 FILE_UNIX_BASIC_INFO *pRetData, __u32 *pOplock,
1031 const char *name, const struct nls_table *nls_codepage,
1032 int remap)
Steve French2dd29d32007-04-23 22:07:35 +00001033{
1034 TRANSACTION2_SPI_REQ *pSMB = NULL;
1035 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1036 int name_len;
1037 int rc = 0;
1038 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001039 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001040 OPEN_PSX_REQ *pdata;
1041 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001042
Joe Perchesf96637b2013-05-04 22:12:25 -05001043 cifs_dbg(FYI, "In POSIX Create\n");
Steve French2dd29d32007-04-23 22:07:35 +00001044PsxCreat:
1045 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1046 (void **) &pSMBr);
1047 if (rc)
1048 return rc;
1049
1050 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1051 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001052 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1053 PATH_MAX, nls_codepage, remap);
Steve French2dd29d32007-04-23 22:07:35 +00001054 name_len++; /* trailing null */
1055 name_len *= 2;
1056 } else { /* BB improve the check for buffer overruns BB */
1057 name_len = strnlen(name, PATH_MAX);
1058 name_len++; /* trailing null */
1059 strncpy(pSMB->FileName, name, name_len);
1060 }
1061
1062 params = 6 + name_len;
1063 count = sizeof(OPEN_PSX_REQ);
1064 pSMB->MaxParameterCount = cpu_to_le16(2);
1065 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1066 pSMB->MaxSetupCount = 0;
1067 pSMB->Reserved = 0;
1068 pSMB->Flags = 0;
1069 pSMB->Timeout = 0;
1070 pSMB->Reserved2 = 0;
1071 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001072 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001073 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001074 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001075 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001076 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001077 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001078 pdata->OpenFlags = cpu_to_le32(*pOplock);
1079 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1080 pSMB->DataOffset = cpu_to_le16(offset);
1081 pSMB->SetupCount = 1;
1082 pSMB->Reserved3 = 0;
1083 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1084 byte_count = 3 /* pad */ + params + count;
1085
1086 pSMB->DataCount = cpu_to_le16(count);
1087 pSMB->ParameterCount = cpu_to_le16(params);
1088 pSMB->TotalDataCount = pSMB->DataCount;
1089 pSMB->TotalParameterCount = pSMB->ParameterCount;
1090 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1091 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001092 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001093 pSMB->ByteCount = cpu_to_le16(byte_count);
1094 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1095 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1096 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001097 cifs_dbg(FYI, "Posix create returned %d\n", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001098 goto psx_create_err;
1099 }
1100
Joe Perchesf96637b2013-05-04 22:12:25 -05001101 cifs_dbg(FYI, "copying inode info\n");
Steve French2dd29d32007-04-23 22:07:35 +00001102 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1103
Jeff Layton820a8032011-05-04 08:05:26 -04001104 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001105 rc = -EIO; /* bad smb */
1106 goto psx_create_err;
1107 }
1108
1109 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001110 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001111 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001112
Steve French2dd29d32007-04-23 22:07:35 +00001113 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001114 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001115 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1116 /* Let caller know file was created so we can set the mode. */
1117 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001118 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001119 *pOplock |= CIFS_CREATE_ACTION;
1120 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001121 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1122 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesf96637b2013-05-04 22:12:25 -05001123 cifs_dbg(NOISY, "unknown type\n");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001124 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001125 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001126 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001127 cifs_dbg(VFS, "Open response data too small\n");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001128 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001129 goto psx_create_err;
1130 }
Steve French50c2f752007-07-13 00:33:32 +00001131 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001132 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001133 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001134 }
Steve French2dd29d32007-04-23 22:07:35 +00001135
1136psx_create_err:
1137 cifs_buf_release(pSMB);
1138
Steve French65bc98b2009-07-10 15:27:25 +00001139 if (posix_flags & SMB_O_DIRECTORY)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001140 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixmkdirs);
Steve French65bc98b2009-07-10 15:27:25 +00001141 else
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001142 cifs_stats_inc(&tcon->stats.cifs_stats.num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001143
1144 if (rc == -EAGAIN)
1145 goto PsxCreat;
1146
Steve French50c2f752007-07-13 00:33:32 +00001147 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001148}
1149
Steve Frencha9d02ad2005-08-24 23:06:05 -07001150static __u16 convert_disposition(int disposition)
1151{
1152 __u16 ofun = 0;
1153
1154 switch (disposition) {
1155 case FILE_SUPERSEDE:
1156 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1157 break;
1158 case FILE_OPEN:
1159 ofun = SMBOPEN_OAPPEND;
1160 break;
1161 case FILE_CREATE:
1162 ofun = SMBOPEN_OCREATE;
1163 break;
1164 case FILE_OPEN_IF:
1165 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1166 break;
1167 case FILE_OVERWRITE:
1168 ofun = SMBOPEN_OTRUNC;
1169 break;
1170 case FILE_OVERWRITE_IF:
1171 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1172 break;
1173 default:
Joe Perchesf96637b2013-05-04 22:12:25 -05001174 cifs_dbg(FYI, "unknown disposition %d\n", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001175 ofun = SMBOPEN_OAPPEND; /* regular open */
1176 }
1177 return ofun;
1178}
1179
Jeff Layton35fc37d2008-05-14 10:22:03 -07001180static int
1181access_flags_to_smbopen_mode(const int access_flags)
1182{
1183 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1184
1185 if (masked_flags == GENERIC_READ)
1186 return SMBOPEN_READ;
1187 else if (masked_flags == GENERIC_WRITE)
1188 return SMBOPEN_WRITE;
1189
1190 /* just go for read/write */
1191 return SMBOPEN_READWRITE;
1192}
1193
Steve Frencha9d02ad2005-08-24 23:06:05 -07001194int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001195SMBLegacyOpen(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001196 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001197 const int access_flags, const int create_options, __u16 *netfid,
1198 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001199 const struct nls_table *nls_codepage, int remap)
1200{
1201 int rc = -EACCES;
1202 OPENX_REQ *pSMB = NULL;
1203 OPENX_RSP *pSMBr = NULL;
1204 int bytes_returned;
1205 int name_len;
1206 __u16 count;
1207
1208OldOpenRetry:
1209 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1210 (void **) &pSMBr);
1211 if (rc)
1212 return rc;
1213
1214 pSMB->AndXCommand = 0xFF; /* none */
1215
1216 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1217 count = 1; /* account for one byte pad to word boundary */
1218 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06001219 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1220 fileName, PATH_MAX, nls_codepage, remap);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001221 name_len++; /* trailing null */
1222 name_len *= 2;
1223 } else { /* BB improve check for buffer overruns BB */
1224 count = 0; /* no pad */
1225 name_len = strnlen(fileName, PATH_MAX);
1226 name_len++; /* trailing null */
1227 strncpy(pSMB->fileName, fileName, name_len);
1228 }
1229 if (*pOplock & REQ_OPLOCK)
1230 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001231 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001232 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001233
Steve Frencha9d02ad2005-08-24 23:06:05 -07001234 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001235 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001236 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1237 /* set file as system file if special file such
1238 as fifo and server expecting SFU style and
1239 no Unix extensions */
1240
Steve French790fe572007-07-07 19:25:05 +00001241 if (create_options & CREATE_OPTION_SPECIAL)
1242 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001243 else /* BB FIXME BB */
1244 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001245
Jeff Layton67750fb2008-05-09 22:28:02 +00001246 if (create_options & CREATE_OPTION_READONLY)
1247 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001248
1249 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001250/* pSMB->CreateOptions = cpu_to_le32(create_options &
1251 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001252 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001253
1254 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001255 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001256 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001257 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001258
1259 pSMB->ByteCount = cpu_to_le16(count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001260 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001261 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001262 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001263 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001264 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001265 } else {
1266 /* BB verify if wct == 15 */
1267
Steve French582d21e2008-05-13 04:54:12 +00001268/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001269
1270 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1271 /* Let caller know file was created so we can set the mode. */
1272 /* Do we care about the CreateAction in any other cases? */
1273 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001274/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001275 *pOplock |= CIFS_CREATE_ACTION; */
1276 /* BB FIXME END */
1277
Steve French790fe572007-07-07 19:25:05 +00001278 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001279 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1280 pfile_info->LastAccessTime = 0; /* BB fixme */
1281 pfile_info->LastWriteTime = 0; /* BB fixme */
1282 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001283 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001284 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001285 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001286 pfile_info->AllocationSize =
1287 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1288 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001289 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001290 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001291 }
1292 }
1293
1294 cifs_buf_release(pSMB);
1295 if (rc == -EAGAIN)
1296 goto OldOpenRetry;
1297 return rc;
1298}
1299
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300int
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001301CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
1302 FILE_ALL_INFO *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303{
1304 int rc = -EACCES;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001305 OPEN_REQ *req = NULL;
1306 OPEN_RSP *rsp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 int bytes_returned;
1308 int name_len;
1309 __u16 count;
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001310 struct cifs_sb_info *cifs_sb = oparms->cifs_sb;
1311 struct cifs_tcon *tcon = oparms->tcon;
Steve French2baa2682014-09-27 02:19:01 -05001312 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001313 const struct nls_table *nls = cifs_sb->local_nls;
1314 int create_options = oparms->create_options;
1315 int desired_access = oparms->desired_access;
1316 int disposition = oparms->disposition;
1317 const char *path = oparms->path;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318
1319openRetry:
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001320 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **)&req,
1321 (void **)&rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 if (rc)
1323 return rc;
1324
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001325 /* no commands go after this */
1326 req->AndXCommand = 0xFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001328 if (req->hdr.Flags2 & SMBFLG2_UNICODE) {
1329 /* account for one byte pad to word boundary */
1330 count = 1;
1331 name_len = cifsConvertToUTF16((__le16 *)(req->fileName + 1),
1332 path, PATH_MAX, nls, remap);
1333 /* trailing null */
1334 name_len++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 name_len *= 2;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001336 req->NameLength = cpu_to_le16(name_len);
1337 } else {
1338 /* BB improve check for buffer overruns BB */
1339 /* no pad */
1340 count = 0;
1341 name_len = strnlen(path, PATH_MAX);
1342 /* trailing null */
1343 name_len++;
1344 req->NameLength = cpu_to_le16(name_len);
1345 strncpy(req->fileName, path, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 }
Jeff Layton67750fb2008-05-09 22:28:02 +00001347
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001348 if (*oplock & REQ_OPLOCK)
1349 req->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1350 else if (*oplock & REQ_BATCHOPLOCK)
1351 req->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1352
1353 req->DesiredAccess = cpu_to_le32(desired_access);
1354 req->AllocationSize = 0;
1355
1356 /*
1357 * Set file as system file if special file such as fifo and server
1358 * expecting SFU style and no Unix extensions.
1359 */
1360 if (create_options & CREATE_OPTION_SPECIAL)
1361 req->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1362 else
1363 req->FileAttributes = cpu_to_le32(ATTR_NORMAL);
1364
1365 /*
1366 * XP does not handle ATTR_POSIX_SEMANTICS but it helps speed up case
1367 * sensitive checks for other servers such as Samba.
1368 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 if (tcon->ses->capabilities & CAP_UNIX)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001370 req->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371
Jeff Layton67750fb2008-05-09 22:28:02 +00001372 if (create_options & CREATE_OPTION_READONLY)
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001373 req->FileAttributes |= cpu_to_le32(ATTR_READONLY);
Jeff Layton67750fb2008-05-09 22:28:02 +00001374
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001375 req->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1376 req->CreateDisposition = cpu_to_le32(disposition);
1377 req->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
1378
Steve French09d1db52005-04-28 22:41:08 -07001379 /* BB Expirement with various impersonation levels and verify */
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001380 req->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1381 req->SecurityFlags = SECURITY_CONTEXT_TRACKING|SECURITY_EFFECTIVE_ONLY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382
1383 count += name_len;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001384 inc_rfc1001_len(req, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001386 req->ByteCount = cpu_to_le16(count);
1387 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *)req,
1388 (struct smb_hdr *)rsp, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001389 cifs_stats_inc(&tcon->stats.cifs_stats.num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001391 cifs_dbg(FYI, "Error in Open = %d\n", rc);
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001392 cifs_buf_release(req);
1393 if (rc == -EAGAIN)
1394 goto openRetry;
1395 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001397
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001398 /* 1 byte no need to le_to_cpu */
1399 *oplock = rsp->OplockLevel;
1400 /* cifs fid stays in le */
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001401 oparms->fid->netfid = rsp->Fid;
Pavel Shilovsky9bf4fa02014-01-16 15:53:33 +04001402
1403 /* Let caller know file was created so we can set the mode. */
1404 /* Do we care about the CreateAction in any other cases? */
1405 if (cpu_to_le32(FILE_CREATE) == rsp->CreateAction)
1406 *oplock |= CIFS_CREATE_ACTION;
1407
1408 if (buf) {
1409 /* copy from CreationTime to Attributes */
1410 memcpy((char *)buf, (char *)&rsp->CreationTime, 36);
1411 /* the file_info buf is endian converted by caller */
1412 buf->AllocationSize = rsp->AllocationSize;
1413 buf->EndOfFile = rsp->EndOfFile;
1414 buf->NumberOfLinks = cpu_to_le32(1);
1415 buf->DeletePending = 0;
1416 }
1417
1418 cifs_buf_release(req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 return rc;
1420}
1421
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001422/*
1423 * Discard any remaining data in the current SMB. To do this, we borrow the
1424 * current bigbuf.
1425 */
Pavel Shilovskyc42a6ab2016-11-17 16:20:23 -08001426int
Pavel Shilovsky350be252017-04-10 10:31:33 -07001427cifs_discard_remaining_data(struct TCP_Server_Info *server)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001428{
Pavel Shilovsky350be252017-04-10 10:31:33 -07001429 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001430 int remaining = rfclen + 4 - server->total_read;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001431
1432 while (remaining > 0) {
1433 int length;
1434
1435 length = cifs_read_from_socket(server, server->bigbuf,
1436 min_t(unsigned int, remaining,
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001437 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001438 if (length < 0)
1439 return length;
1440 server->total_read += length;
1441 remaining -= length;
1442 }
1443
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001444 return 0;
1445}
1446
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001447static int
Pavel Shilovsky482592b2019-01-17 15:29:26 -08001448__cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid,
1449 bool malformed)
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001450{
1451 int length;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001452
Pavel Shilovsky350be252017-04-10 10:31:33 -07001453 length = cifs_discard_remaining_data(server);
Pavel Shilovsky482592b2019-01-17 15:29:26 -08001454 dequeue_mid(mid, malformed);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001455 mid->resp_buf = server->smallbuf;
1456 server->smallbuf = NULL;
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001457 return length;
1458}
1459
Pavel Shilovsky482592b2019-01-17 15:29:26 -08001460static int
1461cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1462{
1463 struct cifs_readdata *rdata = mid->callback_data;
1464
1465 return __cifs_readv_discard(server, mid, rdata->result);
1466}
1467
Pavel Shilovsky09a47072012-09-18 16:20:29 -07001468int
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001469cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1470{
1471 int length, len;
Jeff Layton8d5ce4d2012-05-16 07:13:16 -04001472 unsigned int data_offset, data_len;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001473 struct cifs_readdata *rdata = mid->callback_data;
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001474 char *buf = server->smallbuf;
1475 unsigned int buflen = get_rfc1002_length(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001476
Joe Perchesf96637b2013-05-04 22:12:25 -05001477 cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
1478 __func__, mid->mid, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001479
1480 /*
1481 * read the rest of READ_RSP header (sans Data array), or whatever we
1482 * can if there's not enough data. At this point, we've read down to
1483 * the Mid.
1484 */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001485 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
Pavel Shilovsky1887f602012-05-17 12:45:31 +04001486 HEADER_SIZE(server) + 1;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001487
Al Viroa6137302016-01-09 19:37:16 -05001488 length = cifs_read_from_socket(server,
1489 buf + HEADER_SIZE(server) - 1, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001490 if (length < 0)
1491 return length;
1492 server->total_read += length;
1493
Pavel Shilovsky511c54a2017-07-08 14:32:00 -07001494 if (server->ops->is_session_expired &&
1495 server->ops->is_session_expired(buf)) {
1496 cifs_reconnect(server);
1497 wake_up(&server->response_q);
1498 return -1;
1499 }
1500
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001501 if (server->ops->is_status_pending &&
1502 server->ops->is_status_pending(buf, server, 0)) {
Pavel Shilovsky350be252017-04-10 10:31:33 -07001503 cifs_discard_remaining_data(server);
Pavel Shilovsky6cc3b242016-02-27 11:58:18 +03001504 return -1;
1505 }
1506
Pavel Shilovsky482592b2019-01-17 15:29:26 -08001507 /* set up first two iov for signature check and to get credits */
1508 rdata->iov[0].iov_base = buf;
1509 rdata->iov[0].iov_len = 4;
1510 rdata->iov[1].iov_base = buf + 4;
1511 rdata->iov[1].iov_len = server->total_read - 4;
1512 cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
1513 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
1514 cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n",
1515 rdata->iov[1].iov_base, rdata->iov[1].iov_len);
1516
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001517 /* Was the SMB read successful? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001518 rdata->result = server->ops->map_error(buf, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001519 if (rdata->result != 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001520 cifs_dbg(FYI, "%s: server returned error %d\n",
1521 __func__, rdata->result);
Pavel Shilovsky482592b2019-01-17 15:29:26 -08001522 /* normal error on read response */
1523 return __cifs_readv_discard(server, mid, false);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001524 }
1525
1526 /* Is there enough to get to the rest of the READ_RSP header? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001527 if (server->total_read < server->vals->read_rsp_size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001528 cifs_dbg(FYI, "%s: server returned short header. got=%u expected=%zu\n",
1529 __func__, server->total_read,
1530 server->vals->read_rsp_size);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001531 rdata->result = -EIO;
1532 return cifs_readv_discard(server, mid);
1533 }
1534
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001535 data_offset = server->ops->read_data_offset(buf) + 4;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001536 if (data_offset < server->total_read) {
1537 /*
1538 * win2k8 sometimes sends an offset of 0 when the read
1539 * is beyond the EOF. Treat it as if the data starts just after
1540 * the header.
1541 */
Joe Perchesf96637b2013-05-04 22:12:25 -05001542 cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
1543 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001544 data_offset = server->total_read;
1545 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1546 /* data_offset is beyond the end of smallbuf */
Joe Perchesf96637b2013-05-04 22:12:25 -05001547 cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
1548 __func__, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001549 rdata->result = -EIO;
1550 return cifs_readv_discard(server, mid);
1551 }
1552
Joe Perchesf96637b2013-05-04 22:12:25 -05001553 cifs_dbg(FYI, "%s: total_read=%u data_offset=%u\n",
1554 __func__, server->total_read, data_offset);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001555
1556 len = data_offset - server->total_read;
1557 if (len > 0) {
1558 /* read any junk before data into the rest of smallbuf */
Al Viroa6137302016-01-09 19:37:16 -05001559 length = cifs_read_from_socket(server,
1560 buf + server->total_read, len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001561 if (length < 0)
1562 return length;
1563 server->total_read += length;
1564 }
1565
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001566 /* how much data is in the response? */
Pavel Shilovskyeb378712012-05-17 13:02:51 +04001567 data_len = server->ops->read_data_length(buf);
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001568 if (data_offset + data_len > buflen) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001569 /* data_len is corrupt -- discard frame */
1570 rdata->result = -EIO;
1571 return cifs_readv_discard(server, mid);
1572 }
1573
Jeff Layton8321fec2012-09-19 06:22:32 -07001574 length = rdata->read_into_pages(server, rdata, data_len);
1575 if (length < 0)
1576 return length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001577
Jeff Layton8321fec2012-09-19 06:22:32 -07001578 server->total_read += length;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001579
Joe Perchesf96637b2013-05-04 22:12:25 -05001580 cifs_dbg(FYI, "total_read=%u buflen=%u remaining=%u\n",
1581 server->total_read, buflen, data_len);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001582
1583 /* discard anything left over */
Pavel Shilovsky5ffef7b2012-03-23 14:28:03 -04001584 if (server->total_read < buflen)
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001585 return cifs_readv_discard(server, mid);
1586
1587 dequeue_mid(mid, false);
Pavel Shilovsky350be252017-04-10 10:31:33 -07001588 mid->resp_buf = server->smallbuf;
1589 server->smallbuf = NULL;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001590 return length;
1591}
1592
1593static void
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001594cifs_readv_callback(struct mid_q_entry *mid)
1595{
1596 struct cifs_readdata *rdata = mid->callback_data;
1597 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1598 struct TCP_Server_Info *server = tcon->ses->server;
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001599 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1600 .rq_nvec = 2,
Jeff Layton8321fec2012-09-19 06:22:32 -07001601 .rq_pages = rdata->pages,
1602 .rq_npages = rdata->nr_pages,
1603 .rq_pagesz = rdata->pagesz,
1604 .rq_tailsz = rdata->tailsz };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001605
Joe Perchesf96637b2013-05-04 22:12:25 -05001606 cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n",
1607 __func__, mid->mid, mid->mid_state, rdata->result,
1608 rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001609
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04001610 switch (mid->mid_state) {
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001611 case MID_RESPONSE_RECEIVED:
1612 /* result already set, check signature */
Jeff Layton38d77c52013-05-26 07:01:00 -04001613 if (server->sign) {
Steve French985e4ff02012-08-03 09:42:45 -05001614 int rc = 0;
1615
Jeff Laytonbf5ea0e2012-09-18 16:20:34 -07001616 rc = cifs_verify_signature(&rqst, server,
Jeff Layton0124cc42013-04-03 11:55:03 -04001617 mid->sequence_number);
Steve French985e4ff02012-08-03 09:42:45 -05001618 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001619 cifs_dbg(VFS, "SMB signature verification returned error = %d\n",
1620 rc);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001621 }
1622 /* FIXME: should this be counted toward the initiating task? */
Pavel Shilovsky34a54d62014-07-10 10:03:29 +04001623 task_io_account_read(rdata->got_bytes);
1624 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001625 break;
1626 case MID_REQUEST_SUBMITTED:
1627 case MID_RETRY_NEEDED:
1628 rdata->result = -EAGAIN;
Pavel Shilovskyd913ed12014-07-10 11:31:48 +04001629 if (server->sign && rdata->got_bytes)
1630 /* reset bytes number since we can not check a sign */
1631 rdata->got_bytes = 0;
1632 /* FIXME: should this be counted toward the initiating task? */
1633 task_io_account_read(rdata->got_bytes);
1634 cifs_stats_bytes_read(tcon, rdata->got_bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001635 break;
1636 default:
1637 rdata->result = -EIO;
1638 }
1639
Jeff Laytonda472fc2012-03-23 14:40:53 -04001640 queue_work(cifsiod_wq, &rdata->work);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001641 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04001642 add_credits(server, 1, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001643}
1644
1645/* cifs_async_readv - send an async write, and set up mid to handle result */
1646int
1647cifs_async_readv(struct cifs_readdata *rdata)
1648{
1649 int rc;
1650 READ_REQ *smb = NULL;
1651 int wct;
1652 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001653 struct smb_rqst rqst = { .rq_iov = rdata->iov,
1654 .rq_nvec = 2 };
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001655
Joe Perchesf96637b2013-05-04 22:12:25 -05001656 cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
1657 __func__, rdata->offset, rdata->bytes);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001658
1659 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1660 wct = 12;
1661 else {
1662 wct = 10; /* old style read */
1663 if ((rdata->offset >> 32) > 0) {
1664 /* can not handle this big offset for old */
1665 return -EIO;
1666 }
1667 }
1668
1669 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1670 if (rc)
1671 return rc;
1672
1673 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1674 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1675
1676 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001677 smb->Fid = rdata->cfile->fid.netfid;
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001678 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1679 if (wct == 12)
1680 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1681 smb->Remaining = 0;
1682 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1683 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1684 if (wct == 12)
1685 smb->ByteCount = 0;
1686 else {
1687 /* old style read */
1688 struct smb_com_readx_req *smbr =
1689 (struct smb_com_readx_req *)smb;
1690 smbr->ByteCount = 0;
1691 }
1692
1693 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08001694 rdata->iov[0].iov_base = smb;
1695 rdata->iov[0].iov_len = 4;
1696 rdata->iov[1].iov_base = (char *)smb + 4;
1697 rdata->iov[1].iov_len = get_rfc1002_length(smb);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001698
Jeff Layton6993f742012-05-16 07:13:17 -04001699 kref_get(&rdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07001700 rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive,
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -08001701 cifs_readv_callback, NULL, rdata, 0);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001702
1703 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001704 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Jeff Layton6993f742012-05-16 07:13:17 -04001705 else
1706 kref_put(&rdata->refcount, cifs_readdata_release);
Jeff Laytone28bc5b2011-10-19 15:30:07 -04001707
1708 cifs_small_buf_release(smb);
1709 return rc;
1710}
1711
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001713CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
1714 unsigned int *nbytes, char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715{
1716 int rc = -EACCES;
1717 READ_REQ *pSMB = NULL;
1718 READ_RSP *pSMBr = NULL;
1719 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001720 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001721 int resp_buf_type = 0;
1722 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001723 struct kvec rsp_iov;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001724 __u32 pid = io_parms->pid;
1725 __u16 netfid = io_parms->netfid;
1726 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001727 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001728 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729
Joe Perchesf96637b2013-05-04 22:12:25 -05001730 cifs_dbg(FYI, "Reading %d bytes on fid %d\n", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001731 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001732 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001733 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001734 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001735 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001736 /* can not handle this big offset for old */
1737 return -EIO;
1738 }
1739 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740
1741 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001742 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 if (rc)
1744 return rc;
1745
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001746 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1747 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1748
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 /* tcon and ses pointer are checked in smb_init */
1750 if (tcon->ses->server == NULL)
1751 return -ECONNABORTED;
1752
Steve Frenchec637e32005-12-12 20:53:18 -08001753 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001755 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001756 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001757 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001758
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 pSMB->Remaining = 0;
1760 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1761 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001762 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001763 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1764 else {
1765 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001766 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001767 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001768 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001769 }
Steve Frenchec637e32005-12-12 20:53:18 -08001770
1771 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001772 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001773 rc = SendReceive2(xid, tcon->ses, iov, 1, &resp_buf_type,
1774 CIFS_LOG_ERROR, &rsp_iov);
1775 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001776 cifs_stats_inc(&tcon->stats.cifs_stats.num_reads);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001777 pSMBr = (READ_RSP *)rsp_iov.iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001779 cifs_dbg(VFS, "Send error in read = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 } else {
1781 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1782 data_length = data_length << 16;
1783 data_length += le16_to_cpu(pSMBr->DataLength);
1784 *nbytes = data_length;
1785
1786 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001787 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 || (data_length > count)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001789 cifs_dbg(FYI, "bad length %d for count %d\n",
Joe Perchesb6b38f72010-04-21 03:50:45 +00001790 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 rc = -EIO;
1792 *nbytes = 0;
1793 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001794 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001795 le16_to_cpu(pSMBr->DataOffset);
1796/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001797 cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
Steve French50c2f752007-07-13 00:33:32 +00001798 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001799 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001800 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001801 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 }
1803 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804
Steve French790fe572007-07-07 19:25:05 +00001805 if (*buf) {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001806 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French790fe572007-07-07 19:25:05 +00001807 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001808 /* return buffer to caller to free */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07001809 *buf = rsp_iov.iov_base;
Steve French790fe572007-07-07 19:25:05 +00001810 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001811 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001812 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001813 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001814 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001815
1816 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 since file handle passed in no longer valid */
1818 return rc;
1819}
1820
Steve Frenchec637e32005-12-12 20:53:18 -08001821
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001823CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
Al Virodbbab322016-09-05 17:53:43 -04001824 unsigned int *nbytes, const char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825{
1826 int rc = -EACCES;
1827 WRITE_REQ *pSMB = NULL;
1828 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001829 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 __u32 bytes_sent;
1831 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001832 __u32 pid = io_parms->pid;
1833 __u16 netfid = io_parms->netfid;
1834 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001835 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001836 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837
Steve Frencha24e2d72010-04-03 17:20:21 +00001838 *nbytes = 0;
1839
Joe Perchesf96637b2013-05-04 22:12:25 -05001840 /* cifs_dbg(FYI, "write at %lld %d bytes\n", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001841 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001842 return -ECONNABORTED;
1843
Steve French790fe572007-07-07 19:25:05 +00001844 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001845 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001846 else {
Steve French1c955182005-08-30 20:58:07 -07001847 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001848 if ((offset >> 32) > 0) {
1849 /* can not handle big offset for old srv */
1850 return -EIO;
1851 }
1852 }
Steve French1c955182005-08-30 20:58:07 -07001853
1854 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 (void **) &pSMBr);
1856 if (rc)
1857 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001858
1859 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1860 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1861
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 /* tcon and ses pointer are checked in smb_init */
1863 if (tcon->ses->server == NULL)
1864 return -ECONNABORTED;
1865
1866 pSMB->AndXCommand = 0xFF; /* none */
1867 pSMB->Fid = netfid;
1868 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001869 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001870 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001871
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 pSMB->Reserved = 0xFFFFFFFF;
1873 pSMB->WriteMode = 0;
1874 pSMB->Remaining = 0;
1875
Steve French50c2f752007-07-13 00:33:32 +00001876 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 can send more if LARGE_WRITE_X capability returned by the server and if
1878 our buffer is big enough or if we convert to iovecs on socket writes
1879 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001880 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1882 } else {
1883 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1884 & ~0xFF;
1885 }
1886
1887 if (bytes_sent > count)
1888 bytes_sent = count;
1889 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001890 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001891 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001892 memcpy(pSMB->Data, buf, bytes_sent);
Al Virodbbab322016-09-05 17:53:43 -04001893 else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 /* No buffer */
1895 cifs_buf_release(pSMB);
1896 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001897 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001898 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001899 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001900 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001901 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001902
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1904 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001905 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001906
Steve French790fe572007-07-07 19:25:05 +00001907 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001908 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001909 else { /* old style write has byte count 4 bytes earlier
1910 so 4 bytes pad */
1911 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001912 (struct smb_com_writex_req *)pSMB;
1913 pSMBW->ByteCount = cpu_to_le16(byte_count);
1914 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915
1916 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Al Virodbbab322016-09-05 17:53:43 -04001917 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04001918 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001920 cifs_dbg(FYI, "Send error in write = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 } else {
1922 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1923 *nbytes = (*nbytes) << 16;
1924 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301925
1926 /*
1927 * Mask off high 16 bits when bytes written as returned by the
1928 * server is greater than bytes requested by the client. Some
1929 * OS/2 servers are known to set incorrect CountHigh values.
1930 */
1931 if (*nbytes > count)
1932 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 }
1934
1935 cifs_buf_release(pSMB);
1936
Steve French50c2f752007-07-13 00:33:32 +00001937 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 since file handle passed in no longer valid */
1939
1940 return rc;
1941}
1942
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001943void
1944cifs_writedata_release(struct kref *refcount)
1945{
1946 struct cifs_writedata *wdata = container_of(refcount,
1947 struct cifs_writedata, refcount);
1948
1949 if (wdata->cfile)
1950 cifsFileInfo_put(wdata->cfile);
1951
1952 kfree(wdata);
1953}
1954
1955/*
1956 * Write failed with a retryable error. Resend the write request. It's also
1957 * possible that the page was redirtied so re-clean the page.
1958 */
1959static void
1960cifs_writev_requeue(struct cifs_writedata *wdata)
1961{
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001962 int i, rc = 0;
David Howells2b0143b2015-03-17 22:25:59 +00001963 struct inode *inode = d_inode(wdata->cfile->dentry);
Pavel Shilovskyc9de5c82012-09-18 16:20:29 -07001964 struct TCP_Server_Info *server;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001965 unsigned int rest_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001966
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001967 server = tlink_tcon(wdata->cfile->tlink)->ses->server;
1968 i = 0;
1969 rest_len = wdata->bytes;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001970 do {
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001971 struct cifs_writedata *wdata2;
1972 unsigned int j, nr_pages, wsize, tailsz, cur_len;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001973
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001974 wsize = server->ops->wp_retry_size(inode);
1975 if (wsize < rest_len) {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001976 nr_pages = wsize / PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001977 if (!nr_pages) {
1978 rc = -ENOTSUPP;
1979 break;
1980 }
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001981 cur_len = nr_pages * PAGE_SIZE;
1982 tailsz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001983 } else {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001984 nr_pages = DIV_ROUND_UP(rest_len, PAGE_SIZE);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001985 cur_len = rest_len;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03001986 tailsz = rest_len - (nr_pages - 1) * PAGE_SIZE;
Ouyang Maochunc51bb0e2013-02-18 09:54:52 -06001987 }
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04001988
1989 wdata2 = cifs_writedata_alloc(nr_pages, cifs_writev_complete);
1990 if (!wdata2) {
1991 rc = -ENOMEM;
1992 break;
1993 }
1994
1995 for (j = 0; j < nr_pages; j++) {
1996 wdata2->pages[j] = wdata->pages[i + j];
1997 lock_page(wdata2->pages[j]);
1998 clear_page_dirty_for_io(wdata2->pages[j]);
1999 }
2000
2001 wdata2->sync_mode = wdata->sync_mode;
2002 wdata2->nr_pages = nr_pages;
2003 wdata2->offset = page_offset(wdata2->pages[0]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002004 wdata2->pagesz = PAGE_SIZE;
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002005 wdata2->tailsz = tailsz;
2006 wdata2->bytes = cur_len;
2007
2008 wdata2->cfile = find_writable_file(CIFS_I(inode), false);
2009 if (!wdata2->cfile) {
2010 cifs_dbg(VFS, "No writable handles for inode\n");
2011 rc = -EBADF;
2012 break;
2013 }
2014 wdata2->pid = wdata2->cfile->pid;
2015 rc = server->ops->async_writev(wdata2, cifs_writedata_release);
2016
2017 for (j = 0; j < nr_pages; j++) {
2018 unlock_page(wdata2->pages[j]);
2019 if (rc != 0 && rc != -EAGAIN) {
2020 SetPageError(wdata2->pages[j]);
2021 end_page_writeback(wdata2->pages[j]);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002022 put_page(wdata2->pages[j]);
Pavel Shilovsky7f6c5002014-06-22 11:03:22 +04002023 }
2024 }
2025
2026 if (rc) {
2027 kref_put(&wdata2->refcount, cifs_writedata_release);
2028 if (rc == -EAGAIN)
2029 continue;
2030 break;
2031 }
2032
2033 rest_len -= cur_len;
2034 i += nr_pages;
2035 } while (i < wdata->nr_pages);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002036
2037 mapping_set_error(inode->i_mapping, rc);
2038 kref_put(&wdata->refcount, cifs_writedata_release);
2039}
2040
Jeff Laytonc2e87642012-03-23 14:40:55 -04002041void
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002042cifs_writev_complete(struct work_struct *work)
2043{
2044 struct cifs_writedata *wdata = container_of(work,
2045 struct cifs_writedata, work);
David Howells2b0143b2015-03-17 22:25:59 +00002046 struct inode *inode = d_inode(wdata->cfile->dentry);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002047 int i = 0;
2048
2049 if (wdata->result == 0) {
Jeff Layton597b0272012-03-23 14:40:56 -04002050 spin_lock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002051 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
Jeff Layton597b0272012-03-23 14:40:56 -04002052 spin_unlock(&inode->i_lock);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002053 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
2054 wdata->bytes);
2055 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
2056 return cifs_writev_requeue(wdata);
2057
2058 for (i = 0; i < wdata->nr_pages; i++) {
2059 struct page *page = wdata->pages[i];
2060 if (wdata->result == -EAGAIN)
2061 __set_page_dirty_nobuffers(page);
2062 else if (wdata->result < 0)
2063 SetPageError(page);
2064 end_page_writeback(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +03002065 put_page(page);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002066 }
2067 if (wdata->result != -EAGAIN)
2068 mapping_set_error(inode->i_mapping, wdata->result);
2069 kref_put(&wdata->refcount, cifs_writedata_release);
2070}
2071
2072struct cifs_writedata *
Jeff Laytonc2e87642012-03-23 14:40:55 -04002073cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002074{
2075 struct cifs_writedata *wdata;
2076
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002077 /* writedata + number of page pointers */
2078 wdata = kzalloc(sizeof(*wdata) +
Jeff Layton26c8f0d2014-02-07 11:04:04 -05002079 sizeof(struct page *) * nr_pages, GFP_NOFS);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002080 if (wdata != NULL) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002081 kref_init(&wdata->refcount);
Jeff Laytonda82f7e2012-03-23 14:40:56 -04002082 INIT_LIST_HEAD(&wdata->list);
2083 init_completion(&wdata->done);
2084 INIT_WORK(&wdata->work, complete);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002085 }
2086 return wdata;
2087}
2088
2089/*
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002090 * Check the mid_state and signature on received buffer (if any), and queue the
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002091 * workqueue completion task.
2092 */
2093static void
2094cifs_writev_callback(struct mid_q_entry *mid)
2095{
2096 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00002097 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002098 unsigned int written;
2099 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2100
Pavel Shilovsky7c9421e2012-03-23 14:28:03 -04002101 switch (mid->mid_state) {
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002102 case MID_RESPONSE_RECEIVED:
2103 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2104 if (wdata->result != 0)
2105 break;
2106
2107 written = le16_to_cpu(smb->CountHigh);
2108 written <<= 16;
2109 written += le16_to_cpu(smb->Count);
2110 /*
2111 * Mask off high 16 bits when bytes written as returned
2112 * by the server is greater than bytes requested by the
2113 * client. OS/2 servers are known to set incorrect
2114 * CountHigh values.
2115 */
2116 if (written > wdata->bytes)
2117 written &= 0xFFFF;
2118
2119 if (written < wdata->bytes)
2120 wdata->result = -ENOSPC;
2121 else
2122 wdata->bytes = written;
2123 break;
2124 case MID_REQUEST_SUBMITTED:
2125 case MID_RETRY_NEEDED:
2126 wdata->result = -EAGAIN;
2127 break;
2128 default:
2129 wdata->result = -EIO;
2130 break;
2131 }
2132
Jeff Laytonda472fc2012-03-23 14:40:53 -04002133 queue_work(cifsiod_wq, &wdata->work);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002134 DeleteMidQEntry(mid);
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002135 add_credits(tcon->ses->server, 1, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002136}
2137
2138/* cifs_async_writev - send an async write, and set up mid to handle result */
2139int
Steve French4a5c80d2014-02-07 20:45:12 -06002140cifs_async_writev(struct cifs_writedata *wdata,
2141 void (*release)(struct kref *kref))
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002142{
Jeff Laytoneddb0792012-09-18 16:20:35 -07002143 int rc = -EACCES;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002144 WRITE_REQ *smb = NULL;
2145 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00002146 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002147 struct kvec iov[2];
Jeff Laytonfec344e2012-09-18 16:20:35 -07002148 struct smb_rqst rqst = { };
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002149
2150 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2151 wct = 14;
2152 } else {
2153 wct = 12;
2154 if (wdata->offset >> 32 > 0) {
2155 /* can not handle big offset for old srv */
2156 return -EIO;
2157 }
2158 }
2159
2160 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2161 if (rc)
2162 goto async_writev_out;
2163
Jeff Laytonfe5f5d22012-03-23 14:40:55 -04002164 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2165 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002166
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002167 smb->AndXCommand = 0xFF; /* none */
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07002168 smb->Fid = wdata->cfile->fid.netfid;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002169 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2170 if (wct == 14)
2171 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2172 smb->Reserved = 0xFFFFFFFF;
2173 smb->WriteMode = 0;
2174 smb->Remaining = 0;
2175
2176 smb->DataOffset =
2177 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2178
2179 /* 4 for RFC1001 length + 1 for BCC */
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002180 iov[0].iov_len = 4;
2181 iov[0].iov_base = smb;
2182 iov[1].iov_len = get_rfc1002_length(smb) + 1;
2183 iov[1].iov_base = (char *)smb + 4;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002184
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002185 rqst.rq_iov = iov;
2186 rqst.rq_nvec = 2;
Jeff Laytoneddb0792012-09-18 16:20:35 -07002187 rqst.rq_pages = wdata->pages;
2188 rqst.rq_npages = wdata->nr_pages;
2189 rqst.rq_pagesz = wdata->pagesz;
2190 rqst.rq_tailsz = wdata->tailsz;
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002191
Joe Perchesf96637b2013-05-04 22:12:25 -05002192 cifs_dbg(FYI, "async write at %llu %u bytes\n",
2193 wdata->offset, wdata->bytes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002194
2195 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2196 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2197
2198 if (wct == 14) {
2199 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2200 put_bcc(wdata->bytes + 1, &smb->hdr);
2201 } else {
2202 /* wct == 12 */
2203 struct smb_com_writex_req *smbw =
2204 (struct smb_com_writex_req *)smb;
2205 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2206 put_bcc(wdata->bytes + 5, &smbw->hdr);
Pavel Shilovsky738f9de2016-11-23 15:14:57 -08002207 iov[1].iov_len += 4; /* pad bigger by four bytes */
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002208 }
2209
2210 kref_get(&wdata->refcount);
Jeff Laytonfec344e2012-09-18 16:20:35 -07002211 rc = cifs_call_async(tcon->ses->server, &rqst, NULL,
Pavel Shilovsky9b7c18a2016-11-16 14:06:17 -08002212 cifs_writev_callback, NULL, wdata, 0);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002213
2214 if (rc == 0)
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002215 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002216 else
Steve French4a5c80d2014-02-07 20:45:12 -06002217 kref_put(&wdata->refcount, release);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002218
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002219async_writev_out:
2220 cifs_small_buf_release(smb);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04002221 return rc;
2222}
2223
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002224int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002225CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
Pavel Shilovskyba9ad7252012-09-18 16:20:30 -07002226 unsigned int *nbytes, struct kvec *iov, int n_vec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227{
2228 int rc = -EACCES;
2229 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08002230 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002231 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08002232 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002233 __u32 pid = io_parms->pid;
2234 __u16 netfid = io_parms->netfid;
2235 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00002236 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002237 unsigned int count = io_parms->length;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002238 struct kvec rsp_iov;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04002240 *nbytes = 0;
2241
Joe Perchesf96637b2013-05-04 22:12:25 -05002242 cifs_dbg(FYI, "write2 at %lld %d bytes\n", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08002243
Steve French4c3130e2008-12-09 00:28:16 +00002244 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07002245 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00002246 } else {
Steve French8cc64c62005-10-03 13:49:43 -07002247 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00002248 if ((offset >> 32) > 0) {
2249 /* can not handle big offset for old srv */
2250 return -EIO;
2251 }
2252 }
Steve French8cc64c62005-10-03 13:49:43 -07002253 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 if (rc)
2255 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04002256
2257 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2258 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2259
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 /* tcon and ses pointer are checked in smb_init */
2261 if (tcon->ses->server == NULL)
2262 return -ECONNABORTED;
2263
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002264 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 pSMB->Fid = netfid;
2266 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00002267 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002268 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 pSMB->Reserved = 0xFFFFFFFF;
2270 pSMB->WriteMode = 0;
2271 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002272
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00002274 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275
Steve French3e844692005-10-03 13:37:24 -07002276 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2277 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002278 /* header + 1 byte pad */
2279 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00002280 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002281 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07002282 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002283 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00002284 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07002285 pSMB->ByteCount = cpu_to_le16(count + 1);
2286 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00002287 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07002288 (struct smb_com_writex_req *)pSMB;
2289 pSMBW->ByteCount = cpu_to_le16(count + 5);
2290 }
Steve French3e844692005-10-03 13:37:24 -07002291 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00002292 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08002293 iov[0].iov_len = smb_hdr_len + 4;
2294 else /* wct == 12 pad bigger by four bytes */
2295 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00002296
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002297 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0,
2298 &rsp_iov);
2299 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002300 cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002302 cifs_dbg(FYI, "Send error Write2 = %d\n", rc);
Steve French790fe572007-07-07 19:25:05 +00002303 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08002304 /* presumably this can not happen, but best to be safe */
2305 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002306 } else {
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002307 WRITE_RSP *pSMBr = (WRITE_RSP *)rsp_iov.iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002308 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2309 *nbytes = (*nbytes) << 16;
2310 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05302311
2312 /*
2313 * Mask off high 16 bits when bytes written as returned by the
2314 * server is greater than bytes requested by the client. OS/2
2315 * servers are known to set incorrect CountHigh values.
2316 */
2317 if (*nbytes > count)
2318 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00002319 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002321 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322
Steve French50c2f752007-07-13 00:33:32 +00002323 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 since file handle passed in no longer valid */
2325
2326 return rc;
2327}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002328
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002329int cifs_lockv(const unsigned int xid, struct cifs_tcon *tcon,
2330 const __u16 netfid, const __u8 lock_type, const __u32 num_unlock,
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002331 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2332{
2333 int rc = 0;
2334 LOCK_REQ *pSMB = NULL;
2335 struct kvec iov[2];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002336 struct kvec rsp_iov;
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002337 int resp_buf_type;
2338 __u16 count;
2339
Joe Perchesf96637b2013-05-04 22:12:25 -05002340 cifs_dbg(FYI, "cifs_lockv num lock %d num unlock %d\n",
2341 num_lock, num_unlock);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002342
2343 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2344 if (rc)
2345 return rc;
2346
2347 pSMB->Timeout = 0;
2348 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2349 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2350 pSMB->LockType = lock_type;
2351 pSMB->AndXCommand = 0xFF; /* none */
2352 pSMB->Fid = netfid; /* netfid stays le */
2353
2354 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2355 inc_rfc1001_len(pSMB, count);
2356 pSMB->ByteCount = cpu_to_le16(count);
2357
2358 iov[0].iov_base = (char *)pSMB;
2359 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2360 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2361 iov[1].iov_base = (char *)buf;
2362 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2363
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002364 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002365 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP,
2366 &rsp_iov);
2367 cifs_small_buf_release(pSMB);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002368 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002369 cifs_dbg(FYI, "Send error in cifs_lockv = %d\n", rc);
Pavel Shilovsky9ee305b2011-10-22 15:33:31 +04002370
2371 return rc;
2372}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05002373
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002375CIFSSMBLock(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002376 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002378 const __u32 numLock, const __u8 lockType,
2379 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380{
2381 int rc = 0;
2382 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002383/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 int bytes_returned;
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002385 int flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 __u16 count;
2387
Joe Perchesf96637b2013-05-04 22:12:25 -05002388 cifs_dbg(FYI, "CIFSSMBLock timeout %d numLock %d\n",
2389 (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07002390 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2391
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392 if (rc)
2393 return rc;
2394
Steve French790fe572007-07-07 19:25:05 +00002395 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002396 /* no response expected */
2397 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00002399 } else if (waitFlag) {
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002400 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2402 } else {
2403 pSMB->Timeout = 0;
2404 }
2405
2406 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2407 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2408 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002409 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 pSMB->AndXCommand = 0xFF; /* none */
2411 pSMB->Fid = smb_file_id; /* netfid stays le */
2412
Steve French790fe572007-07-07 19:25:05 +00002413 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002414 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 /* BB where to store pid high? */
2416 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2417 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2418 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2419 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2420 count = sizeof(LOCKING_ANDX_RANGE);
2421 } else {
2422 /* oplock break */
2423 count = 0;
2424 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002425 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426 pSMB->ByteCount = cpu_to_le16(count);
2427
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002428 if (waitFlag)
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002429 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002430 (struct smb_hdr *) pSMB, &bytes_returned);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002431 else
Pavel Shilovskya891f0f2012-05-23 16:14:34 +04002432 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002433 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002434 cifs_stats_inc(&tcon->stats.cifs_stats.num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002435 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002436 cifs_dbg(FYI, "Send error in Lock = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437
Steve French50c2f752007-07-13 00:33:32 +00002438 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 since file handle passed in no longer valid */
2440 return rc;
2441}
2442
2443int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002444CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002445 const __u16 smb_file_id, const __u32 netpid,
2446 const loff_t start_offset, const __u64 len,
2447 struct file_lock *pLockData, const __u16 lock_type,
2448 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002449{
2450 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2451 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002452 struct cifs_posix_lock *parm_data;
2453 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002454 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002455 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002456 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002457 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002458 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002459 struct kvec rsp_iov;
Steve French08547b02006-02-28 22:39:25 +00002460
Joe Perchesf96637b2013-05-04 22:12:25 -05002461 cifs_dbg(FYI, "Posix Lock\n");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002462
Steve French08547b02006-02-28 22:39:25 +00002463 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2464
2465 if (rc)
2466 return rc;
2467
2468 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2469
Steve French50c2f752007-07-13 00:33:32 +00002470 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002471 pSMB->MaxSetupCount = 0;
2472 pSMB->Reserved = 0;
2473 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002474 pSMB->Reserved2 = 0;
2475 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2476 offset = param_offset + params;
2477
Steve French08547b02006-02-28 22:39:25 +00002478 count = sizeof(struct cifs_posix_lock);
2479 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002480 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002481 pSMB->SetupCount = 1;
2482 pSMB->Reserved3 = 0;
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002483 if (pLockData)
Steve French08547b02006-02-28 22:39:25 +00002484 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2485 else
2486 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2487 byte_count = 3 /* pad */ + params + count;
2488 pSMB->DataCount = cpu_to_le16(count);
2489 pSMB->ParameterCount = cpu_to_le16(params);
2490 pSMB->TotalDataCount = pSMB->DataCount;
2491 pSMB->TotalParameterCount = pSMB->ParameterCount;
2492 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002493 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002494 (((char *) &pSMB->hdr.Protocol) + offset);
2495
2496 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002497 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002498 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002499 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002500 pSMB->Timeout = cpu_to_le32(-1);
2501 } else
2502 pSMB->Timeout = 0;
2503
Pavel Shilovsky4f6bcec2011-10-22 15:33:30 +04002504 parm_data->pid = cpu_to_le32(netpid);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002505 parm_data->start = cpu_to_le64(start_offset);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002506 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002507
2508 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002509 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002510 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2511 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002512 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002513 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002514 if (waitFlag) {
2515 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2516 (struct smb_hdr *) pSMBr, &bytes_returned);
2517 } else {
Steve French133672e2007-11-13 22:41:37 +00002518 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002519 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002520 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002521 &resp_buf_type, timeout, &rsp_iov);
2522 pSMBr = (struct smb_com_transaction2_sfi_rsp *)rsp_iov.iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002523 }
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002524 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002525
Steve French08547b02006-02-28 22:39:25 +00002526 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002527 cifs_dbg(FYI, "Send error in Posix Lock = %d\n", rc);
Jeff Laytonc5fd3632012-07-23 13:28:37 -04002528 } else if (pLockData) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002529 /* lock structure can be returned on get */
2530 __u16 data_offset;
2531 __u16 data_count;
2532 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002533
Jeff Layton820a8032011-05-04 08:05:26 -04002534 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002535 rc = -EIO; /* bad smb */
2536 goto plk_err_exit;
2537 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002538 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2539 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002540 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002541 rc = -EIO;
2542 goto plk_err_exit;
2543 }
2544 parm_data = (struct cifs_posix_lock *)
2545 ((char *)&pSMBr->hdr.Protocol + data_offset);
Fabian Frederickbc09d142014-12-10 15:41:15 -08002546 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002547 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002548 else {
2549 if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002550 cpu_to_le16(CIFS_RDLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002551 pLockData->fl_type = F_RDLCK;
2552 else if (parm_data->lock_type ==
Fabian Frederickbc09d142014-12-10 15:41:15 -08002553 cpu_to_le16(CIFS_WRLCK))
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002554 pLockData->fl_type = F_WRLCK;
2555
Steve French5443d132011-03-13 05:08:25 +00002556 pLockData->fl_start = le64_to_cpu(parm_data->start);
2557 pLockData->fl_end = pLockData->fl_start +
2558 le64_to_cpu(parm_data->length) - 1;
Benjamin Coddington9d5b86a2017-07-16 10:28:22 -04002559 pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002560 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002561 }
Steve French50c2f752007-07-13 00:33:32 +00002562
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002563plk_err_exit:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002564 free_rsp_buf(resp_buf_type, rsp_iov.iov_base);
Steve French133672e2007-11-13 22:41:37 +00002565
Steve French08547b02006-02-28 22:39:25 +00002566 /* Note: On -EAGAIN error only caller can retry on handle based calls
2567 since file handle passed in no longer valid */
2568
2569 return rc;
2570}
2571
2572
2573int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002574CIFSSMBClose(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575{
2576 int rc = 0;
2577 CLOSE_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002578 cifs_dbg(FYI, "In CIFSSMBClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579
2580/* do not retry on dead session on close */
2581 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002582 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 return 0;
2584 if (rc)
2585 return rc;
2586
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002588 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002590 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002591 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002592 cifs_stats_inc(&tcon->stats.cifs_stats.num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002594 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesf96637b2013-05-04 22:12:25 -05002596 cifs_dbg(VFS, "Send error in Close = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 }
2598 }
2599
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002601 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 rc = 0;
2603
2604 return rc;
2605}
2606
2607int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002608CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002609{
2610 int rc = 0;
2611 FLUSH_REQ *pSMB = NULL;
Joe Perchesf96637b2013-05-04 22:12:25 -05002612 cifs_dbg(FYI, "In CIFSSMBFlush\n");
Steve Frenchb298f222009-02-21 21:17:43 +00002613
2614 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2615 if (rc)
2616 return rc;
2617
2618 pSMB->FileID = (__u16) smb_file_id;
2619 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04002620 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07002621 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002622 cifs_stats_inc(&tcon->stats.cifs_stats.num_flushes);
Steve Frenchb298f222009-02-21 21:17:43 +00002623 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002624 cifs_dbg(VFS, "Send error in Flush = %d\n", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002625
2626 return rc;
2627}
2628
2629int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002630CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002631 const char *from_name, const char *to_name,
2632 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633{
2634 int rc = 0;
2635 RENAME_REQ *pSMB = NULL;
2636 RENAME_RSP *pSMBr = NULL;
2637 int bytes_returned;
2638 int name_len, name_len2;
2639 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05002640 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641
Joe Perchesf96637b2013-05-04 22:12:25 -05002642 cifs_dbg(FYI, "In CIFSSMBRename\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643renameRetry:
2644 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2645 (void **) &pSMBr);
2646 if (rc)
2647 return rc;
2648
2649 pSMB->BufferFormat = 0x04;
2650 pSMB->SearchAttributes =
2651 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2652 ATTR_DIRECTORY);
2653
2654 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002655 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2656 from_name, PATH_MAX,
2657 cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 name_len++; /* trailing null */
2659 name_len *= 2;
2660 pSMB->OldFileName[name_len] = 0x04; /* pad */
2661 /* protocol requires ASCII signature byte on Unicode string */
2662 pSMB->OldFileName[name_len + 1] = 0x00;
2663 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002664 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002665 to_name, PATH_MAX, cifs_sb->local_nls,
2666 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2668 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002669 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002670 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 name_len++; /* trailing null */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002672 strncpy(pSMB->OldFileName, from_name, name_len);
2673 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 name_len2++; /* trailing null */
2675 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Pavel Shilovsky8ceb9842012-09-18 16:20:30 -07002676 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 name_len2++; /* trailing null */
2678 name_len2++; /* signature byte */
2679 }
2680
2681 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002682 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 pSMB->ByteCount = cpu_to_le16(count);
2684
2685 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2686 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002687 cifs_stats_inc(&tcon->stats.cifs_stats.num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002688 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002689 cifs_dbg(FYI, "Send error in rename = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 cifs_buf_release(pSMB);
2692
2693 if (rc == -EAGAIN)
2694 goto renameRetry;
2695
2696 return rc;
2697}
2698
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002699int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002700 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002701 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702{
2703 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2704 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002705 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 char *data_offset;
2707 char dummy_string[30];
2708 int rc = 0;
2709 int bytes_returned = 0;
2710 int len_of_str;
2711 __u16 params, param_offset, offset, count, byte_count;
2712
Joe Perchesf96637b2013-05-04 22:12:25 -05002713 cifs_dbg(FYI, "Rename to File by handle\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2715 (void **) &pSMBr);
2716 if (rc)
2717 return rc;
2718
2719 params = 6;
2720 pSMB->MaxSetupCount = 0;
2721 pSMB->Reserved = 0;
2722 pSMB->Flags = 0;
2723 pSMB->Timeout = 0;
2724 pSMB->Reserved2 = 0;
2725 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2726 offset = param_offset + params;
2727
2728 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2729 rename_info = (struct set_file_rename *) data_offset;
2730 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002731 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 pSMB->SetupCount = 1;
2733 pSMB->Reserved3 = 0;
2734 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2735 byte_count = 3 /* pad */ + params;
2736 pSMB->ParameterCount = cpu_to_le16(params);
2737 pSMB->TotalParameterCount = pSMB->ParameterCount;
2738 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2739 pSMB->DataOffset = cpu_to_le16(offset);
2740 /* construct random name ".cifs_tmp<inodenum><mid>" */
2741 rename_info->overwrite = cpu_to_le32(1);
2742 rename_info->root_fid = 0;
2743 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002744 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002745 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
Steve Frenchacbbb762012-01-18 22:32:33 -06002746 len_of_str =
2747 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002748 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 } else {
Steve Frenchacbbb762012-01-18 22:32:33 -06002750 len_of_str =
2751 cifsConvertToUTF16((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002752 target_name, PATH_MAX, nls_codepage,
2753 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 }
2755 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002756 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 byte_count += count;
2758 pSMB->DataCount = cpu_to_le16(count);
2759 pSMB->TotalDataCount = pSMB->DataCount;
2760 pSMB->Fid = netfid;
2761 pSMB->InformationLevel =
2762 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2763 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002764 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 pSMB->ByteCount = cpu_to_le16(byte_count);
2766 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002767 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002768 cifs_stats_inc(&pTcon->stats.cifs_stats.num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002769 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002770 cifs_dbg(FYI, "Send error in Rename (by file handle) = %d\n",
2771 rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002772
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 cifs_buf_release(pSMB);
2774
2775 /* Note: On -EAGAIN error only caller can retry on handle based calls
2776 since file handle passed in no longer valid */
2777
2778 return rc;
2779}
2780
2781int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002782CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
2783 const char *fromName, const __u16 target_tid, const char *toName,
2784 const int flags, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785{
2786 int rc = 0;
2787 COPY_REQ *pSMB = NULL;
2788 COPY_RSP *pSMBr = NULL;
2789 int bytes_returned;
2790 int name_len, name_len2;
2791 __u16 count;
2792
Joe Perchesf96637b2013-05-04 22:12:25 -05002793 cifs_dbg(FYI, "In CIFSSMBCopy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794copyRetry:
2795 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2796 (void **) &pSMBr);
2797 if (rc)
2798 return rc;
2799
2800 pSMB->BufferFormat = 0x04;
2801 pSMB->Tid2 = target_tid;
2802
2803 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2804
2805 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002806 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2807 fromName, PATH_MAX, nls_codepage,
2808 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 name_len++; /* trailing null */
2810 name_len *= 2;
2811 pSMB->OldFileName[name_len] = 0x04; /* pad */
2812 /* protocol requires ASCII signature byte on Unicode string */
2813 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002814 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06002815 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2816 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2818 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002819 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 name_len = strnlen(fromName, PATH_MAX);
2821 name_len++; /* trailing null */
2822 strncpy(pSMB->OldFileName, fromName, name_len);
2823 name_len2 = strnlen(toName, PATH_MAX);
2824 name_len2++; /* trailing null */
2825 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2826 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2827 name_len2++; /* trailing null */
2828 name_len2++; /* signature byte */
2829 }
2830
2831 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002832 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 pSMB->ByteCount = cpu_to_le16(count);
2834
2835 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2836 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2837 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05002838 cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
2839 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 }
Steve French0d817bc2008-05-22 02:02:03 +00002841 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842
2843 if (rc == -EAGAIN)
2844 goto copyRetry;
2845
2846 return rc;
2847}
2848
2849int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002850CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851 const char *fromName, const char *toName,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002852 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853{
2854 TRANSACTION2_SPI_REQ *pSMB = NULL;
2855 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2856 char *data_offset;
2857 int name_len;
2858 int name_len_target;
2859 int rc = 0;
2860 int bytes_returned = 0;
2861 __u16 params, param_offset, offset, byte_count;
2862
Joe Perchesf96637b2013-05-04 22:12:25 -05002863 cifs_dbg(FYI, "In Symlink Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864createSymLinkRetry:
2865 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2866 (void **) &pSMBr);
2867 if (rc)
2868 return rc;
2869
2870 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2871 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002872 cifsConvertToUTF16((__le16 *) pSMB->FileName, fromName,
2873 /* find define for this maxpathcomponent */
2874 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 name_len++; /* trailing null */
2876 name_len *= 2;
2877
Steve French50c2f752007-07-13 00:33:32 +00002878 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 name_len = strnlen(fromName, PATH_MAX);
2880 name_len++; /* trailing null */
2881 strncpy(pSMB->FileName, fromName, name_len);
2882 }
2883 params = 6 + name_len;
2884 pSMB->MaxSetupCount = 0;
2885 pSMB->Reserved = 0;
2886 pSMB->Flags = 0;
2887 pSMB->Timeout = 0;
2888 pSMB->Reserved2 = 0;
2889 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002890 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 offset = param_offset + params;
2892
2893 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2894 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2895 name_len_target =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09002896 cifsConvertToUTF16((__le16 *) data_offset, toName,
2897 /* find define for this maxpathcomponent */
2898 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 name_len_target++; /* trailing null */
2900 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002901 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 name_len_target = strnlen(toName, PATH_MAX);
2903 name_len_target++; /* trailing null */
2904 strncpy(data_offset, toName, name_len_target);
2905 }
2906
2907 pSMB->MaxParameterCount = cpu_to_le16(2);
2908 /* BB find exact max on data count below from sess */
2909 pSMB->MaxDataCount = cpu_to_le16(1000);
2910 pSMB->SetupCount = 1;
2911 pSMB->Reserved3 = 0;
2912 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2913 byte_count = 3 /* pad */ + params + name_len_target;
2914 pSMB->DataCount = cpu_to_le16(name_len_target);
2915 pSMB->ParameterCount = cpu_to_le16(params);
2916 pSMB->TotalDataCount = pSMB->DataCount;
2917 pSMB->TotalParameterCount = pSMB->ParameterCount;
2918 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2919 pSMB->DataOffset = cpu_to_le16(offset);
2920 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2921 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002922 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923 pSMB->ByteCount = cpu_to_le16(byte_count);
2924 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2925 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04002926 cifs_stats_inc(&tcon->stats.cifs_stats.num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002927 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05002928 cifs_dbg(FYI, "Send error in SetPathInfo create symlink = %d\n",
2929 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930
Steve French0d817bc2008-05-22 02:02:03 +00002931 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932
2933 if (rc == -EAGAIN)
2934 goto createSymLinkRetry;
2935
2936 return rc;
2937}
2938
2939int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04002940CIFSUnixCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002942 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943{
2944 TRANSACTION2_SPI_REQ *pSMB = NULL;
2945 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2946 char *data_offset;
2947 int name_len;
2948 int name_len_target;
2949 int rc = 0;
2950 int bytes_returned = 0;
2951 __u16 params, param_offset, offset, byte_count;
2952
Joe Perchesf96637b2013-05-04 22:12:25 -05002953 cifs_dbg(FYI, "In Create Hard link Unix style\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954createHardLinkRetry:
2955 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2956 (void **) &pSMBr);
2957 if (rc)
2958 return rc;
2959
2960 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchacbbb762012-01-18 22:32:33 -06002961 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2962 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 name_len++; /* trailing null */
2964 name_len *= 2;
2965
Steve French50c2f752007-07-13 00:33:32 +00002966 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 name_len = strnlen(toName, PATH_MAX);
2968 name_len++; /* trailing null */
2969 strncpy(pSMB->FileName, toName, name_len);
2970 }
2971 params = 6 + name_len;
2972 pSMB->MaxSetupCount = 0;
2973 pSMB->Reserved = 0;
2974 pSMB->Flags = 0;
2975 pSMB->Timeout = 0;
2976 pSMB->Reserved2 = 0;
2977 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002978 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 offset = param_offset + params;
2980
2981 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2982 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2983 name_len_target =
Steve Frenchacbbb762012-01-18 22:32:33 -06002984 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2985 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 name_len_target++; /* trailing null */
2987 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002988 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 name_len_target = strnlen(fromName, PATH_MAX);
2990 name_len_target++; /* trailing null */
2991 strncpy(data_offset, fromName, name_len_target);
2992 }
2993
2994 pSMB->MaxParameterCount = cpu_to_le16(2);
2995 /* BB find exact max on data count below from sess*/
2996 pSMB->MaxDataCount = cpu_to_le16(1000);
2997 pSMB->SetupCount = 1;
2998 pSMB->Reserved3 = 0;
2999 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3000 byte_count = 3 /* pad */ + params + name_len_target;
3001 pSMB->ParameterCount = cpu_to_le16(params);
3002 pSMB->TotalParameterCount = pSMB->ParameterCount;
3003 pSMB->DataCount = cpu_to_le16(name_len_target);
3004 pSMB->TotalDataCount = pSMB->DataCount;
3005 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3006 pSMB->DataOffset = cpu_to_le16(offset);
3007 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
3008 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003009 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 pSMB->ByteCount = cpu_to_le16(byte_count);
3011 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3012 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003013 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003014 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003015 cifs_dbg(FYI, "Send error in SetPathInfo (hard link) = %d\n",
3016 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017
3018 cifs_buf_release(pSMB);
3019 if (rc == -EAGAIN)
3020 goto createHardLinkRetry;
3021
3022 return rc;
3023}
3024
3025int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003026CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchd6e906f2012-09-18 16:20:31 -07003027 const char *from_name, const char *to_name,
3028 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029{
3030 int rc = 0;
3031 NT_RENAME_REQ *pSMB = NULL;
3032 RENAME_RSP *pSMBr = NULL;
3033 int bytes_returned;
3034 int name_len, name_len2;
3035 __u16 count;
Steve French2baa2682014-09-27 02:19:01 -05003036 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037
Joe Perchesf96637b2013-05-04 22:12:25 -05003038 cifs_dbg(FYI, "In CIFSCreateHardLink\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039winCreateHardLinkRetry:
3040
3041 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
3042 (void **) &pSMBr);
3043 if (rc)
3044 return rc;
3045
3046 pSMB->SearchAttributes =
3047 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3048 ATTR_DIRECTORY);
3049 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
3050 pSMB->ClusterCount = 0;
3051
3052 pSMB->BufferFormat = 0x04;
3053
3054 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3055 name_len =
Steve Frenchd6e906f2012-09-18 16:20:31 -07003056 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
3057 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058 name_len++; /* trailing null */
3059 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05003060
3061 /* protocol specifies ASCII buffer format (0x04) for unicode */
3062 pSMB->OldFileName[name_len] = 0x04;
3063 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 name_len2 =
Steve Frenchacbbb762012-01-18 22:32:33 -06003065 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
Steve Frenchd6e906f2012-09-18 16:20:31 -07003066 to_name, PATH_MAX, cifs_sb->local_nls,
3067 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
3069 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00003070 } else { /* BB improve the check for buffer overruns BB */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003071 name_len = strnlen(from_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 name_len++; /* trailing null */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003073 strncpy(pSMB->OldFileName, from_name, name_len);
3074 name_len2 = strnlen(to_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 name_len2++; /* trailing null */
3076 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
Steve Frenchd6e906f2012-09-18 16:20:31 -07003077 strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 name_len2++; /* trailing null */
3079 name_len2++; /* signature byte */
3080 }
3081
3082 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003083 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084 pSMB->ByteCount = cpu_to_le16(count);
3085
3086 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3087 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003088 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00003089 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003090 cifs_dbg(FYI, "Send error in hard link (NT rename) = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003091
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092 cifs_buf_release(pSMB);
3093 if (rc == -EAGAIN)
3094 goto winCreateHardLinkRetry;
3095
3096 return rc;
3097}
3098
3099int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003100CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04003101 const unsigned char *searchName, char **symlinkinfo,
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003102 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103{
3104/* SMB_QUERY_FILE_UNIX_LINK */
3105 TRANSACTION2_QPI_REQ *pSMB = NULL;
3106 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3107 int rc = 0;
3108 int bytes_returned;
3109 int name_len;
3110 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04003111 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112
Joe Perchesf96637b2013-05-04 22:12:25 -05003113 cifs_dbg(FYI, "In QPathSymLinkInfo (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114
3115querySymLinkRetry:
3116 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3117 (void **) &pSMBr);
3118 if (rc)
3119 return rc;
3120
3121 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3122 name_len =
Nakajima Akirabc8ebdc42015-02-13 15:35:58 +09003123 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3124 searchName, PATH_MAX, nls_codepage,
3125 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 name_len++; /* trailing null */
3127 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003128 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 name_len = strnlen(searchName, PATH_MAX);
3130 name_len++; /* trailing null */
3131 strncpy(pSMB->FileName, searchName, name_len);
3132 }
3133
3134 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3135 pSMB->TotalDataCount = 0;
3136 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04003137 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138 pSMB->MaxSetupCount = 0;
3139 pSMB->Reserved = 0;
3140 pSMB->Flags = 0;
3141 pSMB->Timeout = 0;
3142 pSMB->Reserved2 = 0;
3143 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003144 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145 pSMB->DataCount = 0;
3146 pSMB->DataOffset = 0;
3147 pSMB->SetupCount = 1;
3148 pSMB->Reserved3 = 0;
3149 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3150 byte_count = params + 1 /* pad */ ;
3151 pSMB->TotalParameterCount = cpu_to_le16(params);
3152 pSMB->ParameterCount = pSMB->TotalParameterCount;
3153 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3154 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003155 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 pSMB->ByteCount = cpu_to_le16(byte_count);
3157
3158 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3159 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3160 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003161 cifs_dbg(FYI, "Send error in QuerySymLinkInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162 } else {
3163 /* decode response */
3164
3165 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003167 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04003168 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00003170 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04003171 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172
Jeff Layton460b9692009-04-30 07:17:56 -04003173 data_start = ((char *) &pSMBr->hdr.Protocol) +
3174 le16_to_cpu(pSMBr->t2.DataOffset);
3175
Steve French0e0d2cf2009-05-01 05:27:32 +00003176 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3177 is_unicode = true;
3178 else
3179 is_unicode = false;
3180
Steve French737b7582005-04-28 22:41:06 -07003181 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchacbbb762012-01-18 22:32:33 -06003182 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3183 count, is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04003184 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04003185 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186 }
3187 }
3188 cifs_buf_release(pSMB);
3189 if (rc == -EAGAIN)
3190 goto querySymLinkRetry;
3191 return rc;
3192}
3193
Steve Frenchc52a9552011-02-24 06:16:22 +00003194/*
3195 * Recent Windows versions now create symlinks more frequently
3196 * and they use the "reparse point" mechanism below. We can of course
3197 * do symlinks nicely to Samba and other servers which support the
3198 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3199 * "MF" symlinks optionally, but for recent Windows we really need to
3200 * reenable the code below and fix the cifs_symlink callers to handle this.
3201 * In the interim this code has been moved to its own config option so
3202 * it is not compiled in by default until callers fixed up and more tested.
3203 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204int
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003205CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
3206 __u16 fid, char **symlinkinfo,
3207 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208{
3209 int rc = 0;
3210 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00003211 struct smb_com_transaction_ioctl_req *pSMB;
3212 struct smb_com_transaction_ioctl_rsp *pSMBr;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003213 bool is_unicode;
3214 unsigned int sub_len;
3215 char *sub_start;
Steve Frenchc31f3302013-09-28 18:24:12 -05003216 struct reparse_symlink_data *reparse_buf;
3217 struct reparse_posix_data *posix_buf;
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003218 __u32 data_offset, data_count;
3219 char *end_of_smb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003221 cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3223 (void **) &pSMBr);
3224 if (rc)
3225 return rc;
3226
3227 pSMB->TotalParameterCount = 0 ;
3228 pSMB->TotalDataCount = 0;
3229 pSMB->MaxParameterCount = cpu_to_le32(2);
3230 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04003231 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 pSMB->MaxSetupCount = 4;
3233 pSMB->Reserved = 0;
3234 pSMB->ParameterOffset = 0;
3235 pSMB->DataCount = 0;
3236 pSMB->DataOffset = 0;
3237 pSMB->SetupCount = 4;
3238 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3239 pSMB->ParameterCount = pSMB->TotalParameterCount;
3240 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3241 pSMB->IsFsctl = 1; /* FSCTL */
3242 pSMB->IsRootFlag = 0;
3243 pSMB->Fid = fid; /* file handle always le */
3244 pSMB->ByteCount = 0;
3245
3246 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3247 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3248 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003249 cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003250 goto qreparse_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251 }
Steve French989c7e52009-05-02 05:32:20 +00003252
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003253 data_offset = le32_to_cpu(pSMBr->DataOffset);
3254 data_count = le32_to_cpu(pSMBr->DataCount);
3255 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3256 /* BB also check enough total bytes returned */
3257 rc = -EIO; /* bad smb */
3258 goto qreparse_out;
3259 }
3260 if (!data_count || (data_count > 2048)) {
3261 rc = -EIO;
3262 cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
3263 goto qreparse_out;
3264 }
3265 end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Steve Frenchc31f3302013-09-28 18:24:12 -05003266 reparse_buf = (struct reparse_symlink_data *)
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003267 ((char *)&pSMBr->hdr.Protocol + data_offset);
3268 if ((char *)reparse_buf >= end_of_smb) {
3269 rc = -EIO;
3270 goto qreparse_out;
3271 }
Steve Frenchc31f3302013-09-28 18:24:12 -05003272 if (reparse_buf->ReparseTag == cpu_to_le32(IO_REPARSE_TAG_NFS)) {
3273 cifs_dbg(FYI, "NFS style reparse tag\n");
3274 posix_buf = (struct reparse_posix_data *)reparse_buf;
3275
3276 if (posix_buf->InodeType != cpu_to_le64(NFS_SPECFILE_LNK)) {
3277 cifs_dbg(FYI, "unsupported file type 0x%llx\n",
3278 le64_to_cpu(posix_buf->InodeType));
3279 rc = -EOPNOTSUPP;
3280 goto qreparse_out;
3281 }
3282 is_unicode = true;
3283 sub_len = le16_to_cpu(reparse_buf->ReparseDataLength);
3284 if (posix_buf->PathBuffer + sub_len > end_of_smb) {
3285 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3286 rc = -EIO;
3287 goto qreparse_out;
3288 }
3289 *symlinkinfo = cifs_strndup_from_utf16(posix_buf->PathBuffer,
3290 sub_len, is_unicode, nls_codepage);
3291 goto qreparse_out;
3292 } else if (reparse_buf->ReparseTag !=
3293 cpu_to_le32(IO_REPARSE_TAG_SYMLINK)) {
3294 rc = -EOPNOTSUPP;
3295 goto qreparse_out;
3296 }
3297
3298 /* Reparse tag is NTFS symlink */
3299 sub_start = le16_to_cpu(reparse_buf->SubstituteNameOffset) +
3300 reparse_buf->PathBuffer;
3301 sub_len = le16_to_cpu(reparse_buf->SubstituteNameLength);
3302 if (sub_start + sub_len > end_of_smb) {
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003303 cifs_dbg(FYI, "reparse buf beyond SMB\n");
3304 rc = -EIO;
3305 goto qreparse_out;
3306 }
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003307 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3308 is_unicode = true;
3309 else
3310 is_unicode = false;
3311
3312 /* BB FIXME investigate remapping reserved chars here */
3313 *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
3314 nls_codepage);
3315 if (!*symlinkinfo)
3316 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07003318 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319
Pavel Shilovskyd244bf22013-08-14 19:25:22 +04003320 /*
3321 * Note: On -EAGAIN error only caller can retry on handle based calls
3322 * since file handle passed in no longer valid.
3323 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003324 return rc;
3325}
3326
Steve Frenchc7f508a2013-10-14 15:27:32 -05003327int
3328CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
3329 __u16 fid)
3330{
3331 int rc = 0;
3332 int bytes_returned;
3333 struct smb_com_transaction_compr_ioctl_req *pSMB;
3334 struct smb_com_transaction_ioctl_rsp *pSMBr;
3335
3336 cifs_dbg(FYI, "Set compression for %u\n", fid);
3337 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3338 (void **) &pSMBr);
3339 if (rc)
3340 return rc;
3341
3342 pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
3343
3344 pSMB->TotalParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003345 pSMB->TotalDataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003346 pSMB->MaxParameterCount = 0;
3347 pSMB->MaxDataCount = 0;
3348 pSMB->MaxSetupCount = 4;
3349 pSMB->Reserved = 0;
3350 pSMB->ParameterOffset = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003351 pSMB->DataCount = cpu_to_le32(2);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003352 pSMB->DataOffset =
3353 cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
3354 compression_state) - 4); /* 84 */
3355 pSMB->SetupCount = 4;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003356 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003357 pSMB->ParameterCount = 0;
Fabian Frederickbc09d142014-12-10 15:41:15 -08003358 pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003359 pSMB->IsFsctl = 1; /* FSCTL */
3360 pSMB->IsRootFlag = 0;
3361 pSMB->Fid = fid; /* file handle always le */
3362 /* 3 byte pad, followed by 2 byte compress state */
Fabian Frederickbc09d142014-12-10 15:41:15 -08003363 pSMB->ByteCount = cpu_to_le16(5);
Steve Frenchc7f508a2013-10-14 15:27:32 -05003364 inc_rfc1001_len(pSMB, 5);
3365
3366 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3367 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3368 if (rc)
3369 cifs_dbg(FYI, "Send error in SetCompression = %d\n", rc);
3370
3371 cifs_buf_release(pSMB);
3372
3373 /*
3374 * Note: On -EAGAIN error only caller can retry on handle based calls
3375 * since file handle passed in no longer valid.
3376 */
3377 return rc;
3378}
3379
3380
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381#ifdef CONFIG_CIFS_POSIX
3382
3383/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003384static void cifs_convert_ace(struct posix_acl_xattr_entry *ace,
Steve French50c2f752007-07-13 00:33:32 +00003385 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386{
3387 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08003388 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3389 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3390 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesf96637b2013-05-04 22:12:25 -05003391/*
3392 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3393 ace->e_perm, ace->e_tag, ace->e_id);
3394*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395
3396 return;
3397}
3398
3399/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00003400static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3401 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402{
3403 int size = 0;
3404 int i;
3405 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00003406 struct cifs_posix_ace *pACE;
3407 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003408 struct posix_acl_xattr_header *local_acl = (void *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409
3410 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3411 return -EOPNOTSUPP;
3412
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003413 if (acl_type == ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414 count = le16_to_cpu(cifs_acl->access_entry_count);
3415 pACE = &cifs_acl->ace_array[0];
3416 size = sizeof(struct cifs_posix_acl);
3417 size += sizeof(struct cifs_posix_ace) * count;
3418 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00003419 if (size_of_data_area < size) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003420 cifs_dbg(FYI, "bad CIFS POSIX ACL size %d vs. %d\n",
3421 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 return -EINVAL;
3423 }
Andreas Gruenbacher45987e02016-04-14 00:30:14 +02003424 } else if (acl_type == ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425 count = le16_to_cpu(cifs_acl->access_entry_count);
3426 size = sizeof(struct cifs_posix_acl);
3427 size += sizeof(struct cifs_posix_ace) * count;
3428/* skip past access ACEs to get to default ACEs */
3429 pACE = &cifs_acl->ace_array[count];
3430 count = le16_to_cpu(cifs_acl->default_entry_count);
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)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 return -EINVAL;
3435 } else {
3436 /* illegal type */
3437 return -EINVAL;
3438 }
3439
3440 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00003441 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00003442 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00003443 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 return -ERANGE;
3445 } else /* buffer big enough */ {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003446 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
3447
Steve Frenchff7feac2005-11-15 16:45:16 -08003448 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00003449 for (i = 0; i < count ; i++) {
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003450 cifs_convert_ace(&ace[i], pACE);
Steve French50c2f752007-07-13 00:33:32 +00003451 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452 }
3453 }
3454 return size;
3455}
3456
Steve French50c2f752007-07-13 00:33:32 +00003457static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003458 const struct posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459{
3460 __u16 rc = 0; /* 0 = ACL converted ok */
3461
Steve Frenchff7feac2005-11-15 16:45:16 -08003462 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3463 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00003465 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 /* Probably no need to le convert -1 on any arch but can not hurt */
3467 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00003468 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08003469 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesf96637b2013-05-04 22:12:25 -05003470/*
3471 cifs_dbg(FYI, "perm %d tag %d id %d\n",
3472 ace->e_perm, ace->e_tag, ace->e_id);
3473*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 return rc;
3475}
3476
3477/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00003478static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3479 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480{
3481 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00003482 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
Andreas Gruenbacher2211d5b2016-09-27 13:03:22 +02003483 struct posix_acl_xattr_header *local_acl = (void *)pACL;
Eryu Guanae9ebe72016-10-24 20:46:40 +08003484 struct posix_acl_xattr_entry *ace = (void *)(local_acl + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485 int count;
3486 int i;
3487
Steve French790fe572007-07-07 19:25:05 +00003488 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489 return 0;
3490
3491 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesf96637b2013-05-04 22:12:25 -05003492 cifs_dbg(FYI, "setting acl with %d entries from buf of length %d and version of %d\n",
3493 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003494 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003495 cifs_dbg(FYI, "unknown POSIX ACL version %d\n",
3496 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497 return 0;
3498 }
3499 cifs_acl->version = cpu_to_le16(1);
Steve Frenchb1d93352013-11-15 20:41:32 -06003500 if (acl_type == ACL_TYPE_ACCESS) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003501 cifs_acl->access_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003502 cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003503 } else if (acl_type == ACL_TYPE_DEFAULT) {
Steve Frenchff7feac2005-11-15 16:45:16 -08003504 cifs_acl->default_entry_count = cpu_to_le16(count);
Fabian Frederickbc09d142014-12-10 15:41:15 -08003505 cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
Steve Frenchb1d93352013-11-15 20:41:32 -06003506 } else {
Joe Perchesf96637b2013-05-04 22:12:25 -05003507 cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508 return 0;
3509 }
Steve French50c2f752007-07-13 00:33:32 +00003510 for (i = 0; i < count; i++) {
Eryu Guanae9ebe72016-10-24 20:46:40 +08003511 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i], &ace[i]);
Steve French790fe572007-07-07 19:25:05 +00003512 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513 /* ACE not converted */
3514 break;
3515 }
3516 }
Steve French790fe572007-07-07 19:25:05 +00003517 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3519 rc += sizeof(struct cifs_posix_acl);
3520 /* BB add check to make sure ACL does not overflow SMB */
3521 }
3522 return rc;
3523}
3524
3525int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003526CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003527 const unsigned char *searchName,
3528 char *acl_inf, const int buflen, const int acl_type,
3529 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530{
3531/* SMB_QUERY_POSIX_ACL */
3532 TRANSACTION2_QPI_REQ *pSMB = NULL;
3533 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3534 int rc = 0;
3535 int bytes_returned;
3536 int name_len;
3537 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003538
Joe Perchesf96637b2013-05-04 22:12:25 -05003539 cifs_dbg(FYI, "In GetPosixACL (Unix) for path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540
3541queryAclRetry:
3542 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3543 (void **) &pSMBr);
3544 if (rc)
3545 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003546
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3548 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003549 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3550 searchName, PATH_MAX, nls_codepage,
3551 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552 name_len++; /* trailing null */
3553 name_len *= 2;
3554 pSMB->FileName[name_len] = 0;
3555 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003556 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557 name_len = strnlen(searchName, PATH_MAX);
3558 name_len++; /* trailing null */
3559 strncpy(pSMB->FileName, searchName, name_len);
3560 }
3561
3562 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3563 pSMB->TotalDataCount = 0;
3564 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003565 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566 pSMB->MaxDataCount = cpu_to_le16(4000);
3567 pSMB->MaxSetupCount = 0;
3568 pSMB->Reserved = 0;
3569 pSMB->Flags = 0;
3570 pSMB->Timeout = 0;
3571 pSMB->Reserved2 = 0;
3572 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003573 offsetof(struct smb_com_transaction2_qpi_req,
3574 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575 pSMB->DataCount = 0;
3576 pSMB->DataOffset = 0;
3577 pSMB->SetupCount = 1;
3578 pSMB->Reserved3 = 0;
3579 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3580 byte_count = params + 1 /* pad */ ;
3581 pSMB->TotalParameterCount = cpu_to_le16(params);
3582 pSMB->ParameterCount = pSMB->TotalParameterCount;
3583 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3584 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003585 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586 pSMB->ByteCount = cpu_to_le16(byte_count);
3587
3588 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3589 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003590 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003592 cifs_dbg(FYI, "Send error in Query POSIX ACL = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593 } else {
3594 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003595
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003598 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 rc = -EIO; /* bad smb */
3600 else {
3601 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3602 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3603 rc = cifs_copy_posix_acl(acl_inf,
3604 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003605 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606 }
3607 }
3608 cifs_buf_release(pSMB);
3609 if (rc == -EAGAIN)
3610 goto queryAclRetry;
3611 return rc;
3612}
3613
3614int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003615CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003616 const unsigned char *fileName,
3617 const char *local_acl, const int buflen,
3618 const int acl_type,
3619 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620{
3621 struct smb_com_transaction2_spi_req *pSMB = NULL;
3622 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3623 char *parm_data;
3624 int name_len;
3625 int rc = 0;
3626 int bytes_returned = 0;
3627 __u16 params, byte_count, data_count, param_offset, offset;
3628
Joe Perchesf96637b2013-05-04 22:12:25 -05003629 cifs_dbg(FYI, "In SetPosixACL (Unix) for path %s\n", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630setAclRetry:
3631 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003632 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633 if (rc)
3634 return rc;
3635 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3636 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06003637 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3638 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639 name_len++; /* trailing null */
3640 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003641 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 name_len = strnlen(fileName, PATH_MAX);
3643 name_len++; /* trailing null */
3644 strncpy(pSMB->FileName, fileName, name_len);
3645 }
3646 params = 6 + name_len;
3647 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003648 /* BB find max SMB size from sess */
3649 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650 pSMB->MaxSetupCount = 0;
3651 pSMB->Reserved = 0;
3652 pSMB->Flags = 0;
3653 pSMB->Timeout = 0;
3654 pSMB->Reserved2 = 0;
3655 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003656 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 offset = param_offset + params;
3658 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3659 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3660
3661 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003662 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663
Steve French790fe572007-07-07 19:25:05 +00003664 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665 rc = -EOPNOTSUPP;
3666 goto setACLerrorExit;
3667 }
3668 pSMB->DataOffset = cpu_to_le16(offset);
3669 pSMB->SetupCount = 1;
3670 pSMB->Reserved3 = 0;
3671 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3672 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3673 byte_count = 3 /* pad */ + params + data_count;
3674 pSMB->DataCount = cpu_to_le16(data_count);
3675 pSMB->TotalDataCount = pSMB->DataCount;
3676 pSMB->ParameterCount = cpu_to_le16(params);
3677 pSMB->TotalParameterCount = pSMB->ParameterCount;
3678 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003679 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680 pSMB->ByteCount = cpu_to_le16(byte_count);
3681 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003682 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003683 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05003684 cifs_dbg(FYI, "Set POSIX ACL returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685
3686setACLerrorExit:
3687 cifs_buf_release(pSMB);
3688 if (rc == -EAGAIN)
3689 goto setAclRetry;
3690 return rc;
3691}
3692
Steve Frenchf654bac2005-04-28 22:41:04 -07003693/* BB fix tabs in this function FIXME BB */
3694int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003695CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003696 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003697{
Steve French50c2f752007-07-13 00:33:32 +00003698 int rc = 0;
3699 struct smb_t2_qfi_req *pSMB = NULL;
3700 struct smb_t2_qfi_rsp *pSMBr = NULL;
3701 int bytes_returned;
3702 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003703
Joe Perchesf96637b2013-05-04 22:12:25 -05003704 cifs_dbg(FYI, "In GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003705 if (tcon == NULL)
3706 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003707
3708GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003709 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3710 (void **) &pSMBr);
3711 if (rc)
3712 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003713
Steve Frenchad7a2922008-02-07 23:25:02 +00003714 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003715 pSMB->t2.TotalDataCount = 0;
3716 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3717 /* BB find exact max data count below from sess structure BB */
3718 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3719 pSMB->t2.MaxSetupCount = 0;
3720 pSMB->t2.Reserved = 0;
3721 pSMB->t2.Flags = 0;
3722 pSMB->t2.Timeout = 0;
3723 pSMB->t2.Reserved2 = 0;
3724 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3725 Fid) - 4);
3726 pSMB->t2.DataCount = 0;
3727 pSMB->t2.DataOffset = 0;
3728 pSMB->t2.SetupCount = 1;
3729 pSMB->t2.Reserved3 = 0;
3730 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3731 byte_count = params + 1 /* pad */ ;
3732 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3733 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3734 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3735 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003736 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003737 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003738 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003739
Steve French790fe572007-07-07 19:25:05 +00003740 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3741 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3742 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003743 cifs_dbg(FYI, "error %d in GetExtAttr\n", rc);
Steve French790fe572007-07-07 19:25:05 +00003744 } else {
3745 /* decode response */
3746 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003747 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003748 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003749 /* If rc should we check for EOPNOSUPP and
3750 disable the srvino flag? or in caller? */
3751 rc = -EIO; /* bad smb */
3752 else {
3753 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3754 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3755 struct file_chattr_info *pfinfo;
3756 /* BB Do we need a cast or hash here ? */
3757 if (count != 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003758 cifs_dbg(FYI, "Illegal size ret in GetExtAttr\n");
Steve French790fe572007-07-07 19:25:05 +00003759 rc = -EIO;
3760 goto GetExtAttrOut;
3761 }
3762 pfinfo = (struct file_chattr_info *)
3763 (data_offset + (char *) &pSMBr->hdr.Protocol);
3764 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003765 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003766 }
3767 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003768GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003769 cifs_buf_release(pSMB);
3770 if (rc == -EAGAIN)
3771 goto GetExtAttrRetry;
3772 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003773}
3774
Steve Frenchf654bac2005-04-28 22:41:04 -07003775#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776
Jeff Layton79df1ba2010-12-06 12:52:08 -05003777#ifdef CONFIG_CIFS_ACL
3778/*
3779 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3780 * all NT TRANSACTS that we init here have total parm and data under about 400
3781 * bytes (to fit in small cifs buffer size), which is the case so far, it
3782 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3783 * returned setup area) and MaxParameterCount (returned parms size) must be set
3784 * by caller
3785 */
3786static int
3787smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003788 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003789 void **ret_buf)
3790{
3791 int rc;
3792 __u32 temp_offset;
3793 struct smb_com_ntransact_req *pSMB;
3794
3795 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3796 (void **)&pSMB);
3797 if (rc)
3798 return rc;
3799 *ret_buf = (void *)pSMB;
3800 pSMB->Reserved = 0;
3801 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3802 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003803 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003804 pSMB->ParameterCount = pSMB->TotalParameterCount;
3805 pSMB->DataCount = pSMB->TotalDataCount;
3806 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3807 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3808 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3809 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3810 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3811 pSMB->SubCommand = cpu_to_le16(sub_command);
3812 return 0;
3813}
3814
3815static int
3816validate_ntransact(char *buf, char **ppparm, char **ppdata,
3817 __u32 *pparmlen, __u32 *pdatalen)
3818{
3819 char *end_of_smb;
3820 __u32 data_count, data_offset, parm_count, parm_offset;
3821 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003822 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003823
3824 *pdatalen = 0;
3825 *pparmlen = 0;
3826
3827 if (buf == NULL)
3828 return -EINVAL;
3829
3830 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3831
Jeff Layton820a8032011-05-04 08:05:26 -04003832 bcc = get_bcc(&pSMBr->hdr);
3833 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003834 (char *)&pSMBr->ByteCount;
3835
3836 data_offset = le32_to_cpu(pSMBr->DataOffset);
3837 data_count = le32_to_cpu(pSMBr->DataCount);
3838 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3839 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3840
3841 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3842 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3843
3844 /* should we also check that parm and data areas do not overlap? */
3845 if (*ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003846 cifs_dbg(FYI, "parms start after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003847 return -EINVAL;
3848 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003849 cifs_dbg(FYI, "parm end after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003850 return -EINVAL;
3851 } else if (*ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003852 cifs_dbg(FYI, "data starts after end of smb\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003853 return -EINVAL;
3854 } else if (data_count + *ppdata > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003855 cifs_dbg(FYI, "data %p + count %d (%p) past smb end %p start %p\n",
3856 *ppdata, data_count, (data_count + *ppdata),
3857 end_of_smb, pSMBr);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003858 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003859 } else if (parm_count + data_count > bcc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003860 cifs_dbg(FYI, "parm count and data count larger than SMB\n");
Jeff Layton79df1ba2010-12-06 12:52:08 -05003861 return -EINVAL;
3862 }
3863 *pdatalen = data_count;
3864 *pparmlen = parm_count;
3865 return 0;
3866}
3867
Steve French0a4b92c2006-01-12 15:44:21 -08003868/* Get Security Descriptor (by handle) from remote server for a file or dir */
3869int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003870CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003871 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003872{
3873 int rc = 0;
3874 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003875 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003876 struct kvec iov[1];
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003877 struct kvec rsp_iov;
Steve French0a4b92c2006-01-12 15:44:21 -08003878
Joe Perchesf96637b2013-05-04 22:12:25 -05003879 cifs_dbg(FYI, "GetCifsACL\n");
Steve French0a4b92c2006-01-12 15:44:21 -08003880
Steve French630f3f0c2007-10-25 21:17:17 +00003881 *pbuflen = 0;
3882 *acl_inf = NULL;
3883
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003884 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003885 8 /* parm len */, tcon, (void **) &pSMB);
3886 if (rc)
3887 return rc;
3888
3889 pSMB->MaxParameterCount = cpu_to_le32(4);
3890 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3891 pSMB->MaxSetupCount = 0;
3892 pSMB->Fid = fid; /* file handle always le */
3893 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3894 CIFS_ACL_DACL);
3895 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003896 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003897 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003898 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003899
Steve Frencha761ac52007-10-18 21:45:27 +00003900 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003901 0, &rsp_iov);
3902 cifs_small_buf_release(pSMB);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04003903 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
Steve French0a4b92c2006-01-12 15:44:21 -08003904 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003905 cifs_dbg(FYI, "Send error in QuerySecDesc = %d\n", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003906 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003907 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003908 __u32 parm_len;
3909 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003910 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003911 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003912
3913/* validate_nttransact */
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003914 rc = validate_ntransact(rsp_iov.iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003915 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003916 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003917 goto qsec_out;
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003918 pSMBr = (struct smb_com_ntransact_rsp *)rsp_iov.iov_base;
Steve French0a4b92c2006-01-12 15:44:21 -08003919
Joe Perchesf96637b2013-05-04 22:12:25 -05003920 cifs_dbg(FYI, "smb %p parm %p data %p\n",
3921 pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003922
3923 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3924 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003925 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003926 goto qsec_out;
3927 }
3928
3929/* BB check that data area is minimum length and as big as acl_len */
3930
Steve Frenchaf6f4612007-10-16 18:40:37 +00003931 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003932 if (acl_len != *pbuflen) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003933 cifs_dbg(VFS, "acl length %d does not match %d\n",
3934 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003935 if (*pbuflen > acl_len)
3936 *pbuflen = acl_len;
3937 }
Steve French0a4b92c2006-01-12 15:44:21 -08003938
Steve French630f3f0c2007-10-25 21:17:17 +00003939 /* check if buffer is big enough for the acl
3940 header followed by the smallest SID */
3941 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3942 (*pbuflen >= 64 * 1024)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05003943 cifs_dbg(VFS, "bad acl length %d\n", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003944 rc = -EINVAL;
3945 *pbuflen = 0;
3946 } else {
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +02003947 *acl_inf = kmemdup(pdata, *pbuflen, GFP_KERNEL);
Steve French630f3f0c2007-10-25 21:17:17 +00003948 if (*acl_inf == NULL) {
3949 *pbuflen = 0;
3950 rc = -ENOMEM;
3951 }
Steve French630f3f0c2007-10-25 21:17:17 +00003952 }
Steve French0a4b92c2006-01-12 15:44:21 -08003953 }
3954qsec_out:
Pavel Shilovskyda502f72016-10-25 11:38:47 -07003955 free_rsp_buf(buf_type, rsp_iov.iov_base);
Steve French0a4b92c2006-01-12 15:44:21 -08003956 return rc;
3957}
Steve French97837582007-12-31 07:47:21 +00003958
3959int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04003960CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003961 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003962{
3963 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3964 int rc = 0;
3965 int bytes_returned = 0;
3966 SET_SEC_DESC_REQ *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003967 void *pSMBr;
Steve French97837582007-12-31 07:47:21 +00003968
3969setCifsAclRetry:
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003970 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
Steve French97837582007-12-31 07:47:21 +00003971 if (rc)
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04003972 return rc;
Steve French97837582007-12-31 07:47:21 +00003973
3974 pSMB->MaxSetupCount = 0;
3975 pSMB->Reserved = 0;
3976
3977 param_count = 8;
3978 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3979 data_count = acllen;
3980 data_offset = param_offset + param_count;
3981 byte_count = 3 /* pad */ + param_count;
3982
3983 pSMB->DataCount = cpu_to_le32(data_count);
3984 pSMB->TotalDataCount = pSMB->DataCount;
3985 pSMB->MaxParameterCount = cpu_to_le32(4);
3986 pSMB->MaxDataCount = cpu_to_le32(16384);
3987 pSMB->ParameterCount = cpu_to_le32(param_count);
3988 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3989 pSMB->TotalParameterCount = pSMB->ParameterCount;
3990 pSMB->DataOffset = cpu_to_le32(data_offset);
3991 pSMB->SetupCount = 0;
3992 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3993 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3994
3995 pSMB->Fid = fid; /* file handle always le */
3996 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003997 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003998
3999 if (pntsd && acllen) {
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04004000 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
4001 data_offset, pntsd, acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004002 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00004003 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004004 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00004005
4006 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4007 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4008
Joe Perchesf96637b2013-05-04 22:12:25 -05004009 cifs_dbg(FYI, "SetCIFSACL bytes_returned: %d, rc: %d\n",
4010 bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00004011 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004012 cifs_dbg(FYI, "Set CIFS ACL returned %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00004013 cifs_buf_release(pSMB);
4014
4015 if (rc == -EAGAIN)
4016 goto setCifsAclRetry;
4017
4018 return (rc);
4019}
4020
Jeff Layton79df1ba2010-12-06 12:52:08 -05004021#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08004022
Steve French6b8edfe2005-08-23 20:26:03 -07004023/* Legacy Query Path Information call for lookup to old servers such
4024 as Win9x/WinME */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004025int
4026SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
4027 const char *search_name, FILE_ALL_INFO *data,
4028 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07004029{
Steve Frenchad7a2922008-02-07 23:25:02 +00004030 QUERY_INFORMATION_REQ *pSMB;
4031 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07004032 int rc = 0;
4033 int bytes_returned;
4034 int name_len;
4035
Joe Perchesf96637b2013-05-04 22:12:25 -05004036 cifs_dbg(FYI, "In SMBQPath path %s\n", search_name);
Steve French6b8edfe2005-08-23 20:26:03 -07004037QInfRetry:
4038 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004039 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07004040 if (rc)
4041 return rc;
4042
4043 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4044 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004045 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004046 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004047 remap);
Steve French6b8edfe2005-08-23 20:26:03 -07004048 name_len++; /* trailing null */
4049 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004050 } else {
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004051 name_len = strnlen(search_name, PATH_MAX);
Steve French6b8edfe2005-08-23 20:26:03 -07004052 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004053 strncpy(pSMB->FileName, search_name, name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004054 }
4055 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00004056 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004057 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07004058 pSMB->ByteCount = cpu_to_le16(name_len);
4059
4060 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004061 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07004062 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004063 cifs_dbg(FYI, "Send error in QueryInfo = %d\n", rc);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004064 } else if (data) {
Steve French1bd5bbc2006-09-28 03:35:57 +00004065 struct timespec ts;
4066 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00004067
4068 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00004069 /* BB FIXME - add time zone adjustment BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004070 memset(data, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00004071 ts.tv_nsec = 0;
4072 ts.tv_sec = time;
4073 /* decode time fields */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004074 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
4075 data->LastWriteTime = data->ChangeTime;
4076 data->LastAccessTime = 0;
4077 data->AllocationSize =
Steve French70ca7342005-09-22 16:32:06 -07004078 cpu_to_le64(le32_to_cpu(pSMBr->size));
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004079 data->EndOfFile = data->AllocationSize;
4080 data->Attributes =
Steve French70ca7342005-09-22 16:32:06 -07004081 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07004082 } else
4083 rc = -EIO; /* bad buffer passed in */
4084
4085 cifs_buf_release(pSMB);
4086
4087 if (rc == -EAGAIN)
4088 goto QInfRetry;
4089
4090 return rc;
4091}
4092
Jeff Laytonbcd53572010-02-12 07:44:16 -05004093int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004094CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05004095 u16 netfid, FILE_ALL_INFO *pFindData)
4096{
4097 struct smb_t2_qfi_req *pSMB = NULL;
4098 struct smb_t2_qfi_rsp *pSMBr = NULL;
4099 int rc = 0;
4100 int bytes_returned;
4101 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07004102
Jeff Laytonbcd53572010-02-12 07:44:16 -05004103QFileInfoRetry:
4104 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4105 (void **) &pSMBr);
4106 if (rc)
4107 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07004108
Jeff Laytonbcd53572010-02-12 07:44:16 -05004109 params = 2 /* level */ + 2 /* fid */;
4110 pSMB->t2.TotalDataCount = 0;
4111 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4112 /* BB find exact max data count below from sess structure BB */
4113 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4114 pSMB->t2.MaxSetupCount = 0;
4115 pSMB->t2.Reserved = 0;
4116 pSMB->t2.Flags = 0;
4117 pSMB->t2.Timeout = 0;
4118 pSMB->t2.Reserved2 = 0;
4119 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4120 Fid) - 4);
4121 pSMB->t2.DataCount = 0;
4122 pSMB->t2.DataOffset = 0;
4123 pSMB->t2.SetupCount = 1;
4124 pSMB->t2.Reserved3 = 0;
4125 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4126 byte_count = params + 1 /* pad */ ;
4127 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4128 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4129 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
4130 pSMB->Pad = 0;
4131 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004132 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004133 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004134
4135 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4136 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4137 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004138 cifs_dbg(FYI, "Send error in QFileInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05004139 } else { /* decode response */
4140 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4141
4142 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4143 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004144 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05004145 rc = -EIO; /* bad smb */
4146 else if (pFindData) {
4147 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4148 memcpy((char *) pFindData,
4149 (char *) &pSMBr->hdr.Protocol +
4150 data_offset, sizeof(FILE_ALL_INFO));
4151 } else
4152 rc = -ENOMEM;
4153 }
4154 cifs_buf_release(pSMB);
4155 if (rc == -EAGAIN)
4156 goto QFileInfoRetry;
4157
4158 return rc;
4159}
Steve French6b8edfe2005-08-23 20:26:03 -07004160
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004162CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004163 const char *search_name, FILE_ALL_INFO *data,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004164 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07004165 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004166{
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004167 /* level 263 SMB_QUERY_FILE_ALL_INFO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168 TRANSACTION2_QPI_REQ *pSMB = NULL;
4169 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4170 int rc = 0;
4171 int bytes_returned;
4172 int name_len;
4173 __u16 params, byte_count;
4174
Joe Perchesf96637b2013-05-04 22:12:25 -05004175 /* cifs_dbg(FYI, "In QPathInfo path %s\n", search_name); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176QPathInfoRetry:
4177 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4178 (void **) &pSMBr);
4179 if (rc)
4180 return rc;
4181
4182 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4183 name_len =
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004184 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06004185 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186 name_len++; /* trailing null */
4187 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004188 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004189 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190 name_len++; /* trailing null */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004191 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192 }
4193
Steve French50c2f752007-07-13 00:33:32 +00004194 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195 pSMB->TotalDataCount = 0;
4196 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004197 /* BB find exact max SMB PDU from sess structure BB */
4198 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199 pSMB->MaxSetupCount = 0;
4200 pSMB->Reserved = 0;
4201 pSMB->Flags = 0;
4202 pSMB->Timeout = 0;
4203 pSMB->Reserved2 = 0;
4204 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004205 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 pSMB->DataCount = 0;
4207 pSMB->DataOffset = 0;
4208 pSMB->SetupCount = 1;
4209 pSMB->Reserved3 = 0;
4210 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4211 byte_count = params + 1 /* pad */ ;
4212 pSMB->TotalParameterCount = cpu_to_le16(params);
4213 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00004214 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004215 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4216 else
4217 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004218 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004219 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220 pSMB->ByteCount = cpu_to_le16(byte_count);
4221
4222 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4223 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4224 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004225 cifs_dbg(FYI, "Send error in QPathInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226 } else { /* decode response */
4227 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4228
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004229 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4230 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04004231 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04004233 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00004234 rc = -EIO; /* 24 or 26 expected but we do not read
4235 last field */
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004236 else if (data) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004237 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00004239
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004240 /*
4241 * On legacy responses we do not read the last field,
4242 * EAsize, fortunately since it varies by subdialect and
4243 * also note it differs on Set vs Get, ie two bytes or 4
4244 * bytes depending but we don't care here.
4245 */
Steve Frenchad7a2922008-02-07 23:25:02 +00004246 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004247 size = sizeof(FILE_INFO_STANDARD);
4248 else
4249 size = sizeof(FILE_ALL_INFO);
Pavel Shilovsky68889f22012-05-25 14:40:22 +04004250 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00004251 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252 } else
4253 rc = -ENOMEM;
4254 }
4255 cifs_buf_release(pSMB);
4256 if (rc == -EAGAIN)
4257 goto QPathInfoRetry;
4258
4259 return rc;
4260}
4261
4262int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004263CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004264 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4265{
4266 struct smb_t2_qfi_req *pSMB = NULL;
4267 struct smb_t2_qfi_rsp *pSMBr = NULL;
4268 int rc = 0;
4269 int bytes_returned;
4270 __u16 params, byte_count;
4271
4272UnixQFileInfoRetry:
4273 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4274 (void **) &pSMBr);
4275 if (rc)
4276 return rc;
4277
4278 params = 2 /* level */ + 2 /* fid */;
4279 pSMB->t2.TotalDataCount = 0;
4280 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4281 /* BB find exact max data count below from sess structure BB */
4282 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4283 pSMB->t2.MaxSetupCount = 0;
4284 pSMB->t2.Reserved = 0;
4285 pSMB->t2.Flags = 0;
4286 pSMB->t2.Timeout = 0;
4287 pSMB->t2.Reserved2 = 0;
4288 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4289 Fid) - 4);
4290 pSMB->t2.DataCount = 0;
4291 pSMB->t2.DataOffset = 0;
4292 pSMB->t2.SetupCount = 1;
4293 pSMB->t2.Reserved3 = 0;
4294 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4295 byte_count = params + 1 /* pad */ ;
4296 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4297 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4298 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4299 pSMB->Pad = 0;
4300 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004301 inc_rfc1001_len(pSMB, byte_count);
David Disseldorp7ac0feb2013-06-28 11:47:33 +02004302 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004303
4304 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4305 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4306 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004307 cifs_dbg(FYI, "Send error in UnixQFileInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05004308 } else { /* decode response */
4309 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4310
Jeff Layton820a8032011-05-04 08:05:26 -04004311 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004312 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 -05004313 rc = -EIO; /* bad smb */
4314 } else {
4315 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4316 memcpy((char *) pFindData,
4317 (char *) &pSMBr->hdr.Protocol +
4318 data_offset,
4319 sizeof(FILE_UNIX_BASIC_INFO));
4320 }
4321 }
4322
4323 cifs_buf_release(pSMB);
4324 if (rc == -EAGAIN)
4325 goto UnixQFileInfoRetry;
4326
4327 return rc;
4328}
4329
4330int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004331CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00004333 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07004334 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335{
4336/* SMB_QUERY_FILE_UNIX_BASIC */
4337 TRANSACTION2_QPI_REQ *pSMB = NULL;
4338 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4339 int rc = 0;
4340 int bytes_returned = 0;
4341 int name_len;
4342 __u16 params, byte_count;
4343
Joe Perchesf96637b2013-05-04 22:12:25 -05004344 cifs_dbg(FYI, "In QPathInfo (Unix) the path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345UnixQPathInfoRetry:
4346 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4347 (void **) &pSMBr);
4348 if (rc)
4349 return rc;
4350
4351 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4352 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004353 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4354 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355 name_len++; /* trailing null */
4356 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004357 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358 name_len = strnlen(searchName, PATH_MAX);
4359 name_len++; /* trailing null */
4360 strncpy(pSMB->FileName, searchName, name_len);
4361 }
4362
Steve French50c2f752007-07-13 00:33:32 +00004363 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364 pSMB->TotalDataCount = 0;
4365 pSMB->MaxParameterCount = cpu_to_le16(2);
4366 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00004367 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368 pSMB->MaxSetupCount = 0;
4369 pSMB->Reserved = 0;
4370 pSMB->Flags = 0;
4371 pSMB->Timeout = 0;
4372 pSMB->Reserved2 = 0;
4373 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004374 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375 pSMB->DataCount = 0;
4376 pSMB->DataOffset = 0;
4377 pSMB->SetupCount = 1;
4378 pSMB->Reserved3 = 0;
4379 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4380 byte_count = params + 1 /* pad */ ;
4381 pSMB->TotalParameterCount = cpu_to_le16(params);
4382 pSMB->ParameterCount = pSMB->TotalParameterCount;
4383 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4384 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004385 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 pSMB->ByteCount = cpu_to_le16(byte_count);
4387
4388 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4389 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4390 if (rc) {
Steve Frenchebcc9432013-12-09 09:18:09 -06004391 cifs_dbg(FYI, "Send error in UnixQPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004392 } else { /* decode response */
4393 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4394
Jeff Layton820a8032011-05-04 08:05:26 -04004395 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004396 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 -07004397 rc = -EIO; /* bad smb */
4398 } else {
4399 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4400 memcpy((char *) pFindData,
4401 (char *) &pSMBr->hdr.Protocol +
4402 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00004403 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404 }
4405 }
4406 cifs_buf_release(pSMB);
4407 if (rc == -EAGAIN)
4408 goto UnixQPathInfoRetry;
4409
4410 return rc;
4411}
4412
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413/* xid, tcon, searchName and codepage are input parms, rest are returned */
4414int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004415CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004416 const char *searchName, struct cifs_sb_info *cifs_sb,
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004417 __u16 *pnetfid, __u16 search_flags,
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004418 struct cifs_search_info *psrch_inf, bool msearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419{
4420/* level 257 SMB_ */
4421 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4422 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004423 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 int rc = 0;
4425 int bytes_returned = 0;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004426 int name_len, remap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427 __u16 params, byte_count;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004428 struct nls_table *nls_codepage;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429
Joe Perchesf96637b2013-05-04 22:12:25 -05004430 cifs_dbg(FYI, "In FindFirst for %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004431
4432findFirstRetry:
4433 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4434 (void **) &pSMBr);
4435 if (rc)
4436 return rc;
4437
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004438 nls_codepage = cifs_sb->local_nls;
Steve French2baa2682014-09-27 02:19:01 -05004439 remap = cifs_remap(cifs_sb);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004440
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4442 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004443 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4444 PATH_MAX, nls_codepage, remap);
Steve French737b7582005-04-28 22:41:06 -07004445 /* We can not add the asterik earlier in case
4446 it got remapped to 0xF03A as if it were part of the
4447 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 name_len *= 2;
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004449 if (msearch) {
4450 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4451 pSMB->FileName[name_len+1] = 0;
4452 pSMB->FileName[name_len+2] = '*';
4453 pSMB->FileName[name_len+3] = 0;
4454 name_len += 4; /* now the trailing null */
4455 /* null terminate just in case */
4456 pSMB->FileName[name_len] = 0;
4457 pSMB->FileName[name_len+1] = 0;
4458 name_len += 2;
4459 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 } else { /* BB add check for overrun of SMB buf BB */
4461 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00004463 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004464 free buffer exit; BB */
4465 strncpy(pSMB->FileName, searchName, name_len);
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004466 if (msearch) {
4467 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4468 pSMB->FileName[name_len+1] = '*';
4469 pSMB->FileName[name_len+2] = 0;
4470 name_len += 3;
4471 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004472 }
4473
4474 params = 12 + name_len /* includes null */ ;
4475 pSMB->TotalDataCount = 0; /* no EAs */
4476 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004477 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 pSMB->MaxSetupCount = 0;
4479 pSMB->Reserved = 0;
4480 pSMB->Flags = 0;
4481 pSMB->Timeout = 0;
4482 pSMB->Reserved2 = 0;
4483 byte_count = params + 1 /* pad */ ;
4484 pSMB->TotalParameterCount = cpu_to_le16(params);
4485 pSMB->ParameterCount = pSMB->TotalParameterCount;
4486 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00004487 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4488 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489 pSMB->DataCount = 0;
4490 pSMB->DataOffset = 0;
4491 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4492 pSMB->Reserved3 = 0;
4493 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4494 pSMB->SearchAttributes =
4495 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4496 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004497 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004498 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4500
4501 /* BB what should we set StorageType to? Does it matter? BB */
4502 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004503 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504 pSMB->ByteCount = cpu_to_le16(byte_count);
4505
4506 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4507 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004508 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509
Steve French88274812006-03-09 22:21:45 +00004510 if (rc) {/* BB add logic to retry regular search if Unix search
4511 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512 /* BB Add code to handle unsupported level rc */
Joe Perchesf96637b2013-05-04 22:12:25 -05004513 cifs_dbg(FYI, "Error in FindFirst = %d\n", rc);
Steve French1982c342005-08-17 12:38:22 -07004514
Steve French88274812006-03-09 22:21:45 +00004515 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004516
4517 /* BB eventually could optimize out free and realloc of buf */
4518 /* for this case */
4519 if (rc == -EAGAIN)
4520 goto findFirstRetry;
4521 } else { /* decode response */
4522 /* BB remember to free buffer if error BB */
4523 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004524 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004525 unsigned int lnoff;
4526
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004528 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 else
Steve French4b18f2a2008-04-29 00:06:05 +00004530 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531
4532 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004533 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004534 psrch_inf->srch_entries_start =
4535 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4538 le16_to_cpu(pSMBr->t2.ParameterOffset));
4539
Steve French790fe572007-07-07 19:25:05 +00004540 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004541 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542 else
Steve French4b18f2a2008-04-29 00:06:05 +00004543 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544
Steve French50c2f752007-07-13 00:33:32 +00004545 psrch_inf->entries_in_buffer =
4546 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004547 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004549 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004550 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004551 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004552 psrch_inf->last_entry = NULL;
4553 return rc;
4554 }
4555
Steve French0752f152008-10-07 20:03:33 +00004556 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004557 lnoff;
4558
Shirish Pargaonkarc052e2b2012-09-28 12:21:14 -05004559 if (pnetfid)
4560 *pnetfid = parms->SearchHandle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561 } else {
4562 cifs_buf_release(pSMB);
4563 }
4564 }
4565
4566 return rc;
4567}
4568
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004569int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4570 __u16 searchHandle, __u16 search_flags,
4571 struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572{
4573 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4574 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004575 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576 char *response_data;
4577 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004578 int bytes_returned;
4579 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580 __u16 params, byte_count;
4581
Joe Perchesf96637b2013-05-04 22:12:25 -05004582 cifs_dbg(FYI, "In FindNext\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004583
Steve French4b18f2a2008-04-29 00:06:05 +00004584 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585 return -ENOENT;
4586
4587 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4588 (void **) &pSMBr);
4589 if (rc)
4590 return rc;
4591
Steve French50c2f752007-07-13 00:33:32 +00004592 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593 byte_count = 0;
4594 pSMB->TotalDataCount = 0; /* no EAs */
4595 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004596 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597 pSMB->MaxSetupCount = 0;
4598 pSMB->Reserved = 0;
4599 pSMB->Flags = 0;
4600 pSMB->Timeout = 0;
4601 pSMB->Reserved2 = 0;
4602 pSMB->ParameterOffset = cpu_to_le16(
4603 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4604 pSMB->DataCount = 0;
4605 pSMB->DataOffset = 0;
4606 pSMB->SetupCount = 1;
4607 pSMB->Reserved3 = 0;
4608 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4609 pSMB->SearchHandle = searchHandle; /* always kept as le */
4610 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004611 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4613 pSMB->ResumeKey = psrch_inf->resume_key;
Shirish Pargaonkar2608bee2012-05-15 10:19:16 -05004614 pSMB->SearchFlags = cpu_to_le16(search_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615
4616 name_len = psrch_inf->resume_name_len;
4617 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004618 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4620 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004621 /* 14 byte parm len above enough for 2 byte null terminator */
4622 pSMB->ResumeFileName[name_len] = 0;
4623 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624 } else {
4625 rc = -EINVAL;
4626 goto FNext2_err_exit;
4627 }
4628 byte_count = params + 1 /* pad */ ;
4629 pSMB->TotalParameterCount = cpu_to_le16(params);
4630 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004631 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004633
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4635 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004636 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637 if (rc) {
4638 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004639 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004640 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004641 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642 } else
Joe Perchesf96637b2013-05-04 22:12:25 -05004643 cifs_dbg(FYI, "FindNext returned = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644 } else { /* decode response */
4645 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004646
Steve French790fe572007-07-07 19:25:05 +00004647 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004648 unsigned int lnoff;
4649
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650 /* BB fixme add lock for file (srch_info) struct here */
4651 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004652 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004653 else
Steve French4b18f2a2008-04-29 00:06:05 +00004654 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004655 response_data = (char *) &pSMBr->hdr.Protocol +
4656 le16_to_cpu(pSMBr->t2.ParameterOffset);
4657 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4658 response_data = (char *)&pSMBr->hdr.Protocol +
4659 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004660 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004661 cifs_small_buf_release(
4662 psrch_inf->ntwrk_buf_start);
4663 else
4664 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665 psrch_inf->srch_entries_start = response_data;
4666 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004667 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004668 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004669 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670 else
Steve French4b18f2a2008-04-29 00:06:05 +00004671 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004672 psrch_inf->entries_in_buffer =
4673 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004674 psrch_inf->index_of_last_entry +=
4675 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004676 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004677 if (CIFSMaxBufSize < lnoff) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004678 cifs_dbg(VFS, "ignoring corrupt resume name\n");
Steve Frenchb77d7532008-10-08 19:13:46 +00004679 psrch_inf->last_entry = NULL;
4680 return rc;
4681 } else
4682 psrch_inf->last_entry =
4683 psrch_inf->srch_entries_start + lnoff;
4684
Joe Perchesf96637b2013-05-04 22:12:25 -05004685/* cifs_dbg(FYI, "fnxt2 entries in buf %d index_of_last %d\n",
4686 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687
4688 /* BB fixme add unlock here */
4689 }
4690
4691 }
4692
4693 /* BB On error, should we leave previous search buf (and count and
4694 last entry fields) intact or free the previous one? */
4695
4696 /* Note: On -EAGAIN error only caller can retry on handle based calls
4697 since file handle passed in no longer valid */
4698FNext2_err_exit:
4699 if (rc != 0)
4700 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701 return rc;
4702}
4703
4704int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004705CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004706 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707{
4708 int rc = 0;
4709 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004710
Joe Perchesf96637b2013-05-04 22:12:25 -05004711 cifs_dbg(FYI, "In CIFSSMBFindClose\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4713
4714 /* no sense returning error if session restarted
4715 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004716 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004717 return 0;
4718 if (rc)
4719 return rc;
4720
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721 pSMB->FileID = searchHandle;
4722 pSMB->ByteCount = 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04004723 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07004724 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00004725 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05004726 cifs_dbg(VFS, "Send error in FindClose = %d\n", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004727
Pavel Shilovsky44c58182012-05-28 14:16:31 +04004728 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729
4730 /* Since session is dead, search handle closed on server already */
4731 if (rc == -EAGAIN)
4732 rc = 0;
4733
4734 return rc;
4735}
4736
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004738CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004739 const char *search_name, __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004740 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741{
4742 int rc = 0;
4743 TRANSACTION2_QPI_REQ *pSMB = NULL;
4744 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4745 int name_len, bytes_returned;
4746 __u16 params, byte_count;
4747
Joe Perchesf96637b2013-05-04 22:12:25 -05004748 cifs_dbg(FYI, "In GetSrvInodeNum for %s\n", search_name);
Steve French790fe572007-07-07 19:25:05 +00004749 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004750 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004751
4752GetInodeNumberRetry:
4753 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004754 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755 if (rc)
4756 return rc;
4757
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4759 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004760 cifsConvertToUTF16((__le16 *) pSMB->FileName,
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004761 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004762 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763 name_len++; /* trailing null */
4764 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004765 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004766 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767 name_len++; /* trailing null */
Pavel Shilovsky1208ef12012-05-27 17:34:43 +04004768 strncpy(pSMB->FileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 }
4770
4771 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4772 pSMB->TotalDataCount = 0;
4773 pSMB->MaxParameterCount = cpu_to_le16(2);
4774 /* BB find exact max data count below from sess structure BB */
4775 pSMB->MaxDataCount = cpu_to_le16(4000);
4776 pSMB->MaxSetupCount = 0;
4777 pSMB->Reserved = 0;
4778 pSMB->Flags = 0;
4779 pSMB->Timeout = 0;
4780 pSMB->Reserved2 = 0;
4781 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004782 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004783 pSMB->DataCount = 0;
4784 pSMB->DataOffset = 0;
4785 pSMB->SetupCount = 1;
4786 pSMB->Reserved3 = 0;
4787 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4788 byte_count = params + 1 /* pad */ ;
4789 pSMB->TotalParameterCount = cpu_to_le16(params);
4790 pSMB->ParameterCount = pSMB->TotalParameterCount;
4791 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4792 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004793 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794 pSMB->ByteCount = cpu_to_le16(byte_count);
4795
4796 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4797 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4798 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004799 cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800 } else {
4801 /* decode response */
4802 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004804 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805 /* If rc should we check for EOPNOSUPP and
4806 disable the srvino flag? or in caller? */
4807 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004808 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4810 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004811 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004813 if (count < 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004814 cifs_dbg(FYI, "Illegal size ret in QryIntrnlInf\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815 rc = -EIO;
4816 goto GetInodeNumOut;
4817 }
4818 pfinfo = (struct file_internal_info *)
4819 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004820 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821 }
4822 }
4823GetInodeNumOut:
4824 cifs_buf_release(pSMB);
4825 if (rc == -EAGAIN)
4826 goto GetInodeNumberRetry;
4827 return rc;
4828}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829
4830int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004831CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004832 const char *search_name, struct dfs_info3_param **target_nodes,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004833 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004834 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835{
4836/* TRANS2_GET_DFS_REFERRAL */
4837 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4838 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839 int rc = 0;
4840 int bytes_returned;
4841 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004842 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004843 *num_of_nodes = 0;
4844 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845
Joe Perchesf96637b2013-05-04 22:12:25 -05004846 cifs_dbg(FYI, "In GetDFSRefer the path %s\n", search_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847 if (ses == NULL)
4848 return -ENODEV;
4849getDFSRetry:
4850 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4851 (void **) &pSMBr);
4852 if (rc)
4853 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004854
4855 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004856 but should never be null here anyway */
Pavel Shilovsky88257362012-05-23 14:01:59 +04004857 pSMB->hdr.Mid = get_next_mid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004858 pSMB->hdr.Tid = ses->ipc_tid;
4859 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004860 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004861 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004862 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004864
4865 if (ses->capabilities & CAP_UNICODE) {
4866 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4867 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06004868 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004869 search_name, PATH_MAX, nls_codepage,
Steve Frenchacbbb762012-01-18 22:32:33 -06004870 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871 name_len++; /* trailing null */
4872 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004873 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004874 name_len = strnlen(search_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875 name_len++; /* trailing null */
Pavel Shilovskyb669f332012-05-27 20:21:53 +04004876 strncpy(pSMB->RequestFileName, search_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004877 }
4878
Dan Carpenter65c3b202015-04-30 17:30:24 +03004879 if (ses->server->sign)
Jeff Layton38d77c52013-05-26 07:01:00 -04004880 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Steve French1a4e15a2006-10-12 21:33:51 +00004881
Steve French50c2f752007-07-13 00:33:32 +00004882 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004883
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884 params = 2 /* level */ + name_len /*includes null */ ;
4885 pSMB->TotalDataCount = 0;
4886 pSMB->DataCount = 0;
4887 pSMB->DataOffset = 0;
4888 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004889 /* BB find exact max SMB PDU from sess structure BB */
4890 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891 pSMB->MaxSetupCount = 0;
4892 pSMB->Reserved = 0;
4893 pSMB->Flags = 0;
4894 pSMB->Timeout = 0;
4895 pSMB->Reserved2 = 0;
4896 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004897 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898 pSMB->SetupCount = 1;
4899 pSMB->Reserved3 = 0;
4900 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4901 byte_count = params + 3 /* pad */ ;
4902 pSMB->ParameterCount = cpu_to_le16(params);
4903 pSMB->TotalParameterCount = pSMB->ParameterCount;
4904 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004905 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004906 pSMB->ByteCount = cpu_to_le16(byte_count);
4907
4908 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4909 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4910 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004911 cifs_dbg(FYI, "Send error in GetDFSRefer = %d\n", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004912 goto GetDFSRefExit;
4913 }
4914 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004915
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004916 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004917 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004918 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004919 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004920 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004921
Joe Perchesf96637b2013-05-04 22:12:25 -05004922 cifs_dbg(FYI, "Decoding GetDFSRefer response BCC: %d Offset %d\n",
4923 get_bcc(&pSMBr->hdr), le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004924
4925 /* parse returned result into more usable form */
Aurelien Aptel4ecce922017-02-13 16:03:47 +01004926 rc = parse_dfs_referrals(&pSMBr->dfs_data,
4927 le16_to_cpu(pSMBr->t2.DataCount),
4928 num_of_nodes, target_nodes, nls_codepage,
4929 remap, search_name,
Steve French284316d2017-03-02 15:42:48 -06004930 (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) != 0);
Igor Mammedovfec45852008-05-16 13:06:30 +04004931
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004933 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004934
4935 if (rc == -EAGAIN)
4936 goto getDFSRetry;
4937
4938 return rc;
4939}
4940
Steve French20962432005-09-21 22:05:57 -07004941/* Query File System Info such as free space to old servers such as Win 9x */
4942int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04004943SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4944 struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004945{
4946/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4947 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4948 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4949 FILE_SYSTEM_ALLOC_INFO *response_data;
4950 int rc = 0;
4951 int bytes_returned = 0;
4952 __u16 params, byte_count;
4953
Joe Perchesf96637b2013-05-04 22:12:25 -05004954 cifs_dbg(FYI, "OldQFSInfo\n");
Steve French20962432005-09-21 22:05:57 -07004955oldQFSInfoRetry:
4956 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4957 (void **) &pSMBr);
4958 if (rc)
4959 return rc;
Steve French20962432005-09-21 22:05:57 -07004960
4961 params = 2; /* level */
4962 pSMB->TotalDataCount = 0;
4963 pSMB->MaxParameterCount = cpu_to_le16(2);
4964 pSMB->MaxDataCount = cpu_to_le16(1000);
4965 pSMB->MaxSetupCount = 0;
4966 pSMB->Reserved = 0;
4967 pSMB->Flags = 0;
4968 pSMB->Timeout = 0;
4969 pSMB->Reserved2 = 0;
4970 byte_count = params + 1 /* pad */ ;
4971 pSMB->TotalParameterCount = cpu_to_le16(params);
4972 pSMB->ParameterCount = pSMB->TotalParameterCount;
4973 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4974 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4975 pSMB->DataCount = 0;
4976 pSMB->DataOffset = 0;
4977 pSMB->SetupCount = 1;
4978 pSMB->Reserved3 = 0;
4979 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4980 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004981 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004982 pSMB->ByteCount = cpu_to_le16(byte_count);
4983
4984 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4985 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4986 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05004987 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Steve French20962432005-09-21 22:05:57 -07004988 } else { /* decode response */
4989 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4990
Jeff Layton820a8032011-05-04 08:05:26 -04004991 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004992 rc = -EIO; /* bad smb */
4993 else {
4994 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05004995 cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n",
Jeff Layton820a8032011-05-04 08:05:26 -04004996 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004997
Steve French50c2f752007-07-13 00:33:32 +00004998 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004999 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5000 FSData->f_bsize =
5001 le16_to_cpu(response_data->BytesPerSector) *
5002 le32_to_cpu(response_data->
5003 SectorsPerAllocationUnit);
5004 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00005005 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07005006 FSData->f_bfree = FSData->f_bavail =
5007 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005008 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5009 (unsigned long long)FSData->f_blocks,
5010 (unsigned long long)FSData->f_bfree,
5011 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07005012 }
5013 }
5014 cifs_buf_release(pSMB);
5015
5016 if (rc == -EAGAIN)
5017 goto oldQFSInfoRetry;
5018
5019 return rc;
5020}
5021
Linus Torvalds1da177e2005-04-16 15:20:36 -07005022int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005023CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
5024 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005025{
5026/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
5027 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5028 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5029 FILE_SYSTEM_INFO *response_data;
5030 int rc = 0;
5031 int bytes_returned = 0;
5032 __u16 params, byte_count;
5033
Joe Perchesf96637b2013-05-04 22:12:25 -05005034 cifs_dbg(FYI, "In QFSInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005035QFSInfoRetry:
5036 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5037 (void **) &pSMBr);
5038 if (rc)
5039 return rc;
5040
5041 params = 2; /* level */
5042 pSMB->TotalDataCount = 0;
5043 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07005044 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005045 pSMB->MaxSetupCount = 0;
5046 pSMB->Reserved = 0;
5047 pSMB->Flags = 0;
5048 pSMB->Timeout = 0;
5049 pSMB->Reserved2 = 0;
5050 byte_count = params + 1 /* pad */ ;
5051 pSMB->TotalParameterCount = cpu_to_le16(params);
5052 pSMB->ParameterCount = pSMB->TotalParameterCount;
5053 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005054 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005055 pSMB->DataCount = 0;
5056 pSMB->DataOffset = 0;
5057 pSMB->SetupCount = 1;
5058 pSMB->Reserved3 = 0;
5059 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5060 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005061 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005062 pSMB->ByteCount = cpu_to_le16(byte_count);
5063
5064 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5065 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5066 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005067 cifs_dbg(FYI, "Send error in QFSInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005068 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00005069 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070
Jeff Layton820a8032011-05-04 08:05:26 -04005071 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072 rc = -EIO; /* bad smb */
5073 else {
5074 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005075
5076 response_data =
5077 (FILE_SYSTEM_INFO
5078 *) (((char *) &pSMBr->hdr.Protocol) +
5079 data_offset);
5080 FSData->f_bsize =
5081 le32_to_cpu(response_data->BytesPerSector) *
5082 le32_to_cpu(response_data->
5083 SectorsPerAllocationUnit);
5084 FSData->f_blocks =
5085 le64_to_cpu(response_data->TotalAllocationUnits);
5086 FSData->f_bfree = FSData->f_bavail =
5087 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesf96637b2013-05-04 22:12:25 -05005088 cifs_dbg(FYI, "Blocks: %lld Free: %lld Block size %ld\n",
5089 (unsigned long long)FSData->f_blocks,
5090 (unsigned long long)FSData->f_bfree,
5091 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005092 }
5093 }
5094 cifs_buf_release(pSMB);
5095
5096 if (rc == -EAGAIN)
5097 goto QFSInfoRetry;
5098
5099 return rc;
5100}
5101
5102int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005103CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104{
5105/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5106 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5107 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5108 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5109 int rc = 0;
5110 int bytes_returned = 0;
5111 __u16 params, byte_count;
5112
Joe Perchesf96637b2013-05-04 22:12:25 -05005113 cifs_dbg(FYI, "In QFSAttributeInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114QFSAttributeRetry:
5115 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5116 (void **) &pSMBr);
5117 if (rc)
5118 return rc;
5119
5120 params = 2; /* level */
5121 pSMB->TotalDataCount = 0;
5122 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005123 /* BB find exact max SMB PDU from sess structure BB */
5124 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005125 pSMB->MaxSetupCount = 0;
5126 pSMB->Reserved = 0;
5127 pSMB->Flags = 0;
5128 pSMB->Timeout = 0;
5129 pSMB->Reserved2 = 0;
5130 byte_count = params + 1 /* pad */ ;
5131 pSMB->TotalParameterCount = cpu_to_le16(params);
5132 pSMB->ParameterCount = pSMB->TotalParameterCount;
5133 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005134 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005135 pSMB->DataCount = 0;
5136 pSMB->DataOffset = 0;
5137 pSMB->SetupCount = 1;
5138 pSMB->Reserved3 = 0;
5139 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5140 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005141 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005142 pSMB->ByteCount = cpu_to_le16(byte_count);
5143
5144 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5145 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5146 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005147 cifs_dbg(VFS, "Send error in QFSAttributeInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148 } else { /* decode response */
5149 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5150
Jeff Layton820a8032011-05-04 08:05:26 -04005151 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00005152 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005153 rc = -EIO; /* bad smb */
5154 } else {
5155 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5156 response_data =
5157 (FILE_SYSTEM_ATTRIBUTE_INFO
5158 *) (((char *) &pSMBr->hdr.Protocol) +
5159 data_offset);
5160 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005161 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162 }
5163 }
5164 cifs_buf_release(pSMB);
5165
5166 if (rc == -EAGAIN)
5167 goto QFSAttributeRetry;
5168
5169 return rc;
5170}
5171
5172int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005173CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005174{
5175/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5176 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5177 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5178 FILE_SYSTEM_DEVICE_INFO *response_data;
5179 int rc = 0;
5180 int bytes_returned = 0;
5181 __u16 params, byte_count;
5182
Joe Perchesf96637b2013-05-04 22:12:25 -05005183 cifs_dbg(FYI, "In QFSDeviceInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184QFSDeviceRetry:
5185 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5186 (void **) &pSMBr);
5187 if (rc)
5188 return rc;
5189
5190 params = 2; /* level */
5191 pSMB->TotalDataCount = 0;
5192 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005193 /* BB find exact max SMB PDU from sess structure BB */
5194 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195 pSMB->MaxSetupCount = 0;
5196 pSMB->Reserved = 0;
5197 pSMB->Flags = 0;
5198 pSMB->Timeout = 0;
5199 pSMB->Reserved2 = 0;
5200 byte_count = params + 1 /* pad */ ;
5201 pSMB->TotalParameterCount = cpu_to_le16(params);
5202 pSMB->ParameterCount = pSMB->TotalParameterCount;
5203 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005204 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005205
5206 pSMB->DataCount = 0;
5207 pSMB->DataOffset = 0;
5208 pSMB->SetupCount = 1;
5209 pSMB->Reserved3 = 0;
5210 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5211 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005212 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213 pSMB->ByteCount = cpu_to_le16(byte_count);
5214
5215 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5216 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5217 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005218 cifs_dbg(FYI, "Send error in QFSDeviceInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219 } else { /* decode response */
5220 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5221
Jeff Layton820a8032011-05-04 08:05:26 -04005222 if (rc || get_bcc(&pSMBr->hdr) <
5223 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224 rc = -EIO; /* bad smb */
5225 else {
5226 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5227 response_data =
Steve French737b7582005-04-28 22:41:06 -07005228 (FILE_SYSTEM_DEVICE_INFO *)
5229 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230 data_offset);
5231 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005232 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233 }
5234 }
5235 cifs_buf_release(pSMB);
5236
5237 if (rc == -EAGAIN)
5238 goto QFSDeviceRetry;
5239
5240 return rc;
5241}
5242
5243int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005244CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005245{
5246/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5247 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5248 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5249 FILE_SYSTEM_UNIX_INFO *response_data;
5250 int rc = 0;
5251 int bytes_returned = 0;
5252 __u16 params, byte_count;
5253
Joe Perchesf96637b2013-05-04 22:12:25 -05005254 cifs_dbg(FYI, "In QFSUnixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005255QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04005256 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5257 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005258 if (rc)
5259 return rc;
5260
5261 params = 2; /* level */
5262 pSMB->TotalDataCount = 0;
5263 pSMB->DataCount = 0;
5264 pSMB->DataOffset = 0;
5265 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005266 /* BB find exact max SMB PDU from sess structure BB */
5267 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268 pSMB->MaxSetupCount = 0;
5269 pSMB->Reserved = 0;
5270 pSMB->Flags = 0;
5271 pSMB->Timeout = 0;
5272 pSMB->Reserved2 = 0;
5273 byte_count = params + 1 /* pad */ ;
5274 pSMB->ParameterCount = cpu_to_le16(params);
5275 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005276 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5277 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005278 pSMB->SetupCount = 1;
5279 pSMB->Reserved3 = 0;
5280 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5281 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005282 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005283 pSMB->ByteCount = cpu_to_le16(byte_count);
5284
5285 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5286 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5287 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005288 cifs_dbg(VFS, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005289 } else { /* decode response */
5290 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5291
Jeff Layton820a8032011-05-04 08:05:26 -04005292 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005293 rc = -EIO; /* bad smb */
5294 } else {
5295 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5296 response_data =
5297 (FILE_SYSTEM_UNIX_INFO
5298 *) (((char *) &pSMBr->hdr.Protocol) +
5299 data_offset);
5300 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00005301 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005302 }
5303 }
5304 cifs_buf_release(pSMB);
5305
5306 if (rc == -EAGAIN)
5307 goto QFSUnixRetry;
5308
5309
5310 return rc;
5311}
5312
Jeremy Allisonac670552005-06-22 17:26:35 -07005313int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005314CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07005315{
5316/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5317 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5318 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5319 int rc = 0;
5320 int bytes_returned = 0;
5321 __u16 params, param_offset, offset, byte_count;
5322
Joe Perchesf96637b2013-05-04 22:12:25 -05005323 cifs_dbg(FYI, "In SETFSUnixInfo\n");
Jeremy Allisonac670552005-06-22 17:26:35 -07005324SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00005325 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04005326 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5327 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07005328 if (rc)
5329 return rc;
5330
5331 params = 4; /* 2 bytes zero followed by info level. */
5332 pSMB->MaxSetupCount = 0;
5333 pSMB->Reserved = 0;
5334 pSMB->Flags = 0;
5335 pSMB->Timeout = 0;
5336 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00005337 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5338 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07005339 offset = param_offset + params;
5340
5341 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00005342 /* BB find exact max SMB PDU from sess structure BB */
5343 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07005344 pSMB->SetupCount = 1;
5345 pSMB->Reserved3 = 0;
5346 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5347 byte_count = 1 /* pad */ + params + 12;
5348
5349 pSMB->DataCount = cpu_to_le16(12);
5350 pSMB->ParameterCount = cpu_to_le16(params);
5351 pSMB->TotalDataCount = pSMB->DataCount;
5352 pSMB->TotalParameterCount = pSMB->ParameterCount;
5353 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5354 pSMB->DataOffset = cpu_to_le16(offset);
5355
5356 /* Params. */
5357 pSMB->FileNum = 0;
5358 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5359
5360 /* Data. */
5361 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5362 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5363 pSMB->ClientUnixCap = cpu_to_le64(cap);
5364
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005365 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07005366 pSMB->ByteCount = cpu_to_le16(byte_count);
5367
5368 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5369 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5370 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005371 cifs_dbg(VFS, "Send error in SETFSUnixInfo = %d\n", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07005372 } else { /* decode response */
5373 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00005374 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07005375 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07005376 }
5377 cifs_buf_release(pSMB);
5378
5379 if (rc == -EAGAIN)
5380 goto SETFSUnixRetry;
5381
5382 return rc;
5383}
5384
5385
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386
5387int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005388CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005389 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005390{
5391/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5392 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5393 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5394 FILE_SYSTEM_POSIX_INFO *response_data;
5395 int rc = 0;
5396 int bytes_returned = 0;
5397 __u16 params, byte_count;
5398
Joe Perchesf96637b2013-05-04 22:12:25 -05005399 cifs_dbg(FYI, "In QFSPosixInfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005400QFSPosixRetry:
5401 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5402 (void **) &pSMBr);
5403 if (rc)
5404 return rc;
5405
5406 params = 2; /* level */
5407 pSMB->TotalDataCount = 0;
5408 pSMB->DataCount = 0;
5409 pSMB->DataOffset = 0;
5410 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005411 /* BB find exact max SMB PDU from sess structure BB */
5412 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005413 pSMB->MaxSetupCount = 0;
5414 pSMB->Reserved = 0;
5415 pSMB->Flags = 0;
5416 pSMB->Timeout = 0;
5417 pSMB->Reserved2 = 0;
5418 byte_count = params + 1 /* pad */ ;
5419 pSMB->ParameterCount = cpu_to_le16(params);
5420 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005421 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5422 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005423 pSMB->SetupCount = 1;
5424 pSMB->Reserved3 = 0;
5425 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5426 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005427 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005428 pSMB->ByteCount = cpu_to_le16(byte_count);
5429
5430 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5431 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5432 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005433 cifs_dbg(FYI, "Send error in QFSUnixInfo = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434 } else { /* decode response */
5435 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5436
Jeff Layton820a8032011-05-04 08:05:26 -04005437 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438 rc = -EIO; /* bad smb */
5439 } else {
5440 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5441 response_data =
5442 (FILE_SYSTEM_POSIX_INFO
5443 *) (((char *) &pSMBr->hdr.Protocol) +
5444 data_offset);
5445 FSData->f_bsize =
5446 le32_to_cpu(response_data->BlockSize);
5447 FSData->f_blocks =
5448 le64_to_cpu(response_data->TotalBlocks);
5449 FSData->f_bfree =
5450 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005451 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005452 FSData->f_bavail = FSData->f_bfree;
5453 } else {
5454 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005455 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456 }
Steve French790fe572007-07-07 19:25:05 +00005457 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005458 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005459 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005460 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005461 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005462 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005463 }
5464 }
5465 cifs_buf_release(pSMB);
5466
5467 if (rc == -EAGAIN)
5468 goto QFSPosixRetry;
5469
5470 return rc;
5471}
5472
5473
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005474/*
5475 * We can not use write of zero bytes trick to set file size due to need for
5476 * large file support. Also note that this SetPathInfo is preferred to
5477 * SetFileInfo based method in next routine which is only needed to work around
5478 * a sharing violation bugin Samba which this routine can run into.
5479 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005481CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005482 const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
5483 bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005484{
5485 struct smb_com_transaction2_spi_req *pSMB = NULL;
5486 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5487 struct file_end_of_file_info *parm_data;
5488 int name_len;
5489 int rc = 0;
5490 int bytes_returned = 0;
Steve French2baa2682014-09-27 02:19:01 -05005491 int remap = cifs_remap(cifs_sb);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005492
Linus Torvalds1da177e2005-04-16 15:20:36 -07005493 __u16 params, byte_count, data_count, param_offset, offset;
5494
Joe Perchesf96637b2013-05-04 22:12:25 -05005495 cifs_dbg(FYI, "In SetEOF\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005496SetEOFRetry:
5497 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5498 (void **) &pSMBr);
5499 if (rc)
5500 return rc;
5501
5502 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5503 name_len =
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005504 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
5505 PATH_MAX, cifs_sb->local_nls, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005506 name_len++; /* trailing null */
5507 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005508 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005509 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005510 name_len++; /* trailing null */
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005511 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005512 }
5513 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005514 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005516 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517 pSMB->MaxSetupCount = 0;
5518 pSMB->Reserved = 0;
5519 pSMB->Flags = 0;
5520 pSMB->Timeout = 0;
5521 pSMB->Reserved2 = 0;
5522 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005523 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005524 offset = param_offset + params;
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005525 if (set_allocation) {
Steve French50c2f752007-07-13 00:33:32 +00005526 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5527 pSMB->InformationLevel =
5528 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5529 else
5530 pSMB->InformationLevel =
5531 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5532 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005533 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5534 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005535 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536 else
5537 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005538 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005539 }
5540
5541 parm_data =
5542 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5543 offset);
5544 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5545 pSMB->DataOffset = cpu_to_le16(offset);
5546 pSMB->SetupCount = 1;
5547 pSMB->Reserved3 = 0;
5548 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5549 byte_count = 3 /* pad */ + params + data_count;
5550 pSMB->DataCount = cpu_to_le16(data_count);
5551 pSMB->TotalDataCount = pSMB->DataCount;
5552 pSMB->ParameterCount = cpu_to_le16(params);
5553 pSMB->TotalParameterCount = pSMB->ParameterCount;
5554 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005555 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005556 parm_data->FileSize = cpu_to_le64(size);
5557 pSMB->ByteCount = cpu_to_le16(byte_count);
5558 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5559 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005560 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005561 cifs_dbg(FYI, "SetPathInfo (file size) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562
5563 cifs_buf_release(pSMB);
5564
5565 if (rc == -EAGAIN)
5566 goto SetEOFRetry;
5567
5568 return rc;
5569}
5570
5571int
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005572CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
5573 struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005574{
5575 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576 struct file_end_of_file_info *parm_data;
5577 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578 __u16 params, param_offset, offset, byte_count, count;
5579
Joe Perchesf96637b2013-05-04 22:12:25 -05005580 cifs_dbg(FYI, "SetFileSize (via SetFileInfo) %lld\n",
5581 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005582 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5583
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584 if (rc)
5585 return rc;
5586
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005587 pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
5588 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005589
Linus Torvalds1da177e2005-04-16 15:20:36 -07005590 params = 6;
5591 pSMB->MaxSetupCount = 0;
5592 pSMB->Reserved = 0;
5593 pSMB->Flags = 0;
5594 pSMB->Timeout = 0;
5595 pSMB->Reserved2 = 0;
5596 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5597 offset = param_offset + params;
5598
Linus Torvalds1da177e2005-04-16 15:20:36 -07005599 count = sizeof(struct file_end_of_file_info);
5600 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005601 /* BB find exact max SMB PDU from sess structure BB */
5602 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005603 pSMB->SetupCount = 1;
5604 pSMB->Reserved3 = 0;
5605 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5606 byte_count = 3 /* pad */ + params + count;
5607 pSMB->DataCount = cpu_to_le16(count);
5608 pSMB->ParameterCount = cpu_to_le16(params);
5609 pSMB->TotalDataCount = pSMB->DataCount;
5610 pSMB->TotalParameterCount = pSMB->ParameterCount;
5611 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5612 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005613 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5614 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005615 pSMB->DataOffset = cpu_to_le16(offset);
5616 parm_data->FileSize = cpu_to_le64(size);
Pavel Shilovskyd1433412012-09-18 16:20:31 -07005617 pSMB->Fid = cfile->fid.netfid;
5618 if (set_allocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005619 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5620 pSMB->InformationLevel =
5621 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5622 else
5623 pSMB->InformationLevel =
5624 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005625 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5627 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005628 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629 else
5630 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005631 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632 }
5633 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005634 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635 pSMB->ByteCount = cpu_to_le16(byte_count);
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005636 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005637 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005638 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05005639 cifs_dbg(FYI, "Send error in SetFileInfo (SetFileSize) = %d\n",
5640 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005641 }
5642
Steve French50c2f752007-07-13 00:33:32 +00005643 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005644 since file handle passed in no longer valid */
5645
5646 return rc;
5647}
5648
Steve French50c2f752007-07-13 00:33:32 +00005649/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650 an open handle, rather than by pathname - this is awkward due to
5651 potential access conflicts on the open, but it is unavoidable for these
5652 old servers since the only other choice is to go from 100 nanosecond DCE
5653 time and resort to the original setpathinfo level which takes the ancient
5654 DOS time format with 2 second granularity */
5655int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005656CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005657 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658{
5659 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005660 char *data_offset;
5661 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005662 __u16 params, param_offset, offset, byte_count, count;
5663
Joe Perchesf96637b2013-05-04 22:12:25 -05005664 cifs_dbg(FYI, "Set Times (via SetFileInfo)\n");
Steve Frenchcd634992005-04-28 22:41:10 -07005665 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5666
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667 if (rc)
5668 return rc;
5669
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005670 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5671 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005672
Linus Torvalds1da177e2005-04-16 15:20:36 -07005673 params = 6;
5674 pSMB->MaxSetupCount = 0;
5675 pSMB->Reserved = 0;
5676 pSMB->Flags = 0;
5677 pSMB->Timeout = 0;
5678 pSMB->Reserved2 = 0;
5679 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5680 offset = param_offset + params;
5681
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005682 data_offset = (char *)pSMB +
5683 offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005684
Steve French26f57362007-08-30 22:09:15 +00005685 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005686 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005687 /* BB find max SMB PDU from sess */
5688 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689 pSMB->SetupCount = 1;
5690 pSMB->Reserved3 = 0;
5691 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5692 byte_count = 3 /* pad */ + params + count;
5693 pSMB->DataCount = cpu_to_le16(count);
5694 pSMB->ParameterCount = cpu_to_le16(params);
5695 pSMB->TotalDataCount = pSMB->DataCount;
5696 pSMB->TotalParameterCount = pSMB->ParameterCount;
5697 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5698 pSMB->DataOffset = cpu_to_le16(offset);
5699 pSMB->Fid = fid;
5700 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5701 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5702 else
5703 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5704 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005705 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005706 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005707 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005708 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005709 cifs_small_buf_release(pSMB);
Steve Frenchad7a2922008-02-07 23:25:02 +00005710 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005711 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
5712 rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005713
Steve French50c2f752007-07-13 00:33:32 +00005714 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005715 since file handle passed in no longer valid */
5716
5717 return rc;
5718}
5719
Jeff Layton6d22f092008-09-23 11:48:35 -04005720int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005721CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005722 bool delete_file, __u16 fid, __u32 pid_of_opener)
5723{
5724 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5725 char *data_offset;
5726 int rc = 0;
5727 __u16 params, param_offset, offset, byte_count, count;
5728
Joe Perchesf96637b2013-05-04 22:12:25 -05005729 cifs_dbg(FYI, "Set File Disposition (via SetFileInfo)\n");
Jeff Layton6d22f092008-09-23 11:48:35 -04005730 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5731
5732 if (rc)
5733 return rc;
5734
5735 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5736 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5737
5738 params = 6;
5739 pSMB->MaxSetupCount = 0;
5740 pSMB->Reserved = 0;
5741 pSMB->Flags = 0;
5742 pSMB->Timeout = 0;
5743 pSMB->Reserved2 = 0;
5744 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5745 offset = param_offset + params;
5746
5747 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5748
5749 count = 1;
5750 pSMB->MaxParameterCount = cpu_to_le16(2);
5751 /* BB find max SMB PDU from sess */
5752 pSMB->MaxDataCount = cpu_to_le16(1000);
5753 pSMB->SetupCount = 1;
5754 pSMB->Reserved3 = 0;
5755 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5756 byte_count = 3 /* pad */ + params + count;
5757 pSMB->DataCount = cpu_to_le16(count);
5758 pSMB->ParameterCount = cpu_to_le16(params);
5759 pSMB->TotalDataCount = pSMB->DataCount;
5760 pSMB->TotalParameterCount = pSMB->ParameterCount;
5761 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5762 pSMB->DataOffset = cpu_to_le16(offset);
5763 pSMB->Fid = fid;
5764 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5765 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005766 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005767 pSMB->ByteCount = cpu_to_le16(byte_count);
5768 *data_offset = delete_file ? 1 : 0;
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04005769 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07005770 cifs_small_buf_release(pSMB);
Jeff Layton6d22f092008-09-23 11:48:35 -04005771 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005772 cifs_dbg(FYI, "Send error in SetFileDisposition = %d\n", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005773
5774 return rc;
5775}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005776
5777int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005778CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005779 const char *fileName, const FILE_BASIC_INFO *data,
5780 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005781{
5782 TRANSACTION2_SPI_REQ *pSMB = NULL;
5783 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5784 int name_len;
5785 int rc = 0;
5786 int bytes_returned = 0;
5787 char *data_offset;
5788 __u16 params, param_offset, offset, byte_count, count;
5789
Joe Perchesf96637b2013-05-04 22:12:25 -05005790 cifs_dbg(FYI, "In SetTimes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791
5792SetTimesRetry:
5793 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5794 (void **) &pSMBr);
5795 if (rc)
5796 return rc;
5797
5798 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5799 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005800 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5801 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005802 name_len++; /* trailing null */
5803 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005804 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005805 name_len = strnlen(fileName, PATH_MAX);
5806 name_len++; /* trailing null */
5807 strncpy(pSMB->FileName, fileName, name_len);
5808 }
5809
5810 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005811 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005812 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005813 /* BB find max SMB PDU from sess structure BB */
5814 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005815 pSMB->MaxSetupCount = 0;
5816 pSMB->Reserved = 0;
5817 pSMB->Flags = 0;
5818 pSMB->Timeout = 0;
5819 pSMB->Reserved2 = 0;
5820 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005821 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005822 offset = param_offset + params;
5823 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5824 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5825 pSMB->DataOffset = cpu_to_le16(offset);
5826 pSMB->SetupCount = 1;
5827 pSMB->Reserved3 = 0;
5828 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5829 byte_count = 3 /* pad */ + params + count;
5830
5831 pSMB->DataCount = cpu_to_le16(count);
5832 pSMB->ParameterCount = cpu_to_le16(params);
5833 pSMB->TotalDataCount = pSMB->DataCount;
5834 pSMB->TotalParameterCount = pSMB->ParameterCount;
5835 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5836 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5837 else
5838 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5839 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005840 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005841 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005842 pSMB->ByteCount = cpu_to_le16(byte_count);
5843 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5844 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005845 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005846 cifs_dbg(FYI, "SetPathInfo (times) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847
5848 cifs_buf_release(pSMB);
5849
5850 if (rc == -EAGAIN)
5851 goto SetTimesRetry;
5852
5853 return rc;
5854}
5855
5856/* Can not be used to set time stamps yet (due to old DOS time format) */
5857/* Can be used to set attributes */
5858#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5859 handling it anyway and NT4 was what we thought it would be needed for
5860 Do not delete it until we prove whether needed for Win9x though */
5861int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005862CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005863 __u16 dos_attrs, const struct nls_table *nls_codepage)
5864{
5865 SETATTR_REQ *pSMB = NULL;
5866 SETATTR_RSP *pSMBr = NULL;
5867 int rc = 0;
5868 int bytes_returned;
5869 int name_len;
5870
Joe Perchesf96637b2013-05-04 22:12:25 -05005871 cifs_dbg(FYI, "In SetAttrLegacy\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005872
5873SetAttrLgcyRetry:
5874 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5875 (void **) &pSMBr);
5876 if (rc)
5877 return rc;
5878
5879 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5880 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06005881 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5882 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005883 name_len++; /* trailing null */
5884 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005885 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005886 name_len = strnlen(fileName, PATH_MAX);
5887 name_len++; /* trailing null */
5888 strncpy(pSMB->fileName, fileName, name_len);
5889 }
5890 pSMB->attr = cpu_to_le16(dos_attrs);
5891 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005892 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005893 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5894 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5895 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005896 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05005897 cifs_dbg(FYI, "Error in LegacySetAttr = %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005898
5899 cifs_buf_release(pSMB);
5900
5901 if (rc == -EAGAIN)
5902 goto SetAttrLgcyRetry;
5903
5904 return rc;
5905}
5906#endif /* temporarily unneeded SetAttr legacy function */
5907
Jeff Layton654cf142009-07-09 20:02:49 -04005908static void
5909cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5910 const struct cifs_unix_set_info_args *args)
5911{
Eric W. Biederman49418b22013-02-06 00:57:56 -08005912 u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64;
Jeff Layton654cf142009-07-09 20:02:49 -04005913 u64 mode = args->mode;
5914
Eric W. Biederman49418b22013-02-06 00:57:56 -08005915 if (uid_valid(args->uid))
5916 uid = from_kuid(&init_user_ns, args->uid);
5917 if (gid_valid(args->gid))
5918 gid = from_kgid(&init_user_ns, args->gid);
5919
Jeff Layton654cf142009-07-09 20:02:49 -04005920 /*
5921 * Samba server ignores set of file size to zero due to bugs in some
5922 * older clients, but we should be precise - we use SetFileSize to
5923 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005924 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005925 * zero instead of -1 here
5926 */
5927 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5928 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5929 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5930 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5931 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
Eric W. Biederman49418b22013-02-06 00:57:56 -08005932 data_offset->Uid = cpu_to_le64(uid);
5933 data_offset->Gid = cpu_to_le64(gid);
Jeff Layton654cf142009-07-09 20:02:49 -04005934 /* better to leave device as zero when it is */
5935 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5936 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5937 data_offset->Permissions = cpu_to_le64(mode);
5938
5939 if (S_ISREG(mode))
5940 data_offset->Type = cpu_to_le32(UNIX_FILE);
5941 else if (S_ISDIR(mode))
5942 data_offset->Type = cpu_to_le32(UNIX_DIR);
5943 else if (S_ISLNK(mode))
5944 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5945 else if (S_ISCHR(mode))
5946 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5947 else if (S_ISBLK(mode))
5948 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5949 else if (S_ISFIFO(mode))
5950 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5951 else if (S_ISSOCK(mode))
5952 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5953}
5954
Linus Torvalds1da177e2005-04-16 15:20:36 -07005955int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04005956CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005957 const struct cifs_unix_set_info_args *args,
5958 u16 fid, u32 pid_of_opener)
5959{
5960 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005961 char *data_offset;
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005962 int rc = 0;
5963 u16 params, param_offset, offset, byte_count, count;
5964
Joe Perchesf96637b2013-05-04 22:12:25 -05005965 cifs_dbg(FYI, "Set Unix Info (via SetFileInfo)\n");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005966 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5967
5968 if (rc)
5969 return rc;
5970
5971 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5972 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5973
5974 params = 6;
5975 pSMB->MaxSetupCount = 0;
5976 pSMB->Reserved = 0;
5977 pSMB->Flags = 0;
5978 pSMB->Timeout = 0;
5979 pSMB->Reserved2 = 0;
5980 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5981 offset = param_offset + params;
5982
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04005983 data_offset = (char *)pSMB +
5984 offsetof(struct smb_hdr, Protocol) + offset;
5985
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005986 count = sizeof(FILE_UNIX_BASIC_INFO);
5987
5988 pSMB->MaxParameterCount = cpu_to_le16(2);
5989 /* BB find max SMB PDU from sess */
5990 pSMB->MaxDataCount = cpu_to_le16(1000);
5991 pSMB->SetupCount = 1;
5992 pSMB->Reserved3 = 0;
5993 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5994 byte_count = 3 /* pad */ + params + count;
5995 pSMB->DataCount = cpu_to_le16(count);
5996 pSMB->ParameterCount = cpu_to_le16(params);
5997 pSMB->TotalDataCount = pSMB->DataCount;
5998 pSMB->TotalParameterCount = pSMB->ParameterCount;
5999 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6000 pSMB->DataOffset = cpu_to_le16(offset);
6001 pSMB->Fid = fid;
6002 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6003 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006004 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006005 pSMB->ByteCount = cpu_to_le16(byte_count);
6006
Jeff Laytonb2a3ad92012-03-26 09:55:29 -04006007 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006008
Pavel Shilovsky792af7b2012-03-23 14:28:02 -04006009 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
Pavel Shilovskyda502f72016-10-25 11:38:47 -07006010 cifs_small_buf_release(pSMB);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006011 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006012 cifs_dbg(FYI, "Send error in Set Time (SetFileInfo) = %d\n",
6013 rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04006014
6015 /* Note: On -EAGAIN error only caller can retry on handle based calls
6016 since file handle passed in no longer valid */
6017
6018 return rc;
6019}
6020
6021int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006022CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006023 const char *file_name,
Jeff Layton01ea95e2009-07-09 20:02:49 -04006024 const struct cifs_unix_set_info_args *args,
6025 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006026{
6027 TRANSACTION2_SPI_REQ *pSMB = NULL;
6028 TRANSACTION2_SPI_RSP *pSMBr = NULL;
6029 int name_len;
6030 int rc = 0;
6031 int bytes_returned = 0;
6032 FILE_UNIX_BASIC_INFO *data_offset;
6033 __u16 params, param_offset, offset, count, byte_count;
6034
Joe Perchesf96637b2013-05-04 22:12:25 -05006035 cifs_dbg(FYI, "In SetUID/GID/Mode\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006036setPermsRetry:
6037 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6038 (void **) &pSMBr);
6039 if (rc)
6040 return rc;
6041
6042 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6043 name_len =
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006044 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
Steve Frenchacbbb762012-01-18 22:32:33 -06006045 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006046 name_len++; /* trailing null */
6047 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07006048 } else { /* BB improve the check for buffer overruns BB */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006049 name_len = strnlen(file_name, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006050 name_len++; /* trailing null */
Pavel Shilovskyff691e92012-07-13 14:04:46 +04006051 strncpy(pSMB->FileName, file_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006052 }
6053
6054 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00006055 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006056 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006057 /* BB find max SMB PDU from sess structure BB */
6058 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006059 pSMB->MaxSetupCount = 0;
6060 pSMB->Reserved = 0;
6061 pSMB->Flags = 0;
6062 pSMB->Timeout = 0;
6063 pSMB->Reserved2 = 0;
6064 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006065 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006066 offset = param_offset + params;
6067 data_offset =
6068 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
6069 offset);
6070 memset(data_offset, 0, count);
6071 pSMB->DataOffset = cpu_to_le16(offset);
6072 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6073 pSMB->SetupCount = 1;
6074 pSMB->Reserved3 = 0;
6075 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6076 byte_count = 3 /* pad */ + params + count;
6077 pSMB->ParameterCount = cpu_to_le16(params);
6078 pSMB->DataCount = cpu_to_le16(count);
6079 pSMB->TotalParameterCount = pSMB->ParameterCount;
6080 pSMB->TotalDataCount = pSMB->DataCount;
6081 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6082 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006083 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00006084
Jeff Layton654cf142009-07-09 20:02:49 -04006085 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006086
6087 pSMB->ByteCount = cpu_to_le16(byte_count);
6088 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6089 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006090 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006091 cifs_dbg(FYI, "SetPathInfo (perms) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006092
Steve French0d817bc2008-05-22 02:02:03 +00006093 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006094 if (rc == -EAGAIN)
6095 goto setPermsRetry;
6096 return rc;
6097}
6098
Linus Torvalds1da177e2005-04-16 15:20:36 -07006099#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05006100/*
6101 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6102 * function used by listxattr and getxattr type calls. When ea_name is set,
6103 * it looks for that attribute name and stuffs that value into the EAData
6104 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6105 * buffer. In both cases, the return value is either the length of the
6106 * resulting data or a negative error code. If EAData is a NULL pointer then
6107 * the data isn't copied to it, but the length is returned.
6108 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006109ssize_t
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006110CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05006111 const unsigned char *searchName, const unsigned char *ea_name,
6112 char *EAData, size_t buf_size,
Steve French67b4c882017-05-12 20:59:10 -05006113 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006114{
6115 /* BB assumes one setup word */
6116 TRANSACTION2_QPI_REQ *pSMB = NULL;
6117 TRANSACTION2_QPI_RSP *pSMBr = NULL;
Steve French67b4c882017-05-12 20:59:10 -05006118 int remap = cifs_remap(cifs_sb);
6119 struct nls_table *nls_codepage = cifs_sb->local_nls;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006120 int rc = 0;
6121 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05006122 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006123 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00006124 struct fea *temp_fea;
6125 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006126 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006127 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04006128 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006129
Joe Perchesf96637b2013-05-04 22:12:25 -05006130 cifs_dbg(FYI, "In Query All EAs path %s\n", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006131QAllEAsRetry:
6132 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6133 (void **) &pSMBr);
6134 if (rc)
6135 return rc;
6136
6137 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05006138 list_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006139 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6140 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05006141 list_len++; /* trailing null */
6142 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006143 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05006144 list_len = strnlen(searchName, PATH_MAX);
6145 list_len++; /* trailing null */
6146 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006147 }
6148
Jeff Layton6e462b92010-02-10 16:18:26 -05006149 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006150 pSMB->TotalDataCount = 0;
6151 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006152 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05006153 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006154 pSMB->MaxSetupCount = 0;
6155 pSMB->Reserved = 0;
6156 pSMB->Flags = 0;
6157 pSMB->Timeout = 0;
6158 pSMB->Reserved2 = 0;
6159 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00006160 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006161 pSMB->DataCount = 0;
6162 pSMB->DataOffset = 0;
6163 pSMB->SetupCount = 1;
6164 pSMB->Reserved3 = 0;
6165 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6166 byte_count = params + 1 /* pad */ ;
6167 pSMB->TotalParameterCount = cpu_to_le16(params);
6168 pSMB->ParameterCount = pSMB->TotalParameterCount;
6169 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6170 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006171 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006172 pSMB->ByteCount = cpu_to_le16(byte_count);
6173
6174 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6175 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6176 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006177 cifs_dbg(FYI, "Send error in QueryAllEAs = %d\n", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05006178 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006179 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006180
6181
6182 /* BB also check enough total bytes returned */
6183 /* BB we need to improve the validity checking
6184 of these trans2 responses */
6185
6186 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04006187 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05006188 rc = -EIO; /* bad smb */
6189 goto QAllEAsOut;
6190 }
6191
6192 /* check that length of list is not more than bcc */
6193 /* check that each entry does not go beyond length
6194 of list */
6195 /* check that each element of each entry does not
6196 go beyond end of list */
6197 /* validate_trans2_offsets() */
6198 /* BB check if start of smb + data_offset > &bcc+ bcc */
6199
6200 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6201 ea_response_data = (struct fealist *)
6202 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6203
Jeff Layton6e462b92010-02-10 16:18:26 -05006204 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesf96637b2013-05-04 22:12:25 -05006205 cifs_dbg(FYI, "ea length %d\n", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05006206 if (list_len <= 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006207 cifs_dbg(FYI, "empty EA list returned from server\n");
Steve French60977fc2014-03-25 19:46:36 -05006208 /* didn't find the named attribute */
6209 if (ea_name)
6210 rc = -ENODATA;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006211 goto QAllEAsOut;
6212 }
6213
Jeff Layton0cd126b2010-02-10 16:18:26 -05006214 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05006215 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05006216 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006217 cifs_dbg(FYI, "EA list appears to go beyond SMB\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006218 rc = -EIO;
6219 goto QAllEAsOut;
6220 }
6221
Jeff Laytonf0d38682010-02-10 16:18:26 -05006222 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05006223 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006224 temp_fea = ea_response_data->list;
6225 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05006226 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00006227 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006228 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006229
Jeff Layton6e462b92010-02-10 16:18:26 -05006230 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006231 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05006232 /* make sure we can read name_len and value_len */
6233 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006234 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006235 rc = -EIO;
6236 goto QAllEAsOut;
6237 }
6238
6239 name_len = temp_fea->name_len;
6240 value_len = le16_to_cpu(temp_fea->value_len);
6241 list_len -= name_len + 1 + value_len;
6242 if (list_len < 0) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006243 cifs_dbg(FYI, "EA entry goes beyond length of list\n");
Jeff Layton0cd126b2010-02-10 16:18:26 -05006244 rc = -EIO;
6245 goto QAllEAsOut;
6246 }
6247
Jeff Layton31c05192010-02-10 16:18:26 -05006248 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04006249 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04006250 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05006251 temp_ptr += name_len + 1;
6252 rc = value_len;
6253 if (buf_size == 0)
6254 goto QAllEAsOut;
6255 if ((size_t)value_len > buf_size) {
6256 rc = -ERANGE;
6257 goto QAllEAsOut;
6258 }
6259 memcpy(EAData, temp_ptr, value_len);
6260 goto QAllEAsOut;
6261 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006262 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05006263 /* account for prefix user. and trailing null */
6264 rc += (5 + 1 + name_len);
6265 if (rc < (int) buf_size) {
6266 memcpy(EAData, "user.", 5);
6267 EAData += 5;
6268 memcpy(EAData, temp_ptr, name_len);
6269 EAData += name_len;
6270 /* null terminate name */
6271 *EAData = 0;
6272 ++EAData;
6273 } else if (buf_size == 0) {
6274 /* skip copy - calc size only */
6275 } else {
6276 /* stop before overrun buffer */
6277 rc = -ERANGE;
6278 break;
6279 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05006280 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05006281 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05006282 temp_fea = (struct fea *)temp_ptr;
6283 }
6284
Jeff Layton31c05192010-02-10 16:18:26 -05006285 /* didn't find the named attribute */
6286 if (ea_name)
6287 rc = -ENODATA;
6288
Jeff Laytonf0d38682010-02-10 16:18:26 -05006289QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00006290 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006291 if (rc == -EAGAIN)
6292 goto QAllEAsRetry;
6293
6294 return (ssize_t)rc;
6295}
6296
Linus Torvalds1da177e2005-04-16 15:20:36 -07006297int
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006298CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6299 const char *fileName, const char *ea_name, const void *ea_value,
Steve French50c2f752007-07-13 00:33:32 +00006300 const __u16 ea_value_len, const struct nls_table *nls_codepage,
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006301 struct cifs_sb_info *cifs_sb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006302{
6303 struct smb_com_transaction2_spi_req *pSMB = NULL;
6304 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6305 struct fealist *parm_data;
6306 int name_len;
6307 int rc = 0;
6308 int bytes_returned = 0;
6309 __u16 params, param_offset, byte_count, offset, count;
Ronnie Sahlberg55175542017-08-24 11:24:56 +10006310 int remap = cifs_remap(cifs_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006311
Joe Perchesf96637b2013-05-04 22:12:25 -05006312 cifs_dbg(FYI, "In SetEA\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006313SetEARetry:
6314 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6315 (void **) &pSMBr);
6316 if (rc)
6317 return rc;
6318
6319 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6320 name_len =
Steve Frenchacbbb762012-01-18 22:32:33 -06006321 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6322 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006323 name_len++; /* trailing null */
6324 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00006325 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006326 name_len = strnlen(fileName, PATH_MAX);
6327 name_len++; /* trailing null */
6328 strncpy(pSMB->FileName, fileName, name_len);
6329 }
6330
6331 params = 6 + name_len;
6332
6333 /* done calculating parms using name_len of file name,
6334 now use name_len to calculate length of ea name
6335 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00006336 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006337 name_len = 0;
6338 else
Steve French50c2f752007-07-13 00:33:32 +00006339 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006340
Steve Frenchdae5dbd2007-12-30 23:49:57 +00006341 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006342 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00006343 /* BB find max SMB PDU from sess */
6344 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006345 pSMB->MaxSetupCount = 0;
6346 pSMB->Reserved = 0;
6347 pSMB->Flags = 0;
6348 pSMB->Timeout = 0;
6349 pSMB->Reserved2 = 0;
6350 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00006351 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006352 offset = param_offset + params;
6353 pSMB->InformationLevel =
6354 cpu_to_le16(SMB_SET_FILE_EA);
6355
Arnd Bergmann05921c42018-02-02 16:48:47 +01006356 parm_data = (void *)pSMB + offsetof(struct smb_hdr, Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006357 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6358 pSMB->DataOffset = cpu_to_le16(offset);
6359 pSMB->SetupCount = 1;
6360 pSMB->Reserved3 = 0;
6361 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6362 byte_count = 3 /* pad */ + params + count;
6363 pSMB->DataCount = cpu_to_le16(count);
6364 parm_data->list_len = cpu_to_le32(count);
6365 parm_data->list[0].EA_flags = 0;
6366 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08006367 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006368 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00006369 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00006370 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006371 parm_data->list[0].name[name_len] = 0;
6372 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6373 /* caller ensures that ea_value_len is less than 64K but
6374 we need to ensure that it fits within the smb */
6375
Steve French50c2f752007-07-13 00:33:32 +00006376 /*BB add length check to see if it would fit in
6377 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00006378 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6379 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00006380 memcpy(parm_data->list[0].name+name_len+1,
6381 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006382
6383 pSMB->TotalDataCount = pSMB->DataCount;
6384 pSMB->ParameterCount = cpu_to_le16(params);
6385 pSMB->TotalParameterCount = pSMB->ParameterCount;
6386 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00006387 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006388 pSMB->ByteCount = cpu_to_le16(byte_count);
6389 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6390 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00006391 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05006392 cifs_dbg(FYI, "SetPathInfo (EA) returned %d\n", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006393
6394 cifs_buf_release(pSMB);
6395
6396 if (rc == -EAGAIN)
6397 goto SetEARetry;
6398
6399 return rc;
6400}
Linus Torvalds1da177e2005-04-16 15:20:36 -07006401#endif
Steve French0eff0e22011-02-24 05:39:23 +00006402
6403#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6404/*
6405 * Years ago the kernel added a "dnotify" function for Samba server,
6406 * to allow network clients (such as Windows) to display updated
6407 * lists of files in directory listings automatically when
6408 * files are added by one user when another user has the
6409 * same directory open on their desktop. The Linux cifs kernel
6410 * client hooked into the kernel side of this interface for
6411 * the same reason, but ironically when the VFS moved from
6412 * "dnotify" to "inotify" it became harder to plug in Linux
6413 * network file system clients (the most obvious use case
6414 * for notify interfaces is when multiple users can update
6415 * the contents of the same directory - exactly what network
6416 * file systems can do) although the server (Samba) could
6417 * still use it. For the short term we leave the worker
6418 * function ifdeffed out (below) until inotify is fixed
6419 * in the VFS to make it easier to plug in network file
6420 * system clients. If inotify turns out to be permanently
6421 * incompatible for network fs clients, we could instead simply
6422 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6423 */
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04006424int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006425 const int notify_subdirs, const __u16 netfid,
6426 __u32 filter, struct file *pfile, int multishot,
6427 const struct nls_table *nls_codepage)
6428{
6429 int rc = 0;
6430 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6431 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6432 struct dir_notify_req *dnotify_req;
6433 int bytes_returned;
6434
Joe Perchesf96637b2013-05-04 22:12:25 -05006435 cifs_dbg(FYI, "In CIFSSMBNotify for file handle %d\n", (int)netfid);
Steve French0eff0e22011-02-24 05:39:23 +00006436 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6437 (void **) &pSMBr);
6438 if (rc)
6439 return rc;
6440
6441 pSMB->TotalParameterCount = 0 ;
6442 pSMB->TotalDataCount = 0;
6443 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006444 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006445 pSMB->MaxSetupCount = 4;
6446 pSMB->Reserved = 0;
6447 pSMB->ParameterOffset = 0;
6448 pSMB->DataCount = 0;
6449 pSMB->DataOffset = 0;
6450 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6451 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6452 pSMB->ParameterCount = pSMB->TotalParameterCount;
6453 if (notify_subdirs)
6454 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6455 pSMB->Reserved2 = 0;
6456 pSMB->CompletionFilter = cpu_to_le32(filter);
6457 pSMB->Fid = netfid; /* file handle always le */
6458 pSMB->ByteCount = 0;
6459
6460 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6461 (struct smb_hdr *)pSMBr, &bytes_returned,
6462 CIFS_ASYNC_OP);
6463 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05006464 cifs_dbg(FYI, "Error in Notify = %d\n", rc);
Steve French0eff0e22011-02-24 05:39:23 +00006465 } else {
6466 /* Add file to outstanding requests */
6467 /* BB change to kmem cache alloc */
6468 dnotify_req = kmalloc(
6469 sizeof(struct dir_notify_req),
6470 GFP_KERNEL);
6471 if (dnotify_req) {
6472 dnotify_req->Pid = pSMB->hdr.Pid;
6473 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6474 dnotify_req->Mid = pSMB->hdr.Mid;
6475 dnotify_req->Tid = pSMB->hdr.Tid;
6476 dnotify_req->Uid = pSMB->hdr.Uid;
6477 dnotify_req->netfid = netfid;
6478 dnotify_req->pfile = pfile;
6479 dnotify_req->filter = filter;
6480 dnotify_req->multishot = multishot;
6481 spin_lock(&GlobalMid_Lock);
6482 list_add_tail(&dnotify_req->lhead,
6483 &GlobalDnotifyReqList);
6484 spin_unlock(&GlobalMid_Lock);
6485 } else
6486 rc = -ENOMEM;
6487 }
6488 cifs_buf_release(pSMB);
6489 return rc;
6490}
6491#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */